lڴIH3xw0t6%MR%jhB<\0AQ-ʈQH\nvL+væ<\rv\\*Ӵݢgn˩TЩ2P\rߋ\"+z8:#2J[i;zr3#ى:n\r㽃epdݍ 2c4k\rGE6_މb/HB%0>hoWnxl֍浃CQ^\r4lK{Z:Ã.pĂJB-+B(T%J0lT`+-@BۄV\0C,0tF?Ġ\na@Ɍ>ZECO-^Q&)I)R]\r97_\rF80Ob >\nR_8٫ov0bCAF!tă%0/zAYO(4 '] I8hH053@x&n|T)`.s6eYDzJѓ.{GEbӋ2{\$**@C-:zYHZI5F]YCOA`x'.*9t'{(wP=**xwr*cc|DV\rV.0Vd?Ҁ,E͝`T6ۈ-ڎT[ѐz.Ar̀Pnc=a9Fn!uA0iPJ6eT]V[\rXavk\n+Eܕ*\0~@g\"NCI\$Ɍx@Wy*vuD\0v댆V\0V`GuE֕flh@)0@T7§RAٷ3ۘ/Q],s{VRFA<vץ%@9F5t%+/8;WJo:N` h{ܣ Ԑ8Eu&W|ɆU&\r\"|-udžN:ncfV#U20>\">`k]-xS͇ТcB}&`r+E\$yNb,Wx -9r,`+ˊC)7x\rWfMSR\\zQ̓uA24L&Hi µS\$)eg rȌ\$]ZiYskWn>7E1k8drkEwwcmTya\$tx\rB=*<lfKN/ lkH8.?f6ч{gi/\"@K@2a|#,Z wd6w^&tP].Tkro\ro=%h`:\0᱂|ꊣaԮ6*:*rO-^nM}Aya\nu^rnO\r`T~</wy}:|̡6v\rcٸߣC/6ഷ#p@p`Zch\0\0o4OOi\0-\n/\0D. .Đ\0fiȫ\0ID\0\r0foGeJ|\rl 3~iP&/\09 ^\0r0] o.\" MvPZmpPڜޏ{C?kϼ}dʏ~=.- m1>hЕ1;QIOP\rcpApVk\rQ*Q}q>u15BqQ[1flap\0*JQ=G_bGHF.0 = 2PP!#(3 \n!1&72f`/\0\"PU\$\r0,QrU&2f_X]9\"S''y8\rkW)O)*Ra%\\i%&ҳ+r3S`,v&2L&Pu*-0\"%HĬԞ@ؓHBP(\$p&,1M ح;\rn. I.',1)42u+3 `SpL\nt_*S3;6r'h3555䜋d2q+68O7sC\"pm8ҭ69m\n@e0<8B8<,(8\0 0J<@IR6pԭmG\"116.\"5̂:8bA1;';?<*\$,̍o= T/3#҆");}elseif($_GET["file"]=="functions.js"){header("Content-Type: text/javascript; charset=utf-8");echo
+lzw_decompress("f:gCI\n0Sa9S`&(n0QIf\$At^ sGtf6ey()LSP'R'fq]\"s> )`H2Eq9?*)t'ϧ\n \rs2Xœej:9^1cȝ:Y@u㓛4X&|)ђ-KxS1\$@\\!x]\0FCO:1K*F4akKϚ2lp3J<,28# \r hF݉2Pl(\$ְ\nJ۷-ǰcc~Frtbm{h.{tkBKcz4C9۫~>`ƓC s:!cڵ*WHX:W;Nj*/(_p3HIKln!trG㭺tC v?m㤣\0Coܥcbf6I'\rb7h`9id5taM={ɩ`NoK !d4zWXdmH*S ]3&\0ڰ d%A- (Q}U!t7䋆>xt{mY0@^\"=@t\r+Y.X\nI'KT^(D.@++@3X aE!,Y2-432ԌMOI\$q% ċGX9[R\0nи PJy\r Bp\\HpgSɼFaejk.4C.^yi9PĈe\"ΔNYBH#8B1\"j\\کx#@G 92f.ЌpsrTJxk4KIlf8zKȇ>AKn^=&A*?'^%;4܀9QhN>M=['vHIJvRt<Ҳ^zB^h'ɩ)-'#9JT)@jO!c,ej@H,javZ>ҷ)E`\0\nTP8LX'L{XzoD%sPW:[=v0?ܷ,%{\"..YIB \nWpV)qAMV5IPοˎ(b.\$[Қj@h\nF-48nj+VMxnjmb\$ \n'~ Z@VL\"p5O,\0K\0-6\r:pDbՐn\$mm\$i )O6(APIP+VHpn4?BMJF.0+ij P(&a%l]'^@(5N fscbz >x\0k Đ\rJH'3(Fтz`O qX`r\r 1,gk lv|+kf'=R@46`-.i~4#<\$R|u2N;Bn<-#{%b=#(J1b%gzG21^8wb^%/ G*7D\0^rcp\nL,0+ Xr\$ 8-)+(D\nbs12G\\{.I~`*l]N X.#%\$KS'36\$CrC0B\r--H| Ȇ,\"57ӒT)nĸ/2La72K1/d\"4SH͌1\0O6R8|S|+rӲ\$O\re(\r\"8ӎs\r2!*mNTQ]jk+15Rh1Qz`pRE-SS\r1@vo.tTUFqE;g\\\"DQ`sIv`0 +KpT)|l8%'LLJ@\r&+ ԃX&t\\*'4NƣO\0OTDb\r1PL\0gM\"O>Cw]770 !\"ː4\0zW2 D\\W<2\"_ xw|qJ&e24\"qX:d6+-̓/ӄ[V71\rc\n\0\n`J ~+'1f!G\0[a\rv\0^\0ZK ~Ʌ7w%/(F?`z%vjyj\$w/!fqT,ӉY7I*jF,yRK~rr菒_W|x;`㍃nn<'%xр8߀ b_J \"h`Ev\\ˁ#\"4ٛɖلxdLFq9TljV#q-=qD2Mދud+rTtgcfnx^@da&\n\0B|:I+,7'8\\P,\"-scsvG'W\$=}[~ YycYi2sw4\rK.PU@珜\nAi2قY~'AmqӚ,4<ss#@`X\rͲ1E=G4vG\0R'Y@7:@fPV{!\"z7Mo[D!*W2j2g8|L\$DiG}GRb!r&-3ԣmș\r0qh1Ki,|ezHYFdiS3b\r>]:~=!}i']2(\nFgXXn}#ܗn`\r?t XQɑLZny~?nNr\0\$oj7Z&9S tU`tc*7s\r|w盕N)=\$Z'ˀ a!#Uȕe^ia0-ʀ!JD`fd0)RH+dI6AfvۓxT{C 1&GO \\Ex(.nP\"(02쮇dW=.@gG['jZ2='!K5f)R(r1j\rX1i5\$ Ļt, o\0p2,m%unoS0PJ\\6sp)jL?ֲ~9d\r-,@%ZfQY,pXRCiJ!3#Y nc|@ (ɲ\"q\n_)1!8\0ы`cC}(_2 8MY^3.U]!4a\ngJKЋ`9LH) Xn00܌S4EP`+ I4YFXI9hWIJE9!k#H]f7<fm(Q<@0|&'@4 vȞ\0/ A\"&0yS<'5UZq%\"3 Rr鋞Ip:\0-PXT\\\0NYI2\0&n;2g|9N}ANP欫\0>&T D5sb\",VSPО2` .e@\\RDw4\$(⒢ 'b2\0\$Bf7\"q%W@\0`E]BJSxo\r8By(\nS =@7UA\r{\$bc\n\\\".h^\0`\"^L\0@9W\0RO`eN=8ogv3n-CFq!Bp-qa7Mb'sK'MqHZm\$1IOj5lkgmzi6A\\@d,\n@Ӯ4tiJ\0l( k哊Vˆ\0Oiȭm(9tЅA\0fT~\$S]\\d[9g2\rpB֠x\0-6eEA1\"y,+V]ٔimtW[B<&`bmqH|fSZ-?gDOQAVθE3Q`T&AƩ\0\n%a\\Si 'bhH^|}O!.ɞW!\$Lyи:ݻ[:HD\0v\0v*l{(.uŕRÕZtm+lLY<+1!05/>T:Z6ISǯՠ?La,l.=[3tlhʲ0XhF⧂xPFhVu0a,،9\n`nTŬb7l\$M9+Ldl6Y5+ZreI qPZ40YaE'5pmK`آ|\r|\$CKBxRյmt8ogIu1ZeИϓO%MCS nwݧAut\$2{6X2V'ݼ/o[\\]s0!%}xY7+?aI[#U\0c{2f*F2}\0bm@zdX!T˔Md&ےI8.tJd/\0X{I K~^7C @D&]&SCVۧdyD41\$ F'\\2Et@}fA8.iK6~kOrW['/FL`J8EݦvVR%꒡*ɀJ^rcH7t:n7mx]&ze)5JtA֫)ZK%/ne®|6ɘc|Ԗ\\>ۖK~Ԃ۾ò\0-MliRdB|!O\$=\$Y;z]a8p!T\0.\r>(28i,XW4Z8h%Z6jDs2M_\nҤ6ՖRTQY,`F/S\"`nHWy!2\"\\\0=66B )\\-UιWp )}q!p\\\nRXlJ-# Sm=\\KE1#H2 _Mm.Hҥo&!9V'+*U_)L.&J p5kB5T,M\"7Q\"\$aE7):Ţr:*.5|=a68JZLivBx t>mY9N\"4Ub,p1wP>A:nWqhR;Z\0b,=Cp\0,R^rk7G>MiVi)h9+2Jս!~4V4疮l=e恺։,d#ZiYſiH#[JkɕkKax\nPTٲc8r~9dO,᠍DA^d=?O5E5O߲j)j#[eMݐViaqp Kt -9+ċ̙YN6\rH[ŹK:fQ\nAJ]eo Ҹ?-r:s)1lS+dFz3<k^6\0Ae8fifj*rfi&V>Lzu'3I5k5Ƒ#la|@̗lh9C拑,K,&nBUze7\n:X@I\n<+\r&mf[d++A3Dm7BD`9Eh(N̓k :U)1뵙'\nL& \$8ElDihq%\"NcI@회6|Pe,{ śfu\"f(l-\\P5f|kP\nh(p&Nzb\r3*ֈL{zuLeoPͲVz\n<|N1l)9z*j#h)y_!gut!^My\rj4xҞ\"U] Xj>Cr:w\nt`%!CzȐ\0^Jxa4.cXmUY|\rHR%#N\$00.淝:2OA&\02 y0apYC\0{ IU1>|4 \0W@oQ\0An߈y.hFP\nx<\rDx}.Bh\0ʳ!uBE61U`i9噎=Kmi{?H˭wk>G)v-٥Z:m+CsQh\n[W)3ï\nH\0\n9\rsd3|h|9p,^WsգC/c\">AaNh0 {8Bȇ@0!tO-\n^9j/N7D\"pHsq^5Nˢ߁ ɗpWoyYr4Ί-9SXŞ&'Cuaz~d\n7??mnvKҶkWǐm+ba9\\/~˸ݸ|tcp%F0}pz\0Z5=qtTU\"u<.ugW&¿]f3י9?h6m\0tŏf,]\$u^-_UGԾ%&i(]0kGr'z\$?P~Kq\\*_gW2t");}elseif($_GET["file"]=="jush.js"){header("Content-Type: text/javascript; charset=utf-8");echo
+lzw_decompress("v0F==FS _6MƳr:ECIo:CXc\rJ(:=Ea28x?'iSANNxsNBVl0S Ul(D|҄P>E㩶yHch-3Eb bpEp9.~\n?Kbiw|`d.x8EN!23\rYy6GFmY8o7\n\r0\0Dbc!Q7Шd8~N)Eг`Ns`S)O/<x9o3n2!r:;+9CȨ\n<`b\\?`4\r#`8\$c1cc{n7ANRLi\r1!(j´+62X8+.\r!xh'6S\0RO\n1(W07q:NE:68n+մ5_(s\r/m6P@EQ9\nV-\".:J8weq|؇X]Y XezW 7Z1hQfuj4Z{p\\AUJ<k@ɍ@}&L7UwuYh2@u P7Ah3ÛXEͅZ]l@Mplv) HWy>Y-Y/hC[*F#~!`\r#0PC˝f\\^%B<\\fޱ&/OL\\jFjZ1\\:ƴ>NXaFAfh{\"s\n64?8^p\"띰ȸ\\e(PNq[gr&}PhW*r_sPh\nom#.\0@pdW \$ҺQ۽Tl0 HdH)ۏ)PHgUBe\rt:\0)\"t,[(DO\nR8!Ƭ֚lAV4hSq<@}gK]]=90'wA<a~WD|A2XU2yŊ=p)\0P sn3rf\0FvGI@%+_I`\r.NKI[ʖSJaUfSzM%\"Q|9Bcaq\08#Zle5#U@iUGn%Ұs;gxLpP?BQ\\b龒Q=7:ݡQ\r:t:y( \nd)\nX;CaA\rPGH!@9\n\nAl~HV\nsիƯbBr3\rP%ф\r}b/Α\$5PC\"wB_UgAt夅^QUjBvh졄4)+)lj-&`9qPy6\r.y&ảE80kAVT7px)ޡ~M!EtP\\ϗm~cB\\\nmv{9`G[~xsL\\IXwy\nuSc1?A*{Ϳ|9/E4/W[ȳ>]rv~B PB`TH>0B)>N!4\"xW-X)0BhA0J2P@>AA)SnnOQbrҦh@ȋ(\nFϖƙ(γP\0No}lVԍp8%2>Bm@G(s\$d̜v\"pw6}(VKˠKL ¾Wq\r̤ʀQL%PdJHNxK:\n %fn%ҌDM [#T\rr.LL&W/>h6@ELPvC6O:Yh^mn6nj>7`z`N\\j\rg\ri2I\$\"@[`hM3q3d\0ֵys\$`D\$\0QOf1&\"~0`\"@ZG) Y:SD.S%͈3 dmU5.p2Q3VذWBDtCq#C@IPDT_D:Qf-WX\rpUDt&7@? }O122#UK*)긋0o<>]HƿrLGNW%M^9X:ɥNsE@xy(HƙMd5<52B k!>\r^J`ISN4'ƚ**`>`|0,DJFxb4lTؕ[[\\Ԡ\\{6\\ޖ (#mJԣ,`IJխl jj֟?֣kGkT9]3ohuJW\rk)\03@x,- 5B=࣐#gf&Z`#oXf\r Jh5rqnzs,6otDybhCtn9n`X&\r'tpL7Η&lZ-w{r@iUzM{rxאmSB\r@ H*BD.7(3XCV ʘɆ:6;ZX0̢#cMyUi2,qF˚bJ @gG|4gmzW )r|X`Scէ˙c!B/}{4J\0ÝnKuz @mѮ߭y͞y\")uY睘scy둶y7||{Ϙ*)4Y`ϵ[v^NXW7;_*x\r߉xm+m \$\nl);|٠ڙ:N:_8NU5;p+UL\\9O:IzQT)XGJ{w8ʼnU\$PxTYpjhJÀJ{@ǂZsh˘X\0ۖlӖθY}^@u2S#U;È|P\\#|<\\J,\\̚E]Wl,ɖ<Ό>Yn),ΙrԼ⍺] \$qDJ=XI-ŀallõ]\\w(iC׃tkRu\\+>)3PP6M%pԌA3qmu2fzۯ4s `ێ-kS%6\"IT5~\"Ut_ TuvֽYw0I7L\$1M?e@3q{,\"&ViI?mUWR\"uiTuqj\"G(-By5c?wT`eiJtbgU3@~+\0MG7`\0_-?\rV?FO6`\noϚIn*pe\"T{[Гp^\nlh@l0[/poJKX<=9{Ǿ6!OQx{ZVFԎ`~IߖL)Q[TMT*BC~ \ngÈŅp9zKwzO9di^'+Dz4gHALy\nr/%|ȅ̒ގ\$)1P30(\r+\nZz))\0*\0k2υ(E86stf&+;76&K_(9f,@-4l\$ۂe7\0:lLM7.\0|oJ۩Zu̺'y{H,#\0vU@9! '&G@_-ٿt;:uDPUцjH9FBcCiBwMtxPM?p=8lg~ta%]b\$\rra,6tW)\0UF |쓢vhQ*Ol.C\$\\ցRR[j[]KRJ>.;F=Rڌ<rM=Ԓh^Y\\Rmn Nn*gB5^Q҉@OxHIT9)(&}A)P\\/_!́Hڑ\0B\$z4TYuJv\0ꏃ%@32\0Sm--Gi@Q%jY+FuzlSW3ŷOrU\$E;M\\Աu/jeQ,#JXP&|Uс`h2n6I+né-nD`ɔ@B!;XsmȯpC`p5O%Z/5#CK`XcbQ#Qaqp)G+~ۖ\"lM_^z!EХap86n+oJ,w\n]̓pR'eJq'ܨ%'nlOh@>NBȊX5,rGrZ l\r(ˑjIl%b;s+נWg7)*e13Le@(p\0ÎdsAD\0Í\\bD\nu/&1XRץE楂5T\r}7A٬k\\͵q2܀Z-wotZ]-yq2j+ՆխënXA\0\0+S+Y6_BV7znZ@̆Էƴ]-UMJc*s\"+\0xB3^0\rc\\j*P-\\Q8ʎlc%XVB},;(`*Q \$r{KC%\rx Q,/v\" p~ J5eE-^X;c\\m7?6C*庮,7Hf/9e0[@!bUБ=i.Jocj;B\0]ՔvG8O\\\0NJO\$.& p\\H1bp:F\"8ŶVxRx=3f1+|\0BkbPLђ\$zc i,Pcb,pn(,`'/~kֵpq-ȱV܆\r \0dS+\"鈭1\0(-1~tcfBۑb}ؠ0<1\rL\$2d\"1&ƀBóN\rB\rr\"?vdZ.\".\0?w9o\r0с!dR뤶\0Hra%Њ+\0yrHsϒ4W#,\$ \0*xB\nP| 8@/\02UbΪx!dN3S?P(g\n8ppS9@' \0y\0y46H<\n`SCYjp:\0N(ӍX4kgDyt{>\0P`O\\s<?4w~f@z~hBWxhAO'=Pײ=c[ysg|掳%M,Q8'X hlUs٢ 4qDx*8gNLBȖ;}%e@Yvho!\$NcCX@;YH'@^ Rf^x\0^os_f;pj]:Ԥ.mLl\rV\0@܀\"1%!_@-]8f-a]YWψh`(J@\rY kB(x:5B\\QkO[:0¼ukX\\P\0[xŮ`RIGk5YzPҙ=l=e\02=k` [KB8C}kc{#آldfF.̵-A6KPv'lHiA8C G`Gbyپ- 0Ĭ;[*_mlH{(;Uo*],ċX80CK !N(I` VDvwrpc,\09~sXnr[ec4dpi \\e2laZCkglbB7x%Żk`\n(@ź5ݘϭċ#tܖE}ńsLvE\nQQ۔76}Orjb%@7۵hwnk`Vq~~4{ˁ;8p2mP+ daX8&,=n}!/K&\rtH)/Y6@=}EUlK\\kb[1GM)JxXET /\"-<4xDp(3ʟߴ'+\$\rF܉\\Rپ-nܧ\n?F~a+x\rl,fC+wiG.X!_71ym~D7 G;gwb/89x@!R9éJqYh'3Ĭ*Xwˮ^ 75`:#+ۭ0S@0o7:&~r(ZG1zpdN`/Fz@8t0Z_ 0{LnׇoEÍ=rGj]HҷAf+Vm7B*q}cw=ۄgwE-H&Rh4MZ_L]WV'զ\"u@-aMs@9L:Ւ]#aoyb\n\0[rp*}Qbw?;Vcʰ .s索XְyR=&drO2j!uxR{N&ѻ5}vy۰1o8Z#{NrQ:BHzW{W{:r}D\$j7)PCvVXdD7፮,h_]^qσܟxO]?p{\"O8Q?xw}J?9kx5bu&o^>wg]h#?+m(/ng 55<;ȅ˳x%;(V;o-˽.enkp_FX9WjQCBاv3R=솦;a][yȻ4/|##v @_ǭ}UM>1\rCMqCdĘU#[ɦm\n\\\r6'>iI;R\0X{~wH/vL\n9?do,x)#>#b`',gT~t Y}/]-'\0( @ϡ/>~olH/qDT~o|a#|F8dϥ/|uVh\n>{ _{G IaE&{VNodFBX(IN@Y9ɿ\n-{@Ro۽&o^3Y>|-~/?*`\n?S!Vϩ>}O⟕>RM?b@\nO?0s\0Iπ+'X,`'?\0K௸CO2t>LOLv3\0[PΛlH\nhlr\$/\0+\0 \r@?K)<#Ps\0?K@@\0ꀱ\0%,p)?#\$\niL3[3?@O\0A|P\0D?N@\$,/\$B?0\0\$\0VLhͅ >#6+>R:p>7#\\гlΓAo<3l pe#7A@)@#AV?h 0*Z\0*\\Au_>kb?>\"c#6>B\"\0>\0ps?DPvA\\#(>3EP>:<\nO\0d\"@A\0Aꎐ5 # c +@h\$\0:M3n3c`T+I8B3@* @'\\pM8OlMc#7Bh`, 6o\\\\.S>DC0ƣS\$2B@&A>Lk4Aܭ3@;>p\r\n3|\0\nOA:6\0d7@8%`#É[=D\n3uLC9BC:`\$!h\$;B20u[8C <篟dP|=q2pV> |*1\0\rE\0dAovPt'?d,PD*@ /#6CPBO\n8',5ÏE Lq\r?mEq\nzC@+r60C?3/̓\nPlHDͤ5\ni)D1(D7u>\n\$Aj4\0?4?LK A>Ͻ?qDI@\$;D8 &?;cJأbP\0 B#3`)O3CMZ50EO6C\0\\\$p[9B#cj<11B;cDBh?@`*.qbX o?;\0Kp38 RC6/\$>lͤpI,!*\0+>=]w\nT^pgź#\0?\$J@ \0*C*7h\nj?:pAr]YLDbьB4d@(DcE@>\$ 4ؑ</?\n/ĺ>gp>I6i8;Ɖc1AZ6!}_dUкZP4D|;rC[9ꤥ5I5I\0EOB\0{9qC|\"pUZP` GcQCGPJO6(Bz>7F0I:vOǑBuE,\\0Ǹr8qgA6>74D0qG>-SE@#G.*\0i\n\\-`*\0q\n\\e\")qun@`>D8 \0/@_ڀw#ǍlG>Ԅ-+ߐ6Wl%6l0\$5s&\r*\0e!rqI \"> Ș3EIL\"94G\$/\0\0 -2>/倘Gg\n/LqBP\"#7zHMԅOO\0̏&2LT^P@Zd=]Q=KCE\0QO\\s0>qCzG> @?0?\\o¿4Md19\0G?m\rD(ԴLd\\KJ8\rE-24U0VAR=Ee5!2mqAEV\$ϕI9 C&\\G)D 4I#p#C\\xC(\$H:NI(J\0\"w\0,)PǬϋ4ex-JKPrԂ-`2_7-!\"JؐJH.o-.\$ d\nH\"؆o+sؐ 3+ 6/a.\rnd˨?z1\0? 7\$\n`+Aw*MQ̄\0?jēVq?\$ 9-2ID9Lg1h[ۏ1sC1sީ9Lz? LWdovL#9`ͨ0ɦWh>\0>/)DL\$a9*<:C+JKPJ\"L\\*b 164ja+\0%Qf ;KE`>>7tHwMPn3I:fD \rX\r!\0\nBsVM63KO:Įc5 X!AQ9z%`{:HDEcv!Ν,:X)(%2a&,l38j1|͇=CRr<\$\"KB3'9:|)`Oj+9 }-S>2UU5BUNNSNO3KNЎ @:/7āQ!@.(&v9d^ج![.pGc K#?fpÝeOd2\0k6),\r65GmOFVdix,a=O@sc6`¤\rJ\0;H(*r-.M[BΠ!(MLPbUpJ:1E!:,:YB*KRޤr0جLa6;6+2)UB`JsV0:0_B14/AONe)A~\r ̠NPw,C3殹T3q9}SQ\$APD;!:!Ys6RԁFt#CπQ\\`rXr<'72ؼO-w9Ӥb853{\07\ra\"\nh[jFa)+2<%M|m|\n54p &bUQ8\0Eѥ4AAN,ˍ˝FؕTo(G`OGAGl`:=\0<\0TNϬ=. 6Ζ(SBİ\0,J?.(%,?B.<2hMI`Ό4*˯G'I9RXE%,O\r,ʈs*(}<ڗ@cRj]D`URγ,.dr \\NlR-˚kQK,I.T@1\0K4/]04KK\nC&F,SF0ԵS.-K2RLe'7L0oK3TS.4T:X̾49/:WR9.62J6S .cSv^ 0O|LMD%34z3Id\n#tPq5h{!7Zۻ2 thʠ!K7Y1Sƺ!1{ÀӼuEM4{֔4TGa;|5\"SNkS8D?JcU0կRtB{5qSB,\0pj!\0006K1 X@DV_.(_`-`Dua .X\rFRFDSRxhLU`4\n͌To9vFUm\"uDՀ \rw+\r`V(VPj]K⏜4oT.\$mDĵ Se@3;@7m:륥d!ZQ[5P7;S/B!McGTW(V䯕<7[lt^\ri0Pa|VX̃a[x9H]^&mҤ\0Xl㤫ހTOXl0(,`oau3U#'0+ӽ8]HT!XX\ryW@\$MQb-)X o\n|`-q-bٶUVc 3N=5vAg\r8\ra^Ю0\"䱿R,3D2iG5?:\rT!wgM[7;[v{֪Cs\rU9d`yh\0h@~qT4_QVvF5Ps*Mc]I91T0mV)SX[*cdA+1hb:IhM@s>P9vuT>ֽ` O5ccjϏ?QTmq\$=(V6F\rTr~\0|mC)[ՂN,d+;Qm-Ň\$oB-sRN:/8>b.40>,.tںJ\r\rk6 WMm3[x5qLb6;`Lm4I6^d!5`7:aOh4-3HUmڒ^_NTꍱ[PH؝a=UH\rE\rjMSPsN6MXQ 5 \rۭYKqs[s-\0]aNd5?+CfRe^+@[P5GaҵoM@w\0QyoKUe}[_oK@nwxVpEPuo5R8c. Uo5w\0\n(%NpV֮JAqtZ#Ոk6iEVR{qf{3l@PqHr!VS]6'q@>R=E\0S+UjʔY[źuUոջrp6s]h't mJ8QUUuDm2zЄBKv'Pl]AAfch\"RVpX;U5cְzPTuUQYZ5UJen5novs=HuZoaitoUڻuuH5n=jSUPZMNQmobFA>]i\\G\rTvւ\"2v4γ=]2z\n=:\rh*sfw_Ut8[݄8]+=G7z=nۗJu8|4u] caz׀Ywt]ܪ^r)w]%i,e}w0<3nLr.iy-7(K&\r_;f[̈\\\rX+Ha=ܳbnc ,c!8\$mVvRJ]g -WOsR(5]WHVC\\5@D!s%Β^sd%N97փ{U+I-ռP\0\"FЈS5F[zsk(7Ez1-@x̹>MgWMjԻn\n ^tLUc}AVR@;X-\nXsYn^c{j7:]E\"JVJe~.QHgT3rcVBce3e^Հ98\n Z(䇪 ;tzՍ# q#\0V.\nS/Dk/k4(iJ`uM5lG'\0n`54\r5tB}ZH4i:x4ӊ53&`ġamn-n\rWaMXCKQm4Ȉ5AXG@':LԠY3\"@WƎ,MQ[apfJ;`c=Rް~Vo韢wcXnч8K8tj't5eB:kxyaࣾFn |:a09\$cuf\nw>\"a!8~Z\\xM#،J\$yHhMQH \$\0]`@3bS#wЈ?L2YI>!?,@[G>>,ROs*dRcGQG!ùsq|AXqPP%\\PxÿTI8ŶΤs#磵# Ş#ϏLlE;C;#Q}H_LYJy\$KL/~=1J(0d/\$Ae)lE/mϡ54)QŀtGdqQQ1Ep0 d13t!C?\$^>Q|!B?F9!c 'WhALY䅐p1K\\y*&MA{~d=/pdtPRjEA\\(Y:\n,yP@iDy)9B\r!df=Lĝ4pd>>pdV Kpe&PhBe&Apd'D&Y6esU:Bd?O5\r'KeFDdeFEC\0t(|)-#)!m\n܊l4?[қI\rL^r5cU1\r,Rr?dRs7&^!O1F[-,\0)\nB}?^a!9pe?f1n)Na~W}eS>JOB\nP%\n*AIleqE،^}QD2p GfmJ\$}ҹ+-5Eg\0QTF6Y #c*ʃK4@[s8LaN)CXD[ImR\0006N9fz3M=~9`%sg=>G9ﶤT것4Ztl炳86!_KthIvOo3xSƁ#1(XIeVx%UT#qNp #\$L)f|C3˹MbMG%d4L]Kmw6f酘 8\rvu9rAx\0h^:bdghE4R}xAH|Eݤ9|ZIVsNCϗ.֑֢nwMNR=(ZD=Sl,95M7/qɘUACSa^ne~\0m)(%P!3JF;&ͲA[KslF1˧V28͔5p!!l V\0m\"1I\r&Im35*|g.ZNt62倳qMZc]\rt-kZ/A{YpWЛsÔ _tvCi;EvI.фmQYܙ3#OGmaZ1FUJt!s\\Msܴ\rګ1H]=,It5(5xX5o\\YVmARuYVsz\";ҿ?;*PZ,LA3XU^!ORȑe&4].qe:Mif 5c3}7t.Ӟvh9%A;:7zhdW%S]hЩ{D;٥e]i;g&V]YO⏹,>k2ۂ\"-R@2%o\rTRS1_e!C_E֖Uɋu\\yS/˼WNmJ!@P\r`9Mss#|XnεAw^ttZ?=_eB\r`}P]Pe:XպIUN˝6CSRoMۭ%ۖ`Ps>@C!]EUjNl*B{\nSYʼnuOP&ԏDU\0^e\\\rRLUrVi5f~=tU'<[k=UCh.|2URkICpG!@<@㷯'f:?J0]T57YeGIf*U\rS \rz%GuYU'!PK6/M4\\-x\\prqCV31LMtԫj]AXyN]z|\n]߲ASѼUفa'_w\$EY+F6]h%닸>U'ǎt]G*o]+'*w\\TŴ쬀1\0as;Kr`\"\0Z伵W.T܂q\0T!Ǥ*W]lrrӋo;*z]!uO6ծ\n`4/seTDH.CW?7E%X9\0_gIs>`ׄLM4(n'+٭&ӣOVtZ \r>#Od^m:ah)Nd).)TtO=;pfWt`;l=)u[|tҰ\r%\rҕj2,J40{bI*trPpk:?ĝ<ӷJ|\\t#4[}8j\\\n뺝?/Z\nG}mS=Ex@X\0_J=KzG\nhWR05ys>=0س|CNG~R]/b PЂ5ZB\nqҤ-Yv|ɢg`*vHOD4ۑGQEvboW\0\0003Q'_>@~kO_#`&<u쎰]Ƞ':NEH[-p+IHhў~DF/g1w&0Edlhݜ}{q\0FZ|v9H R4@r ȝl#>?\$r361IA62»%lpo\"4\\>J@ȡ\"qyIrDUIiwI\0\$CI%<0fIeT2WfZ~;&BDC7et5Oɣ&FBDNI]~@Q,?)a1,3 a8Jh\"3pRs-N8RYh\\{3Fu5D!?{S\$19|Ȩ-ʹ\"Ӵ5sy516'yMc䵶م:\$@gOgIu\\wB叕^VÞT%j#[ɍ#qvoρe;8ubI\0q[>3l0\rCJ&1=D2\re5}8.њ^xYѸ'.*Cy7Sf \r)8#Gg%V*\0aLf(s \0b\$z0\0h92`ߤ8\0jޒ2\0\0k闤\0AǤ`\0òS\0\0z}闧z@迥zkB\0\0s` zW\0mߤnz \0nϪ mG~zq\"\0o7\0鿮~zg`rFϭj>,귰z5>F-\0~Ϥ\0ޱzܾ\0a쇴z;헫>k>ϥG\0s߳>d\0_o\0kzw{oqwz״~{@B@1 ~۱_zף>zǮ^zo\0s폵z~G^駽g紞9Ϫ\0s穾!췵 {\$q\0\0\$I\0}h {ǰz?_\rz~N%z'{/UGzO{iw|/ɟ{w\0i?\n\0iϯ|WQw+A?{_ ^oοR|#|io?2|\r'Ǟ{z&{_C?~z7!7Xazzi?_OEҾ\0g@mz|?O {ק5>_za_V_^N%1O}\rw~ y}?>{_\r؞{~!\$g?cǮYƟz?zUo~|_!}@~_>5^{ǧߠg_b~wdzھ__yzk2zОzO{SIYOɟ\0m̞}^{w&|\r~泇?W?ߨ{-釸}%O>~g?=yD|_k؟6}S?\r_;it~o_8Qש_{YOu|Qz>~O|Ϳ/_0{C}qE{%/}s/qI\0j|0g/b>{&SGY=}ݷ+0z-{7ϫ_@\$Y7F=~}`=<'HY\0q'oŀE8W\0002,CWޏ`^:zkK`{j5o~fQcǪ~@O6M{qϙ_-,zW`?3zEo|H'@|Da̯M^=pHs(/sr{\0/@R\r퇧_>'I]ׯ:FW>e|`gO߬yzS\np@r|i6ް}0jH~s}ј\r{\0!կH>4{\0\rGR|#zA{~\r>zT]O`=|#e|P[؈\"/O=A'ޑ?{|{Ǐ->|\\yC7^@RzaU3CGzI0?ۂdە8h9@>%-w{F4P~!O_=#֨J|r)H0V˿w!O,+`|>҇}a)7zk\0vh!t4A6.K\n_0=V~3x\nO{@BUH`AdpPߠzǨp=Lz5Y+>IzO> s'^н~N-wO^Z9>>9V}ߖ%|b;8AF}M{8 q@(߬yQѵ#|DRH!E<3#x! 'Z)!Fo\nIKA| 0\\Juԅ,tu 5C !>v~\0@'tǺ\$H?,0ppC\nGF['`2ׅZ{@aQBȟ ' fK\rP(_p/ Ba`S\$!2چj\n8\0jّTXnDVrءs+҉4hQ(\0,J]-ĭC1EM\0!hF\0Wt rZ\$!@R{FPHQ9Q+afb\0(e/\$*T\nEU`楏^BBL\0PY*8TCI<9th,\"#hJ\0\"ZQN(C\\{5SC^ƲP!OBN:Hx'Q91\$lj!0Cy\nS(Uu\r3/t\\8#8@\nр9ybH*7]R_3^8>'g aY~EC`\0+j\r8@V`\n\"3D\$p 8DD*5DGᎁwIQ S\$FY1̈Q HDx۲Bc+FKf[BEL\0O@&҃?*TZTD:Ct\$gJ\r!\$xX(b#!\"}fE\0PD\rɅ*T :+J蟑,L>A9/Y~,9=PDBOv+Lx뤂 FhbD:,I\"ANbqtFq¸j+4fW<᠅f&.~Ȟbˉ,SSP¤\rC\\lEC7PخCлH#(!TqEǦ!Rl\"m3g.)A8:BZ0;j3e%%ن\$ok4PѲAM\0Tb1cJ12(z?B)H\":EasA4GvтEwE\nXD:_\0#HA\$~\$q%\$#,јōc2\"hQEh{/k(G]dM/1Yŧ2-Td赤^ŰCq[H2\$ŷC|%L,Pԋq^!SE44sc,&Z'dUюc73H J4]HwL\r+iFDp#L\$.5@EB~|k0!<\"Lmhy\$A#60 ibAHl;(\0/AHHdz}\rѢI0b rEv7jD.cvqPt,&JH%#t)P h8&>ʆ\\+d)J϶P\0k7ibB\$Zde3BAWB?C z7nW͢#6h#f/+@'ca!,?>#!]i\$.\0 xC
c180Ful A2WK>㯻:F) f~P%h pl4Fܘ@S\$(C#k|T0h1EȎ(G(cpb4f0yh!\"S菏G\0=.hF |.=مGHopt=r2=z_Q:я2>oLǷFh5/&#\" HA}D\"Dj-1^QR2N6~?dw1\"Pt\0҄<GBZF?&\0!0q\\p!У{?4\")^(WHH\n'\08ސ\0_BZp>鰝\$n^A\"3;GA <kQ.1F 2a\"A&tm#d\$F\0Lz;8ɏ\$#!1B3aQ=-;gJ!CzЍ\$Gߏ C*t`ȑd5bM ! _\0S\r^ĵC]\\jB6\$cwGw9j&aO\$4@RE^DL4,7܈㐟{=ʔ?K%IU*G\rP0{.Y`3 DBD'hNC\$Gh\$cZ!90VR3Q~6CԀ2u04,MXrG\0:9P\$JH/ydw@=1N(@a@()\n3#[y\"LsG~^lHDԈ.(EϨGVD\"či)6\$y fd~fC4d: 3JRWHFAC TZ@%q2.(rF9 PQ#GFRbA?ِ\"!`\nȟGiG84QHCAbL(h8G8M,4Hd%N~Yܜ.;@q&s5k3B@%u6(\$נؐU%7'HgϤ I6!9L1 ҟȑ\$&\$95L#nò#6{E -'v@Q8䅢\0:?GN7T@^hHɣ,\n;Hcv-@)bfK5>@I\0%Kh0jFs)|P0U#yxZ-CCg/.O:ItFCM]P`X3b\0.&ll3ҋ46ʉ~*WT@*Tl8(J~\nU@-+.UAү@n+\n)Zv)\n[`o0RUYX2#Ĕ+DyYR%N>G+SySR%fJ+S9KOoJWiX_U\n',2WLap%Tdu,1|i]ұI+Ti^%:K,WiZå0K,S̱i`%xK,V< \\\0/ #,rYlIgH%;2XYi\$eT/,RԴcr[쥩u%~˯?)]|uʜ_.]\$nKwy.YB̒%KS/.] yrH-*^{2ݾ*^yzNT|a/_4XJ.]\$iw%K9/^г%F唹/_ܦ)>%i8)+`1`2%Jq[r_0<Ը)]R[w/Z`its%L0r]df\n0atV430_9rޘL5y0ariz2l©={z_wSJbSf?30e[1\0s{1Ƃ^=le/|Ɇ&pw0Ɉ&!LpY1*`SKAsdyA{1d<Y&4>Y+-NdiJ̊rd\$&M̒rcCֹ3&&S̚eLXT̢g2e|iR4={2ef^̲2ei.&a̺YcCɚ30&g2fifhʙ32f_&2g<`7`I&:3a)P\$7La3Y 1?x3LϩOI 3jh\$=L.Vh3֙gs=~#0h79^pRb<ɡIL嘥4Fb҉8-(4c҉b&L1h9f}4hC8ߠ;FiܓD\r|i3d\$\0T&{5BjקC{.g\0 1Wܒ&kհYY@A:~E3jSɪRfu̔#2Zkҹh&r̜5eyM&tz50)SD^Lz6:jcJz6:j;if4Eٹ:ޟL噡4FfډSRͦ#6jɵQe6gDh\n@+MwZhDiaMGZl4NA:pRkiE\rA:|q\$)pNzA:4BnSX|=Z76hӏfKu4vo|ݹuS{% 8YGN#dp|4cqƥAM\\_xQg ut >Dd`\"F0%pXH}Iƙf9-2CXP\0KJy:?LhIV5z(Xx1o#I2|:.8,cTx\nMdnYc̜rTfDYunȺ1 A((E\$tDcXV(!^¥[\n%%Чb,/&))T%t|=Js## G.\\`x' &2EX̘gA8QERS0ĭ>8su\$@'8\nT91gΤ#i8BgUE#Gr%9ՑcN?-8(L;xѐ\\ƓqpPDCr\$P_\$(LP6PNg'Nќ;Fts\$);'XE ̃p.H-Dne .ا!t9/rα]#yȎ\\\\(f;pDs\"2\\('N&+\$ӦP#:^x\0sxț:+]'V?:IZYƑ\\ò=u︷aNc9\n.3!=\"\0Y\"w^XsgOA=/jQ3\"2:55)af{2CV!5 3T*0Ț~\n57hq1;h\$H.e0 CwjNJ=+pʑͥC(t6Ć ZoyLgŷO|X5\$gn7d*2'gBoi#V)>Y>P'#^>Ӌ70m`[P9ii~r0~}디 \\}VX5@>@ө?5K4)gkjR~jN[W\$rSZ]Kv{[P'OixOmJf%\0S'p ,K<RP`\\Գ@]gyR\\8h `R'7HBc(7f1c\0wMo3sG@`7zgFP\"(@mƐH:N3>eK:t%,(LMEAVOM:q5E%-)@jچSLME>dAesAz7D\nه.J\r5lK\0nt@\n2:?V\"5lɭ&SQ[ }\0سK>tG0T:\nj!Y+!¶ (-mj!\njʹ(EЩ!5@J}6҅T+A&bZVE6iΞK8BcaY(_'QW %`\$}n\\3-4Nԡ5EPᎆsJ\"ܽP* h҇+?SUbwfHt'/\\x\nr\riFT=y5PAdE:(RPQ S-84OU?ʹ3x`G=gKPb 'xBk8.b4FV%UXkJxQ\nǃ/TFa\0m_eF\"!ꚇ\rYm1F2Rp IhĵG(zZ3hϸm>hss4dsфQfq\0NQ2X5ݠDՎ5шTpk-B\"ʜ_ѹ^n}ަthqqG8S-sQĢ>|+:-˓∖hU-x4IΓmGhG0U>B4.ZM9[I`P:Cbs\nu(V\ns%T֣P'B|3DRQ\n]?6aT_O̤xC90Q5I\n,TTqC @*5JMITIy>Ji&\n[I1M\rc夘jycy:N㞗BM*t6ieϫ\nӱyz\njR\"tJ/; h>|f\0ZrCez&k`p \0s.\$t\$S#DM4xCU)W҄\0J*jV\0*\0\0Jlb\0`ZףvTM=I'D_ZW糸P+\n2NGS\"f\$j6V65pT>3ZXk");}else{header("Content-Type: image/gif");switch($_GET["file"]){case"plus.gif":echo"GIF89a\0\0\0001\0\0\0\0\0!\0\0\0,\0\0\0\0\0\0!M*)o) qe#L\0;";break;case"cross.gif":echo"GIF89a\0\0\0001\0\0\0\0\0!\0\0\0,\0\0\0\0\0\0##\naFo~y._wa1JGL6]\0\0;";break;case"up.gif":echo"GIF89a\0\0\0001\0\0\0\0\0!\0\0\0,\0\0\0\0\0\0 MQN\n}a8yaŶ\0\0;";break;case"down.gif":echo"GIF89a\0\0\0001\0\0\0\0\0!\0\0\0,\0\0\0\0\0\0 M*)[W\\L&ٜƶ\0\0;";break;case"arrow.gif":echo"GIF89a\0\n\0\0\0!\0\0\0,\0\0\0\0\0\n\0\0iӲ\0\0;";break;}}exit;}function
+connection(){global$h;return$h;}function
+adminer(){global$b;return$b;}function
+idf_unescape($t){$Qd=substr($t,-1);return
+str_replace($Qd.$Qd,$Qd,substr($t,1,-1));}function
+escape_string($X){return
+substr(q($X),1,-1);}function
+number($X){return
+preg_replace('~[^0-9]+~','',$X);}function
+remove_slashes($If,$Jc=false){if(get_magic_quotes_gpc()){while(list($x,$X)=each($If)){foreach($X
+as$Gd=>$W){unset($If[$x][$Gd]);if(is_array($W)){$If[$x][stripslashes($Gd)]=$W;$If[]=&$If[$x][stripslashes($Gd)];}else$If[$x][stripslashes($Gd)]=($Jc?$W:stripslashes($W));}}}}function
+bracket_escape($t,$Na=false){static$th=array(':'=>':1',']'=>':2','['=>':3');return
+strtr($t,($Na?array_flip($th):$th));}function
+charset($h){return(version_compare($h->server_info,"5.5.3")>=0?"utf8mb4":"utf8");}function
+h($P){return
+str_replace("\0","",htmlspecialchars($P,ENT_QUOTES,'utf-8'));}function
+nbsp($P){return(trim($P)!=""?h($P):" ");}function
+nl_br($P){return
+str_replace("\n"," ",$P);}function
+checkbox($C,$Y,$db,$Nd="",$Pe="",$ib=""){$J=" ";return($Nd!=""||$ib?"$J".h($Nd)." ":$J);}function
+optionlist($Ve,$tg=null,$Oh=false){$J="";foreach($Ve
+as$Gd=>$W){$We=array($Gd=>$W);if(is_array($W)){$J.='';$We=$W;}foreach($We
+as$x=>$X)$J.=''.h($X);if(is_array($W))$J.=' ';}return$J;}function
+html_select($C,$Ve,$Y="",$Oe=true){if($Oe)return"".optionlist($Ve,$Y)." ";$J="";foreach($Ve
+as$x=>$X)$J.=" ".h($X)." ";return$J;}function
+select_input($Ja,$Ve,$Y="",$vf=""){return($Ve?"$vf".optionlist($Ve,$Y,true)." ":" ");}function
+confirm(){return" onclick=\"return confirm('".lang(0)."');\"";}function
+print_fieldset($jd,$Vd,$Zh=false,$Pe=""){echo"$Vd \n";}function
+bold($Va,$ib=""){return($Va?" class='active $ib'":($ib?" class='$ib'":""));}function
+odd($J=' class="odd"'){static$s=0;if(!$J)$s=-1;return($s++%2?$J:'');}function
+js_escape($P){return
+addcslashes($P,"\r\n'\\/");}function
+json_row($x,$X=null){static$Kc=true;if($Kc)echo"{";if($x!=""){echo($Kc?"":",")."\n\t\"".addcslashes($x,"\r\n\"\\/").'": '.($X!==null?'"'.addcslashes($X,"\r\n\"\\/").'"':'undefined');$Kc=false;}else{echo"\n}\n";$Kc=true;}}function
+ini_bool($td){$X=ini_get($td);return(preg_match('~^(on|true|yes)$~i',$X)||(int)$X);}function
+sid(){static$J;if($J===null)$J=(SID&&!($_COOKIE&&ini_bool("session.use_cookies")));return$J;}function
+set_password($Vh,$N,$V,$G){$_SESSION["pwds"][$Vh][$N][$V]=($_COOKIE["adminer_key"]&&is_string($G)?array(encrypt_string($G,$_COOKIE["adminer_key"])):$G);}function
+get_password(){$J=get_session("pwds");if(is_array($J))$J=($_COOKIE["adminer_key"]?decrypt_string($J[0],$_COOKIE["adminer_key"]):false);return$J;}function
+q($P){global$h;return$h->quote($P);}function
+get_vals($H,$e=0){global$h;$J=array();$I=$h->query($H);if(is_object($I)){while($K=$I->fetch_row())$J[]=$K[$e];}return$J;}function
+get_key_vals($H,$i=null,$jh=0){global$h;if(!is_object($i))$i=$h;$J=array();$i->timeout=$jh;$I=$i->query($H);$i->timeout=0;if(is_object($I)){while($K=$I->fetch_row())$J[$K[0]]=$K[1];}return$J;}function
+get_rows($H,$i=null,$n="
"){global$h;$ub=(is_object($i)?$i:$h);$J=array();$I=$ub->query($H);if(is_object($I)){while($K=$I->fetch_assoc())$J[]=$K;}elseif(!$I&&!is_object($i)&&$n&&defined("PAGE_HEADER"))echo$n.error()."\n";return$J;}function
+unique_array($K,$v){foreach($v
+as$u){if(preg_match("~PRIMARY|UNIQUE~",$u["type"])){$J=array();foreach($u["columns"]as$x){if(!isset($K[$x]))continue
+2;$J[$x]=$K[$x];}return$J;}}}function
+escape_key($x){if(preg_match('(^([\w(]+)('.str_replace("_",".*",preg_quote(idf_escape("_"))).')([ \w)]+)$)',$x,$B))return$B[1].idf_escape(idf_unescape($B[2])).$B[3];return
+idf_escape($x);}function
+where($Z,$p=array()){global$h,$w;$J=array();foreach((array)$Z["where"]as$x=>$X){$x=bracket_escape($x,1);$e=escape_key($x);$J[]=$e.(($w=="sql"&&preg_match('~^[0-9]*\\.[0-9]*$~',$X))||$w=="mssql"?" LIKE ".q(addcslashes($X,"%_\\")):" = ".unconvert_field($p[$x],q($X)));if($w=="sql"&&preg_match('~char|text~',$p[$x]["type"])&&preg_match("~[^ -@]~",$X))$J[]="$e = ".q($X)." COLLATE ".charset($h)."_bin";}foreach((array)$Z["null"]as$x)$J[]=escape_key($x)." IS NULL";return
+implode(" AND ",$J);}function
+where_check($X,$p=array()){parse_str($X,$bb);remove_slashes(array(&$bb));return
+where($bb,$p);}function
+where_link($s,$e,$Y,$Re="="){return"&where%5B$s%5D%5Bcol%5D=".urlencode($e)."&where%5B$s%5D%5Bop%5D=".urlencode(($Y!==null?$Re:"IS NULL"))."&where%5B$s%5D%5Bval%5D=".urlencode($Y);}function
+convert_fields($f,$p,$M=array()){$J="";foreach($f
+as$x=>$X){if($M&&!in_array(idf_escape($x),$M))continue;$Ga=convert_field($p[$x]);if($Ga)$J.=", $Ga AS ".idf_escape($x);}return$J;}function
+cookie($C,$Y,$Xd=2592000){global$ba;$F=array($C,(preg_match("~\n~",$Y)?"":$Y),($Xd?time()+$Xd:0),preg_replace('~\\?.*~','',$_SERVER["REQUEST_URI"]),"",$ba);if(version_compare(PHP_VERSION,'5.2.0')>=0)$F[]=true;return
+call_user_func_array('setcookie',$F);}function
+restart_session(){if(!ini_bool("session.use_cookies"))session_start();}function
+stop_session(){if(!ini_bool("session.use_cookies"))session_write_close();}function&get_session($x){return$_SESSION[$x][DRIVER][SERVER][$_GET["username"]];}function
+set_session($x,$X){$_SESSION[$x][DRIVER][SERVER][$_GET["username"]]=$X;}function
+auth_url($Vh,$N,$V,$m=null){global$Xb;preg_match('~([^?]*)\\??(.*)~',remove_from_uri(implode("|",array_keys($Xb))."|username|".($m!==null?"db|":"").session_name()),$B);return"$B[1]?".(sid()?SID."&":"").($Vh!="server"||$N!=""?urlencode($Vh)."=".urlencode($N)."&":"")."username=".urlencode($V).($m!=""?"&db=".urlencode($m):"").($B[2]?"&$B[2]":"");}function
+is_ajax(){return($_SERVER["HTTP_X_REQUESTED_WITH"]=="XMLHttpRequest");}function
+redirect($A,$me=null){if($me!==null){restart_session();$_SESSION["messages"][preg_replace('~^[^?]*~','',($A!==null?$A:$_SERVER["REQUEST_URI"]))][]=$me;}if($A!==null){if($A=="")$A=".";header("Location: $A");exit;}}function
+query_redirect($H,$A,$me,$Sf=true,$wc=true,$Dc=false,$ih=""){global$h,$n,$b;if($wc){$Hg=microtime(true);$Dc=!$h->query($H);$ih=format_time($Hg);}$Fg="";if($H)$Fg=$b->messageQuery($H,$ih);if($Dc){$n=error().$Fg;return
+false;}if($Sf)redirect($A,$me.$Fg);return
+true;}function
+queries($H){global$h;static$Mf=array();static$Hg;if(!$Hg)$Hg=microtime(true);if($H===null)return
+array(implode("\n",$Mf),format_time($Hg));$Mf[]=(preg_match('~;$~',$H)?"DELIMITER ;;\n$H;\nDELIMITER ":$H).";";return$h->query($H);}function
+apply_queries($H,$S,$sc='table'){foreach($S
+as$Q){if(!queries("$H ".$sc($Q)))return
+false;}return
+true;}function
+queries_redirect($A,$me,$Sf){list($Mf,$ih)=queries(null);return
+query_redirect($Mf,$A,$me,$Sf,false,!$Sf,$ih);}function
+format_time($Hg){return
+lang(1,max(0,microtime(true)-$Hg));}function
+remove_from_uri($jf=""){return
+substr(preg_replace("~(?<=[?&])($jf".(SID?"":"|".session_name()).")=[^&]*&~",'',"$_SERVER[REQUEST_URI]&"),0,-1);}function
+pagination($E,$Db){return" ".($E==$Db?$E+1:''.($E+1)." ");}function
+get_file($x,$Kb=false){$Hc=$_FILES[$x];if(!$Hc)return
+null;foreach($Hc
+as$x=>$X)$Hc[$x]=(array)$X;$J='';foreach($Hc["error"]as$x=>$n){if($n)return$n;$C=$Hc["name"][$x];$qh=$Hc["tmp_name"][$x];$wb=file_get_contents($Kb&&preg_match('~\\.gz$~',$C)?"compress.zlib://$qh":$qh);if($Kb){$Hg=substr($wb,0,3);if(function_exists("iconv")&&preg_match("~^\xFE\xFF|^\xFF\xFE~",$Hg,$Yf))$wb=iconv("utf-16","utf-8",$wb);elseif($Hg=="\xEF\xBB\xBF")$wb=substr($wb,3);$J.=$wb."\n\n";}else$J.=$wb;}return$J;}function
+upload_error($n){$je=($n==UPLOAD_ERR_INI_SIZE?ini_get("upload_max_filesize"):0);return($n?lang(2).($je?" ".lang(3,$je):""):lang(4));}function
+repeat_pattern($tf,$y){return
+str_repeat("$tf{0,65535}",$y/65535)."$tf{0,".($y%65535)."}";}function
+is_utf8($X){return(preg_match('~~u',$X)&&!preg_match('~[\\0-\\x8\\xB\\xC\\xE-\\x1F]~',$X));}function
+shorten_utf8($P,$y=80,$Og=""){if(!preg_match("(^(".repeat_pattern("[\t\r\n -\x{FFFF}]",$y).")($)?)u",$P,$B))preg_match("(^(".repeat_pattern("[\t\r\n -~]",$y).")($)?)",$P,$B);return
+h($B[1]).$Og.(isset($B[2])?"":"... ");}function
+format_number($X){return
+strtr(number_format($X,0,".",lang(5)),preg_split('~~u',lang(6),-1,PREG_SPLIT_NO_EMPTY));}function
+friendly_url($X){return
+preg_replace('~[^a-z0-9_]~i','-',$X);}function
+hidden_fields($If,$md=array()){while(list($x,$X)=each($If)){if(!in_array($x,$md)){if(is_array($X)){foreach($X
+as$Gd=>$W)$If[$x."[$Gd]"]=$W;}else
+echo' ';}}}function
+hidden_fields_get(){echo(sid()?' ':''),(SERVER!==null?' ':""),' ';}function
+table_status1($Q,$Ec=false){$J=table_status($Q,$Ec);return($J?$J:array("Name"=>$Q));}function
+column_foreign_keys($Q){global$b;$J=array();foreach($b->foreignKeys($Q)as$q){foreach($q["source"]as$X)$J[$X][]=$q;}return$J;}function
+enum_input($U,$Ja,$o,$Y,$mc=null){global$b;preg_match_all("~'((?:[^']|'')*)'~",$o["length"],$ee);$J=($mc!==null?"".lang(7)." ":"");foreach($ee[1]as$s=>$X){$X=stripcslashes(str_replace("''","'",$X));$db=(is_int($Y)?$Y==$s+1:(is_array($Y)?in_array($s+1,$Y):$Y===$X));$J.=" '.h($b->editVal($X,$o)).' ';}return$J;}function
+input($o,$Y,$r){global$h,$Bh,$b,$w;$C=h(bracket_escape($o["field"]));echo"
";if(is_array($Y)&&!$r){$Ea=array($Y);if(version_compare(PHP_VERSION,5.4)>=0)$Ea[]=JSON_PRETTY_PRINT;$Y=call_user_func_array('json_encode',$Ea);$r="json";}$bg=($w=="mssql"&&$o["auto_increment"]);if($bg&&!$_POST["save"])$r=null;$Uc=(isset($_GET["select"])||$bg?array("orig"=>lang(8)):array())+$b->editFunctions($o);$Ja=" name='fields[$C]'";if($o["type"]=="enum")echo
+nbsp($Uc[""])." ".$b->editInput($_GET["edit"],$o,$Ja,$Y);else{$Kc=0;foreach($Uc
+as$x=>$X){if($x===""||!$X)break;$Kc++;}$Oe=($Kc?" onchange=\"var f = this.form['function[".h(js_escape(bracket_escape($o["field"])))."]']; if ($Kc > f.selectedIndex) f.selectedIndex = $Kc;\" onkeyup='keyupChange.call(this);'":"");$Ja.=$Oe;$cd=(in_array($r,$Uc)||isset($Uc[$r]));echo(count($Uc)>1?"".optionlist($Uc,$r===null||$cd?$r:"")." ":nbsp(reset($Uc))).' ';$vd=$b->editInput($_GET["edit"],$o,$Ja,$Y);if($vd!="")echo$vd;elseif($o["type"]=="set"){preg_match_all("~'((?:[^']|'')*)'~",$o["length"],$ee);foreach($ee[1]as$s=>$X){$X=stripcslashes(str_replace("''","'",$X));$db=(is_int($Y)?($Y>>$s)&1:in_array($X,explode(",",$Y),true));echo" ".h($b->editVal($X,$o)).' ';}}elseif(preg_match('~blob|bytea|raw|file~',$o["type"])&&ini_bool("file_uploads"))echo" ";elseif(($gh=preg_match('~text|lob~',$o["type"]))||preg_match("~\n~",$Y)){if($gh&&$w!="sqlite")$Ja.=" cols='50' rows='12'";else{$L=min(12,substr_count($Y,"\n")+1);$Ja.=" cols='30' rows='$L'".($L==1?" style='height: 1.2em;'":"");}echo"';}elseif($r=="json")echo"';else{$le=(!preg_match('~int~',$o["type"])&&preg_match('~^(\\d+)(,(\\d+))?$~',$o["length"],$B)?((preg_match("~binary~",$o["type"])?2:1)*$B[1]+($B[3]?1:0)+($B[2]&&!$o["unsigned"]?1:0)):($Bh[$o["type"]]?$Bh[$o["type"]]+($o["unsigned"]?0:1):0));if($w=='sql'&&$h->server_info>=5.6&&preg_match('~time~',$o["type"]))$le+=7;echo" 20?" size='40'":"")."$Ja>";}}}function
+process_input($o){global$b;$t=bracket_escape($o["field"]);$r=$_POST["function"][$t];$Y=$_POST["fields"][$t];if($o["type"]=="enum"){if($Y==-1)return
+false;if($Y=="")return"NULL";return+$Y;}if($o["auto_increment"]&&$Y=="")return
+null;if($r=="orig")return($o["on_update"]=="CURRENT_TIMESTAMP"?idf_escape($o["field"]):false);if($r=="NULL")return"NULL";if($o["type"]=="set")return
+array_sum((array)$Y);if($r=="json"){$r="";$Y=json_decode($Y,true);if(!is_array($Y))return
+false;return$Y;}if(preg_match('~blob|bytea|raw|file~',$o["type"])&&ini_bool("file_uploads")){$Hc=get_file("fields-$t");if(!is_string($Hc))return
+false;return
+q($Hc);}return$b->processInput($o,$Y,$r);}function
+fields_from_edit(){global$Wb;$J=array();foreach((array)$_POST["field_keys"]as$x=>$X){if($X!=""){$X=bracket_escape($X);$_POST["function"][$X]=$_POST["field_funs"][$x];$_POST["fields"][$X]=$_POST["field_vals"][$x];}}foreach((array)$_POST["fields"]as$x=>$X){$C=bracket_escape($x,1);$J[$C]=array("field"=>$C,"privileges"=>array("insert"=>1,"update"=>1),"null"=>1,"auto_increment"=>($x==$Wb->primary),);}return$J;}function
+search_tables(){global$b,$h;$_GET["where"][0]["op"]="LIKE %%";$_GET["where"][0]["val"]=$_POST["query"];$Qc=false;foreach(table_status('',true)as$Q=>$R){$C=$b->tableName($R);if(isset($R["Engine"])&&$C!=""&&(!$_POST["tables"]||in_array($Q,$_POST["tables"]))){$I=$h->query("SELECT".limit("1 FROM ".table($Q)," WHERE ".implode(" AND ",$b->selectSearchProcess(fields($Q),array())),1));if(!$I||$I->fetch_row()){if(!$Qc){echo"\n";$Qc=true;}echo"".($I?"$C \n":"$C: ".error()." \n");}}}echo($Qc?" ":"".lang(9))."\n";}function
+dump_headers($kd,$ve=false){global$b;$J=$b->dumpHeaders($kd,$ve);$hf=$_POST["output"];if($hf!="text")header("Content-Disposition: attachment; filename=".$b->dumpFilename($kd).".$J".($hf!="file"&&!preg_match('~[^0-9a-z]~',$hf)?".$hf":""));session_write_close();ob_flush();flush();return$J;}function
+dump_csv($K){foreach($K
+as$x=>$X){if(preg_match("~[\"\n,;\t]~",$X)||$X==="")$K[$x]='"'.str_replace('"','""',$X).'"';}echo
+implode(($_POST["format"]=="csv"?",":($_POST["format"]=="tsv"?"\t":";")),$K)."\r\n";}function
+apply_sql_function($r,$e){return($r?($r=="unixepoch"?"DATETIME($e, '$r')":($r=="count distinct"?"COUNT(DISTINCT ":strtoupper("$r("))."$e)"):$e);}function
+get_temp_dir(){$J=ini_get("upload_tmp_dir");if(!$J){if(function_exists('sys_get_temp_dir'))$J=sys_get_temp_dir();else{$Ic=@tempnam("","");if(!$Ic)return
+false;$J=dirname($Ic);unlink($Ic);}}return$J;}function
+password_file($j){$Ic=get_temp_dir()."/adminer.key";$J=@file_get_contents($Ic);if($J||!$j)return$J;$Sc=@fopen($Ic,"w");if($Sc){chmod($Ic,0660);$J=rand_string();fwrite($Sc,$J);fclose($Sc);}return$J;}function
+rand_string(){return
+md5(uniqid(mt_rand(),true));}function
+select_value($X,$_,$o,$hh){global$b,$ba;if(is_array($X)){$J="";foreach($X
+as$Gd=>$W)$J.="
".($X!=array_values($X)?"".h($Gd):"")." ".select_value($W,$_,$o,$hh);return"";}if(!$_)$_=$b->selectLink($X,$o);if($_===null){if(is_mail($X))$_="mailto:$X";if($Kf=is_url($X))$_=(($Kf=="http"&&$ba)||preg_match('~WebKit~i',$_SERVER["HTTP_USER_AGENT"])?$X:"$Kf://www.adminer.org/redirect/?url=".urlencode($X));}$J=$b->editVal($X,$o);if($J!==null){if($J==="")$J=" ";elseif(!is_utf8($J))$J="\0";elseif($hh!=""&&is_shortable($o))$J=shorten_utf8($J,max(0,+$hh));else$J=h($J);}return$b->selectVal($J,$_,$o,$X);}function
+is_mail($jc){$Ha='[-a-z0-9!#$%&\'*+/=?^_`{|}~]';$Vb='[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])';$tf="$Ha+(\\.$Ha+)*@($Vb?\\.)+$Vb";return
+is_string($jc)&&preg_match("(^$tf(,\\s*$tf)*\$)i",$jc);}function
+is_url($P){$Vb='[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])';return(preg_match("~^(https?)://($Vb?\\.)+$Vb(:\\d+)?(/.*)?(\\?.*)?(#.*)?\$~i",$P,$B)?strtolower($B[1]):"");}function
+is_shortable($o){return
+preg_match('~char|text|lob|geometry|point|linestring|polygon|string~',$o["type"]);}function
+count_rows($Q,$Z,$Ad,$Xc){global$w;$H=" FROM ".table($Q).($Z?" WHERE ".implode(" AND ",$Z):"");return($Ad&&($w=="sql"||count($Xc)==1)?"SELECT COUNT(DISTINCT ".implode(", ",$Xc).")$H":"SELECT COUNT(*)".($Ad?" FROM (SELECT 1$H$Yc) x":$H));}function
+slow_query($H){global$b,$T;$m=$b->database();$jh=$b->queryTimeout();if(support("kill")&&is_object($i=connect())&&($m==""||$i->select_db($m))){$Ld=$i->result("SELECT CONNECTION_ID()");echo'
+';}else$i=null;ob_flush();flush();$J=@get_key_vals($H,$i,$jh);if($i){echo"\n";ob_flush();flush();}return
+array_keys($J);}function
+get_token(){$Pf=rand(1,1e6);return($Pf^$_SESSION["token"]).":$Pf";}function
+verify_token(){list($T,$Pf)=explode(":",$_POST["token"]);return($Pf^$_SESSION["token"])==$T;}function
+lzw_decompress($Ra){$Rb=256;$Sa=8;$kb=array();$dg=0;$eg=0;for($s=0;$s=$Sa){$eg-=$Sa;$kb[]=$dg>>$eg;$dg&=(1<<$eg)-1;$Rb++;if($Rb>>$Sa)$Sa++;}}$Qb=range("\0","\xFF");$J="";foreach($kb
+as$s=>$jb){$ic=$Qb[$jb];if(!isset($ic))$ic=$di.$di[0];$J.=$ic;if($s)$Qb[]=$di.$ic[0];$di=$ic;}return$J;}function
+on_help($pb,$Ag=0){return" onmouseover='helpMouseover(this, event, ".h($pb).", $Ag);' onmouseout='helpMouseout(this, event);'";}function
+edit_form($a,$p,$K,$Jh){global$b,$w,$T,$n;$Tg=$b->tableName(table_status1($a,true));page_header(($Jh?lang(10):lang(11)),$n,array("select"=>array($a,$Tg)),$Tg);if($K===false)echo"".lang(12)."\n";echo'
+';}global$b,$h,$Xb,$fc,$pc,$n,$Uc,$Zc,$ba,$ud,$w,$ca,$Pd,$Ne,$uf,$Lg,$dd,$T,$vh,$Bh,$Ih,$ia;if(!$_SERVER["REQUEST_URI"])$_SERVER["REQUEST_URI"]=$_SERVER["ORIG_PATH_INFO"];if(!strpos($_SERVER["REQUEST_URI"],'?')&&$_SERVER["QUERY_STRING"]!="")$_SERVER["REQUEST_URI"].="?$_SERVER[QUERY_STRING]";$ba=$_SERVER["HTTPS"]&&strcasecmp($_SERVER["HTTPS"],"off");@ini_set("session.use_trans_sid",false);session_cache_limiter("");if(!defined("SID")){session_name("adminer_sid");$F=array(0,preg_replace('~\\?.*~','',$_SERVER["REQUEST_URI"]),"",$ba);if(version_compare(PHP_VERSION,'5.2.0')>=0)$F[]=true;call_user_func_array('session_set_cookie_params',$F);session_start();}remove_slashes(array(&$_GET,&$_POST,&$_COOKIE),$Jc);if(get_magic_quotes_runtime())set_magic_quotes_runtime(false);@set_time_limit(0);@ini_set("zend.ze1_compatibility_mode",false);@ini_set("precision",20);$Pd=array('en'=>'English','ar'=>'العربية','bn'=>'বাংলা','ca'=>'Català','cs'=>'Čeština','da'=>'Dansk','de'=>'Deutsch','es'=>'Español','et'=>'Eesti','fa'=>'فارسی','fr'=>'Français','hu'=>'Magyar','id'=>'Bahasa Indonesia','it'=>'Italiano','ja'=>'日本語','ko'=>'한국어','lt'=>'Lietuvių','nl'=>'Nederlands','no'=>'Norsk','pl'=>'Polski','pt'=>'Português','pt-br'=>'Português (Brazil)','ro'=>'Limba Română','ru'=>'Русский язык','sk'=>'Slovenčina','sl'=>'Slovenski','sr'=>'Српски','ta'=>'தமிழ்','th'=>'ภาษาไทย','tr'=>'Türkçe','uk'=>'Українська','vi'=>'Tiếng Việt','zh'=>'简体中文','zh-tw'=>'繁體中文',);function
+get_lang(){global$ca;return$ca;}function
+lang($t,$Ee=null){if(is_string($t)){$xf=array_search($t,get_translations("en"));if($xf!==false)$t=$xf;}global$ca,$vh;$uh=($vh[$t]?$vh[$t]:$t);if(is_array($uh)){$xf=($Ee==1?0:($ca=='cs'||$ca=='sk'?($Ee&&$Ee<5?1:2):($ca=='fr'?(!$Ee?0:1):($ca=='pl'?($Ee%10>1&&$Ee%10<5&&$Ee/10%10!=1?1:2):($ca=='sl'?($Ee%100==1?0:($Ee%100==2?1:($Ee%100==3||$Ee%100==4?2:3))):($ca=='lt'?($Ee%10==1&&$Ee%100!=11?0:($Ee%10>1&&$Ee/10%10!=1?1:2)):($ca=='ru'||$ca=='sr'||$ca=='uk'?($Ee%10==1&&$Ee%100!=11?0:($Ee%10>1&&$Ee%10<5&&$Ee/10%10!=1?1:2)):1)))))));$uh=$uh[$xf];}$Ea=func_get_args();array_shift($Ea);$Pc=str_replace("%d","%s",$uh);if($Pc!=$uh)$Ea[0]=format_number($Ee);return
+vsprintf($Pc,$Ea);}function
+switch_lang(){global$ca,$Pd;echo"\n";}if(isset($_POST["lang"])&&verify_token()){cookie("adminer_lang",$_POST["lang"]);$_SESSION["lang"]=$_POST["lang"];$_SESSION["translations"]=array();redirect(remove_from_uri());}$ca="en";if(isset($Pd[$_COOKIE["adminer_lang"]])){cookie("adminer_lang",$_COOKIE["adminer_lang"]);$ca=$_COOKIE["adminer_lang"];}elseif(isset($Pd[$_SESSION["lang"]]))$ca=$_SESSION["lang"];else{$ua=array();preg_match_all('~([-a-z]+)(;q=([0-9.]+))?~',str_replace("_","-",strtolower($_SERVER["HTTP_ACCEPT_LANGUAGE"])),$ee,PREG_SET_ORDER);foreach($ee
+as$B)$ua[$B[1]]=(isset($B[3])?$B[3]:1);arsort($ua);foreach($ua
+as$x=>$Lf){if(isset($Pd[$x])){$ca=$x;break;}$x=preg_replace('~-.*~','',$x);if(!isset($ua[$x])&&isset($Pd[$x])){$ca=$x;break;}}}$vh=&$_SESSION["translations"];if($_SESSION["translations_version"]!=646742810){$vh=array();$_SESSION["translations_version"]=646742810;}function
+get_translations($Od){switch($Od){case"en":$g="A9Dy@s:G(ff :Sa2\"1..L'Im#s,KOP#I@%9i4o2ύ,9%Pb2ar\n2NC(r41C`(:Eb9Ai:&㙔yFY\r\n 8ZS=\$A`=܌0\ndF n:Zΰ)QAk}eADaį\\}5#|@h3N}@i˞Nt~9B؍8:-pKX9,p:8(\0(@-BƎN@.9#3Ӊz7:ތ@F.1\r\"\"ӈ#c:9;RТ<;چ\$#!,32ȀP:#ʾK#8Ac7 -BμH3£ǣ;,|:Rp9mP(\\6md:ƀ-M,KA#FN_TvhK.#gfXx2Q`P<2v.X)ٶ:!2J [3bѹq\nz5V(&3TlO[~7'3pt.xN%-MA67V\nJP\rb#2x;̳j֔F=\nNN64J2b(e8Ɯ7% TA*\\ZЀD4xf8Ǽcs^4#*:oB,ލa}mU|Ē:GQaZ8\\.\\K\"P˼qE\0\$\n[ȼ\0P)g)3EwUkc0RX&ʞ^t)+2'}MIE:'UvAz\"rBRi}i|lf0d GKdx@L(d ¢F-)Tg21yIP8@UF䟍zkؘPQ3\$x(X2\$ɒ07pI:#q ȳRFDpp \n@\"@Tx\"@o\r\"NXaC\nG\0|Sa`\$k옢3\$;e12ϞX\n3pJ]xU1_g2FYEE5͉͊<ę+7ZڥTbl9`K:A#@|\$i XS̫f\n1]YNaR#Qxo\nrʓ%a{)4@Keܫ]W2e\\́&tϹ^5{*_z?rkckr`! Mz4h3lB7xX.2joΨљCjN#ꖨV[t3)Sf48 >h2|؋I{즻Z-WaGId\rx)\r\nz(zS\\LJjf-% WdޣUf܃e(WyVQoW}곲36>g7Gګ]JPS}]\\|2_2@\$.ر2%&5\01Wڪ\"ٴ,L:J8Nƙ#6\r):)q́Q'dBX@ANnpEhX9/\"ΰĘfj\n _s\nbT߽y[@1d-4h_;Kq \\\"i\$ MUè67crcMp\0(eak!ֲD.l2pްM.Cg[\rШ0#\$!/BO}&&L!/10hW\$XRdF4b!X8VxLZ*\\sQ 2PQ\"1\$X/dbN[|BŢR\"=OXpFɩ4c M>7@`So}'Ղ\0IݼTMcTc\n<)BDT1J\n[&ZBtc\r2ZKiRtA,q\nnWB@%ǮxNT(@(\n \"Pi\0 GrP%CN>6H!j]L(Z D0h|l`1-Y/jԱY6Y50.;T+F@4~ښyI3Qfvk`Ta©TE-Jv1*ȑ-KYyeN@u#cV͠f7Z^Y(!'Mף }G|ϴBf{>OI&2F`5\$2W.0(\nr89)g2/c4kٔkUYM6TdCE!̍YOLPhJz(EVZ =j[ѓNO)KTO劦Kő\\ǔ:\nŘQ&:43a\$֚q>ǣ\$,\"6oB)ef'k`a/?B0Cg2)#8Ly8\"Aru\nHŁG|Le1`r .9F+sC=>fnҺ@/FpɴK?HI`\"x|P\n#etEw::_\nKBUSyR5fV^\\eB+G\"٩焏bqǷ6\n t,tPRI8J\"x+!t7'TI8a-PS\\ RM3աKLJ\$]*sfmvjQjiw3\$\$qtXV:p깺E@\n%S @ft:,u#}t'<1(<-#9(.=wJrIԢcvy?he'jڍIJ[u߿f_晗1߿8bs3<1z&L* C=,tZq>o=(j`!SğR#lQ\nc*|=˵& ?}jaK@Xe3*'-0\\M\\tEAa\"3NeU4yH/B1EqPQߢy'@1JjeNHEQyQa%q!s2/lfCUVg1|(Q\"Q^j M-gб\nqMl!qF\$g d'2AA-eiw>p*\$O\rx fNZ*䫎%B\"lzsB=ŀt`@i~\r \r`@*\nCohn\r o6&6\05.\nZ\0@u`&8,Wn`@\nS)J\$\$^#Y ,ZG&rW\rTbPR@N>P8HF p^H.hb(^'NFʬ. ށ#=3 `}^8c\"1\$[ jfT#3|sF5 5OeVQ=NQ5.F\n7V5_(iz\rnsjܑŪ]M\"Cnd\"]`<%YK/;kB^Q:N}\0Ҭ+\n@ \rkA'Aj:n+S4J&KL1Zޯe\"@m#5>S9e?3T.ēHG@lG \0t @\n`";break;case"bn":$g="S)\nt]\0_ XD)L@4l5BQp 9\n\0,hSE0ba%. H\0.b2nDe*DM,OJÐvх\$:IKg5U4L Nd!u>&a\\@'JxS4PDz.SE]R-ˇ1+|CXMJ|Y_Y7+'izWȓKnw*\r9\0wr<3`؍*PL_T\r6na1337thaP0pPg6@~@s07)\0C\naH#)fkKq)bVQ/A4.zړwdj4ܝ[[f:TC\\(^I\0`/XJ1r=9pe4 \0<'`z@t^@.!*t2:\r!k'.t}9I\r٪/ ){:>P0Cg\nb%E`?]aQR6II\$RPgITdJEtP AS!Yޑ\0P\\LrG\rr\"))yPfy(f6WAҺMaDKQ g(hSN-X\n!҅I,bY\0Ҋ7Dfo7%e;^Č-_;G4@C՟GB O7@fd(Gj\0,B6J\$x\0¡x\r`^wa\"kT~Y;\\),QvҼrN2A3\0\0f=K)cgAu@/D99]Dil@%bЮLFEңO3U`KtVEbp[X@[QOpѴS89KQA2`(v!5dFy16RZl/e*P\"N)]0X2NE1+6͒8\$*ř{&msj|y٢5DC\0!*(N-¾^\$ƒq\\vC/M-Kp攬AL wFtقbd\\)ޕRʴS}3Q#Vdt𣑳V^{qs ZML3%dwSPCeA·e=FlڔSE9#\rwF\"`}Cת`ݍWyIœq\r2RX(]l]t,cފzCJ)8^E1%5ZItڎr\r;OZdлFȦ9:_怲cqkyf=kkZUUu{uR\0zeU?~S7E\rtGm[vZWQRP;\\@xD^+Y`@s<<\0\r<Eֱ9vLlp-<(ucgjqv)L/st巑r>`\rhfuR\r,\0g@\r \n`C,|3?#\n~\n;oό(؋^B\\F\$^].x̳afgʂ̹Bk-CRLK&v3épt0Y\$l1\"P d\$SL\$y)n+OoM|)NS,,}tD\n2\r\$4쒠9I4\nb*\r#)`N(ˍ(9\nH0K !KD (+2 &?PH\"CP#\n7,-#zpEH4cJhŠ2an|4\rZ09#P&A(r1S!B1[CrG5K˴@ʡ9(CpEUsB2EY3L+%(1zR6\rx 㒍ZLibaVQ:( Ӥ[Y@ (hZL@)\"c\"1 ?OBY|L2S%1MRs`0C\rRM%5Q7\$6JUʼn\rk^B*P<\"Öj!w1L0'Bf6H SFҤ3(c<ь7Js31T82OĂ<8¼Z\raL.7n@!b29g\$:\nz<92\nbͨ+9E[3D9|bp;< 2@&C(3:t㿼#^.8^+!xEwM5A(sx>Ad 2lɨap\0ٓ1FBL'B6S;A(1+bzq/̘HLM!\00og(A\0PTAJBY3\$Ni/d@ Si,X`ԝ֊aH ~?FM\n1 \$D~R7v@SjAV@CU;L4V`aBW2TE ~u'pN&@\\pUEhpfˬ¤c>ӈ(mÊl:BD`a'g`I5mwLNRc1S%3lBa=;@HY\")`9 N2nmm(<MIbhL&;Pŕ*Aّsi}D|a1T!&lZIA!1d;[{ҝ@UdyF,cf>)c\$KlTK4C5rS~\\7nv@1{TFTTM6nO6]#Fc⳧uhg`((V \rF㞓{N-]R>Œ¯Qkm]Ok=,,ܸd(gkK'Ou0hɓnB.q)ӛrv4~[_\reT*{QO]PYI'l92YD{5![>]a](쇳\\Q?@üg}navͿ~<tۜo/O\0&e)>\ru.B+M3 f~q(Oe?˳<݀d|\"+6OLĔLQBd/p3A&ۣ^QʷmnׇYB\$wgz?+gy)ލ4_문eE\"s)\"83ODdl&0bPm+1I|5h*Z9Cc('(.fP ;GcD !yp&0J\nPPXЕ\npMP#Nb1*Rp\rpd.mn뜸+.Эpΐ-x뎠EFP@DP0'>.<\r\"b \r\"nGOi:Y'\n\$TQUP)-fmj<@\$1z0+ǔ(#NOUOHHb\n@H i\nM zJ&\nw&,g:@#\nZk~iCOu 2Dfg\\^VHhs-ʳ>+%i<1?cK1kCqL(BM1e\$(vdq:`&6^n2\rƭ>DƮJd\ndSl>)k)ke*cy*OzN\n6C5PC&r#DfeP*dps)SRjX-Ȕj'3\0\\-\"\"\0xY!MeEB^MC-@W-\\?=2/\"2\0003\0qrsi\$RJM+/7xs0\r345:NP\$f \\0bEC\0O` \0t @\n`";break;case"cs":$g="O8'c!~\nfaN2\rC2i6Qh90'Hib7ii6ȍA;͆Y@v2\r&yHsJGQ8%9e:L:e2Zt@\nFC1l7AP4Tت;j\nbdWeHa1M̬Ne^/J-{JplPDle2bcu:F\rbʻP77LDn[?j1FU5/r(?y\$ߝִͦJMxɊ(So\04u=\n 1c(*\n99*^Xa8 QF&0B#Z:0)02 1P4L\niRB874Ƣ=#l:)*406ǃ(P! P2C|Jְlj(\"H#z9Ƣ0K4i.69C{M㢖5X(\r\r%5}#If\rcպp5ā(CUe]\rV]Z.o`@1b07\rq 3LP@P2@;JԱs84d&&0m<ȃ`1ANPI∘mP=Xm4\$v471c{;_[77J7PNu!Ib=)ē8ѐGR 3HB۱ؒ6C\"d]{V-NTC\rSΣ30̡\r*V'j;\07\rPk@N辽=`@=mI[#lp6Nñ;.ϴ붕}Mko~@_76/\r~\"[fݸOC>s?:3HF:&5\0)B0\\k+C2R6S3v14Z4;8)Ps77wvqQN+O6=ᶂY4ͨ4&F\n{Do<@C0=A:@x/-wFq)10^VOn}%:0A|1\"57탠xa͙2T\$ᑂ4 ;}8fqV1zI :OOz;LBC!E5qa}\0\"Ag\0P @G+H@kc'|80B<&y'g#I;xUFtM^xZi}PJT*55BO1\\bDt\r- v/a+]I?((\\\0£-/僧Ŋ(n&\rz~4ppi;c(ŧVq5II9V\rǣ8G\"7l7bHڃN ]+@0Cd:\$URjv\$H68iM\"M\$4ӑBrf} :TZK\$UDTtVHE[R\$ id=E-;ǀVt1\$Q6\r'JsD4GQbVfU)9Y=:y1v2{hDtՒkJ-:JIhyD1A\\9NLFGT+ONQ.- 6\nd\rC.QCPJzGHRb}VY+c!ͥIdWVPFje`)-\0X_7!дjA\rL\$|My9SZq0G9aBqUŘ'DlgH%5)̯a=0CͩdZPQC\rآ}XթlO<_ r&VkVMQ٫n&NؗΏSUTf}/J uI9h}sF͑(V:e&8d̫q&)v%jYhfx4^v\rOQgٚumF>wӳT-I32!~pFBFTpN܄T̂sYRĞVVK\nnG\0w27MpSi7-kԕ\n̶VJ1)Ir\0dL9;54~7Φ;Us_4ҤHs '*c)MQVJt~꤯^Ӳu#j/l\neu&ى'pC@())i\n혆L:X/بDaHwZ4\0A\n\0QJ\$>&;2zGR Lכ`G9\rLv?MiP~]v]f1_~pSziw)d쯬>|wSyi_:E'tBL\$WĴZrҎKY \r*0.0E4C#<Lzבm\r,H,p\0t#R4rm\r.G %`#'<6,0cF3@P<c\$\n\"`Z5\07B걄ƞL1B{e/#K%s0Y愲 P-0v>(-/H8R\rmphZPpsIӨBނ-(3R6*\r,j%QCjn12\$J9V49\$S:[0\\@4'0z\rxDžd8^rkOp^.:pęXD]`D!^0(@,ilcv\0ΝY2]*;z6۫B6DR۬N1-qϸ*It˳a\0\$\nn%'(JLOrg,힗 @Jk\ry4~IQ,%}!=0O-5szZBjͬ3C[Ȉy`4ދM&'OX)afÃ+a䤕¡F /d\rڨ\"+Q;'zTiJΔNc\0k2Dpt\\ü\nj\\F\nAHan \"28拀e\0R^)CP*YL E V>EPaE˝({e/\nm;2FDhCm@_0@Ls0lL8Is\rG3xo\\.2j\n\"jӰI3~s9t<ϙ%\0Ru(td;}F\n#tp\$J?JZR@Ξ\"inBZ\"0:+VZJ\0d\rV\rc\rmlw>4-f4ZzC=0\nu\$bPNM6z*Imڸ0I\"0hEz/bfB7bcx/bUox,5/Bjf~\0U#v⢠R\"0剞4(=BӃW F:Б>MBi줌P6[p\r{/^2I[\"0rKQ)<2U@ @M`%HA%qT2٢B/RD)\"9)\$K ,ЭA)䠧&Cl'0TdqomחByNE>'fv.sHv!.iga}˰g~qmFu14c\r+s|CX0KXS-'N3-xd<;jTW8!ӳC3~kwnY{2X_QYggq[4|B:[D(/Z\r^%O\r0ξ,4,&£,xCPBL`E,P0ΑR)DQNwLPl>6@\0M>yH8Ə>f/0n\0Vl\0S p{kЂ@3:(f\nC\"`WRK` SNK1\n#@ 9@BC1#\r\\ÐV>RL6Sm1qn:Y1\\fDf01~A*Cdr|\"*L\"I>=\r\$\nPGTny\rOʙ\rଇ\0sph\r+, fY6)Αͤ;G6&T4vLB\0P qx^E\n;\r@@\"Z*~BOȆ`\np4B0lȂp-o,Ԥ;&-dLiHn>\$\"T˃c\0=`4Jr6.@~r8c>G@#D Rإ\\cH@\rŌ\\q^##.<\$R\$!J0n?/\r#g.)';\0m@0s\$0S)*O1jKlB#<!Hq2>R\06ilJ+f3-M-\$.AP?\04+tJ˹\r###Rd\$/I/\r_M@,b\")DˌMQvT6>gSxˣȎu@N <fqϸprcq\n)}#u]ri&fvIࢩP :\"\nؿ2ô4J?jҫ&Bҍ#\n\n9H\"kP2P2ۂ4-!*O4@)9MapØ1/I204svxGjsRk'5&\rCRc\n{pM\r.tˮK,:c0,\nå\r*D0L#߶p:,pxJ24CQ,\rKF34IYns p9FLB9k;M@CTՁy(+fi! gdp!K&-\$`H\0'ଉ)\0MTMPHL2ӆG,TMaRC/=A{ԧUd%aa+P\\p+AONx#jP+AZQzڪi{8'WWJ[`aؿ',+!6SY Լ[ɞU1 \rA2LXgΕ@9=r\"RbJqD(*GbP9T'b(h-;C-,>B\n ][.9jP&e6\n|k|T+Nv뭵\\lR7Gglnբ6_WoI&[*hR=JN!\$}Ô {b[M0Ƨ<(kq#Ly +nm?Q %\nh^F\rt\\[d5H***wKlr6y\\ jOjL9&vAmY8LUs_ cs\$F?uk0\$8\r\r08|׳ݎ'vL@\"rKX6^ە=<|5.<qp\$۾q\$\0PIWv*!y'91 <6JT_wiy'pw[=m![S|B{_.Ηvloq&&w}\noϠ}ȩ-`Loj]t^I*@DHތ^|jdOfU[jp&<U4P\n[\$\$c\$\0qOJlHIY\0]0.pP0a\r} LHZ/J0H1>0,0%ʼeiPؼ:c0# kkw׀/ץ.Kv^\rO/D\$0Rc/,X\"bQ^JLy`Gh0|ۄ9B,`ldLo\\n\0\np#0b&LPȶL]L#D4#lъʈl\0ׯ\r0= 2JOƱn,J@ZrZŚ #a^DXOqĉz`(@CtnbIvGܒT*zic`y\0\$y.b`&-A.2_.Č1EE/OQp;+VT \0t @\n`";break;case"et":$g="K0a 5MC)~\nfaF0M\ry9&!\n2IIنcfp(a53#tΧS%9pNS\$X\nFC1l7AGH\n7&xT\n*LP| j\n)NfS9f\\U}:Rɼ 4NғqUj;F| :/IIR7aýatpQl79Q.SwL(LGye:^#&X_v Rө~2,X2Cj(L3|4P:Ԡ88#(Z-\0000!-\nx5Bz:HB87/d(\\ )07x3q|-ܓ,H'H%h7BS;h=\r|kBzV?yKLFá8\"]p=zAm=i\\йA`qnrUlZhPl3<> Ki\\jlmP9QGqh*R\0S=ʎ|^S0>;ژPQy{켻}_q(r+NEW?@EaRڅt/p:p1̫k\$ozLpbpVk \\F\"iDLv*\r0pСWIh˰EDϬʭc\rpՄAC~P밚CK0mx: ,H\0 %@I&\rCƈ}\\*#hI&KUoyv`נܢ,\"lx!%F.-Mh9H``&e0Db)iz.h=\npx`h\n9j~\$L\"jY'?/\"m`(T\rN/͞r=#\$\"!&>90JLH^2`NIlR4e\r,>́N>\$\rHݍY(HI?Ť-G ҟ j\r`(pB@34%\"ҰUNr+æQ+(!\npLfb#d\$-90ec\"@lϤ#r\0N1ԞI\"dE~ h(Hb#mO%,RKL)dM2ҲSykY2k1B3 +0h>o7V\$@\$D- \0t @\n`";break;case"fa":$g="B6P텛aTF6(J.0SeSěaQ\n\$6Ma+X!(At^.2[\"S-\\J)Cfh!(i2o D6\nsRXĨ\0Sm`ۘk6Ѷmkvᶹ6 C!ZQdJɊX+mc[Pvrs\rZUsLv4K\"[GXU+)6\r*>n?a &IYdcC1[fU6 PH*|jڮ\$+TɬZU9P&!%E2z'esΪ 0r41\"Ȉ= P?:oR@ʒ\nҤld,\\bɄ#i4,ZMCR<1\"Kp;*p.\n1t7+d#Q'o,2=TTcW0)B]t ,DB:1{S\n\nB{0J)h\"P=TuC!>[l%vM&!|SB\0(hS]\$%\\;0l0:e7FoIv[)R)j(9\"<̫6ܩ\r-PF'CIp\0P:\rdJ 7K5S50e(S`2DF(UA&Qni\$B%mFH/lϵD϶;߹=uI\0T]1¢)!bx2ZZ\ntLܲðOb\\WfY,~ۼ[-pj1>ONBPn?H^juYˮVĭK\$2yi3:@!\0(f4@/i{!:;\0Cxn.C6>bD/ 1F]B\r \nʛbb5+2[Qz\$9V`LiP'\r:hN,Ɂ٣tb)gYSZCqA@\$NbkPPK,&81\n\nOE)ڛcie13HyMoQ(fVPk y_{D8̗\$è V۰U4 \0q9\0xmA C6f0p%D~FGbTkw\rȱtJrV_\rGqFVЂK-\$1Et(أֽ|'6T7tۂ0Tρd5j؈r/#K \$|faKĚIV3(I8o ('@BD!P\"ʜ(LQjl֤dLQ-2nYaXK#\rYxP WHWFLZ8=H4G)oqϫT'],Jn|LE-G&|DENM?*%[9T;:Ԩ\$<ڃbIu28m6)TbX-*F%JUCEq(\09&ʨhC6P1D\\5xA|ɘԪ*MKU^)Eq;:V9hҭJ\\cL6E[tF_6#?IMXs+?\nS QJჶgT,v:Zj2LT0og舠[6\\?hi>bӴo'\rdfӠD̘\nجa&V\n0\$Xrg66Zs &7\$C0rB2#渆bO5Λ0frL3mć6\\\"/+KCۣKq3N+ߤP~7M&8i>;^zIH TX\\p\"9E+;04va Iȉ\\DܬūYSdL'Q7i66\0P3rjvhemRcx\\ʢ:册Ebu:UܚWmRRO@dphi^S/\\Ci\n-@n'S1`'*b©rP)[6UmSfFVsٱzۼo}6ds6.rs&ȚvĆK#ݙSSh)3~\r%wF=seMoqkrLi׃\$>{>[\"_1Q~pT=Qb@߫BTeXPD%gŴi@+8y\ngC9R1Շ^|oV;L~.O}v1]_݆v_яTaD秮>MetI?ac~\rL~9Md/k]m>ئD-EF*ĶDDNW:pXDZF(:kp200n%-.Pn\n0\np0hpKfoЊ.U \\Bfj1\r\nOWtddx>,^-xmEG!q0}NԦBedf,Eg\0If\nHf^1ub/D\\\"M'*ͳkIBdO(kK\$)lݩިpz5.\rV`\r.k`6\nZ.'/ 2&jnq\nk^BL@ޑgK0G@~q7P!% d̔R_bxMMxQbZCjL&*ZӲTBV}VԈ\$øMbRFMDʂMXm'Ì 8x2/pI)[''])ҭ#~or*r F Xdn5d)q*eZÎL^hjcl两<4\\c0ن@!Rwn1M8=8õ&RIM)8\"z24K'3Rs/0d2sP lf>ce73";break;case"fr":$g="E1iu9fSi7\n\0%(m8g3IeIcIiDi6Lİ22@sY2:JeS\ntLM&Ӄ PsLeCf4(iƓyI&)ɣ(:eV)\"c!xW+J#iAtu8-\0U_T\0;a4=3_&Cm^2\r0~Tsb{٭3ֻe@>#*舣ƼLjzTK8NN>`F@=3FW84%z§B%<%7K0rT=4+אW.\0ܲJyö\0 Ap*,|lǰ/%w s_6շ?[t)OHXN7At*\r^<b#=,D܃sjd3%k<43'sBDc=< B]wԥ>zo%z:*\"\r8^ü!2g2 (GpkhE\r1_1̐JrSꇈ\n29}WQ `u\r9!sIHT\"u!UawƜԚWo&LeXa\$8 a)!`faVBBO\naP:@ך:8TIreHue͋Ý.<Lu\nYyj#l\rHY[&`&'wGxίrbJi/+cPg:?aI6U\n 8PT@-BFHѦӱBKs*\r'E+}bÄ#X[H̙A+ɋ2 0\r8I!kCP>Fh8)DALVKl6)òTR3uĆN`AƥgZBOm9dD,'rB\0Ud]j.\nւra10ktN-|]+fl=ؕܚA=^FlϽLcRv!yGI=GmyN`eZg6]@OMs+r\ruƘt5T>-;bbΞoNX\\X/邔b8ävI\r7x*7B|g0(6@,LN3!0 r\$B0K\"HS6cDVo\0X,X@®2: h!LqUo ;&^bU\0 NPP8lJ#'ϒSQglo\r*(n: Qɔ:\$.\$\"L`bi@xI\0[[\0o(3LDM'nb>E;J+%Q%\nIHP2DF.JqhP1o1xQ:葈1ѕ\nlDOnpmޱEQ\0_*]tǑL,dGp\"\" N !R*,w#\nI#NGOɬDX@#+&D+5&ҀˑBt E\"`Wź ǜG.3f,\$f2Bu 1J&!2k#r/X&?/r`,@jl\r&J5pa\ro'\"v)M53b,C3pZ\rTu/ֳP)R#ZPN Hn2N\nI[f\"iO1' |\0E83#2cQ1V솶]Йg<> oB\0[:3^\"63T,C->>5R*n?s渓\0T;6>'p@AS;gN G#\\%+BkM\\_#FREE?(&\$\r'\n,J^P0\0(@ހ\$N\rJ:*@Jd),/=T\r";break;case"hu":$g="B4e7P\\33\r5 d8NF0Q8mC|e6kiL 0CT\\\n Č'LMBl4fjMRr2X)\no9D:OF\\@\nFC1l7AL5 \nLLtn1eJ7)F)\n!aOL5xLsTV\r*DAq2QǙdu'c-L 8'cI'Χ!!4Pd&nMJ6Apdo6N\n)pW7c\r[6+*JUn\\t(;1(6?O'Z`AJcJ923:)h6P5OaizTVh\"\"@\r##:1eX #df=7P2Kd7Ċ+q[95t>6D0 IC\rJ\rPʬBP\"=A\0B9;cbJ5Lk'*i /n/GRaCRB0\0J2 ɠu*S38:B[fT<:X4ăZp3@G84;\09I7.l[꼥c[7F]5Y2mJ<)b6Հ:ö0\0&66Twd2Nt)J.S()\"%S4c4Y^5뒁Bd>8:}|\$xc}\n<\nA[XÈ05\"ʶt:It5v;ߣ; ˢ\r*@ФD4xڇAu3G\nˀ\r.#9I}A}JDp6D:^A\"E%f*BN#)Dd97Ckxd PBX r-B Hd*dxJ\rqB\$ 7̛Me͇C:9p\r\0HA,rY2eq0J,zرZ3,ru\n!r:60 nHy42#S\\RJ8aJPfDB]sa?F6ACa\$0E1\n<)HoQmQe\\pB̈4AVdDU6\0@㉻O@`\"&F֛Bba_\nR\$,\\Lq\rkEkx\nEG#q*\02~L2b3!TxT~8z]^C0a^*h>yLkTs쥕5F9A2E4JHv;dW/pMH9H)(\$hX\"CY'Ց<+:hjao\n\nf^.?\nJ\$1Ebymf!ChHEt\nd2IQIY<X1Skb^KQ%%Z/FCxpA%j=]p(xc5ҩ]wXVAsZInȏQ*3+\n`y Hr\\Њ^\$\r[9XXy>F@()0\"^B,i4A剡@!VwæW|6f-SAʩ}T`&gԸ]Jn9ڰC)UEa՞zJ9w+/\0\n>9k\\\\U2Хo31IBSYűÌ5(Mqw4w0\\v@܊Ap(Y=;ɑ(U@R*N:5Bmr]0\$i,#:eGN~ޢ\nbpF9QņMLwɩ0#xƉJ%т:I\\5NX%\n~kt-)\ra=]^ԩu[sKnsF9+ǖR~Y16)S0E|t\r*ѬJ EOM^W5ĩnvpێSw.aHzJZiCLâ`LSn8NW*úiOf2tV\\yz֍\\L7N8[ᔲ69n7Ucݝu};bKZ>+CLٓlx{ۉaTj!g{w?\$'-QOT+\0Mbh iBi;0i\0Ylp\$l#FJ;WiF b#%1\"N2z 3+mPNΓ֎ ,P/feW.C\0^/qIRPWN;\np0d`\rg*9D9b^ႮEi\np0\nOYG]&7\"No M̤&S`,`dm Spiν0HޑG)S'pq\\Q:dqd&VDo+h\nKD(KHQVQn?`3k^\rrc#V⥊U ̮ ʛ-/Gc2 &GHBV,%F!7\"\$\"\nAnנ)Gq \np3\$Qί4~?ggv'{'2Ox\"<\$D\$@k E%bb*k)'D;.L\$\n rr(J%ϡݶCڢ\$2\"='x8gNxO\"V%Li:M&T;riBx!ԗ !'JGA\0c\rɺS##\$(1D`d̘4vvJG%I@'I/hͩeB` p' .0FTZۇ\$\\I\0cSܶxNT(@(\n \"Pd\0\n id?\"b< !DnRE'(f,P>h(&( 6#aGfE\":A-XV_39:0Ҍ:2&Ԕ+%4,1RfHx0ȀV1)|2z ': yv]NO!!,7tD'!Kl!UaeX2KVTg%ԨanerMdPWĎVJcq- 1z;+=AںBNKN\r0-4T+F'qVd\nCTx e[([4\rm&SPLba\$JgW+yuC6 (\njr\$UcRu%8vF&W.S4mE;P|ŐV6xajJ\$>ütUa aKiva&;Q/,˼,m'P5y=qE;Bis(Z@//_ɀfI~W\$dHˡR)-ހ ѲuɉRN:IaGi,=\"H&)Z H\0(6l3 & wW\\Ș&58y!M]K!p[S__&P%bQGVc<5\rj˸BMO*E\0>ւXs(ɦj.9Ҋ_3uBI\"jtsE㿧η姎sRx2E,+I:!ڙnJI 5c(vs_0,ZxP5#97l:U>\\L]mtMޜ*L!\\WԢIGWAYQkr5Uk\n2r[/fhuO2cnFԵ/I89P̸Snrі=۲Nc%Kda1\0sajjgj}H 7_*5NB%m\r5. 2\nhq.bݎm1]VymN' s>![c8̯Vu䬦\"8_IGOOKBA:BHϳ\"ԍR{pRϽO,ވ&!xs-o,jn/ff..B0^%#d͆+H)CP&7#DY@%#c\rV9irdH`dP=ɢ*d\np*\07%>`&Gk#E%`βZ\$Nj/jCo&jОd.LHB#ZEĆ/\$&C\r8]]\0\0#\"bydԣ\$0LNb,W(G!bC3,\"}1'Ю{l\$V2.|vfzrRQLNU =#..D& \"\$I` D^\"I^, L%ޙ`Veyn49ȅ\nI^\n=\n%^NLƠ \0@ t\n`";break;case"ja":$g="W'\nc/ɘ2-Oᙘ@SN4UƂPԑ\\}%QGqB\r[^G0e< &0S8r&#APKY}t Q\$I+ܪÕ8B0<h5\rSR9P:aKI T\n\n>Ygn4\nT:Shi1zRxL&g`ɼ 4NQ 8'cIg2Myd05CAtt0S~9s=(4>rt/TRE:S*Lҡ\0U'(T#d HEqE')xZJA1 1@#9D sIU*\$ʨS/l _')U#R8#8D*%ʨEYpEu\"9=Qd~Y@=&\$'16Z/%ucYI@B]DJt%E?GI,Q0ԄsZNiv]!4B\\w\$mJB'*'I*[J P:cv\01#s(fWL]Fs7U6AAXe%c_~JZZbAKxKnh;KALŲY8Vͷu>hYer:M#L#X70eZI`b(p:cr9@6\r;9ό#8KoRsUb#N.\\G)\rƄq\rru\nP)]H(Ay]=H+G%֨:y>X`M!#aØw\roPKjPf4@/nA0(n: \"cHFS%\r`\rm! G7yk5:fanI߉&'\$'eX^(~2zrBC\n2gd,(PZ\rAE \"\n&hľD)\"c\\4o㼒 sTeW#9DxUP&CLګĐƁ1'ޡQ\\\rr\" Yb0=@Hyp4]C98Me7@a\0'I<Tg>\"MD 7\$0@j([wQ%4AL9EzD1&p\"D`,x18cNs@HgM\0mMa*iN2J='FH%HlHQN8K'@BD!P\" E SĘ>ZC0ac;<C/M̽<5c{(9\"!HPD*X7b>\nuST1N+Vυe3kB\$ˑs.6@L4XM-V7zT%(}0wq-0HEpTqW \$)|TxAՠP/Zo;=PpwX)Sld=QDTvMu X)I_JH8JUKNY}\$\0}!UX³a襲?Uy`ܦDiq/YH/\"]6^E;0!˓AHOrٷuQDnWg4lϗV,Tx m46, &n9c] ӓQ-\r;3 ,nhSs\"~ZVm\"\$U*VLUۃwmKA%YI0mF&`ԚТXQbWGM}eTmnLQMMޚ4^k8PEVG([B|m_TqH^(Idal\"(hGcdZkWDیHHKQkG%1EisNZ96G{}H:p6uX]3,Iaxs+M9z9D#y~*MK3k&]a{AYn Hg&t%佈Dh0,3o6ۤrIFb+A 00.HmybR ri4BΣD,oD#:dzF\"d040:ɜi=K>*boԯe|XOPE\nFOP?n],aW\"t26?B\0Ee|0Vgc..\09]O%]0iH|PyErи%4G1:[\"[,LG!cu\n%kĶ16#xOu!dɱgqms\0GdG~H0,.%Gkf둼ѱ\rQ@##Qˏ;Qm,P=!?!.E'dK =O`Ek[vƸk2E,ɚI-CbdAna!\r/rLb`EH^JTR)R-rhxg\rV`*s\r s9Ƨ \nprr@68MEqjp*JIk\"r.TVB0@";break;case"ko":$g="EdHڕL@؊ZhR? E30شDc:!#t+BuӐd]ñN, v%qUY7D 7i6LS:h4NP +[Gbu,ݔ#qO){M%K#d`̫z [*KXvEJLd *\n`JvPBO\naP*P-bqziLk4&dpubT4Nb41\\+\r)\0C8 \nlHcpkͻR.aSiq*ÑL-;1]xP*PI\0D0\"V/ʫV+N l\\0;<3\ra\rȿ(:HPvFB_/@GXv\ng5YILPtBP ']d¼3)4ږzlv,GhPD(\ndegIoXT=\"]N0E'X:Du\"v@k^5SxCHz(!pXS1P~Oiv.B2RVMQ_ JoXI&S*aU=hٸ\$l,>\nv\r8j>tzxkƔg}M)X-9N/ؘ\nbv*RU5F\$\nZŗi_9!%\0^q @UI|js,XYS5q5zW4y4c\\Y'&W3mxʋ:_PL\\)ʚKӱ;e ͞\r\r wqm߸|M=Jvs1+EjGҗiZ)my6:^)5\0i\$%SسVwP(>;Ώq#~OW>BxsLMWx:^*ܛStO/`ERMoYli[7ޖ|TxD%dP8;\"h:HRf9/[eAg:/Xa*[qOCDePj\"rH*i<l. ^/煺CpinOd#ʒdގ𮝤rGoVJ/\$ip\nF0NPPjltl(qd1OOddLM\rl%\rPpV@|f.zƱĝ/\$B*+N\$DN@E@a8]f#ÈҪK@\n@ \r)#\"Hm\0ŴheajR2\$ )2ncFn\"g2f. @65 ~lL%:J#2O<J>t#";break;case"lt":$g="T4FH%(e8NǓY@W̦á@f\rQ4k9MaŌ!^- Nd)!BaS9lt:F 0cAn8Ui0#InP!D@l2Kg\$)L=&:\nb+ulF0jo:\r#(8Yƛ/:E@t4MHI'S9P춛hb&Nq|JPQOn3}WY,#H(,1XI3&7tٻ,AuPdtܺi枧z8jJ\nд#RӍ()h\"< :/~6 *D@5Λ<+8!87ȥ[98ʕ(,lR)ă@bzk)1 #\nh5((\r?S4%KP:3XxAZH%P|?#;ʍJ#uv̥N}OOEwNf5\$i,%?J\0;u(<\rD4x\nrŌ3sn7^Xr3ZX\"r/ zjӞĜʝ\$LϦt&DQ!+Ӭ<9#\r3O\r00BP2`ÄJP @.\0 bȜ3.Y-^ۛ\n\"VJ-%%P \r!3I9*Ny&A,maqT`Lt#\0952D̬%D@ٴ@'0ڑwji@25\nK&HgC1eP\rb:p;>@5Z\rªb03T͢\">yD m)-%Xљ8\0p\\Vд)νYO\\ґ ˡ\"R,ȃ'HMJ\$@>\r@!D7D he<2T_;xKuFQ4Ȓ#a#f<ʒfK2UP3٫-D+lP\r6OlƸ2RYV%#yr!*BZYgD1P]%1u d!Qr\$Ԡ3Ո2lNPD& }M=CG\$˘dHYcWH0 ҤUS1z7ٙn\"1e,oo%(bY:G=J;URNZ(oo!m\0+ݧL<`TzB(r^DT%VrT\n9N>uT\\d \$H4Q9Ѐ/.\"%R.aG#@GGc.Rf6&\nŗrsY6Yd|u+BZ3V}ЁC _R;bv&hlԘ&F5'\":\"~e,jTq OI0+ir#*RMP\"A%&0nDxD&F| M\"\"cQ -q8^!2{@=)c3gZKGlL\\Jh+\0i: -L,c*4Yl8.!\\¸+aB?Bxf\n'*}\$J3(MS \nX.^2d]#iX\r\\+&:\$XŐQ@/1IF@./\\fFX&`F,BH/ dAmp\0l\$)0\"vA\0(*ymIrrNtD\r\"Fxtn\nMBI,EI6EMQ\0f) Gd~f5\n<)@Z*,&b_?IL`\\PCPuaU!^&dk y1R\$%Ȇ\r'p#H VʋXo\$ĸ!52C\n@\".\0U\n @+\0D0\"`AKiL(@l1\"f)\"PZ#Rn\$eFlq?M<6b.\\r0r`4L)%(dBL9^9̔p3p։;*Pe7,+8ҽQ\"g/F-C+(tJ!)DY}%t( aWv: Ahy\"Ve%&TȅIS]\0mjH\"~2?Hi\rpUC8VeeUQR8Z{n/#M\$۳oS͍1#\$ù+(-Ȃ`Lf) ȜlI\$Lc\rD\0001a]6Rb_jɑ\$0CqjmdK6H`,6TADLĩ!`r~dG *= w!e%2zIS-f\n`!5̡eL}u9`\$v_ vJՌMwDkc(f8qT̫JJ@_A'6J;3%ZzI˴\\0a.;qw,u24L7e6bt.C6иzYJIL%FzZ+2snӪX@z~ ͲPl9\"G\0Pn:&^ N<8\0B?R`C94It֪Gi[M Ӿdj;F@gE|^p̳/S7]sW[ }[fffS2.'\\o 嗝3?Ԧe6mFce൮ggmٕНN͡[^oo'kH4j]e_Pӻ.~lB?箈vP}3*LΏ&_I,xO`ł]Wj~vm<\"+<{'Mz7P \nL\\!bf/cMe!ezUF\"5PqJ\\˨\r&EXkTeFJOK *n\0P`#B\\8L;#d!K924Ϥ\$kL\nZXNj>X#4dkڶˡ%n#4(\">\$.njbO`}@Tbℚb,ȣ.:#b\0Ez06XFFbAHFK.JA\$L(\"*~0X8C%1ca#`\"+Βqe\nLB*c8sF8P4'JvUQhQ,WpkJ\"DHZIZm/n*b˞9nP)%. QDBtX%;`J)@V/M*db\rDH7\"ɀPIA^h^.i\$Nj*e\0jI\r`ObTE \0t @\n`";break;case"no":$g="E9Qk5NCP\\33AADeA\"atl\\u6xA%kl9!B)̅)#I̦Zi¨q,@\nFC1l7AGCyo9Lq\n\$?6B%#)\n̳hZr&K(6nWmj4`qe>䶁\rKM7'*\\^w6^MҒa>mv>t4 O[߽0ȽGy`N-1B9{mi&@vlHS\$c/߾C80r`6 ²zd48a*-ʠ9b9oą-\n:9B0P#+r緫dn(!L.7:CcO ތX(,&\"-X405H~-p1hh)\0c)ȪZ5\rR0@3Acr?iۼ4C:6*\0@6KS!\nc[7! P#BC\$2<˕\0:-zc\$\"`Z5P7BT)MÂ.#0 J\n5C+\" ,w+t7k #hN*[}%WMm]%qʀ\r|c`Z4'cp, 5jc;{eCxISz*9c5pIX¶0\$P\rXaJR*ؿ.A\0)B6(7A\0Z0MKo#f\nQ<؏(CdYcbv8:Z 7<;ѵȨ@88ct:%)Z9tNj\0x0B|3Л^H\\3_b<\$B9.cB/HPPx!,c|znʝlcRR[^l\r5wK2N|AJ+eosи|H(_'\nJib7cNj\$EAYh2!B6rVSy12H\\b~L\rߊ[=\nH?B\"XB\07RӘt\r dNfFx G[Li8(hs)Fy\r-u0@_A 1\nCP3= C~'4c\0k2DprDIe !M`Lpis*W{%)9\nYHY 2\$e\0R;E\n=r@BD!P\"@(L!8c )B !bܟ eQbj{|ML\$\n\00068H\"D#.kO-D +\$JWm`41y s;%\$AVẈPzHnDL\0SGt9E\r!(:z@X_(/LGl^)iR*hCHzHAfN|AW%,52\\PLZVȉu`M1oM 2*Ie}ZY1R75&ZH{IK0\r@B\$-)s\rFg,#RNFMqyW(2'to\0K-ҁegtxKgvŸsLÑ q&+qɹvŔ7t.11b(fѧ[y%u' %}\$n fR&&TJ)zZRRq##~^`/ə %RxWQ!Hpy\n־\0O[\\[iƮubBdUDi)]ҘPnv#A/f,ΒF%556LD^\\9ă-9]s4ClF,>~0ߕJPτ(\\\$'&C[Ua(y%\n6flρz7)PCM>@;C00+Yr͙+V-]\\mQո[ct|gv )s~ǻit[ ۶2no 7s`e!9e9dJa}TSmW`sYbiĵyQ\"R,}O\\q\\RMvARq\"|hUoվl&%U5_+n@Bi;d/Py.kIӓ=[v6fI)zP+؆2USa#D͍ǧAh^Vev6oUQ;t?Ucz6PC'\r/ \$`Jsdl}IO(>@>USglϖ3_mWyLŇKvWIUXo6?V TB\n\$Gj/'lx/edc2SmZ`c^㖰=*RNfN0,jD(cN iNBdS`DSkܡJ8md&\rV\rc!R=`4҃Xl.0}d2I~\n(P\r6%0^ҕ#~KPP|ńML)nȂ~9c/惌M8# 0(?Xѩb0(*H9CAJS\"0Ac̺5LR:CXJdG2JXEo6-\$\\f2#̎QfN\$ʥ\":sp9`1ĭcq,U-ʢŪLT'pX\\{\n\"ڞ\ne!VrCY 602Ob0\0',eC̪DLj0x~\nb.\r ";break;case"pl":$g="C=D)eb)e7BQp 9s\r&ybob\$Gs(M0gin0!Sa`b!29)V%9 Y 4I0cAn8X1b2i<\n!GjC\r6\"'CD78k@r2юFF6ՎZB.j4 Ui'\nv7v;=SF7&A<؉vwCNAg\r(s:D\\<#(r7\\xy)V>2A\no|!*#0j3< P:#=?8¾7\0=(ȨȠzh\r*\0hz( ˄\nLLXC\n\np\"h9;Ɍ3#8#z'(,Sr1\r704nhºkX9T(\rXH)##jKA#DMtd2ȉ3:!-C&NKSlO3xè5p?\rs(T bcx02(/Hå#(:tH7(خ#:%/t:Pk茡\0(P:\07lBCx;`9m)Eɯ3>s.7Ks\"]؞*dFOmy2z:TH@̢80hä5,P6u\"ZM⅛Kn;0ġe+\rƂH@72D&\\4͓D%ih1g*1d!b0o6|%S:9ap®2zɿ||59q-g,\$dPX@ssGCwC7oFBl'!2K\rh@!b`^iHp:终ѣ^6~҈5(>Dq5&> kqVKpЗ W/\"Va{𠆃 \"\r:\0txw@0G\$r8^C\rɭDkCgU\"4ր<'pF!T1}B&A aAz ͬ1@(fя\r U()@bL˲mMgй1ش(*\0&hhЙ;W^*&T(k>zNa?#ht\\Sg&&V L lmF\$@A@\$XCY5%<.dWp+g:'a2Sl\r:\05D.j(7Ep0iM\$vM,Cq]RFjXLr\$^R)Q:\$B{^. #I)N\n,8:B\\MXl:2Ӡ`̠סQ3pn^BpmC 8k&BpA-!PO\n+R\nQ~\$Жȁ|b ƙbw\rǰSRRw▵P1Ya'['=B/1tWYOb2do͢*#!]F@\n1r O^2ހ(d,QeV2L-24C-14vD~!ge L5пJF\rFhQ\$ \\g.RC(E+(buJEu6e18c{D p\\_EViCr F3+epAA\"'ePBuIi#Ǚsy2wT\"@~oWmɻM\n_nx)[襯]>fSEFizMO*痁M:&_[λzΠSƿѥajP.[dgӐ6B>aif;ݺbi1\$#Drnv0iAo\nwdG7tדdH =5UWC.fp &FEoϐy d<\\J>f4A\$(0OMDۗgncX-KPzE5x5'PpGH7z0%Ml_w/gh1띔B9!bnUNl,*wغ/6@o06?Q.k\r=]?JǗڭ\n/Xm==}M`]G{]E«*jR'\\[ns3|P~n~'}NwwQspCB?=,(_B?msgu\"oOCLc\0\$T0*.@I6oXʐP1Ip 70?xozLŌ\\\n:Lڭ@('>K? j^c-gi\"%A%\$`-rhZ\$I\"-d H>@ w)6\n\"plhRqȲ9\"0Non=R\nV]@QOvVl&}q\$]lkVZ\0iBcE:q?/(&NّT:Q(bOVE!=8ŮOCqF}Q8g撫(@\$wү,ѳ,V9b3\$Gq5JJ & OhY!#!JbN#,M-Jcr@jr`]lrU!O}j6IP[&x2V[,(,)\"|\0EBJD6*os*į+/'h&\$o:Ƴ\0%1#yАHlR63C4JMT%\$I\n_/0&\r3 /͈(QxC.06*\nTH<s\n\r18\r:KP\n'iFJDԐ&2ld\rV\rbBh\"N iN9\nJ11)d\$xb!)\n\0\np&hR*iG|2pF);;RrӺ2-;/Ds#\0#__\$}2JXɢJ9>H).c op%5CLǤR.V:N/,\\&/lEn Jt%xR(i<0(hweEOvHtyH`ZNHNHR!\"ǣXN`- 4Ns\n`I .ԡT6 t<\rFJ-Ċ5^Q\$N@\$N#=FI3*\"PS*\ngzt'Qt^3IBmCFIkM37i@6gPPj?J!<-ĶB^]\nb\rfEDXMb%";break;case"pt":$g="T2Dr:OF(J.0Q97js9էc)@e7&2f4SI.& 6'I2dfsXl@%9jTl 7E&Z!8h5\rQz4Fi7MZԞ &))8&̆X\n\$py1~4נ\"^&aV#'ٞ2Hd0vfβK\$Syx`\\[\rOZ?2wYn6M[<7ESIQ8g:'P,+J9Vp@O-?J| JE\"A \$>jjxՒW6 J4f*?>dL\n/|'\0\0%ʿd \r8\r㞶o8\0b6f=\$EZfh0Bco3nłn*2Nvc <`=eAMC:Z\$H ZYs\0000 `Za#r,2,rpŨ@)8C'؈fOp o1\nb) C\rdLj\rB/GP% (FFF( c(V7E\0^Tq0VP6MS%7 p>6R6@FȞA5dqFv#-09#Њ0́\$LL\r9RW#cR\$F3##O:0R\"te\$i*X:2I@3i\"CJXd\0x@/\$L1.7h1\" #̦n/*C*4d\0\",BW,q,'p<%ev~I=\0FjfCq@o\$h";break;case"pt-br":$g="V7jm̧(1? E30\n'0f\rR 8g6e6㱤rG%oihXj2LSIp6NLv>%9\$\\n 7FZ)\r9h5\rQz4Fi7M&)A9\"*RQ\$sNXHfF[\"MQ'Sfs!\r4g䧂fLo7TY|%7RA\\yiuLb0՝4\$ˊ͒rF(s/6:\0Ꞅ\rp ̹Zh@5(l@JB(*@7Cꡯ2]\rZD7C!0LPBB8=l&3R.)ɨxl\"#p=l4#jB2(.᱃dl1aʋUDmSXcx3\r\0,t7)2ƅ\$c0سh 0A@x֕)\"X*H\\Lk۱bEC!Lz6rǙQôel[\0y9`PQI9@ԇÇьD4x慅~引s^8cBҟ\ra}\r*:xAZ:( {<7q|75f)6֘Pd1#\n^@hdI \n (h!((+\0d*d!\rؔJ]Θ\0\na'!DD(А\\zp*H;9&\0ݣT<\nU\r3d#F14!Zr`cX P L*&CL3SBԇHnGT˳\r`u-M(Cz91@ae\0!j<\\@8}U{tit].c}xNT(@*ȜA\":HL<6+/<P%Q?ֆI :',ตCѝDǗsG4S\r9E(L0Ϫ~\$^Gi&&~8p)CBr|?4˹\\HEر.&TZÑzL,P+B³(dπ8bV!n.G(qAga\\-+Q6I6\0Q5s*fogR3vӰ,A40dP?D\n}q;b4솖0\$ӬAQf0HESsT-60T/\".m5†T sX\0005037Ԡ7+I9Ej85Ӗe*2FʘLhT\$ORU7L/3Mk`ZۉFX\rD!'!ѮWk{%8c{0t\0E3YV:To]@LzʬX0ܰS`]0_tC#+JU͈pKȄosy!9BZ~BBU{xHIY\0\n6(^]e&pڝt\\@NB~.2VHt*oF2!xrQ\rA ^3n`N؆/^zuASy:3uebt>EU;NB^T&/'GkkF#d)\$ֆ#|Z FI[Mj+>[:6M9D\\Pѻ[=FmAP䚷~ZRXW\"Z} \rN\"s}[ɹ5c@RopE7`zU]?`Vn: 1ݚ{6etSMM=MۛJFS)Ųv+l͚(;>iĖt)| 3G/X7y'?Dv~pŪwd\nMMld|;nfwi \\z/ź\r/ifLu~/RJ!FFC~,&\n06`2c鍎譕NVaRHb_/b\\o~b.ͺaFGb&^]NNUedO]+p,0yC P SPppE*j/Pо/ˋ #\rp!kn/K %䲢p\rQKg\$1\nE-n \rlG;6T1F\"\n*8>m(,BehLe1C(T¤4.ph|\nw.gh=@i\r%\"CFX?lP ZXrɆ\0pI\np%E\r\$;ZMV2Ixfi4*\$hx%#0N˔mH#B/j\n`\rc2p(]07k(dFE(Mdr0%FiFުL\\pQ1 V@·'-gRw#\$108C x'PҊȲ]24o*bR'CD#TҦ1[.B~O8ŦcV8I4rl72T6JWY0-`2/ c6R|2DXq&%.R8kb00ĕ\"@%Kˎ|F͆FQR7m ";break;case"ro":$g="S:VBl 9LSBQp @p:\$\"cfLL#>eL1p(/iiLI@- Nde9% @nh|X\nFC1l7AFsyo9B&\rن7F82`uZ:LFSazE2`xHx(n9̹gIf;=,foNƜ :nN,h2YYN; Af2r'-Kk{3>1`L@[Q2Bz2˨ބ:/a62āJ'&::80Ґ/!¸+Mc\"1Ic) \r)[c1P\$T80K&\nH!6(6Zp 0tBpQ\n0B1T7p8&j(2LcΈ2TH+)Nh̥C DE2\nС(4Boc\0:㳮`3,\rj:h¬h9r+̇`D4xW/8_D}0xD?r/7=U. x>*%9.u6ϋreiB%iX\r.\ny8g\\(2=#HY;WL4,1gï\n7]DDp=8҅Qzlli1B6l%`ŬLPuGЛRGy%V\n%bh\rEhOBI&rJѡ\r㜓-wDx W;mМSy%`0xS\nAcyT/++rA PF]¡*2\rEAV:0CiTfwm<Oz5a;ȭʓS@}S#e}XKMVhO-Hm{Qj}䊞T!:!g<0QS)c,к'op+cnk'=,6P;'_U'2'x9M>x5\rR@Bt_Q>A6\rA}c1}!\\(:돦_ stZWuWRgRu^TJVJPp]olߏiT]B-ݬ0T4l0\$BlZe߯ޣ2eRdK*P:@aDC\\~Q:cDPbf\$S0pFDnХA%3o Ib =\n3(c\$Oh/%AVL. Aw\n0QP71= q\$!\rQ5#A7v4\n?Lêny^dd\\i1`j,/+VdS \"!Q.&DEF}/`F(1QQMNQ0]qF j@03PqD\rVeR\rm47\nEThv\$:g\"B2n\\\0\npBN2̥rHW'(hͲ\$&>i*L\":#B\$fQ\"0..D`:<#4Z&>%E&B8&@8\"A9zN%/&bd)C?W)cNE1U~Uu0q+s>QL+5sFdS5 &3*)h6&rK1H\\'Plf/*q,Ee_bs;i:H^MZrV.Fǔ?N8@\ndR@ 8Fbk6wNkBc:m4JbB/;@AJǪ:1\\1b==vH? Ś#H|(sHT \0t @\n`";break;case"ru":$g="I4Qb\rh-Z(KA{ᙘ@s4\$hX4mEFyAg\nQBKW2)RA@apz\0]NKWRiAy-]!& pCE#yl\n@N'R)@%9*I.Z3{AZ(Tq\0(`1ƃQp9Xi\$fi'B2,lƄ~C>4PT!HkhRHb4i6FFc{Y3-jrɼ 4NQ 8'cIg2O9d0SLN}\rg4C- \r'ZRXfԻ%QQElLaSo1&'^?hxh4<\n&K-Â3cwO8\rh9ډg9BIQ2d*saMl-P\\ԩ%3ޝ&\ng DUɱL:\$'2e@QEZқE\$`w\0d\r,N`.>P\08S90r\rc@1|ԑ>QU|Ԛ-t\" \n<)@ZikYZJɭ-/Qh[Ӥ(LVEVzzKU%UT1M8q iW\rJ\0C8 \nncydP(^PLВra+rw=⠑i)N'=B&=k嗝aDs܌SkRFɐ:\rnH.km#('aW!* E'+QJhK\$ÆGgb4rW59c4Yq(,fl#A\"ՈEK0P-H\n\0Qe7ypI2zvC@O18ɾ;X8^a\n8ðRg\"@iA;!\na33jER nuxX1>õISqKz7M_<7On d!JOVU8E1\r[/]1uaPY|&w9ggџbe&KGY+b.[UO-I9b\$k\$J;\\e7MHȥt͠cMkyVB3\rΉ+*C,{Nli~HfD*eƲʸ0`\nb?!j]+=Qaiof.QHnO/Y!u6gibz(=s\"Ly][ivI5y7GqT=%zG^\$zSz?ţƣ&N,\r\0Ft 0B%\n Xv'\"'B;\"o\$%,&\"X6N/B(^axa-Aφ!M:N\";D-`g-\0|S\rvHrUh0DP'ECFdOcY4bNnVn6SP2{R8b`sL}\r/2bq;SnJp7I0dc'7ptu2GEKjRS@cF R6\0M?]?@@7,(%ƺat ?@eXr\"@+CC@q@GDD~mF|l_D5Ft\\;\$PGIGN4Ra3\$\$6\"XR#XϺF02;RA%q+#@+I %BL73c xlI=K):T}OgBG+T+`e\$#^~B*fAgF!8EBʸN0q-Q&%SJTcT\\\$gU\"VTT5lrcU2?F&dU\rpzUOU5|=TGZuKWUll)A3(vQ35.u01iG^5n/p!sUq2\$-@6_`u3T&yEnzaAZ`Ub\0CeECZJ[_F*/6ŜJmTu)ΕX e.eZ__gN\r؏L +k+ >+pHrԨOUhE-bLjOD\$j/3!v(ZɓtGBmVi'1ּIlf7fRgpo<.g\rW2TdBeʮlHhWN@\0Ĝ\nZ\0@@ƛV)k\$!\0\r&)x75lȾh[n!tdtaeNΞWE- x<3ON\0)Sdea]PL\n=Px0eң\"4 AVTGUxT=Yղ*ajE\r*<@O0Ƹ\\1`cD*\$sIW׆kCIzrBv5k'_o<FeچDާĹz~ \"7oZ@L&BRK\rTdB\"'\ndGH>pfC06%Fs\0Dg\0&eU!}'_0VƇOD}0B6`NfeӆE`FQ+/c\n-85ҬH,LNml b@uVt\rJ*ŷ+.B2\$B9.&s-@С\rV\rf\re(@\"f#8p\"k:Dt@2 D#☆w.ZA\"6:6\\hll6J5,/O,rm-szmlf\":#xjZNC ZJ\nȾFD^&)#dVBFn5'ɝl;%2ENT@g.@\r:?ET\rDY.B9zƦft]Ov`oB.ܯOg\nt\$c\r.^TBUbx\\qk|wDwн:y*#|hHpqiP`ɄJ%cd3&F @\n,f^㎆Y&nL\ndIM9#fӼ1GA;«@O(DJ1CxYXp/t@byK\nV_`9Fb \0@ t\n`";break;case"sl":$g="S:Dib#L&H%(6l7WƓ@d0\rY]0XI \r&y'̲%9JnnS鉆^ #!j6 !n7F9gk53trρDы(P FSU8Fzi63iI2syO\nE./b;Z4P ,)6HN!-Bj\nD87(9!1 #k^Ҡ.`PZECAЛ4(2BZ5#̜n o薁B5)L=h1-\"2ŭ3#9Ϋ-\"pc\$Z:!ĘHKEQ\rH\rI-&Qt麣+(è5r-5B.Z9'ӈ\$z* BI x5K)b\nP`.(1nފb(f\ng_]PFSQcy6W|贊0_H˓:&*|Z:%|2Uf4\ro@<+@r2^l6H692jX2D4xمͶO=CH793#T/XH82|3t8x¢\$=*v2ݏx<2 \"M\r=|F*>AMdLG&d 4sB~{d @\nH&K,4Zɏ*M`LpGa@}F!41\$G8sF\\b*02^Hy1d4bOوn>\nC'r4ml1#\r+3-ԂvdIPpD(Z}DF(al/)9LxW9\nR#O#k`@m-n&*AB}A'.\"Ħr%P`nGT4As?gRȘ]S\"|:hkRBd!0HQ=\$03OHl (%\\Ô%Ffq|fOYEb`avJ)eYqF<9CV,\"(4̒N(p0ϔr#gųd@RT\nxg(fJ@oD) %lsIt'2fPZ='.qTh85\$̸c )-QD<(T\"~7WKThΜR:&|bܸ[1S6x8\\+Dyt%!6&pB|_,a1\"ʆ|_9#ϴ\0 fJ_d*mm4/MĐ 8>2n{&i4^Vq0aK\"Jn7r*o~܁7L7 G>XÕ`RJe(W-꽖n2(\\F4rC˿NE^kpw:eDpI8l+_3xנ|6!i\n6Iێu㿊4q 7~|xy4앉vɸ_!d,RC fCY0,~b>'/\0GU1υ5@W堗B4[6eáP#=P-\$ƇBQ攊3FE #ڭSe_b0(\"~G˄PȻC1\\l*C\0![:GuCQ3 ErbaߒLQ_5\r9vJC*t/E]cZ:L/HL@\0pze| 5A2l]kste@p[zCn .CU݁wrɇ=yLQͶtֿ;n-@/,IM{%M5ޫ1Ӿr&c(}n\r=v]CdL݂f/{+,Et坏2F˃w7~lnURX6FR4(ciﻚSfaPfȒƯXXh*Xm\nT&,\$AC2>(C<*{bo\\-`]OuZcnO-o.vBN(o10D8PPA`಄Գvb10\$q5 p5 T}0P;+27\0H'_q7pCuq@x/cb-\$ emh>8gK\"#gQ̤4QCHf̭4Pb^뇆b8rvQCKo&,P/E-͖E\"b0ڑ^\rV\r\nn '\"~\"^@iS6\np/`a(O@f R>,@)(0>b6ţ%&,DJ>@.涒X+vH&-HЂ~-3-\$U8\$& 6ÎS CBBfZmeM(\rd/3El>f.xtKE57LC.3c2\$l\05Ŭ6.\\%~#.Ũ`Mbt'Th :%O\$h泉+\0dJ%%<\r)\r7@\n/.@7e;t\"c 0z,>1l#\$TN^ʈHX\0 |G1DqM|];ٴRTR)H3)Cmj\$?ƃF1ED48t%Ln58x&45-Jh%z)Ţ!I:۬е*H\"h\"|>r\\-q,25ZE\$+\$Jz,mZHQ&EԂA6#LtU8iRrX\$Tf|^@b1'\"ˊ_>\rRFő\nl꠫q̅\"fD<Yu.γV+Y22-;Q(\0Ze#Zqf3j\n#lP#>Mw(vW^\$aE%#ʍN2n@*33q2J m%=6?o;q0%pCX6.J<tI鋒 CT\\;[(D bl]∙E,uo ^ކDHIP!-mX\nuy'\n@\",tcK'!uf5̔ CG0Ò8| <&`z@t^.!t@2\r!3#Nht|\0I\r/ Ao]FCpCHt8}Z+D@(tXE&+b\r-48#\$RfLuA1r+ZGC(,¯.(SjXaܙ?'3+B%;y.YB5DgH1]ɜ(FT,iva@\"*E +H(\$ i]I8\"w:\$o\r ljePDa͛'Կ1xS\n֓9&\nG(A4D4X&j~C50R tM>xFF2RXNPPѼoA A3\0ԁ\0f9Gİ&;]= %\$kt89zXMLPeu,&xNT(@( O>j<\0`\n@U\"h-c\$I&bȋ VrL,y@&T*%r#+Q\n9!~Ybij e CeSRzy\0[EB\r%oR'کH230Lǯb!rs,h+2\\[ST!5Pp !b\rP~.\r4F1ҰW%T8ss%RLOc\nWd`0hD`5R*2JV\n#>BA^f 1f<Ɖ6qU#\"%иܢZ DəXEe.y(b\n٧Hz(!ѠS,1p[CNy+a<gnIuq,*d+lg*myk5FBLM&K^K3]gV4|җI[E.NdXMڜ3KUZ'%\rxD+(vket9\\XbRta˵]oeBBÀNFAR\nnMU浸[0\\\\\nˤAsĪ_|Yv5nSpn |?'*,Yhg)yɩsNPѧ^LyG@*Z~0:u>RzQi!ug4X\n QH,*hѻj^9sTE:!NOȉ^0hF\"e\0000D&.D8WKFfC丂rNA3UO,r#2p8Ű®LjLeb鐶#H?-m1G٥UNa\r\$j\0OJh&ҩ\\\$+FZb,L#N0bjrPHe1ekfhV[n\rN6#<+\$`+m3+{/׃&rqhDʰ>*h&٬d3>/LB|vt*bp Y8cL\\&&W d~-Hϒâ,Eq>+H5Fi5jث|:5pd2ryGQA(g/ M'#6j(/*,VL.Eb`D@H8#duiR>&&\$+(Su',p2sҘ[13&cgKdxmfXiǐZFp-H= f{6-6clzc'\$X\"ڝJvs!2Ȗ!7s>2fr5R.MW5Ӻΐ:!r8;r-zXFXp~\r9sx̀R(?\"%@343V>\"?M\$#\npiwA\r%\r%mͤGD*UW%=AN1iv6L,44wì8'iE96sG%me@gB";break;case"ta":$g="W* iF\\Hd_+BQp 9t\\U@W(<\\@1 |@(:\r S.WAht]R&\\I`DJ\$:TϠX`*rj1k,Յz@%95|Udߠj䦸Cf4~Lgp:E5e&@.quW[\"+@m\0,-һ[&a;Dxr4&)s<!:\r?8\nRl[zR.<\n8N\"0AN*Åq` \no\072k,SD)Y,:҄)\rkf.b:C lJNr\$Ţ)20\nq\$&*A\$:SPzik\0ҏ9#xܣU-P J8\r,suYB\"\"+I\\Բ#6|\"ܢʵ(+r\07CURl,A\\'\r{EH_*4ةP)DX\$B\0T2&4\rRB\$.k{k=8F@2hfN=ޮ}%t\\)Yc2,5͖2OSHrOTe\n!VHrC\nRRB̈́54Bh5)Ֆ1+%\\IBIqi)SGZ0m0oMr3_5LCmDaR˫S\"XWJwKPn)Ԕ5.:_oṕ\\\\m6+(UX_[P2BmmFՂ07c=dU)HP 8ݞ&Zau(Α/KTwK,~ۚ#rn!pD1/6fjE^-u6>/ؐc܊L)26dnJpO'!ff/\$ؔiq5\"@W\rBSf6T\\!Hqa9&^`џ+4ka2 Cw>\\. !&ՠ NR4q]6粩S\"IixrB&cb_~\\aՇq/ tk eB\"Sw)2?\"CbGl~xfSgoKe%@yCk ׇ0aXs9K\n+IΆVO(`01H6fDD\$vZ7pSlcR&GM9&lL;v\$a\ng)/eN(u Ġ+X-Br>W'IEAQPs7b5PD\0,T7.V6e]&yvV;O,Z23a([ڋ%r#?}*-7&ߢjJƨ[\0Uޛ0z%%ҽ)=)Kֱw%Zy5jc?`\n \$|<@K<-~!ذh !ӳX\0c(lx\nx{dVQ\n<)D(ӗ!9^e+.Ϲc=sg?i3CO؞WbzC-p؝bS(3\rG/RvN\0UJR?.crx@&4гonBLaxNT(@(\n \"Pv:*=_ʣGE3-VkYFDI LlsV6TR\0,;L~o0@a0hWҋzA)GԌDmƛ?q)q_&8CLhJ{3*ͯ3\\i)\$yR6Yg>UҤ3 rCykiB®Q缛1CJ\"3#RFiI{JMLA9\$T~ܺyuHtvDZCy\"zwǭD<iL_`\n\"pJ|'yj+,@6F@u84}p-fvuy\"%\r\\u?LC\n[߇0&m{OcE=Php)SC(d98\rN:mAD`ݿ%c\na4`7\$]Іv7M}fa:dnd`ʄ(X:\r#FNn(/¤W\\AgN,i.Vt `Z@TgKV}DKhCG\\VsDbƄ&Wn')rbM,Єjb.ΜTPoLHBfdڐNФB-XDV ACs#g/7'9.zݤnz%4^og;MCq\r|*\"\$7Q:a\\fzf(Q\$0[ĺJM*qQAH>\\I\nQxCj3s%;mIH@pB0} ႸF(bR4\rU#\0'FR1W5HNq!nEfrړluM[roI\$mz::eh␎h&'\nbΦQUg͙%lb#L(Cf%Pcؔ5 AD,%t\nFXGh 0}Nr2~sѭ3Дk3s3J+3*؍jl T/,+67Hdi \nU/}&53|+8RQ.:dBjfG=tt&RtL\0~MrP.Fz|9Ei@ړ,&nHOB\0ȨO9_9lӨoLt8@@\n\rO\0}zF)\rLpƈONP²p-)u567iz wJsOxvvwh`W7NӽCzGGzLL4s{D7=}7{U+v(JD?SG8%/q/[uTrE,?OzkX\"TPBkU#3'5YwcurՋg{rTQ2^MU{`7MQu1Ӿu`vL^*q11X}8tziJQ0)؆ޘvL2L1j\rRUAG7q|EUM~amyunWQьl1Q}7t~54iw3o_Yy\$8ܐxEy\r֬B0rwݔw=^蓑8е{20qt1Y^`/DIk5i9_pusuAy2N~x=JSmn29-8ZHS%3xUpp🞺K;YєY`V \nr}uXPi\$qz vuOD1+\$N,gw;I1uJXߦ_Z.9W'Oj4d-@EpG;e_҈XDWZIQ`7)2xTn{z}]Dk!2~e\rV@`֕\rOƃ\r ̗k+=c\r`ı-\nZ\0AeEꅨ+WB1a7l2%%Y{7Zi%KfZFCu]yWoY(+[XrVHA!38-`DxuU12-w0!1*Kg8[ u>7|IN .jy<aa<7:6[O+9\0#;&\05(Õ5֚A@u\nRL,:˼%kx םw\$X\rpi]R{tlE<G~̱&=\r\0\r \r9sK' Cam&4T2qq9'=\0P\nNvD:d%pfz,ae&N3)Agk\r} Kbhގ\0[o<ۋDcsnc` \0@ t\n`";break;case"th":$g="\\! M@0tD\0 \nX:&\0*\n8\0 E30/\0ZB(^\0AK2\0&b8KGn I?J\\)b.)\\S\"s\0CWJ_6\\+eV6rJé5k]8@%994fv2 #!j65:i\\(zʳyW ej\0MLrS{q\0ק|\\Iq n[R|馛7;Z4 =j.Y7D 7i6LS0x4\r/0Oڶp\0@-pBP,JQpXD1jCb2α;\$3\$4<3/mJ'6Dڲ6@)[t+.~ s0/p#\rR'L[IΓʕEhD)1q7h\rl\n(E9*P>t\\8*/TI9&35kh_H\"UFq8Ő.e|&l UPIsLJ/\$'ajYfI۱aY93d\\!WqJCMc=a6T ^RQSh+;ĐF!pY뛍.^Ӄ,Eg+^;ybFbӷDriDmU2>Q6ZPwZD7Oa6%>NZam3\r%s`90S\"V\r'BMJYz;hӥliP2PMO\nѻp);wQ'porh^Y.QV+#`P:c?!\01#wi\\:\nbmI+wdmw8%E 1ƾ oj\"ϑc\"oͩ_zA4PJLLG X.A;ULP%Y(2ܰkm <6W{;6[*OmJb\nh.0;B(6@A!b<=3 ]2dF*py70a\0:<`(C8aGEVQu@9sZI`IS\nARy6Xt%b-b\"ɷ>vSRQQ1s\08V*b`)Ǡr62 |!fZ7%1%R*ܬ(r>s9pe4\0<.`z@t^.!Ht28,ux<~å5ꆰDHm6xa\\ST۩5ʳjjNU)#&t84Nǘ1+ZNJ!n'bw \0 \n (\0PbJBDc@\npVfUJEBPs~<θ:2R/is]WXSX*u]Lh*öܛ\$C4ߥ+\$ inƤ:;PPA:ʐo\r H<=?crgA*7\\+MPPWIT)\"k]ʂ&vξu%QgHPDoywfP^sO3tj%Iǐk.D֞{~&LB@C;{3} F\nPLH;uz}}tq`OY\\֭g^1/fO0ȵN\0vܙNg\n%\\ED~ϝ%WDI;NՍp9jS[d5I/qmi9u;xU`@gͼ:9G[ʗ,V̎\0{J[f0%#aۯIg稪8(?bc1=Qc-\"c=C-['Qn6rF'roq8<#Q4R CP\nC%5?p/T.;+;.hI4ԈI 8Q1?I(,`@y`G>k 34LɡNOOMM1U)eb. GLi:4٣&u=!4#KIRS2KJSR\"9FKMHAUU-R3#7Hf`U=TTWСP0c/5KS8&9B\0 O?XզUb&VV0IFRwDb6;y:.gf \0@ t\n`";break;case"tr":$g="E6M i=BQp 9 3!i6`'y\\\nb,P!= 2̑Hoǜ㑄̠%%M :Ir?F 5 \"ih`ttT;ơ䐣##CdAƇ8\\RHXȉI&d}u%{ 8SFH!x(b\"¢}>gPpH4^0E܊8DuyttĚE*&h/\nxfU9#\"73㷉ƼPQF͓f[<8^ڋlգ66nK<6\"W|swsQmuq%ֻp\\\"6OYmUPKilU\r=J1;\0i[|NyO3|x4HmwmI?D|˃\r@F(9_+Dd-caq\0'ul2T>@l{nҸR4[`p5;FucY@IXP/\ru@թ9gKUuM2ɀQ><0@4r\$*Z;\\oMA?SdGldam^UyN|}no_o8/`wvMG})3&T\$THU-|vHΖSzL||oZ \r\$ˈ)64.L鍰PR@RԬ\$#p)|D66/>*CNැDP ^%i%pbTP\\\rP~M\0\ru\0PK (p E;+>d#P,s\r0ȼNxb\$fR@^NJ-T!iDe*#̫,pQqO6T\r\"~3gRbNM\nbZXC4@E\0d/0Lbl~\nZ~ا8PY9REѰ[Q%pSJtq%\$<,LAh/-vbpOj&Mt`>|_>0tC(U1)6\$\$.\rf\"ax:@1(Fe,d+%86Ua6s&K i@B1B#pG81`2LA,%J:eqJ=+ \r>\rtȘ S@";break;case"uk":$g="I4ɠh-`&KBQp 9 rh--}[ZH`RdbrbhdZGH\rMs6@Se+ȃE6JTdJsh\$g\$Gfj>Cf4jSdRB\rhSE6\rVG!TIV{ZLʔi%QBvUXhZ<,Aev4s)@tNC Ӑt4zC kK4\\L+U0\\F>kC5A2@\$M4TAJ\\GB4;!/(+`P{\\\r'TSX6VZ(\"I(L` ʱ\nf@\\.)D(SkZڱ-ꄗ.YD~HMVF: E:fF(ɳ˚lGLA;Szu CDRJ`hr@=Bs;MNrJۭ)S3NjfBTш54T462(>ɫ)F#DMRDkgVhIt;rFHe_7i]EA MH\0ը.Aj}c\\f-7b\$GmJ)ʠc\",IxP*b)f%yenEOZ4k.,͞5oA%[4d5A0鲄PE(J}3;P\nX3rvT0è6:+c\"d>a\r&ٲRno7!Z5BKFxҧzu)GC8aB\0 @Pu;9fچ.f\0FkG]Je)aX\\,DDJŻ&-BND3bݥ+Sl.Z*%G7̉%FDF#\\QG en5\"&5E\rH&w̎;ă(xH\\ }A p@y,d2 ]8/QHo#\$h_<5 |Chp:AQ@x>K\\2\0Ď!s\$:E*F?HT2aХb!ͳ\\?])5cѾ?%%D-iFvT\n8)GRT)DG2TD|^o5 \\gA\n?l%G(.PGP.5R\rj6\n,]W̊gb9%Qy&cT7,\$pp\0d\r,HL(A:Ϩ8S30r\r4#`1uz:CHsSД \n<)FU]E=-LU\nA 6 S\\ GJEvMaGs3#e09 %uD\r7?t !4p@ۈ D PAs|ιUUqaK2eJ5\rM)\$6J3ALrL&!'e}!\nh36\r3+\r69B٣S0qFEi11~SZ[(f-g`+2)Qj)uχ\nʨ[ wLήI]B\\ԩU=wbӠ-k\n D; ؙ`\0 %[Q[UعPCy\"4Y\\Q}c\r?Nk'97&rO,@5XV{OgbTpX%\\ID&Y\$r6FM|WjL;P-6ۄLzj x{|DvTF\np`#dnT۰н*\nY&c\$jnh#BMւO´0rF\np6=0mw_mi>Ltd*4hn\nx!lD%@SL*{̸r!OND\n,Tϑ\rJ\n!7(EO9&y6y\nEѨM1Ƕj\$}ogW1V'0~dΰDtF0zPDkp&2zdx.HqaFPvT !!BFHhG#1#r2@ʲDJE&*b\"NER/1+!k22}(k*2!cҘ\$3d|\n[Z*%n- B_\nfZ,?\$7,8aI)rq<&@䯺%K, ȶl+-*DKxB*5*KM#%S-rgrZQH_b2%⭰7rBw8ai,KU7Ntӊ̲ F7(3+,P60!Dt%\",%*ӑB499ұD<&Txja`0ECTHY>? EY=F!GXâhzA dTt=C*_JO,e.\0B\rJK21<1R3>TM4.=;KgMtͶ+TI9ujNn&LHU8 P(..,+M78EQT,tfݪT/H3`U,V!ND:S-膊#;S,urM.W<C(5Vf,DER*JsDB4nl ٍ\n=e?#T]2tF[}@po6\$i42a^o]+FXH%e]xBVh3pYZ) 6\0\r[EX5Trt^52*\"@EcvK\n6B\r||r7*K!41=Q6E'B@Ȃx˘@I\np FiB\0:fQxnllg|hM.lABdGLżd5Ǩ BadZCt%.CD4? NX5e2Ɲ6\\m!2p֑o,l)\$t#Jzz@\nB7iv.Ð;p\nJnƧǢM2Cfpy//_rzPeQ\r\\UTP \$)Uy0D\$.o%7}C%9E{wZe\n!rċ4Ux:ݓ`] 襴!HN\0v\$\n@ \rI~\"Maf.n|,QM' Uf=7z~r'1 ,X~x#W<(;8ExbCTOD3bB.Oc&Ѫ>";break;case"vi":$g="Bp& *(J.0Q,Z)v@Tf\npjp*VC`]rY<#\$b\$L2@%9IΓ4˅d3\rFqt9N1QE3ڡhj[J;o\n(UbdaI¾RiD\0\0A)X8@q:g!C_#y̸6:ڋ.K;.inE{\rB\n'_2ka!W&Asv6'HƻvOIvLØ:J8楩Bakj*#ӊX\n\npEɚ44K\nd@3!pK Pkhv4D4 I/+|4\n#TP tom\rl)\"c\rh&I>\r41J\"dL>c(Zi S*\r螀6quTbwg\0VmcԠE%u;q:0Vح>@S+Q\$~4h VT\r@,9\032cCPe&0)v2S~ X\"l8ɳA-Uʌ)tۉ\nl)ܘSJ%2RH1D4EXP\";ſ3
3穩/eC#x:>s;/KA\0<(a`z@t^.!6\0poAPC\r4^:@pbU\r`sA 2|!SmqA.iG 3\\]\n& dA-݀t-P @-4G'd4RRܺqQ!O~e!!1 Cjb/rSF'I qIP(q-?1<I. \$H<V\0n\r9GCHsA!E30R\"i(l\r6 aY.@CQ,@'0'0\0\$>؆^0DvIxJ#g'r!DUQժVMBI\nDF-:U(&l7:6[R{9)n('[\$iPrڮ*1dS\"QG[!\$h&j(/'\\ KR\n?TUd|.Bcb5[@{y0Wڬ&,vGIUY,_u@SY zcK.?\n.X %,ehA\$XP\nЕ\"/Ki|\r !\n#TlEPk0\n\nW8(]/x0\"^LI&䆭ZW8mŜƎPՎdhUw8 ȏ H㫅aTPnhF!mVCv(Z(Yl*\$\\\"j +KJ}X#HI5Un>h^T^w]C݇\\x !\$#'tاy3&LOdLp&?ȤjƐfAP(!%cˏIY ӑv(L1Qq\$3{`?܊4:\"qIo+gȒDP ɋXj)ClڢKH\niiO>L:OtNYv)мcd|չrUY\"ŽA )9`HzHW'\\h\r#홡R!AB}hEBL9_q2%9\\~+t,KgD|Úto,F7m3mTE1\r^G%.J[5MpKWQti95R3ti4Vz0}vNώ;}l]̴drXms9rr\r}\\Z\$JHܹUPoGtެ^hutq:x)7(uFqn\nreO8V!N#~yU+3fEյO+|z؞z>=^]:*ߧΓ/Ys=3l/݊lC?^\$r l\":ZI!vH\nfV0\n\"Zt`k\r<rC+A,Dxq*Ƌ4P8_~r<JZh1PbNjQAK߂cVJiܨ&2Lm\"̈́(pFʊq/ *&|-PCPyЌ/20#^%\0бMOo8ĕ +pBb/ PW0B\rp]2\$pSL<:M\0*HDþķ&ZUP55wVV~cl/=mb{*@\"RQw~(Nb\\ b\r(|kxGrߦ\$BMbH.&\"JG \np:%\0J\rV谓<\$n,j@JH) IyNSq6(j,J\$6IE>jT2\nPbbf*l 8Cv%QNAA./t`rqr4trH7c\"6+[!X[e^oU%T(p'mGfLcx j&e .&Bp+r¤%p̶N\0X`S@X\0\r <%-R7B>wGy#A^0dGGQJ^\nmjG.4hrsZd9vpp&1\r3X20\nиHΐ-K+v30SQŖ4b";break;case"zh":$g="^s\\r|%:\$\nr.2r/dȻ[8 S8r!T\\sI4brЀJs!KdueVDX,#!j6 :t\nrU:.ZPˑ.\rVWd^%䌵rTԼ*s#U`Qdu'c(oFe3Nb`p2NSӣ:LYta~&6ۊrsk{fqw-\n2#*B!@LNzШ@F:QQWs~r.ndJXˊ;.M(bxd*cTAns%O-3!J1.[\$hVdDcMAlN-9@)6_Dseۂ%yP̞BFys\nZñ()tI4^F'<\$'I\0DYS1RZL9H]8\$O\\sS1}GR)v]PJ2E%?H%\0\$*H i N外g1i^iD}`LKFr4V%aBPHG1E#`6L@9c\nbr(v9Uo)DO\$=g)xsLR5rxarsyeG1?bчg1LA4s0Xr>3ORt@Sf9YUTTC`91x@0L3c21fT\$*\rw!\07c1Cr`3XZ3.`A XP9:\0)B0@9F* Sy#=&FVE`#xRϱ!rήh9c3ݎc9T(8\r:H#0z\r8Ax^;p2ocp9w<5{SW@ЎXD #hgk|Q5RP@Y\r!̾6pt697ީE\"]D*HBh(#o.\"q> A^ө:@\$\0AEQ`ANJ`+SIB\\L &ܜD@9pPGcȗ &Z0d\r*@`i4m\$8SE0r\r} 1i#ӿ4&ԘHpP L*C>b[0H\"ЀOFHXKz/aHcq]Ӷ\0b\r!/12u`r\r/H'2\$>B)UXP%^.@PO *\0BE3\"Pg,Z#a\r!`%E=9(f+\n`#-sEpv.0GQtxEҢ)O6366%D_*Z9Ilr1 :B3r(\"i\$ZB ]K9n lCeAA`9f2ӾxUHJ/Et QE\\+@KEА,mGĉhCB(P%*TH8\"5[&CI#{`Ƽ.O+8PFQ q>)O%f-TL0@w\nD=# ԐWWbA]\$\$l,b&ZL*#1ziۢ[DߑB(&M9 uAd@RM`ɡ^!}%U\n\n1coXHR ں3Q ţնpMRHFgZ!!hhBxiE Sk8Jӓ.G/Uu#\"S_M7GAkqj6E4K;ERVe#~ԯUӬ)ju]H]ҙ:ģ\\JKw9l-%%A^u\$pHo\r;g]GRdi=H\\aؓ]ˈ?3 =ɵnکye?9wS>Kz`?vL=/ys=\"+;yoґ_]-|q~_~Sʈ? ??䅌`Hwa20fle\"A>K;dnLljlI)t-\n\"l\"Sz1h`i\r \r`@uI05ƺcjɔwGV\nZ\0@} 6Z0O|#B8#Ƚ6 qP(a!(a\",ͣ=CC/ˠeкԁx!B\r9~\r2R6\"Z'BvQA`] OtȊ{7(YP\$tZI0\nR\"h9=c9U@4 \\-D4xƍ(z8_wO>n}#L0_75 |Chp4χ@x>A\n ޫMP myĮk\r;\0xP(X0F*A(-\"V@IJTWa-P A a\nR0D\"aTa\$G@d< Dq.&\"+t2\0O gt'RQ(l !J39@lC^!ӮxmGl mJ01\n<)@@#\r(o0\nqY&\"`7pi)@@4O#@r\r0E뮠'̿rZ)tjR\0(I\0'@BD!P\"\n E \$ŀ(jrd\n#PwQp(\n3a\rp\nv:80`Ow:\"Pȸg(!zT25FSxȤ2-IBUFPɔJq @Z&+R\",@a\n[@\" \n&B=(bCPm9T!\n(!@:S`JĢBiA9B}w&1\0xjRe4fX-TymB\"L:El\"QQx\"cc\\k>0]U 2;}Oy8u0U\"\"a̞GaxMkQ.Gl]k<^o1CGt!Җ'(\">:Y<,@y-ǎl!O oŘ2~\"|_b@e3d]W T\\|(DbU|'28A2uA(s)dB,8)/-7\"N!/\\K @ G&r|T!!c26\$\\1Q̓V\"Z QzHLk00@aR\$\\6v!E@gTeR+j1ߎa6-( !UHbҪ\$3fgVn}%ܕ>.juWg1Ru9\0(@%Q\"b#s9w>K[KeŸt?HwXwMhy-UGl6X/U5hm3Y\\Kކy<%qyed{ͤBFZYGC3Ƽؓ>?]ޣ˹/U[(9WTT%#9a[}vā&wUd2vk78)sݵ..[Jv]v.ъezjҜ/UAoܗ-=e*wLSc~d{Uƫg,\r\0KV\"D½kw#&>1o;:\0JX#`uEs\\\0x7֯މ'K6D\"DDc+\0.asOcp#\0I\0AR,-\0j.+L0JHkf9ؼQEbFdtLCjCCp2 y^lhAD8ɀ@\n @n^N)nM\naz\"p\\,w\"k\r\rU-`,h2 k\0iV\r \r`@'Ħ*f6&ޝt@z\\3G\nZ\0@sä7NgǖŬ\"4#j\$Hnn@0P.MH9#xpl)h;N,\r:# q3C\\6\$d<^j!,!qnnج\r\r:&(ED2 _N203@R\rg/OPL\"X%۲(Jm\r\",\"Jz ҦKE\n@@\n@ \r\0fzbe0Ѩ-@Ooperators);if($xf!==false)unset($b->operators[$xf]);}function
+dsn($cc,$V,$G){try{parent::__construct($cc,$V,$G);}catch(Exception$uc){auth_error($uc->getMessage());}$this->setAttribute(13,array('Min_PDOStatement'));$this->server_info=$this->getAttribute(4);}function
+query($H,$Ch=false){$I=parent::query($H);$this->error="";if(!$I){list(,$this->errno,$this->error)=$this->errorInfo();return
+false;}$this->store_result($I);return$I;}function
+multi_query($H){return$this->_result=$this->query($H);}function
+store_result($I=null){if(!$I){$I=$this->_result;if(!$I)return
+false;}if($I->columnCount()){$I->num_rows=$I->rowCount();return$I;}$this->affected_rows=$I->rowCount();return
+true;}function
+next_result(){if(!$this->_result)return
+false;$this->_result->_offset=0;return@$this->_result->nextRowset();}function
+result($H,$o=0){$I=$this->query($H);if(!$I)return
+false;$K=$I->fetch();return$K[$o];}}class
+Min_PDOStatement
+extends
+PDOStatement{var$_offset=0,$num_rows;function
+fetch_assoc(){return$this->fetch(2);}function
+fetch_row(){return$this->fetch(3);}function
+fetch_field(){$K=(object)$this->getColumnMeta($this->_offset++);$K->orgtable=$K->table;$K->orgname=$K->name;$K->charsetnr=(in_array("blob",(array)$K->flags)?63:0);return$K;}}}$Xb=array();class
+Min_SQL{var$_conn;function
+Min_SQL($h){$this->_conn=$h;}function
+select($Q,$M,$Z,$Xc,$Xe=array(),$z=1,$E=0,$Ef=false){global$b,$w;$Ad=(count($Xc)selectQueryBuild($M,$Z,$Xc,$Xe,$z,$E);if(!$H)$H="SELECT".limit(($_GET["page"]!="last"&&+$z&&$Xc&&$Ad&&$w=="sql"?"SQL_CALC_FOUND_ROWS ":"").implode(", ",$M)."\nFROM ".table($Q),($Z?"\nWHERE ".implode(" AND ",$Z):"").($Xc&&$Ad?"\nGROUP BY ".implode(", ",$Xc):"").($Xe?"\nORDER BY ".implode(", ",$Xe):""),($z!=""?+$z:null),($E?$z*$E:0),"\n");$Hg=microtime(true);$J=$this->_conn->query($H);if($Ef)echo$b->selectQuery($H,format_time($Hg));return$J;}function
+delete($Q,$Nf,$z=0){$H="FROM ".table($Q);return
+queries("DELETE".($z?limit1($H,$Nf):" $H$Nf"));}function
+update($Q,$O,$Nf,$z=0,$vg="\n"){$Th=array();foreach($O
+as$x=>$X)$Th[]="$x = $X";$H=table($Q)." SET$vg".implode(",$vg",$Th);return
+queries("UPDATE".($z?limit1($H,$Nf):" $H$Nf"));}function
+insert($Q,$O){return
+queries("INSERT INTO ".table($Q).($O?" (".implode(", ",array_keys($O)).")\nVALUES (".implode(", ",$O).")":" DEFAULT VALUES"));}function
+insertUpdate($Q,$L,$Cf){return
+false;}function
+begin(){return
+queries("BEGIN");}function
+commit(){return
+queries("COMMIT");}function
+rollback(){return
+queries("ROLLBACK");}}$Xb["sqlite"]="SQLite 3";$Xb["sqlite2"]="SQLite 2";if(isset($_GET["sqlite"])||isset($_GET["sqlite2"])){$_f=array((isset($_GET["sqlite"])?"SQLite3":"SQLite"),"PDO_SQLite");define("DRIVER",(isset($_GET["sqlite"])?"sqlite":"sqlite2"));if(class_exists(isset($_GET["sqlite"])?"SQLite3":"SQLiteDatabase")){if(isset($_GET["sqlite"])){class
+Min_SQLite{var$extension="SQLite3",$server_info,$affected_rows,$errno,$error,$_link;function
+Min_SQLite($Ic){$this->_link=new
+SQLite3($Ic);$Wh=$this->_link->version();$this->server_info=$Wh["versionString"];}function
+query($H){$I=@$this->_link->query($H);$this->error="";if(!$I){$this->errno=$this->_link->lastErrorCode();$this->error=$this->_link->lastErrorMsg();return
+false;}elseif($I->numColumns())return
+new
+Min_Result($I);$this->affected_rows=$this->_link->changes();return
+true;}function
+quote($P){return(is_utf8($P)?"'".$this->_link->escapeString($P)."'":"x'".reset(unpack('H*',$P))."'");}function
+store_result(){return$this->_result;}function
+result($H,$o=0){$I=$this->query($H);if(!is_object($I))return
+false;$K=$I->_result->fetchArray();return$K[$o];}}class
+Min_Result{var$_result,$_offset=0,$num_rows;function
+Min_Result($I){$this->_result=$I;}function
+fetch_assoc(){return$this->_result->fetchArray(SQLITE3_ASSOC);}function
+fetch_row(){return$this->_result->fetchArray(SQLITE3_NUM);}function
+fetch_field(){$e=$this->_offset++;$U=$this->_result->columnType($e);return(object)array("name"=>$this->_result->columnName($e),"type"=>$U,"charsetnr"=>($U==SQLITE3_BLOB?63:0),);}function
+__desctruct(){return$this->_result->finalize();}}}else{class
+Min_SQLite{var$extension="SQLite",$server_info,$affected_rows,$error,$_link;function
+Min_SQLite($Ic){$this->server_info=sqlite_libversion();$this->_link=new
+SQLiteDatabase($Ic);}function
+query($H,$Ch=false){$se=($Ch?"unbufferedQuery":"query");$I=@$this->_link->$se($H,SQLITE_BOTH,$n);$this->error="";if(!$I){$this->error=$n;return
+false;}elseif($I===true){$this->affected_rows=$this->changes();return
+true;}return
+new
+Min_Result($I);}function
+quote($P){return"'".sqlite_escape_string($P)."'";}function
+store_result(){return$this->_result;}function
+result($H,$o=0){$I=$this->query($H);if(!is_object($I))return
+false;$K=$I->_result->fetch();return$K[$o];}}class
+Min_Result{var$_result,$_offset=0,$num_rows;function
+Min_Result($I){$this->_result=$I;if(method_exists($I,'numRows'))$this->num_rows=$I->numRows();}function
+fetch_assoc(){$K=$this->_result->fetch(SQLITE_ASSOC);if(!$K)return
+false;$J=array();foreach($K
+as$x=>$X)$J[($x[0]=='"'?idf_unescape($x):$x)]=$X;return$J;}function
+fetch_row(){return$this->_result->fetch(SQLITE_NUM);}function
+fetch_field(){$C=$this->_result->fieldName($this->_offset++);$tf='(\\[.*]|"(?:[^"]|"")*"|(.+))';if(preg_match("~^($tf\\.)?$tf\$~",$C,$B)){$Q=($B[3]!=""?$B[3]:idf_unescape($B[2]));$C=($B[5]!=""?$B[5]:idf_unescape($B[4]));}return(object)array("name"=>$C,"orgname"=>$C,"orgtable"=>$Q,);}}}}elseif(extension_loaded("pdo_sqlite")){class
+Min_SQLite
+extends
+Min_PDO{var$extension="PDO_SQLite";function
+Min_SQLite($Ic){$this->dsn(DRIVER.":$Ic","","");}}}if(class_exists("Min_SQLite")){class
+Min_DB
+extends
+Min_SQLite{function
+Min_DB(){$this->Min_SQLite(":memory:");}function
+select_db($Ic){if(is_readable($Ic)&&$this->query("ATTACH ".$this->quote(preg_match("~(^[/\\\\]|:)~",$Ic)?$Ic:dirname($_SERVER["SCRIPT_FILENAME"])."/$Ic")." AS a")){$this->Min_SQLite($Ic);return
+true;}return
+false;}function
+multi_query($H){return$this->_result=$this->query($H);}function
+next_result(){return
+false;}}}class
+Min_Driver
+extends
+Min_SQL{function
+insertUpdate($Q,$L,$Cf){$Th=array();foreach($L
+as$O)$Th[]="(".implode(", ",$O).")";return
+queries("REPLACE INTO ".table($Q)." (".implode(", ",array_keys(reset($L))).") VALUES\n".implode(",\n",$Th));}}function
+idf_escape($t){return'"'.str_replace('"','""',$t).'"';}function
+table($t){return
+idf_escape($t);}function
+connect(){return
+new
+Min_DB;}function
+get_databases(){return
+array();}function
+limit($H,$Z,$z,$D=0,$vg=" "){return" $H$Z".($z!==null?$vg."LIMIT $z".($D?" OFFSET $D":""):"");}function
+limit1($H,$Z){global$h;return($h->result("SELECT sqlite_compileoption_used('ENABLE_UPDATE_DELETE_LIMIT')")?limit($H,$Z,1):" $H$Z");}function
+db_collation($m,$nb){global$h;return$h->result("PRAGMA encoding");}function
+engines(){return
+array();}function
+logged_user(){return
+get_current_user();}function
+tables_list(){return
+get_key_vals("SELECT name, type FROM sqlite_master WHERE type IN ('table', 'view') ORDER BY (name = 'sqlite_sequence'), name",1);}function
+count_tables($l){return
+array();}function
+table_status($C=""){global$h;$J=array();foreach(get_rows("SELECT name AS Name, type AS Engine FROM sqlite_master WHERE type IN ('table', 'view') ".($C!=""?"AND name = ".q($C):"ORDER BY name"))as$K){$K["Oid"]=1;$K["Auto_increment"]="";$K["Rows"]=$h->result("SELECT COUNT(*) FROM ".idf_escape($K["Name"]));$J[$K["Name"]]=$K;}foreach(get_rows("SELECT * FROM sqlite_sequence",null,"")as$K)$J[$K["name"]]["Auto_increment"]=$K["seq"];return($C!=""?$J[$C]:$J);}function
+is_view($R){return$R["Engine"]=="view";}function
+fk_support($R){global$h;return!$h->result("SELECT sqlite_compileoption_used('OMIT_FOREIGN_KEY')");}function
+fields($Q){global$h;$J=array();$Cf="";foreach(get_rows("PRAGMA table_info(".table($Q).")")as$K){$C=$K["name"];$U=strtolower($K["type"]);$Lb=$K["dflt_value"];$J[$C]=array("field"=>$C,"type"=>(preg_match('~int~i',$U)?"integer":(preg_match('~char|clob|text~i',$U)?"text":(preg_match('~blob~i',$U)?"blob":(preg_match('~real|floa|doub~i',$U)?"real":"numeric")))),"full_type"=>$U,"default"=>(preg_match("~'(.*)'~",$Lb,$B)?str_replace("''","'",$B[1]):($Lb=="NULL"?null:$Lb)),"null"=>!$K["notnull"],"privileges"=>array("select"=>1,"insert"=>1,"update"=>1),"primary"=>$K["pk"],);if($K["pk"]){if($Cf!="")$J[$Cf]["auto_increment"]=false;elseif(preg_match('~^integer$~i',$U))$J[$C]["auto_increment"]=true;$Cf=$C;}}$Fg=$h->result("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ".q($Q));preg_match_all('~(("[^"]*+")+|[a-z0-9_]+)\s+text\s+COLLATE\s+(\'[^\']+\'|\S+)~i',$Fg,$ee,PREG_SET_ORDER);foreach($ee
+as$B){$C=str_replace('""','"',preg_replace('~^"|"$~','',$B[1]));if($J[$C])$J[$C]["collation"]=trim($B[3],"'");}return$J;}function
+indexes($Q,$i=null){global$h;if(!is_object($i))$i=$h;$J=array();$Fg=$i->result("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ".q($Q));if(preg_match('~\bPRIMARY\s+KEY\s*\((([^)"]+|"[^"]*")++)~i',$Fg,$B)){$J[""]=array("type"=>"PRIMARY","columns"=>array(),"lengths"=>array(),"descs"=>array());preg_match_all('~((("[^"]*+")+)|(\S+))(\s+(ASC|DESC))?(,\s*|$)~i',$B[1],$ee,PREG_SET_ORDER);foreach($ee
+as$B){$J[""]["columns"][]=idf_unescape($B[2]).$B[4];$J[""]["descs"][]=(preg_match('~DESC~i',$B[5])?'1':null);}}if(!$J){foreach(fields($Q)as$C=>$o){if($o["primary"])$J[""]=array("type"=>"PRIMARY","columns"=>array($C),"lengths"=>array(),"descs"=>array(null));}}$Gg=get_key_vals("SELECT name, sql FROM sqlite_master WHERE type = 'index' AND tbl_name = ".q($Q),$i);foreach(get_rows("PRAGMA index_list(".table($Q).")",$i)as$K){$C=$K["name"];$u=array("type"=>($K["unique"]?"UNIQUE":"INDEX"));$u["lengths"]=array();$u["descs"]=array();foreach(get_rows("PRAGMA index_info(".idf_escape($C).")",$i)as$lg){$u["columns"][]=$lg["name"];$u["descs"][]=null;}if(preg_match('~^CREATE( UNIQUE)? INDEX '.preg_quote(idf_escape($C).' ON '.idf_escape($Q),'~').' \((.*)\)$~i',$Gg[$C],$Yf)){preg_match_all('/("[^"]*+")+( DESC)?/',$Yf[2],$ee);foreach($ee[2]as$x=>$X){if($X)$u["descs"][$x]='1';}}if(!$J[""]||$u["type"]!="UNIQUE"||$u["columns"]!=$J[""]["columns"]||$u["descs"]!=$J[""]["descs"]||!preg_match("~^sqlite_~",$C))$J[$C]=$u;}return$J;}function
+foreign_keys($Q){$J=array();foreach(get_rows("PRAGMA foreign_key_list(".table($Q).")")as$K){$q=&$J[$K["id"]];if(!$q)$q=$K;$q["source"][]=$K["from"];$q["target"][]=$K["to"];}return$J;}function
+view($C){global$h;return
+array("select"=>preg_replace('~^(?:[^`"[]+|`[^`]*`|"[^"]*")* AS\\s+~iU','',$h->result("SELECT sql FROM sqlite_master WHERE name = ".q($C))));}function
+collations(){return(isset($_GET["create"])?get_vals("PRAGMA collation_list",1):array());}function
+information_schema($m){return
+false;}function
+error(){global$h;return
+h($h->error);}function
+check_sqlite_name($C){global$h;$Cc="db|sdb|sqlite";if(!preg_match("~^[^\\0]*\\.($Cc)\$~",$C)){$h->error=lang(21,str_replace("|",", ",$Cc));return
+false;}return
+true;}function
+create_database($m,$d){global$h;if(file_exists($m)){$h->error=lang(22);return
+false;}if(!check_sqlite_name($m))return
+false;try{$_=new
+Min_SQLite($m);}catch(Exception$uc){$h->error=$uc->getMessage();return
+false;}$_->query('PRAGMA encoding = "UTF-8"');$_->query('CREATE TABLE adminer (i)');$_->query('DROP TABLE adminer');return
+true;}function
+drop_databases($l){global$h;$h->Min_SQLite(":memory:");foreach($l
+as$m){if(!@unlink($m)){$h->error=lang(22);return
+false;}}return
+true;}function
+rename_database($C,$d){global$h;if(!check_sqlite_name($C))return
+false;$h->Min_SQLite(":memory:");$h->error=lang(22);return@rename(DB,$C);}function
+auto_increment(){return" PRIMARY KEY".(DRIVER=="sqlite"?" AUTOINCREMENT":"");}function
+alter_table($Q,$C,$p,$Mc,$rb,$nc,$d,$La,$of){$Nh=($Q==""||$Mc);foreach($p
+as$o){if($o[0]!=""||!$o[1]||$o[2]){$Nh=true;break;}}$c=array();$ff=array();foreach($p
+as$o){if($o[1]){$c[]=($Nh?$o[1]:"ADD ".implode($o[1]));if($o[0]!="")$ff[$o[0]]=$o[1][0];}}if(!$Nh){foreach($c
+as$X){if(!queries("ALTER TABLE ".table($Q)." $X"))return
+false;}if($Q!=$C&&!queries("ALTER TABLE ".table($Q)." RENAME TO ".table($C)))return
+false;}elseif(!recreate_table($Q,$C,$c,$ff,$Mc))return
+false;if($La)queries("UPDATE sqlite_sequence SET seq = $La WHERE name = ".q($C));return
+true;}function
+recreate_table($Q,$C,$p,$ff,$Mc,$v=array()){if($Q!=""){if(!$p){foreach(fields($Q)as$x=>$o){$p[]=process_field($o,$o);$ff[$x]=idf_escape($x);}}$Df=false;foreach($p
+as$o){if($o[6])$Df=true;}$ac=array();foreach($v
+as$x=>$X){if($X[2]=="DROP"){$ac[$X[1]]=true;unset($v[$x]);}}foreach(indexes($Q)as$Jd=>$u){$f=array();foreach($u["columns"]as$x=>$e){if(!$ff[$e])continue
+2;$f[]=$ff[$e].($u["descs"][$x]?" DESC":"");}if(!$ac[$Jd]){if($u["type"]!="PRIMARY"||!$Df)$v[]=array($u["type"],$Jd,$f);}}foreach($v
+as$x=>$X){if($X[0]=="PRIMARY"){unset($v[$x]);$Mc[]=" PRIMARY KEY (".implode(", ",$X[2]).")";}}foreach(foreign_keys($Q)as$Jd=>$q){foreach($q["source"]as$x=>$e){if(!$ff[$e])continue
+2;$q["source"][$x]=idf_unescape($ff[$e]);}if(!isset($Mc[" $Jd"]))$Mc[]=" ".format_foreign_key($q);}queries("BEGIN");}foreach($p
+as$x=>$o)$p[$x]=" ".implode($o);$p=array_merge($p,array_filter($Mc));if(!queries("CREATE TABLE ".table($Q!=""?"adminer_$C":$C)." (\n".implode(",\n",$p)."\n)"))return
+false;if($Q!=""){if($ff&&!queries("INSERT INTO ".table("adminer_$C")." (".implode(", ",$ff).") SELECT ".implode(", ",array_map('idf_escape',array_keys($ff)))." FROM ".table($Q)))return
+false;$zh=array();foreach(triggers($Q)as$xh=>$kh){$wh=trigger($xh);$zh[]="CREATE TRIGGER ".idf_escape($xh)." ".implode(" ",$kh)." ON ".table($C)."\n$wh[Statement]";}if(!queries("DROP TABLE ".table($Q)))return
+false;queries("ALTER TABLE ".table("adminer_$C")." RENAME TO ".table($C));if(!alter_indexes($C,$v))return
+false;foreach($zh
+as$wh){if(!queries($wh))return
+false;}queries("COMMIT");}return
+true;}function
+index_sql($Q,$U,$C,$f){return"CREATE $U ".($U!="INDEX"?"INDEX ":"").idf_escape($C!=""?$C:uniqid($Q."_"))." ON ".table($Q)." $f";}function
+alter_indexes($Q,$c){foreach($c
+as$Cf){if($Cf[0]=="PRIMARY")return
+recreate_table($Q,$Q,array(),array(),array(),$c);}foreach(array_reverse($c)as$X){if(!queries($X[2]=="DROP"?"DROP INDEX ".idf_escape($X[1]):index_sql($Q,$X[0],$X[1],"(".implode(", ",$X[2]).")")))return
+false;}return
+true;}function
+truncate_tables($S){return
+apply_queries("DELETE FROM",$S);}function
+drop_views($Yh){return
+apply_queries("DROP VIEW",$Yh);}function
+drop_tables($S){return
+apply_queries("DROP TABLE",$S);}function
+move_tables($S,$Yh,$bh){return
+false;}function
+trigger($C){global$h;if($C=="")return
+array("Statement"=>"BEGIN\n\t;\nEND");$t='(?:[^`"\\s]+|`[^`]*`|"[^"]*")+';$yh=trigger_options();preg_match("~^CREATE\\s+TRIGGER\\s*$t\\s*(".implode("|",$yh["Timing"]).")\\s+([a-z]+)(?:\\s+OF\\s+($t))?\\s+ON\\s*$t\\s*(?:FOR\\s+EACH\\s+ROW\\s)?(.*)~is",$h->result("SELECT sql FROM sqlite_master WHERE type = 'trigger' AND name = ".q($C)),$B);$Ge=$B[3];return
+array("Timing"=>strtoupper($B[1]),"Event"=>strtoupper($B[2]).($Ge?" OF":""),"Of"=>($Ge[0]=='`'||$Ge[0]=='"'?idf_unescape($Ge):$Ge),"Trigger"=>$C,"Statement"=>$B[4],);}function
+triggers($Q){$J=array();$yh=trigger_options();foreach(get_rows("SELECT * FROM sqlite_master WHERE type = 'trigger' AND tbl_name = ".q($Q))as$K){preg_match('~^CREATE\\s+TRIGGER\\s*(?:[^`"\\s]+|`[^`]*`|"[^"]*")+\\s*('.implode("|",$yh["Timing"]).')\\s*(.*)\\s+ON\\b~iU',$K["sql"],$B);$J[$K["name"]]=array($B[1],$B[2]);}return$J;}function
+trigger_options(){return
+array("Timing"=>array("BEFORE","AFTER","INSTEAD OF"),"Event"=>array("INSERT","UPDATE","UPDATE OF","DELETE"),"Type"=>array("FOR EACH ROW"),);}function
+routine($C,$U){}function
+routines(){}function
+routine_languages(){}function
+begin(){return
+queries("BEGIN");}function
+last_id(){global$h;return$h->result("SELECT LAST_INSERT_ROWID()");}function
+explain($h,$H){return$h->query("EXPLAIN QUERY PLAN $H");}function
+found_rows($R,$Z){}function
+types(){return
+array();}function
+schemas(){return
+array();}function
+get_schema(){return"";}function
+set_schema($pg){return
+true;}function
+create_sql($Q,$La){global$h;$J=$h->result("SELECT sql FROM sqlite_master WHERE type IN ('table', 'view') AND name = ".q($Q));foreach(indexes($Q)as$C=>$u){if($C=='')continue;$J.=";\n\n".index_sql($Q,$u['type'],$C,"(".implode(", ",array_map('idf_escape',$u['columns'])).")");}return$J;}function
+truncate_sql($Q){return"DELETE FROM ".table($Q);}function
+use_sql($Gb){}function
+trigger_sql($Q,$Mg){return
+implode(get_vals("SELECT sql || ';;\n' FROM sqlite_master WHERE type = 'trigger' AND tbl_name = ".q($Q)));}function
+show_variables(){global$h;$J=array();foreach(array("auto_vacuum","cache_size","count_changes","default_cache_size","empty_result_callbacks","encoding","foreign_keys","full_column_names","fullfsync","journal_mode","journal_size_limit","legacy_file_format","locking_mode","page_size","max_page_count","read_uncommitted","recursive_triggers","reverse_unordered_selects","secure_delete","short_column_names","synchronous","temp_store","temp_store_directory","schema_version","integrity_check","quick_check")as$x)$J[$x]=$h->result("PRAGMA $x");return$J;}function
+show_status(){$J=array();foreach(get_vals("PRAGMA compile_options")as$Ue){list($x,$X)=explode("=",$Ue,2);$J[$x]=$X;}return$J;}function
+convert_field($o){}function
+unconvert_field($o,$J){return$J;}function
+support($Fc){return
+preg_match('~^(columns|database|drop_col|dump|indexes|move_col|sql|status|table|trigger|variables|view|view_trigger)$~',$Fc);}$w="sqlite";$Bh=array("integer"=>0,"real"=>0,"numeric"=>0,"text"=>0,"blob"=>0);$Lg=array_keys($Bh);$Ih=array();$Se=array("=","<",">","<=",">=","!=","LIKE","LIKE %%","IN","IS NULL","NOT LIKE","NOT IN","IS NOT NULL","SQL");$Uc=array("hex","length","lower","round","unixepoch","upper");$Zc=array("avg","count","count distinct","group_concat","max","min","sum");$fc=array(array(),array("integer|real|numeric"=>"+/-","text"=>"||",));}$Xb["pgsql"]="PostgreSQL";if(isset($_GET["pgsql"])){$_f=array("PgSQL","PDO_PgSQL");define("DRIVER","pgsql");if(extension_loaded("pgsql")){class
+Min_DB{var$extension="PgSQL",$_link,$_result,$_string,$_database=true,$server_info,$affected_rows,$error;function
+_error($qc,$n){if(ini_bool("html_errors"))$n=html_entity_decode(strip_tags($n));$n=preg_replace('~^[^:]*: ~','',$n);$this->error=$n;}function
+connect($N,$V,$G){global$b;$m=$b->database();set_error_handler(array($this,'_error'));$this->_string="host='".str_replace(":","' port='",addcslashes($N,"'\\"))."' user='".addcslashes($V,"'\\")."' password='".addcslashes($G,"'\\")."'";$this->_link=@pg_connect("$this->_string dbname='".($m!=""?addcslashes($m,"'\\"):"postgres")."'",PGSQL_CONNECT_FORCE_NEW);if(!$this->_link&&$m!=""){$this->_database=false;$this->_link=@pg_connect("$this->_string dbname='postgres'",PGSQL_CONNECT_FORCE_NEW);}restore_error_handler();if($this->_link){$Wh=pg_version($this->_link);$this->server_info=$Wh["server"];pg_set_client_encoding($this->_link,"UTF8");}return(bool)$this->_link;}function
+quote($P){return"'".pg_escape_string($this->_link,$P)."'";}function
+select_db($Gb){global$b;if($Gb==$b->database())return$this->_database;$J=@pg_connect("$this->_string dbname='".addcslashes($Gb,"'\\")."'",PGSQL_CONNECT_FORCE_NEW);if($J)$this->_link=$J;return$J;}function
+close(){$this->_link=@pg_connect("$this->_string dbname='postgres'");}function
+query($H,$Ch=false){$I=@pg_query($this->_link,$H);$this->error="";if(!$I){$this->error=pg_last_error($this->_link);return
+false;}elseif(!pg_num_fields($I)){$this->affected_rows=pg_affected_rows($I);return
+true;}return
+new
+Min_Result($I);}function
+multi_query($H){return$this->_result=$this->query($H);}function
+store_result(){return$this->_result;}function
+next_result(){return
+false;}function
+result($H,$o=0){$I=$this->query($H);if(!$I||!$I->num_rows)return
+false;return
+pg_fetch_result($I->_result,0,$o);}}class
+Min_Result{var$_result,$_offset=0,$num_rows;function
+Min_Result($I){$this->_result=$I;$this->num_rows=pg_num_rows($I);}function
+fetch_assoc(){return
+pg_fetch_assoc($this->_result);}function
+fetch_row(){return
+pg_fetch_row($this->_result);}function
+fetch_field(){$e=$this->_offset++;$J=new
+stdClass;if(function_exists('pg_field_table'))$J->orgtable=pg_field_table($this->_result,$e);$J->name=pg_field_name($this->_result,$e);$J->orgname=$J->name;$J->type=pg_field_type($this->_result,$e);$J->charsetnr=($J->type=="bytea"?63:0);return$J;}function
+__destruct(){pg_free_result($this->_result);}}}elseif(extension_loaded("pdo_pgsql")){class
+Min_DB
+extends
+Min_PDO{var$extension="PDO_PgSQL";function
+connect($N,$V,$G){global$b;$m=$b->database();$P="pgsql:host='".str_replace(":","' port='",addcslashes($N,"'\\"))."' options='-c client_encoding=utf8'";$this->dsn("$P dbname='".($m!=""?addcslashes($m,"'\\"):"postgres")."'",$V,$G);return
+true;}function
+select_db($Gb){global$b;return($b->database()==$Gb);}function
+close(){}}}class
+Min_Driver
+extends
+Min_SQL{function
+insertUpdate($Q,$L,$Cf){global$h;foreach($L
+as$O){$Jh=array();$Z=array();foreach($O
+as$x=>$X){$Jh[]="$x = $X";if(isset($Cf[idf_unescape($x)]))$Z[]="$x = $X";}if(!(($Z&&queries("UPDATE ".table($Q)." SET ".implode(", ",$Jh)." WHERE ".implode(" AND ",$Z))&&$h->affected_rows)||queries("INSERT INTO ".table($Q)." (".implode(", ",array_keys($O)).") VALUES (".implode(", ",$O).")")))return
+false;}return
+true;}}function
+idf_escape($t){return'"'.str_replace('"','""',$t).'"';}function
+table($t){return
+idf_escape($t);}function
+connect(){global$b;$h=new
+Min_DB;$k=$b->credentials();if($h->connect($k[0],$k[1],$k[2])){if($h->server_info>=9)$h->query("SET application_name = 'Adminer'");return$h;}return$h->error;}function
+get_databases(){return
+get_vals("SELECT datname FROM pg_database ORDER BY datname");}function
+limit($H,$Z,$z,$D=0,$vg=" "){return" $H$Z".($z!==null?$vg."LIMIT $z".($D?" OFFSET $D":""):"");}function
+limit1($H,$Z){return" $H$Z";}function
+db_collation($m,$nb){global$h;return$h->result("SHOW LC_COLLATE");}function
+engines(){return
+array();}function
+logged_user(){global$h;return$h->result("SELECT user");}function
+tables_list(){$H="SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = current_schema()";if(support('materializedview'))$H.="
+UNION ALL
+SELECT matviewname, 'MATERIALIZED VIEW'
+FROM pg_matviews
+WHERE schemaname = current_schema()";$H.="
+ORDER BY 1";return
+get_key_vals($H);}function
+count_tables($l){return
+array();}function
+table_status($C=""){$J=array();foreach(get_rows("SELECT relname AS \"Name\", CASE relkind WHEN 'r' THEN 'table' WHEN 'mv' THEN 'materialized view' WHEN 'f' THEN 'foreign table' ELSE 'view' END AS \"Engine\", pg_relation_size(oid) AS \"Data_length\", pg_total_relation_size(oid) - pg_relation_size(oid) AS \"Index_length\", obj_description(oid, 'pg_class') AS \"Comment\", relhasoids::int AS \"Oid\", reltuples as \"Rows\"
+FROM pg_class
+WHERE relkind IN ('r','v','mv','f')
+AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = current_schema())
+".($C!=""?"AND relname = ".q($C):"ORDER BY relname"))as$K)$J[$K["Name"]]=$K;return($C!=""?$J[$C]:$J);}function
+is_view($R){return
+in_array($R["Engine"],array("view","materialized view"));}function
+fk_support($R){return
+true;}function
+fields($Q){$J=array();$Ca=array('timestamp without time zone'=>'timestamp','timestamp with time zone'=>'timestamptz',);foreach(get_rows("SELECT a.attname AS field, format_type(a.atttypid, a.atttypmod) AS full_type, d.adsrc AS default, a.attnotnull::int, col_description(c.oid, a.attnum) AS comment
+FROM pg_class c
+JOIN pg_namespace n ON c.relnamespace = n.oid
+JOIN pg_attribute a ON c.oid = a.attrelid
+LEFT JOIN pg_attrdef d ON c.oid = d.adrelid AND a.attnum = d.adnum
+WHERE c.relname = ".q($Q)."
+AND n.nspname = current_schema()
+AND NOT a.attisdropped
+AND a.attnum > 0
+ORDER BY a.attnum")as$K){preg_match('~([^([]+)(\((.*)\))?([a-z ]+)?((\[[0-9]*])*)$~',$K["full_type"],$B);list(,$U,$y,$K["length"],$wa,$Fa)=$B;$K["length"].=$Fa;$cb=$U.$wa;if(isset($Ca[$cb])){$K["type"]=$Ca[$cb];$K["full_type"]=$K["type"].$y.$Fa;}else{$K["type"]=$U;$K["full_type"]=$K["type"].$y.$wa.$Fa;}$K["null"]=!$K["attnotnull"];$K["auto_increment"]=preg_match('~^nextval\\(~i',$K["default"]);$K["privileges"]=array("insert"=>1,"select"=>1,"update"=>1);if(preg_match('~(.+)::[^)]+(.*)~',$K["default"],$B))$K["default"]=($B[1][0]=="'"?idf_unescape($B[1]):$B[1]).$B[2];$J[$K["field"]]=$K;}return$J;}function
+indexes($Q,$i=null){global$h;if(!is_object($i))$i=$h;$J=array();$Ug=$i->result("SELECT oid FROM pg_class WHERE relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = current_schema()) AND relname = ".q($Q));$f=get_key_vals("SELECT attnum, attname FROM pg_attribute WHERE attrelid = $Ug AND attnum > 0",$i);foreach(get_rows("SELECT relname, indisunique::int, indisprimary::int, indkey, indoption FROM pg_index i, pg_class ci WHERE i.indrelid = $Ug AND ci.oid = i.indexrelid",$i)as$K){$Zf=$K["relname"];$J[$Zf]["type"]=($K["indisprimary"]?"PRIMARY":($K["indisunique"]?"UNIQUE":"INDEX"));$J[$Zf]["columns"]=array();foreach(explode(" ",$K["indkey"])as$qd)$J[$Zf]["columns"][]=$f[$qd];$J[$Zf]["descs"]=array();foreach(explode(" ",$K["indoption"])as$rd)$J[$Zf]["descs"][]=($rd&1?'1':null);$J[$Zf]["lengths"]=array();}return$J;}function
+foreign_keys($Q){global$Ne;$J=array();foreach(get_rows("SELECT conname, pg_get_constraintdef(oid) AS definition
+FROM pg_constraint
+WHERE conrelid = (SELECT pc.oid FROM pg_class AS pc INNER JOIN pg_namespace AS pn ON (pn.oid = pc.relnamespace) WHERE pc.relname = ".q($Q)." AND pn.nspname = current_schema())
+AND contype = 'f'::char
+ORDER BY conkey, conname")as$K){if(preg_match('~FOREIGN KEY\s*\((.+)\)\s*REFERENCES (.+)\((.+)\)(.*)$~iA',$K['definition'],$B)){$K['source']=array_map('trim',explode(',',$B[1]));if(preg_match('~^(("([^"]|"")+"|[^"]+)\.)?"?("([^"]|"")+"|[^"]+)$~',$B[2],$de)){$K['ns']=str_replace('""','"',preg_replace('~^"(.+)"$~','\1',$de[2]));$K['table']=str_replace('""','"',preg_replace('~^"(.+)"$~','\1',$de[4]));}$K['target']=array_map('trim',explode(',',$B[3]));$K['on_delete']=(preg_match("~ON DELETE ($Ne)~",$B[4],$de)?$de[1]:'NO ACTION');$K['on_update']=(preg_match("~ON UPDATE ($Ne)~",$B[4],$de)?$de[1]:'NO ACTION');$J[$K['conname']]=$K;}}return$J;}function
+view($C){global$h;return
+array("select"=>$h->result("SELECT pg_get_viewdef(".q($C).")"));}function
+collations(){return
+array();}function
+information_schema($m){return($m=="information_schema");}function
+error(){global$h;$J=h($h->error);if(preg_match('~^(.*\\n)?([^\\n]*)\\n( *)\\^(\\n.*)?$~s',$J,$B))$J=$B[1].preg_replace('~((?:[^&]|&[^;]*;){'.strlen($B[3]).'})(.*)~','\\1\\2 ',$B[2]).$B[4];return
+nl_br($J);}function
+create_database($m,$d){return
+queries("CREATE DATABASE ".idf_escape($m).($d?" ENCODING ".idf_escape($d):""));}function
+drop_databases($l){global$h;$h->close();return
+apply_queries("DROP DATABASE",$l,'idf_escape');}function
+rename_database($C,$d){return
+queries("ALTER DATABASE ".idf_escape(DB)." RENAME TO ".idf_escape($C));}function
+auto_increment(){return"";}function
+alter_table($Q,$C,$p,$Mc,$rb,$nc,$d,$La,$of){$c=array();$Mf=array();foreach($p
+as$o){$e=idf_escape($o[0]);$X=$o[1];if(!$X)$c[]="DROP $e";else{$Sh=$X[5];unset($X[5]);if(isset($X[6])&&$o[0]=="")$X[1]=($X[1]=="bigint"?" big":" ")."serial";if($o[0]=="")$c[]=($Q!=""?"ADD ":" ").implode($X);else{if($e!=$X[0])$Mf[]="ALTER TABLE ".table($Q)." RENAME $e TO $X[0]";$c[]="ALTER $e TYPE$X[1]";if(!$X[6]){$c[]="ALTER $e ".($X[3]?"SET$X[3]":"DROP DEFAULT");$c[]="ALTER $e ".($X[2]==" NULL"?"DROP NOT":"SET").$X[2];}}if($o[0]!=""||$Sh!="")$Mf[]="COMMENT ON COLUMN ".table($Q).".$X[0] IS ".($Sh!=""?substr($Sh,9):"''");}}$c=array_merge($c,$Mc);if($Q=="")array_unshift($Mf,"CREATE TABLE ".table($C)." (\n".implode(",\n",$c)."\n)");elseif($c)array_unshift($Mf,"ALTER TABLE ".table($Q)."\n".implode(",\n",$c));if($Q!=""&&$Q!=$C)$Mf[]="ALTER TABLE ".table($Q)." RENAME TO ".table($C);if($Q!=""||$rb!="")$Mf[]="COMMENT ON TABLE ".table($C)." IS ".q($rb);if($La!=""){}foreach($Mf
+as$H){if(!queries($H))return
+false;}return
+true;}function
+alter_indexes($Q,$c){$j=array();$Yb=array();$Mf=array();foreach($c
+as$X){if($X[0]!="INDEX")$j[]=($X[2]=="DROP"?"\nDROP CONSTRAINT ".idf_escape($X[1]):"\nADD".($X[1]!=""?" CONSTRAINT ".idf_escape($X[1]):"")." $X[0] ".($X[0]=="PRIMARY"?"KEY ":"")."(".implode(", ",$X[2]).")");elseif($X[2]=="DROP")$Yb[]=idf_escape($X[1]);else$Mf[]="CREATE INDEX ".idf_escape($X[1]!=""?$X[1]:uniqid($Q."_"))." ON ".table($Q)." (".implode(", ",$X[2]).")";}if($j)array_unshift($Mf,"ALTER TABLE ".table($Q).implode(",",$j));if($Yb)array_unshift($Mf,"DROP INDEX ".implode(", ",$Yb));foreach($Mf
+as$H){if(!queries($H))return
+false;}return
+true;}function
+truncate_tables($S){return
+queries("TRUNCATE ".implode(", ",array_map('table',$S)));return
+true;}function
+drop_views($Yh){return
+drop_tables($Yh);}function
+drop_tables($S){foreach($S
+as$Q){$Ig=table_status($Q);if(!queries("DROP ".strtoupper($Ig["Engine"])." ".table($Q)))return
+false;}return
+true;}function
+move_tables($S,$Yh,$bh){foreach(array_merge($S,$Yh)as$Q){$Ig=table_status($Q);if(!queries("ALTER ".strtoupper($Ig["Engine"])." ".table($Q)." SET SCHEMA ".idf_escape($bh)))return
+false;}return
+true;}function
+trigger($C){if($C=="")return
+array("Statement"=>"EXECUTE PROCEDURE ()");$L=get_rows('SELECT trigger_name AS "Trigger", condition_timing AS "Timing", event_manipulation AS "Event", \'FOR EACH \' || action_orientation AS "Type", action_statement AS "Statement" FROM information_schema.triggers WHERE event_object_table = '.q($_GET["trigger"]).' AND trigger_name = '.q($C));return
+reset($L);}function
+triggers($Q){$J=array();foreach(get_rows("SELECT * FROM information_schema.triggers WHERE event_object_table = ".q($Q))as$K)$J[$K["trigger_name"]]=array($K["condition_timing"],$K["event_manipulation"]);return$J;}function
+trigger_options(){return
+array("Timing"=>array("BEFORE","AFTER"),"Event"=>array("INSERT","UPDATE","DELETE"),"Type"=>array("FOR EACH ROW","FOR EACH STATEMENT"),);}function
+routines(){return
+get_rows('SELECT p.proname AS "ROUTINE_NAME", p.proargtypes AS "ROUTINE_TYPE", pg_catalog.format_type(p.prorettype, NULL) AS "DTD_IDENTIFIER"
+FROM pg_catalog.pg_namespace n
+JOIN pg_catalog.pg_proc p ON p.pronamespace = n.oid
+WHERE n.nspname = current_schema()
+ORDER BY p.proname');}function
+routine_languages(){return
+get_vals("SELECT langname FROM pg_catalog.pg_language");}function
+last_id(){return
+0;}function
+explain($h,$H){return$h->query("EXPLAIN $H");}function
+found_rows($R,$Z){global$h;if(preg_match("~ rows=([0-9]+)~",$h->result("EXPLAIN SELECT * FROM ".idf_escape($R["Name"]).($Z?" WHERE ".implode(" AND ",$Z):"")),$Yf))return$Yf[1];return
+false;}function
+types(){return
+get_vals("SELECT typname
+FROM pg_type
+WHERE typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = current_schema())
+AND typtype IN ('b','d','e')
+AND typelem = 0");}function
+schemas(){return
+get_vals("SELECT nspname FROM pg_namespace ORDER BY nspname");}function
+get_schema(){global$h;return$h->result("SELECT current_schema()");}function
+set_schema($og){global$h,$Bh,$Lg;$J=$h->query("SET search_path TO ".idf_escape($og));foreach(types()as$U){if(!isset($Bh[$U])){$Bh[$U]=0;$Lg[lang(23)][]=$U;}}return$J;}function
+use_sql($Gb){return"\connect ".idf_escape($Gb);}function
+show_variables(){return
+get_key_vals("SHOW ALL");}function
+process_list(){global$h;return
+get_rows("SELECT * FROM pg_stat_activity ORDER BY ".($h->server_info<9.2?"procpid":"pid"));}function
+show_status(){}function
+convert_field($o){}function
+unconvert_field($o,$J){return$J;}function
+support($Fc){global$h;return
+preg_match('~^(database|table|columns|sql|indexes|comment|view|'.($h->server_info>=9.3?'materializedview|':'').'scheme|processlist|sequence|trigger|type|variables|drop_col)$~',$Fc);}$w="pgsql";$Bh=array();$Lg=array();foreach(array(lang(24)=>array("smallint"=>5,"integer"=>10,"bigint"=>19,"boolean"=>1,"numeric"=>0,"real"=>7,"double precision"=>16,"money"=>20),lang(25)=>array("date"=>13,"time"=>17,"timestamp"=>20,"timestamptz"=>21,"interval"=>0),lang(26)=>array("character"=>0,"character varying"=>0,"text"=>0,"tsquery"=>0,"tsvector"=>0,"uuid"=>0,"xml"=>0),lang(27)=>array("bit"=>0,"bit varying"=>0,"bytea"=>0),lang(28)=>array("cidr"=>43,"inet"=>43,"macaddr"=>17,"txid_snapshot"=>0),lang(29)=>array("box"=>0,"circle"=>0,"line"=>0,"lseg"=>0,"path"=>0,"point"=>0,"polygon"=>0),)as$x=>$X){$Bh+=$X;$Lg[$x]=array_keys($X);}$Ih=array();$Se=array("=","<",">","<=",">=","!=","~","!~","LIKE","LIKE %%","ILIKE","ILIKE %%","IN","IS NULL","NOT LIKE","NOT IN","IS NOT NULL");$Uc=array("char_length","lower","round","to_hex","to_timestamp","upper");$Zc=array("avg","count","count distinct","max","min","sum");$fc=array(array("char"=>"md5","date|time"=>"now",),array("int|numeric|real|money"=>"+/-","date|time"=>"+ interval/- interval","char|text"=>"||",));}$Xb["oracle"]="Oracle";if(isset($_GET["oracle"])){$_f=array("OCI8","PDO_OCI");define("DRIVER","oracle");if(extension_loaded("oci8")){class
+Min_DB{var$extension="oci8",$_link,$_result,$server_info,$affected_rows,$errno,$error;function
+_error($qc,$n){if(ini_bool("html_errors"))$n=html_entity_decode(strip_tags($n));$n=preg_replace('~^[^:]*: ~','',$n);$this->error=$n;}function
+connect($N,$V,$G){$this->_link=@oci_new_connect($V,$G,$N,"AL32UTF8");if($this->_link){$this->server_info=oci_server_version($this->_link);return
+true;}$n=oci_error();$this->error=$n["message"];return
+false;}function
+quote($P){return"'".str_replace("'","''",$P)."'";}function
+select_db($Gb){return
+true;}function
+query($H,$Ch=false){$I=oci_parse($this->_link,$H);$this->error="";if(!$I){$n=oci_error($this->_link);$this->errno=$n["code"];$this->error=$n["message"];return
+false;}set_error_handler(array($this,'_error'));$J=@oci_execute($I);restore_error_handler();if($J){if(oci_num_fields($I))return
+new
+Min_Result($I);$this->affected_rows=oci_num_rows($I);}return$J;}function
+multi_query($H){return$this->_result=$this->query($H);}function
+store_result(){return$this->_result;}function
+next_result(){return
+false;}function
+result($H,$o=1){$I=$this->query($H);if(!is_object($I)||!oci_fetch($I->_result))return
+false;return
+oci_result($I->_result,$o);}}class
+Min_Result{var$_result,$_offset=1,$num_rows;function
+Min_Result($I){$this->_result=$I;}function
+_convert($K){foreach((array)$K
+as$x=>$X){if(is_a($X,'OCI-Lob'))$K[$x]=$X->load();}return$K;}function
+fetch_assoc(){return$this->_convert(oci_fetch_assoc($this->_result));}function
+fetch_row(){return$this->_convert(oci_fetch_row($this->_result));}function
+fetch_field(){$e=$this->_offset++;$J=new
+stdClass;$J->name=oci_field_name($this->_result,$e);$J->orgname=$J->name;$J->type=oci_field_type($this->_result,$e);$J->charsetnr=(preg_match("~raw|blob|bfile~",$J->type)?63:0);return$J;}function
+__destruct(){oci_free_statement($this->_result);}}}elseif(extension_loaded("pdo_oci")){class
+Min_DB
+extends
+Min_PDO{var$extension="PDO_OCI";function
+connect($N,$V,$G){$this->dsn("oci:dbname=//$N;charset=AL32UTF8",$V,$G);return
+true;}function
+select_db($Gb){return
+true;}}}class
+Min_Driver
+extends
+Min_SQL{function
+begin(){return
+true;}}function
+idf_escape($t){return'"'.str_replace('"','""',$t).'"';}function
+table($t){return
+idf_escape($t);}function
+connect(){global$b;$h=new
+Min_DB;$k=$b->credentials();if($h->connect($k[0],$k[1],$k[2]))return$h;return$h->error;}function
+get_databases(){return
+get_vals("SELECT tablespace_name FROM user_tablespaces");}function
+limit($H,$Z,$z,$D=0,$vg=" "){return($D?" * FROM (SELECT t.*, rownum AS rnum FROM (SELECT $H$Z) t WHERE rownum <= ".($z+$D).") WHERE rnum > $D":($z!==null?" * FROM (SELECT $H$Z) WHERE rownum <= ".($z+$D):" $H$Z"));}function
+limit1($H,$Z){return" $H$Z";}function
+db_collation($m,$nb){global$h;return$h->result("SELECT value FROM nls_database_parameters WHERE parameter = 'NLS_CHARACTERSET'");}function
+engines(){return
+array();}function
+logged_user(){global$h;return$h->result("SELECT USER FROM DUAL");}function
+tables_list(){return
+get_key_vals("SELECT table_name, 'table' FROM all_tables WHERE tablespace_name = ".q(DB)."
+UNION SELECT view_name, 'view' FROM user_views
+ORDER BY 1");}function
+count_tables($l){return
+array();}function
+table_status($C=""){$J=array();$qg=q($C);foreach(get_rows('SELECT table_name "Name", \'table\' "Engine", avg_row_len * num_rows "Data_length", num_rows "Rows" FROM all_tables WHERE tablespace_name = '.q(DB).($C!=""?" AND table_name = $qg":"")."
+UNION SELECT view_name, 'view', 0, 0 FROM user_views".($C!=""?" WHERE view_name = $qg":"")."
+ORDER BY 1")as$K){if($C!="")return$K;$J[$K["Name"]]=$K;}return$J;}function
+is_view($R){return$R["Engine"]=="view";}function
+fk_support($R){return
+true;}function
+fields($Q){$J=array();foreach(get_rows("SELECT * FROM all_tab_columns WHERE table_name = ".q($Q)." ORDER BY column_id")as$K){$U=$K["DATA_TYPE"];$y="$K[DATA_PRECISION],$K[DATA_SCALE]";if($y==",")$y=$K["DATA_LENGTH"];$J[$K["COLUMN_NAME"]]=array("field"=>$K["COLUMN_NAME"],"full_type"=>$U.($y?"($y)":""),"type"=>strtolower($U),"length"=>$y,"default"=>$K["DATA_DEFAULT"],"null"=>($K["NULLABLE"]=="Y"),"privileges"=>array("insert"=>1,"select"=>1,"update"=>1),);}return$J;}function
+indexes($Q,$i=null){$J=array();foreach(get_rows("SELECT uic.*, uc.constraint_type
+FROM user_ind_columns uic
+LEFT JOIN user_constraints uc ON uic.index_name = uc.constraint_name AND uic.table_name = uc.table_name
+WHERE uic.table_name = ".q($Q)."
+ORDER BY uc.constraint_type, uic.column_position",$i)as$K){$od=$K["INDEX_NAME"];$J[$od]["type"]=($K["CONSTRAINT_TYPE"]=="P"?"PRIMARY":($K["CONSTRAINT_TYPE"]=="U"?"UNIQUE":"INDEX"));$J[$od]["columns"][]=$K["COLUMN_NAME"];$J[$od]["lengths"][]=($K["CHAR_LENGTH"]&&$K["CHAR_LENGTH"]!=$K["COLUMN_LENGTH"]?$K["CHAR_LENGTH"]:null);$J[$od]["descs"][]=($K["DESCEND"]?'1':null);}return$J;}function
+view($C){$L=get_rows('SELECT text "select" FROM user_views WHERE view_name = '.q($C));return
+reset($L);}function
+collations(){return
+array();}function
+information_schema($m){return
+false;}function
+error(){global$h;return
+h($h->error);}function
+explain($h,$H){$h->query("EXPLAIN PLAN FOR $H");return$h->query("SELECT * FROM plan_table");}function
+found_rows($R,$Z){}function
+alter_table($Q,$C,$p,$Mc,$rb,$nc,$d,$La,$of){$c=$Yb=array();foreach($p
+as$o){$X=$o[1];if($X&&$o[0]!=""&&idf_escape($o[0])!=$X[0])queries("ALTER TABLE ".table($Q)." RENAME COLUMN ".idf_escape($o[0])." TO $X[0]");if($X)$c[]=($Q!=""?($o[0]!=""?"MODIFY (":"ADD ("):" ").implode($X).($Q!=""?")":"");else$Yb[]=idf_escape($o[0]);}if($Q=="")return
+queries("CREATE TABLE ".table($C)." (\n".implode(",\n",$c)."\n)");return(!$c||queries("ALTER TABLE ".table($Q)."\n".implode("\n",$c)))&&(!$Yb||queries("ALTER TABLE ".table($Q)." DROP (".implode(", ",$Yb).")"))&&($Q==$C||queries("ALTER TABLE ".table($Q)." RENAME TO ".table($C)));}function
+foreign_keys($Q){$J=array();$H="SELECT c_list.CONSTRAINT_NAME as NAME,
+c_src.COLUMN_NAME as SRC_COLUMN,
+c_dest.OWNER as DEST_DB,
+c_dest.TABLE_NAME as DEST_TABLE,
+c_dest.COLUMN_NAME as DEST_COLUMN,
+c_list.DELETE_RULE as ON_DELETE
+FROM ALL_CONSTRAINTS c_list, ALL_CONS_COLUMNS c_src, ALL_CONS_COLUMNS c_dest
+WHERE c_list.CONSTRAINT_NAME = c_src.CONSTRAINT_NAME
+AND c_list.R_CONSTRAINT_NAME = c_dest.CONSTRAINT_NAME
+AND c_list.CONSTRAINT_TYPE = 'R'
+AND c_src.TABLE_NAME = ".q($Q);foreach(get_rows($H)as$K)$J[$K['NAME']]=array("db"=>$K['DEST_DB'],"table"=>$K['DEST_TABLE'],"source"=>array($K['SRC_COLUMN']),"target"=>array($K['DEST_COLUMN']),"on_delete"=>$K['ON_DELETE'],"on_update"=>null,);return$J;}function
+truncate_tables($S){return
+apply_queries("TRUNCATE TABLE",$S);}function
+drop_views($Yh){return
+apply_queries("DROP VIEW",$Yh);}function
+drop_tables($S){return
+apply_queries("DROP TABLE",$S);}function
+last_id(){return
+0;}function
+schemas(){return
+get_vals("SELECT DISTINCT owner FROM dba_segments WHERE owner IN (SELECT username FROM dba_users WHERE default_tablespace NOT IN ('SYSTEM','SYSAUX'))");}function
+get_schema(){global$h;return$h->result("SELECT sys_context('USERENV', 'SESSION_USER') FROM dual");}function
+set_schema($pg){global$h;return$h->query("ALTER SESSION SET CURRENT_SCHEMA = ".idf_escape($pg));}function
+show_variables(){return
+get_key_vals('SELECT name, display_value FROM v$parameter');}function
+process_list(){return
+get_rows('SELECT sess.process AS "process", sess.username AS "user", sess.schemaname AS "schema", sess.status AS "status", sess.wait_class AS "wait_class", sess.seconds_in_wait AS "seconds_in_wait", sql.sql_text AS "sql_text", sess.machine AS "machine", sess.port AS "port"
+FROM v$session sess LEFT OUTER JOIN v$sql sql
+ON sql.sql_id = sess.sql_id
+WHERE sess.type = \'USER\'
+ORDER BY PROCESS
+');}function
+show_status(){$L=get_rows('SELECT * FROM v$instance');return
+reset($L);}function
+convert_field($o){}function
+unconvert_field($o,$J){return$J;}function
+support($Fc){return
+preg_match('~^(columns|database|drop_col|indexes|processlist|scheme|sql|status|table|variables|view|view_trigger)$~',$Fc);}$w="oracle";$Bh=array();$Lg=array();foreach(array(lang(24)=>array("number"=>38,"binary_float"=>12,"binary_double"=>21),lang(25)=>array("date"=>10,"timestamp"=>29,"interval year"=>12,"interval day"=>28),lang(26)=>array("char"=>2000,"varchar2"=>4000,"nchar"=>2000,"nvarchar2"=>4000,"clob"=>4294967295,"nclob"=>4294967295),lang(27)=>array("raw"=>2000,"long raw"=>2147483648,"blob"=>4294967295,"bfile"=>4294967296),)as$x=>$X){$Bh+=$X;$Lg[$x]=array_keys($X);}$Ih=array();$Se=array("=","<",">","<=",">=","!=","LIKE","LIKE %%","IN","IS NULL","NOT LIKE","NOT REGEXP","NOT IN","IS NOT NULL","SQL");$Uc=array("length","lower","round","upper");$Zc=array("avg","count","count distinct","max","min","sum");$fc=array(array("date"=>"current_date","timestamp"=>"current_timestamp",),array("number|float|double"=>"+/-","date|timestamp"=>"+ interval/- interval","char|clob"=>"||",));}$Xb["mssql"]="MS SQL";if(isset($_GET["mssql"])){$_f=array("SQLSRV","MSSQL");define("DRIVER","mssql");if(extension_loaded("sqlsrv")){class
+Min_DB{var$extension="sqlsrv",$_link,$_result,$server_info,$affected_rows,$errno,$error;function
+_get_error(){$this->error="";foreach(sqlsrv_errors()as$n){$this->errno=$n["code"];$this->error.="$n[message]\n";}$this->error=rtrim($this->error);}function
+connect($N,$V,$G){$this->_link=@sqlsrv_connect($N,array("UID"=>$V,"PWD"=>$G,"CharacterSet"=>"UTF-8"));if($this->_link){$sd=sqlsrv_server_info($this->_link);$this->server_info=$sd['SQLServerVersion'];}else$this->_get_error();return(bool)$this->_link;}function
+quote($P){return"'".str_replace("'","''",$P)."'";}function
+select_db($Gb){return$this->query("USE ".idf_escape($Gb));}function
+query($H,$Ch=false){$I=sqlsrv_query($this->_link,$H);$this->error="";if(!$I){$this->_get_error();return
+false;}return$this->store_result($I);}function
+multi_query($H){$this->_result=sqlsrv_query($this->_link,$H);$this->error="";if(!$this->_result){$this->_get_error();return
+false;}return
+true;}function
+store_result($I=null){if(!$I)$I=$this->_result;if(!$I)return
+false;if(sqlsrv_field_metadata($I))return
+new
+Min_Result($I);$this->affected_rows=sqlsrv_rows_affected($I);return
+true;}function
+next_result(){return$this->_result?sqlsrv_next_result($this->_result):null;}function
+result($H,$o=0){$I=$this->query($H);if(!is_object($I))return
+false;$K=$I->fetch_row();return$K[$o];}}class
+Min_Result{var$_result,$_offset=0,$_fields,$num_rows;function
+Min_Result($I){$this->_result=$I;}function
+_convert($K){foreach((array)$K
+as$x=>$X){if(is_a($X,'DateTime'))$K[$x]=$X->format("Y-m-d H:i:s");}return$K;}function
+fetch_assoc(){return$this->_convert(sqlsrv_fetch_array($this->_result,SQLSRV_FETCH_ASSOC,SQLSRV_SCROLL_NEXT));}function
+fetch_row(){return$this->_convert(sqlsrv_fetch_array($this->_result,SQLSRV_FETCH_NUMERIC,SQLSRV_SCROLL_NEXT));}function
+fetch_field(){if(!$this->_fields)$this->_fields=sqlsrv_field_metadata($this->_result);$o=$this->_fields[$this->_offset++];$J=new
+stdClass;$J->name=$o["Name"];$J->orgname=$o["Name"];$J->type=($o["Type"]==1?254:0);return$J;}function
+seek($D){for($s=0;$s<$D;$s++)sqlsrv_fetch($this->_result);}function
+__destruct(){sqlsrv_free_stmt($this->_result);}}}elseif(extension_loaded("mssql")){class
+Min_DB{var$extension="MSSQL",$_link,$_result,$server_info,$affected_rows,$error;function
+connect($N,$V,$G){$this->_link=@mssql_connect($N,$V,$G);if($this->_link){$I=$this->query("SELECT SERVERPROPERTY('ProductLevel'), SERVERPROPERTY('Edition')");$K=$I->fetch_row();$this->server_info=$this->result("sp_server_info 2",2)." [$K[0]] $K[1]";}else$this->error=mssql_get_last_message();return(bool)$this->_link;}function
+quote($P){return"'".str_replace("'","''",$P)."'";}function
+select_db($Gb){return
+mssql_select_db($Gb);}function
+query($H,$Ch=false){$I=mssql_query($H,$this->_link);$this->error="";if(!$I){$this->error=mssql_get_last_message();return
+false;}if($I===true){$this->affected_rows=mssql_rows_affected($this->_link);return
+true;}return
+new
+Min_Result($I);}function
+multi_query($H){return$this->_result=$this->query($H);}function
+store_result(){return$this->_result;}function
+next_result(){return
+mssql_next_result($this->_result);}function
+result($H,$o=0){$I=$this->query($H);if(!is_object($I))return
+false;return
+mssql_result($I->_result,0,$o);}}class
+Min_Result{var$_result,$_offset=0,$_fields,$num_rows;function
+Min_Result($I){$this->_result=$I;$this->num_rows=mssql_num_rows($I);}function
+fetch_assoc(){return
+mssql_fetch_assoc($this->_result);}function
+fetch_row(){return
+mssql_fetch_row($this->_result);}function
+num_rows(){return
+mssql_num_rows($this->_result);}function
+fetch_field(){$J=mssql_fetch_field($this->_result);$J->orgtable=$J->table;$J->orgname=$J->name;return$J;}function
+seek($D){mssql_data_seek($this->_result,$D);}function
+__destruct(){mssql_free_result($this->_result);}}}class
+Min_Driver
+extends
+Min_SQL{function
+insertUpdate($Q,$L,$Cf){foreach($L
+as$O){$Jh=array();$Z=array();foreach($O
+as$x=>$X){$Jh[]="$x = $X";if(isset($Cf[idf_unescape($x)]))$Z[]="$x = $X";}if(!queries("MERGE ".table($Q)." USING (VALUES(".implode(", ",$O).")) AS source (c".implode(", c",range(1,count($O))).") ON ".implode(" AND ",$Z)." WHEN MATCHED THEN UPDATE SET ".implode(", ",$Jh)." WHEN NOT MATCHED THEN INSERT (".implode(", ",array_keys($O)).") VALUES (".implode(", ",$O).");"))return
+false;}return
+true;}function
+begin(){return
+queries("BEGIN TRANSACTION");}}function
+idf_escape($t){return"[".str_replace("]","]]",$t)."]";}function
+table($t){return($_GET["ns"]!=""?idf_escape($_GET["ns"]).".":"").idf_escape($t);}function
+connect(){global$b;$h=new
+Min_DB;$k=$b->credentials();if($h->connect($k[0],$k[1],$k[2]))return$h;return$h->error;}function
+get_databases(){return
+get_vals("EXEC sp_databases");}function
+limit($H,$Z,$z,$D=0,$vg=" "){return($z!==null?" TOP (".($z+$D).")":"")." $H$Z";}function
+limit1($H,$Z){return
+limit($H,$Z,1);}function
+db_collation($m,$nb){global$h;return$h->result("SELECT collation_name FROM sys.databases WHERE name = ".q($m));}function
+engines(){return
+array();}function
+logged_user(){global$h;return$h->result("SELECT SUSER_NAME()");}function
+tables_list(){return
+get_key_vals("SELECT name, type_desc FROM sys.all_objects WHERE schema_id = SCHEMA_ID(".q(get_schema()).") AND type IN ('S', 'U', 'V') ORDER BY name");}function
+count_tables($l){global$h;$J=array();foreach($l
+as$m){$h->select_db($m);$J[$m]=$h->result("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES");}return$J;}function
+table_status($C=""){$J=array();foreach(get_rows("SELECT name AS Name, type_desc AS Engine FROM sys.all_objects WHERE schema_id = SCHEMA_ID(".q(get_schema()).") AND type IN ('S', 'U', 'V') ".($C!=""?"AND name = ".q($C):"ORDER BY name"))as$K){if($C!="")return$K;$J[$K["Name"]]=$K;}return$J;}function
+is_view($R){return$R["Engine"]=="VIEW";}function
+fk_support($R){return
+true;}function
+fields($Q){$J=array();foreach(get_rows("SELECT c.*, t.name type, d.definition [default]
+FROM sys.all_columns c
+JOIN sys.all_objects o ON c.object_id = o.object_id
+JOIN sys.types t ON c.user_type_id = t.user_type_id
+LEFT JOIN sys.default_constraints d ON c.default_object_id = d.parent_column_id
+WHERE o.schema_id = SCHEMA_ID(".q(get_schema()).") AND o.type IN ('S', 'U', 'V') AND o.name = ".q($Q))as$K){$U=$K["type"];$y=(preg_match("~char|binary~",$U)?$K["max_length"]:($U=="decimal"?"$K[precision],$K[scale]":""));$J[$K["name"]]=array("field"=>$K["name"],"full_type"=>$U.($y?"($y)":""),"type"=>$U,"length"=>$y,"default"=>$K["default"],"null"=>$K["is_nullable"],"auto_increment"=>$K["is_identity"],"collation"=>$K["collation_name"],"privileges"=>array("insert"=>1,"select"=>1,"update"=>1),"primary"=>$K["is_identity"],);}return$J;}function
+indexes($Q,$i=null){$J=array();foreach(get_rows("SELECT i.name, key_ordinal, is_unique, is_primary_key, c.name AS column_name, is_descending_key
+FROM sys.indexes i
+INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
+INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
+WHERE OBJECT_NAME(i.object_id) = ".q($Q),$i)as$K){$C=$K["name"];$J[$C]["type"]=($K["is_primary_key"]?"PRIMARY":($K["is_unique"]?"UNIQUE":"INDEX"));$J[$C]["lengths"]=array();$J[$C]["columns"][$K["key_ordinal"]]=$K["column_name"];$J[$C]["descs"][$K["key_ordinal"]]=($K["is_descending_key"]?'1':null);}return$J;}function
+view($C){global$h;return
+array("select"=>preg_replace('~^(?:[^[]|\\[[^]]*])*\\s+AS\\s+~isU','',$h->result("SELECT VIEW_DEFINITION FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA = SCHEMA_NAME() AND TABLE_NAME = ".q($C))));}function
+collations(){$J=array();foreach(get_vals("SELECT name FROM fn_helpcollations()")as$d)$J[preg_replace('~_.*~','',$d)][]=$d;return$J;}function
+information_schema($m){return
+false;}function
+error(){global$h;return
+nl_br(h(preg_replace('~^(\\[[^]]*])+~m','',$h->error)));}function
+create_database($m,$d){return
+queries("CREATE DATABASE ".idf_escape($m).(preg_match('~^[a-z0-9_]+$~i',$d)?" COLLATE $d":""));}function
+drop_databases($l){return
+queries("DROP DATABASE ".implode(", ",array_map('idf_escape',$l)));}function
+rename_database($C,$d){if(preg_match('~^[a-z0-9_]+$~i',$d))queries("ALTER DATABASE ".idf_escape(DB)." COLLATE $d");queries("ALTER DATABASE ".idf_escape(DB)." MODIFY NAME = ".idf_escape($C));return
+true;}function
+auto_increment(){return" IDENTITY".($_POST["Auto_increment"]!=""?"(".number($_POST["Auto_increment"]).",1)":"")." PRIMARY KEY";}function
+alter_table($Q,$C,$p,$Mc,$rb,$nc,$d,$La,$of){$c=array();foreach($p
+as$o){$e=idf_escape($o[0]);$X=$o[1];if(!$X)$c["DROP"][]=" COLUMN $e";else{$X[1]=preg_replace("~( COLLATE )'(\\w+)'~","\\1\\2",$X[1]);if($o[0]=="")$c["ADD"][]="\n ".implode("",$X).($Q==""?substr($Mc[$X[0]],16+strlen($X[0])):"");else{unset($X[6]);if($e!=$X[0])queries("EXEC sp_rename ".q(table($Q).".$e").", ".q(idf_unescape($X[0])).", 'COLUMN'");$c["ALTER COLUMN ".implode("",$X)][]="";}}}if($Q=="")return
+queries("CREATE TABLE ".table($C)." (".implode(",",(array)$c["ADD"])."\n)");if($Q!=$C)queries("EXEC sp_rename ".q(table($Q)).", ".q($C));if($Mc)$c[""]=$Mc;foreach($c
+as$x=>$X){if(!queries("ALTER TABLE ".idf_escape($C)." $x".implode(",",$X)))return
+false;}return
+true;}function
+alter_indexes($Q,$c){$u=array();$Yb=array();foreach($c
+as$X){if($X[2]=="DROP"){if($X[0]=="PRIMARY")$Yb[]=idf_escape($X[1]);else$u[]=idf_escape($X[1])." ON ".table($Q);}elseif(!queries(($X[0]!="PRIMARY"?"CREATE $X[0] ".($X[0]!="INDEX"?"INDEX ":"").idf_escape($X[1]!=""?$X[1]:uniqid($Q."_"))." ON ".table($Q):"ALTER TABLE ".table($Q)." ADD PRIMARY KEY")." (".implode(", ",$X[2]).")"))return
+false;}return(!$u||queries("DROP INDEX ".implode(", ",$u)))&&(!$Yb||queries("ALTER TABLE ".table($Q)." DROP ".implode(", ",$Yb)));}function
+last_id(){global$h;return$h->result("SELECT SCOPE_IDENTITY()");}function
+explain($h,$H){$h->query("SET SHOWPLAN_ALL ON");$J=$h->query($H);$h->query("SET SHOWPLAN_ALL OFF");return$J;}function
+found_rows($R,$Z){}function
+foreign_keys($Q){$J=array();foreach(get_rows("EXEC sp_fkeys @fktable_name = ".q($Q))as$K){$q=&$J[$K["FK_NAME"]];$q["table"]=$K["PKTABLE_NAME"];$q["source"][]=$K["FKCOLUMN_NAME"];$q["target"][]=$K["PKCOLUMN_NAME"];}return$J;}function
+truncate_tables($S){return
+apply_queries("TRUNCATE TABLE",$S);}function
+drop_views($Yh){return
+queries("DROP VIEW ".implode(", ",array_map('table',$Yh)));}function
+drop_tables($S){return
+queries("DROP TABLE ".implode(", ",array_map('table',$S)));}function
+move_tables($S,$Yh,$bh){return
+apply_queries("ALTER SCHEMA ".idf_escape($bh)." TRANSFER",array_merge($S,$Yh));}function
+trigger($C){if($C=="")return
+array();$L=get_rows("SELECT s.name [Trigger],
+CASE WHEN OBJECTPROPERTY(s.id, 'ExecIsInsertTrigger') = 1 THEN 'INSERT' WHEN OBJECTPROPERTY(s.id, 'ExecIsUpdateTrigger') = 1 THEN 'UPDATE' WHEN OBJECTPROPERTY(s.id, 'ExecIsDeleteTrigger') = 1 THEN 'DELETE' END [Event],
+CASE WHEN OBJECTPROPERTY(s.id, 'ExecIsInsteadOfTrigger') = 1 THEN 'INSTEAD OF' ELSE 'AFTER' END [Timing],
+c.text
+FROM sysobjects s
+JOIN syscomments c ON s.id = c.id
+WHERE s.xtype = 'TR' AND s.name = ".q($C));$J=reset($L);if($J)$J["Statement"]=preg_replace('~^.+\\s+AS\\s+~isU','',$J["text"]);return$J;}function
+triggers($Q){$J=array();foreach(get_rows("SELECT sys1.name,
+CASE WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsertTrigger') = 1 THEN 'INSERT' WHEN OBJECTPROPERTY(sys1.id, 'ExecIsUpdateTrigger') = 1 THEN 'UPDATE' WHEN OBJECTPROPERTY(sys1.id, 'ExecIsDeleteTrigger') = 1 THEN 'DELETE' END [Event],
+CASE WHEN OBJECTPROPERTY(sys1.id, 'ExecIsInsteadOfTrigger') = 1 THEN 'INSTEAD OF' ELSE 'AFTER' END [Timing]
+FROM sysobjects sys1
+JOIN sysobjects sys2 ON sys1.parent_obj = sys2.id
+WHERE sys1.xtype = 'TR' AND sys2.name = ".q($Q))as$K)$J[$K["name"]]=array($K["Timing"],$K["Event"]);return$J;}function
+trigger_options(){return
+array("Timing"=>array("AFTER","INSTEAD OF"),"Event"=>array("INSERT","UPDATE","DELETE"),"Type"=>array("AS"),);}function
+schemas(){return
+get_vals("SELECT name FROM sys.schemas");}function
+get_schema(){global$h;if($_GET["ns"]!="")return$_GET["ns"];return$h->result("SELECT SCHEMA_NAME()");}function
+set_schema($og){return
+true;}function
+use_sql($Gb){return"USE ".idf_escape($Gb);}function
+show_variables(){return
+array();}function
+show_status(){return
+array();}function
+convert_field($o){}function
+unconvert_field($o,$J){return$J;}function
+support($Fc){return
+preg_match('~^(columns|database|drop_col|indexes|scheme|sql|table|trigger|view|view_trigger)$~',$Fc);}$w="mssql";$Bh=array();$Lg=array();foreach(array(lang(24)=>array("tinyint"=>3,"smallint"=>5,"int"=>10,"bigint"=>20,"bit"=>1,"decimal"=>0,"real"=>12,"float"=>53,"smallmoney"=>10,"money"=>20),lang(25)=>array("date"=>10,"smalldatetime"=>19,"datetime"=>19,"datetime2"=>19,"time"=>8,"datetimeoffset"=>10),lang(26)=>array("char"=>8000,"varchar"=>8000,"text"=>2147483647,"nchar"=>4000,"nvarchar"=>4000,"ntext"=>1073741823),lang(27)=>array("binary"=>8000,"varbinary"=>8000,"image"=>2147483647),)as$x=>$X){$Bh+=$X;$Lg[$x]=array_keys($X);}$Ih=array();$Se=array("=","<",">","<=",">=","!=","LIKE","LIKE %%","IN","IS NULL","NOT LIKE","NOT IN","IS NOT NULL");$Uc=array("len","lower","round","upper");$Zc=array("avg","count","count distinct","max","min","sum");$fc=array(array("date|time"=>"getdate",),array("int|decimal|real|float|money|datetime"=>"+/-","char|text"=>"+",));}$Xb['firebird']='Firebird (alpha)';if(isset($_GET["firebird"])){$_f=array("interbase");define("DRIVER","firebird");if(extension_loaded("interbase")){class
+Min_DB{var$extension="Firebird",$server_info,$affected_rows,$errno,$error,$_link,$_result;function
+connect($N,$V,$G){$this->_link=ibase_connect($N,$V,$G);if($this->_link){$Lh=explode(':',$N);$this->service_link=ibase_service_attach($Lh[0],$V,$G);$this->server_info=ibase_server_info($this->service_link,IBASE_SVC_SERVER_VERSION);}else{$this->errno=ibase_errcode();$this->error=ibase_errmsg();}return(bool)$this->_link;}function
+quote($P){return"'".str_replace("'","''",$P)."'";}function
+select_db($Gb){return($Gb=="domain");}function
+query($H,$Ch=false){$I=ibase_query($H,$this->_link);if(!$I){$this->errno=ibase_errcode();$this->error=ibase_errmsg();return
+false;}$this->error="";if($I===true){$this->affected_rows=ibase_affected_rows($this->_link);return
+true;}return
+new
+Min_Result($I);}function
+multi_query($H){return$this->_result=$this->query($H);}function
+store_result(){return$this->_result;}function
+next_result(){return
+false;}function
+result($H,$o=0){$I=$this->query($H);if(!$I||!$I->num_rows)return
+false;$K=$I->fetch_row();return$K[$o];}}class
+Min_Result{var$num_rows,$_result,$_offset=0;function
+Min_Result($I){$this->_result=$I;}function
+fetch_assoc(){return
+ibase_fetch_assoc($this->_result);}function
+fetch_row(){return
+ibase_fetch_row($this->_result);}function
+fetch_field(){$o=ibase_field_info($this->_result,$this->_offset++);return(object)array('name'=>$o['name'],'orgname'=>$o['name'],'type'=>$o['type'],'charsetnr'=>$o['length'],);}function
+__destruct(){ibase_free_result($this->_result);}}}class
+Min_Driver
+extends
+Min_SQL{}function
+idf_escape($t){return'"'.str_replace('"','""',$t).'"';}function
+table($t){return
+idf_escape($t);}function
+connect(){global$b;$h=new
+Min_DB;$k=$b->credentials();if($h->connect($k[0],$k[1],$k[2]))return$h;return$h->error;}function
+get_databases($Lc){return
+array("domain");}function
+limit($H,$Z,$z,$D=0,$vg=" "){$J='';$J.=($z!==null?$vg."FIRST $z".($D?" SKIP $D":""):"");$J.=" $H$Z";return$J;}function
+limit1($H,$Z){return
+limit($H,$Z,1);}function
+db_collation($m,$nb){}function
+engines(){return
+array();}function
+logged_user(){global$b;$k=$b->credentials();return$k[1];}function
+tables_list(){global$h;$H='SELECT RDB$RELATION_NAME FROM rdb$relations WHERE rdb$system_flag = 0';$I=ibase_query($h->_link,$H);$J=array();while($K=ibase_fetch_assoc($I))$J[$K['RDB$RELATION_NAME']]='table';ksort($J);return$J;}function
+count_tables($l){return
+array();}function
+table_status($C="",$Ec=false){global$h;$J=array();$Eb=tables_list();foreach($Eb
+as$u=>$X){$u=trim($u);$J[$u]=array('Name'=>$u,'Engine'=>'standard',);if($C==$u)return$J[$u];}return$J;}function
+is_view($R){return
+false;}function
+fk_support($R){return
+preg_match('~InnoDB|IBMDB2I~i',$R["Engine"]);}function
+fields($Q){global$h;$J=array();$H='SELECT r.RDB$FIELD_NAME AS field_name,
+r.RDB$DESCRIPTION AS field_description,
+r.RDB$DEFAULT_VALUE AS field_default_value,
+r.RDB$NULL_FLAG AS field_not_null_constraint,
+f.RDB$FIELD_LENGTH AS field_length,
+f.RDB$FIELD_PRECISION AS field_precision,
+f.RDB$FIELD_SCALE AS field_scale,
+CASE f.RDB$FIELD_TYPE
+WHEN 261 THEN \'BLOB\'
+WHEN 14 THEN \'CHAR\'
+WHEN 40 THEN \'CSTRING\'
+WHEN 11 THEN \'D_FLOAT\'
+WHEN 27 THEN \'DOUBLE\'
+WHEN 10 THEN \'FLOAT\'
+WHEN 16 THEN \'INT64\'
+WHEN 8 THEN \'INTEGER\'
+WHEN 9 THEN \'QUAD\'
+WHEN 7 THEN \'SMALLINT\'
+WHEN 12 THEN \'DATE\'
+WHEN 13 THEN \'TIME\'
+WHEN 35 THEN \'TIMESTAMP\'
+WHEN 37 THEN \'VARCHAR\'
+ELSE \'UNKNOWN\'
+END AS field_type,
+f.RDB$FIELD_SUB_TYPE AS field_subtype,
+coll.RDB$COLLATION_NAME AS field_collation,
+cset.RDB$CHARACTER_SET_NAME AS field_charset
+FROM RDB$RELATION_FIELDS r
+LEFT JOIN RDB$FIELDS f ON r.RDB$FIELD_SOURCE = f.RDB$FIELD_NAME
+LEFT JOIN RDB$COLLATIONS coll ON f.RDB$COLLATION_ID = coll.RDB$COLLATION_ID
+LEFT JOIN RDB$CHARACTER_SETS cset ON f.RDB$CHARACTER_SET_ID = cset.RDB$CHARACTER_SET_ID
+WHERE r.RDB$RELATION_NAME = '.q($Q).'
+ORDER BY r.RDB$FIELD_POSITION';$I=ibase_query($h->_link,$H);while($K=ibase_fetch_assoc($I))$J[trim($K['FIELD_NAME'])]=array("field"=>trim($K["FIELD_NAME"]),"full_type"=>trim($K["FIELD_TYPE"]),"type"=>trim($K["FIELD_SUB_TYPE"]),"default"=>trim($K['FIELD_DEFAULT_VALUE']),"null"=>(trim($K["FIELD_NOT_NULL_CONSTRAINT"])=="YES"),"auto_increment"=>'0',"collation"=>trim($K["FIELD_COLLATION"]),"privileges"=>array("insert"=>1,"select"=>1,"update"=>1),"comment"=>trim($K["FIELD_DESCRIPTION"]),);return$J;}function
+indexes($Q,$i=null){$J=array();return$J;}function
+foreign_keys($Q){return
+array();}function
+collations(){return
+array();}function
+information_schema($m){return
+false;}function
+error(){global$h;return
+h($h->error);}function
+types(){return
+array();}function
+schemas(){return
+array();}function
+get_schema(){return"";}function
+set_schema($og){return
+true;}function
+support($Fc){return
+preg_match("~^(columns|sql|status|table)$~",$Fc);}$w="firebird";$Se=array("=");$Uc=array();$Zc=array();$fc=array();}$Xb["simpledb"]="SimpleDB";if(isset($_GET["simpledb"])){$_f=array("SimpleXML");define("DRIVER","simpledb");if(class_exists('SimpleXMLElement')){class
+Min_DB{var$extension="SimpleXML",$server_info='2009-04-15',$error,$timeout,$next,$affected_rows,$_result;function
+select_db($Gb){return($Gb=="domain");}function
+query($H,$Ch=false){$F=array('SelectExpression'=>$H,'ConsistentRead'=>'true');if($this->next)$F['NextToken']=$this->next;$I=sdb_request_all('Select','Item',$F,$this->timeout);if($I===false)return$I;if(preg_match('~^\s*SELECT\s+COUNT\(~i',$H)){$Pg=0;foreach($I
+as$Ed)$Pg+=$Ed->Attribute->Value;$I=array((object)array('Attribute'=>array((object)array('Name'=>'Count','Value'=>$Pg,))));}return
+new
+Min_Result($I);}function
+multi_query($H){return$this->_result=$this->query($H);}function
+store_result(){return$this->_result;}function
+next_result(){return
+false;}function
+quote($P){return"'".str_replace("'","''",$P)."'";}}class
+Min_Result{var$num_rows,$_rows=array(),$_offset=0;function
+Min_Result($I){foreach($I
+as$Ed){$K=array();if($Ed->Name!='')$K['itemName()']=(string)$Ed->Name;foreach($Ed->Attribute
+as$Ia){$C=$this->_processValue($Ia->Name);$Y=$this->_processValue($Ia->Value);if(isset($K[$C])){$K[$C]=(array)$K[$C];$K[$C][]=$Y;}else$K[$C]=$Y;}$this->_rows[]=$K;foreach($K
+as$x=>$X){if(!isset($this->_rows[0][$x]))$this->_rows[0][$x]=null;}}$this->num_rows=count($this->_rows);}function
+_processValue($ic){return(is_object($ic)&&$ic['encoding']=='base64'?base64_decode($ic):(string)$ic);}function
+fetch_assoc(){$K=current($this->_rows);if(!$K)return$K;$J=array();foreach($this->_rows[0]as$x=>$X)$J[$x]=$K[$x];next($this->_rows);return$J;}function
+fetch_row(){$J=$this->fetch_assoc();if(!$J)return$J;return
+array_values($J);}function
+fetch_field(){$Kd=array_keys($this->_rows[0]);return(object)array('name'=>$Kd[$this->_offset++]);}}}class
+Min_Driver
+extends
+Min_SQL{public$Cf="itemName()";function
+_chunkRequest($ld,$va,$F,$yc=array()){global$h;foreach(array_chunk($ld,25)as$gb){$kf=$F;foreach($gb
+as$s=>$jd){$kf["Item.$s.ItemName"]=$jd;foreach($yc
+as$x=>$X)$kf["Item.$s.$x"]=$X;}if(!sdb_request($va,$kf))return
+false;}$h->affected_rows=count($ld);return
+true;}function
+_extractIds($Q,$Nf,$z){$J=array();if(preg_match_all("~itemName\(\) = (('[^']*+')+)~",$Nf,$ee))$J=array_map('idf_unescape',$ee[1]);else{foreach(sdb_request_all('Select','Item',array('SelectExpression'=>'SELECT itemName() FROM '.table($Q).$Nf.($z?" LIMIT 1":"")))as$Ed)$J[]=$Ed->Name;}return$J;}function
+select($Q,$M,$Z,$Xc,$Xe=array(),$z=1,$E=0,$Ef=false){global$h;$h->next=$_GET["next"];$J=parent::select($Q,$M,$Z,$Xc,$Xe,$z,$E,$Ef);$h->next=0;return$J;}function
+delete($Q,$Nf,$z=0){return$this->_chunkRequest($this->_extractIds($Q,$Nf,$z),'BatchDeleteAttributes',array('DomainName'=>$Q));}function
+update($Q,$O,$Nf,$z=0,$vg="\n"){$Mb=array();$wd=array();$s=0;$ld=$this->_extractIds($Q,$Nf,$z);$jd=idf_unescape($O["`itemName()`"]);unset($O["`itemName()`"]);foreach($O
+as$x=>$X){$x=idf_unescape($x);if($X=="NULL"||($jd!=""&&array($jd)!=$ld))$Mb["Attribute.".count($Mb).".Name"]=$x;if($X!="NULL"){foreach((array)$X
+as$Gd=>$W){$wd["Attribute.$s.Name"]=$x;$wd["Attribute.$s.Value"]=(is_array($X)?$W:idf_unescape($W));if(!$Gd)$wd["Attribute.$s.Replace"]="true";$s++;}}}$F=array('DomainName'=>$Q);return(!$wd||$this->_chunkRequest(($jd!=""?array($jd):$ld),'BatchPutAttributes',$F,$wd))&&(!$Mb||$this->_chunkRequest($ld,'BatchDeleteAttributes',$F,$Mb));}function
+insert($Q,$O){$F=array("DomainName"=>$Q);$s=0;foreach($O
+as$C=>$Y){if($Y!="NULL"){$C=idf_unescape($C);if($C=="itemName()")$F["ItemName"]=idf_unescape($Y);else{foreach((array)$Y
+as$X){$F["Attribute.$s.Name"]=$C;$F["Attribute.$s.Value"]=(is_array($Y)?$X:idf_unescape($Y));$s++;}}}}return
+sdb_request('PutAttributes',$F);}function
+insertUpdate($Q,$L,$Cf){foreach($L
+as$O){if(!$this->update($Q,$O,"WHERE `itemName()` = ".q($O["`itemName()`"])))return
+false;}return
+true;}function
+begin(){return
+false;}function
+commit(){return
+false;}function
+rollback(){return
+false;}}function
+connect(){return
+new
+Min_DB;}function
+support($Fc){return
+preg_match('~sql~',$Fc);}function
+logged_user(){global$b;$k=$b->credentials();return$k[1];}function
+get_databases(){return
+array("domain");}function
+collations(){return
+array();}function
+db_collation($m,$nb){}function
+tables_list(){global$h;$J=array();foreach(sdb_request_all('ListDomains','DomainName')as$Q)$J[(string)$Q]='table';if($h->error&&defined("PAGE_HEADER"))echo"".error()."\n";return$J;}function
+table_status($C="",$Ec=false){$J=array();foreach(($C!=""?array($C=>true):tables_list())as$Q=>$U){$K=array("Name"=>$Q,"Auto_increment"=>"");if(!$Ec){$re=sdb_request('DomainMetadata',array('DomainName'=>$Q));if($re){foreach(array("Rows"=>"ItemCount","Data_length"=>"ItemNamesSizeBytes","Index_length"=>"AttributeValuesSizeBytes","Data_free"=>"AttributeNamesSizeBytes",)as$x=>$X)$K[$x]=(string)$re->$X;}}if($C!="")return$K;$J[$Q]=$K;}return$J;}function
+explain($h,$H){}function
+error(){global$h;return
+h($h->error);}function
+information_schema(){}function
+is_view($R){}function
+indexes($Q,$i=null){return
+array(array("type"=>"PRIMARY","columns"=>array("itemName()")),);}function
+fields($Q){return
+fields_from_edit();}function
+foreign_keys($Q){return
+array();}function
+table($t){return
+idf_escape($t);}function
+idf_escape($t){return"`".str_replace("`","``",$t)."`";}function
+limit($H,$Z,$z,$D=0,$vg=" "){return" $H$Z".($z!==null?$vg."LIMIT $z":"");}function
+unconvert_field($o,$J){return$J;}function
+fk_support($R){}function
+engines(){return
+array();}function
+alter_table($Q,$C,$p,$Mc,$rb,$nc,$d,$La,$of){return($Q==""&&sdb_request('CreateDomain',array('DomainName'=>$C)));}function
+drop_tables($S){foreach($S
+as$Q){if(!sdb_request('DeleteDomain',array('DomainName'=>$Q)))return
+false;}return
+true;}function
+count_tables($l){foreach($l
+as$m)return
+array($m=>count(tables_list()));}function
+found_rows($R,$Z){return($Z?null:$R["Rows"]);}function
+last_id(){}function
+hmac($Ba,$Eb,$x,$Rf=false){$Ua=64;if(strlen($x)>$Ua)$x=pack("H*",$Ba($x));$x=str_pad($x,$Ua,"\0");$Hd=$x^str_repeat("\x36",$Ua);$Id=$x^str_repeat("\x5C",$Ua);$J=$Ba($Id.pack("H*",$Ba($Hd.$Eb)));if($Rf)$J=pack("H*",$J);return$J;}function
+sdb_request($va,$F=array()){global$b,$h;list($hd,$F['AWSAccessKeyId'],$rg)=$b->credentials();$F['Action']=$va;$F['Timestamp']=gmdate('Y-m-d\TH:i:s+00:00');$F['Version']='2009-04-15';$F['SignatureVersion']=2;$F['SignatureMethod']='HmacSHA1';ksort($F);$H='';foreach($F
+as$x=>$X)$H.='&'.rawurlencode($x).'='.rawurlencode($X);$H=str_replace('%7E','~',substr($H,1));$H.="&Signature=".urlencode(base64_encode(hmac('sha1',"POST\n".preg_replace('~^https?://~','',$hd)."\n/\n$H",$rg,true)));@ini_set('track_errors',1);$Hc=@file_get_contents((preg_match('~^https?://~',$hd)?$hd:"http://$hd"),false,stream_context_create(array('http'=>array('method'=>'POST','content'=>$H,'ignore_errors'=>1,))));if(!$Hc){$h->error=$php_errormsg;return
+false;}libxml_use_internal_errors(true);$ei=simplexml_load_string($Hc);if(!$ei){$n=libxml_get_last_error();$h->error=$n->message;return
+false;}if($ei->Errors){$n=$ei->Errors->Error;$h->error="$n->Message ($n->Code)";return
+false;}$h->error='';$ah=$va."Result";return($ei->$ah?$ei->$ah:true);}function
+sdb_request_all($va,$ah,$F=array(),$jh=0){$J=array();$Hg=($jh?microtime(true):0);$z=(preg_match('~LIMIT\s+(\d+)\s*$~i',$F['SelectExpression'],$B)?$B[1]:0);do{$ei=sdb_request($va,$F);if(!$ei)break;foreach($ei->$ah
+as$ic)$J[]=$ic;if($z&&count($J)>=$z){$_GET["next"]=$ei->NextToken;break;}if($jh&µtime(true)-$Hg>$jh)return
+false;$F['NextToken']=$ei->NextToken;if($z)$F['SelectExpression']=preg_replace('~\d+\s*$~',$z-count($J),$F['SelectExpression']);}while($ei->NextToken);return$J;}$w="simpledb";$Se=array("=","<",">","<=",">=","!=","LIKE","LIKE %%","IN","IS NULL","NOT LIKE","IS NOT NULL");$Uc=array();$Zc=array("count");$fc=array(array("json"));}$Xb["mongo"]="MongoDB (beta)";if(isset($_GET["mongo"])){$_f=array("mongo");define("DRIVER","mongo");if(class_exists('MongoDB')){class
+Min_DB{var$extension="Mongo",$error,$last_id,$_link,$_db;function
+connect($N,$V,$G){global$b;$m=$b->database();$Ve=array();if($V!=""){$Ve["username"]=$V;$Ve["password"]=$G;}if($m!="")$Ve["db"]=$m;try{$this->_link=@new
+MongoClient("mongodb://$N",$Ve);return
+true;}catch(Exception$uc){$this->error=$uc->getMessage();return
+false;}}function
+query($H){return
+false;}function
+select_db($Gb){try{$this->_db=$this->_link->selectDB($Gb);return
+true;}catch(Exception$uc){$this->error=$uc->getMessage();return
+false;}}function
+quote($P){return$P;}}class
+Min_Result{var$num_rows,$_rows=array(),$_offset=0,$_charset=array();function
+Min_Result($I){foreach($I
+as$Ed){$K=array();foreach($Ed
+as$x=>$X){if(is_a($X,'MongoBinData'))$this->_charset[$x]=63;$K[$x]=(is_a($X,'MongoId')?'ObjectId("'.strval($X).'")':(is_a($X,'MongoDate')?gmdate("Y-m-d H:i:s",$X->sec)." GMT":(is_a($X,'MongoBinData')?$X->bin:(is_a($X,'MongoRegex')?strval($X):(is_object($X)?get_class($X):$X)))));}$this->_rows[]=$K;foreach($K
+as$x=>$X){if(!isset($this->_rows[0][$x]))$this->_rows[0][$x]=null;}}$this->num_rows=count($this->_rows);}function
+fetch_assoc(){$K=current($this->_rows);if(!$K)return$K;$J=array();foreach($this->_rows[0]as$x=>$X)$J[$x]=$K[$x];next($this->_rows);return$J;}function
+fetch_row(){$J=$this->fetch_assoc();if(!$J)return$J;return
+array_values($J);}function
+fetch_field(){$Kd=array_keys($this->_rows[0]);$C=$Kd[$this->_offset++];return(object)array('name'=>$C,'charsetnr'=>$this->_charset[$C],);}}}class
+Min_Driver
+extends
+Min_SQL{public$Cf="_id";function
+select($Q,$M,$Z,$Xc,$Xe=array(),$z=1,$E=0,$Ef=false){$M=($M==array("*")?array():array_fill_keys($M,true));$Cg=array();foreach($Xe
+as$X){$X=preg_replace('~ DESC$~','',$X,1,$Ab);$Cg[$X]=($Ab?-1:1);}return
+new
+Min_Result($this->_conn->_db->selectCollection($Q)->find(array(),$M)->sort($Cg)->limit(+$z)->skip($E*$z));}function
+insert($Q,$O){try{$J=$this->_conn->_db->selectCollection($Q)->insert($O);$this->_conn->errno=$J['code'];$this->_conn->error=$J['err'];$this->_conn->last_id=$O['_id'];return!$J['err'];}catch(Exception$uc){$this->_conn->error=$uc->getMessage();return
+false;}}}function
+connect(){global$b;$h=new
+Min_DB;$k=$b->credentials();if($h->connect($k[0],$k[1],$k[2]))return$h;return$h->error;}function
+error(){global$h;return
+h($h->error);}function
+logged_user(){global$b;$k=$b->credentials();return$k[1];}function
+get_databases($Lc){global$h;$J=array();$Jb=$h->_link->listDBs();foreach($Jb['databases']as$m)$J[]=$m['name'];return$J;}function
+collations(){return
+array();}function
+db_collation($m,$nb){}function
+count_tables($l){global$h;$J=array();foreach($l
+as$m)$J[$m]=count($h->_link->selectDB($m)->getCollectionNames(true));return$J;}function
+tables_list(){global$h;return
+array_fill_keys($h->_db->getCollectionNames(true),'table');}function
+table_status($C="",$Ec=false){$J=array();foreach(tables_list()as$Q=>$U){$J[$Q]=array("Name"=>$Q);if($C==$Q)return$J[$Q];}return$J;}function
+information_schema(){}function
+is_view($R){}function
+drop_databases($l){global$h;foreach($l
+as$m){$cg=$h->_link->selectDB($m)->drop();if(!$cg['ok'])return
+false;}return
+true;}function
+indexes($Q,$i=null){global$h;$J=array();foreach($h->_db->selectCollection($Q)->getIndexInfo()as$u){$Pb=array();foreach($u["key"]as$e=>$U)$Pb[]=($U==-1?'1':null);$J[$u["name"]]=array("type"=>($u["name"]=="_id_"?"PRIMARY":($u["unique"]?"UNIQUE":"INDEX")),"columns"=>array_keys($u["key"]),"lengths"=>array(),"descs"=>$Pb,);}return$J;}function
+fields($Q){return
+fields_from_edit();}function
+convert_field($o){}function
+unconvert_field($o,$J){return$J;}function
+foreign_keys($Q){return
+array();}function
+fk_support($R){}function
+engines(){return
+array();}function
+found_rows($R,$Z){global$h;return$h->_db->selectCollection($_GET["select"])->count($Z);}function
+alter_table($Q,$C,$p,$Mc,$rb,$nc,$d,$La,$of){global$h;if($Q==""){$h->_db->createCollection($C);return
+true;}}function
+drop_tables($S){global$h;foreach($S
+as$Q){$cg=$h->_db->selectCollection($Q)->drop();if(!$cg['ok'])return
+false;}return
+true;}function
+truncate_tables($S){global$h;foreach($S
+as$Q){$cg=$h->_db->selectCollection($Q)->remove();if(!$cg['ok'])return
+false;}return
+true;}function
+alter_indexes($Q,$c){global$h;foreach($c
+as$X){list($U,$C,$O)=$X;if($O=="DROP")$J=$h->_db->command(array("deleteIndexes"=>$Q,"index"=>$C));else{$f=array();foreach($O
+as$e){$e=preg_replace('~ DESC$~','',$e,1,$Ab);$f[$e]=($Ab?-1:1);}$J=$h->_db->selectCollection($Q)->ensureIndex($f,array("unique"=>($U=="UNIQUE"),"name"=>$C,));}if($J['errmsg']){$h->error=$J['errmsg'];return
+false;}}return
+true;}function
+last_id(){global$h;return$h->last_id;}function
+table($t){return$t;}function
+idf_escape($t){return$t;}function
+support($Fc){return
+preg_match("~database|indexes~",$Fc);}$w="mongo";$Se=array("=");$Uc=array();$Zc=array();$fc=array(array("json"));}$Xb["elastic"]="Elasticsearch (beta)";if(isset($_GET["elastic"])){$_f=array("json");define("DRIVER","elastic");if(function_exists('json_decode')){class
+Min_DB{var$extension="JSON",$server_info,$errno,$error,$_url;function
+rootQuery($rf,$wb=array(),$se='GET'){@ini_set('track_errors',1);$Hc=@file_get_contents($this->_url.'/'.ltrim($rf,'/'),false,stream_context_create(array('http'=>array('method'=>$se,'content'=>json_encode($wb),'ignore_errors'=>1,))));if(!$Hc){$this->error=$php_errormsg;return$Hc;}if(!preg_match('~^HTTP/[0-9.]+ 2~i',$http_response_header[0])){$this->error=$Hc;return
+false;}$J=json_decode($Hc,true);if($J===null){$this->errno=json_last_error();if(function_exists('json_last_error_msg'))$this->error=json_last_error_msg();else{$vb=get_defined_constants(true);foreach($vb['json']as$C=>$Y){if($Y==$this->errno&&preg_match('~^JSON_ERROR_~',$C)){$this->error=$C;break;}}}}return$J;}function
+query($rf,$wb=array(),$se='GET'){return$this->rootQuery(($this->_db!=""?"$this->_db/":"/").ltrim($rf,'/'),$wb,$se);}function
+connect($N,$V,$G){$this->_url="http://$V:$G@$N/";$J=$this->query('');if($J)$this->server_info=$J['version']['number'];return(bool)$J;}function
+select_db($Gb){$this->_db=$Gb;return
+true;}function
+quote($P){return$P;}}class
+Min_Result{var$num_rows,$_rows;function
+Min_Result($L){$this->num_rows=count($this->_rows);$this->_rows=$L;reset($this->_rows);}function
+fetch_assoc(){$J=current($this->_rows);next($this->_rows);return$J;}function
+fetch_row(){return
+array_values($this->fetch_assoc());}}}class
+Min_Driver
+extends
+Min_SQL{function
+select($Q,$M,$Z,$Xc,$Xe=array(),$z=1,$E=0,$Ef=false){global$b;$Eb=array();$H="$Q/_search";if($M!=array("*"))$Eb["fields"]=$M;if($Xe){$Cg=array();foreach($Xe
+as$lb){$lb=preg_replace('~ DESC$~','',$lb,1,$Ab);$Cg[]=($Ab?array($lb=>"desc"):$lb);}$Eb["sort"]=$Cg;}if($z){$Eb["size"]=+$z;if($E)$Eb["from"]=($E*$z);}foreach($Z
+as$X){list($lb,$Qe,$X)=explode(" ",$X,3);if($lb=="_id")$Eb["query"]["ids"]["values"][]=$X;elseif($lb.$X!=""){$eh=array("term"=>array(($lb!=""?$lb:"_all")=>$X));if($Qe=="=")$Eb["query"]["filtered"]["filter"]["and"][]=$eh;else$Eb["query"]["filtered"]["query"]["bool"]["must"][]=$eh;}}if($Eb["query"]&&!$Eb["query"]["filtered"]["query"]&&!$Eb["query"]["ids"])$Eb["query"]["filtered"]["query"]=array("match_all"=>array());$Hg=microtime(true);$qg=$this->_conn->query($H,$Eb);if($Ef)echo$b->selectQuery("$H: ".print_r($Eb,true),format_time($Hg));if(!$qg)return
+false;$J=array();foreach($qg['hits']['hits']as$gd){$K=array();if($M==array("*"))$K["_id"]=$gd["_id"];$p=$gd['_source'];if($M!=array("*")){$p=array();foreach($M
+as$x)$p[$x]=$gd['fields'][$x];}foreach($p
+as$x=>$X){if($Eb["fields"])$X=$X[0];$K[$x]=(is_array($X)?json_encode($X):$X);}$J[]=$K;}return
+new
+Min_Result($J);}}function
+connect(){global$b;$h=new
+Min_DB;$k=$b->credentials();if($h->connect($k[0],$k[1],$k[2]))return$h;return$h->error;}function
+support($Fc){return
+preg_match("~database|table|columns~",$Fc);}function
+logged_user(){global$b;$k=$b->credentials();return$k[1];}function
+get_databases(){global$h;$J=$h->rootQuery('_aliases');if($J){$J=array_keys($J);sort($J,SORT_STRING);}return$J;}function
+collations(){return
+array();}function
+db_collation($m,$nb){}function
+engines(){return
+array();}function
+count_tables($l){global$h;$J=$h->query('_mapping');if($J)$J=array_map('count',$J);return$J;}function
+tables_list(){global$h;$J=$h->query('_mapping');if($J)$J=array_fill_keys(array_keys($J[$h->_db]["mappings"]),'table');return$J;}function
+table_status($C="",$Ec=false){global$h;$qg=$h->query("_search?search_type=count",array("facets"=>array("count_by_type"=>array("terms"=>array("field"=>"_type",)))),"POST");$J=array();if($qg){foreach($qg["facets"]["count_by_type"]["terms"]as$Q)$J[$Q["term"]]=array("Name"=>$Q["term"],"Engine"=>"table","Rows"=>$Q["count"],);if($C!=""&&$C==$Q["term"])return$J[$C];}return$J;}function
+error(){global$h;return
+h($h->error);}function
+information_schema(){}function
+is_view($R){}function
+indexes($Q,$i=null){return
+array(array("type"=>"PRIMARY","columns"=>array("_id")),);}function
+fields($Q){global$h;$I=$h->query("$Q/_mapping");$J=array();if($I){$ce=$I[$Q]['properties'];if(!$ce)$ce=$I[$h->_db]['mappings'][$Q]['properties'];if($ce){foreach($ce
+as$C=>$o){$J[$C]=array("field"=>$C,"full_type"=>$o["type"],"type"=>$o["type"],"privileges"=>array("insert"=>1,"select"=>1,"update"=>1),);if($o["properties"]){unset($J[$C]["privileges"]["insert"]);unset($J[$C]["privileges"]["update"]);}}}}return$J;}function
+foreign_keys($Q){return
+array();}function
+table($t){return$t;}function
+idf_escape($t){return$t;}function
+convert_field($o){}function
+unconvert_field($o,$J){return$J;}function
+fk_support($R){}function
+found_rows($R,$Z){return
+null;}function
+create_database($m){global$h;return$h->rootQuery(urlencode($m),array(),'PUT');}function
+drop_databases($l){global$h;return$h->rootQuery(urlencode(implode(',',$l)),array(),'DELETE');}function
+drop_tables($S){global$h;$J=true;foreach($S
+as$Q)$J=$J&&$h->query(urlencode($Q),array(),'DELETE');return$J;}$w="elastic";$Se=array("=","query");$Uc=array();$Zc=array();$fc=array(array("json"));}$Xb=array("server"=>"MySQL")+$Xb;if(!defined("DRIVER")){$_f=array("MySQLi","MySQL","PDO_MySQL");define("DRIVER","server");if(extension_loaded("mysqli")){class
+Min_DB
+extends
+MySQLi{var$extension="MySQLi";function
+Min_DB(){parent::init();}function
+connect($N,$V,$G){mysqli_report(MYSQLI_REPORT_OFF);list($hd,$wf)=explode(":",$N,2);$J=@$this->real_connect(($N!=""?$hd:ini_get("mysqli.default_host")),($N.$V!=""?$V:ini_get("mysqli.default_user")),($N.$V.$G!=""?$G:ini_get("mysqli.default_pw")),null,(is_numeric($wf)?$wf:ini_get("mysqli.default_port")),(!is_numeric($wf)?$wf:null));return$J;}function
+set_charset($ab){if(parent::set_charset($ab))return
+true;parent::set_charset('utf8');return$this->query("SET NAMES $ab");}function
+result($H,$o=0){$I=$this->query($H);if(!$I)return
+false;$K=$I->fetch_array();return$K[$o];}function
+quote($P){return"'".$this->escape_string($P)."'";}}}elseif(extension_loaded("mysql")&&!(ini_get("sql.safe_mode")&&extension_loaded("pdo_mysql"))){class
+Min_DB{var$extension="MySQL",$server_info,$affected_rows,$errno,$error,$_link,$_result;function
+connect($N,$V,$G){$this->_link=@mysql_connect(($N!=""?$N:ini_get("mysql.default_host")),("$N$V"!=""?$V:ini_get("mysql.default_user")),("$N$V$G"!=""?$G:ini_get("mysql.default_password")),true,131072);if($this->_link)$this->server_info=mysql_get_server_info($this->_link);else$this->error=mysql_error();return(bool)$this->_link;}function
+set_charset($ab){if(function_exists('mysql_set_charset')){if(mysql_set_charset($ab,$this->_link))return
+true;mysql_set_charset('utf8',$this->_link);}return$this->query("SET NAMES $ab");}function
+quote($P){return"'".mysql_real_escape_string($P,$this->_link)."'";}function
+select_db($Gb){return
+mysql_select_db($Gb,$this->_link);}function
+query($H,$Ch=false){$I=@($Ch?mysql_unbuffered_query($H,$this->_link):mysql_query($H,$this->_link));$this->error="";if(!$I){$this->errno=mysql_errno($this->_link);$this->error=mysql_error($this->_link);return
+false;}if($I===true){$this->affected_rows=mysql_affected_rows($this->_link);$this->info=mysql_info($this->_link);return
+true;}return
+new
+Min_Result($I);}function
+multi_query($H){return$this->_result=$this->query($H);}function
+store_result(){return$this->_result;}function
+next_result(){return
+false;}function
+result($H,$o=0){$I=$this->query($H);if(!$I||!$I->num_rows)return
+false;return
+mysql_result($I->_result,0,$o);}}class
+Min_Result{var$num_rows,$_result,$_offset=0;function
+Min_Result($I){$this->_result=$I;$this->num_rows=mysql_num_rows($I);}function
+fetch_assoc(){return
+mysql_fetch_assoc($this->_result);}function
+fetch_row(){return
+mysql_fetch_row($this->_result);}function
+fetch_field(){$J=mysql_fetch_field($this->_result,$this->_offset++);$J->orgtable=$J->table;$J->orgname=$J->name;$J->charsetnr=($J->blob?63:0);return$J;}function
+__destruct(){mysql_free_result($this->_result);}}}elseif(extension_loaded("pdo_mysql")){class
+Min_DB
+extends
+Min_PDO{var$extension="PDO_MySQL";function
+connect($N,$V,$G){$this->dsn("mysql:charset=utf8;host=".str_replace(":",";unix_socket=",preg_replace('~:(\\d)~',';port=\\1',$N)),$V,$G);return
+true;}function
+set_charset($ab){$this->query("SET NAMES $ab");}function
+select_db($Gb){return$this->query("USE ".idf_escape($Gb));}function
+query($H,$Ch=false){$this->setAttribute(1000,!$Ch);return
+parent::query($H,$Ch);}}}class
+Min_Driver
+extends
+Min_SQL{function
+insert($Q,$O){return($O?parent::insert($Q,$O):queries("INSERT INTO ".table($Q)." ()\nVALUES ()"));}function
+insertUpdate($Q,$L,$Cf){$f=array_keys(reset($L));$Af="INSERT INTO ".table($Q)." (".implode(", ",$f).") VALUES\n";$Th=array();foreach($f
+as$x)$Th[$x]="$x = VALUES($x)";$Og="\nON DUPLICATE KEY UPDATE ".implode(", ",$Th);$Th=array();$y=0;foreach($L
+as$O){$Y="(".implode(", ",$O).")";if($Th&&(strlen($Af)+$y+strlen($Y)+strlen($Og)>1e6)){if(!queries($Af.implode(",\n",$Th).$Og))return
+false;$Th=array();$y=0;}$Th[]=$Y;$y+=strlen($Y)+2;}return
+queries($Af.implode(",\n",$Th).$Og);}}function
+idf_escape($t){return"`".str_replace("`","``",$t)."`";}function
+table($t){return
+idf_escape($t);}function
+connect(){global$b;$h=new
+Min_DB;$k=$b->credentials();if($h->connect($k[0],$k[1],$k[2])){$h->set_charset(charset($h));$h->query("SET sql_quote_show_create = 1, autocommit = 1");return$h;}$J=$h->error;if(function_exists('iconv')&&!is_utf8($J)&&strlen($mg=iconv("windows-1250","utf-8",$J))>strlen($J))$J=$mg;return$J;}function
+get_databases($Lc){global$h;$J=get_session("dbs");if($J===null){$H=($h->server_info>=5?"SELECT SCHEMA_NAME FROM information_schema.SCHEMATA":"SHOW DATABASES");$J=($Lc?slow_query($H):get_vals($H));restart_session();set_session("dbs",$J);stop_session();}return$J;}function
+limit($H,$Z,$z,$D=0,$vg=" "){return" $H$Z".($z!==null?$vg."LIMIT $z".($D?" OFFSET $D":""):"");}function
+limit1($H,$Z){return
+limit($H,$Z,1);}function
+db_collation($m,$nb){global$h;$J=null;$j=$h->result("SHOW CREATE DATABASE ".idf_escape($m),1);if(preg_match('~ COLLATE ([^ ]+)~',$j,$B))$J=$B[1];elseif(preg_match('~ CHARACTER SET ([^ ]+)~',$j,$B))$J=$nb[$B[1]][-1];return$J;}function
+engines(){$J=array();foreach(get_rows("SHOW ENGINES")as$K){if(preg_match("~YES|DEFAULT~",$K["Support"]))$J[]=$K["Engine"];}return$J;}function
+logged_user(){global$h;return$h->result("SELECT USER()");}function
+tables_list(){global$h;return
+get_key_vals($h->server_info>=5?"SELECT TABLE_NAME, TABLE_TYPE FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() ORDER BY TABLE_NAME":"SHOW TABLES");}function
+count_tables($l){$J=array();foreach($l
+as$m)$J[$m]=count(get_vals("SHOW TABLES IN ".idf_escape($m)));return$J;}function
+table_status($C="",$Ec=false){global$h;$J=array();foreach(get_rows($Ec&&$h->server_info>=5?"SELECT TABLE_NAME AS Name, Engine, TABLE_COMMENT AS Comment FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() ".($C!=""?"AND TABLE_NAME = ".q($C):"ORDER BY Name"):"SHOW TABLE STATUS".($C!=""?" LIKE ".q(addcslashes($C,"%_\\")):""))as$K){if($K["Engine"]=="InnoDB")$K["Comment"]=preg_replace('~(?:(.+); )?InnoDB free: .*~','\\1',$K["Comment"]);if(!isset($K["Engine"]))$K["Comment"]="";if($C!="")return$K;$J[$K["Name"]]=$K;}return$J;}function
+is_view($R){return$R["Engine"]===null;}function
+fk_support($R){global$h;return
+preg_match('~InnoDB|IBMDB2I~i',$R["Engine"])||(preg_match('~NDB~i',$R["Engine"])&&version_compare($h->server_info,'5.6')>=0);}function
+fields($Q){$J=array();foreach(get_rows("SHOW FULL COLUMNS FROM ".table($Q))as$K){preg_match('~^([^( ]+)(?:\\((.+)\\))?( unsigned)?( zerofill)?$~',$K["Type"],$B);$J[$K["Field"]]=array("field"=>$K["Field"],"full_type"=>$K["Type"],"type"=>$B[1],"length"=>$B[2],"unsigned"=>ltrim($B[3].$B[4]),"default"=>($K["Default"]!=""||preg_match("~char|set~",$B[1])?$K["Default"]:null),"null"=>($K["Null"]=="YES"),"auto_increment"=>($K["Extra"]=="auto_increment"),"on_update"=>(preg_match('~^on update (.+)~i',$K["Extra"],$B)?$B[1]:""),"collation"=>$K["Collation"],"privileges"=>array_flip(preg_split('~, *~',$K["Privileges"])),"comment"=>$K["Comment"],"primary"=>($K["Key"]=="PRI"),);}return$J;}function
+indexes($Q,$i=null){$J=array();foreach(get_rows("SHOW INDEX FROM ".table($Q),$i)as$K){$J[$K["Key_name"]]["type"]=($K["Key_name"]=="PRIMARY"?"PRIMARY":($K["Index_type"]=="FULLTEXT"?"FULLTEXT":($K["Non_unique"]?"INDEX":"UNIQUE")));$J[$K["Key_name"]]["columns"][]=$K["Column_name"];$J[$K["Key_name"]]["lengths"][]=$K["Sub_part"];$J[$K["Key_name"]]["descs"][]=null;}return$J;}function
+foreign_keys($Q){global$h,$Ne;static$tf='`(?:[^`]|``)+`';$J=array();$Bb=$h->result("SHOW CREATE TABLE ".table($Q),1);if($Bb){preg_match_all("~CONSTRAINT ($tf) FOREIGN KEY ?\\(((?:$tf,? ?)+)\\) REFERENCES ($tf)(?:\\.($tf))? \\(((?:$tf,? ?)+)\\)(?: ON DELETE ($Ne))?(?: ON UPDATE ($Ne))?~",$Bb,$ee,PREG_SET_ORDER);foreach($ee
+as$B){preg_match_all("~$tf~",$B[2],$Dg);preg_match_all("~$tf~",$B[5],$bh);$J[idf_unescape($B[1])]=array("db"=>idf_unescape($B[4]!=""?$B[3]:$B[4]),"table"=>idf_unescape($B[4]!=""?$B[4]:$B[3]),"source"=>array_map('idf_unescape',$Dg[0]),"target"=>array_map('idf_unescape',$bh[0]),"on_delete"=>($B[6]?$B[6]:"RESTRICT"),"on_update"=>($B[7]?$B[7]:"RESTRICT"),);}}return$J;}function
+view($C){global$h;return
+array("select"=>preg_replace('~^(?:[^`]|`[^`]*`)*\\s+AS\\s+~isU','',$h->result("SHOW CREATE VIEW ".table($C),1)));}function
+collations(){$J=array();foreach(get_rows("SHOW COLLATION")as$K){if($K["Default"])$J[$K["Charset"]][-1]=$K["Collation"];else$J[$K["Charset"]][]=$K["Collation"];}ksort($J);foreach($J
+as$x=>$X)asort($J[$x]);return$J;}function
+information_schema($m){global$h;return($h->server_info>=5&&$m=="information_schema")||($h->server_info>=5.5&&$m=="performance_schema");}function
+error(){global$h;return
+h(preg_replace('~^You have an error.*syntax to use~U',"Syntax error",$h->error));}function
+error_line(){global$h;if(preg_match('~ at line ([0-9]+)$~',$h->error,$Yf))return$Yf[1]-1;}function
+create_database($m,$d){return
+queries("CREATE DATABASE ".idf_escape($m).($d?" COLLATE ".q($d):""));}function
+drop_databases($l){$J=apply_queries("DROP DATABASE",$l,'idf_escape');restart_session();set_session("dbs",null);return$J;}function
+rename_database($C,$d){$J=false;if(create_database($C,$d)){$ag=array();foreach(tables_list()as$Q=>$U)$ag[]=table($Q)." TO ".idf_escape($C).".".table($Q);$J=(!$ag||queries("RENAME TABLE ".implode(", ",$ag)));if($J)queries("DROP DATABASE ".idf_escape(DB));restart_session();set_session("dbs",null);}return$J;}function
+auto_increment(){$Ma=" PRIMARY KEY";if($_GET["create"]!=""&&$_POST["auto_increment_col"]){foreach(indexes($_GET["create"])as$u){if(in_array($_POST["fields"][$_POST["auto_increment_col"]]["orig"],$u["columns"],true)){$Ma="";break;}if($u["type"]=="PRIMARY")$Ma=" UNIQUE";}}return" AUTO_INCREMENT$Ma";}function
+alter_table($Q,$C,$p,$Mc,$rb,$nc,$d,$La,$of){$c=array();foreach($p
+as$o)$c[]=($o[1]?($Q!=""?($o[0]!=""?"CHANGE ".idf_escape($o[0]):"ADD"):" ")." ".implode($o[1]).($Q!=""?$o[2]:""):"DROP ".idf_escape($o[0]));$c=array_merge($c,$Mc);$Ig=($rb!==null?" COMMENT=".q($rb):"").($nc?" ENGINE=".q($nc):"").($d?" COLLATE ".q($d):"").($La!=""?" AUTO_INCREMENT=$La":"");if($Q=="")return
+queries("CREATE TABLE ".table($C)." (\n".implode(",\n",$c)."\n)$Ig$of");if($Q!=$C)$c[]="RENAME TO ".table($C);if($Ig)$c[]=ltrim($Ig);return($c||$of?queries("ALTER TABLE ".table($Q)."\n".implode(",\n",$c).$of):true);}function
+alter_indexes($Q,$c){foreach($c
+as$x=>$X)$c[$x]=($X[2]=="DROP"?"\nDROP INDEX ".idf_escape($X[1]):"\nADD $X[0] ".($X[0]=="PRIMARY"?"KEY ":"").($X[1]!=""?idf_escape($X[1])." ":"")."(".implode(", ",$X[2]).")");return
+queries("ALTER TABLE ".table($Q).implode(",",$c));}function
+truncate_tables($S){return
+apply_queries("TRUNCATE TABLE",$S);}function
+drop_views($Yh){return
+queries("DROP VIEW ".implode(", ",array_map('table',$Yh)));}function
+drop_tables($S){return
+queries("DROP TABLE ".implode(", ",array_map('table',$S)));}function
+move_tables($S,$Yh,$bh){$ag=array();foreach(array_merge($S,$Yh)as$Q)$ag[]=table($Q)." TO ".idf_escape($bh).".".table($Q);return
+queries("RENAME TABLE ".implode(", ",$ag));}function
+copy_tables($S,$Yh,$bh){queries("SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'");foreach($S
+as$Q){$C=($bh==DB?table("copy_$Q"):idf_escape($bh).".".table($Q));if(!queries("\nDROP TABLE IF EXISTS $C")||!queries("CREATE TABLE $C LIKE ".table($Q))||!queries("INSERT INTO $C SELECT * FROM ".table($Q)))return
+false;}foreach($Yh
+as$Q){$C=($bh==DB?table("copy_$Q"):idf_escape($bh).".".table($Q));$Xh=view($Q);if(!queries("DROP VIEW IF EXISTS $C")||!queries("CREATE VIEW $C AS $Xh[select]"))return
+false;}return
+true;}function
+trigger($C){if($C=="")return
+array();$L=get_rows("SHOW TRIGGERS WHERE `Trigger` = ".q($C));return
+reset($L);}function
+triggers($Q){$J=array();foreach(get_rows("SHOW TRIGGERS LIKE ".q(addcslashes($Q,"%_\\")))as$K)$J[$K["Trigger"]]=array($K["Timing"],$K["Event"]);return$J;}function
+trigger_options(){return
+array("Timing"=>array("BEFORE","AFTER"),"Event"=>array("INSERT","UPDATE","DELETE"),"Type"=>array("FOR EACH ROW"),);}function
+routine($C,$U){global$h,$pc,$ud,$Bh;$Ca=array("bool","boolean","integer","double precision","real","dec","numeric","fixed","national char","national varchar");$Ah="((".implode("|",array_merge(array_keys($Bh),$Ca)).")\\b(?:\\s*\\(((?:[^'\")]|$pc)++)\\))?\\s*(zerofill\\s*)?(unsigned(?:\\s+zerofill)?)?)(?:\\s*(?:CHARSET|CHARACTER\\s+SET)\\s*['\"]?([^'\"\\s,]+)['\"]?)?";$tf="\\s*(".($U=="FUNCTION"?"":$ud).")?\\s*(?:`((?:[^`]|``)*)`\\s*|\\b(\\S+)\\s+)$Ah";$j=$h->result("SHOW CREATE $U ".idf_escape($C),2);preg_match("~\\(((?:$tf\\s*,?)*)\\)\\s*".($U=="FUNCTION"?"RETURNS\\s+$Ah\\s+":"")."(.*)~is",$j,$B);$p=array();preg_match_all("~$tf\\s*,?~is",$B[1],$ee,PREG_SET_ORDER);foreach($ee
+as$jf){$C=str_replace("``","`",$jf[2]).$jf[3];$p[]=array("field"=>$C,"type"=>strtolower($jf[5]),"length"=>preg_replace_callback("~$pc~s",'normalize_enum',$jf[6]),"unsigned"=>strtolower(preg_replace('~\\s+~',' ',trim("$jf[8] $jf[7]"))),"null"=>1,"full_type"=>$jf[4],"inout"=>strtoupper($jf[1]),"collation"=>strtolower($jf[9]),);}if($U!="FUNCTION")return
+array("fields"=>$p,"definition"=>$B[11]);return
+array("fields"=>$p,"returns"=>array("type"=>$B[12],"length"=>$B[13],"unsigned"=>$B[15],"collation"=>$B[16]),"definition"=>$B[17],"language"=>"SQL",);}function
+routines(){return
+get_rows("SELECT ROUTINE_NAME, ROUTINE_TYPE, DTD_IDENTIFIER FROM information_schema.ROUTINES WHERE ROUTINE_SCHEMA = ".q(DB));}function
+routine_languages(){return
+array();}function
+last_id(){global$h;return$h->result("SELECT LAST_INSERT_ID()");}function
+explain($h,$H){return$h->query("EXPLAIN ".($h->server_info>=5.1?"PARTITIONS ":"").$H);}function
+found_rows($R,$Z){return($Z||$R["Engine"]!="InnoDB"?null:$R["Rows"]);}function
+types(){return
+array();}function
+schemas(){return
+array();}function
+get_schema(){return"";}function
+set_schema($og){return
+true;}function
+create_sql($Q,$La){global$h;$J=$h->result("SHOW CREATE TABLE ".table($Q),1);if(!$La)$J=preg_replace('~ AUTO_INCREMENT=\\d+~','',$J);return$J;}function
+truncate_sql($Q){return"TRUNCATE ".table($Q);}function
+use_sql($Gb){return"USE ".idf_escape($Gb);}function
+trigger_sql($Q,$Mg){$J="";foreach(get_rows("SHOW TRIGGERS LIKE ".q(addcslashes($Q,"%_\\")),null,"-- ")as$K)$J.="\n".($Mg=='CREATE+ALTER'?"DROP TRIGGER IF EXISTS ".idf_escape($K["Trigger"]).";;\n":"")."CREATE TRIGGER ".idf_escape($K["Trigger"])." $K[Timing] $K[Event] ON ".table($K["Table"])." FOR EACH ROW\n$K[Statement];;\n";return$J;}function
+show_variables(){return
+get_key_vals("SHOW VARIABLES");}function
+process_list(){return
+get_rows("SHOW FULL PROCESSLIST");}function
+show_status(){return
+get_key_vals("SHOW STATUS");}function
+convert_field($o){if(preg_match("~binary~",$o["type"]))return"HEX(".idf_escape($o["field"]).")";if($o["type"]=="bit")return"BIN(".idf_escape($o["field"])." + 0)";if(preg_match("~geometry|point|linestring|polygon~",$o["type"]))return"AsWKT(".idf_escape($o["field"]).")";}function
+unconvert_field($o,$J){if(preg_match("~binary~",$o["type"]))$J="UNHEX($J)";if($o["type"]=="bit")$J="CONV($J, 2, 10) + 0";if(preg_match("~geometry|point|linestring|polygon~",$o["type"]))$J="GeomFromText($J)";return$J;}function
+support($Fc){global$h;return!preg_match("~scheme|sequence|type|view_trigger".($h->server_info<5.1?"|event|partitioning".($h->server_info<5?"|routine|trigger|view":""):"")."~",$Fc);}$w="sql";$Bh=array();$Lg=array();foreach(array(lang(24)=>array("tinyint"=>3,"smallint"=>5,"mediumint"=>8,"int"=>10,"bigint"=>20,"decimal"=>66,"float"=>12,"double"=>21),lang(25)=>array("date"=>10,"datetime"=>19,"timestamp"=>19,"time"=>10,"year"=>4),lang(26)=>array("char"=>255,"varchar"=>65535,"tinytext"=>255,"text"=>65535,"mediumtext"=>16777215,"longtext"=>4294967295),lang(30)=>array("enum"=>65535,"set"=>64),lang(27)=>array("bit"=>20,"binary"=>255,"varbinary"=>65535,"tinyblob"=>255,"blob"=>65535,"mediumblob"=>16777215,"longblob"=>4294967295),lang(29)=>array("geometry"=>0,"point"=>0,"linestring"=>0,"polygon"=>0,"multipoint"=>0,"multilinestring"=>0,"multipolygon"=>0,"geometrycollection"=>0),)as$x=>$X){$Bh+=$X;$Lg[$x]=array_keys($X);}$Ih=array("unsigned","zerofill","unsigned zerofill");$Se=array("=","<",">","<=",">=","!=","LIKE","LIKE %%","REGEXP","IN","IS NULL","NOT LIKE","NOT REGEXP","NOT IN","IS NOT NULL","SQL");$Uc=array("char_length","date","from_unixtime","lower","round","sec_to_time","time_to_sec","upper");$Zc=array("avg","count","count distinct","group_concat","max","min","sum");$fc=array(array("char"=>"md5/sha1/password/encrypt/uuid","binary"=>"md5/sha1","date|time"=>"now",),array("(^|[^o])int|float|double|decimal"=>"+/-","date"=>"+ interval/- interval","time"=>"addtime/subtime","char|text"=>"concat",));}define("SERVER",$_GET[DRIVER]);define("DB",$_GET["db"]);define("ME",preg_replace('~^[^?]*/([^?]*).*~','\\1',$_SERVER["REQUEST_URI"]).'?'.(sid()?SID.'&':'').(SERVER!==null?DRIVER."=".urlencode(SERVER).'&':'').(isset($_GET["username"])?"username=".urlencode($_GET["username"]).'&':'').(DB!=""?'db='.urlencode(DB).'&'.(isset($_GET["ns"])?"ns=".urlencode($_GET["ns"])."&":""):''));$ia="4.2.1";class
+Adminer{var$operators;function
+name(){return"Adminer ";}function
+credentials(){return
+array(SERVER,$_GET["username"],get_password());}function
+permanentLogin($j=false){return
+password_file($j);}function
+bruteForceKey(){return$_SERVER["REMOTE_ADDR"];}function
+database(){return
+DB;}function
+databases($Lc=true){return
+get_databases($Lc);}function
+schemas(){return
+schemas();}function
+queryTimeout(){return
+5;}function
+headers(){return
+true;}function
+head(){return
+true;}function
+loginForm(){global$Xb;echo'
+',lang(31),' ',html_select("auth[driver]",$Xb,DRIVER,"loginDriver(this);"),' ',lang(32),'
+',lang(33),'
+',lang(34),'
+',lang(35),' " autocapitalize="off">
+
+
+ \n",checkbox("auth[permanent]",1,$_COOKIE["adminer_permanent"],lang(37))."\n";}function
+login($ae,$G){return
+true;}function
+tableName($Sg){return
+h($Sg["Name"]);}function
+fieldName($o,$Xe=0){return''.h($o["field"]).' ';}function
+selectLinks($Sg,$O=""){echo'';$Zd=array("select"=>lang(38));if(support("table")||support("indexes"))$Zd["table"]=lang(39);if(support("table")){if(is_view($Sg))$Zd["view"]=lang(40);else$Zd["create"]=lang(41);}if($O!==null)$Zd["edit"]=lang(42);foreach($Zd
+as$x=>$X)echo" $X ";echo"\n";}function
+foreignKeys($Q){return
+foreign_keys($Q);}function
+backwardKeys($Q,$Rg){return
+array();}function
+backwardKeysPrint($Oa,$K){}function
+selectQuery($H,$ih){global$w;return"
".h(str_replace("\n"," ",$H))."
($ih) ".(support("sql")?" ".lang(10)." ":"")."
";}function
+rowDescription($Q){return"";}function
+rowDescriptions($L,$Nc){return$L;}function
+selectLink($X,$o){}function
+selectVal($X,$_,$o,$ef){$J=($X===null?"NULL ":(preg_match("~char|binary~",$o["type"])&&!preg_match("~var~",$o["type"])?"$X
":$X));if(preg_match('~blob|bytea|raw|file~',$o["type"])&&!is_utf8($X))$J=lang(43,strlen($ef));return($_?"$J ":$J);}function
+editVal($X,$o){return$X;}function
+selectColumnsPrint($M,$f){global$Uc,$Zc;print_fieldset("select",lang(44),$M);$s=0;$M[""]=array();foreach($M
+as$x=>$X){$X=$_GET["columns"][$x];$e=select_input(" name='columns[$s][col]' onchange='".($x!==""?"selectFieldChange(this.form)":"selectAddRow(this)").";'",$f,$X["col"]);echo"".($Uc||$Zc?"".optionlist(array(-1=>"")+array_filter(array(lang(45)=>$Uc,lang(46)=>$Zc)),$X["fun"])." "."($e)":$e)."
\n";$s++;}echo"\n";}function
+selectSearchPrint($Z,$f,$v){print_fieldset("search",lang(47),$Z);foreach($v
+as$s=>$u){if($u["type"]=="FULLTEXT"){echo"(".implode(" , ",array_map('h',$u["columns"]))." ) AGAINST"," ",checkbox("boolean[$s]",1,isset($_GET["boolean"][$s]),"BOOL")," \n";}}$_GET["where"]=(array)$_GET["where"];reset($_GET["where"]);$Za="this.nextSibling.onchange();";for($s=0;$s<=count($_GET["where"]);$s++){list(,$X)=each($_GET["where"]);if(!$X||("$X[col]$X[val]"!=""&&in_array($X["op"],$this->operators))){echo"".select_input(" name='where[$s][col]' onchange='$Za'",$f,$X["col"],"(".lang(48).")"),html_select("where[$s][op]",$this->operators,$X["op"],$Za),"
\n";}}echo"\n";}function
+selectOrderPrint($Xe,$f,$v){print_fieldset("sort",lang(49),$Xe);$s=0;foreach((array)$_GET["order"]as$x=>$X){if($X!=""){echo"".select_input(" name='order[$s]' onchange='selectFieldChange(this.form);'",$f,$X),checkbox("desc[$s]",1,isset($_GET["desc"][$x]),lang(50))."
\n";$s++;}}echo"".select_input(" name='order[$s]' onchange='selectAddRow(this);'",$f),checkbox("desc[$s]",1,false,lang(50))."
\n","\n";}function
+selectLimitPrint($z){echo"".lang(51)." ";echo" ","
\n";}function
+selectLengthPrint($hh){if($hh!==null){echo"".lang(52)." "," ","
\n";}}function
+selectActionPrint($v){echo"".lang(53)." "," "," ","\n","
\n";}function
+selectCommandPrint(){return!information_schema(DB);}function
+selectImportPrint(){return!information_schema(DB);}function
+selectEmailPrint($kc,$f){}function
+selectColumnsProcess($f,$v){global$Uc,$Zc;$M=array();$Xc=array();foreach((array)$_GET["columns"]as$x=>$X){if($X["fun"]=="count"||($X["col"]!=""&&(!$X["fun"]||in_array($X["fun"],$Uc)||in_array($X["fun"],$Zc)))){$M[$x]=apply_sql_function($X["fun"],($X["col"]!=""?idf_escape($X["col"]):"*"));if(!in_array($X["fun"],$Zc))$Xc[]=$M[$x];}}return
+array($M,$Xc);}function
+selectSearchProcess($p,$v){global$h,$w;$J=array();foreach($v
+as$s=>$u){if($u["type"]=="FULLTEXT"&&$_GET["fulltext"][$s]!="")$J[]="MATCH (".implode(", ",array_map('idf_escape',$u["columns"])).") AGAINST (".q($_GET["fulltext"][$s]).(isset($_GET["boolean"][$s])?" IN BOOLEAN MODE":"").")";}foreach((array)$_GET["where"]as$X){if("$X[col]$X[val]"!=""&&in_array($X["op"],$this->operators)){$tb=" $X[op]";if(preg_match('~IN$~',$X["op"])){$nd=process_length($X["val"]);$tb.=" ".($nd!=""?$nd:"(NULL)");}elseif($X["op"]=="SQL")$tb=" $X[val]";elseif($X["op"]=="LIKE %%")$tb=" LIKE ".$this->processInput($p[$X["col"]],"%$X[val]%");elseif($X["op"]=="ILIKE %%")$tb=" ILIKE ".$this->processInput($p[$X["col"]],"%$X[val]%");elseif(!preg_match('~NULL$~',$X["op"]))$tb.=" ".$this->processInput($p[$X["col"]],$X["val"]);if($X["col"]!="")$J[]=idf_escape($X["col"]).$tb;else{$ob=array();foreach($p
+as$C=>$o){$Cd=preg_match('~char|text|enum|set~',$o["type"]);if((is_numeric($X["val"])||!preg_match('~(^|[^o])int|float|double|decimal|bit~',$o["type"]))&&(!preg_match("~[\x80-\xFF]~",$X["val"])||$Cd)){$C=idf_escape($C);$ob[]=($w=="sql"&&$Cd&&!preg_match("~^utf8_~",$o["collation"])?"CONVERT($C USING ".charset($h).")":$C);}}$J[]=($ob?"(".implode("$tb OR ",$ob)."$tb)":"0");}}}return$J;}function
+selectOrderProcess($p,$v){$J=array();foreach((array)$_GET["order"]as$x=>$X){if($X!="")$J[]=(preg_match('~^((COUNT\\(DISTINCT |[A-Z0-9_]+\\()(`(?:[^`]|``)+`|"(?:[^"]|"")+")\\)|COUNT\\(\\*\\))$~',$X)?$X:idf_escape($X)).(isset($_GET["desc"][$x])?" DESC":"");}return$J;}function
+selectLimitProcess(){return(isset($_GET["limit"])?$_GET["limit"]:"50");}function
+selectLengthProcess(){return(isset($_GET["text_length"])?$_GET["text_length"]:"100");}function
+selectEmailProcess($Z,$Nc){return
+false;}function
+selectQueryBuild($M,$Z,$Xc,$Xe,$z,$E){return"";}function
+messageQuery($H,$ih){global$w;restart_session();$ed=&get_session("queries");$jd="sql-".count($ed[$_GET["db"]]);if(strlen($H)>1e6)$H=preg_replace('~[\x80-\xFF]+$~','',substr($H,0,1e6))."\n...";$ed[$_GET["db"]][]=array($H,time(),$ih);return" ".@date("H:i:s")." ".lang(55)." "."".shorten_utf8($H,1000).'
'.($ih?"
($ih) ":'').(support("sql")?'
'.lang(10).' ':'').'
';}function
+editFunctions($o){global$fc;$J=($o["null"]?"NULL/":"");foreach($fc
+as$x=>$Uc){if(!$x||(!isset($_GET["call"])&&(isset($_GET["select"])||where($_GET)))){foreach($Uc
+as$tf=>$X){if(!$tf||preg_match("~$tf~",$o["type"]))$J.="/$X";}if($x&&!preg_match('~set|blob|bytea|raw|file~',$o["type"]))$J.="/SQL";}}if($o["auto_increment"]&&!isset($_GET["select"])&&!where($_GET))$J=lang(56);return
+explode("/",$J);}function
+editInput($Q,$o,$Ja,$Y){if($o["type"]=="enum")return(isset($_GET["select"])?"".lang(8)." ":"").($o["null"]?"NULL ":"").enum_input("radio",$Ja,$o,$Y,0);return"";}function
+processInput($o,$Y,$r=""){if($r=="SQL")return$Y;$C=$o["field"];$J=q($Y);if(preg_match('~^(now|getdate|uuid)$~',$r))$J="$r()";elseif(preg_match('~^current_(date|timestamp)$~',$r))$J=$r;elseif(preg_match('~^([+-]|\\|\\|)$~',$r))$J=idf_escape($C)." $r $J";elseif(preg_match('~^[+-] interval$~',$r))$J=idf_escape($C)." $r ".(preg_match("~^(\\d+|'[0-9.: -]') [A-Z_]+$~i",$Y)?$Y:$J);elseif(preg_match('~^(addtime|subtime|concat)$~',$r))$J="$r(".idf_escape($C).", $J)";elseif(preg_match('~^(md5|sha1|password|encrypt)$~',$r))$J="$r($J)";return
+unconvert_field($o,$J);}function
+dumpOutput(){$J=array('text'=>lang(57),'file'=>lang(58));if(function_exists('gzencode'))$J['gz']='gzip';return$J;}function
+dumpFormat(){return
+array('sql'=>'SQL','csv'=>'CSV,','csv;'=>'CSV;','tsv'=>'TSV');}function
+dumpDatabase($m){}function
+dumpTable($Q,$Mg,$Dd=0){if($_POST["format"]!="sql"){echo"\xef\xbb\xbf";if($Mg)dump_csv(array_keys(fields($Q)));}else{if($Dd==2){$p=array();foreach(fields($Q)as$C=>$o)$p[]=idf_escape($C)." $o[full_type]";$j="CREATE TABLE ".table($Q)." (".implode(", ",$p).")";}else$j=create_sql($Q,$_POST["auto_increment"]);set_utf8mb4($j);if($Mg&&$j){if($Mg=="DROP+CREATE"||$Dd==1)echo"DROP ".($Dd==2?"VIEW":"TABLE")." IF EXISTS ".table($Q).";\n";if($Dd==1)$j=remove_definer($j);echo"$j;\n\n";}}}function
+dumpData($Q,$Mg,$H){global$h,$w;$ge=($w=="sqlite"?0:1048576);if($Mg){if($_POST["format"]=="sql"){if($Mg=="TRUNCATE+INSERT")echo
+truncate_sql($Q).";\n";$p=fields($Q);}$I=$h->query($H,1);if($I){$wd="";$Xa="";$Kd=array();$Og="";$Gc=($Q!=''?'fetch_assoc':'fetch_row');while($K=$I->$Gc()){if(!$Kd){$Th=array();foreach($K
+as$X){$o=$I->fetch_field();$Kd[]=$o->name;$x=idf_escape($o->name);$Th[]="$x = VALUES($x)";}$Og=($Mg=="INSERT+UPDATE"?"\nON DUPLICATE KEY UPDATE ".implode(", ",$Th):"").";\n";}if($_POST["format"]!="sql"){if($Mg=="table"){dump_csv($Kd);$Mg="INSERT";}dump_csv($K);}else{if(!$wd)$wd="INSERT INTO ".table($Q)." (".implode(", ",array_map('idf_escape',$Kd)).") VALUES";foreach($K
+as$x=>$X){$o=$p[$x];$K[$x]=($X!==null?unconvert_field($o,preg_match('~(^|[^o])int|float|double|decimal~',$o["type"])&&$X!=''?$X:q($X)):"NULL");}$mg=($ge?"\n":" ")."(".implode(",\t",$K).")";if(!$Xa)$Xa=$wd.$mg;elseif(strlen($Xa)+4+strlen($mg)+strlen($Og)<$ge)$Xa.=",$mg";else{echo$Xa.$Og;$Xa=$wd.$mg;}}}if($Xa)echo$Xa.$Og;}elseif($_POST["format"]=="sql")echo"-- ".str_replace("\n"," ",$h->error)."\n";}}function
+dumpFilename($kd){return
+friendly_url($kd!=""?$kd:(SERVER!=""?SERVER:"localhost"));}function
+dumpHeaders($kd,$ve=false){$hf=$_POST["output"];$Ac=(preg_match('~sql~',$_POST["format"])?"sql":($ve?"tar":"csv"));header("Content-Type: ".($hf=="gz"?"application/x-gzip":($Ac=="tar"?"application/x-tar":($Ac=="sql"||$hf!="file"?"text/plain":"text/csv")."; charset=utf-8")));if($hf=="gz")ob_start('ob_gzencode',1e6);return$Ac;}function
+homepage(){echo''.($_GET["ns"]==""&&support("database")?''.lang(59)." \n":""),(support("scheme")?"".($_GET["ns"]!=""?lang(60):lang(61))." \n":""),($_GET["ns"]!==""?''.lang(62)." \n":""),(support("privileges")?"".lang(63)." \n":"");return
+true;}function
+navigation($ue){global$ia,$w,$Xb,$h;echo'
+';if($ue=="auth"){$Kc=true;foreach((array)$_SESSION["pwds"]as$Vh=>$zg){foreach($zg
+as$N=>$Qh){foreach($Qh
+as$V=>$G){if($G!==null){if($Kc){echo"\n";$Kc=false;}$Jb=$_SESSION["db"][$Vh][$N][$V];foreach(($Jb?array_keys($Jb):array(""))as$m)echo"($Xb[$Vh]) ".h($V.($N!=""?"@$N":"").($m!=""?" - $m":""))." \n";}}}}}else{if($_GET["ns"]!==""&&!$ue&&DB!=""){$h->select_db(DB);$S=table_status('',true);}if(support("sql")){echo'
+
+';}$this->databasesPrint($ue);if(DB==""||!$ue){echo"
".(support("sql")?"".lang(55)." \n".lang(64)." \n":"")."";if(support("dump"))echo"".lang(65)." \n";}if($_GET["ns"]!==""&&!$ue&&DB!=""){echo'".lang(66)." \n";if(!$S)echo"
".lang(9)."\n";else$this->tablesPrint($S);}}}function
+databasesPrint($ue){global$b,$h;$l=$this->databases();echo'
\n";}function
+tablesPrint($S){echo"\n";foreach($S
+as$Q=>$Ig){echo'".lang(69)." ";$C=$this->tableName($Ig);echo(support("table")||support("indexes")?'$C ":"$C ")." \n";}}}$b=(function_exists('adminer_object')?adminer_object():new
+Adminer);if($b->operators===null)$b->operators=$Se;function
+page_header($lh,$n="",$Wa=array(),$mh=""){global$ca,$ia,$b,$Xb,$w;page_headers();if(is_ajax()&&$n){page_messages($n);exit;}$nh=$lh.($mh!=""?": $mh":"");$oh=strip_tags($nh.(SERVER!=""&&SERVER!="localhost"?h(" - ".SERVER):"")." - ".$b->name());echo'
+
+
+
+
+
+
',$oh,'
+
+
+';if($b->head()){echo'
+
+';if(file_exists("adminer.css")){echo'
+';}}echo'
+>
+
+
+
+
+
+';if($Wa!==null){$_=substr(preg_replace('~\b(username|db|ns)=[^&]*&~','',ME),0,-1);echo'
'.$Xb[DRIVER].' » ';$_=substr(preg_replace('~\b(db|ns)=[^&]*&~','',ME),0,-1);$N=(SERVER!=""?h(SERVER):lang(32));if($Wa===false)echo"$N\n";else{echo"$N » ";if($_GET["ns"]!=""||(DB!=""&&is_array($Wa)))echo''.h(DB).' » ';if(is_array($Wa)){if($_GET["ns"]!="")echo''.h($_GET["ns"]).' » ';foreach($Wa
+as$x=>$X){$Ob=(is_array($X)?$X[1]:h($X));if($Ob!="")echo"$Ob » ";}}echo"$lh\n";}}echo"
$nh \n","
\n";restart_session();page_messages($n);$l=&get_session("dbs");if(DB!=""&&$l&&!in_array(DB,$l,true))$l=null;stop_session();define("PAGE_HEADER",1);}function
+page_headers(){global$b;header("Content-Type: text/html; charset=utf-8");header("Cache-Control: no-cache");if($b->headers()){header("X-Frame-Options: deny");header("X-XSS-Protection: 0");}}function
+page_messages($n){$Kh=preg_replace('~^[^?]*~','',$_SERVER["REQUEST_URI"]);$qe=$_SESSION["messages"][$Kh];if($qe){echo"
".implode("
\n
",$qe)."
\n";unset($_SESSION["messages"][$Kh]);}if($n)echo"
$n
\n";}function
+page_footer($ue=""){global$b,$T;echo'
+
+';switch_lang();if($ue!="auth"){echo'
+';}echo'
+
+';}function
+int32($xe){while($xe>=2147483648)$xe-=4294967296;while($xe<=-2147483649)$xe+=4294967296;return(int)$xe;}function
+long2str($W,$ai){$mg='';foreach($W
+as$X)$mg.=pack('V',$X);if($ai)return
+substr($mg,0,end($W));return$mg;}function
+str2long($mg,$ai){$W=array_values(unpack('V*',str_pad($mg,4*ceil(strlen($mg)/4),"\0")));if($ai)$W[]=strlen($mg);return$W;}function
+xxtea_mx($gi,$fi,$Pg,$Gd){return
+int32((($gi>>5&0x7FFFFFF)^$fi<<2)+(($fi>>3&0x1FFFFFFF)^$gi<<4))^int32(($Pg^$fi)+($Gd^$gi));}function
+encrypt_string($Kg,$x){if($Kg=="")return"";$x=array_values(unpack("V*",pack("H*",md5($x))));$W=str2long($Kg,true);$xe=count($W)-1;$gi=$W[$xe];$fi=$W[0];$Lf=floor(6+52/($xe+1));$Pg=0;while($Lf-->0){$Pg=int32($Pg+0x9E3779B9);$ec=$Pg>>2&3;for($if=0;$if<$xe;$if++){$fi=$W[$if+1];$we=xxtea_mx($gi,$fi,$Pg,$x[$if&3^$ec]);$gi=int32($W[$if]+$we);$W[$if]=$gi;}$fi=$W[0];$we=xxtea_mx($gi,$fi,$Pg,$x[$if&3^$ec]);$gi=int32($W[$xe]+$we);$W[$xe]=$gi;}return
+long2str($W,false);}function
+decrypt_string($Kg,$x){if($Kg=="")return"";if(!$x)return
+false;$x=array_values(unpack("V*",pack("H*",md5($x))));$W=str2long($Kg,false);$xe=count($W)-1;$gi=$W[$xe];$fi=$W[0];$Lf=floor(6+52/($xe+1));$Pg=int32($Lf*0x9E3779B9);while($Pg){$ec=$Pg>>2&3;for($if=$xe;$if>0;$if--){$gi=$W[$if-1];$we=xxtea_mx($gi,$fi,$Pg,$x[$if&3^$ec]);$fi=int32($W[$if]-$we);$W[$if]=$fi;}$gi=$W[$xe];$we=xxtea_mx($gi,$fi,$Pg,$x[$if&3^$ec]);$fi=int32($W[0]-$we);$W[0]=$fi;$Pg=int32($Pg-0x9E3779B9);}return
+long2str($W,true);}$h='';$dd=$_SESSION["token"];if(!$dd)$_SESSION["token"]=rand(1,1e6);$T=get_token();$uf=array();if($_COOKIE["adminer_permanent"]){foreach(explode(" ",$_COOKIE["adminer_permanent"])as$X){list($x)=explode(":",$X);$uf[$x]=$X;}}function
+add_invalid_login(){global$b;$Ic=get_temp_dir()."/adminer.invalid";$Sc=@fopen($Ic,"r+");if(!$Sc){$Sc=@fopen($Ic,"w");if(!$Sc)return;}flock($Sc,LOCK_EX);$zd=unserialize(stream_get_contents($Sc));$ih=time();if($zd){foreach($zd
+as$_d=>$X){if($X[0]<$ih)unset($zd[$_d]);}}$yd=&$zd[$b->bruteForceKey()];if(!$yd)$yd=array($ih+30*60,0);$yd[1]++;$xg=serialize($zd);rewind($Sc);fwrite($Sc,$xg);ftruncate($Sc,strlen($xg));flock($Sc,LOCK_UN);fclose($Sc);}$Ka=$_POST["auth"];if($Ka){$zd=unserialize(@file_get_contents(get_temp_dir()."/adminer.invalid"));$yd=$zd[$b->bruteForceKey()];$Ce=($yd[1]>30?$yd[0]-time():0);if($Ce>0)auth_error(lang(73,ceil($Ce/60)));session_regenerate_id();$Vh=$Ka["driver"];$N=$Ka["server"];$V=$Ka["username"];$G=(string)$Ka["password"];$m=$Ka["db"];set_password($Vh,$N,$V,$G);$_SESSION["db"][$Vh][$N][$V][$m]=true;if($Ka["permanent"]){$x=base64_encode($Vh)."-".base64_encode($N)."-".base64_encode($V)."-".base64_encode($m);$Ff=$b->permanentLogin(true);$uf[$x]="$x:".base64_encode($Ff?encrypt_string($G,$Ff):"");cookie("adminer_permanent",implode(" ",$uf));}if(count($_POST)==1||DRIVER!=$Vh||SERVER!=$N||$_GET["username"]!==$V||DB!=$m)redirect(auth_url($Vh,$N,$V,$m));}elseif($_POST["logout"]){if($dd&&!verify_token()){page_header(lang(72),lang(74));page_footer("db");exit;}else{foreach(array("pwds","db","dbs","queries")as$x)set_session($x,null);unset_permanent();redirect(substr(preg_replace('~\b(username|db|ns)=[^&]*&~','',ME),0,-1),lang(75));}}elseif($uf&&!$_SESSION["pwds"]){session_regenerate_id();$Ff=$b->permanentLogin();foreach($uf
+as$x=>$X){list(,$hb)=explode(":",$X);list($Vh,$N,$V,$m)=array_map('base64_decode',explode("-",$x));set_password($Vh,$N,$V,decrypt_string(base64_decode($hb),$Ff));$_SESSION["db"][$Vh][$N][$V][$m]=true;}}function
+unset_permanent(){global$uf;foreach($uf
+as$x=>$X){list($Vh,$N,$V,$m)=array_map('base64_decode',explode("-",$x));if($Vh==DRIVER&&$N==SERVER&&$V==$_GET["username"]&&$m==DB)unset($uf[$x]);}cookie("adminer_permanent",implode(" ",$uf));}function
+auth_error($n){global$b,$dd;$n=h($n);$_g=session_name();if(isset($_GET["username"])){header("HTTP/1.1 403 Forbidden");if(($_COOKIE[$_g]||$_GET[$_g])&&!$dd)$n=lang(76);else{add_invalid_login();$G=get_password();if($G!==null){if($G===false)$n.=' '.lang(77,'permanentLogin()
');set_password(DRIVER,SERVER,$_GET["username"],null);}unset_permanent();}}if(!$_COOKIE[$_g]&&$_GET[$_g]&&ini_bool("session.use_only_cookies"))$n=lang(78);$F=session_get_cookie_params();cookie("adminer_key",($_COOKIE["adminer_key"]?$_COOKIE["adminer_key"]:rand_string()),$F["lifetime"]);page_header(lang(36),$n,null);echo"\n";page_footer("auth");exit;}if(isset($_GET["username"])){if(!class_exists("Min_DB")){unset($_SESSION["pwds"][DRIVER]);unset_permanent();page_header(lang(79),lang(80,implode(", ",$_f)),false);page_footer("auth");exit;}$h=connect();}$Wb=new
+Min_Driver($h);if(!is_object($h)||!$b->login($_GET["username"],get_password()))auth_error((is_string($h)?$h:lang(81)));if($Ka&&$_POST["token"])$_POST["token"]=$T;$n='';if($_POST){if(!verify_token()){$td="max_input_vars";$ke=ini_get($td);if(extension_loaded("suhosin")){foreach(array("suhosin.request.max_vars","suhosin.post.max_vars")as$x){$X=ini_get($x);if($X&&(!$ke||$X<$ke)){$td=$x;$ke=$X;}}}$n=(!$_POST["token"]&&$ke?lang(82,"'$td'"):lang(74).' '.lang(83));}}elseif($_SERVER["REQUEST_METHOD"]=="POST"){$n=lang(84,"'post_max_size'");if(isset($_GET["sql"]))$n.=' '.lang(85);}if(!ini_bool("session.use_cookies")||@ini_set("session.use_cookies",false)!==false)session_write_close();function
+select($I,$i=null,$af=array(),$z=0){global$w;$Zd=array();$v=array();$f=array();$Ta=array();$Bh=array();$J=array();odd('');for($s=0;(!$z||$s<$z)&&($K=$I->fetch_row());$s++){if(!$s){echo"\n","";for($Fd=0;$Fdfetch_field();$C=$o->name;$Ze=$o->orgtable;$Ye=$o->orgname;$J[$o->table]=$Ze;if($af&&$w=="sql")$Zd[$Fd]=($C=="table"?"table=":($C=="possible_keys"?"indexes=":null));elseif($Ze!=""){if(!isset($v[$Ze])){$v[$Ze]=array();foreach(indexes($Ze,$i)as$u){if($u["type"]=="PRIMARY"){$v[$Ze]=array_flip($u["columns"]);break;}}$f[$Ze]=$v[$Ze];}if(isset($f[$Ze][$Ye])){unset($f[$Ze][$Ye]);$v[$Ze][$Ye]=$Fd;$Zd[$Fd]=$Ze;}}if($o->charsetnr==63)$Ta[$Fd]=true;$Bh[$Fd]=$o->type;echo"name!=$Ye?" title='".h(($Ze!=""?"$Ze.":"").$Ye)."'":"").">".h($C).($af?doc_link(array('sql'=>"explain-output.html#explain_".strtolower($C))):"");}echo" \n";}echo"";foreach($K
+as$x=>$X){if($X===null)$X="NULL ";elseif($Ta[$x]&&!is_utf8($X))$X="".lang(43,strlen($X))." ";elseif(!strlen($X))$X=" ";else{$X=h($X);if($Bh[$x]==254)$X="$X
";}if(isset($Zd[$x])&&!$f[$Zd[$x]]){if($af&&$w=="sql"){$Q=$K[array_search("table=",$Zd)];$_=$Zd[$x].urlencode($af[$Q]!=""?$af[$Q]:$Q);}else{$_="edit=".urlencode($Zd[$x]);foreach($v[$Zd[$x]]as$lb=>$Fd)$_.="&where".urlencode("[".bracket_escape($lb)."]")."=".urlencode($K[$Fd]);}$X="$X ";}echo"$X";}}echo($s?"
":"".lang(12))."\n";return$J;}function
+referencable_primary($ug){$J=array();foreach(table_status('',true)as$Tg=>$Q){if($Tg!=$ug&&fk_support($Q)){foreach(fields($Tg)as$o){if($o["primary"]){if($J[$Tg]){unset($J[$Tg]);break;}$J[$Tg]=$o;}}}}return$J;}function
+textarea($C,$Y,$L=10,$ob=80){global$w;echo"";}function
+edit_type($x,$o,$nb,$Oc=array()){global$Lg,$Bh,$Ih,$Ne;$U=$o["type"];echo'
';if($U&&!isset($Bh[$U])&&!isset($Oc[$U]))array_unshift($Lg,$U);if($Oc)$Lg[lang(86)]=$Oc;echo
+optionlist($Lg,$U),'
+';echo"('.lang(87).')'.optionlist($nb,$o["collation"]).' ',($Ih?"'.optionlist($Ih,$o["unsigned"]).' ':''),(isset($o['on_update'])?"'.optionlist(array(""=>"(".lang(88).")","CURRENT_TIMESTAMP"),$o["on_update"]).' ':''),($Oc?"(".lang(89).")".optionlist(explode("|",$Ne),$o["on_delete"])." ":" ");}function
+process_length($y){global$pc;return(preg_match("~^\\s*\\(?\\s*$pc(?:\\s*,\\s*$pc)*+\\s*\\)?\\s*\$~",$y)&&preg_match_all("~$pc~",$y,$ee)?"(".implode(",",$ee[0]).")":preg_replace('~^[0-9].*~','(\0)',preg_replace('~[^-0-9,+()[\]]~','',$y)));}function
+process_type($o,$mb="COLLATE"){global$Ih;return" $o[type]".process_length($o["length"]).(preg_match('~(^|[^o])int|float|double|decimal~',$o["type"])&&in_array($o["unsigned"],$Ih)?" $o[unsigned]":"").(preg_match('~char|text|enum|set~',$o["type"])&&$o["collation"]?" $mb ".q($o["collation"]):"");}function
+process_field($o,$_h){global$w;$Lb=$o["default"];return
+array(idf_escape(trim($o["field"])),process_type($_h),($o["null"]?" NULL":" NOT NULL"),(isset($Lb)?" DEFAULT ".((preg_match('~time~',$o["type"])&&preg_match('~^CURRENT_TIMESTAMP$~i',$Lb))||($w=="sqlite"&&preg_match('~^CURRENT_(TIME|TIMESTAMP|DATE)$~i',$Lb))||($o["type"]=="bit"&&preg_match("~^([0-9]+|b'[0-1]+')\$~",$Lb))||($w=="pgsql"&&preg_match("~^[a-z]+\\(('[^']*')+\\)\$~",$Lb))?$Lb:q($Lb)):""),(preg_match('~timestamp|datetime~',$o["type"])&&$o["on_update"]?" ON UPDATE $o[on_update]":""),(support("comment")&&$o["comment"]!=""?" COMMENT ".q($o["comment"]):""),($o["auto_increment"]?auto_increment():null),);}function
+type_class($U){foreach(array('char'=>'text','date'=>'time|year','binary'=>'blob','enum'=>'set',)as$x=>$X){if(preg_match("~$x|$X~",$U))return" class='$x'";}}function
+edit_fields($p,$nb,$U="TABLE",$Oc=array(),$sb=false){global$h,$ud;echo'
+';if($U=="PROCEDURE"){echo' ';}echo' ',($U=="TABLE"?lang(90):lang(91)),' ',lang(92),'
+ ',lang(93),' ',lang(94);if($U=="TABLE"){echo' NULL
+ AI ',doc_link(array('sql'=>"example-auto-increment.html",'sqlite'=>"autoinc.html",'pgsql'=>"datatype.html#DATATYPE-SERIAL",'mssql'=>"ms186775.aspx",)),'',lang(95),(support("comment")?" ".lang(96):"");}echo' '," ",'
+
+
+';foreach($p
+as$s=>$o){$s++;$bf=$o[($_POST?"orig":"field")];$Sb=(isset($_POST["add"][$s-1])||(isset($o["field"])&&!$_POST["drop_col"][$s]))&&(support("drop_col")||$bf=="");echo'
+',($U=="PROCEDURE"?"".html_select("fields[$s][inout]",explode("|",$ud),$o["inout"]):""),' ';if($Sb){echo' 1?'':' editingAddRow(this);" onkeyup="if (this.value) editingAddRow(this);'),'" maxlength="64" autocapitalize="off">';}echo'
+';edit_type("fields[$s]",$o,$nb,$Oc);if($U=="TABLE"){echo' ',checkbox("fields[$s][null]",1,$o["null"],"","","block"),' onclick="var field = this.form['fields[' + this.value + '][field]']; if (!field.value) { field.value = 'id'; field.onchange(); }">
+',(support("comment")?" ":"");}echo"",(support("move_col")?" "." "." ":""),($bf==""||support("drop_col")?" ":""),"\n";}}function
+process_fields(&$p){ksort($p);$D=0;if($_POST["up"]){$Qd=0;foreach($p
+as$x=>$o){if(key($_POST["up"])==$x){unset($p[$x]);array_splice($p,$Qd,0,array($o));break;}if(isset($o["field"]))$Qd=$D;$D++;}}elseif($_POST["down"]){$Qc=false;foreach($p
+as$x=>$o){if(isset($o["field"])&&$Qc){unset($p[key($_POST["down"])]);array_splice($p,$D,0,array($Qc));break;}if(key($_POST["down"])==$x)$Qc=$o;$D++;}}elseif($_POST["add"]){$p=array_values($p);array_splice($p,key($_POST["add"]),0,array(array()));}elseif(!$_POST["drop_col"])return
+false;return
+true;}function
+normalize_enum($B){return"'".str_replace("'","''",addcslashes(stripcslashes(str_replace($B[0][0].$B[0][0],$B[0][0],substr($B[0],1,-1))),'\\'))."'";}function
+grant($Vc,$Hf,$f,$Me){if(!$Hf)return
+true;if($Hf==array("ALL PRIVILEGES","GRANT OPTION"))return($Vc=="GRANT"?queries("$Vc ALL PRIVILEGES$Me WITH GRANT OPTION"):queries("$Vc ALL PRIVILEGES$Me")&&queries("$Vc GRANT OPTION$Me"));return
+queries("$Vc ".preg_replace('~(GRANT OPTION)\\([^)]*\\)~','\\1',implode("$f, ",$Hf).$f).$Me);}function
+drop_create($Yb,$j,$Zb,$fh,$bc,$A,$pe,$ne,$oe,$Je,$_e){if($_POST["drop"])query_redirect($Yb,$A,$pe);elseif($Je=="")query_redirect($j,$A,$oe);elseif($Je!=$_e){$Cb=queries($j);queries_redirect($A,$ne,$Cb&&queries($Yb));if($Cb)queries($Zb);}else
+queries_redirect($A,$ne,queries($fh)&&queries($bc)&&queries($Yb)&&queries($j));}function
+create_trigger($Me,$K){global$w;$kh=" $K[Timing] $K[Event]".($K["Event"]=="UPDATE OF"?" ".idf_escape($K["Of"]):"");return"CREATE TRIGGER ".idf_escape($K["Trigger"]).($w=="mssql"?$Me.$kh:$kh.$Me).rtrim(" $K[Type]\n$K[Statement]",";").";";}function
+create_routine($ig,$K){global$ud;$O=array();$p=(array)$K["fields"];ksort($p);foreach($p
+as$o){if($o["field"]!="")$O[]=(preg_match("~^($ud)\$~",$o["inout"])?"$o[inout] ":"").idf_escape($o["field"]).process_type($o,"CHARACTER SET");}return"CREATE $ig ".idf_escape(trim($K["name"]))." (".implode(", ",$O).")".(isset($_GET["function"])?" RETURNS".process_type($K["returns"],"CHARACTER SET"):"").($K["language"]?" LANGUAGE $K[language]":"").rtrim("\n$K[definition]",";").";";}function
+remove_definer($H){return
+preg_replace('~^([A-Z =]+) DEFINER=`'.preg_replace('~@(.*)~','`@`(%|\\1)',logged_user()).'`~','\\1',$H);}function
+format_foreign_key($q){global$Ne;return" FOREIGN KEY (".implode(", ",array_map('idf_escape',$q["source"])).") REFERENCES ".table($q["table"])." (".implode(", ",array_map('idf_escape',$q["target"])).")".(preg_match("~^($Ne)\$~",$q["on_delete"])?" ON DELETE $q[on_delete]":"").(preg_match("~^($Ne)\$~",$q["on_update"])?" ON UPDATE $q[on_update]":"");}function
+tar_file($Ic,$ph){$J=pack("a100a8a8a8a12a12",$Ic,644,0,0,decoct($ph->size),decoct(time()));$fb=8*32;for($s=0;$ssend();echo
+str_repeat("\0",511-($ph->size+511)%512);}function
+ini_bytes($td){$X=ini_get($td);switch(strtolower(substr($X,-1))){case'g':$X*=1024;case'm':$X*=1024;case'k':$X*=1024;}return$X;}function
+doc_link($sf){global$w,$h;$Mh=array('sql'=>"http://dev.mysql.com/doc/refman/".substr($h->server_info,0,3)."/en/",'sqlite'=>"http://www.sqlite.org/",'pgsql'=>"http://www.postgresql.org/docs/".substr($h->server_info,0,3)."/static/",'mssql'=>"http://msdn.microsoft.com/library/",'oracle'=>"http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/",);return($sf[$w]?"? ":"");}function
+ob_gzencode($P){return
+gzencode($P);}function
+db_size($m){global$h;if(!$h->select_db($m))return"?";$J=0;foreach(table_status()as$R)$J+=$R["Data_length"]+$R["Index_length"];return
+format_number($J);}function
+set_utf8mb4($j){global$h;static$O=false;if(!$O&&preg_match('~\butf8mb4~i',$j)){$O=true;echo"SET NAMES ".charset($h).";\n\n";}}function
+connect_error(){global$b,$h,$T,$n,$Xb;if(DB!=""){header("HTTP/1.1 404 Not Found");page_header(lang(35).": ".h(DB),lang(101),true);}else{if($_POST["db"]&&!$n)queries_redirect(substr(ME,0,-1),lang(102),drop_databases($_POST["db"]));page_header(lang(103),$n,false);echo"\n";foreach(array('database'=>lang(104),'privileges'=>lang(63),'processlist'=>lang(105),'variables'=>lang(106),'status'=>lang(107),)as$x=>$X){if(support($x))echo"$X \n";}echo"
".lang(108,$Xb[DRIVER],"".h($h->server_info)." ","$h->extension ")."\n","
".lang(109,"".h(logged_user())." ")."\n";$l=$b->databases();if($l){$pg=support("scheme");$nb=collations();echo"
\n";}}page_footer("db");}if(isset($_GET["status"]))$_GET["variables"]=$_GET["status"];if(isset($_GET["import"]))$_GET["sql"]=$_GET["import"];if(!(DB!=""?$h->select_db(DB):isset($_GET["sql"])||isset($_GET["dump"])||isset($_GET["database"])||isset($_GET["processlist"])||isset($_GET["privileges"])||isset($_GET["user"])||isset($_GET["variables"])||$_GET["script"]=="connect"||$_GET["script"]=="kill")){if(DB!=""||$_GET["refresh"]){restart_session();set_session("dbs",null);}connect_error();exit;}if(support("scheme")&&DB!=""&&$_GET["ns"]!==""){if(!isset($_GET["ns"]))redirect(preg_replace('~ns=[^&]*&~','',ME)."ns=".get_schema());if(!set_schema($_GET["ns"])){header("HTTP/1.1 404 Not Found");page_header(lang(68).": ".h($_GET["ns"]),lang(117),true);page_footer("ns");exit;}}$Ne="RESTRICT|NO ACTION|CASCADE|SET NULL|SET DEFAULT";class
+TmpFile{var$handler;var$size;function
+TmpFile(){$this->handler=tmpfile();}function
+write($xb){$this->size+=strlen($xb);fwrite($this->handler,$xb);}function
+send(){fseek($this->handler,0);fpassthru($this->handler);fclose($this->handler);}}$pc="'(?:''|[^'\\\\]|\\\\.)*'";$ud="IN|OUT|INOUT";if(isset($_GET["select"])&&($_POST["edit"]||$_POST["clone"])&&!$_POST["save"])$_GET["edit"]=$_GET["select"];if(isset($_GET["callf"]))$_GET["call"]=$_GET["callf"];if(isset($_GET["function"]))$_GET["procedure"]=$_GET["function"];if(isset($_GET["download"])){$a=$_GET["download"];$p=fields($a);header("Content-Type: application/octet-stream");header("Content-Disposition: attachment; filename=".friendly_url("$a-".implode("_",$_GET["where"])).".".friendly_url($_GET["field"]));$M=array(idf_escape($_GET["field"]));$I=$Wb->select($a,$M,array(where($_GET,$p)),$M);$K=($I?$I->fetch_row():array());echo$K[0];exit;}elseif(isset($_GET["table"])){$a=$_GET["table"];$p=fields($a);if(!$p)$n=error();$R=table_status1($a,true);page_header(($p&&is_view($R)?lang(118):lang(119)).": ".h($a),$n);$b->selectLinks($R);$rb=$R["Comment"];if($rb!="")echo"".lang(96).": ".h($rb)."\n";if($p){echo"
\n","".lang(120)." ".lang(92).(support("comment")?" ".lang(96):"")." \n";foreach($p
+as$o){echo"".h($o["field"])," ".h($o["full_type"])." ",($o["null"]?" NULL ":""),($o["auto_increment"]?" ".lang(56)." ":""),(isset($o["default"])?" [".h($o["default"])." ] ":""),(support("comment")?"".nbsp($o["comment"]):""),"\n";}echo"
\n";}if(!is_view($R)){if(support("indexes")){echo"".lang(121)." \n";$v=indexes($a);if($v){echo"\n";foreach($v
+as$C=>$u){ksort($u["columns"]);$Ef=array();foreach($u["columns"]as$x=>$X)$Ef[]="".h($X)." ".($u["lengths"][$x]?"(".$u["lengths"][$x].")":"").($u["descs"][$x]?" DESC":"");echo"$u[type] ".implode(", ",$Ef)."\n";}echo"
\n";}echo''.lang(122)." \n";}if(fk_support($R)){echo"
".lang(86)." \n";$Oc=foreign_keys($a);if($Oc){echo"\n","".lang(123)." ".lang(124)." ".lang(89)." ".lang(88)." \n";foreach($Oc
+as$C=>$q){echo"","".implode(" , ",array_map('h',$q["source"]))." ","".($q["db"]!=""?"".h($q["db"])." .":"").($q["ns"]!=""?"".h($q["ns"])." .":"").h($q["table"])." ","(".implode(" , ",array_map('h',$q["target"]))." )","".nbsp($q["on_delete"])."\n"," ".nbsp($q["on_update"])."\n",' '.lang(125).' ';}echo"
\n";}echo''.lang(126)." \n";}}if(support(is_view($R)?"view_trigger":"trigger")){echo"
".lang(127)." \n";$zh=triggers($a);if($zh){echo"\n";foreach($zh
+as$x=>$X)echo"".h($X[0])." ".h($X[1])." ".h($x)." ".lang(125)." \n";echo"
\n";}echo''.lang(128)." \n";}}elseif(isset($_GET["schema"])){page_header(lang(62),"",array(),h(DB.($_GET["ns"]?".$_GET[ns]":"")));$Vg=array();$Wg=array();$ea=($_GET["schema"]?$_GET["schema"]:$_COOKIE["adminer_schema-".str_replace(".","_",DB)]);preg_match_all('~([^:]+):([-0-9.]+)x([-0-9.]+)(_|$)~',$ea,$ee,PREG_SET_ORDER);foreach($ee
+as$s=>$B){$Vg[$B[1]]=array($B[2],$B[3]);$Wg[]="\n\t'".js_escape($B[1])."': [ $B[2], $B[3] ]";}$rh=0;$Qa=-1;$og=array();$Wf=array();$Ud=array();foreach(table_status('',true)as$Q=>$R){if(is_view($R))continue;$xf=0;$og[$Q]["fields"]=array();foreach(fields($Q)as$C=>$o){$xf+=1.25;$o["pos"]=$xf;$og[$Q]["fields"][$C]=$o;}$og[$Q]["pos"]=($Vg[$Q]?$Vg[$Q]:array($rh,0));foreach($b->foreignKeys($Q)as$X){if(!$X["db"]){$Sd=$Qa;if($Vg[$Q][1]||$Vg[$X["table"]][1])$Sd=min(floatval($Vg[$Q][1]),floatval($Vg[$X["table"]][1]))-1;else$Qa-=.1;while($Ud[(string)$Sd])$Sd-=.0001;$og[$Q]["references"][$X["table"]][(string)$Sd]=array($X["source"],$X["target"]);$Wf[$X["table"]][$Q][(string)$Sd]=$X["target"];$Ud[(string)$Sd]=true;}}$rh=max($rh,$og[$Q]["pos"][0]+2.5+$xf);}echo'
+
+';foreach($og
+as$C=>$Q){echo"
",'
'.h($C)." ";foreach($Q["fields"]as$o){$X='
'.h($o["field"]).' ';echo"
".($o["primary"]?"
$X ":$X);}foreach((array)$Q["references"]as$ch=>$Xf){foreach($Xf
+as$Sd=>$Tf){$Td=$Sd-$Vg[$C][1];$s=0;foreach($Tf[0]as$Dg)echo"\n
";}}foreach((array)$Wf[$C]as$ch=>$Xf){foreach($Xf
+as$Sd=>$f){$Td=$Sd-$Vg[$C][1];$s=0;foreach($f
+as$bh)echo"\n
";}}echo"\n
\n";}foreach($og
+as$C=>$Q){foreach((array)$Q["references"]as$ch=>$Xf){foreach($Xf
+as$Sd=>$Tf){$te=$rh;$ie=-10;foreach($Tf[0]as$x=>$Dg){$yf=$Q["pos"][0]+$Q["fields"][$Dg]["pos"];$zf=$og[$ch]["pos"][0]+$og[$ch]["fields"][$Tf[1][$x]]["pos"];$te=min($te,$yf,$zf);$ie=max($ie,$yf,$zf);}echo"
\n";}}}echo'
+',lang(129),'
+';}elseif(isset($_GET["dump"])){$a=$_GET["dump"];if($_POST&&!$n){$_b="";foreach(array("output","format","db_style","routines","events","table_style","auto_increment","triggers","data_style")as$x)$_b.="&$x=".urlencode($_POST[$x]);cookie("adminer_export",substr($_b,1));$S=array_flip((array)$_POST["tables"])+array_flip((array)$_POST["data"]);$Ac=dump_headers((count($S)==1?key($S):DB),(DB==""||count($S)>1));$Bd=preg_match('~sql~',$_POST["format"]);if($Bd){echo"-- Adminer $ia ".$Xb[DRIVER]." dump\n\n";if($w=="sql"){echo"SET NAMES utf8;
+SET time_zone = '+00:00';
+".($_POST["data_style"]?"SET foreign_key_checks = 0;
+SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';
+":"")."
+";$h->query("SET time_zone = '+00:00';");}}$Mg=$_POST["db_style"];$l=array(DB);if(DB==""){$l=$_POST["databases"];if(is_string($l))$l=explode("\n",rtrim(str_replace("\r","",$l),"\n"));}foreach((array)$l
+as$m){$b->dumpDatabase($m);if($h->select_db($m)){if($Bd&&preg_match('~CREATE~',$Mg)&&($j=$h->result("SHOW CREATE DATABASE ".idf_escape($m),1))){set_utf8mb4($j);if($Mg=="DROP+CREATE")echo"DROP DATABASE IF EXISTS ".idf_escape($m).";\n";echo"$j;\n";}if($Bd){if($Mg)echo
+use_sql($m).";\n\n";$gf="";if($_POST["routines"]){foreach(array("FUNCTION","PROCEDURE")as$ig){foreach(get_rows("SHOW $ig STATUS WHERE Db = ".q($m),null,"-- ")as$K){$j=remove_definer($h->result("SHOW CREATE $ig ".idf_escape($K["Name"]),2));set_utf8mb4($j);$gf.=($Mg!='DROP+CREATE'?"DROP $ig IF EXISTS ".idf_escape($K["Name"]).";;\n":"")."$j;;\n\n";}}}if($_POST["events"]){foreach(get_rows("SHOW EVENTS",null,"-- ")as$K){$j=remove_definer($h->result("SHOW CREATE EVENT ".idf_escape($K["Name"]),3));set_utf8mb4($j);$gf.=($Mg!='DROP+CREATE'?"DROP EVENT IF EXISTS ".idf_escape($K["Name"]).";;\n":"")."$j;;\n\n";}}if($gf)echo"DELIMITER ;;\n\n$gf"."DELIMITER ;\n\n";}if($_POST["table_style"]||$_POST["data_style"]){$Yh=array();foreach(table_status('',true)as$C=>$R){$Q=(DB==""||in_array($C,(array)$_POST["tables"]));$Eb=(DB==""||in_array($C,(array)$_POST["data"]));if($Q||$Eb){if($Ac=="tar"){$ph=new
+TmpFile;ob_start(array($ph,'write'),1e5);}$b->dumpTable($C,($Q?$_POST["table_style"]:""),(is_view($R)?2:0));if(is_view($R))$Yh[]=$C;elseif($Eb){$p=fields($C);$b->dumpData($C,$_POST["data_style"],"SELECT *".convert_fields($p,$p)." FROM ".table($C));}if($Bd&&$_POST["triggers"]&&$Q&&($zh=trigger_sql($C,$_POST["table_style"])))echo"\nDELIMITER ;;\n$zh\nDELIMITER ;\n";if($Ac=="tar"){ob_end_flush();tar_file((DB!=""?"":"$m/")."$C.csv",$ph);}elseif($Bd)echo"\n";}}foreach($Yh
+as$Xh)$b->dumpTable($Xh,$_POST["table_style"],1);if($Ac=="tar")echo
+pack("x512");}}}if($Bd)echo"-- ".$h->result("SELECT NOW()")."\n";exit;}page_header(lang(65),$n,($_GET["export"]!=""?array("table"=>$_GET["export"]):array()),h(DB));echo'
+
+';$Kc=true;foreach($Bf
+as$x=>$X){if($x!=""&&$X>1){echo($Kc?"":" ")."".h($x)." ";$Kc=false;}}}elseif(isset($_GET["privileges"])){page_header(lang(63));$I=$h->query("SELECT User, Host FROM mysql.".(DB==""?"user":"db WHERE ".q(DB)." LIKE Db")." ORDER BY Host, User");$Vc=$I;if(!$I)$I=$h->query("SELECT SUBSTRING_INDEX(CURRENT_USER, '@', 1) AS User, SUBSTRING_INDEX(CURRENT_USER, '@', -1) AS Host");echo"
\n";hidden_fields_get();echo" \n",($Vc?"":" \n"),"
\n"," \n",''.lang(135)." ";}elseif(isset($_GET["sql"])){if(!$n&&$_POST["export"]){dump_headers("sql");$b->dumpTable("","");$b->dumpData("","table",$_POST["query"]);exit;}restart_session();$fd=&get_session("queries");$ed=&$fd[DB];if(!$n&&$_POST["clear"]){$ed=array();redirect(remove_from_uri("history"));}page_header((isset($_GET["import"])?lang(64):lang(55)),$n);if(!$n&&$_POST){$Sc=false;if(!isset($_GET["import"]))$H=$_POST["query"];elseif($_POST["webfile"]){$Sc=@fopen((file_exists("adminer.sql")?"adminer.sql":"compress.zlib://adminer.sql.gz"),"rb");$H=($Sc?fread($Sc,1e6):false);}else$H=get_file("sql_file",true);if(is_string($H)){if(function_exists('memory_get_usage'))@ini_set("memory_limit",max(ini_bytes("memory_limit"),2*strlen($H)+memory_get_usage()+8e6));if($H!=""&&strlen($H)<1e6){$Lf=$H.(preg_match("~;[ \t\r\n]*\$~",$H)?"":";");if(!$ed||reset(end($ed))!=$Lf){restart_session();$ed[]=array($Lf,time());set_session("queries",$fd);stop_session();}}$Eg="(?:\\s|/\\*.*\\*/|(?:#|-- )[^\n]*\n|--\r?\n)";$Nb=";";$D=0;$mc=true;$i=connect();if(is_object($i)&&DB!="")$i->select_db(DB);$qb=0;$rc=array();$Yd=0;$lf='[\'"'.($w=="sql"?'`#':($w=="sqlite"?'`[':($w=="mssql"?'[':''))).']|/\\*|-- |$'.($w=="pgsql"?'|\\$[^$]*\\$':'');$sh=microtime(true);parse_str($_COOKIE["adminer_export"],$xa);$dc=$b->dumpFormat();unset($dc["sql"]);while($H!=""){if(!$D&&preg_match("~^$Eg*DELIMITER\\s+(\\S+)~i",$H,$B)){$Nb=$B[1];$H=substr($H,strlen($B[0]));}else{preg_match('('.preg_quote($Nb)."\\s*|$lf)",$H,$B,PREG_OFFSET_CAPTURE,$D);list($Qc,$xf)=$B[0];if(!$Qc&&$Sc&&!feof($Sc))$H.=fread($Sc,1e5);else{if(!$Qc&&rtrim($H)=="")break;$D=$xf+strlen($Qc);if($Qc&&rtrim($Qc)!=$Nb){while(preg_match('('.($Qc=='/*'?'\\*/':($Qc=='['?']':(preg_match('~^-- |^#~',$Qc)?"\n":preg_quote($Qc)."|\\\\."))).'|$)s',$H,$B,PREG_OFFSET_CAPTURE,$D)){$mg=$B[0][0];if(!$mg&&$Sc&&!feof($Sc))$H.=fread($Sc,1e5);else{$D=$B[0][1]+strlen($mg);if($mg[0]!="\\")break;}}}else{$mc=false;$Lf=substr($H,0,$xf);$qb++;$Ef="
".shorten_utf8(trim($Lf),1000)."
\n";if(!$_POST["only_errors"]){echo$Ef;ob_flush();flush();}$Hg=microtime(true);if($h->multi_query($Lf)&&is_object($i)&&preg_match("~^$Eg*USE\\b~isU",$Lf))$i->query($Lf);do{$I=$h->store_result();$ih=" (".format_time($Hg).") ".(strlen($Lf)<1000?" ".lang(10)." ":"");if($h->error){echo($_POST["only_errors"]?$Ef:""),"".lang(136).($h->errno?" ($h->errno)":"").": ".error()."\n";$rc[]=" $qb ";if($_POST["error_stops"])break
+2;}elseif(is_object($I)){$z=$_POST["limit"];$af=select($I,$i,array(),$z);if(!$_POST["only_errors"]){echo"
\n";$De=$I->num_rows;echo"".($De?($z&&$De>$z?lang(137,$z):"").lang(138,$De):""),$ih;$jd="export-$qb";$_c=", ".lang(65)." : ".html_select("output",$b->dumpOutput(),$xa["output"])." ".html_select("format",$dc,$xa["format"])." "." \n";if($i&&preg_match("~^($Eg|\\()*SELECT\\b~isU",$Lf)&&($zc=explain($i,$Lf))){$jd="explain-$qb";echo", EXPLAIN $_c","
\n";select($zc,$i,$af);echo"
\n";}else
+echo$_c;echo" \n";}}else{if(preg_match("~^$Eg*(CREATE|DROP|ALTER)$Eg+(DATABASE|SCHEMA)\\b~isU",$Lf)){restart_session();set_session("dbs",null);stop_session();}if(!$_POST["only_errors"])echo"".lang(139,$h->affected_rows)."$ih\n";}$Hg=microtime(true);}while($h->next_result());$Yd+=substr_count($Lf.$Qc,"\n");$H=substr($H,$D);$D=0;}}}}if($mc)echo"
".lang(140)."\n";elseif($_POST["only_errors"]){echo"
".lang(141,$qb-count($rc))," (".format_time($sh).") \n";}elseif($rc&&$qb>1)echo"
".lang(136).": ".implode("",$rc)."\n";}else
+echo"
".upload_error($H)."\n";}echo'
+
+';$wc=" ";if(!isset($_GET["import"])){$Lf=$_GET["sql"];if($_POST)$Lf=$_POST["query"];elseif($_GET["history"]=="all")$Lf=$ed;elseif($_GET["history"]!="")$Lf=$ed[$_GET["history"]][0];echo"";textarea("query",$Lf,20);echo($_POST?"":"\n"),"
$wc\n",lang(143).": \n";}else{echo"
".lang(144)." ",(ini_bool("file_uploads")?"SQL (< ".ini_get("upload_max_filesize")."B): \n$wc":lang(145)),"
\n","".lang(146)." ",lang(147,"adminer.sql".(extension_loaded("zlib")?"[.gz]":"")."
"),' ',"
\n","";}echo
+checkbox("error_stops",1,($_POST?$_POST["error_stops"]:isset($_GET["import"])),lang(149))."\n",checkbox("only_errors",1,($_POST?$_POST["only_errors"]:isset($_GET["import"])),lang(150))."\n"," \n";if(!isset($_GET["import"])&&$ed){print_fieldset("history",lang(151),$_GET["history"]!="");for($X=end($ed);$X;$X=prev($ed)){$x=key($ed);list($Lf,$ih,$hc)=$X;echo''.lang(10)." "." ".@date("H:i:s",$ih)." "." ".shorten_utf8(ltrim(str_replace("\n"," ",str_replace("\r","",preg_replace('~^(#|-- ).*~m','',$Lf)))),80,"
").($hc?" ($hc) ":"")." \n";}echo" \n","".lang(153)." \n","\n";}echo'
+';}elseif(isset($_GET["edit"])){$a=$_GET["edit"];$p=fields($a);$Z=(isset($_GET["select"])?(count($_POST["check"])==1?where_check($_POST["check"][0],$p):""):where($_GET,$p));$Jh=(isset($_GET["select"])?$_POST["edit"]:$Z);foreach($p
+as$C=>$o){if(!isset($o["privileges"][$Jh?"update":"insert"])||$b->fieldName($o)=="")unset($p[$C]);}if($_POST&&!$n&&!isset($_GET["select"])){$A=$_POST["referer"];if($_POST["insert"])$A=($Jh?null:$_SERVER["REQUEST_URI"]);elseif(!preg_match('~^.+&select=.+$~',$A))$A=ME."select=".urlencode($a);$v=indexes($a);$Eh=unique_array($_GET["where"],$v);$Of="\nWHERE $Z";if(isset($_POST["delete"]))queries_redirect($A,lang(154),$Wb->delete($a,$Of,!$Eh));else{$O=array();foreach($p
+as$C=>$o){$X=process_input($o);if($X!==false&&$X!==null)$O[idf_escape($C)]=$X;}if($Jh){if(!$O)redirect($A);queries_redirect($A,lang(155),$Wb->update($a,$O,$Of,!$Eh));if(is_ajax()){page_headers();page_messages($n);exit;}}else{$I=$Wb->insert($a,$O);$Rd=($I?last_id():0);queries_redirect($A,lang(156,($Rd?" $Rd":"")),$I);}}}$K=null;if($_POST["save"])$K=(array)$_POST["fields"];elseif($Z){$M=array();foreach($p
+as$C=>$o){if(isset($o["privileges"]["select"])){$Ga=convert_field($o);if($_POST["clone"]&&$o["auto_increment"])$Ga="''";if($w=="sql"&&preg_match("~enum|set~",$o["type"]))$Ga="1*".idf_escape($C);$M[]=($Ga?"$Ga AS ":"").idf_escape($C);}}$K=array();if(!support("table"))$M=array("*");if($M){$I=$Wb->select($a,$M,array($Z),$M,array(),(isset($_GET["select"])?2:1));$K=$I->fetch_assoc();if(!$K)$K=false;if(isset($_GET["select"])&&(!$K||$I->fetch_assoc()))$K=null;}}if(!support("table")&&!$p){if(!$Z){$I=$Wb->select($a,array("*"),$Z,array("*"));$K=($I?$I->fetch_assoc():false);if(!$K)$K=array($Wb->primary=>"");}if($K){foreach($K
+as$x=>$X){if(!$Z)$K[$x]=null;$p[$x]=array("field"=>$x,"null"=>($x!=$Wb->primary),"auto_increment"=>($x==$Wb->primary));}}}edit_form($a,$p,$K,$Jh);}elseif(isset($_GET["create"])){$a=$_GET["create"];$mf=array();foreach(array('HASH','LINEAR HASH','KEY','LINEAR KEY','RANGE','LIST')as$x)$mf[$x]=$x;$Vf=referencable_primary($a);$Oc=array();foreach($Vf
+as$Tg=>$o)$Oc[str_replace("`","``",$Tg)."`".str_replace("`","``",$o["field"])]=$Tg;$df=array();$R=array();if($a!=""){$df=fields($a);$R=table_status($a);if(!$R)$n=lang(9);}$K=$_POST;$K["fields"]=(array)$K["fields"];if($K["auto_increment_col"])$K["fields"][$K["auto_increment_col"]]["auto_increment"]=true;if($_POST&&!process_fields($K["fields"])&&!$n){if($_POST["drop"])queries_redirect(substr(ME,0,-1),lang(157),drop_tables(array($a)));else{$p=array();$Da=array();$Nh=false;$Mc=array();ksort($K["fields"]);$cf=reset($df);$Aa=" FIRST";foreach($K["fields"]as$x=>$o){$q=$Oc[$o["type"]];$_h=($q!==null?$Vf[$q]:$o);if($o["field"]!=""){if(!$o["has_default"])$o["default"]=null;if($x==$K["auto_increment_col"])$o["auto_increment"]=true;$Jf=process_field($o,$_h);$Da[]=array($o["orig"],$Jf,$Aa);if($Jf!=process_field($cf,$cf)){$p[]=array($o["orig"],$Jf,$Aa);if($o["orig"]!=""||$Aa)$Nh=true;}if($q!==null)$Mc[idf_escape($o["field"])]=($a!=""&&$w!="sqlite"?"ADD":" ").format_foreign_key(array('table'=>$Oc[$o["type"]],'source'=>array($o["field"]),'target'=>array($_h["field"]),'on_delete'=>$o["on_delete"],));$Aa=" AFTER ".idf_escape($o["field"]);}elseif($o["orig"]!=""){$Nh=true;$p[]=array($o["orig"]);}if($o["orig"]!=""){$cf=next($df);if(!$cf)$Aa="";}}$of="";if($mf[$K["partition_by"]]){$pf=array();if($K["partition_by"]=='RANGE'||$K["partition_by"]=='LIST'){foreach(array_filter($K["partition_names"])as$x=>$X){$Y=$K["partition_values"][$x];$pf[]="\n PARTITION ".idf_escape($X)." VALUES ".($K["partition_by"]=='RANGE'?"LESS THAN":"IN").($Y!=""?" ($Y)":" MAXVALUE");}}$of.="\nPARTITION BY $K[partition_by]($K[partition])".($pf?" (".implode(",",$pf)."\n)":($K["partitions"]?" PARTITIONS ".(+$K["partitions"]):""));}elseif(support("partitioning")&&preg_match("~partitioned~",$R["Create_options"]))$of.="\nREMOVE PARTITIONING";$me=lang(158);if($a==""){cookie("adminer_engine",$K["Engine"]);$me=lang(159);}$C=trim($K["name"]);queries_redirect(ME.(support("table")?"table=":"select=").urlencode($C),$me,alter_table($a,$C,($w=="sqlite"&&($Nh||$Mc)?$Da:$p),$Mc,($K["Comment"]!=$R["Comment"]?$K["Comment"]:null),($K["Engine"]&&$K["Engine"]!=$R["Engine"]?$K["Engine"]:""),($K["Collation"]&&$K["Collation"]!=$R["Collation"]?$K["Collation"]:""),($K["Auto_increment"]!=""?number($K["Auto_increment"]):""),$of));}}page_header(($a!=""?lang(41):lang(66)),$n,array("table"=>$a),h($a));if(!$_POST){$K=array("Engine"=>$_COOKIE["adminer_engine"],"fields"=>array(array("field"=>"","type"=>(isset($Bh["int"])?"int":(isset($Bh["integer"])?"integer":"")))),"partition_names"=>array(""),);if($a!=""){$K=$R;$K["name"]=$a;$K["fields"]=array();if(!$_GET["auto_increment"])$K["Auto_increment"]="";foreach($df
+as$o){$o["has_default"]=isset($o["default"]);$K["fields"][]=$o;}if(support("partitioning")){$Tc="FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA = ".q(DB)." AND TABLE_NAME = ".q($a);$I=$h->query("SELECT PARTITION_METHOD, PARTITION_ORDINAL_POSITION, PARTITION_EXPRESSION $Tc ORDER BY PARTITION_ORDINAL_POSITION DESC LIMIT 1");list($K["partition_by"],$K["partitions"],$K["partition"])=$I->fetch_row();$pf=get_key_vals("SELECT PARTITION_NAME, PARTITION_DESCRIPTION $Tc AND PARTITION_NAME != '' ORDER BY PARTITION_ORDINAL_POSITION");$pf[""]="";$K["partition_names"]=array_keys($pf);$K["partition_values"]=array_values($pf);}}}$nb=collations();$oc=engines();foreach($oc
+as$nc){if(!strcasecmp($nc,$K["Engine"])){$K["Engine"]=$nc;break;}}echo'
+
+
+';if(support("columns")||$a==""){echo
+lang(160),':
+';if($a==""&&!$_POST){?>".optionlist(array(""=>"(".lang(161).")")+$oc,$K["Engine"])."":""),' ',($nb&&!preg_match("~sqlite|mssql~",$w)?html_select("Collation",array(""=>"(".lang(87).")")+$nb,$K["Collation"]):""),'
+';}echo'
+';if(support("columns")){echo'
+';$sb=($_POST?$_POST["comments"]:$K["Comment"]!="");if(!$_POST&&!$sb){foreach($K["fields"]as$o){if($o["comment"]!=""){$sb=true;break;}}}edit_fields($K["fields"],$nb,"TABLE",$Oc,$sb);echo'
+
+',lang(56),':
+',checkbox("defaults",1,true,lang(162),"columnShow(this.checked, 5)","jsonly");if(!$_POST["defaults"]){echo'';}echo(support("comment")?" ".lang(96)." ".' ':''),'
+
+';}echo'
+';if($a!=""){echo' ';}if(support("partitioning")){$nf=preg_match('~RANGE|LIST~',$K["partition_by"]);print_fieldset("partition",lang(163),$K["partition_by"]);echo'
+',"".optionlist(array(""=>"")+$mf,$K["partition_by"])." ",'( )
+',lang(164),':
+
+
+';}echo'
+
+';}elseif(isset($_GET["indexes"])){$a=$_GET["indexes"];$pd=array("PRIMARY","UNIQUE","INDEX");$R=table_status($a,true);if(preg_match('~MyISAM|M?aria'.($h->server_info>=5.6?'|InnoDB':'').'~i',$R["Engine"]))$pd[]="FULLTEXT";$v=indexes($a);$Cf=array();if($w=="mongo"){$Cf=$v["_id_"];unset($pd[0]);unset($v["_id_"]);}$K=$_POST;if($_POST&&!$n&&!$_POST["add"]&&!$_POST["drop_col"]){$c=array();foreach($K["indexes"]as$u){$C=$u["name"];if(in_array($u["type"],$pd)){$f=array();$Wd=array();$Pb=array();$O=array();ksort($u["columns"]);foreach($u["columns"]as$x=>$e){if($e!=""){$y=$u["lengths"][$x];$Ob=$u["descs"][$x];$O[]=idf_escape($e).($y?"(".(+$y).")":"").($Ob?" DESC":"");$f[]=$e;$Wd[]=($y?$y:null);$Pb[]=$Ob;}}if($f){$xc=$v[$C];if($xc){ksort($xc["columns"]);ksort($xc["lengths"]);ksort($xc["descs"]);if($u["type"]==$xc["type"]&&array_values($xc["columns"])===$f&&(!$xc["lengths"]||array_values($xc["lengths"])===$Wd)&&array_values($xc["descs"])===$Pb){unset($v[$C]);continue;}}$c[]=array($u["type"],$C,$O);}}}foreach($v
+as$C=>$xc)$c[]=array($xc["type"],$C,"DROP");if(!$c)redirect(ME."table=".urlencode($a));queries_redirect(ME."table=".urlencode($a),lang(167),alter_indexes($a,$c));}page_header(lang(121),$n,array("table"=>$a),h($a));$p=array_keys(fields($a));if($_POST["add"]){foreach($K["indexes"]as$x=>$u){if($u["columns"][count($u["columns"])]!="")$K["indexes"][$x]["columns"][]="";}$u=end($K["indexes"]);if($u["type"]||array_filter($u["columns"],'strlen'))$K["indexes"][]=array("columns"=>array(1=>""));}if(!$K){foreach($v
+as$x=>$u){$v[$x]["name"]=$x;$v[$x]["columns"][]="";}$v[]=array("columns"=>array(1=>""));$K["indexes"]=$v;}echo'
+
+
+
+',lang(168),' ',lang(169),'',lang(170);?>
+
+
+';if($Cf){echo"PRIMARY ";foreach($Cf["columns"]as$x=>$e){echo
+select_input(" disabled",$p,$e)," ".lang(50)." ";}echo" \n";}$Fd=1;foreach($K["indexes"]as$u){if(!$_POST["drop_col"]||$Fd!=key($_POST["drop_col"])){echo" ".html_select("indexes[$Fd][type]",array(-1=>"")+$pd,$u["type"],($Fd==count($K["indexes"])?"indexesAddRow(this);":1))," ";ksort($u["columns"]);$s=1;foreach($u["columns"]as$x=>$e){echo"".select_input(" name='indexes[$Fd][columns][$s]' onchange=\"".($s==count($u["columns"])?"indexesAddColumn":"indexesChangeColumn")."(this, '".js_escape($w=="sql"?"":$_GET["indexes"]."_")."');\"",($p?array_combine($p,$p):$p),$e),($w=="sql"||$w=="mssql"?" ":""),($w!="sql"?checkbox("indexes[$Fd][descs][$s]",1,$u["descs"][$x],lang(50)):"")," ";$s++;}echo" \n"," \n";}$Fd++;}echo'
+
+
+
+
+';}elseif(isset($_GET["database"])){$K=$_POST;if($_POST&&!$n&&!isset($_POST["add_x"])){$C=trim($K["name"]);if($_POST["drop"]){$_GET["db"]="";queries_redirect(remove_from_uri("db|database"),lang(171),drop_databases(array(DB)));}elseif(DB!==$C){if(DB!=""){$_GET["db"]=$C;queries_redirect(preg_replace('~\bdb=[^&]*&~','',ME)."db=".urlencode($C),lang(172),rename_database($C,$K["collation"]));}else{$l=explode("\n",str_replace("\r","",$C));$Ng=true;$Qd="";foreach($l
+as$m){if(count($l)==1||$m!=""){if(!create_database($m,$K["collation"]))$Ng=false;$Qd=$m;}}restart_session();set_session("dbs",null);queries_redirect(ME."db=".urlencode($Qd),lang(173),$Ng);}}else{if(!$K["collation"])redirect(substr(ME,0,-1));query_redirect("ALTER DATABASE ".idf_escape($C).(preg_match('~^[a-z0-9_]+$~i',$K["collation"])?" COLLATE $K[collation]":""),substr(ME,0,-1),lang(174));}}page_header(DB!=""?lang(59):lang(175),$n,array(),h(DB));$nb=collations();$C=DB;if($_POST)$C=$K["name"];elseif(DB!="")$K["collation"]=db_collation(DB,$nb);elseif($w=="sql"){foreach(get_vals("SHOW GRANTS")as$Vc){if(preg_match('~ ON (`(([^\\\\`]|``|\\\\.)*)%`\\.\\*)?~',$Vc,$B)&&$B[1]){$C=stripcslashes(idf_unescape("`$B[2]`"));break;}}}echo'
+
+
+',($_POST["add_x"]||strpos($C,"\n")?''.h($C).' ':' ')."\n".($nb?html_select("collation",array(""=>"(".lang(87).")")+$nb,$K["collation"]).doc_link(array('sql'=>"charset-charsets.html",'mssql'=>"ms187963.aspx",)):"");?>
+
+
+';if(DB!="")echo" \n";elseif(!$_POST["add_x"]&&$_GET["db"]=="")echo" \n";echo'
+
+';}elseif(isset($_GET["scheme"])){$K=$_POST;if($_POST&&!$n){$_=preg_replace('~ns=[^&]*&~','',ME)."ns=";if($_POST["drop"])query_redirect("DROP SCHEMA ".idf_escape($_GET["ns"]),$_,lang(176));else{$C=trim($K["name"]);$_.=urlencode($C);if($_GET["ns"]=="")query_redirect("CREATE SCHEMA ".idf_escape($C),$_,lang(177));elseif($_GET["ns"]!=$C)query_redirect("ALTER SCHEMA ".idf_escape($_GET["ns"])." RENAME TO ".idf_escape($C),$_,lang(178));else
+redirect($_);}}page_header($_GET["ns"]!=""?lang(60):lang(61),$n);if(!$K)$K["name"]=$_GET["ns"];echo'
+
+ " autocapitalize="off">
+
+
+';if($_GET["ns"]!="")echo" \n";echo'
+
+';}elseif(isset($_GET["call"])){$da=$_GET["call"];page_header(lang(179).": ".h($da),$n);$ig=routine($da,(isset($_GET["callf"])?"FUNCTION":"PROCEDURE"));$nd=array();$gf=array();foreach($ig["fields"]as$s=>$o){if(substr($o["inout"],-3)=="OUT")$gf[$s]="@".idf_escape($o["field"])." AS ".idf_escape($o["field"]);if(!$o["inout"]||substr($o["inout"],0,2)=="IN")$nd[]=$s;}if(!$n&&$_POST){$Ya=array();foreach($ig["fields"]as$x=>$o){if(in_array($x,$nd)){$X=process_input($o);if($X===false)$X="''";if(isset($gf[$x]))$h->query("SET @".idf_escape($o["field"])." = $X");}$Ya[]=(isset($gf[$x])?"@".idf_escape($o["field"]):$X);}$H=(isset($_GET["callf"])?"SELECT":"CALL")." ".idf_escape($da)."(".implode(", ",$Ya).")";echo"".h($H)."
".lang(10)." \n";if(!$h->multi_query($H))echo"
".error()."\n";else{$i=connect();if(is_object($i))$i->select_db(DB);do{$I=$h->store_result();if(is_object($I))select($I,$i);else
+echo"
".lang(180,$h->affected_rows)."\n";}while($h->next_result());if($gf)select($h->query("SELECT ".implode(", ",$gf)));}}echo'
+
+';if($nd){echo"\n";foreach($nd
+as$x){$o=$ig["fields"][$x];$C=$o["field"];echo"".$b->fieldName($o);$Y=$_POST["fields"][$C];if($Y!=""){if($o["type"]=="enum")$Y=+$Y;if($o["type"]=="set")$Y=array_sum($Y);}input($o,$Y,(string)$_POST["function"][$C]);echo"\n";}echo"
\n";}echo'
+
+
+
+';}elseif(isset($_GET["foreign"])){$a=$_GET["foreign"];$C=$_GET["name"];$K=$_POST;if($_POST&&!$n&&!$_POST["add"]&&!$_POST["change"]&&!$_POST["change-js"]){$me=($_POST["drop"]?lang(181):($C!=""?lang(182):lang(183)));$A=ME."table=".urlencode($a);$K["source"]=array_filter($K["source"],'strlen');ksort($K["source"]);$bh=array();foreach($K["source"]as$x=>$X)$bh[$x]=$K["target"][$x];$K["target"]=$bh;if($w=="sqlite")queries_redirect($A,$me,recreate_table($a,$a,array(),array(),array(" $C"=>($_POST["drop"]?"":" ".format_foreign_key($K)))));else{$c="ALTER TABLE ".table($a);$Yb="\nDROP ".($w=="sql"?"FOREIGN KEY ":"CONSTRAINT ").idf_escape($C);if($_POST["drop"])query_redirect($c.$Yb,$A,$me);else{query_redirect($c.($C!=""?"$Yb,":"")."\nADD".format_foreign_key($K),$A,$me);$n=lang(184)." $n";}}}page_header(lang(185),$n,array("table"=>$a),h($a));if($_POST){ksort($K["source"]);if($_POST["add"])$K["source"][]="";elseif($_POST["change"]||$_POST["change-js"])$K["target"]=array();}elseif($C!=""){$Oc=foreign_keys($a);$K=$Oc[$C];$K["source"][]="";}else{$K["table"]=$a;$K["source"]=array("");}$Dg=array_keys(fields($a));$bh=($a===$K["table"]?$Dg:array_keys(fields($K["table"])));$Uf=array_keys(array_filter(table_status('',true),'fk_support'));echo'
+
+
+';if($K["db"]==""&&$K["ns"]==""){echo
+lang(186),':
+',html_select("table",$Uf,$K["table"],"this.form['change-js'].value = '1'; this.form.submit();"),'
+
+
+',lang(123),' ',lang(124),'
+';$Fd=0;foreach($K["source"]as$x=>$X){echo"","".html_select("source[".(+$x)."]",array(-1=>"")+$Dg,$X,($Fd==count($K["source"])-1?"foreignAddRow(this);":1))," ".html_select("target[".(+$x)."]",$bh,$K["target"][$x]);$Fd++;}echo'
+
+',lang(89),': ',html_select("on_delete",array(-1=>"")+explode("|",$Ne),$K["on_delete"]),' ',lang(88),': ',html_select("on_update",array(-1=>"")+explode("|",$Ne),$K["on_update"]),doc_link(array('sql'=>"innodb-foreign-key-constraints.html",'pgsql'=>"sql-createtable.html#SQL-CREATETABLE-REFERENCES",'mssql'=>"ms174979.aspx",'oracle'=>"clauses002.htm#sthref2903",)),'
+
+
+';}if($C!=""){echo' ';}echo'
+
+';}elseif(isset($_GET["view"])){$a=$_GET["view"];$K=$_POST;if($_POST&&!$n){$C=trim($K["name"]);$Ga=" AS\n$K[select]";$A=ME."table=".urlencode($C);$me=lang(189);if($_GET["materialized"])$U="MATERIALIZED VIEW";else{$U="VIEW";if($w=="pgsql"){$Ig=table_status($C);$U=($Ig?strtoupper($Ig["Engine"]):$U);}}if(!$_POST["drop"]&&$a==$C&&$w!="sqlite"&&$U!="MATERIALIZED VIEW")query_redirect(($w=="mssql"?"ALTER":"CREATE OR REPLACE")." VIEW ".table($C).$Ga,$A,$me);else{$dh=$C."_adminer_".uniqid();drop_create("DROP $U ".table($a),"CREATE $U ".table($C).$Ga,"DROP $U ".table($C),"CREATE $U ".table($dh).$Ga,"DROP $U ".table($dh),($_POST["drop"]?substr(ME,0,-1):$A),lang(190),$me,lang(191),$a,$C);}}if(!$_POST&&$a!=""){$K=view($a);$K["name"]=$a;if(!$n)$n=error();}page_header(($a!=""?lang(40):lang(192)),$n,array("table"=>$a),h($a));echo'
+
+',lang(170),':
+
';textarea("select",$K["select"]);echo'
+
+';if($_GET["view"]!=""){echo' ';}echo'
+
+';}elseif(isset($_GET["event"])){$aa=$_GET["event"];$xd=array("YEAR","QUARTER","MONTH","DAY","HOUR","MINUTE","WEEK","SECOND","YEAR_MONTH","DAY_HOUR","DAY_MINUTE","DAY_SECOND","HOUR_MINUTE","HOUR_SECOND","MINUTE_SECOND");$Jg=array("ENABLED"=>"ENABLE","DISABLED"=>"DISABLE","SLAVESIDE_DISABLED"=>"DISABLE ON SLAVE");$K=$_POST;if($_POST&&!$n){if($_POST["drop"])query_redirect("DROP EVENT ".idf_escape($aa),substr(ME,0,-1),lang(193));elseif(in_array($K["INTERVAL_FIELD"],$xd)&&isset($Jg[$K["STATUS"]])){$ng="\nON SCHEDULE ".($K["INTERVAL_VALUE"]?"EVERY ".q($K["INTERVAL_VALUE"])." $K[INTERVAL_FIELD]".($K["STARTS"]?" STARTS ".q($K["STARTS"]):"").($K["ENDS"]?" ENDS ".q($K["ENDS"]):""):"AT ".q($K["STARTS"]))." ON COMPLETION".($K["ON_COMPLETION"]?"":" NOT")." PRESERVE";queries_redirect(substr(ME,0,-1),($aa!=""?lang(194):lang(195)),queries(($aa!=""?"ALTER EVENT ".idf_escape($aa).$ng.($aa!=$K["EVENT_NAME"]?"\nRENAME TO ".idf_escape($K["EVENT_NAME"]):""):"CREATE EVENT ".idf_escape($K["EVENT_NAME"]).$ng)."\n".$Jg[$K["STATUS"]]." COMMENT ".q($K["EVENT_COMMENT"]).rtrim(" DO\n$K[EVENT_DEFINITION]",";").";"));}}page_header(($aa!=""?lang(196).": ".h($aa):lang(197)),$n);if(!$K&&$aa!=""){$L=get_rows("SELECT * FROM information_schema.EVENTS WHERE EVENT_SCHEMA = ".q(DB)." AND EVENT_NAME = ".q($aa));$K=reset($L);}echo'
+
+
+',lang(170),'
+',lang(198),'
+',lang(199),'
+',lang(200),' ',html_select("INTERVAL_FIELD",$xd,$K["INTERVAL_FIELD"]),'',lang(107),' ',html_select("STATUS",$Jg,$K["STATUS"]),' ',lang(96),'
+ ',checkbox("ON_COMPLETION","PRESERVE",$K["ON_COMPLETION"]=="PRESERVE",lang(201)),'
+';textarea("EVENT_DEFINITION",$K["EVENT_DEFINITION"]);echo'
+
+';if($aa!=""){echo' ';}echo'
+
+';}elseif(isset($_GET["procedure"])){$da=$_GET["procedure"];$ig=(isset($_GET["function"])?"FUNCTION":"PROCEDURE");$K=$_POST;$K["fields"]=(array)$K["fields"];if($_POST&&!process_fields($K["fields"])&&!$n){$dh="$K[name]_adminer_".uniqid();drop_create("DROP $ig ".idf_escape($da),create_routine($ig,$K),"DROP $ig ".idf_escape($K["name"]),create_routine($ig,array("name"=>$dh)+$K),"DROP $ig ".idf_escape($dh),substr(ME,0,-1),lang(202),lang(203),lang(204),$da,$K["name"]);}page_header(($da!=""?(isset($_GET["function"])?lang(205):lang(206)).": ".h($da):(isset($_GET["function"])?lang(207):lang(208))),$n);if(!$_POST&&$da!=""){$K=routine($da,$ig);$K["name"]=$da;}$nb=get_vals("SHOW CHARACTER SET");sort($nb);$jg=routine_languages();echo'
+
+',lang(170),':
+',($jg?lang(19).": ".html_select("language",$jg,$K["language"]):""),'
+
+';edit_fields($K["fields"],$nb,$ig);if(isset($_GET["function"])){echo"".lang(209);edit_type("returns",$K["returns"],$nb);}echo'
+';textarea("definition",$K["definition"]);echo'
+
+';if($da!=""){echo' ';}echo'
+
+';}elseif(isset($_GET["sequence"])){$fa=$_GET["sequence"];$K=$_POST;if($_POST&&!$n){$_=substr(ME,0,-1);$C=trim($K["name"]);if($_POST["drop"])query_redirect("DROP SEQUENCE ".idf_escape($fa),$_,lang(210));elseif($fa=="")query_redirect("CREATE SEQUENCE ".idf_escape($C),$_,lang(211));elseif($fa!=$C)query_redirect("ALTER SEQUENCE ".idf_escape($fa)." RENAME TO ".idf_escape($C),$_,lang(212));else
+redirect($_);}page_header($fa!=""?lang(213).": ".h($fa):lang(214),$n);if(!$K)$K["name"]=$fa;echo'
+
+
+
+';if($fa!="")echo" \n";echo'
+
+';}elseif(isset($_GET["type"])){$ga=$_GET["type"];$K=$_POST;if($_POST&&!$n){$_=substr(ME,0,-1);if($_POST["drop"])query_redirect("DROP TYPE ".idf_escape($ga),$_,lang(215));else
+query_redirect("CREATE TYPE ".idf_escape(trim($K["name"]))." $K[as]",$_,lang(216));}page_header($ga!=""?lang(217).": ".h($ga):lang(218),$n);if(!$K)$K["as"]="AS ";echo'
+
+
+';if($ga!="")echo" \n";else{echo" \n";textarea("as",$K["as"]);echo"
\n";}echo'
+
+';}elseif(isset($_GET["trigger"])){$a=$_GET["trigger"];$C=$_GET["name"];$yh=trigger_options();$K=(array)trigger($C)+array("Trigger"=>$a."_bi");if($_POST){if(!$n&&in_array($_POST["Timing"],$yh["Timing"])&&in_array($_POST["Event"],$yh["Event"])&&in_array($_POST["Type"],$yh["Type"])){$Me=" ON ".table($a);$Yb="DROP TRIGGER ".idf_escape($C).($w=="pgsql"?$Me:"");$A=ME."table=".urlencode($a);if($_POST["drop"])query_redirect($Yb,$A,lang(219));else{if($C!="")queries($Yb);queries_redirect($A,($C!=""?lang(220):lang(221)),queries(create_trigger($Me,$_POST)));if($C!="")queries(create_trigger($Me,$K+array("Type"=>reset($yh["Type"]))));}}$K=$_POST;}page_header(($C!=""?lang(222).": ".h($C):lang(223)),$n,array("table"=>$a));echo'
+
+
+',lang(224),' ',html_select("Timing",$yh["Timing"],$K["Timing"],"triggerChange(/^".preg_quote($a,"/")."_[ba][iud]$/, '".js_escape($a)."', this.form);"),' ',lang(225),' ',html_select("Event",$yh["Event"],$K["Event"],"this.form['Timing'].onchange();"),(in_array("UPDATE OF",$yh["Event"])?" ":""),' ',lang(92),' ',html_select("Type",$yh["Type"],$K["Type"]),'
+',lang(170),': " maxlength="64" autocapitalize="off">
+
+
+
+';if($C!=""){echo' ';}echo'
+
+';}elseif(isset($_GET["user"])){$ha=$_GET["user"];$Hf=array(""=>array("All privileges"=>""));foreach(get_rows("SHOW PRIVILEGES")as$K){foreach(explode(",",($K["Privilege"]=="Grant option"?"":$K["Context"]))as$yb)$Hf[$yb][$K["Privilege"]]=$K["Comment"];}$Hf["Server Admin"]+=$Hf["File access on server"];$Hf["Databases"]["Create routine"]=$Hf["Procedures"]["Create routine"];unset($Hf["Procedures"]["Create routine"]);$Hf["Columns"]=array();foreach(array("Select","Insert","Update","References")as$X)$Hf["Columns"][$X]=$Hf["Tables"][$X];unset($Hf["Server Admin"]["Usage"]);foreach($Hf["Tables"]as$x=>$X)unset($Hf["Databases"][$x]);$ze=array();if($_POST){foreach($_POST["objects"]as$x=>$X)$ze[$X]=(array)$ze[$X]+(array)$_POST["grants"][$x];}$Wc=array();$Ke="";if(isset($_GET["host"])&&($I=$h->query("SHOW GRANTS FOR ".q($ha)."@".q($_GET["host"])))){while($K=$I->fetch_row()){if(preg_match('~GRANT (.*) ON (.*) TO ~',$K[0],$B)&&preg_match_all('~ *([^(,]*[^ ,(])( *\\([^)]+\\))?~',$B[1],$ee,PREG_SET_ORDER)){foreach($ee
+as$X){if($X[1]!="USAGE")$Wc["$B[2]$X[2]"][$X[1]]=true;if(preg_match('~ WITH GRANT OPTION~',$K[0]))$Wc["$B[2]$X[2]"]["GRANT OPTION"]=true;}}if(preg_match("~ IDENTIFIED BY PASSWORD '([^']+)~",$K[0],$B))$Ke=$B[1];}}if($_POST&&!$n){$Le=(isset($_GET["host"])?q($ha)."@".q($_GET["host"]):"''");if($_POST["drop"])query_redirect("DROP USER $Le",ME."privileges=",lang(226));else{$Ae=q($_POST["user"])."@".q($_POST["host"]);$qf=$_POST["pass"];if($qf!=''&&!$_POST["hashed"]){$qf=$h->result("SELECT PASSWORD(".q($qf).")");$n=!$qf;}$Cb=false;if(!$n){if($Le!=$Ae){$Cb=queries(($h->server_info<5?"GRANT USAGE ON *.* TO":"CREATE USER")." $Ae IDENTIFIED BY PASSWORD ".q($qf));$n=!$Cb;}elseif($qf!=$Ke)queries("SET PASSWORD FOR $Ae = ".q($qf));}if(!$n){$fg=array();foreach($ze
+as$Fe=>$Vc){if(isset($_GET["grant"]))$Vc=array_filter($Vc);$Vc=array_keys($Vc);if(isset($_GET["grant"]))$fg=array_diff(array_keys(array_filter($ze[$Fe],'strlen')),$Vc);elseif($Le==$Ae){$Ie=array_keys((array)$Wc[$Fe]);$fg=array_diff($Ie,$Vc);$Vc=array_diff($Vc,$Ie);unset($Wc[$Fe]);}if(preg_match('~^(.+)\\s*(\\(.*\\))?$~U',$Fe,$B)&&(!grant("REVOKE",$fg,$B[2]," ON $B[1] FROM $Ae")||!grant("GRANT",$Vc,$B[2]," ON $B[1] TO $Ae"))){$n=true;break;}}}if(!$n&&isset($_GET["host"])){if($Le!=$Ae)queries("DROP USER $Le");elseif(!isset($_GET["grant"])){foreach($Wc
+as$Fe=>$fg){if(preg_match('~^(.+)(\\(.*\\))?$~U',$Fe,$B))grant("REVOKE",array_keys($fg),$B[2]," ON $B[1] FROM $Ae");}}}queries_redirect(ME."privileges=",(isset($_GET["host"])?lang(227):lang(228)),!$n);if($Cb)$h->query("DROP USER $Ae");}}page_header((isset($_GET["host"])?lang(33).": ".h("$ha@$_GET[host]"):lang(135)),$n,array("privileges"=>array('',lang(63))));if($_POST){$K=$_POST;$Wc=$ze;}else{$K=$_GET+array("host"=>$h->result("SELECT SUBSTRING_INDEX(CURRENT_USER, '@', -1)"));$K["pass"]=$Ke;if($Ke!="")$K["hashed"]=true;$Wc[(DB==""||$Wc?"":idf_escape(addcslashes(DB,"%_\\"))).".*"]=array();}echo'
+
+',lang(32),'
+',lang(33),'
+',lang(34),'
+';if(!$K["hashed"]){echo'';}echo
+checkbox("hashed",1,$K["hashed"],lang(229),"typePassword(this.form['pass'], this.checked);"),'
+
+';echo"\n",'
+
+';if(isset($_GET["host"])){echo' ';}echo'
+
+';}elseif(isset($_GET["processlist"])){if(support("kill")&&$_POST&&!$n){$Md=0;foreach((array)$_POST["kill"]as$X){if(queries("KILL ".number($X)))$Md++;}queries_redirect(ME."processlist=",lang(233,$Md),$Md||!$_POST["kill"]);}page_header(lang(105),$n);echo'
+
+
+';$s=-1;foreach(process_list()as$s=>$K){if(!$s){echo"".(support("kill")?" ":"");foreach($K
+as$x=>$X)echo" $x".doc_link(array('sql'=>"show-processlist.html#processlist_".strtolower($x),'pgsql'=>"monitoring-stats.html#PG-STAT-ACTIVITY-VIEW",'oracle'=>"../b14237/dynviews_2088.htm",));echo" \n";}echo"".(support("kill")?"".checkbox("kill[]",$K["Id"],0):"");foreach($K
+as$x=>$X)echo" ".(($w=="sql"&&$x=="Info"&&preg_match("~Query|Killed~",$K["Command"])&&$X!="")||($w=="pgsql"&&$x=="current_query"&&$X!="")||($w=="oracle"&&$x=="sql_text"&&$X!="")?"".shorten_utf8($X,100,"
").' '.lang(234).' ':nbsp($X));echo"\n";}echo'
+
+
+';if(support("kill")){echo($s+1)."/".lang(235,$h->result("SELECT @@max_connections")),"
\n";}echo'
+
+';}elseif(isset($_GET["select"])){$a=$_GET["select"];$R=table_status1($a);$v=indexes($a);$p=fields($a);$Oc=column_foreign_keys($a);$He="";if($R["Oid"]){$He=($w=="sqlite"?"rowid":"oid");$v[]=array("type"=>"PRIMARY","columns"=>array($He));}parse_str($_COOKIE["adminer_import"],$ya);$gg=array();$f=array();$hh=null;foreach($p
+as$x=>$o){$C=$b->fieldName($o);if(isset($o["privileges"]["select"])&&$C!=""){$f[$x]=html_entity_decode(strip_tags($C),ENT_QUOTES);if(is_shortable($o))$hh=$b->selectLengthProcess();}$gg+=$o["privileges"];}list($M,$Xc)=$b->selectColumnsProcess($f,$v);$Ad=count($Xc)selectSearchProcess($p,$v);$Xe=$b->selectOrderProcess($p,$v);$z=$b->selectLimitProcess();$Tc=($M?implode(", ",$M):"*".($He?", $He":"")).convert_fields($f,$p,$M)."\nFROM ".table($a);$Yc=($Xc&&$Ad?"\nGROUP BY ".implode(", ",$Xc):"").($Xe?"\nORDER BY ".implode(", ",$Xe):"");if($_GET["val"]&&is_ajax()){header("Content-Type: text/plain; charset=utf-8");foreach($_GET["val"]as$Fh=>$K){$Ga=convert_field($p[key($K)]);$M=array($Ga?$Ga:idf_escape(key($K)));$Z[]=where_check($Fh,$p);$J=$Wb->select($a,$M,$Z,$M);if($J)echo
+reset($J->fetch_row());}exit;}if($_POST&&!$n){$ci=$Z;if(!$_POST["all"]&&is_array($_POST["check"])){$eb=array();foreach($_POST["check"]as$bb)$eb[]=where_check($bb,$p);$ci[]="((".implode(") OR (",$eb)."))";}$ci=($ci?"\nWHERE ".implode(" AND ",$ci):"");$Cf=$Hh=null;foreach($v
+as$u){if($u["type"]=="PRIMARY"){$Cf=array_flip($u["columns"]);$Hh=($M?$Cf:array());break;}}foreach((array)$Hh
+as$x=>$X){if(in_array(idf_escape($x),$M))unset($Hh[$x]);}if($_POST["export"]){cookie("adminer_import","output=".urlencode($_POST["output"])."&format=".urlencode($_POST["format"]));dump_headers($a);$b->dumpTable($a,"");if(!is_array($_POST["check"])||$Hh===array())$H="SELECT $Tc$ci$Yc";else{$Dh=array();foreach($_POST["check"]as$X)$Dh[]="(SELECT".limit($Tc,"\nWHERE ".($Z?implode(" AND ",$Z)." AND ":"").where_check($X,$p).$Yc,1).")";$H=implode(" UNION ALL ",$Dh);}$b->dumpData($a,"table",$H);exit;}if(!$b->selectEmailProcess($Z,$Oc)){if($_POST["save"]||$_POST["delete"]){$I=true;$za=0;$O=array();if(!$_POST["delete"]){foreach($f
+as$C=>$X){$X=process_input($p[$C]);if($X!==null&&($_POST["clone"]||$X!==false))$O[idf_escape($C)]=($X!==false?$X:idf_escape($C));}}if($_POST["delete"]||$O){if($_POST["clone"])$H="INTO ".table($a)." (".implode(", ",array_keys($O)).")\nSELECT ".implode(", ",$O)."\nFROM ".table($a);if($_POST["all"]||($Hh===array()&&is_array($_POST["check"]))||$Ad){$I=($_POST["delete"]?$Wb->delete($a,$ci):($_POST["clone"]?queries("INSERT $H$ci"):$Wb->update($a,$O,$ci)));$za=$h->affected_rows;}else{foreach((array)$_POST["check"]as$X){$bi="\nWHERE ".($Z?implode(" AND ",$Z)." AND ":"").where_check($X,$p);$I=($_POST["delete"]?$Wb->delete($a,$bi,1):($_POST["clone"]?queries("INSERT".limit1($H,$bi)):$Wb->update($a,$O,$bi)));if(!$I)break;$za+=$h->affected_rows;}}}$me=lang(237,$za);if($_POST["clone"]&&$I&&$za==1){$Rd=last_id();if($Rd)$me=lang(156," $Rd");}queries_redirect(remove_from_uri($_POST["all"]&&$_POST["delete"]?"page":""),$me,$I);if(!$_POST["delete"]){edit_form($a,$p,(array)$_POST["fields"],!$_POST["clone"]);page_footer();exit;}}elseif(!$_POST["import"]){if(!$_POST["val"])$n=lang(238);else{$I=true;$za=0;foreach($_POST["val"]as$Fh=>$K){$O=array();foreach($K
+as$x=>$X){$x=bracket_escape($x,1);$O[idf_escape($x)]=(preg_match('~char|text~',$p[$x]["type"])||$X!=""?$b->processInput($p[$x],$X):"NULL");}$I=$Wb->update($a,$O," WHERE ".($Z?implode(" AND ",$Z)." AND ":"").where_check($Fh,$p),!($Ad||$Hh===array())," ");if(!$I)break;$za+=$h->affected_rows;}queries_redirect(remove_from_uri(),lang(237,$za),$I);}}elseif(!is_string($Hc=get_file("csv_file",true)))$n=upload_error($Hc);elseif(!preg_match('~~u',$Hc))$n=lang(239);else{cookie("adminer_import","output=".urlencode($ya["output"])."&format=".urlencode($_POST["separator"]));$I=true;$ob=array_keys($p);preg_match_all('~(?>"[^"]*"|[^"\\r\\n]+)+~',$Hc,$ee);$za=count($ee[0]);$Wb->begin();$vg=($_POST["separator"]=="csv"?",":($_POST["separator"]=="tsv"?"\t":";"));$L=array();foreach($ee[0]as$x=>$X){preg_match_all("~((?>\"[^\"]*\")+|[^$vg]*)$vg~",$X.$vg,$fe);if(!$x&&!array_diff($fe[1],$ob)){$ob=$fe[1];$za--;}else{$O=array();foreach($fe[1]as$s=>$lb)$O[idf_escape($ob[$s])]=($lb==""&&$p[$ob[$s]]["null"]?"NULL":q(str_replace('""','"',preg_replace('~^"|"$~','',$lb))));$L[]=$O;}}$I=(!$L||$Wb->insertUpdate($a,$L,$Cf));if($I)$Wb->commit();queries_redirect(remove_from_uri("page"),lang(240,$za),$I);$Wb->rollback();}}}$Tg=$b->tableName($R);if(is_ajax()){page_headers();ob_start();}else
+page_header(lang(44).": $Tg",$n);$O=null;if(isset($gg["insert"])||!support("table")){$O="";foreach((array)$_GET["where"]as$X){if(count($Oc[$X["col"]])==1&&($X["op"]=="="||(!$X["op"]&&!preg_match('~[_%]~',$X["val"]))))$O.="&set".urlencode("[".bracket_escape($X["col"])."]")."=".urlencode($X["val"]);}}$b->selectLinks($R,$O);if(!$f&&support("table"))echo"".lang(241).($p?".":": ".error())."\n";else{echo"
\n","";hidden_fields_get();echo(DB!=""?' '.(isset($_GET["ns"])?' ':""):"");echo' ',"
\n";$b->selectColumnsPrint($M,$f);$b->selectSearchPrint($Z,$f,$v);$b->selectOrderPrint($Xe,$f,$v);$b->selectLimitPrint($z);$b->selectLengthPrint($hh);$b->selectActionPrint($v);echo" \n";$E=$_GET["page"];if($E=="last"){$Rc=$h->result(count_rows($a,$Z,$Ad,$Xc));$E=floor(max(0,$Rc-1)/$z);}$sg=$M;if(!$sg){$sg[]="*";if($He)$sg[]=$He;}$zb=convert_fields($f,$p,$M);if($zb)$sg[]=substr($zb,2);$I=$Wb->select($a,$sg,$Z,$Xc,$Xe,$z,$E,true);if(!$I)echo"".error()."\n";else{if($w=="mssql"&&$E)$I->seek($z*$E);$lc=array();echo"
\n";$L=array();while($K=$I->fetch_assoc()){if($E&&$w=="oracle")unset($K["RNUM"]);$L[]=$K;}if($_GET["page"]!="last"&&+$z&&$Xc&&$Ad&&$w=="sql")$Rc=$h->result(" SELECT FOUND_ROWS()");if(!$L)echo"".lang(12)."\n";else{$Pa=$b->backwardKeys($a,$Tg);echo"
\n","".(!$Xc&&$M?"":" ".lang(242)." ");$ye=array();$Uc=array();reset($M);$Qf=1;foreach($L[0]as$x=>$X){if($x!=$He){$X=$_GET["columns"][key($M)];$o=$p[$M?($X?$X["col"]:current($M)):$x];$C=($o?$b->fieldName($o,$Qf):($X["fun"]?"*":$x));if($C!=""){$Qf++;$ye[$x]=$C;$e=idf_escape($x);$id=remove_from_uri('(order|desc)[^=]*|page').'&order%5B0%5D='.urlencode($x);$Ob="&desc%5B0%5D=1";echo'','';echo
+apply_sql_function($X["fun"],$C)." ";echo""," ↓ ";if(!$X["fun"])echo' = ';echo" ";}$Uc[$x]=$X["fun"];next($M);}}$Wd=array();if($_GET["modify"]){foreach($L
+as$K){foreach($K
+as$x=>$X)$Wd[$x]=max($Wd[$x],min(40,strlen(utf8_decode($X))));}}echo($Pa?" ".lang(243):"")." \n";if(is_ajax()){if($z%2==1&&$E%2==1)odd();ob_end_clean();}foreach($b->rowDescriptions($L,$Oc)as$xe=>$K){$Eh=unique_array($L[$xe],$v);if(!$Eh){$Eh=array();foreach($L[$xe]as$x=>$X){if(!preg_match('~^(COUNT\\((\\*|(DISTINCT )?`(?:[^`]|``)+`)\\)|(AVG|GROUP_CONCAT|MAX|MIN|SUM)\\(`(?:[^`]|``)+`\\))$~',$x))$Eh[$x]=$X;}}$Fh="";foreach($Eh
+as$x=>$X){if(($w=="sql"||$w=="pgsql")&&strlen($X)>64){$x=(strpos($x,'(')?$x:idf_escape($x));$x="MD5(".($w=='sql'&&preg_match("~^utf8_~",$p[$x]["collation"])?$x:"CONVERT($x USING ".charset($h).")").")";$X=md5($X);}$Fh.="&".($X!==null?urlencode("where[".bracket_escape($x)."]")."=".urlencode($X):"null%5B%5D=".urlencode($x));}echo"".(!$Xc&&$M?"":"".checkbox("check[]",substr($Fh,1),in_array(substr($Fh,1),(array)$_POST["check"]),"","this.form['all'].checked = false; formUncheck('all-page');").($Ad||information_schema(DB)?"":" ".lang(244)." "));foreach($K
+as$x=>$X){if(isset($ye[$x])){$o=$p[$x];if($X!=""&&(!isset($lc[$x])||$lc[$x]!=""))$lc[$x]=(is_mail($X)?$ye[$x]:"");$_="";if(preg_match('~blob|bytea|raw|file~',$o["type"])&&$X!="")$_=ME.'download='.urlencode($a).'&field='.urlencode($x).$Fh;if(!$_&&$X!==null){foreach((array)$Oc[$x]as$q){if(count($Oc[$x])==1||end($q["source"])==$x){$_="";foreach($q["source"]as$s=>$Dg)$_.=where_link($s,$q["target"][$s],$L[$xe][$Dg]);$_=($q["db"]!=""?preg_replace('~([?&]db=)[^&]+~','\\1'.urlencode($q["db"]),ME):ME).'select='.urlencode($q["table"]).$_;if(count($q["source"])==1)break;}}}if($x=="COUNT(*)"){$_=ME."select=".urlencode($a);$s=0;foreach((array)$_GET["where"]as$W){if(!array_key_exists($W["col"],$Eh))$_.=where_link($s++,$W["col"],$W["val"],$W["op"]);}foreach($Eh
+as$Gd=>$W)$_.=where_link($s++,$Gd,$W);}$X=select_value($X,$_,$o,$hh);$jd=h("val[$Fh][".bracket_escape($x)."]");$Y=$_POST["val"][$Fh][bracket_escape($x)];$gc=!is_array($K[$x])&&is_utf8($X)&&$L[$xe][$x]==$K[$x]&&!$Uc[$x];$gh=preg_match('~text|lob~',$o["type"]);if(($_GET["modify"]&&$gc)||$Y!==null){$ad=h($Y!==null?$Y:$K[$x]);echo" ".($gh?"$ad ":" ");}else{$be=strpos($X,"... ");echo" $X";}}}if($Pa)echo" ";$b->backwardKeysPrint($Pa,$L[$xe]);echo" \n";}if(is_ajax())exit;echo"
\n";}if(($L||$E)&&!is_ajax()){$vc=true;if($_GET["page"]!="last"){if(!+$z)$Rc=count($L);elseif($w!="sql"||!$Ad){$Rc=($Ad?false:found_rows($R,$Z));if($Rc$z||$E)){echo"";$he=($Rc===false?$E+(count($L)>=$z?2:1):floor(($Rc-1)/$z));if($w!="simpledb"){echo'".lang(246)." :",pagination(0,$E).($E>5?" ...":"");for($s=max(1,$E-4);$s0){echo($E+5<$he?" ...":""),($vc&&$Rc!==false?pagination($he,$E):" ".lang(247)." ");}echo(($Rc===false?count($L)+1:$Rc-$E*$z)>$z?' '.lang(249).' ':'');}else{echo
+lang(246).":",pagination(0,$E).($E>1?" ...":""),($E?pagination($E,$E):""),($he>$E?pagination($E+1,$E).($he>$E+1?" ...":""):"");}}echo"\n",($Rc!==false?"(".($vc?"":"~ ").lang(138,$Rc).") ":"");$Tb=($vc?"":"~ ").$Rc;echo
+checkbox("all",1,0,lang(250),"var checked = formChecked(this, /check/); selectCount('selected', this.checked ? '$Tb' : checked); selectCount('selected2', this.checked || !checked ? '$Tb' : checked);")."\n";if($b->selectCommandPrint()){echo'
',lang(242),'
+
+
+',lang(115),'
+
+
+
+
+';}$Pc=$b->dumpFormat();foreach((array)$_GET["columns"]as$e){if($e["fun"]){unset($Pc['sql']);break;}}if($Pc){print_fieldset("export",lang(65)." ");$hf=$b->dumpOutput();echo($hf?html_select("output",$hf,$ya["output"])." ":""),html_select("format",$Pc,$ya["format"])," \n","\n";}echo(!$Xc&&$M?"":"\n");}if($b->selectImportPrint()){print_fieldset("import",lang(64),!$L);echo" ",html_select("separator",array("csv"=>"CSV,","csv;"=>"CSV;","tsv"=>"TSV"),$ya["format"],1);echo" ","\n";}$b->selectEmailPrint(array_filter($lc,'strlen'),$f);echo"
\n","
\n";}}if(is_ajax()){ob_end_clean();exit;}}elseif(isset($_GET["variables"])){$Ig=isset($_GET["status"]);page_header($Ig?lang(107):lang(106));$Uh=($Ig?show_status():show_variables());if(!$Uh)echo"".lang(12)."\n";else{echo"
\n";foreach($Uh
+as$x=>$X){echo"","".h($x)."
","".nbsp($X);}echo"
\n";}}elseif(isset($_GET["script"])){header("Content-Type: text/javascript; charset=utf-8");if($_GET["script"]=="db"){$Qg=array("Data_length"=>0,"Index_length"=>0,"Data_free"=>0);foreach(table_status()as$C=>$R){json_row("Comment-$C",nbsp($R["Comment"]));if(!is_view($R)){foreach(array("Engine","Collation")as$x)json_row("$x-$C",nbsp($R[$x]));foreach($Qg+array("Auto_increment"=>0,"Rows"=>0)as$x=>$X){if($R[$x]!=""){$X=format_number($R[$x]);json_row("$x-$C",($x=="Rows"&&$X&&$R["Engine"]==($Fg=="pgsql"?"table":"InnoDB")?"~ $X":$X));if(isset($Qg[$x]))$Qg[$x]+=($R["Engine"]!="InnoDB"||$x!="Data_free"?$R[$x]:0);}elseif(array_key_exists($x,$R))json_row("$x-$C");}}}foreach($Qg
+as$x=>$X)json_row("sum-$x",format_number($X));json_row("");}elseif($_GET["script"]=="kill")$h->query("KILL ".number($_POST["kill"]));else{foreach(count_tables($b->databases())as$m=>$X){json_row("tables-$m",$X);json_row("size-$m",db_size($m));}json_row("");}exit;}else{$Zg=array_merge((array)$_POST["tables"],(array)$_POST["views"]);if($Zg&&!$n&&!$_POST["search"]){$I=true;$me="";if($w=="sql"&&count($_POST["tables"])>1&&($_POST["drop"]||$_POST["truncate"]||$_POST["copy"]))queries("SET foreign_key_checks = 0");if($_POST["truncate"]){if($_POST["tables"])$I=truncate_tables($_POST["tables"]);$me=lang(251);}elseif($_POST["move"]){$I=move_tables((array)$_POST["tables"],(array)$_POST["views"],$_POST["target"]);$me=lang(252);}elseif($_POST["copy"]){$I=copy_tables((array)$_POST["tables"],(array)$_POST["views"],$_POST["target"]);$me=lang(253);}elseif($_POST["drop"]){if($_POST["views"])$I=drop_views($_POST["views"]);if($I&&$_POST["tables"])$I=drop_tables($_POST["tables"]);$me=lang(254);}elseif($w!="sql"){$I=($w=="sqlite"?queries("VACUUM"):apply_queries("VACUUM".($_POST["optimize"]?"":" ANALYZE"),$_POST["tables"]));$me=lang(255);}elseif(!$_POST["tables"])$me=lang(9);elseif($I=queries(($_POST["optimize"]?"OPTIMIZE":($_POST["check"]?"CHECK":($_POST["repair"]?"REPAIR":"ANALYZE")))." TABLE ".implode(", ",array_map('idf_escape',$_POST["tables"])))){while($K=$I->fetch_assoc())$me.="".h($K["Table"])." : ".h($K["Msg_text"])." ";}queries_redirect(substr(ME,0,-1),$me,$I);}page_header(($_GET["ns"]==""?lang(35).": ".h(DB):lang(68).": ".h($_GET["ns"])),$n,true);if($b->homepage()){if($_GET["ns"]!==""){echo"".lang(256)." \n";$Yg=tables_list();if(!$Yg)echo"".lang(9)."\n";else{echo"
\n";if(support("table")){echo"".lang(257)." "," \n","
\n";if($_POST["search"]&&$_POST["query"]!="")search_tables();}echo"\n",' ';$Ub=doc_link(array('sql'=>'show-table-status.html'));echo''.lang(119),' '.lang(258).doc_link(array('sql'=>'storage-engines.html')),' '.lang(111).doc_link(array('sql'=>'charset-mysql.html')),' '.lang(259).$Ub,' '.lang(260).$Ub,' '.lang(261).$Ub,' '.lang(56).doc_link(array('sql'=>'example-auto-increment.html')),' '.lang(262).$Ub,(support("comment")?' '.lang(96).$Ub:'')," \n";$S=0;foreach($Yg
+as$C=>$U){$Xh=($U!==null&&!preg_match('~table~i',$U));echo''.checkbox(($Xh?"views[]":"tables[]"),$C,in_array($C,$Zg,true),"","formUncheck('check-all');"),' '.(support("table")||support("indexes")?''.h($C).' ':h($C));if($Xh){echo' '.(preg_match('~materialized~i',$U)?lang(263):lang(118)).' ','? ';}else{foreach(array("Engine"=>array(),"Collation"=>array(),"Data_length"=>array("create",lang(41)),"Index_length"=>array("indexes",lang(122)),"Data_free"=>array("edit",lang(42)),"Auto_increment"=>array("auto_increment=1&create",lang(41)),"Rows"=>array("select",lang(38)),)as$x=>$_){$jd=" id='$x-".h($C)."'";echo($_?"".(support("table")||$x=="Rows"||(support("indexes")&&$x!="Data_length")?"? ":"? "):" ");}$S++;}echo(support("comment")?" ".lang(235,count($Yg))," ".nbsp($w=="sql"?$h->result("SELECT @@storage_engine"):"")," ".nbsp(db_collation(DB,collations()));foreach(array("Data_length","Index_length","Data_free")as$x)echo" ";echo"
\n";if(!information_schema(DB)){$Rh=" ";$Te=" ";echo"".lang(115)." \n";}echo" \n","\n";}echo''.lang(66)." \n",(support("view")?''.lang(192)." \n":""),(support("materializedview")?''.lang(273)." \n":"");if(support("routine")){echo"
".lang(132)." \n";$kg=routines();if($kg){echo"\n";}echo''.(support("procedure")?''.lang(208).' ':'').''.lang(207)." \n";}if(support("sequence")){echo"
".lang(274)." \n";$wg=get_vals("SELECT sequence_name FROM information_schema.sequences WHERE sequence_schema = current_schema() ORDER BY sequence_name");if($wg){echo"\n","".lang(170)." \n";odd('');foreach($wg
+as$X)echo"".h($X)." \n";echo"
\n";}echo"".lang(214)." \n";}if(support("type")){echo"
".lang(23)." \n";$Ph=types();if($Ph){echo"\n","".lang(170)." \n";odd('');foreach($Ph
+as$X)echo"".h($X)." \n";echo"
\n";}echo"".lang(218)." \n";}if(support("event")){echo"
".lang(133)." \n";$L=get_rows("SHOW EVENTS");if($L){echo"\n","".lang(170)." ".lang(275)." ".lang(198)." ".lang(199)." \n";foreach($L
+as$K){echo"","".h($K["Name"])," ".($K["Execute at"]?lang(276)." ".$K["Execute at"]:lang(200)." ".$K["Interval value"]." ".$K["Interval field"]." $K[Starts]")," $K[Ends]",' '.lang(125).' ';}echo"
\n";$tc=$h->result("SELECT @@event_scheduler");if($tc&&$tc!="ON")echo"event_scheduler
: ".h($tc)."\n";}echo'
'.lang(197)." \n";}if($Yg)echo"\n";}}}page_footer();
\ No newline at end of file
diff --git a/vendor/dg/adminer-custom/composer.json b/vendor/dg/adminer-custom/composer.json
new file mode 100755
index 0000000..91a6272
--- /dev/null
+++ b/vendor/dg/adminer-custom/composer.json
@@ -0,0 +1,5 @@
+{
+ "name": "dg/adminer-custom",
+ "description": "Customization for the best database management tool written in PHP, Adminer",
+ "type": "project"
+}
diff --git a/vendor/dg/adminer-custom/index.php b/vendor/dg/adminer-custom/index.php
new file mode 100755
index 0000000..9b4b46a
--- /dev/null
+++ b/vendor/dg/adminer-custom/index.php
@@ -0,0 +1,45 @@
+]*(href|src)=")(adminer\.css|static/.+)"#U', function($m) {
+ return $m[1] . '?file=' . urlencode($m[4]) . '"';
+ }, $s);
+ }, 4096);
+
+} elseif (preg_match('#^(default|adminer|static(/\w[\w.-]*)+)\.(\w+)\z#', $_GET['file'], $m)) {
+ if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
+ header('HTTP/1.1 304 Not Modified');
+ exit;
+ }
+
+ header('Expires: ' . gmdate('D, d M Y H:i:s', strtotime('1 month')) . ' GMT');
+ header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
+
+ $types = array('css' => 'text/css', 'js' => 'text/javascript', 'gif' => 'image/gif', 'png' => 'image/png');
+ if (isset($types[$m[3]])) {
+ header('Content-Type: ' . $types[$m[3]]);
+ }
+ @readfile(__DIR__ . '/' . $_GET['file']);
+ exit;
+}
+
+
+function adminer_object() {
+ include_once dirname(__FILE__) . '/plugins/plugin.php';
+
+ foreach (glob(dirname(__FILE__) . '/plugins/*.php') as $filename) {
+ include_once $filename;
+ }
+
+ $plugins = array(
+ new AdminerDisableJush,
+ new AdminerAutocomplete,
+ new AdminerSaveMenuPos,
+ new AdminerRemoteColor,
+ );
+
+ return new AdminerPlugin($plugins);
+}
+
+include dirname(__FILE__) . '/adminer.php';
diff --git a/vendor/dg/adminer-custom/plugins/autocomplete.php b/vendor/dg/adminer-custom/plugins/autocomplete.php
new file mode 100755
index 0000000..98ad357
--- /dev/null
+++ b/vendor/dg/adminer-custom/plugins/autocomplete.php
@@ -0,0 +1,34 @@
+ $foo) {
+ $suggests[] = "$table.$field";
+ }
+ }
+ ?>
+
+
+
+
+
+
+_findRootClass($class), 'Adminer')) { // can use interface since PHP 5
+ $plugins[$class] = new $class;
+ }
+ }
+ }
+ $this->plugins = $plugins;
+ // it is possible to use ReflectionObject in PHP 5 to find out which plugins defines which methods at once
+ }
+
+ function _callParent($function, $args) {
+ switch (count($args)) { // call_user_func_array(array('parent', $function), $args) works since PHP 5
+ case 0: return parent::$function();
+ case 1: return parent::$function($args[0]);
+ case 2: return parent::$function($args[0], $args[1]);
+ case 3: return parent::$function($args[0], $args[1], $args[2]);
+ case 4: return parent::$function($args[0], $args[1], $args[2], $args[3]);
+ case 5: return parent::$function($args[0], $args[1], $args[2], $args[3], $args[4]);
+ case 6: return parent::$function($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]);
+ default: trigger_error('Too many parameters.', E_USER_WARNING);
+ }
+ }
+
+ function _applyPlugin($function, $args) {
+ foreach ($this->plugins as $plugin) {
+ if (method_exists($plugin, $function)) {
+ switch (count($args)) { // call_user_func_array() doesn't work well with references
+ case 0: $return = $plugin->$function(); break;
+ case 1: $return = $plugin->$function($args[0]); break;
+ case 2: $return = $plugin->$function($args[0], $args[1]); break;
+ case 3: $return = $plugin->$function($args[0], $args[1], $args[2]); break;
+ case 4: $return = $plugin->$function($args[0], $args[1], $args[2], $args[3]); break;
+ case 5: $return = $plugin->$function($args[0], $args[1], $args[2], $args[3], $args[4]); break;
+ case 6: $return = $plugin->$function($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]); break;
+ default: trigger_error('Too many parameters.', E_USER_WARNING);
+ }
+ if ($return !== null) {
+ return $return;
+ }
+ }
+ }
+ return $this->_callParent($function, $args);
+ }
+
+ function _appendPlugin($function, $args) {
+ $return = $this->_callParent($function, $args);
+ foreach ($this->plugins as $plugin) {
+ if (method_exists($plugin, $function)) {
+ $return += call_user_func_array(array($plugin, $function), $args);
+ }
+ }
+ return $return;
+ }
+
+ // appendPlugin
+
+ function dumpFormat() {
+ $args = func_get_args();
+ return $this->_appendPlugin(__FUNCTION__, $args);
+ }
+
+ function dumpOutput() {
+ $args = func_get_args();
+ return $this->_appendPlugin(__FUNCTION__, $args);
+ }
+
+ function editFunctions() {
+ $args = func_get_args();
+ return $this->_appendPlugin(__FUNCTION__, $args);
+ }
+
+ // applyPlugin
+
+ function name() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function credentials() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function permanentLogin() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function database() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function databases() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function queryTimeout() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function headers() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function head() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function loginForm() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function login() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function tableName() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function fieldName() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectLinks() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function foreignKeys() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function backwardKeys() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function backwardKeysPrint() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectQuery() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function rowDescription() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function rowDescriptions() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectLink() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectVal() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function editVal() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectColumnsPrint() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectSearchPrint() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectOrderPrint() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectLimitPrint() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectLengthPrint() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectActionPrint() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectCommandPrint() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectImportPrint() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectEmailPrint() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectColumnsProcess() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectSearchProcess() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectOrderProcess() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectLimitProcess() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectLengthProcess() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectEmailProcess() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function selectQueryBuild() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function messageQuery() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function editInput() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function processInput() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function dumpDatabase() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function dumpTable() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function dumpData() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function dumpFilename() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function dumpHeaders() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function homepage() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function navigation() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function databasesPrint() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+ function tablesPrint() {
+ $args = func_get_args();
+ return $this->_applyPlugin(__FUNCTION__, $args);
+ }
+
+}
diff --git a/vendor/dg/adminer-custom/plugins/remoteColor.php b/vendor/dg/adminer-custom/plugins/remoteColor.php
new file mode 100755
index 0000000..919592f
--- /dev/null
+++ b/vendor/dg/adminer-custom/plugins/remoteColor.php
@@ -0,0 +1,18 @@
+document.documentElement.className+=" remote";';
+ }
+ }
+
+}
diff --git a/vendor/dg/adminer-custom/plugins/saveMenuPos.php b/vendor/dg/adminer-custom/plugins/saveMenuPos.php
new file mode 100755
index 0000000..098c0e9
--- /dev/null
+++ b/vendor/dg/adminer-custom/plugins/saveMenuPos.php
@@ -0,0 +1,37 @@
+
+
+= 0 && j < len ? [ this[j] ] : [] );
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: deletedIds.sort,
+ splice: deletedIds.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var src, copyIsArray, copy, name, options, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+
+ // skip the boolean and the target
+ target = arguments[ i ] || {};
+ i++;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( i === length ) {
+ target = this;
+ i--;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ // Unique for each copy of jQuery on the page
+ expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+ // Assume jQuery is ready without the ready module
+ isReady: true,
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ noop: function() {},
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ isWindow: function( obj ) {
+ /* jshint eqeqeq: false */
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ // parseFloat NaNs numeric-cast false positives (null|true|false|"")
+ // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+ // subtraction forces infinities to NaN
+ // adding 1 corrects loss of precision from parseFloat (#15100)
+ return !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0;
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ isPlainObject: function( obj ) {
+ var key;
+
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ try {
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !hasOwn.call(obj, "constructor") &&
+ !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+ } catch ( e ) {
+ // IE8,9 Will throw exceptions on certain host objects #9897
+ return false;
+ }
+
+ // Support: IE<9
+ // Handle iteration over inherited properties before own properties.
+ if ( support.ownLast ) {
+ for ( key in obj ) {
+ return hasOwn.call( obj, key );
+ }
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+ for ( key in obj ) {}
+
+ return key === undefined || hasOwn.call( obj, key );
+ },
+
+ type: function( obj ) {
+ if ( obj == null ) {
+ return obj + "";
+ }
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ toString.call(obj) ] || "object" :
+ typeof obj;
+ },
+
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && jQuery.trim( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+ },
+
+ // args is for internal usage only
+ each: function( obj, callback, args ) {
+ var value,
+ i = 0,
+ length = obj.length,
+ isArray = isArraylike( obj );
+
+ if ( args ) {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.apply( obj[ i ], args );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ value = callback.call( obj[ i ], i, obj[ i ] );
+
+ if ( value === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // Support: Android<4.1, IE<9
+ trim: function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArraylike( Object(arr) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ var len;
+
+ if ( arr ) {
+ if ( indexOf ) {
+ return indexOf.call( arr, elem, i );
+ }
+
+ len = arr.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in arr && arr[ i ] === elem ) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var len = +second.length,
+ j = 0,
+ i = first.length;
+
+ while ( j < len ) {
+ first[ i++ ] = second[ j++ ];
+ }
+
+ // Support: IE<9
+ // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
+ if ( len !== len ) {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, invert ) {
+ var callbackInverse,
+ matches = [],
+ i = 0,
+ length = elems.length,
+ callbackExpect = !invert;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ callbackInverse = !callback( elems[ i ], i );
+ if ( callbackInverse !== callbackExpect ) {
+ matches.push( elems[ i ] );
+ }
+ }
+
+ return matches;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value,
+ i = 0,
+ length = elems.length,
+ isArray = isArraylike( elems ),
+ ret = [];
+
+ // Go through the array, translating each of the items to their new values
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ var args, proxy, tmp;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ now: function() {
+ return +( new Date() );
+ },
+
+ // jQuery.support is not used in Core but other projects attach their
+ // properties to it so it needs to exist.
+ support: support
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+function isArraylike( obj ) {
+ var length = obj.length,
+ type = jQuery.type( obj );
+
+ if ( type === "function" || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ if ( obj.nodeType === 1 && length ) {
+ return true;
+ }
+
+ return type === "array" || length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v2.2.0-pre
+ * http://sizzlejs.com/
+ *
+ * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2014-12-16
+ */
+(function( window ) {
+
+var i,
+ support,
+ Expr,
+ getText,
+ isXML,
+ tokenize,
+ compile,
+ select,
+ outermostContext,
+ sortInput,
+ hasDuplicate,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + 1 * new Date(),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ },
+
+ // General-purpose constants
+ MAX_NEGATIVE = 1 << 31,
+
+ // Instance methods
+ hasOwn = ({}).hasOwnProperty,
+ arr = [],
+ pop = arr.pop,
+ push_native = arr.push,
+ push = arr.push,
+ slice = arr.slice,
+ // Use a stripped-down indexOf as it's faster than native
+ // http://jsperf.com/thor-indexof-vs-for/5
+ indexOf = function( list, elem ) {
+ var i = 0,
+ len = list.length;
+ for ( ; i < len; i++ ) {
+ if ( list[i] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
+
+ // Regular expressions
+
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+ // http://www.w3.org/TR/css3-syntax/#characters
+ characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
+
+ // Loosely modeled on CSS identifier characters
+ // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = characterEncoding.replace( "w", "w#" ),
+
+ // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
+ // Operator (capture 2)
+ "*([*^$|!~]?=)" + whitespace +
+ // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
+ "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
+ "*\\]",
+
+ pseudos = ":(" + characterEncoding + ")(?:\\((" +
+ // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+ // 1. quoted (capture 3; capture 4 or capture 5)
+ "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+ // 2. simple (capture 6)
+ "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+ // 3. anything else (capture 2)
+ ".*" +
+ ")\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rwhitespace = new RegExp( whitespace + "+", "g" ),
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
+
+ rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
+
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
+ whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+ },
+
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rsibling = /[+~]/,
+ rescape = /'|\\/g,
+
+ // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
+ funescape = function( _, escaped, escapedWhitespace ) {
+ var high = "0x" + escaped - 0x10000;
+ // NaN means non-codepoint
+ // Support: Firefox<24
+ // Workaround erroneous numeric interpretation of +"0x"
+ return high !== high || escapedWhitespace ?
+ escaped :
+ high < 0 ?
+ // BMP codepoint
+ String.fromCharCode( high + 0x10000 ) :
+ // Supplemental Plane codepoint (surrogate pair)
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ },
+
+ // Used for iframes
+ // See setDocument()
+ // Removing the function wrapper causes a "Permission Denied"
+ // error in IE
+ unloadHandler = function() {
+ setDocument();
+ };
+
+// Optimize for push.apply( _, NodeList )
+try {
+ push.apply(
+ (arr = slice.call( preferredDoc.childNodes )),
+ preferredDoc.childNodes
+ );
+ // Support: Android<4.0
+ // Detect silently failing push.apply
+ arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+ push = { apply: arr.length ?
+
+ // Leverage slice if possible
+ function( target, els ) {
+ push_native.apply( target, slice.call(els) );
+ } :
+
+ // Support: IE<9
+ // Otherwise append directly
+ function( target, els ) {
+ var j = target.length,
+ i = 0;
+ // Can't trust NodeList.length
+ while ( (target[j++] = els[i++]) ) {}
+ target.length = j - 1;
+ }
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ var match, elem, m, nodeType,
+ // QSA vars
+ i, groups, old, nid, newContext, newSelector;
+
+ if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
+ setDocument( context );
+ }
+
+ context = context || document;
+ results = results || [];
+ nodeType = context.nodeType;
+
+ if ( typeof selector !== "string" || !selector ||
+ nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
+
+ return results;
+ }
+
+ if ( !seed && documentIsHTML ) {
+
+ // Try to shortcut find operations when possible (e.g., not under DocumentFragment)
+ if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
+ // Speed-up: Sizzle("#ID")
+ if ( (m = match[1]) ) {
+ if ( nodeType === 9 ) {
+ elem = context.getElementById( m );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document (jQuery #6963)
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } else {
+ // Context is not a document
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+ contains( context, elem ) && elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Speed-up: Sizzle("TAG")
+ } else if ( match[2] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( (m = match[3]) && support.getElementsByClassName ) {
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
+ }
+
+ // QSA path
+ if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
+ nid = old = expando;
+ newContext = context;
+ newSelector = nodeType !== 1 && selector;
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ groups = tokenize( selector );
+
+ if ( (old = context.getAttribute("id")) ) {
+ nid = old.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", nid );
+ }
+ nid = "[id='" + nid + "'] ";
+
+ i = groups.length;
+ while ( i-- ) {
+ groups[i] = nid + toSelector( groups[i] );
+ }
+ newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
+ newSelector = groups.join(",");
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch(qsaError) {
+ } finally {
+ if ( !old ) {
+ context.removeAttribute("id");
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+function createCache() {
+ var keys = [];
+
+ function cache( key, value ) {
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if ( keys.push( key + " " ) > Expr.cacheLength ) {
+ // Only keep the most recent entries
+ delete cache[ keys.shift() ];
+ }
+ return (cache[ key + " " ] = value);
+ }
+ return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+ fn[ expando ] = true;
+ return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created div and expects a boolean result
+ */
+function assert( fn ) {
+ var div = document.createElement("div");
+
+ try {
+ return !!fn( div );
+ } catch (e) {
+ return false;
+ } finally {
+ // Remove from its parent by default
+ if ( div.parentNode ) {
+ div.parentNode.removeChild( div );
+ }
+ // release memory in IE
+ div = null;
+ }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+ var arr = attrs.split("|"),
+ i = attrs.length;
+
+ while ( i-- ) {
+ Expr.attrHandle[ arr[i] ] = handler;
+ }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+ var cur = b && a,
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+ ( ~b.sourceIndex || MAX_NEGATIVE ) -
+ ( ~a.sourceIndex || MAX_NEGATIVE );
+
+ // Use IE sourceIndex if available on both nodes
+ if ( diff ) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if ( cur ) {
+ while ( (cur = cur.nextSibling) ) {
+ if ( cur === b ) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+ return markFunction(function( argument ) {
+ argument = +argument;
+ return markFunction(function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ (j = matchIndexes[i]) ] ) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
+}
+
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+ return context && typeof context.getElementsByTagName !== "undefined" && context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+ var hasCompare, parent,
+ doc = node ? node.ownerDocument || node : preferredDoc;
+
+ // If no document and documentElement is available, return
+ if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Set our document
+ document = doc;
+ docElem = doc.documentElement;
+ parent = doc.defaultView;
+
+ // Support: IE>8
+ // If iframe document is assigned to "document" variable and if iframe has been reloaded,
+ // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
+ // IE6-8 do not support the defaultView property so parent will be undefined
+ if ( parent && parent !== parent.top ) {
+ // IE11 does not have attachEvent, so all must suffer
+ if ( parent.addEventListener ) {
+ parent.addEventListener( "unload", unloadHandler, false );
+ } else if ( parent.attachEvent ) {
+ parent.attachEvent( "onunload", unloadHandler );
+ }
+ }
+
+ /* Support tests
+ ---------------------------------------------------------------------- */
+ documentIsHTML = !isXML( doc );
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties
+ // (excepting IE8 booleans)
+ support.attributes = assert(function( div ) {
+ div.className = "i";
+ return !div.getAttribute("className");
+ });
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert(function( div ) {
+ div.appendChild( doc.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ });
+
+ // Support: IE<9
+ support.getElementsByClassName = rnative.test( doc.getElementsByClassName );
+
+ // Support: IE<10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert(function( div ) {
+ docElem.appendChild( div ).id = expando;
+ return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
+ });
+
+ // ID find and filter
+ if ( support.getById ) {
+ Expr.find["ID"] = function( id, context ) {
+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+ var m = context.getElementById( id );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [ m ] : [];
+ }
+ };
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ return elem.getAttribute("id") === attrId;
+ };
+ };
+ } else {
+ // Support: IE6/7
+ // getElementById is not reliable as a find shortcut
+ delete Expr.find["ID"];
+
+ Expr.filter["ID"] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+ return node && node.value === attrId;
+ };
+ };
+ }
+
+ // Tag
+ Expr.find["TAG"] = support.getElementsByTagName ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( tag );
+
+ // DocumentFragment nodes don't have gEBTN
+ } else if ( support.qsa ) {
+ return context.querySelectorAll( tag );
+ }
+ } :
+
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+ // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
+ results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Class
+ Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
+ if ( documentIsHTML ) {
+ return context.getElementsByClassName( className );
+ }
+ };
+
+ /* QSA/matchesSelector
+ ---------------------------------------------------------------------- */
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21)
+ // We allow this because of a bug in IE8/9 that throws an error
+ // whenever `document.activeElement` is accessed on an iframe
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
+ // See http://bugs.jquery.com/ticket/13378
+ rbuggyQSA = [];
+
+ if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function( div ) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explicitly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ docElem.appendChild( div ).innerHTML = " " +
+ "" +
+ " ";
+
+ // Support: IE8, Opera 11-12.16
+ // Nothing should be selected when empty strings follow ^= or $= or *=
+ // The test attribute must be unknown in Opera but "safe" for WinRT
+ // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+ if ( div.querySelectorAll("[msallowcapture^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+ }
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
+
+ // Support: Chrome<29, Android<4.2+, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.7+
+ if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+ rbuggyQSA.push("~=");
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":checked").length ) {
+ rbuggyQSA.push(":checked");
+ }
+
+ // Support: Safari 8+, iOS 8+
+ // https://bugs.webkit.org/show_bug.cgi?id=136851
+ // In-page `selector#id sibing-combinator selector` fails
+ if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) {
+ rbuggyQSA.push(".#.+[+~]");
+ }
+ });
+
+ assert(function( div ) {
+ // Support: Windows 8 Native Apps
+ // The type and name attributes are restricted during .innerHTML assignment
+ var input = doc.createElement("input");
+ input.setAttribute( "type", "hidden" );
+ div.appendChild( input ).setAttribute( "name", "D" );
+
+ // Support: IE8
+ // Enforce case-sensitivity of name attribute
+ if ( div.querySelectorAll("[name=d]").length ) {
+ rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if ( !div.querySelectorAll(":enabled").length ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ div.querySelectorAll("*,:x");
+ rbuggyQSA.push(",.*:");
+ });
+ }
+
+ if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
+ docElem.webkitMatchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector) )) ) {
+
+ assert(function( div ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call( div, "div" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( div, "[s!='']:x" );
+ rbuggyMatches.push( "!=", pseudos );
+ });
+ }
+
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
+
+ /* Contains
+ ---------------------------------------------------------------------- */
+ hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+ // Element contains another
+ // Purposefully does not implement inclusive descendent
+ // As in, an element does not contain itself
+ contains = hasCompare || rnative.test( docElem.contains ) ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ));
+ } :
+ function( a, b ) {
+ if ( b ) {
+ while ( (b = b.parentNode) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ /* Sorting
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = hasCompare ?
+ function( a, b ) {
+
+ // Flag for duplicate removal
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ // Sort on method existence if only one input has compareDocumentPosition
+ var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+ if ( compare ) {
+ return compare;
+ }
+
+ // Calculate position if both inputs belong to the same document
+ compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
+ a.compareDocumentPosition( b ) :
+
+ // Otherwise we know they are disconnected
+ 1;
+
+ // Disconnected nodes
+ if ( compare & 1 ||
+ (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
+
+ // Choose the first element that is related to our preferred document
+ if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
+ return -1;
+ }
+ if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ } :
+ function( a, b ) {
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Parentless nodes are either documents or disconnected
+ if ( !aup || !bup ) {
+ return a === doc ? -1 :
+ b === doc ? 1 :
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ( (cur = cur.parentNode) ) {
+ ap.unshift( cur );
+ }
+ cur = b;
+ while ( (cur = cur.parentNode) ) {
+ bp.unshift( cur );
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while ( ap[i] === bp[i] ) {
+ i++;
+ }
+
+ return i ?
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck( ap[i], bp[i] ) :
+
+ // Otherwise nodes in our document sort first
+ ap[i] === preferredDoc ? -1 :
+ bp[i] === preferredDoc ? 1 :
+ 0;
+ };
+
+ return doc;
+};
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace( rattributeQuotes, "='$1']" );
+
+ if ( support.matchesSelector && documentIsHTML &&
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
+
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || support.disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch (e) {}
+ }
+
+ return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+ // Set document vars if needed
+ if ( ( context.ownerDocument || context ) !== document ) {
+ setDocument( context );
+ }
+ return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+ // Set document vars if needed
+ if ( ( elem.ownerDocument || elem ) !== document ) {
+ setDocument( elem );
+ }
+
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+ fn( elem, name, !documentIsHTML ) :
+ undefined;
+
+ return val !== undefined ?
+ val :
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute( name ) :
+ (val = elem.getAttributeNode(name)) && val.specified ?
+ val.value :
+ null;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ j = 0,
+ i = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ sortInput = !support.sortStable && results.slice( 0 );
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ while ( (elem = results[i++]) ) {
+ if ( elem === results[ i ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ // Clear input after sorting to release objects
+ // See https://github.com/jquery/sizzle/pull/225
+ sortInput = null;
+
+ return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+ // If no nodeType, this is expected to be an array
+ while ( (node = elem[i++]) ) {
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (jQuery #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ attrHandle: {},
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[1] = match[1].replace( runescape, funescape );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
+
+ if ( match[2] === "~=" ) {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if ( match[1].slice( 0, 3 ) === "nth" ) {
+ // nth-* requires argument
+ if ( !match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
+ match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[3] ) {
+ Sizzle.error( match[0] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var excess,
+ unquoted = !match[6] && match[2];
+
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[3] ) {
+ match[2] = match[4] || match[5] || "";
+
+ // Strip excess characters from unquoted arguments
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize( unquoted, true )) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+ // excess is a negative index
+ match[0] = match[0].slice( 0, excess );
+ match[2] = unquoted.slice( 0, excess );
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+
+ "TAG": function( nodeNameSelector ) {
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ return nodeNameSelector === "*" ?
+ function() { return true; } :
+ function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ className + " " ];
+
+ return pattern ||
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+ classCache( className, function( elem ) {
+ return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
+ });
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.slice( -check.length ) === check :
+ operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function( type, what, argument, first, last ) {
+ var simple = type.slice( 0, 3 ) !== "nth",
+ forward = type.slice( -4 ) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function( elem ) {
+ return !!elem.parentNode;
+ } :
+
+ function( elem, context, xml ) {
+ var cache, outerCache, node, diff, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType;
+
+ if ( parent ) {
+
+ // :(first|last|only)-(child|of-type)
+ if ( simple ) {
+ while ( dir ) {
+ node = elem;
+ while ( (node = node[ dir ]) ) {
+ if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
+ return false;
+ }
+ }
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
+ }
+
+ start = [ forward ? parent.firstChild : parent.lastChild ];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if ( forward && useCache ) {
+ // Seek `elem` from a previously-cached index
+ outerCache = parent[ expando ] || (parent[ expando ] = {});
+ cache = outerCache[ type ] || [];
+ nodeIndex = cache[0] === dirruns && cache[1];
+ diff = cache[0] === dirruns && cache[2];
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+
+ // Fallback to seeking `elem` from the start
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ // When found, cache indexes on `parent` and break
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
+ outerCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ // Use previously-cached element index if available
+ } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
+ diff = cache[1];
+
+ // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ } else {
+ // Use the same loop as above to seek `elem` from the start
+ while ( (node = ++nodeIndex && node && node[ dir ] ||
+ (diff = nodeIndex = 0) || start.pop()) ) {
+
+ if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction(function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf( seed, matched[i] );
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
+ }
+ }) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ // Potentially complex pseudos
+ "not": markFunction(function( selector ) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction(function( seed, matches, context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( (elem = unmatched[i]) ) {
+ seed[i] = !(matches[i] = elem);
+ }
+ }
+ }) :
+ function( elem, context, xml ) {
+ input[0] = elem;
+ matcher( input, null, xml, results );
+ // Don't keep the element (issue #299)
+ input[0] = null;
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ text = text.replace( runescape, funescape );
+ return function( elem ) {
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+ };
+ }),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction( function( lang ) {
+ // lang value must be a valid identifier
+ if ( !ridentifier.test(lang || "") ) {
+ Sizzle.error( "unsupported lang: " + lang );
+ }
+ lang = lang.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ var elemLang;
+ do {
+ if ( (elemLang = documentIsHTML ?
+ elem.lang :
+ elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+ }
+ } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
+ return false;
+ };
+ }),
+
+ // Miscellaneous
+ "target": function( elem ) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice( 1 ) === elem.id;
+ },
+
+ "root": function( elem ) {
+ return elem === docElem;
+ },
+
+ "focus": function( elem ) {
+ return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ // Boolean properties
+ "enabled": function( elem ) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function( elem ) {
+ return elem.disabled === true;
+ },
+
+ "checked": function( elem ) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function( elem ) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+ // but not by others (comment: 8; processing instruction: 7; etc.)
+ // nodeType < 6 works because attributes (2) do not appear as children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeType < 6 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos["empty"]( elem );
+ },
+
+ // Element/input types
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function( elem ) {
+ var attr;
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+
+ // Support: IE<8
+ // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo(function() {
+ return [ 0 ];
+ }),
+
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
+ return [ length - 1 ];
+ }),
+
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ }),
+
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 0;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
+ var i = 1;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ })
+ }
+};
+
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+ Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+ Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
+ if ( match ) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[0].length ) || soFar;
+ }
+ groups.push( (tokens = []) );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( (match = rcombinators.exec( soFar )) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ // Cast descendant combinators to space
+ type: match[0].replace( rtrim, " " )
+ });
+ soFar = soFar.slice( matched.length );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+ (match = preFilters[ type ]( match ))) ) {
+ matched = match.shift();
+ tokens.push({
+ value: matched,
+ type: type,
+ matches: match
+ });
+ soFar = soFar.slice( matched.length );
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+};
+
+function toSelector( tokens ) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for ( ; i < len; i++ ) {
+ selector += tokens[i].value;
+ }
+ return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ checkNonElements = base && dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ var oldCache, outerCache,
+ newCache = [ dirruns, doneName ];
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if ( xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ if ( matcher( elem, context, xml ) ) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ( (elem = elem[ dir ]) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ outerCache = elem[ expando ] || (elem[ expando ] = {});
+ if ( (oldCache = outerCache[ dir ]) &&
+ oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+ // Assign to newCache so results back-propagate to previous elements
+ return (newCache[ 2 ] = oldCache[ 2 ]);
+ } else {
+ // Reuse newcache so results back-propagate to previous elements
+ outerCache[ dir ] = newCache;
+
+ // A match means we're done; a fail means we have to keep checking
+ if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[i]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+}
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( (elem = unmatched[i]) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction(function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( (elem = temp[i]) ) {
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) ) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( (matcherIn[i] = elem) );
+ }
+ }
+ postFinder( null, (matcherOut = []), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ });
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[0].type ],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ // Avoid hanging onto element (issue #299)
+ checkContext = null;
+ return ret;
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+ matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
+ } else {
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[j].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && toSelector(
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
+ ).replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+ j < len && toSelector( tokens )
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, outermost ) {
+ var elem, j, matcher,
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ setMatched = [],
+ contextBackup = outermostContext,
+ // We must always have either seed elements or outermost context
+ elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
+ len = elems.length;
+
+ if ( outermost ) {
+ outermostContext = context !== document && context;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
+ // Support: IE<9, Safari
+ // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id
+ for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+ while ( (matcher = elementMatchers[j++]) ) {
+ if ( matcher( elem, context, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+ // They will have gone through all possible matchers
+ if ( (elem = !matcher && elem) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if ( bySet && i !== matchedCount ) {
+ j = 0;
+ while ( (matcher = setMatchers[j++]) ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !(unmatched[i] || setMatched[i]) ) {
+ setMatched[i] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ selector + " " ];
+
+ if ( !cached ) {
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !match ) {
+ match = tokenize( selector );
+ }
+ i = match.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( match[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+
+ // Save selector and tokenization
+ cached.selector = selector;
+ }
+ return cached;
+};
+
+/**
+ * A low-level selection function that works with Sizzle's compiled
+ * selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ * selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+select = Sizzle.select = function( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ compiled = typeof selector === "function" && selector,
+ match = !seed && tokenize( (selector = compiled.selector || selector) );
+
+ results = results || [];
+
+ // Try to minimize operations if there is no seed and only one group
+ if ( match.length === 1 ) {
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice( 0 );
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ support.getById && context.nodeType === 9 && documentIsHTML &&
+ Expr.relative[ tokens[1].type ] ) {
+
+ context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
+ if ( !context ) {
+ return results;
+
+ // Precompiled matchers will still verify ancestry, so step up a level
+ } else if ( compiled ) {
+ context = context.parentNode;
+ }
+
+ selector = selector.slice( tokens.shift().value.length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
+ while ( i-- ) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ (type = token.type) ] ) {
+ break;
+ }
+ if ( (find = Expr.find[ type ]) ) {
+ // Search, expanding context for leading sibling combinators
+ if ( (seed = find(
+ token.matches[0].replace( runescape, funescape ),
+ rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
+ )) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && toSelector( tokens );
+ if ( !selector ) {
+ push.apply( results, seed );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function if one is not provided
+ // Provide `match` to avoid retokenization if we modified the selector above
+ ( compiled || compile( selector, match ) )(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ rsibling.test( selector ) && testContext( context.parentNode ) || context
+ );
+ return results;
+};
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
+
+// Support: Chrome 14-35+
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert(function( div1 ) {
+ // Should return 1, but returns 4 (following)
+ return div1.compareDocumentPosition( document.createElement("div") ) & 1;
+});
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert(function( div ) {
+ div.innerHTML = " ";
+ return div.firstChild.getAttribute("href") === "#" ;
+}) ) {
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+ }
+ });
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert(function( div ) {
+ div.innerHTML = " ";
+ div.firstChild.setAttribute( "value", "" );
+ return div.firstChild.getAttribute( "value" ) === "";
+}) ) {
+ addHandle( "value", function( elem, name, isXML ) {
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+ return elem.defaultValue;
+ }
+ });
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert(function( div ) {
+ return div.getAttribute("disabled") == null;
+}) ) {
+ addHandle( booleans, function( elem, name, isXML ) {
+ var val;
+ if ( !isXML ) {
+ return elem[ name ] === true ? name.toLowerCase() :
+ (val = elem.getAttributeNode( name )) && val.specified ?
+ val.value :
+ null;
+ }
+ });
+}
+
+return Sizzle;
+
+})( window );
+
+
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.pseudos;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+
+var rneedsContext = jQuery.expr.match.needsContext;
+
+var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
+
+
+
+var risSimple = /^.[^:#\[\.,]*$/;
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep( elements, function( elem, i ) {
+ /* jshint -W018 */
+ return !!qualifier.call( elem, i, elem ) !== not;
+ });
+
+ }
+
+ if ( qualifier.nodeType ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( elem === qualifier ) !== not;
+ });
+
+ }
+
+ if ( typeof qualifier === "string" ) {
+ if ( risSimple.test( qualifier ) ) {
+ return jQuery.filter( qualifier, elements, not );
+ }
+
+ qualifier = jQuery.filter( qualifier, elements );
+ }
+
+ return jQuery.grep( elements, function( elem ) {
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
+ });
+}
+
+jQuery.filter = function( expr, elems, not ) {
+ var elem = elems[ 0 ];
+
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 && elem.nodeType === 1 ?
+ jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
+ jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+ return elem.nodeType === 1;
+ }));
+};
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var i,
+ ret = [],
+ self = this,
+ len = self.length;
+
+ if ( typeof selector !== "string" ) {
+ return this.pushStack( jQuery( selector ).filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ }) );
+ }
+
+ for ( i = 0; i < len; i++ ) {
+ jQuery.find( selector, self[ i ], ret );
+ }
+
+ // Needed because $( selector, context ) becomes $( context ).find( selector )
+ ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
+ ret.selector = this.selector ? this.selector + " " + selector : selector;
+ return ret;
+ },
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], false) );
+ },
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector || [], true) );
+ },
+ is: function( selector ) {
+ return !!winnow(
+ this,
+
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ typeof selector === "string" && rneedsContext.test( selector ) ?
+ jQuery( selector ) :
+ selector || [],
+ false
+ ).length;
+ }
+});
+
+
+// Initialize a jQuery object
+
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+ // Use the correct document accordingly with window argument (sandbox)
+ document = window.document,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
+
+ init = jQuery.fn.init = function( selector, context ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+
+ // scripts is true for back-compat
+ // Intentionally let the error be thrown if parseHTML is not present
+ jQuery.merge( this, jQuery.parseHTML(
+ match[1],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+ // Properties of context are called as methods if possible
+ if ( jQuery.isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return typeof rootjQuery.ready !== "undefined" ?
+ rootjQuery.ready( selector ) :
+ // Execute immediately if ready is not present
+ selector( jQuery );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ };
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.extend({
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ cur = elem[ dir ];
+
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+ if ( cur.nodeType === 1 ) {
+ matched.push( cur );
+ }
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ r.push( n );
+ }
+ }
+
+ return r;
+ }
+});
+
+jQuery.fn.extend({
+ has: function( target ) {
+ var i,
+ targets = jQuery( target, this ),
+ len = targets.length;
+
+ return this.filter(function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ matched = [],
+ pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( ; i < l; i++ ) {
+ for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
+ // Always skip document fragments
+ if ( cur.nodeType < 11 && (pos ?
+ pos.index(cur) > -1 :
+
+ // Don't pass non-elements to Sizzle
+ cur.nodeType === 1 &&
+ jQuery.find.matchesSelector(cur, selectors)) ) {
+
+ matched.push( cur );
+ break;
+ }
+ }
+ }
+
+ return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
+ }
+
+ // index in selector
+ if ( typeof elem === "string" ) {
+ return jQuery.inArray( this[0], jQuery( elem ) );
+ }
+
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[0] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ return this.pushStack(
+ jQuery.unique(
+ jQuery.merge( this.get(), jQuery( selector, context ) )
+ )
+ );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter(selector)
+ );
+ }
+});
+
+function sibling( cur, dir ) {
+ do {
+ cur = cur[ dir ];
+ } while ( cur && cur.nodeType !== 1 );
+
+ return cur;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until );
+
+ if ( name.slice( -5 ) !== "Until" ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ if ( this.length > 1 ) {
+ // Remove duplicates
+ if ( !guaranteedUnique[ name ] ) {
+ ret = jQuery.unique( ret );
+ }
+
+ // Reverse order for parents* and prev-derivatives
+ if ( rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+ }
+
+ return this.pushStack( ret );
+ };
+});
+var rnotwhite = (/\S+/g);
+
+
+
+// String to Object options format cache
+var optionsCache = {};
+
+// Convert String-formatted options into Object-formatted ones and store in cache
+function createOptions( options ) {
+ var object = optionsCache[ options ] = {};
+ jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ });
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ ( optionsCache[ options ] || createOptions( options ) ) :
+ jQuery.extend( {}, options );
+
+ var // Flag to know if list is currently firing
+ firing,
+ // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = !options.once && [],
+ // Fire callbacks
+ fire = function( data ) {
+ memory = options.memory && data;
+ fired = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ firing = true;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
+ memory = false; // To prevent further calls using add
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( stack ) {
+ if ( stack.length ) {
+ fire( stack.shift() );
+ }
+ } else if ( memory ) {
+ list = [];
+ } else {
+ self.disable();
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ // First, we save the current length
+ var start = list.length;
+ (function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
+ // Inspect recursively
+ add( arg );
+ }
+ });
+ })( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away
+ } else if ( memory ) {
+ firingStart = start;
+ fire( memory );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+ // Handle firing indexes
+ if ( firing ) {
+ if ( index <= firingLength ) {
+ firingLength--;
+ }
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ });
+ }
+ return this;
+ },
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ firingLength = 0;
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( list && ( !fired || stack ) ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ if ( firing ) {
+ stack.push( args );
+ } else {
+ fire( args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+
+
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var tuples = [
+ // action, add listener, listener list, final state
+ [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
+ [ "notify", "progress", jQuery.Callbacks("memory") ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ then: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( tuples, function( i, tuple ) {
+ var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
+ // deferred[ done | fail | progress ] for forwarding actions to newDefer
+ deferred[ tuple[1] ](function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise()
+ .done( newDefer.resolve )
+ .fail( newDefer.reject )
+ .progress( newDefer.notify );
+ } else {
+ newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
+ }
+ });
+ });
+ fns = null;
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Keep pipe for back-compat
+ promise.pipe = promise.then;
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 3 ];
+
+ // promise[ done | fail | progress ] = list.add
+ promise[ tuple[1] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(function() {
+ // state = [ resolved | rejected ]
+ state = stateString;
+
+ // [ reject_list | resolve_list ].disable; progress_list.lock
+ }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
+ }
+
+ // deferred[ resolve | reject | notify ]
+ deferred[ tuple[0] ] = function() {
+ deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
+ return this;
+ };
+ deferred[ tuple[0] + "With" ] = list.fireWith;
+ });
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( subordinate /* , ..., subordinateN */ ) {
+ var i = 0,
+ resolveValues = slice.call( arguments ),
+ length = resolveValues.length,
+
+ // the count of uncompleted subordinates
+ remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
+
+ // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
+ deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
+
+ // Update function for both resolve and progress values
+ updateFunc = function( i, contexts, values ) {
+ return function( value ) {
+ contexts[ i ] = this;
+ values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+ if ( values === progressValues ) {
+ deferred.notifyWith( contexts, values );
+
+ } else if ( !(--remaining) ) {
+ deferred.resolveWith( contexts, values );
+ }
+ };
+ },
+
+ progressValues, progressContexts, resolveContexts;
+
+ // add listeners to Deferred subordinates; treat others as resolved
+ if ( length > 1 ) {
+ progressValues = new Array( length );
+ progressContexts = new Array( length );
+ resolveContexts = new Array( length );
+ for ( ; i < length; i++ ) {
+ if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
+ resolveValues[ i ].promise()
+ .done( updateFunc( i, resolveContexts, resolveValues ) )
+ .fail( deferred.reject )
+ .progress( updateFunc( i, progressContexts, progressValues ) );
+ } else {
+ --remaining;
+ }
+ }
+ }
+
+ // if we're not waiting on anything, resolve the master
+ if ( !remaining ) {
+ deferred.resolveWith( resolveContexts, resolveValues );
+ }
+
+ return deferred.promise();
+ }
+});
+
+
+// The deferred used on DOM ready
+var readyList;
+
+jQuery.fn.ready = function( fn ) {
+ // Add the callback
+ jQuery.ready.promise().done( fn );
+
+ return this;
+};
+
+jQuery.extend({
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.triggerHandler ) {
+ jQuery( document ).triggerHandler( "ready" );
+ jQuery( document ).off( "ready" );
+ }
+ }
+});
+
+/**
+ * Clean-up method for dom ready events
+ */
+function detach() {
+ if ( document.addEventListener ) {
+ document.removeEventListener( "DOMContentLoaded", completed, false );
+ window.removeEventListener( "load", completed, false );
+
+ } else {
+ document.detachEvent( "onreadystatechange", completed );
+ window.detachEvent( "onload", completed );
+ }
+}
+
+/**
+ * The ready event handler and self cleanup method
+ */
+function completed() {
+ // readyState === "complete" is good enough for us to call the dom ready in oldIE
+ if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
+ detach();
+ jQuery.ready();
+ }
+}
+
+jQuery.ready.promise = function( obj ) {
+ if ( !readyList ) {
+
+ readyList = jQuery.Deferred();
+
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ setTimeout( jQuery.ready );
+
+ // Standards-based browsers support DOMContentLoaded
+ } else if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed, false );
+
+ // If IE event model is used
+ } else {
+ // Ensure firing before onload, maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", completed );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", completed );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var top = false;
+
+ try {
+ top = window.frameElement == null && document.documentElement;
+ } catch(e) {}
+
+ if ( top && top.doScroll ) {
+ (function doScrollCheck() {
+ if ( !jQuery.isReady ) {
+
+ try {
+ // Use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ top.doScroll("left");
+ } catch(e) {
+ return setTimeout( doScrollCheck, 50 );
+ }
+
+ // detach all dom ready events
+ detach();
+
+ // and execute any waiting functions
+ jQuery.ready();
+ }
+ })();
+ }
+ }
+ }
+ return readyList.promise( obj );
+};
+
+
+var strundefined = typeof undefined;
+
+
+
+// Support: IE<9
+// Iteration over object's inherited properties before its own
+var i;
+for ( i in jQuery( support ) ) {
+ break;
+}
+support.ownLast = i !== "0";
+
+// Note: most support tests are defined in their respective modules.
+// false until the test is run
+support.inlineBlockNeedsLayout = false;
+
+// Execute ASAP in case we need to set body.style.zoom
+jQuery(function() {
+ // Minified: var a,b,c,d
+ var val, div, body, container;
+
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ if ( !body || !body.style ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ // Setup
+ div = document.createElement( "div" );
+ container = document.createElement( "div" );
+ container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+ body.appendChild( container ).appendChild( div );
+
+ if ( typeof div.style.zoom !== strundefined ) {
+ // Support: IE<8
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1";
+
+ support.inlineBlockNeedsLayout = val = div.offsetWidth === 3;
+ if ( val ) {
+ // Prevent IE 6 from affecting layout for positioned elements #11048
+ // Prevent IE from shrinking the body in IE 7 mode #12869
+ // Support: IE<8
+ body.style.zoom = 1;
+ }
+ }
+
+ body.removeChild( container );
+});
+
+
+
+
+(function() {
+ var div = document.createElement( "div" );
+
+ // Execute the test only if not already executed in another module.
+ if (support.deleteExpando == null) {
+ // Support: IE<9
+ support.deleteExpando = true;
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+ }
+
+ // Null elements to avoid leaks in IE.
+ div = null;
+})();
+
+
+/**
+ * Determines whether an object can have data
+ */
+jQuery.acceptData = function( elem ) {
+ var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ],
+ nodeType = +elem.nodeType || 1;
+
+ // Do not set data on non-element DOM nodes because it will not be cleared (#8335).
+ return nodeType !== 1 && nodeType !== 9 ?
+ false :
+
+ // Nodes accept data unless otherwise specified; rejection can be conditional
+ !noData || noData !== true && elem.getAttribute("classid") === noData;
+};
+
+
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ // Only convert to a number if it doesn't change the string
+ +data + "" === data ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+ var name;
+ for ( name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var ret, thisCache,
+ internalKey = jQuery.expando,
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ // Avoid exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( typeof name === "string" ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+}
+
+function internalRemoveData( elem, name, pvt ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, i,
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+ id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split(" ");
+ }
+ }
+ } else {
+ // If "name" is an array of keys...
+ // When data is initially created, via ("key", "val") signature,
+ // keys will be converted to camelCase.
+ // Since there is no way to tell _how_ a key was added, remove
+ // both plain key and camelCase key. #12786
+ // This will only penalize the array argument path.
+ name = name.concat( jQuery.map( name, jQuery.camelCase ) );
+ }
+
+ i = name.length;
+ while ( i-- ) {
+ delete thisCache[ name[i] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject( cache[ id ] ) ) {
+ return;
+ }
+ }
+
+ // Destroy the cache
+ if ( isNode ) {
+ jQuery.cleanData( [ elem ], true );
+
+ // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
+ /* jshint eqeqeq: false */
+ } else if ( support.deleteExpando || cache != cache.window ) {
+ /* jshint eqeqeq: true */
+ delete cache[ id ];
+
+ // When all else fails, null
+ } else {
+ cache[ id ] = null;
+ }
+}
+
+jQuery.extend({
+ cache: {},
+
+ // The following elements (space-suffixed to avoid Object.prototype collisions)
+ // throw uncatchable exceptions if you attempt to set expando properties
+ noData: {
+ "applet ": true,
+ "embed ": true,
+ // ...but Flash objects (which have this classid) *can* handle expandos
+ "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return internalData( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ return internalRemoveData( elem, name );
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return internalData( elem, name, data, true );
+ },
+
+ _removeData: function( elem, name ) {
+ return internalRemoveData( elem, name, true );
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var i, name, data,
+ elem = this[0],
+ attrs = elem && elem.attributes;
+
+ // Special expections of .data basically thwart jQuery.access,
+ // so implement the relevant behavior ourselves
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ i = attrs.length;
+ while ( i-- ) {
+
+ // Support: IE11+
+ // The attrs elements can be null (#14894)
+ if ( attrs[ i ] ) {
+ name = attrs[ i ].name;
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = jQuery.camelCase( name.slice(5) );
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ }
+ jQuery._data( elem, "parsedAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ return arguments.length > 1 ?
+
+ // Sets one value
+ this.each(function() {
+ jQuery.data( this, key, value );
+ }) :
+
+ // Gets one value
+ // Try to fetch any internally stored data first
+ elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+
+jQuery.extend({
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || jQuery.isArray(data) ) {
+ queue = jQuery._data( elem, type, jQuery.makeArray(data) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // not intended for public consumption - generates a queueHooks object, or returns the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return jQuery._data( elem, key ) || jQuery._data( elem, key, {
+ empty: jQuery.Callbacks("once memory").add(function() {
+ jQuery._removeData( elem, type + "queue" );
+ jQuery._removeData( elem, key );
+ })
+ });
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while ( i-- ) {
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+});
+var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
+
+var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+var isHidden = function( elem, el ) {
+ // isHidden might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+ return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
+ };
+
+
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ length = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( jQuery.type( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !jQuery.isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < length; i++ ) {
+ fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
+ }
+ }
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+};
+var rcheckableType = (/^(?:checkbox|radio)$/i);
+
+
+
+(function() {
+ // Minified: var a,b,c
+ var input = document.createElement( "input" ),
+ div = document.createElement( "div" ),
+ fragment = document.createDocumentFragment();
+
+ // Setup
+ div.innerHTML = " a ";
+
+ // IE strips leading whitespace when .innerHTML is used
+ support.leadingWhitespace = div.firstChild.nodeType === 3;
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ support.tbody = !div.getElementsByTagName( "tbody" ).length;
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ support.htmlSerialize = !!div.getElementsByTagName( "link" ).length;
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ support.html5Clone =
+ document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>";
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ input.type = "checkbox";
+ input.checked = true;
+ fragment.appendChild( input );
+ support.appendChecked = input.checked;
+
+ // Make sure textarea (and checkbox) defaultValue is properly cloned
+ // Support: IE6-IE11+
+ div.innerHTML = "x ";
+ support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ fragment.appendChild( div );
+ div.innerHTML = " ";
+
+ // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
+ // old WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE<9
+ // Opera does not clone events (and typeof div.attachEvent === undefined).
+ // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
+ support.noCloneEvent = true;
+ if ( div.attachEvent ) {
+ div.attachEvent( "onclick", function() {
+ support.noCloneEvent = false;
+ });
+
+ div.cloneNode( true ).click();
+ }
+
+ // Execute the test only if not already executed in another module.
+ if (support.deleteExpando == null) {
+ // Support: IE<9
+ support.deleteExpando = true;
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+ }
+})();
+
+
+(function() {
+ var i, eventName,
+ div = document.createElement( "div" );
+
+ // Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event)
+ for ( i in { submit: true, change: true, focusin: true }) {
+ eventName = "on" + i;
+
+ if ( !(support[ i + "Bubbles" ] = eventName in window) ) {
+ // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
+ div.setAttribute( eventName, "t" );
+ support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false;
+ }
+ }
+
+ // Null elements to avoid leaks in IE.
+ div = null;
+})();
+
+
+var rformElems = /^(?:input|select|textarea)$/i,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+ var tmp, events, t, handleObjIn,
+ special, eventHandle, handleObj,
+ handlers, type, namespaces, origType,
+ elemData = jQuery._data( elem );
+
+ // Don't attach events to noData or text/comment nodes (but allow plain objects)
+ if ( !elemData ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !(events = elemData.events) ) {
+ events = elemData.events = {};
+ }
+ if ( !(eventHandle = elemData.handle) ) {
+ eventHandle = elemData.handle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ types = ( types || "" ).match( rnotwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // There *must* be a type, no attaching namespace-only handlers
+ if ( !type ) {
+ continue;
+ }
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !(handlers = events[ type ]) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+ var j, handleObj, tmp,
+ origCount, t, events,
+ special, handlers, type,
+ namespaces, origType,
+ elemData = jQuery.hasData( elem ) && jQuery._data( elem );
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( rnotwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tmp[1];
+ namespaces = ( tmp[2] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ delete elemData.handle;
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery._removeData( elem, "events" );
+ }
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+ var handle, ontype, cur,
+ bubbleType, special, tmp, i,
+ eventPath = [ elem || document ],
+ type = hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
+
+ cur = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf(".") >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf(":") < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+ event.isTrigger = onlyHandlers ? 2 : 3;
+ event.namespace = namespaces.join(".");
+ event.namespace_re = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === (elem.ownerDocument || document) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
+
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
+ event.result = handle.apply( cur, data );
+ if ( event.result === false ) {
+ event.preventDefault();
+ }
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
+ jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ try {
+ elem[ type ]();
+ } catch ( e ) {
+ // IE<9 dies on focus/blur to hidden element (#1486,#12518)
+ // only reproducible on winXP IE8 native, not IE9 in IE8 mode
+ }
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event );
+
+ var i, ret, handleObj, matched, j,
+ handlerQueue = [],
+ args = slice.call( arguments ),
+ handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
+
+ // Triggered event must either 1) have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( (event.result = ret) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var sel, handleObj, matches, i,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ // Black-hole SVG instance trees (#13180)
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
+
+ /* jshint eqeqeq: false */
+ for ( ; cur != this; cur = cur.parentNode || this ) {
+ /* jshint eqeqeq: true */
+
+ // Don't check non-elements (#13208)
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
+ matches = [];
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+
+ // Don't conflict with Object.prototype properties (#13203)
+ sel = handleObj.selector + " ";
+
+ if ( matches[ sel ] === undefined ) {
+ matches[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) >= 0 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( matches[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, handlers: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( delegateCount < handlers.length ) {
+ handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
+ }
+
+ return handlerQueue;
+ },
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop, copy,
+ type = event.type,
+ originalEvent = event,
+ fixHook = this.fixHooks[ type ];
+
+ if ( !fixHook ) {
+ this.fixHooks[ type ] = fixHook =
+ rmouseEvent.test( type ) ? this.mouseHooks :
+ rkeyEvent.test( type ) ? this.keyHooks :
+ {};
+ }
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = new jQuery.Event( originalEvent );
+
+ i = copy.length;
+ while ( i-- ) {
+ prop = copy[ i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Support: IE<9
+ // Fix target property (#1925)
+ if ( !event.target ) {
+ event.target = originalEvent.srcElement || document;
+ }
+
+ // Support: Chrome 23+, Safari?
+ // Target should not be a text node (#504, #13143)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // Support: IE<9
+ // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
+ event.metaKey = !!event.metaKey;
+
+ return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var body, eventDoc, doc,
+ button = original.button,
+ fromElement = original.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && fromElement ) {
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
+
+ special: {
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+ focus: {
+ // Fire native event if possible so blur/focus sequence is correct
+ trigger: function() {
+ if ( this !== safeActiveElement() && this.focus ) {
+ try {
+ this.focus();
+ return false;
+ } catch ( e ) {
+ // Support: IE<9
+ // If we error on focus to hidden element (#1486, #12518),
+ // let .trigger() run the handlers
+ }
+ }
+ },
+ delegateType: "focusin"
+ },
+ blur: {
+ trigger: function() {
+ if ( this === safeActiveElement() && this.blur ) {
+ this.blur();
+ return false;
+ }
+ },
+ delegateType: "focusout"
+ },
+ click: {
+ // For checkbox, fire native event so checked state will be right
+ trigger: function() {
+ if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
+ this.click();
+ return false;
+ }
+ },
+
+ // For cross-browser consistency, don't fire native .click() on links
+ _default: function( event ) {
+ return jQuery.nodeName( event.target, "a" );
+ }
+ },
+
+ beforeunload: {
+ postDispatch: function( event ) {
+
+ // Support: Firefox 20+
+ // Firefox doesn't alert if the returnValue field is not set.
+ if ( event.result !== undefined && event.originalEvent ) {
+ event.originalEvent.returnValue = event.result;
+ }
+ }
+ }
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ {
+ type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ }
+};
+
+jQuery.removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+ } :
+ function( elem, type, handle ) {
+ var name = "on" + type;
+
+ if ( elem.detachEvent ) {
+
+ // #8545, #7054, preventing memory leaks for custom events in IE6-8
+ // detachEvent needed property on element, by name of that event, to properly expose it to GC
+ if ( typeof elem[ name ] === strundefined ) {
+ elem[ name ] = null;
+ }
+
+ elem.detachEvent( name, handle );
+ }
+ };
+
+jQuery.Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !(this instanceof jQuery.Event) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = src.defaultPrevented ||
+ src.defaultPrevented === undefined &&
+ // Support: IE < 9, Android < 4.0
+ src.returnValue === false ?
+ returnTrue :
+ returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse,
+
+ preventDefault: function() {
+ var e = this.originalEvent;
+
+ this.isDefaultPrevented = returnTrue;
+ if ( !e ) {
+ return;
+ }
+
+ // If preventDefault exists, run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+
+ // Support: IE
+ // Otherwise set the returnValue property of the original event to false
+ } else {
+ e.returnValue = false;
+ }
+ },
+ stopPropagation: function() {
+ var e = this.originalEvent;
+
+ this.isPropagationStopped = returnTrue;
+ if ( !e ) {
+ return;
+ }
+ // If stopPropagation exists, run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+
+ // Support: IE
+ // Set the cancelBubble property of the original event to true
+ e.cancelBubble = true;
+ },
+ stopImmediatePropagation: function() {
+ var e = this.originalEvent;
+
+ this.isImmediatePropagationStopped = returnTrue;
+
+ if ( e && e.stopImmediatePropagation ) {
+ e.stopImmediatePropagation();
+ }
+
+ this.stopPropagation();
+ }
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout",
+ pointerenter: "pointerover",
+ pointerleave: "pointerout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+});
+
+// IE submit delegation
+if ( !support.submitBubbles ) {
+
+ jQuery.event.special.submit = {
+ setup: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+ // Node name check avoids a VML-related crash in IE (#9807)
+ var elem = e.target,
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+ if ( form && !jQuery._data( form, "submitBubbles" ) ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ event._submit_bubble = true;
+ });
+ jQuery._data( form, "submitBubbles", true );
+ }
+ });
+ // return undefined since we don't need an event listener
+ },
+
+ postDispatch: function( event ) {
+ // If form was submitted by the user, bubble the event up the tree
+ if ( event._submit_bubble ) {
+ delete event._submit_bubble;
+ if ( this.parentNode && !event.isTrigger ) {
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
+ }
+ }
+ },
+
+ teardown: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+ jQuery.event.remove( this, "._submit" );
+ }
+ };
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !support.changeBubbles ) {
+
+ jQuery.event.special.change = {
+
+ setup: function() {
+
+ if ( rformElems.test( this.nodeName ) ) {
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
+ // after a propertychange. Eat the blur-change in special.change.handle.
+ // This still fires onchange a second time for check/radio after blur.
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ jQuery.event.add( this, "propertychange._change", function( event ) {
+ if ( event.originalEvent.propertyName === "checked" ) {
+ this._just_changed = true;
+ }
+ });
+ jQuery.event.add( this, "click._change", function( event ) {
+ if ( this._just_changed && !event.isTrigger ) {
+ this._just_changed = false;
+ }
+ // Allow triggered, simulated change events (#11500)
+ jQuery.event.simulate( "change", this, event, true );
+ });
+ }
+ return false;
+ }
+ // Delegated event; lazy-add a change handler on descendant inputs
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
+ var elem = e.target;
+
+ if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+ jQuery.event.simulate( "change", this.parentNode, event, true );
+ }
+ });
+ jQuery._data( elem, "changeBubbles", true );
+ }
+ });
+ },
+
+ handle: function( event ) {
+ var elem = event.target;
+
+ // Swallow native change events from checkbox/radio, we already triggered them above
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+ return event.handleObj.handler.apply( this, arguments );
+ }
+ },
+
+ teardown: function() {
+ jQuery.event.remove( this, "._change" );
+
+ return !rformElems.test( this.nodeName );
+ }
+ };
+}
+
+// Create "bubbling" focus and blur events
+if ( !support.focusinBubbles ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler on the document while someone wants focusin/focusout
+ var handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ var doc = this.ownerDocument || this,
+ attaches = jQuery._data( doc, fix );
+
+ if ( !attaches ) {
+ doc.addEventListener( orig, handler, true );
+ }
+ jQuery._data( doc, fix, ( attaches || 0 ) + 1 );
+ },
+ teardown: function() {
+ var doc = this.ownerDocument || this,
+ attaches = jQuery._data( doc, fix ) - 1;
+
+ if ( !attaches ) {
+ doc.removeEventListener( orig, handler, true );
+ jQuery._removeData( doc, fix );
+ } else {
+ jQuery._data( doc, fix, attaches );
+ }
+ }
+ };
+ });
+}
+
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var type, origFn;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
+ }
+ return this;
+ }
+
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on( types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+ triggerHandler: function( type, data ) {
+ var elem = this[0];
+ if ( elem ) {
+ return jQuery.event.trigger( type, data, elem, true );
+ }
+ }
+});
+
+
+function createSafeFragment( document ) {
+ var list = nodeNames.split( "|" ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( list.length ) {
+ safeFrag.createElement(
+ list.pop()
+ );
+ }
+ }
+ return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+ rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+ rtagName = /<([\w:]+)/,
+ rtbody = /\s*$/g,
+
+ // We have to close these tags to support XHTML (#13200)
+ wrapMap = {
+ option: [ 1, "", " " ],
+ legend: [ 1, "", " " ],
+ area: [ 1, "", " " ],
+ param: [ 1, "", " " ],
+ thead: [ 1, "" ],
+ tr: [ 2, "" ],
+ col: [ 2, "" ],
+ td: [ 3, "" ],
+
+ // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
+ // unless wrapped in a div with non-breaking characters in front of it.
+ _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X", "
" ]
+ },
+ safeFragment = createSafeFragment( document ),
+ fragmentDiv = safeFragment.appendChild( document.createElement("div") );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+function getAll( context, tag ) {
+ var elems, elem,
+ i = 0,
+ found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) :
+ typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) :
+ undefined;
+
+ if ( !found ) {
+ for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
+ if ( !tag || jQuery.nodeName( elem, tag ) ) {
+ found.push( elem );
+ } else {
+ jQuery.merge( found, getAll( elem, tag ) );
+ }
+ }
+ }
+
+ return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
+ jQuery.merge( [ context ], found ) :
+ found;
+}
+
+// Used in buildFragment, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+ if ( rcheckableType.test( elem.type ) ) {
+ elem.defaultChecked = elem.checked;
+ }
+}
+
+// Support: IE<8
+// Manipulating tables requires a tbody
+function manipulationTarget( elem, content ) {
+ return jQuery.nodeName( elem, "table" ) &&
+ jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
+
+ elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
+ elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+ elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
+ return elem;
+}
+function restoreScript( elem ) {
+ var match = rscriptTypeMasked.exec( elem.type );
+ if ( match ) {
+ elem.type = match[1];
+ } else {
+ elem.removeAttribute("type");
+ }
+ return elem;
+}
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var elem,
+ i = 0;
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
+ }
+}
+
+function cloneCopyEvent( src, dest ) {
+
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+ return;
+ }
+
+ var type, i, l,
+ oldData = jQuery._data( src ),
+ curData = jQuery._data( dest, oldData ),
+ events = oldData.events;
+
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+
+ // make the cloned public data object a copy from the original
+ if ( curData.data ) {
+ curData.data = jQuery.extend( {}, curData.data );
+ }
+}
+
+function fixCloneNodeIssues( src, dest ) {
+ var nodeName, e, data;
+
+ // We do not need to do anything for non-Elements
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ nodeName = dest.nodeName.toLowerCase();
+
+ // IE6-8 copies events bound via attachEvent when using cloneNode.
+ if ( !support.noCloneEvent && dest[ jQuery.expando ] ) {
+ data = jQuery._data( dest );
+
+ for ( e in data.events ) {
+ jQuery.removeEvent( dest, e, data.handle );
+ }
+
+ // Event data gets referenced instead of copied if the expando gets copied too
+ dest.removeAttribute( jQuery.expando );
+ }
+
+ // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
+ if ( nodeName === "script" && dest.text !== src.text ) {
+ disableScript( dest ).text = src.text;
+ restoreScript( dest );
+
+ // IE6-10 improperly clones children of object elements using classid.
+ // IE10 throws NoModificationAllowedError if parent is null, #12132.
+ } else if ( nodeName === "object" ) {
+ if ( dest.parentNode ) {
+ dest.outerHTML = src.outerHTML;
+ }
+
+ // This path appears unavoidable for IE9. When cloning an object
+ // element in IE9, the outerHTML strategy above is not sufficient.
+ // If the src has innerHTML and the destination does not,
+ // copy the src.innerHTML into the dest.innerHTML. #10324
+ if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
+ dest.innerHTML = src.innerHTML;
+ }
+
+ } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+ // IE6-8 fails to persist the checked state of a cloned checkbox
+ // or radio button. Worse, IE6-7 fail to give the cloned element
+ // a checked appearance if the defaultChecked value isn't also set
+
+ dest.defaultChecked = dest.checked = src.checked;
+
+ // IE6-7 get confused and end up setting the value of a cloned
+ // checkbox/radio button to an empty string instead of "on"
+ if ( dest.value !== src.value ) {
+ dest.value = src.value;
+ }
+
+ // IE6-8 fails to return the selected option to the default selected
+ // state when cloning options
+ } else if ( nodeName === "option" ) {
+ dest.defaultSelected = dest.selected = src.defaultSelected;
+
+ // IE6-8 fails to set the defaultValue to the correct value when
+ // cloning other types of input fields
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+ }
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var destElements, node, clone, i, srcElements,
+ inPage = jQuery.contains( elem.ownerDocument, elem );
+
+ if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
+ clone = elem.cloneNode( true );
+
+ // IE<=8 does not properly clone detached, unknown element nodes
+ } else {
+ fragmentDiv.innerHTML = elem.outerHTML;
+ fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
+ }
+
+ if ( (!support.noCloneEvent || !support.noCloneChecked) &&
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+
+ // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
+ destElements = getAll( clone );
+ srcElements = getAll( elem );
+
+ // Fix all IE cloning issues
+ for ( i = 0; (node = srcElements[i]) != null; ++i ) {
+ // Ensure that the destination node is not null; Fixes #9587
+ if ( destElements[i] ) {
+ fixCloneNodeIssues( node, destElements[i] );
+ }
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ if ( deepDataAndEvents ) {
+ srcElements = srcElements || getAll( elem );
+ destElements = destElements || getAll( clone );
+
+ for ( i = 0; (node = srcElements[i]) != null; i++ ) {
+ cloneCopyEvent( node, destElements[i] );
+ }
+ } else {
+ cloneCopyEvent( elem, clone );
+ }
+ }
+
+ // Preserve script evaluation history
+ destElements = getAll( clone, "script" );
+ if ( destElements.length > 0 ) {
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+ }
+
+ destElements = srcElements = node = null;
+
+ // Return the cloned set
+ return clone;
+ },
+
+ buildFragment: function( elems, context, scripts, selection ) {
+ var j, elem, contains,
+ tmp, tag, tbody, wrap,
+ l = elems.length,
+
+ // Ensure a safe fragment
+ safe = createSafeFragment( context ),
+
+ nodes = [],
+ i = 0;
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( jQuery.type( elem ) === "object" ) {
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+ // Convert non-html into a text node
+ } else if ( !rhtml.test( elem ) ) {
+ nodes.push( context.createTextNode( elem ) );
+
+ // Convert html into DOM nodes
+ } else {
+ tmp = tmp || safe.appendChild( context.createElement("div") );
+
+ // Deserialize a standard representation
+ tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+
+ tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>$2>" ) + wrap[2];
+
+ // Descend through wrappers to the right content
+ j = wrap[0];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Manually add leading whitespace removed by IE
+ if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
+ }
+
+ // Remove IE's autoinserted from table fragments
+ if ( !support.tbody ) {
+
+ // String was a , *may* have spurious
+ elem = tag === "table" && !rtbody.test( elem ) ?
+ tmp.firstChild :
+
+ // String was a bare or
+ wrap[1] === "" && !rtbody.test( elem ) ?
+ tmp :
+ 0;
+
+ j = elem && elem.childNodes.length;
+ while ( j-- ) {
+ if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
+ elem.removeChild( tbody );
+ }
+ }
+ }
+
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Fix #12392 for WebKit and IE > 9
+ tmp.textContent = "";
+
+ // Fix #12392 for oldIE
+ while ( tmp.firstChild ) {
+ tmp.removeChild( tmp.firstChild );
+ }
+
+ // Remember the top-level container for proper cleanup
+ tmp = safe.lastChild;
+ }
+ }
+ }
+
+ // Fix #11356: Clear elements from fragment
+ if ( tmp ) {
+ safe.removeChild( tmp );
+ }
+
+ // Reset defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ if ( !support.appendChecked ) {
+ jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
+ }
+
+ i = 0;
+ while ( (elem = nodes[ i++ ]) ) {
+
+ // #4087 - If origin and destination elements are the same, and this is
+ // that element, do not do anything
+ if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
+ continue;
+ }
+
+ contains = jQuery.contains( elem.ownerDocument, elem );
+
+ // Append to fragment
+ tmp = getAll( safe.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( contains ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( (elem = tmp[ j++ ]) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ tmp = null;
+
+ return safe;
+ },
+
+ cleanData: function( elems, /* internal */ acceptData ) {
+ var elem, type, id, data,
+ i = 0,
+ internalKey = jQuery.expando,
+ cache = jQuery.cache,
+ deleteExpando = support.deleteExpando,
+ special = jQuery.event.special;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ if ( acceptData || jQuery.acceptData( elem ) ) {
+
+ id = elem[ internalKey ];
+ data = id && cache[ id ];
+
+ if ( data ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ // Remove cache only if it was not already removed by jQuery.event.remove
+ if ( cache[ id ] ) {
+
+ delete cache[ id ];
+
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( deleteExpando ) {
+ delete elem[ internalKey ];
+
+ } else if ( typeof elem.removeAttribute !== strundefined ) {
+ elem.removeAttribute( internalKey );
+
+ } else {
+ elem[ internalKey ] = null;
+ }
+
+ deletedIds.push( id );
+ }
+ }
+ }
+ }
+ }
+});
+
+jQuery.fn.extend({
+ text: function( value ) {
+ return access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+ }, null, value, arguments.length );
+ },
+
+ append: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.insertBefore( elem, target.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this );
+ }
+ });
+ },
+
+ after: function() {
+ return this.domManip( arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ }
+ });
+ },
+
+ remove: function( selector, keepData /* Internal Use Only */ ) {
+ var elem,
+ elems = selector ? jQuery.filter( selector, this ) : this,
+ i = 0;
+
+ for ( ; (elem = elems[i]) != null; i++ ) {
+
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem ) );
+ }
+
+ if ( elem.parentNode ) {
+ if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
+ setGlobalEval( getAll( elem, "script" ) );
+ }
+ elem.parentNode.removeChild( elem );
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+
+ // If this is a select, ensure that it displays empty (#12336)
+ // Support: IE<9
+ if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
+ elem.options.length = 0;
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map(function() {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ return access( this, function( value ) {
+ var elem = this[ 0 ] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined ) {
+ return elem.nodeType === 1 ?
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
+ undefined;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ ( support.htmlSerialize || !rnoshimcache.test( value ) ) &&
+ ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+ !wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1>$2>" );
+
+ try {
+ for (; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ elem = this[i] || {};
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function() {
+ var arg = arguments[ 0 ];
+
+ // Make the changes, replacing each context element with the new content
+ this.domManip( arguments, function( elem ) {
+ arg = this.parentNode;
+
+ jQuery.cleanData( getAll( this ) );
+
+ if ( arg ) {
+ arg.replaceChild( elem, this );
+ }
+ });
+
+ // Force removal if there was no new content (e.g., from empty arguments)
+ return arg && (arg.length || arg.nodeType) ? this : this.remove();
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, callback ) {
+
+ // Flatten any nested arrays
+ args = concat.apply( [], args );
+
+ var first, node, hasScripts,
+ scripts, doc, fragment,
+ i = 0,
+ l = this.length,
+ set = this,
+ iNoClone = l - 1,
+ value = args[0],
+ isFunction = jQuery.isFunction( value );
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( isFunction ||
+ ( l > 1 && typeof value === "string" &&
+ !support.checkClone && rchecked.test( value ) ) ) {
+ return this.each(function( index ) {
+ var self = set.eq( index );
+ if ( isFunction ) {
+ args[0] = value.call( this, index, self.html() );
+ }
+ self.domManip( args, callback );
+ });
+ }
+
+ if ( l ) {
+ fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ if ( first ) {
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+ hasScripts = scripts.length;
+
+ // Use the original fragment for the last item instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ for ( ; i < l; i++ ) {
+ node = fragment;
+
+ if ( i !== iNoClone ) {
+ node = jQuery.clone( node, true, true );
+
+ // Keep references to cloned scripts for later restoration
+ if ( hasScripts ) {
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
+
+ callback.call( this[i], node, i );
+ }
+
+ if ( hasScripts ) {
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+ // Reenable scripts
+ jQuery.map( scripts, restoreScript );
+
+ // Evaluate executable scripts on first document insertion
+ for ( i = 0; i < hasScripts; i++ ) {
+ node = scripts[ i ];
+ if ( rscriptType.test( node.type || "" ) &&
+ !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
+
+ if ( node.src ) {
+ // Optional AJAX dependency, but won't run scripts if not present
+ if ( jQuery._evalUrl ) {
+ jQuery._evalUrl( node.src );
+ }
+ } else {
+ jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
+ }
+ }
+ }
+ }
+
+ // Fix #11809: Avoid leaking memory
+ fragment = first = null;
+ }
+ }
+
+ return this;
+ }
+});
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ i = 0,
+ ret = [],
+ insert = jQuery( selector ),
+ last = insert.length - 1;
+
+ for ( ; i <= last; i++ ) {
+ elems = i === last ? this : this.clone(true);
+ jQuery( insert[i] )[ original ]( elems );
+
+ // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
+ push.apply( ret, elems.get() );
+ }
+
+ return this.pushStack( ret );
+ };
+});
+
+
+var iframe,
+ elemdisplay = {};
+
+/**
+ * Retrieve the actual display of a element
+ * @param {String} name nodeName of the element
+ * @param {Object} doc Document object
+ */
+// Called only from within defaultDisplay
+function actualDisplay( name, doc ) {
+ var style,
+ elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
+
+ // getDefaultComputedStyle might be reliably used only on attached element
+ display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
+
+ // Use of this method is a temporary fix (more like optmization) until something better comes along,
+ // since it was removed from specification and supported only in FF
+ style.display : jQuery.css( elem[ 0 ], "display" );
+
+ // We don't have any data stored on the element,
+ // so use "detach" method as fast way to get rid of the element
+ elem.detach();
+
+ return display;
+}
+
+/**
+ * Try to determine the default display value of an element
+ * @param {String} nodeName
+ */
+function defaultDisplay( nodeName ) {
+ var doc = document,
+ display = elemdisplay[ nodeName ];
+
+ if ( !display ) {
+ display = actualDisplay( nodeName, doc );
+
+ // If the simple way fails, read from inside an iframe
+ if ( display === "none" || !display ) {
+
+ // Use the already-created iframe if possible
+ iframe = (iframe || jQuery( "" )).appendTo( doc.documentElement );
+
+ // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
+ doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document;
+
+ // Support: IE
+ doc.write();
+ doc.close();
+
+ display = actualDisplay( nodeName, doc );
+ iframe.detach();
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return display;
+}
+
+
+(function() {
+ var shrinkWrapBlocksVal;
+
+ support.shrinkWrapBlocks = function() {
+ if ( shrinkWrapBlocksVal != null ) {
+ return shrinkWrapBlocksVal;
+ }
+
+ // Will be changed later if needed.
+ shrinkWrapBlocksVal = false;
+
+ // Minified: var b,c,d
+ var div, body, container;
+
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ if ( !body || !body.style ) {
+ // Test fired too early or in an unsupported environment, exit.
+ return;
+ }
+
+ // Setup
+ div = document.createElement( "div" );
+ container = document.createElement( "div" );
+ container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+ body.appendChild( container ).appendChild( div );
+
+ // Support: IE6
+ // Check if elements with layout shrink-wrap their children
+ if ( typeof div.style.zoom !== strundefined ) {
+ // Reset CSS: box-sizing; display; margin; border
+ div.style.cssText =
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+ "box-sizing:content-box;display:block;margin:0;border:0;" +
+ "padding:1px;width:1px;zoom:1";
+ div.appendChild( document.createElement( "div" ) ).style.width = "5px";
+ shrinkWrapBlocksVal = div.offsetWidth !== 3;
+ }
+
+ body.removeChild( container );
+
+ return shrinkWrapBlocksVal;
+ };
+
+})();
+var rmargin = (/^margin/);
+
+var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+
+
+
+var getStyles, curCSS,
+ rposition = /^(top|right|bottom|left)$/;
+
+if ( window.getComputedStyle ) {
+ getStyles = function( elem ) {
+ // Support: IE<=11+, Firefox<=30+ (#15098, #14150)
+ // IE throws on elements created in popups
+ // FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
+ if ( elem.ownerDocument.defaultView.opener ) {
+ return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
+ }
+
+ return window.getComputedStyle( elem, null );
+ };
+
+ curCSS = function( elem, name, computed ) {
+ var width, minWidth, maxWidth, ret,
+ style = elem.style;
+
+ computed = computed || getStyles( elem );
+
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+ ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
+
+ if ( computed ) {
+
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
+ // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
+ // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
+
+ // Remember the original values
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ // Put in the new values to get a computed value out
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ // Revert the changed values
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ // Support: IE
+ // IE returns zIndex value as an integer.
+ return ret === undefined ?
+ ret :
+ ret + "";
+ };
+} else if ( document.documentElement.currentStyle ) {
+ getStyles = function( elem ) {
+ return elem.currentStyle;
+ };
+
+ curCSS = function( elem, name, computed ) {
+ var left, rs, rsLeft, ret,
+ style = elem.style;
+
+ computed = computed || getStyles( elem );
+ ret = computed ? computed[ name ] : undefined;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && style[ name ] ) {
+ ret = style[ name ];
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ // but not position css attributes, as those are proportional to the parent element instead
+ // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
+ if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rs = elem.runtimeStyle;
+ rsLeft = rs && rs.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ rs.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ rs.left = rsLeft;
+ }
+ }
+
+ // Support: IE
+ // IE returns zIndex value as an integer.
+ return ret === undefined ?
+ ret :
+ ret + "" || "auto";
+ };
+}
+
+
+
+
+function addGetHookIf( conditionFn, hookFn ) {
+ // Define the hook, we'll check on the first run if it's really needed.
+ return {
+ get: function() {
+ var condition = conditionFn();
+
+ if ( condition == null ) {
+ // The test was not ready at this point; screw the hook this time
+ // but check again when needed next time.
+ return;
+ }
+
+ if ( condition ) {
+ // Hook not needed (or it's not possible to use it due to missing dependency),
+ // remove it.
+ // Since there are no other hooks for marginRight, remove the whole object.
+ delete this.get;
+ return;
+ }
+
+ // Hook needed; redefine it so that the support test is not executed again.
+
+ return (this.get = hookFn).apply( this, arguments );
+ }
+ };
+}
+
+
+(function() {
+ // Minified: var b,c,d,e,f,g, h,i
+ var div, style, a, pixelPositionVal, boxSizingReliableVal,
+ reliableHiddenOffsetsVal, reliableMarginRightVal;
+
+ // Setup
+ div = document.createElement( "div" );
+ div.innerHTML = " a ";
+ a = div.getElementsByTagName( "a" )[ 0 ];
+ style = a && a.style;
+
+ // Finish early in limited (non-browser) environments
+ if ( !style ) {
+ return;
+ }
+
+ style.cssText = "float:left;opacity:.5";
+
+ // Support: IE<9
+ // Make sure that element opacity exists (as opposed to filter)
+ support.opacity = style.opacity === "0.5";
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ support.cssFloat = !!style.cssFloat;
+
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ support.boxSizing = style.boxSizing === "" || style.MozBoxSizing === "" ||
+ style.WebkitBoxSizing === "";
+
+ jQuery.extend(support, {
+ reliableHiddenOffsets: function() {
+ if ( reliableHiddenOffsetsVal == null ) {
+ computeStyleTests();
+ }
+ return reliableHiddenOffsetsVal;
+ },
+
+ boxSizingReliable: function() {
+ if ( boxSizingReliableVal == null ) {
+ computeStyleTests();
+ }
+ return boxSizingReliableVal;
+ },
+
+ pixelPosition: function() {
+ if ( pixelPositionVal == null ) {
+ computeStyleTests();
+ }
+ return pixelPositionVal;
+ },
+
+ // Support: Android 2.3
+ reliableMarginRight: function() {
+ if ( reliableMarginRightVal == null ) {
+ computeStyleTests();
+ }
+ return reliableMarginRightVal;
+ }
+ });
+
+ function computeStyleTests() {
+ // Minified: var b,c,d,j
+ var div, body, container, contents;
+
+ body = document.getElementsByTagName( "body" )[ 0 ];
+ if ( !body || !body.style ) {
+ // Test fired too early or in an unsupported environment, exit.
+ return;
+ }
+
+ // Setup
+ div = document.createElement( "div" );
+ container = document.createElement( "div" );
+ container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
+ body.appendChild( container ).appendChild( div );
+
+ div.style.cssText =
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
+ "box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
+ "border:1px;padding:1px;width:4px;position:absolute";
+
+ // Support: IE<9
+ // Assume reasonable values in the absence of getComputedStyle
+ pixelPositionVal = boxSizingReliableVal = false;
+ reliableMarginRightVal = true;
+
+ // Check for getComputedStyle so that this code is not run in IE<9.
+ if ( window.getComputedStyle ) {
+ pixelPositionVal = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
+ boxSizingReliableVal =
+ ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
+
+ // Support: Android 2.3
+ // Div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container (#3333)
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ contents = div.appendChild( document.createElement( "div" ) );
+
+ // Reset CSS: box-sizing; display; margin; border; padding
+ contents.style.cssText = div.style.cssText =
+ // Support: Firefox<29, Android 2.3
+ // Vendor-prefix box-sizing
+ "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
+ "box-sizing:content-box;display:block;margin:0;border:0;padding:0";
+ contents.style.marginRight = contents.style.width = "0";
+ div.style.width = "1px";
+
+ reliableMarginRightVal =
+ !parseFloat( ( window.getComputedStyle( contents, null ) || {} ).marginRight );
+
+ div.removeChild( contents );
+ }
+
+ // Support: IE8
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ div.innerHTML = "";
+ contents = div.getElementsByTagName( "td" );
+ contents[ 0 ].style.cssText = "margin:0;border:0;padding:0;display:none";
+ reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
+ if ( reliableHiddenOffsetsVal ) {
+ contents[ 0 ].style.display = "";
+ contents[ 1 ].style.display = "none";
+ reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
+ }
+
+ body.removeChild( container );
+ }
+
+})();
+
+
+// A method for quickly swapping in/out CSS properties to get correct calculations.
+jQuery.swap = function( elem, options, callback, args ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.apply( elem, args || [] );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+};
+
+
+var
+ ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity\s*=\s*([^)]*)/,
+
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
+ rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: "0",
+ fontWeight: "400"
+ },
+
+ cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
+
+
+// return a css property mapped to a potentially vendor prefixed property
+function vendorPropName( style, name ) {
+
+ // shortcut for names that are not vendor prefixed
+ if ( name in style ) {
+ return name;
+ }
+
+ // check for vendor prefixed names
+ var capName = name.charAt(0).toUpperCase() + name.slice(1),
+ origName = name,
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in style ) {
+ return name;
+ }
+ }
+
+ return origName;
+}
+
+function showHide( elements, show ) {
+ var display, elem, hidden,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+
+ values[ index ] = jQuery._data( elem, "olddisplay" );
+ display = elem.style.display;
+ if ( show ) {
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !values[ index ] && display === "none" ) {
+ elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( elem.style.display === "" && isHidden( elem ) ) {
+ values[ index ] = jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
+ }
+ } else {
+ hidden = isHidden( elem );
+
+ if ( display && display !== "none" || !hidden ) {
+ jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( index = 0; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+ if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
+ elem.style.display = show ? values[ index ] || "" : "none";
+ }
+ }
+
+ return elements;
+}
+
+function setPositiveNumber( elem, value, subtract ) {
+ var matches = rnumsplit.exec( value );
+ return matches ?
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
+ value;
+}
+
+function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
+ var i = extra === ( isBorderBox ? "border" : "content" ) ?
+ // If we already have the right measurement, avoid augmentation
+ 4 :
+ // Otherwise initialize for horizontal or vertical properties
+ name === "width" ? 1 : 0,
+
+ val = 0;
+
+ for ( ; i < 4; i += 2 ) {
+ // both box models exclude margin, so add it if we want it
+ if ( extra === "margin" ) {
+ val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
+ }
+
+ if ( isBorderBox ) {
+ // border-box includes padding, so remove it if we want content
+ if ( extra === "content" ) {
+ val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
+
+ // at this point, extra isn't border nor margin, so remove border
+ if ( extra !== "margin" ) {
+ val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ } else {
+ // at this point, extra isn't content, so add padding
+ val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+ // at this point, extra isn't content nor padding, so add border
+ if ( extra !== "padding" ) {
+ val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ }
+ }
+
+ return val;
+}
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property, which is equivalent to the border-box value
+ var valueIsBorderBox = true,
+ val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ styles = getStyles( elem ),
+ isBorderBox = support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+ if ( val <= 0 || val == null ) {
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name, styles );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // we need the check for style in case a browser which returns unreliable values
+ // for getComputedStyle silently falls back to the reliable elem.style
+ valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] );
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+ }
+
+ // use the active box-sizing model to add/subtract irrelevant styles
+ return ( val +
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox,
+ styles
+ )
+ ) + "px";
+}
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+ }
+ }
+ }
+ },
+
+ // Don't automatically add "px" to these possibly-unitless properties
+ cssNumber: {
+ "columnCount": true,
+ "fillOpacity": true,
+ "flexGrow": true,
+ "flexShrink": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "order": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": support.cssFloat ? "cssFloat" : "styleFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = jQuery.camelCase( name ),
+ style = elem.style;
+
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that null and NaN values aren't set. See: #7116
+ if ( value == null || value !== value ) {
+ return;
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
+ // but it would mean to define eight (for every problematic property) identical functions
+ if ( !support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
+ style[ name ] = "inherit";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
+
+ // Support: IE
+ // Swallow errors from 'invalid' CSS values (#5509)
+ try {
+ style[ name ] = value;
+ } catch(e) {}
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra, styles ) {
+ var num, val, hooks,
+ origName = jQuery.camelCase( name );
+
+ // Make sure that we're working with the right name
+ name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
+
+ // gets hook for the prefixed version
+ // followed by the unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name, styles );
+ }
+
+ //convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Return, converting to number if forced or a qualifier was provided and val looks numeric
+ if ( extra === "" || extra ) {
+ num = parseFloat( val );
+ return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
+ }
+ return val;
+ }
+});
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+ // certain elements can have dimension info if we invisibly show them
+ // however, it must have a current display style that would benefit from this
+ return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
+ jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ }) :
+ getWidthOrHeight( elem, name, extra );
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ var styles = extra && getStyles( elem );
+ return setPositiveNumber( elem, value, extra ?
+ augmentWidthOrHeight(
+ elem,
+ name,
+ extra,
+ support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ styles
+ ) : 0
+ );
+ }
+ };
+});
+
+if ( !support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+ ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
+ computed ? "1" : "";
+ },
+
+ set: function( elem, value ) {
+ var style = elem.style,
+ currentStyle = elem.currentStyle,
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
+
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+ // if value === "", then remove inline opacity #12685
+ if ( ( value >= 1 || value === "" ) &&
+ jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
+ style.removeAttribute ) {
+
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
+ // style.removeAttribute is IE Only, but so apparently is this code path...
+ style.removeAttribute( "filter" );
+
+ // if there is no filter style applied in a css rule or unset inline opacity, we are done
+ if ( value === "" || currentStyle && !currentStyle.filter ) {
+ return;
+ }
+ }
+
+ // otherwise, set new filter values
+ style.filter = ralpha.test( filter ) ?
+ filter.replace( ralpha, opacity ) :
+ filter + " " + opacity;
+ }
+ };
+}
+
+jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
+ function( elem, computed ) {
+ if ( computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" },
+ curCSS, [ elem, "marginRight" ] );
+ }
+ }
+);
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i = 0,
+ expanded = {},
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ];
+
+ for ( ; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( !rmargin.test( prefix ) ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+});
+
+jQuery.fn.extend({
+ css: function( name, value ) {
+ return access( this, function( elem, name, value ) {
+ var styles, len,
+ map = {},
+ i = 0;
+
+ if ( jQuery.isArray( name ) ) {
+ styles = getStyles( elem );
+ len = name.length;
+
+ for ( ; i < len; i++ ) {
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+ }
+
+ return map;
+ }
+
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ },
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ if ( typeof state === "boolean" ) {
+ return state ? this.show() : this.hide();
+ }
+
+ return this.each(function() {
+ if ( isHidden( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ });
+ }
+});
+
+
+function Tween( elem, options, prop, end, easing ) {
+ return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+ constructor: Tween,
+ init: function( elem, options, prop, end, easing, unit ) {
+ this.elem = elem;
+ this.prop = prop;
+ this.easing = easing || "swing";
+ this.options = options;
+ this.start = this.now = this.cur();
+ this.end = end;
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+ },
+ cur: function() {
+ var hooks = Tween.propHooks[ this.prop ];
+
+ return hooks && hooks.get ?
+ hooks.get( this ) :
+ Tween.propHooks._default.get( this );
+ },
+ run: function( percent ) {
+ var eased,
+ hooks = Tween.propHooks[ this.prop ];
+
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
+ this.now = ( this.end - this.start ) * eased + this.start;
+
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ if ( hooks && hooks.set ) {
+ hooks.set( this );
+ } else {
+ Tween.propHooks._default.set( this );
+ }
+ return this;
+ }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+ _default: {
+ get: function( tween ) {
+ var result;
+
+ if ( tween.elem[ tween.prop ] != null &&
+ (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+ return tween.elem[ tween.prop ];
+ }
+
+ // passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails
+ // so, simple values such as "10px" are parsed to Float.
+ // complex values such as "rotate(1rad)" are returned as is.
+ result = jQuery.css( tween.elem, tween.prop, "" );
+ // Empty strings, null, undefined and "auto" are converted to 0.
+ return !result || result === "auto" ? 0 : result;
+ },
+ set: function( tween ) {
+ // use step hook for back compat - use cssHook if its there - use .style if its
+ // available and use plain properties where available
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+ } else {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+ }
+};
+
+// Support: IE <=9
+// Panic based approach to setting things on disconnected nodes
+
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+ set: function( tween ) {
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+};
+
+jQuery.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p * Math.PI ) / 2;
+ }
+};
+
+jQuery.fx = Tween.prototype.init;
+
+// Back Compat <1.8 extension point
+jQuery.fx.step = {};
+
+
+
+
+var
+ fxNow, timerId,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
+ rrun = /queueHooks$/,
+ animationPrefilters = [ defaultPrefilter ],
+ tweeners = {
+ "*": [ function( prop, value ) {
+ var tween = this.createTween( prop, value ),
+ target = tween.cur(),
+ parts = rfxnum.exec( value ),
+ unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
+ rfxnum.exec( jQuery.css( tween.elem, prop ) ),
+ scale = 1,
+ maxIterations = 20;
+
+ if ( start && start[ 3 ] !== unit ) {
+ // Trust units reported by jQuery.css
+ unit = unit || start[ 3 ];
+
+ // Make sure we update the tween properties later on
+ parts = parts || [];
+
+ // Iteratively approximate from a nonzero starting point
+ start = +target || 1;
+
+ do {
+ // If previous iteration zeroed out, double until we get *something*
+ // Use a string for doubling factor so we don't accidentally see scale as unchanged below
+ scale = scale || ".5";
+
+ // Adjust and apply
+ start = start / scale;
+ jQuery.style( tween.elem, prop, start + unit );
+
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+ } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
+ }
+
+ // Update tween properties
+ if ( parts ) {
+ start = tween.start = +start || +target || 0;
+ tween.unit = unit;
+ // If a +=/-= token was provided, we're doing a relative animation
+ tween.end = parts[ 1 ] ?
+ start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
+ +parts[ 2 ];
+ }
+
+ return tween;
+ } ]
+ };
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout(function() {
+ fxNow = undefined;
+ });
+ return ( fxNow = jQuery.now() );
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+ var which,
+ attrs = { height: type },
+ i = 0;
+
+ // if we include width, step value is 1 to do all cssExpand values,
+ // if we don't include width, step value is 2 to skip over Left and Right
+ includeWidth = includeWidth ? 1 : 0;
+ for ( ; i < 4 ; i += 2 - includeWidth ) {
+ which = cssExpand[ i ];
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+ }
+
+ if ( includeWidth ) {
+ attrs.opacity = attrs.width = type;
+ }
+
+ return attrs;
+}
+
+function createTween( value, prop, animation ) {
+ var tween,
+ collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( (tween = collection[ index ].call( animation, prop, value )) ) {
+
+ // we're done with this property
+ return tween;
+ }
+ }
+}
+
+function defaultPrefilter( elem, props, opts ) {
+ /* jshint validthis: true */
+ var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
+ anim = this,
+ orig = {},
+ style = elem.style,
+ hidden = elem.nodeType && isHidden( elem ),
+ dataShow = jQuery._data( elem, "fxshow" );
+
+ // handle queue: false promises
+ if ( !opts.queue ) {
+ hooks = jQuery._queueHooks( elem, "fx" );
+ if ( hooks.unqueued == null ) {
+ hooks.unqueued = 0;
+ oldfire = hooks.empty.fire;
+ hooks.empty.fire = function() {
+ if ( !hooks.unqueued ) {
+ oldfire();
+ }
+ };
+ }
+ hooks.unqueued++;
+
+ anim.always(function() {
+ // doing this makes sure that the complete handler will be called
+ // before this completes
+ anim.always(function() {
+ hooks.unqueued--;
+ if ( !jQuery.queue( elem, "fx" ).length ) {
+ hooks.empty.fire();
+ }
+ });
+ });
+ }
+
+ // height/width overflow pass
+ if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE does not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height animated
+ display = jQuery.css( elem, "display" );
+
+ // Test default display if display is currently "none"
+ checkDisplay = display === "none" ?
+ jQuery._data( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
+
+ if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( !support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) {
+ style.display = "inline-block";
+ } else {
+ style.zoom = 1;
+ }
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ if ( !support.shrinkWrapBlocks() ) {
+ anim.always(function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ });
+ }
+ }
+
+ // show/hide pass
+ for ( prop in props ) {
+ value = props[ prop ];
+ if ( rfxtypes.exec( value ) ) {
+ delete props[ prop ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+
+ // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
+ if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+ hidden = true;
+ } else {
+ continue;
+ }
+ }
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+
+ // Any non-fx value stops us from restoring the original display value
+ } else {
+ display = undefined;
+ }
+ }
+
+ if ( !jQuery.isEmptyObject( orig ) ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+ } else {
+ dataShow = jQuery._data( elem, "fxshow", {} );
+ }
+
+ // store state if its toggle - enables .stop().toggle() to "reverse"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+ if ( hidden ) {
+ jQuery( elem ).show();
+ } else {
+ anim.done(function() {
+ jQuery( elem ).hide();
+ });
+ }
+ anim.done(function() {
+ var prop;
+ jQuery._removeData( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ });
+ for ( prop in orig ) {
+ tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = tween.start;
+ if ( hidden ) {
+ tween.end = tween.start;
+ tween.start = prop === "width" || prop === "height" ? 1 : 0;
+ }
+ }
+ }
+
+ // If this is a noop like .hide().hide(), restore an overwritten display value
+ } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
+ style.display = display;
+ }
+}
+
+function propFilter( props, specialEasing ) {
+ var index, name, easing, value, hooks;
+
+ // camelCase, specialEasing and expand cssHook pass
+ for ( index in props ) {
+ name = jQuery.camelCase( index );
+ easing = specialEasing[ name ];
+ value = props[ index ];
+ if ( jQuery.isArray( value ) ) {
+ easing = value[ 1 ];
+ value = props[ index ] = value[ 0 ];
+ }
+
+ if ( index !== name ) {
+ props[ name ] = value;
+ delete props[ index ];
+ }
+
+ hooks = jQuery.cssHooks[ name ];
+ if ( hooks && "expand" in hooks ) {
+ value = hooks.expand( value );
+ delete props[ name ];
+
+ // not quite $.extend, this wont overwrite keys already present.
+ // also - reusing 'index' from above because we have the correct "name"
+ for ( index in value ) {
+ if ( !( index in props ) ) {
+ props[ index ] = value[ index ];
+ specialEasing[ index ] = easing;
+ }
+ }
+ } else {
+ specialEasing[ name ] = easing;
+ }
+ }
+}
+
+function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = animationPrefilters.length,
+ deferred = jQuery.Deferred().always( function() {
+ // don't match elem in the :animated selector
+ delete tick.elem;
+ }),
+ tick = function() {
+ if ( stopped ) {
+ return false;
+ }
+ var currentTime = fxNow || createFxNow(),
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+ // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
+ index = 0,
+ length = animation.tweens.length;
+
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( percent );
+ }
+
+ deferred.notifyWith( elem, [ animation, percent, remaining ]);
+
+ if ( percent < 1 && length ) {
+ return remaining;
+ } else {
+ deferred.resolveWith( elem, [ animation ] );
+ return false;
+ }
+ },
+ animation = deferred.promise({
+ elem: elem,
+ props: jQuery.extend( {}, properties ),
+ opts: jQuery.extend( true, { specialEasing: {} }, options ),
+ originalProperties: properties,
+ originalOptions: options,
+ startTime: fxNow || createFxNow(),
+ duration: options.duration,
+ tweens: [],
+ createTween: function( prop, end ) {
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
+ animation.tweens.push( tween );
+ return tween;
+ },
+ stop: function( gotoEnd ) {
+ var index = 0,
+ // if we are going to the end, we want to run all the tweens
+ // otherwise we skip this part
+ length = gotoEnd ? animation.tweens.length : 0;
+ if ( stopped ) {
+ return this;
+ }
+ stopped = true;
+ for ( ; index < length ; index++ ) {
+ animation.tweens[ index ].run( 1 );
+ }
+
+ // resolve when we played the last frame
+ // otherwise, reject
+ if ( gotoEnd ) {
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
+ } else {
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
+ }
+ return this;
+ }
+ }),
+ props = animation.props;
+
+ propFilter( props, animation.opts.specialEasing );
+
+ for ( ; index < length ; index++ ) {
+ result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ return result;
+ }
+ }
+
+ jQuery.map( props, createTween, animation );
+
+ if ( jQuery.isFunction( animation.opts.start ) ) {
+ animation.opts.start.call( elem, animation );
+ }
+
+ jQuery.fx.timer(
+ jQuery.extend( tick, {
+ elem: elem,
+ anim: animation,
+ queue: animation.opts.queue
+ })
+ );
+
+ // attach callbacks from options
+ return animation.progress( animation.opts.progress )
+ .done( animation.opts.done, animation.opts.complete )
+ .fail( animation.opts.fail )
+ .always( animation.opts.always );
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+ tweener: function( props, callback ) {
+ if ( jQuery.isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.split(" ");
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length ; index++ ) {
+ prop = props[ index ];
+ tweeners[ prop ] = tweeners[ prop ] || [];
+ tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ animationPrefilters.unshift( callback );
+ } else {
+ animationPrefilters.push( callback );
+ }
+ }
+});
+
+jQuery.speed = function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function() {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ }
+ };
+
+ return opt;
+};
+
+jQuery.fn.extend({
+ fadeTo: function( speed, to, easing, callback ) {
+
+ // show any hidden elements after setting opacity to 0
+ return this.filter( isHidden ).css( "opacity", 0 ).show()
+
+ // animate to the value specified
+ .end().animate({ opacity: to }, speed, easing, callback );
+ },
+ animate: function( prop, speed, easing, callback ) {
+ var empty = jQuery.isEmptyObject( prop ),
+ optall = jQuery.speed( speed, easing, callback ),
+ doAnimation = function() {
+ // Operate on a copy of prop so per-property easing won't be lost
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+ // Empty animations, or finishing resolves immediately
+ if ( empty || jQuery._data( this, "finish" ) ) {
+ anim.stop( true );
+ }
+ };
+ doAnimation.finish = doAnimation;
+
+ return empty || optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+ stop: function( type, clearQueue, gotoEnd ) {
+ var stopQueue = function( hooks ) {
+ var stop = hooks.stop;
+ delete hooks.stop;
+ stop( gotoEnd );
+ };
+
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each(function() {
+ var dequeue = true,
+ index = type != null && type + "queueHooks",
+ timers = jQuery.timers,
+ data = jQuery._data( this );
+
+ if ( index ) {
+ if ( data[ index ] && data[ index ].stop ) {
+ stopQueue( data[ index ] );
+ }
+ } else {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+ stopQueue( data[ index ] );
+ }
+ }
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ timers[ index ].anim.stop( gotoEnd );
+ dequeue = false;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( dequeue || !gotoEnd ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ finish: function( type ) {
+ if ( type !== false ) {
+ type = type || "fx";
+ }
+ return this.each(function() {
+ var index,
+ data = jQuery._data( this ),
+ queue = data[ type + "queue" ],
+ hooks = data[ type + "queueHooks" ],
+ timers = jQuery.timers,
+ length = queue ? queue.length : 0;
+
+ // enable finishing flag on private data
+ data.finish = true;
+
+ // empty the queue first
+ jQuery.queue( this, type, [] );
+
+ if ( hooks && hooks.stop ) {
+ hooks.stop.call( this, true );
+ }
+
+ // look for any active animations, and finish them
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+ timers[ index ].anim.stop( true );
+ timers.splice( index, 1 );
+ }
+ }
+
+ // look for any animations in the old queue and finish them
+ for ( index = 0; index < length; index++ ) {
+ if ( queue[ index ] && queue[ index ].finish ) {
+ queue[ index ].finish.call( this );
+ }
+ }
+
+ // turn off finishing flag
+ delete data.finish;
+ });
+ }
+});
+
+jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
+ var cssFn = jQuery.fn[ name ];
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return speed == null || typeof speed === "boolean" ?
+ cssFn.apply( this, arguments ) :
+ this.animate( genFx( name, true ), speed, easing, callback );
+ };
+});
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx("show"),
+ slideUp: genFx("hide"),
+ slideToggle: genFx("toggle"),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+});
+
+jQuery.timers = [];
+jQuery.fx.tick = function() {
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ fxNow = jQuery.now();
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+ jQuery.timers.push( timer );
+ if ( timer() ) {
+ jQuery.fx.start();
+ } else {
+ jQuery.timers.pop();
+ }
+};
+
+jQuery.fx.interval = 13;
+
+jQuery.fx.start = function() {
+ if ( !timerId ) {
+ timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
+ }
+};
+
+jQuery.fx.stop = function() {
+ clearInterval( timerId );
+ timerId = null;
+};
+
+jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+};
+
+
+// Based off of the plugin by Clint Helfers, with permission.
+// http://blindsignals.com/index.php/2009/07/jquery-delay/
+jQuery.fn.delay = function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+};
+
+
+(function() {
+ // Minified: var a,b,c,d,e
+ var input, div, select, a, opt;
+
+ // Setup
+ div = document.createElement( "div" );
+ div.setAttribute( "className", "t" );
+ div.innerHTML = " a ";
+ a = div.getElementsByTagName("a")[ 0 ];
+
+ // First batch of tests.
+ select = document.createElement("select");
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName("input")[ 0 ];
+
+ a.style.cssText = "top:1px";
+
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ support.getSetAttribute = div.className !== "t";
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ support.style = /top/.test( a.getAttribute("style") );
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ support.hrefNormalized = a.getAttribute("href") === "/a";
+
+ // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
+ support.checkOn = !!input.value;
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ support.optSelected = opt.selected;
+
+ // Tests for enctype support on a form (#6743)
+ support.enctype = !!document.createElement("form").enctype;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Support: IE8 only
+ // Check if we can trust getAttribute("value")
+ input = document.createElement( "input" );
+ input.setAttribute( "value", "" );
+ support.input = input.getAttribute( "value" ) === "";
+
+ // Check if an input maintains its value after becoming a radio
+ input.value = "t";
+ input.setAttribute( "type", "radio" );
+ support.radioValue = input.value === "t";
+})();
+
+
+var rreturn = /\r/g;
+
+jQuery.fn.extend({
+ val: function( value ) {
+ var hooks, ret, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, jQuery( this ).val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map( val, function( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ var val = jQuery.find.attr( elem, "value" );
+ return val != null ?
+ val :
+ // Support: IE10-11+
+ // option.text throws exceptions (#14686, #14858)
+ jQuery.trim( jQuery.text( elem ) );
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // oldIE doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var optionSet, option,
+ options = elem.options,
+ values = jQuery.makeArray( value ),
+ i = options.length;
+
+ while ( i-- ) {
+ option = options[ i ];
+
+ if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) >= 0 ) {
+
+ // Support: IE6
+ // When new option element is added to select box we need to
+ // force reflow of newly added node in order to workaround delay
+ // of initialization properties
+ try {
+ option.selected = optionSet = true;
+
+ } catch ( _ ) {
+
+ // Will be executed only in IE6
+ option.scrollHeight;
+ }
+
+ } else {
+ option.selected = false;
+ }
+ }
+
+ // Force browsers to behave consistently when non-matching value is set
+ if ( !optionSet ) {
+ elem.selectedIndex = -1;
+ }
+
+ return options;
+ }
+ }
+ }
+});
+
+// Radios and checkboxes getter/setter
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ };
+ if ( !support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ // Support: Webkit
+ // "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ };
+ }
+});
+
+
+
+
+var nodeHook, boolHook,
+ attrHandle = jQuery.expr.attrHandle,
+ ruseDefault = /^(?:checked|selected)$/i,
+ getSetAttribute = support.getSetAttribute,
+ getSetInput = support.input;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ }
+});
+
+jQuery.extend({
+ attr: function( elem, name, value ) {
+ var hooks, ret,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === strundefined ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] ||
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+
+ } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ ret = jQuery.find.attr( elem, name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name, propName,
+ i = 0,
+ attrNames = value && value.match( rnotwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( (name = attrNames[i++]) ) {
+ propName = jQuery.propFix[ name ] || name;
+
+ // Boolean attributes get special treatment (#10870)
+ if ( jQuery.expr.match.bool.test( name ) ) {
+ // Set corresponding property to false
+ if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ elem[ propName ] = false;
+ // Support: IE<9
+ // Also clear defaultChecked/defaultSelected (if appropriate)
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] =
+ elem[ propName ] = false;
+ }
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ } else {
+ jQuery.attr( elem, name, "" );
+ }
+
+ elem.removeAttribute( getSetAttribute ? name : propName );
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to default in case type is set after value during creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ }
+});
+
+// Hook for boolean attributes
+boolHook = {
+ set: function( elem, value, name ) {
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
+ // IE<8 needs the *property* name
+ elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
+
+ // Use defaultChecked and defaultSelected for oldIE
+ } else {
+ elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
+ }
+
+ return name;
+ }
+};
+
+// Retrieve booleans specially
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
+
+ var getter = attrHandle[ name ] || jQuery.find.attr;
+
+ attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
+ function( elem, name, isXML ) {
+ var ret, handle;
+ if ( !isXML ) {
+ // Avoid an infinite loop by temporarily removing this function from the getter
+ handle = attrHandle[ name ];
+ attrHandle[ name ] = ret;
+ ret = getter( elem, name, isXML ) != null ?
+ name.toLowerCase() :
+ null;
+ attrHandle[ name ] = handle;
+ }
+ return ret;
+ } :
+ function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem[ jQuery.camelCase( "default-" + name ) ] ?
+ name.toLowerCase() :
+ null;
+ }
+ };
+});
+
+// fix oldIE attroperties
+if ( !getSetInput || !getSetAttribute ) {
+ jQuery.attrHooks.value = {
+ set: function( elem, value, name ) {
+ if ( jQuery.nodeName( elem, "input" ) ) {
+ // Does not return so that setAttribute is also used
+ elem.defaultValue = value;
+ } else {
+ // Use nodeHook if defined (#1954); otherwise setAttribute is fine
+ return nodeHook && nodeHook.set( elem, value, name );
+ }
+ }
+ };
+}
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+ // Use this for any attribute in IE6/7
+ // This fixes almost every IE6/7 issue
+ nodeHook = {
+ set: function( elem, value, name ) {
+ // Set the existing or create a new attribute node
+ var ret = elem.getAttributeNode( name );
+ if ( !ret ) {
+ elem.setAttributeNode(
+ (ret = elem.ownerDocument.createAttribute( name ))
+ );
+ }
+
+ ret.value = value += "";
+
+ // Break association with cloned elements by also using setAttribute (#9646)
+ if ( name === "value" || value === elem.getAttribute( name ) ) {
+ return value;
+ }
+ }
+ };
+
+ // Some attributes are constructed with empty-string values when not defined
+ attrHandle.id = attrHandle.name = attrHandle.coords =
+ function( elem, name, isXML ) {
+ var ret;
+ if ( !isXML ) {
+ return (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
+ ret.value :
+ null;
+ }
+ };
+
+ // Fixing value retrieval on a button requires this module
+ jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret = elem.getAttributeNode( name );
+ if ( ret && ret.specified ) {
+ return ret.value;
+ }
+ },
+ set: nodeHook.set
+ };
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ set: function( elem, value, name ) {
+ nodeHook.set( elem, value === "" ? false : value, name );
+ }
+ };
+
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+ // This is for removals
+ jQuery.each([ "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = {
+ set: function( elem, value ) {
+ if ( value === "" ) {
+ elem.setAttribute( name, "auto" );
+ return value;
+ }
+ }
+ };
+ });
+}
+
+if ( !support.style ) {
+ jQuery.attrHooks.style = {
+ get: function( elem ) {
+ // Return undefined in the case of empty string
+ // Note: IE uppercases css property names, but if we were to .toLowerCase()
+ // .cssText, that would destroy case senstitivity in URL's, like in "background"
+ return elem.style.cssText || undefined;
+ },
+ set: function( elem, value ) {
+ return ( elem.style.cssText = value + "" );
+ }
+ };
+}
+
+
+
+
+var rfocusable = /^(?:input|select|textarea|button|object)$/i,
+ rclickable = /^(?:a|area)$/i;
+
+jQuery.fn.extend({
+ prop: function( name, value ) {
+ return access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ name = jQuery.propFix[ name ] || name;
+ return this.each(function() {
+ // try/catch handles cases where IE balks (such as removing a property on window)
+ try {
+ this[ name ] = undefined;
+ delete this[ name ];
+ } catch( e ) {}
+ });
+ }
+});
+
+jQuery.extend({
+ propFix: {
+ "for": "htmlFor",
+ "class": "className"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
+ ret :
+ ( elem[ name ] = value );
+
+ } else {
+ return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
+ ret :
+ elem[ name ];
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ // Use proper attribute retrieval(#12072)
+ var tabindex = jQuery.find.attr( elem, "tabindex" );
+
+ return tabindex ?
+ parseInt( tabindex, 10 ) :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ -1;
+ }
+ }
+ }
+});
+
+// Some attributes require a special call on IE
+// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !support.hrefNormalized ) {
+ // href/src property should get the full normalized URL (#10299/#12915)
+ jQuery.each([ "href", "src" ], function( i, name ) {
+ jQuery.propHooks[ name ] = {
+ get: function( elem ) {
+ return elem.getAttribute( name, 4 );
+ }
+ };
+ });
+}
+
+// Support: Safari, IE9+
+// mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !support.optSelected ) {
+ jQuery.propHooks.selected = {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ return null;
+ }
+ };
+}
+
+jQuery.each([
+ "tabIndex",
+ "readOnly",
+ "maxLength",
+ "cellSpacing",
+ "cellPadding",
+ "rowSpan",
+ "colSpan",
+ "useMap",
+ "frameBorder",
+ "contentEditable"
+], function() {
+ jQuery.propFix[ this.toLowerCase() ] = this;
+});
+
+// IE6/7 call enctype encoding
+if ( !support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
+
+
+
+var rclass = /[\t\r\n\f]/g;
+
+jQuery.fn.extend({
+ addClass: function( value ) {
+ var classes, elem, cur, clazz, j, finalValue,
+ i = 0,
+ len = this.length,
+ proceed = typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call( this, j, this.className ) );
+ });
+ }
+
+ if ( proceed ) {
+ // The disjunction here is for better compressibility (see removeClass)
+ classes = ( value || "" ).match( rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ " "
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+
+ // only assign if different to avoid unneeded rendering.
+ finalValue = jQuery.trim( cur );
+ if ( elem.className !== finalValue ) {
+ elem.className = finalValue;
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, clazz, j, finalValue,
+ i = 0,
+ len = this.length,
+ proceed = arguments.length === 0 || typeof value === "string" && value;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, this.className ) );
+ });
+ }
+ if ( proceed ) {
+ classes = ( value || "" ).match( rnotwhite ) || [];
+
+ for ( ; i < len; i++ ) {
+ elem = this[ i ];
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( elem.className ?
+ ( " " + elem.className + " " ).replace( rclass, " " ) :
+ ""
+ );
+
+ if ( cur ) {
+ j = 0;
+ while ( (clazz = classes[j++]) ) {
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+
+ // only assign if different to avoid unneeded rendering.
+ finalValue = value ? jQuery.trim( cur ) : "";
+ if ( elem.className !== finalValue ) {
+ elem.className = finalValue;
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value;
+
+ if ( typeof stateVal === "boolean" && type === "string" ) {
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
+ }
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ classNames = value.match( rnotwhite ) || [];
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space separated list
+ if ( self.hasClass( className ) ) {
+ self.removeClass( className );
+ } else {
+ self.addClass( className );
+ }
+ }
+
+ // Toggle whole class name
+ } else if ( type === strundefined || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // If the element has a class name or if we're passed "false",
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+});
+
+
+
+
+// Return jQuery for attributes-only inclusion
+
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+});
+
+jQuery.fn.extend({
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+ }
+});
+
+
+var nonce = jQuery.now();
+
+var rquery = (/\?/);
+
+
+
+var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
+
+jQuery.parseJSON = function( data ) {
+ // Attempt to parse using the native JSON parser first
+ if ( window.JSON && window.JSON.parse ) {
+ // Support: Android 2.3
+ // Workaround failure to string-cast null input
+ return window.JSON.parse( data + "" );
+ }
+
+ var requireNonComma,
+ depth = null,
+ str = jQuery.trim( data + "" );
+
+ // Guard against invalid (and possibly dangerous) input by ensuring that nothing remains
+ // after removing valid tokens
+ return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) {
+
+ // Force termination if we see a misplaced comma
+ if ( requireNonComma && comma ) {
+ depth = 0;
+ }
+
+ // Perform no more replacements after returning to outermost depth
+ if ( depth === 0 ) {
+ return token;
+ }
+
+ // Commas must not follow "[", "{", or ","
+ requireNonComma = open || comma;
+
+ // Determine new depth
+ // array/object open ("[" or "{"): depth += true - false (increment)
+ // array/object close ("]" or "}"): depth += false - true (decrement)
+ // other cases ("," or primitive): depth += true - true (numeric cast)
+ depth += !close - !open;
+
+ // Remove this token
+ return "";
+ }) ) ?
+ ( Function( "return " + str ) )() :
+ jQuery.error( "Invalid JSON: " + data );
+};
+
+
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+ var xml, tmp;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ try {
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data, "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+ } catch( e ) {
+ xml = undefined;
+ }
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+};
+
+
+var
+ // Document location
+ ajaxLocParts,
+ ajaxLocation,
+
+ rhash = /#.*$/,
+ rts = /([?&])_=[^&]*/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = "*/".concat("*");
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+ ajaxLocation = location.href;
+} catch( e ) {
+ // Use the href attribute of an A element
+ // since IE will modify it given document.location
+ ajaxLocation = document.createElement( "a" );
+ ajaxLocation.href = "";
+ ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ var dataType,
+ i = 0,
+ dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
+
+ if ( jQuery.isFunction( func ) ) {
+ // For each dataType in the dataTypeExpression
+ while ( (dataType = dataTypes[i++]) ) {
+ // Prepend if requested
+ if ( dataType.charAt( 0 ) === "+" ) {
+ dataType = dataType.slice( 1 ) || "*";
+ (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
+
+ // Otherwise append
+ } else {
+ (structure[ dataType ] = structure[ dataType ] || []).push( func );
+ }
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+ var inspected = {},
+ seekingTransport = ( structure === transports );
+
+ function inspect( dataType ) {
+ var selected;
+ inspected[ dataType ] = true;
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+ if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+ options.dataTypes.unshift( dataTypeOrTransport );
+ inspect( dataTypeOrTransport );
+ return false;
+ } else if ( seekingTransport ) {
+ return !( selected = dataTypeOrTransport );
+ }
+ });
+ return selected;
+ }
+
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var deep, key,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+
+ return target;
+}
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+ var firstDataType, ct, finalDataType, type,
+ contents = s.contents,
+ dataTypes = s.dataTypes;
+
+ // Remove auto dataType and get content-type in the process
+ while ( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+ var conv2, current, conv, tmp, prev,
+ converters = {},
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice();
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ current = dataTypes.shift();
+
+ // Convert to each sequential dataType
+ while ( current ) {
+
+ if ( s.responseFields[ current ] ) {
+ jqXHR[ s.responseFields[ current ] ] = response;
+ }
+
+ // Apply the dataFilter if provided
+ if ( !prev && isSuccess && s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ prev = current;
+ current = dataTypes.shift();
+
+ if ( current ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current === "*" ) {
+
+ current = prev;
+
+ // Convert response if prev dataType is non-auto and differs from current
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Seek a direct converter
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+ // If none found, seek a pair
+ if ( !conv ) {
+ for ( conv2 in converters ) {
+
+ // If conv2 outputs current
+ tmp = conv2.split( " " );
+ if ( tmp[ 1 ] === current ) {
+
+ // If prev can be converted to accepted input
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
+ converters[ "* " + tmp[ 0 ] ];
+ if ( conv ) {
+ // Condense equivalence converters
+ if ( conv === true ) {
+ conv = converters[ conv2 ];
+
+ // Otherwise, insert the intermediate dataType
+ } else if ( converters[ conv2 ] !== true ) {
+ current = tmp[ 0 ];
+ dataTypes.unshift( tmp[ 1 ] );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Apply converter (if not an equivalence)
+ if ( conv !== true ) {
+
+ // Unless errors are allowed to bubble, catch and return them
+ if ( conv && s[ "throws" ] ) {
+ response = conv( response );
+ } else {
+ try {
+ response = conv( response );
+ } catch ( e ) {
+ return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return { state: "success", data: response };
+}
+
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajaxSettings: {
+ url: ajaxLocation,
+ type: "GET",
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ global: true,
+ processData: true,
+ async: true,
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ throws: false,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ "*": allTypes,
+ text: "text/plain",
+ html: "text/html",
+ xml: "application/xml, text/xml",
+ json: "application/json, text/javascript"
+ },
+
+ contents: {
+ xml: /xml/,
+ html: /html/,
+ json: /json/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText",
+ json: "responseJSON"
+ },
+
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
+ converters: {
+
+ // Convert anything to text
+ "* text": String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": jQuery.parseJSON,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ url: true,
+ context: true
+ }
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ return settings ?
+
+ // Building a settings object
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+ // Extending ajaxSettings
+ ajaxExtend( jQuery.ajaxSettings, target );
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var // Cross-domain detection vars
+ parts,
+ // Loop variable
+ i,
+ // URL without anti-cache param
+ cacheURL,
+ // Response headers as string
+ responseHeadersString,
+ // timeout handle
+ timeoutTimer,
+
+ // To know if global events are to be dispatched
+ fireGlobals,
+
+ transport,
+ // Response headers
+ responseHeaders,
+ // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
+ globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks("once memory"),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+ // The jqXHR state
+ state = 0,
+ // Default abort message
+ strAbort = "canceled",
+ // Fake xhr
+ jqXHR = {
+ readyState: 0,
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( state === 2 ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while ( (match = rheaders.exec( responseHeadersString )) ) {
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() ];
+ }
+ return match == null ? null : match;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ var lname = name.toLowerCase();
+ if ( !state ) {
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Status-dependent callbacks
+ statusCode: function( map ) {
+ var code;
+ if ( map ) {
+ if ( state < 2 ) {
+ for ( code in map ) {
+ // Lazy-add the new callback in a way that preserves old ones
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+ }
+ } else {
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ }
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ var finalText = statusText || strAbort;
+ if ( transport ) {
+ transport.abort( finalText );
+ }
+ done( 0, finalText );
+ return this;
+ }
+ };
+
+ // Attach deferreds
+ deferred.promise( jqXHR ).complete = completeDeferred.add;
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Alias method option to type as per ticket #12004
+ s.type = options.method || options.type || s.method || s.type;
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
+
+ // A cross-domain request is in order when we have a protocol:host:port mismatch
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( state === 2 ) {
+ return jqXHR;
+ }
+
+ // We can fire global events as of now if asked to
+ // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
+ fireGlobals = jQuery.event && s.global;
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger("ajaxStart");
+ }
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Save the URL in case we're toying with the If-Modified-Since
+ // and/or If-None-Match header later on
+ cacheURL = s.url;
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+ s.url = rts.test( cacheURL ) ?
+
+ // If there is already a '_' parameter, set its value
+ cacheURL.replace( rts, "$1_=" + nonce++ ) :
+
+ // Otherwise add one to the end
+ cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
+ }
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+ }
+ if ( jQuery.etag[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already and return
+ return jqXHR.abort();
+ }
+
+ // aborting is no longer a cancellation
+ strAbort = "abort";
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout(function() {
+ jqXHR.abort("timeout");
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch ( e ) {
+ // Propagate exception as error if not done
+ if ( state < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ // Callback for when everything is done
+ function done( status, nativeStatusText, responses, headers ) {
+ var isSuccess, success, error, response, modified,
+ statusText = nativeStatusText;
+
+ // Called once
+ if ( state === 2 ) {
+ return;
+ }
+
+ // State is "done" now
+ state = 2;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ // Determine if successful
+ isSuccess = status >= 200 && status < 300 || status === 304;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // Convert no matter what (that way responseXXX fields are always set)
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+ // If successful, handle type chaining
+ if ( isSuccess ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ modified = jqXHR.getResponseHeader("Last-Modified");
+ if ( modified ) {
+ jQuery.lastModified[ cacheURL ] = modified;
+ }
+ modified = jqXHR.getResponseHeader("etag");
+ if ( modified ) {
+ jQuery.etag[ cacheURL ] = modified;
+ }
+ }
+
+ // if no content
+ if ( status === 204 || s.type === "HEAD" ) {
+ statusText = "nocontent";
+
+ // if not modified
+ } else if ( status === 304 ) {
+ statusText = "notmodified";
+
+ // If we have data, let's convert it
+ } else {
+ statusText = response.state;
+ success = response.data;
+ error = response.error;
+ isSuccess = !error;
+ }
+ } else {
+ // We extract error from statusText
+ // then normalize statusText and status for non-aborts
+ error = statusText;
+ if ( status || !statusText ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger("ajaxStop");
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ }
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
+ });
+ };
+});
+
+
+jQuery._evalUrl = function( url ) {
+ return jQuery.ajax({
+ url: url,
+ type: "GET",
+ dataType: "script",
+ async: false,
+ global: false,
+ "throws": true
+ });
+};
+
+
+jQuery.fn.extend({
+ wrapAll: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[0] ) {
+ // The elements to wrap the target around
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+ if ( this[0].parentNode ) {
+ wrap.insertBefore( this[0] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+ elem = elem.firstChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function(i) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ }
+});
+
+
+jQuery.expr.filters.hidden = function( elem ) {
+ // Support: Opera <= 12.12
+ // Opera reports offsetWidths and offsetHeights less than zero on some elements
+ return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
+ (!support.reliableHiddenOffsets() &&
+ ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+};
+
+jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+};
+
+
+
+
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+};
+
+jQuery.fn.extend({
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map(function() {
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ })
+ .filter(function() {
+ var type = this.type;
+ // Use .is(":disabled") so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !rcheckableType.test( type ) );
+ })
+ .map(function( i, elem ) {
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val ) {
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ?
+ // Support: IE6+
+ function() {
+
+ // XHR cannot access local files, always use ActiveX for that case
+ return !this.isLocal &&
+
+ // Support: IE7-8
+ // oldIE XHR does not support non-RFC2616 methods (#13240)
+ // See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx
+ // and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
+ // Although this check for six methods instead of eight
+ // since IE also does not support "trace" and "connect"
+ /^(get|post|head|put|delete|options)$/i.test( this.type ) &&
+
+ createStandardXHR() || createActiveXHR();
+ } :
+ // For all other browsers, use the standard XMLHttpRequest object
+ createStandardXHR;
+
+var xhrId = 0,
+ xhrCallbacks = {},
+ xhrSupported = jQuery.ajaxSettings.xhr();
+
+// Support: IE<10
+// Open requests must be manually aborted on unload (#5280)
+// See https://support.microsoft.com/kb/2856746 for more info
+if ( window.attachEvent ) {
+ window.attachEvent( "onunload", function() {
+ for ( var key in xhrCallbacks ) {
+ xhrCallbacks[ key ]( undefined, true );
+ }
+ });
+}
+
+// Determine support properties
+support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+xhrSupported = support.ajax = !!xhrSupported;
+
+// Create transport if the browser can provide an xhr
+if ( xhrSupported ) {
+
+ jQuery.ajaxTransport(function( options ) {
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( !options.crossDomain || support.cors ) {
+
+ var callback;
+
+ return {
+ send: function( headers, complete ) {
+ var i,
+ xhr = options.xhr(),
+ id = ++xhrId;
+
+ // Open the socket
+ xhr.open( options.type, options.url, options.async, options.username, options.password );
+
+ // Apply custom fields if provided
+ if ( options.xhrFields ) {
+ for ( i in options.xhrFields ) {
+ xhr[ i ] = options.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( options.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( options.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !options.crossDomain && !headers["X-Requested-With"] ) {
+ headers["X-Requested-With"] = "XMLHttpRequest";
+ }
+
+ // Set headers
+ for ( i in headers ) {
+ // Support: IE<9
+ // IE's ActiveXObject throws a 'Type Mismatch' exception when setting
+ // request header to a null-value.
+ //
+ // To keep consistent with other XHR implementations, cast the value
+ // to string and ignore `undefined`.
+ if ( headers[ i ] !== undefined ) {
+ xhr.setRequestHeader( i, headers[ i ] + "" );
+ }
+ }
+
+ // Do send the request
+ // This may raise an exception which is actually
+ // handled in jQuery.ajax (so no try/catch here)
+ xhr.send( ( options.hasContent && options.data ) || null );
+
+ // Listener
+ callback = function( _, isAbort ) {
+ var status, statusText, responses;
+
+ // Was never called and is aborted or complete
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+ // Clean up
+ delete xhrCallbacks[ id ];
+ callback = undefined;
+ xhr.onreadystatechange = jQuery.noop;
+
+ // Abort manually if needed
+ if ( isAbort ) {
+ if ( xhr.readyState !== 4 ) {
+ xhr.abort();
+ }
+ } else {
+ responses = {};
+ status = xhr.status;
+
+ // Support: IE<10
+ // Accessing binary-data responseText throws an exception
+ // (#11426)
+ if ( typeof xhr.responseText === "string" ) {
+ responses.text = xhr.responseText;
+ }
+
+ // Firefox throws an exception when accessing
+ // statusText for faulty cross-domain requests
+ try {
+ statusText = xhr.statusText;
+ } catch( e ) {
+ // We normalize with Webkit giving an empty statusText
+ statusText = "";
+ }
+
+ // Filter status for non standard behaviors
+
+ // If the request is local and we have data: assume a success
+ // (success with no data won't get notified, that's the best we
+ // can do given current implementations)
+ if ( !status && options.isLocal && !options.crossDomain ) {
+ status = responses.text ? 200 : 404;
+ // IE - #1450: sometimes returns 1223 when it should be 204
+ } else if ( status === 1223 ) {
+ status = 204;
+ }
+ }
+ }
+
+ // Call complete if needed
+ if ( responses ) {
+ complete( status, statusText, responses, xhr.getAllResponseHeaders() );
+ }
+ };
+
+ if ( !options.async ) {
+ // if we're in sync mode we fire the callback
+ callback();
+ } else if ( xhr.readyState === 4 ) {
+ // (IE6 & IE7) if it's in cache and has been
+ // retrieved directly we need to fire the callback
+ setTimeout( callback );
+ } else {
+ // Add to the list of active xhr callbacks
+ xhr.onreadystatechange = xhrCallbacks[ id ] = callback;
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback( undefined, true );
+ }
+ }
+ };
+ }
+ });
+}
+
+// Functions to create xhrs
+function createStandardXHR() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch( e ) {}
+}
+
+function createActiveXHR() {
+ try {
+ return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+ } catch( e ) {}
+}
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+ accepts: {
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /(?:java|ecma)script/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ s.global = false;
+ }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
+
+ var script,
+ head = document.head || jQuery("head")[0] || document.documentElement;
+
+ return {
+
+ send: function( _, callback ) {
+
+ script = document.createElement("script");
+
+ script.async = true;
+
+ if ( s.scriptCharset ) {
+ script.charset = s.scriptCharset;
+ }
+
+ script.src = s.url;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+ if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+ // Handle memory leak in IE
+ script.onload = script.onreadystatechange = null;
+
+ // Remove the script
+ if ( script.parentNode ) {
+ script.parentNode.removeChild( script );
+ }
+
+ // Dereference the script
+ script = null;
+
+ // Callback if not abort
+ if ( !isAbort ) {
+ callback( 200, "success" );
+ }
+ }
+ };
+
+ // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
+ head.insertBefore( script, head.firstChild );
+ },
+
+ abort: function() {
+ if ( script ) {
+ script.onload( undefined, true );
+ }
+ }
+ };
+ }
+});
+
+
+
+
+var oldCallbacks = [],
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
+ this[ callback ] = true;
+ return callback;
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var callbackName, overwritten, responseContainer,
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+ "url" :
+ typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
+ );
+
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+ // Get callback name, remembering preexisting value associated with it
+ callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
+ s.jsonpCallback() :
+ s.jsonpCallback;
+
+ // Insert callback into url or form data
+ if ( jsonProp ) {
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+ } else if ( s.jsonp !== false ) {
+ s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+ }
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( callbackName + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Install callback
+ overwritten = window[ callbackName ];
+ window[ callbackName ] = function() {
+ responseContainer = arguments;
+ };
+
+ // Clean-up function (fires after converters)
+ jqXHR.always(function() {
+ // Restore preexisting value
+ window[ callbackName ] = overwritten;
+
+ // Save back as free
+ if ( s[ callbackName ] ) {
+ // make sure that re-using the options doesn't screw things around
+ s.jsonpCallback = originalSettings.jsonpCallback;
+
+ // save the callback name for future use
+ oldCallbacks.push( callbackName );
+ }
+
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( overwritten ) ) {
+ overwritten( responseContainer[ 0 ] );
+ }
+
+ responseContainer = overwritten = undefined;
+ });
+
+ // Delegate to script
+ return "script";
+ }
+});
+
+
+
+
+// data: string of html
+// context (optional): If specified, the fragment will be created in this context, defaults to document
+// keepScripts (optional): If true, will include scripts passed in the html string
+jQuery.parseHTML = function( data, context, keepScripts ) {
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+ context = context || document;
+
+ var parsed = rsingleTag.exec( data ),
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[1] ) ];
+ }
+
+ parsed = jQuery.buildFragment( [ data ], context, scripts );
+
+ if ( scripts && scripts.length ) {
+ jQuery( scripts ).remove();
+ }
+
+ return jQuery.merge( [], parsed.childNodes );
+};
+
+
+// Keep a copy of the old load method
+var _load = jQuery.fn.load;
+
+/**
+ * Load a url into a page
+ */
+jQuery.fn.load = function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+ }
+
+ var selector, response, type,
+ self = this,
+ off = url.indexOf(" ");
+
+ if ( off >= 0 ) {
+ selector = jQuery.trim( url.slice( off, url.length ) );
+ url = url.slice( 0, off );
+ }
+
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( params && typeof params === "object" ) {
+ type = "POST";
+ }
+
+ // If we have elements to modify, make the request
+ if ( self.length > 0 ) {
+ jQuery.ajax({
+ url: url,
+
+ // if "type" variable is undefined, then "GET" method will be used
+ type: type,
+ dataType: "html",
+ data: params
+ }).done(function( responseText ) {
+
+ // Save response for use in complete callback
+ response = arguments;
+
+ self.html( selector ?
+
+ // If a selector was specified, locate the right elements in a dummy div
+ // Exclude scripts to avoid IE 'Permission Denied' errors
+ jQuery("").append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+ // Otherwise use the full result
+ responseText );
+
+ }).complete( callback && function( jqXHR, status ) {
+ self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
+ });
+ }
+
+ return this;
+};
+
+
+
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
+ jQuery.fn[ type ] = function( fn ) {
+ return this.on( type, fn );
+ };
+});
+
+
+
+
+jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+};
+
+
+
+
+
+var docElem = window.document.documentElement;
+
+/**
+ * Gets a window from an element
+ */
+function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ?
+ elem :
+ elem.nodeType === 9 ?
+ elem.defaultView || elem.parentWindow :
+ false;
+}
+
+jQuery.offset = {
+ setOffset: function( elem, options, i ) {
+ var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+ position = jQuery.css( elem, "position" ),
+ curElem = jQuery( elem ),
+ props = {};
+
+ // set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ curOffset = curElem.offset();
+ curCSSTop = jQuery.css( elem, "top" );
+ curCSSLeft = jQuery.css( elem, "left" );
+ calculatePosition = ( position === "absolute" || position === "fixed" ) &&
+ jQuery.inArray("auto", [ curCSSTop, curCSSLeft ] ) > -1;
+
+ // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+jQuery.fn.extend({
+ offset: function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ var docElem, win,
+ box = { top: 0, left: 0 },
+ elem = this[ 0 ],
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return;
+ }
+
+ docElem = doc.documentElement;
+
+ // Make sure it's not a disconnected DOM node
+ if ( !jQuery.contains( docElem, elem ) ) {
+ return box;
+ }
+
+ // If we don't have gBCR, just use 0,0 rather than error
+ // BlackBerry 5, iOS 3 (original iPhone)
+ if ( typeof elem.getBoundingClientRect !== strundefined ) {
+ box = elem.getBoundingClientRect();
+ }
+ win = getWindow( doc );
+ return {
+ top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
+ left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
+ };
+ },
+
+ position: function() {
+ if ( !this[ 0 ] ) {
+ return;
+ }
+
+ var offsetParent, offset,
+ parentOffset = { top: 0, left: 0 },
+ elem = this[ 0 ];
+
+ // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+ // we assume that getBoundingClientRect is available when computed position is fixed
+ offset = elem.getBoundingClientRect();
+ } else {
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent();
+
+ // Get correct offsets
+ offset = this.offset();
+ if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
+ parentOffset = offsetParent.offset();
+ }
+
+ // Add offsetParent borders
+ parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
+ }
+
+ // Subtract parent offsets and element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ return {
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || docElem;
+
+ while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent || docElem;
+ });
+ }
+});
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
+ var top = /Y/.test( prop );
+
+ jQuery.fn[ method ] = function( val ) {
+ return access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
+
+ if ( val === undefined ) {
+ return win ? (prop in win) ? win[ prop ] :
+ win.document.documentElement[ method ] :
+ elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : jQuery( win ).scrollLeft(),
+ top ? val : jQuery( win ).scrollTop()
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length, null );
+ };
+});
+
+// Add the top/left cssHooks using jQuery.fn.position
+// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+// getComputedStyle returns percent when specified for top/left/bottom/right
+// rather than make the css module depend on the offset module, we just check for it here
+jQuery.each( [ "top", "left" ], function( i, prop ) {
+ jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+ function( elem, computed ) {
+ if ( computed ) {
+ computed = curCSS( elem, prop );
+ // if curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( computed ) ?
+ jQuery( elem ).position()[ prop ] + "px" :
+ computed;
+ }
+ }
+ );
+});
+
+
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
+ // margin is only for outerHeight, outerWidth
+ jQuery.fn[ funcName ] = function( margin, value ) {
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+ return access( this, function( elem, type, value ) {
+ var doc;
+
+ if ( jQuery.isWindow( elem ) ) {
+ // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
+ // isn't a whole lot we can do. See pull request at this URL for discussion:
+ // https://github.com/jquery/jquery/pull/764
+ return elem.document.documentElement[ "client" + name ];
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ doc = elem.documentElement;
+
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
+ // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
+ return Math.max(
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
+ doc[ "client" + name ]
+ );
+ }
+
+ return value === undefined ?
+ // Get width or height on the element, requesting but not forcing parseFloat
+ jQuery.css( elem, type, extra ) :
+
+ // Set width or height on the element
+ jQuery.style( elem, type, value, extra );
+ }, type, chainable ? margin : undefined, chainable, null );
+ };
+ });
+});
+
+
+// The number of elements contained in the matched element set
+jQuery.fn.size = function() {
+ return this.length;
+};
+
+jQuery.fn.andSelf = jQuery.fn.addBack;
+
+
+
+
+// Register as a named AMD module, since jQuery can be concatenated with other
+// files that may use define, but not via a proper concatenation script that
+// understands anonymous AMD modules. A named AMD is safest and most robust
+// way to register. Lowercase jquery is used because AMD module names are
+// derived from file names, and jQuery is normally delivered in a lowercase
+// file name. Do this after creating the global so that if an AMD module wants
+// to call noConflict to hide this version of jQuery, it will work.
+
+// Note that for maximum portability, libraries that are not jQuery should
+// declare themselves as anonymous modules, and avoid setting a global if an
+// AMD loader is present. jQuery is a special case. For more information, see
+// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
+
+if ( typeof define === "function" && define.amd ) {
+ define( "jquery", [], function() {
+ return jQuery;
+ });
+}
+
+
+
+
+var
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$;
+
+jQuery.noConflict = function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+};
+
+// Expose jQuery and $ identifiers, even in
+// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// and CommonJS for browser emulators (#13566)
+if ( typeof noGlobal === strundefined ) {
+ window.jQuery = window.$ = jQuery;
+}
+
+
+
+
+return jQuery;
+
+}));
diff --git a/vendor/dg/adminer-custom/static/tabcomplete/README.markdown b/vendor/dg/adminer-custom/static/tabcomplete/README.markdown
new file mode 100755
index 0000000..ce703bb
--- /dev/null
+++ b/vendor/dg/adminer-custom/static/tabcomplete/README.markdown
@@ -0,0 +1,22 @@
+## Demo
+
+A GitHub-hosted demo can be found here:
+[View project page](http://erming.github.io/tabcomplete/)
+
+## Install
+
+Manual install:
+ 1. Download [tabcomplete.js](https://raw.githubusercontent.com/erming/tabcomplete/master/src/tabcomplete.js)
+ 2. Include source: ``
+
+With [NPM](https://www.npmjs.org/package/tabcomplete):
+[](https://www.npmjs.org/package/tabcomplete)
+
+## CDNJS
+
+tabcomplete is now available from [cdnjs](http://cdnjs.com/libraries/tabcomplete)!
+``````
+
+## License
+
+Available under [the MIT license](http://mths.be/mit).
diff --git a/vendor/dg/adminer-custom/static/tabcomplete/package.json b/vendor/dg/adminer-custom/static/tabcomplete/package.json
new file mode 100755
index 0000000..30037b6
--- /dev/null
+++ b/vendor/dg/adminer-custom/static/tabcomplete/package.json
@@ -0,0 +1,67 @@
+{
+ "name": "tabcomplete",
+ "author": {
+ "name": "Mattias Erming"
+ },
+ "version": "1.5.0",
+ "description": "Lightweight tab completion for inputs and textareas",
+ "homepage": "https://github.com/erming/tabcomplete",
+ "repository": {
+ "type": "git",
+ "url": "http://github.com/erming/tabcomplete"
+ },
+ "npmName": "tabcomplete",
+ "npmFileMap": [
+ {
+ "basePath": "/src/",
+ "files": [
+ "*.js"
+ ]
+ }
+ ],
+ "filename": "tabcomplete.js",
+ "license": "MIT",
+ "keywords": [
+ "tab",
+ "complete",
+ "autocomplete",
+ "hint",
+ "hinting",
+ "input",
+ "textarea"
+ ],
+ "dependencies": {
+ "jquery": ">=1.9"
+ },
+ "devDependencies": {
+ "grunt": "^0.4.5",
+ "grunt-contrib-uglify": "^0.4.0"
+ },
+ "gitHead": "06d988cc343428b71b2346742d296b6ff498531c",
+ "bugs": {
+ "url": "https://github.com/erming/tabcomplete/issues"
+ },
+ "_id": "tabcomplete@1.5.0",
+ "scripts": {},
+ "_shasum": "583affad188740aa6d1de2bbd841cc997dbb6ecd",
+ "_from": "tabcomplete@",
+ "_npmVersion": "2.1.5",
+ "_nodeVersion": "0.10.25",
+ "_npmUser": {
+ "name": "erming",
+ "email": "mattias@mattiaserming.com"
+ },
+ "maintainers": [
+ {
+ "name": "erming",
+ "email": "mattias@mattiaserming.com"
+ }
+ ],
+ "dist": {
+ "shasum": "583affad188740aa6d1de2bbd841cc997dbb6ecd",
+ "tarball": "http://registry.npmjs.org/tabcomplete/-/tabcomplete-1.5.0.tgz"
+ },
+ "directories": {},
+ "_resolved": "https://registry.npmjs.org/tabcomplete/-/tabcomplete-1.5.0.tgz",
+ "readme": "ERROR: No README data found!"
+}
diff --git a/vendor/dg/adminer-custom/static/tabcomplete/tabcomplete.js b/vendor/dg/adminer-custom/static/tabcomplete/tabcomplete.js
new file mode 100755
index 0000000..6f5ae46
--- /dev/null
+++ b/vendor/dg/adminer-custom/static/tabcomplete/tabcomplete.js
@@ -0,0 +1,254 @@
+/*!
+ * tabcomplete
+ * http://github.com/erming/tabcomplete
+ * v1.3.1
+ */
+(function($) {
+ var keys = {
+ backspace: 8,
+ tab: 9,
+ up: 38,
+ down: 40
+ };
+
+ $.tabcomplete = {};
+ $.tabcomplete.defaultOptions = {
+ after: "",
+ arrowKeys: false, // Allow the use of
and keys to iterate
+ hint: "placeholder", // "placeholder", "select", false
+ match: match,
+ caseSensitive: false,
+ minLength: 1,
+ wrapInput: true
+ };
+
+ $.fn.tab = // Alias
+ $.fn.tabcomplete = function(args, options) {
+ if (this.length > 1) {
+ return this.each(function() {
+ $(this).tabcomplete(args, options);
+ });
+ }
+
+ // Only enable the plugin on and elements.
+ var tag = this.prop("tagName");
+ if (tag != "INPUT" && tag != "TEXTAREA") {
+ return;
+ }
+
+ // Set default options.
+ this.options = options = $.extend(
+ $.tabcomplete.defaultOptions,
+ options
+ );
+
+ // Remove any leftovers.
+ // This allows us to override the plugin if necessary.
+ this.unbind(".tabcomplete");
+ this.prev(".hint").remove();
+
+ var self = this;
+ var backspace = false;
+ var i = -1;
+ var words = [];
+ var last = "";
+
+ var hint = $.noop;
+
+ // Determine what type of hinting to use.
+ switch (options.hint) {
+ case "placeholder":
+ hint = placeholder;
+ break;
+
+ case "select":
+ hint = select;
+ break;
+ }
+
+ this.on("input.tabcomplete", function() {
+ var input = self.val();
+ var word = input.split(/ |\n/).pop();
+
+ // Reset iteration.
+ i = -1;
+ last = "";
+ words = [];
+
+ // Check for matches if the current word is the last word.
+ if (self[0].selectionStart == input.length
+ && word.length) {
+ // Call the match() function to filter the words.
+ words = options.match(word, args, options.caseSensitive);
+
+ // Append 'after' to each word.
+ if (options.after) {
+ words = $.map(words, function(w) { return w + options.after; });
+ }
+ }
+
+ // Emit the number of matching words with the 'match' event.
+ self.trigger("match", words.length);
+
+ if (options.hint) {
+ if (!(options.hint == "select" && backspace) && word.length >= options.minLength) {
+ // Show hint.
+ hint.call(self, words[0]);
+ } else {
+ // Clear hinting.
+ // This call is needed when using backspace.
+ hint.call(self, "");
+ }
+ }
+
+ if (backspace) {
+ backspace = false;
+ }
+ });
+
+ this.on("keydown.tabcomplete", function(e) {
+ var key = e.which;
+ if (key == keys.tab
+ || (options.arrowKeys && (key == keys.up || key == keys.down))) {
+
+ // Don't lose focus on tab click.
+ e.preventDefault();
+
+ // Iterate the matches with tab and the up and down keys by incrementing
+ // or decrementing the 'i' variable.
+ if (key != keys.up) {
+ i++;
+ } else {
+ if (i == -1) return;
+ if (i == 0) {
+ // Jump to the last word.
+ i = words.length - 1;
+ } else {
+ i--;
+ }
+ }
+
+ // Get next match.
+ var word = words[i % words.length];
+ if (!word) {
+ return;
+ }
+
+ var value = self.val();
+ last = last || value.split(/ |\n/).pop();
+
+ // Return if the 'minLength' requirement isn't met.
+ if (last.length < options.minLength) {
+ return;
+ }
+
+ // Update element with the completed text.
+ var text = options.hint == "select" ? value : value.substr(0, self[0].selectionStart - last.length) + word;
+ self.val(text);
+
+ // Put the cursor at the end after completion.
+ // This isn't strictly necessary, but solves an issue with
+ // Internet Explorer.
+ if (options.hint == "select") {
+ self[0].selectionStart = text.length;
+ }
+
+ // Remember the word until next time.
+ last = word;
+
+ // Emit event.
+ self.trigger("tabcomplete", last);
+
+ if (options.hint) {
+ // Turn off any additional hinting.
+ hint.call(self, "");
+ }
+ } else if (e.which == keys.backspace) {
+ // Remember that backspace was pressed. This is used
+ // by the 'input' event.
+ backspace = true;
+
+ // Reset iteration.
+ i = -1;
+ last = "";
+ }
+ });
+
+ if (options.hint) {
+ // If enabled, turn on hinting.
+ hint.call(this, "");
+ }
+
+ return this;
+ }
+
+ // Simple matching.
+ // Filter the array and return the items that begins with 'word'.
+ function match(word, array, caseSensitive) {
+ return $.grep(
+ array,
+ function(w) {
+ if (caseSensitive) {
+ return !w.indexOf(word);
+ } else {
+ return !w.toLowerCase().indexOf(word.toLowerCase());
+ }
+ }
+ );
+ }
+
+ // Show placeholder text.
+ // This works by creating a copy of the input and placing it behind
+ // the real input.
+ function placeholder(word) {
+ var input = this;
+ var clone = input.prev(".hint");
+
+ input.css({
+ backgroundColor: "transparent",
+ position: "relative",
+ });
+
+ // Lets create a clone of the input if it does
+ // not already exist.
+ if (!clone.length) {
+ if (input.options.wrapInput) {
+ input.wrap(
+ $("").css({position: "relative", height: input.css("height"), display: input.css("display")})
+ );
+ }
+ clone = input
+ .clone()
+ .attr("tabindex", -1)
+ .removeAttr("id name placeholder")
+ .addClass("hint")
+ .insertBefore(input);
+ clone.css({
+ position: "absolute",
+ });
+ }
+
+ var hint = "";
+ if (typeof word !== "undefined") {
+ var value = input.val();
+ hint = value + word.substr(value.split(/ |\n/).pop().length);
+ }
+
+ clone.val(hint);
+ }
+
+ // Hint by selecting part of the suggested word.
+ function select(word) {
+ var input = this;
+ var value = input.val();
+ if (word) {
+ input.val(
+ value
+ + word.substr(value.split(/ |\n/).pop().length)
+ );
+
+ // Select hint.
+ input[0].selectionStart = value.length;
+ }
+ }
+})(jQuery);
diff --git a/vendor/kdyby/translation b/vendor/kdyby/translation
new file mode 160000
index 0000000..f057d03
--- /dev/null
+++ b/vendor/kdyby/translation
@@ -0,0 +1 @@
+Subproject commit f057d032e9043f841c9e994a70300dacf122bad4
diff --git a/vendor/latte/latte/composer.json b/vendor/latte/latte/composer.json
new file mode 100755
index 0000000..4821d24
--- /dev/null
+++ b/vendor/latte/latte/composer.json
@@ -0,0 +1,32 @@
+{
+ "name": "latte/latte",
+ "description": "Latte: the amazing template engine for PHP",
+ "keywords": ["templating", "twig"],
+ "homepage": "http://latte.nette.org",
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.1",
+ "ext-tokenizer": "*"
+ },
+ "require-dev": {
+ "nette/tester": "~1.3"
+ },
+ "suggest": {
+ "ext-mbstring": "to use filters like lower, upper, capitalize, ...",
+ "ext-fileinfo": "to use filter |datastream"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/latte/latte/license.md b/vendor/latte/latte/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/latte/latte/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/latte/latte/src/Latte/Compiler.php b/vendor/latte/latte/src/Latte/Compiler.php
new file mode 100755
index 0000000..14cad9a
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Compiler.php
@@ -0,0 +1,607 @@
+ IMacro[]] */
+ private $macros;
+
+ /** @var \SplObjectStorage */
+ private $macroHandlers;
+
+ /** @var HtmlNode */
+ private $htmlNode;
+
+ /** @var MacroNode */
+ private $macroNode;
+
+ /** @var string[] */
+ private $attrCodes = array();
+
+ /** @var string */
+ private $contentType;
+
+ /** @var array [context, subcontext] */
+ private $context;
+
+ /** @var string */
+ private $templateId;
+
+ /** @var mixed */
+ private $lastAttrValue;
+
+ /** Context-aware escaping content types */
+ const CONTENT_HTML = Engine::CONTENT_HTML,
+ CONTENT_XHTML = Engine::CONTENT_XHTML,
+ CONTENT_XML = Engine::CONTENT_XML,
+ CONTENT_JS = Engine::CONTENT_JS,
+ CONTENT_CSS = Engine::CONTENT_CSS,
+ CONTENT_URL = Engine::CONTENT_URL,
+ CONTENT_ICAL = Engine::CONTENT_ICAL,
+ CONTENT_TEXT = Engine::CONTENT_TEXT;
+
+ /** @internal Context-aware escaping HTML contexts */
+ const CONTEXT_COMMENT = 'comment',
+ CONTEXT_SINGLE_QUOTED_ATTR = "'",
+ CONTEXT_DOUBLE_QUOTED_ATTR = '"',
+ CONTEXT_UNQUOTED_ATTR = '=';
+
+
+ public function __construct()
+ {
+ $this->macroHandlers = new \SplObjectStorage;
+ }
+
+
+ /**
+ * Adds new macro.
+ * @param string
+ * @return self
+ */
+ public function addMacro($name, IMacro $macro)
+ {
+ $this->macros[$name][] = $macro;
+ $this->macroHandlers->attach($macro);
+ return $this;
+ }
+
+
+ /**
+ * Compiles tokens to PHP code.
+ * @param Token[]
+ * @return string
+ */
+ public function compile(array $tokens, $className)
+ {
+ $this->templateId = substr(md5($className), 0, 10);
+ $this->tokens = $tokens;
+ $output = '';
+ $this->output = & $output;
+ $this->htmlNode = $this->macroNode = $this->context = NULL;
+
+ foreach ($this->macroHandlers as $handler) {
+ $handler->initialize($this);
+ }
+
+ foreach ($tokens as $this->position => $token) {
+ $this->{"process$token->type"}($token);
+ }
+
+ while ($this->htmlNode) {
+ if (!empty($this->htmlNode->macroAttrs)) {
+ throw new CompileException('Missing ' . self::printEndTag($this->macroNode));
+ }
+ $this->htmlNode = $this->htmlNode->parentNode;
+ }
+
+ $prologs = $epilogs = '';
+ foreach ($this->macroHandlers as $handler) {
+ $res = $handler->finalize();
+ $handlerName = get_class($handler);
+ $prologs .= empty($res[0]) ? '' : "";
+ $epilogs = (empty($res[1]) ? '' : "") . $epilogs;
+ }
+ $output = ($prologs ? $prologs . "\n" : '') . $output . $epilogs;
+
+ if ($this->macroNode) {
+ throw new CompileException('Missing ' . self::printEndTag($this->macroNode));
+ }
+
+ $output = $this->expandTokens($output);
+ $output = "params as $__k => $__v) $$__k = $__v; unset($__k, $__v);'
+ . '?>' . $output . "contentType = $type;
+ $this->context = NULL;
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getContentType()
+ {
+ return $this->contentType;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setContext($context, $sub = NULL)
+ {
+ $this->context = array($context, $sub);
+ return $this;
+ }
+
+
+ /**
+ * @return array [context, subcontext]
+ */
+ public function getContext()
+ {
+ return $this->context;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getTemplateId()
+ {
+ return $this->templateId;
+ }
+
+
+ /**
+ * @return MacroNode|NULL
+ */
+ public function getMacroNode()
+ {
+ return $this->macroNode;
+ }
+
+
+ /**
+ * Returns current line number.
+ * @return int
+ */
+ public function getLine()
+ {
+ return $this->tokens ? $this->tokens[$this->position]->line : NULL;
+ }
+
+
+ /** @internal */
+ public function expandTokens($s)
+ {
+ return strtr($s, $this->attrCodes);
+ }
+
+
+ private function processText(Token $token)
+ {
+ if (in_array($this->context[0], array(self::CONTEXT_SINGLE_QUOTED_ATTR, self::CONTEXT_DOUBLE_QUOTED_ATTR), TRUE)) {
+ if ($token->text === $this->context[0]) {
+ $this->setContext(self::CONTEXT_UNQUOTED_ATTR);
+ } elseif ($this->lastAttrValue === '') {
+ $this->lastAttrValue = $token->text;
+ }
+ }
+ $this->output .= $token->text;
+ }
+
+
+ private function processMacroTag(Token $token)
+ {
+ if (in_array($this->context[0], array(self::CONTEXT_SINGLE_QUOTED_ATTR, self::CONTEXT_DOUBLE_QUOTED_ATTR, self::CONTEXT_UNQUOTED_ATTR), TRUE)) {
+ $this->lastAttrValue = TRUE;
+ }
+
+ $isRightmost = !isset($this->tokens[$this->position + 1])
+ || substr($this->tokens[$this->position + 1]->text, 0, 1) === "\n";
+
+ if ($token->name[0] === '/') {
+ $this->closeMacro((string) substr($token->name, 1), $token->value, $token->modifiers, $isRightmost);
+ } else {
+ $this->openMacro($token->name, $token->value, $token->modifiers, $isRightmost && !$token->empty);
+ if ($token->empty) {
+ $this->closeMacro($token->name, NULL, NULL, $isRightmost);
+ }
+ }
+ }
+
+
+ private function processHtmlTagBegin(Token $token)
+ {
+ if ($token->closing) {
+ while ($this->htmlNode) {
+ if (strcasecmp($this->htmlNode->name, $token->name) === 0) {
+ break;
+ }
+ if ($this->htmlNode->macroAttrs) {
+ throw new CompileException("Unexpected $token->name>, expecting " . self::printEndTag($this->macroNode));
+ }
+ $this->htmlNode = $this->htmlNode->parentNode;
+ }
+ if (!$this->htmlNode) {
+ $this->htmlNode = new HtmlNode($token->name);
+ }
+ $this->htmlNode->closing = TRUE;
+ $this->htmlNode->offset = strlen($this->output);
+ $this->setContext(NULL);
+
+ } elseif ($token->text === '') {
+ $this->output .= $token->text;
+ $this->setContext(NULL);
+ return;
+ }
+
+ $htmlNode = $this->htmlNode;
+ $end = '';
+
+ if (!$htmlNode->closing) {
+ $htmlNode->isEmpty = strpos($token->text, '/') !== FALSE;
+ if (in_array($this->contentType, array(self::CONTENT_HTML, self::CONTENT_XHTML), TRUE)) {
+ $emptyElement = isset(Helpers::$emptyElements[strtolower($htmlNode->name)]);
+ $htmlNode->isEmpty = $htmlNode->isEmpty || $emptyElement;
+ if ($htmlNode->isEmpty) { // auto-correct
+ $space = substr(strstr($token->text, '>'), 1);
+ if ($emptyElement) {
+ $token->text = ($this->contentType === self::CONTENT_XHTML ? ' />' : '>') . $space;
+ } else {
+ $token->text = '>';
+ $end = "$htmlNode->name>" . $space;
+ }
+ }
+ }
+ }
+
+ if ($htmlNode->macroAttrs) {
+ $code = substr($this->output, $htmlNode->offset) . $token->text;
+ $this->output = substr($this->output, 0, $htmlNode->offset);
+ $this->writeAttrsMacro($code);
+ } else {
+ $this->output .= $token->text . $end;
+ }
+
+ if ($htmlNode->isEmpty) {
+ $htmlNode->closing = TRUE;
+ if ($htmlNode->macroAttrs) {
+ $this->writeAttrsMacro($end);
+ }
+ }
+
+ $this->setContext(NULL);
+
+ if ($htmlNode->closing) {
+ $this->htmlNode = $this->htmlNode->parentNode;
+
+ } elseif ((($lower = strtolower($htmlNode->name)) === 'script' || $lower === 'style')
+ && (!isset($htmlNode->attrs['type']) || preg_match('#(java|j|ecma|live)script|json|css#i', $htmlNode->attrs['type']))
+ ) {
+ $this->setContext($lower === 'script' ? self::CONTENT_JS : self::CONTENT_CSS);
+ }
+ }
+
+
+ private function processHtmlAttribute(Token $token)
+ {
+ if (strncmp($token->name, Parser::N_PREFIX, strlen(Parser::N_PREFIX)) === 0) {
+ $name = substr($token->name, strlen(Parser::N_PREFIX));
+ if (isset($this->htmlNode->macroAttrs[$name])) {
+ throw new CompileException("Found multiple attributes $token->name.");
+
+ } elseif ($this->macroNode && $this->macroNode->htmlNode === $this->htmlNode) {
+ throw new CompileException("n:attributes must not appear inside macro; found $token->name inside {{$this->macroNode->name}}.");
+ }
+ $this->htmlNode->macroAttrs[$name] = $token->value;
+ return;
+ }
+
+ $this->lastAttrValue = & $this->htmlNode->attrs[$token->name];
+ $this->output .= $token->text;
+
+ if (in_array($token->value, array(self::CONTEXT_SINGLE_QUOTED_ATTR, self::CONTEXT_DOUBLE_QUOTED_ATTR), TRUE)) {
+ $this->lastAttrValue = '';
+ $contextMain = $token->value;
+ } else {
+ $this->lastAttrValue = $token->value;
+ $contextMain = self::CONTEXT_UNQUOTED_ATTR;
+ }
+
+ $context = NULL;
+ if (in_array($this->contentType, array(self::CONTENT_HTML, self::CONTENT_XHTML), TRUE)) {
+ $lower = strtolower($token->name);
+ if (substr($lower, 0, 2) === 'on') {
+ $context = self::CONTENT_JS;
+ } elseif ($lower === 'style') {
+ $context = self::CONTENT_CSS;
+ } elseif (in_array($lower, array('href', 'src', 'action', 'formaction'), TRUE)
+ || ($lower === 'data' && strtolower($this->htmlNode->name) === 'object')
+ ) {
+ $context = self::CONTENT_URL;
+ }
+ }
+
+ $this->setContext($contextMain, $context);
+ }
+
+
+ private function processComment(Token $token)
+ {
+ $isLeftmost = trim(substr($this->output, strrpos("\n$this->output", "\n"))) === '';
+ if (!$isLeftmost) {
+ $this->output .= substr($token->text, strlen(rtrim($token->text, "\n")));
+ }
+ }
+
+
+ /********************* macros ****************d*g**/
+
+
+ /**
+ * Generates code for {macro ...} to the output.
+ * @param string
+ * @param string
+ * @param string
+ * @param bool
+ * @return MacroNode
+ * @internal
+ */
+ public function openMacro($name, $args = NULL, $modifiers = NULL, $isRightmost = FALSE, $nPrefix = NULL)
+ {
+ $node = $this->expandMacro($name, $args, $modifiers, $nPrefix);
+ if ($node->isEmpty) {
+ $this->writeCode($node->openingCode, $this->output, $node->replaced, $isRightmost);
+ } else {
+ $this->macroNode = $node;
+ $node->saved = array(& $this->output, $isRightmost);
+ $this->output = & $node->content;
+ }
+ return $node;
+ }
+
+
+ /**
+ * Generates code for {/macro ...} to the output.
+ * @param string
+ * @param string
+ * @param string
+ * @param bool
+ * @return MacroNode
+ * @internal
+ */
+ public function closeMacro($name, $args = NULL, $modifiers = NULL, $isRightmost = FALSE, $nPrefix = NULL)
+ {
+ $node = $this->macroNode;
+
+ if (!$node || ($node->name !== $name && '' !== $name) || $modifiers
+ || ($args && $node->args && strncmp("$node->args ", "$args ", strlen($args) + 1))
+ || $nPrefix !== $node->prefix
+ ) {
+ $name = $nPrefix
+ ? "{$this->htmlNode->name}> for " . Parser::N_PREFIX . implode(' and ' . Parser::N_PREFIX, array_keys($this->htmlNode->macroAttrs))
+ : '{/' . $name . ($args ? ' ' . $args : '') . $modifiers . '}';
+ throw new CompileException("Unexpected $name" . ($node ? ', expecting ' . self::printEndTag($node) : ''));
+ }
+
+ $this->macroNode = $node->parentNode;
+ if (!$node->args) {
+ $node->setArgs($args);
+ }
+
+ $isLeftmost = $node->content ? trim(substr($this->output, strrpos("\n$this->output", "\n"))) === '' : FALSE;
+
+ $node->closing = TRUE;
+ $node->macro->nodeClosed($node);
+
+ $this->output = & $node->saved[0];
+ $this->writeCode($node->openingCode, $this->output, $node->replaced, $node->saved[1]);
+ $this->writeCode($node->closingCode, $node->content, $node->replaced, $isRightmost, $isLeftmost);
+ $this->output .= $node->content;
+ return $node;
+ }
+
+
+ private function writeCode($code, & $output, $replaced, $isRightmost, $isLeftmost = NULL)
+ {
+ if ($isRightmost) {
+ $leftOfs = strrpos("\n$output", "\n");
+ if ($isLeftmost === NULL) {
+ $isLeftmost = trim(substr($output, $leftOfs)) === '';
+ }
+ if ($replaced === NULL) {
+ $replaced = preg_match('#<\?php.*\secho\s#As', $code);
+ }
+ if ($isLeftmost && !$replaced) {
+ $output = substr($output, 0, $leftOfs); // alone macro without output -> remove indentation
+ } elseif (substr($code, -2) === '?>') {
+ $code .= "\n"; // double newline to avoid newline eating by PHP
+ }
+ }
+ $output .= $code;
+ }
+
+
+ /**
+ * Generates code for macro
to the output.
+ * @param string
+ * @return void
+ * @internal
+ */
+ public function writeAttrsMacro($code)
+ {
+ $attrs = $this->htmlNode->macroAttrs;
+ $left = $right = array();
+
+ foreach ($this->macros as $name => $foo) {
+ $attrName = MacroNode::PREFIX_INNER . "-$name";
+ if (isset($attrs[$attrName])) {
+ if ($this->htmlNode->closing) {
+ $left[] = array('closeMacro', $name, '', MacroNode::PREFIX_INNER);
+ } else {
+ array_unshift($right, array('openMacro', $name, $attrs[$attrName], MacroNode::PREFIX_INNER));
+ }
+ unset($attrs[$attrName]);
+ }
+ }
+
+ foreach (array_reverse($this->macros) as $name => $foo) {
+ $attrName = MacroNode::PREFIX_TAG . "-$name";
+ if (isset($attrs[$attrName])) {
+ $left[] = array('openMacro', $name, $attrs[$attrName], MacroNode::PREFIX_TAG);
+ array_unshift($right, array('closeMacro', $name, '', MacroNode::PREFIX_TAG));
+ unset($attrs[$attrName]);
+ }
+ }
+
+ foreach ($this->macros as $name => $foo) {
+ if (isset($attrs[$name])) {
+ if ($this->htmlNode->closing) {
+ $right[] = array('closeMacro', $name, '', MacroNode::PREFIX_NONE);
+ } else {
+ array_unshift($left, array('openMacro', $name, $attrs[$name], MacroNode::PREFIX_NONE));
+ }
+ unset($attrs[$name]);
+ }
+ }
+
+ if ($attrs) {
+ throw new CompileException('Unknown attribute ' . Parser::N_PREFIX
+ . implode(' and ' . Parser::N_PREFIX, array_keys($attrs)));
+ }
+
+ if (!$this->htmlNode->closing) {
+ $this->htmlNode->attrCode = & $this->attrCodes[$uniq = ' n:' . substr(lcg_value(), 2, 10)];
+ $code = substr_replace($code, $uniq, strrpos($code, '/>') ?: strrpos($code, '>'), 0);
+ }
+
+ foreach ($left as $item) {
+ $node = $this->{$item[0]}($item[1], $item[2], NULL, NULL, $item[3]);
+ if ($node->closing || $node->isEmpty) {
+ $this->htmlNode->attrCode .= $node->attrCode;
+ if ($node->isEmpty) {
+ unset($this->htmlNode->macroAttrs[$node->name]);
+ }
+ }
+ }
+
+ $this->output .= $code;
+
+ foreach ($right as $item) {
+ $node = $this->{$item[0]}($item[1], $item[2], NULL, NULL, $item[3]);
+ if ($node->closing) {
+ $this->htmlNode->attrCode .= $node->attrCode;
+ }
+ }
+
+ if ($right && substr($this->output, -2) === '?>') {
+ $this->output .= "\n";
+ }
+ }
+
+
+ /**
+ * Expands macro and returns node & code.
+ * @param string
+ * @param string
+ * @param string
+ * @return MacroNode
+ * @internal
+ */
+ public function expandMacro($name, $args, $modifiers = NULL, $nPrefix = NULL)
+ {
+ $inScript = in_array($this->context[0], array(self::CONTENT_JS, self::CONTENT_CSS), TRUE);
+
+ if (empty($this->macros[$name])) {
+ throw new CompileException("Unknown macro {{$name}}" . ($inScript ? ' (in JavaScript or CSS, try to put a space after bracket.)' : ''));
+ }
+
+ if ($this->context[1] === self::CONTENT_URL) {
+ $modifiers = preg_replace('#\|nosafeurl\s?(?=\||\z)#i', '', $modifiers, -1, $found);
+ if (!$found && !preg_match('#\|datastream(?=\s|\||\z)#i', $modifiers)) {
+ $modifiers .= '|safeurl';
+ }
+ }
+
+ $modifiers = preg_replace('#\|noescape\s?(?=\||\z)#i', '', $modifiers, -1, $found);
+ if (!$found && strpbrk($name, '=~%^&_')) {
+ $modifiers .= '|escape';
+ }
+
+ if (!$found && $inScript && $name === '=' && preg_match('#["\'] *\z#', $this->tokens[$this->position - 1]->text)) {
+ throw new CompileException("Do not place {$this->tokens[$this->position]->text} inside quotes.");
+ }
+
+ foreach (array_reverse($this->macros[$name]) as $macro) {
+ $node = new MacroNode($macro, $name, $args, $modifiers, $this->macroNode, $this->htmlNode, $nPrefix);
+ if ($macro->nodeOpened($node) !== FALSE) {
+ return $node;
+ }
+ }
+
+ throw new CompileException('Unknown ' . ($nPrefix
+ ? 'attribute ' . Parser::N_PREFIX . ($nPrefix === MacroNode::PREFIX_NONE ? '' : "$nPrefix-") . $name
+ : 'macro {' . $name . ($args ? " $args" : '') . '}'
+ ));
+ }
+
+
+ private static function printEndTag(MacroNode $node)
+ {
+ if ($node->prefix) {
+ return "{$node->htmlNode->name}> for " . Parser::N_PREFIX
+ . implode(' and ' . Parser::N_PREFIX, array_keys($node->htmlNode->macroAttrs));
+ } else {
+ return "{/$node->name}";
+ }
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Engine.php b/vendor/latte/latte/src/Latte/Engine.php
new file mode 100755
index 0000000..549fd1d
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Engine.php
@@ -0,0 +1,387 @@
+ array(), // dynamic
+ 'bytes' => 'Latte\Runtime\Filters::bytes',
+ 'capitalize' => 'Latte\Runtime\Filters::capitalize',
+ 'datastream' => 'Latte\Runtime\Filters::dataStream',
+ 'date' => 'Latte\Runtime\Filters::date',
+ 'escapecss' => 'Latte\Runtime\Filters::escapeCss',
+ 'escapehtml' => 'Latte\Runtime\Filters::escapeHtml',
+ 'escapehtmlcomment' => 'Latte\Runtime\Filters::escapeHtmlComment',
+ 'escapeical' => 'Latte\Runtime\Filters::escapeICal',
+ 'escapejs' => 'Latte\Runtime\Filters::escapeJs',
+ 'escapeurl' => 'rawurlencode',
+ 'escapexml' => 'Latte\Runtime\Filters::escapeXML',
+ 'firstupper' => 'Latte\Runtime\Filters::firstUpper',
+ 'implode' => 'implode',
+ 'indent' => 'Latte\Runtime\Filters::indent',
+ 'lower' => 'Latte\Runtime\Filters::lower',
+ 'nl2br' => 'Latte\Runtime\Filters::nl2br',
+ 'number' => 'number_format',
+ 'repeat' => 'str_repeat',
+ 'replace' => 'Latte\Runtime\Filters::replace',
+ 'replacere' => 'Latte\Runtime\Filters::replaceRe',
+ 'safeurl' => 'Latte\Runtime\Filters::safeUrl',
+ 'strip' => 'Latte\Runtime\Filters::strip',
+ 'striptags' => 'strip_tags',
+ 'substr' => 'Latte\Runtime\Filters::substring',
+ 'trim' => 'Latte\Runtime\Filters::trim',
+ 'truncate' => 'Latte\Runtime\Filters::truncate',
+ 'upper' => 'Latte\Runtime\Filters::upper',
+ );
+
+
+ /**
+ * Renders template to output.
+ * @return void
+ */
+ public function render($name, array $params = array())
+ {
+ $class = $this->getTemplateClass($name);
+ if (!class_exists($class, FALSE)) {
+ $this->loadCacheFile($name);
+ }
+
+ $template = new $class($params, $this, $name);
+ $template->render();
+ }
+
+
+ /**
+ * Renders template to string.
+ * @return string
+ */
+ public function renderToString($name, array $params = array())
+ {
+ ob_start();
+ try {
+ $this->render($name, $params);
+ } catch (\Exception $e) {
+ ob_end_clean();
+ throw $e;
+ }
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Compiles template to PHP code.
+ * @return string
+ */
+ public function compile($name)
+ {
+ foreach ($this->onCompile ?: array() as $cb) {
+ call_user_func(Helpers::checkCallback($cb), $this);
+ }
+ $this->onCompile = array();
+
+ $source = $this->getLoader()->getContent($name);
+
+ try {
+ $tokens = $this->getParser()->setContentType($this->contentType)
+ ->parse($source);
+
+ $code = $this->getCompiler()->setContentType($this->contentType)
+ ->compile($tokens, $this->getTemplateClass($name));
+
+ } catch (\Exception $e) {
+ if (!$e instanceof CompileException) {
+ $e = new CompileException("Thrown exception '{$e->getMessage()}'", NULL, $e);
+ }
+ $line = isset($tokens) ? $this->getCompiler()->getLine() : $this->getParser()->getLine();
+ throw $e->setSource($source, $line, $name);
+ }
+
+ if (!preg_match('#\n|\?#', $name)) {
+ $code = "" . $code;
+ }
+ $code = Helpers::optimizePhp($code);
+ return $code;
+ }
+
+
+ /**
+ * Compiles template to cache.
+ * @param string
+ * @return void
+ * @throws \LogicException
+ */
+ public function warmupCache($name)
+ {
+ if (!$this->tempDirectory) {
+ throw new \LogicException('Path to temporary directory is not set.');
+ }
+
+ $class = $this->getTemplateClass($name);
+ if (!class_exists($class, FALSE)) {
+ $this->loadCacheFile($name);
+ }
+ }
+
+
+ /**
+ * @return void
+ */
+ private function loadCacheFile($name)
+ {
+ if (!$this->tempDirectory) {
+ eval('?>' . $this->compile($name));
+ return;
+ }
+
+ $file = $this->getCacheFile($name);
+
+ if (!$this->isExpired($file, $name) && (@include $file) !== FALSE) { // @ - file may not exist
+ return;
+ }
+
+ if (!is_dir($this->tempDirectory)) {
+ @mkdir($this->tempDirectory); // @ - directory may already exist
+ }
+
+ $handle = fopen("$file.lock", 'c+');
+ if (!$handle || !flock($handle, LOCK_EX)) {
+ throw new \RuntimeException("Unable to acquire exclusive lock '$file.lock'.");
+ }
+
+ if (!is_file($file) || $this->isExpired($file, $name)) {
+ $code = $this->compile($name);
+ if (file_put_contents("$file.tmp", $code) !== strlen($code) || !rename("$file.tmp", $file)) {
+ @unlink("$file.tmp"); // @ - file may not exist
+ throw new \RuntimeException("Unable to create '$file'.");
+ }
+ }
+
+ if ((include $file) === FALSE) {
+ throw new \RuntimeException("Unable to load '$file'.");
+ }
+
+ flock($handle, LOCK_UN);
+ }
+
+
+ /**
+ * @param string
+ * @param string
+ * @return bool
+ */
+ private function isExpired($file, $name)
+ {
+ return $this->autoRefresh && $this->getLoader()->isExpired($name, (int) @filemtime($file)); // @ - file may not exist
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getCacheFile($name)
+ {
+ $file = $this->getTemplateClass($name);
+ if (preg_match('#\b\w.{10,50}$#', $name, $m)) {
+ $file = trim(preg_replace('#\W+#', '-', $m[0]), '-') . '-' . $file;
+ }
+ return $this->tempDirectory . '/' . $file . '.php';
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getTemplateClass($name)
+ {
+ return 'Template' . md5("$this->tempDirectory\00$name");
+ }
+
+
+ /**
+ * Registers run-time filter.
+ * @param string|NULL
+ * @param callable
+ * @return self
+ */
+ public function addFilter($name, $callback)
+ {
+ if ($name == NULL) { // intentionally ==
+ array_unshift($this->filters[NULL], $callback);
+ } else {
+ $this->filters[strtolower($name)] = $callback;
+ }
+ return $this;
+ }
+
+
+ /**
+ * Returns all run-time filters.
+ * @return callable[]
+ */
+ public function getFilters()
+ {
+ return $this->filters;
+ }
+
+
+ /**
+ * Call a run-time filter.
+ * @param string filter name
+ * @param array arguments
+ * @return mixed
+ */
+ public function invokeFilter($name, array $args)
+ {
+ $lname = strtolower($name);
+ if (!isset($this->filters[$lname])) {
+ $args2 = $args;
+ array_unshift($args2, $lname);
+ foreach ($this->filters[NULL] as $filter) {
+ $res = call_user_func_array(Helpers::checkCallback($filter), $args2);
+ if ($res !== NULL) {
+ return $res;
+ } elseif (isset($this->filters[$lname])) {
+ return call_user_func_array(Helpers::checkCallback($this->filters[$lname]), $args);
+ }
+ }
+ throw new \LogicException("Filter '$name' is not defined.");
+ }
+ return call_user_func_array(Helpers::checkCallback($this->filters[$lname]), $args);
+ }
+
+
+ /**
+ * Adds new macro.
+ * @return self
+ */
+ public function addMacro($name, IMacro $macro)
+ {
+ $this->getCompiler()->addMacro($name, $macro);
+ return $this;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setContentType($type)
+ {
+ $this->contentType = $type;
+ return $this;
+ }
+
+
+ /**
+ * Sets path to temporary directory.
+ * @return self
+ */
+ public function setTempDirectory($path)
+ {
+ $this->tempDirectory = $path;
+ return $this;
+ }
+
+
+ /**
+ * Sets auto-refresh mode.
+ * @return self
+ */
+ public function setAutoRefresh($on = TRUE)
+ {
+ $this->autoRefresh = (bool) $on;
+ return $this;
+ }
+
+
+ /**
+ * @return Parser
+ */
+ public function getParser()
+ {
+ if (!$this->parser) {
+ $this->parser = new Parser;
+ }
+ return $this->parser;
+ }
+
+
+ /**
+ * @return Compiler
+ */
+ public function getCompiler()
+ {
+ if (!$this->compiler) {
+ $this->compiler = new Compiler;
+ Macros\CoreMacros::install($this->compiler);
+ Macros\BlockMacros::install($this->compiler);
+ }
+ return $this->compiler;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setLoader(ILoader $loader)
+ {
+ $this->loader = $loader;
+ return $this;
+ }
+
+
+ /**
+ * @return ILoader
+ */
+ public function getLoader()
+ {
+ if (!$this->loader) {
+ $this->loader = new Loaders\FileLoader;
+ }
+ return $this->loader;
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Helpers.php b/vendor/latte/latte/src/Latte/Helpers.php
new file mode 100755
index 0000000..e49387d
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Helpers.php
@@ -0,0 +1,113 @@
+ 1,'hr' => 1,'br' => 1,'input' => 1,'meta' => 1,'area' => 1,'embed' => 1,'keygen' => 1,'source' => 1,'base' => 1,
+ 'col' => 1,'link' => 1,'param' => 1,'basefont' => 1,'frame' => 1,'isindex' => 1,'wbr' => 1,'command' => 1,'track' => 1,
+ );
+
+
+ /**
+ * Checks callback.
+ * @return callable
+ */
+ public static function checkCallback($callable)
+ {
+ if (!is_callable($callable, FALSE, $text)) {
+ throw new \InvalidArgumentException("Callback '$text' is not callable.");
+ }
+ return $callable;
+ }
+
+
+ /**
+ * Removes unnecessary blocks of PHP code.
+ * @param string
+ * @return string
+ */
+ public static function optimizePhp($source, $lineLength = 80)
+ {
+ $res = $php = '';
+ $lastChar = ';';
+ $tokens = new \ArrayIterator(token_get_all($source));
+ foreach ($tokens as $n => $token) {
+ if (is_array($token)) {
+ if ($token[0] === T_INLINE_HTML) {
+ $lastChar = '';
+ $res .= $token[1];
+
+ } elseif ($token[0] === T_CLOSE_TAG) {
+ $next = isset($tokens[$n + 1]) ? $tokens[$n + 1] : NULL;
+ if (substr($res, -1) !== '<' && preg_match('#^<\?php\s*\z#', $php)) {
+ $php = ''; // removes empty (?php ?), but retains ((?php ?)?php
+
+ } elseif (is_array($next) && $next[0] === T_OPEN_TAG && (!isset($tokens[$n + 2][1]) || $tokens[$n + 2][1] !== 'xml')) { // remove ?)(?php
+ if (!strspn($lastChar, ';{}:/')) {
+ $php .= $lastChar = ';';
+ }
+ if (substr($next[1], -1) === "\n") {
+ $php .= "\n";
+ }
+ $tokens->next();
+
+ } elseif ($next) {
+ $res .= preg_replace('#;?(\s)*\z#', '$1', $php) . $token[1]; // remove last semicolon before ?)
+ if (strlen($res) - strrpos($res, "\n") > $lineLength
+ && (!is_array($next) || strpos($next[1], "\n") === FALSE)
+ ) {
+ $res .= "\n";
+ }
+ $php = '';
+
+ } else { // remove last ?)
+ if (!strspn($lastChar, '};')) {
+ $php .= ';';
+ }
+ }
+
+ } elseif ($token[0] === T_ELSE || $token[0] === T_ELSEIF) {
+ if ($tokens[$n + 1] === ':' && $lastChar === '}') {
+ $php .= ';'; // semicolon needed in if(): ... if() ... else:
+ }
+ $lastChar = '';
+ $php .= $token[1];
+
+ } elseif ($token[0] === T_OPEN_TAG && $token[1] === '' && isset($tokens[$n + 1][1]) && $tokens[$n + 1][1] === 'xml') {
+ $lastChar = '';
+ $res .= '<?';
+ for ($tokens->next(); $tokens->valid(); $tokens->next()) {
+ $token = $tokens->current();
+ $res .= is_array($token) ? $token[1] : $token;
+ if ($token[0] === T_CLOSE_TAG) {
+ break;
+ }
+ }
+
+ } else {
+ if (!in_array($token[0], array(T_WHITESPACE, T_COMMENT, T_DOC_COMMENT, T_OPEN_TAG), TRUE)) {
+ $lastChar = '';
+ }
+ $php .= $token[1];
+ }
+ } else {
+ $php .= $lastChar = $token;
+ }
+ }
+ return $res . $php;
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/HtmlNode.php b/vendor/latte/latte/src/Latte/HtmlNode.php
new file mode 100755
index 0000000..2e43171
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/HtmlNode.php
@@ -0,0 +1,47 @@
+name = $name;
+ $this->parentNode = $parentNode;
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/ILoader.php b/vendor/latte/latte/src/Latte/ILoader.php
new file mode 100755
index 0000000..4307f86
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/ILoader.php
@@ -0,0 +1,35 @@
+isExpired($file, time())) {
+ touch($file);
+ }
+ return file_get_contents($file);
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isExpired($file, $time)
+ {
+ return @filemtime($file) > $time; // @ - stat may fail
+ }
+
+
+ /**
+ * Returns fully qualified template name.
+ * @return string
+ */
+ public function getChildName($file, $parent = NULL)
+ {
+ if ($parent && !preg_match('#/|\\\\|[a-z][a-z0-9+.-]*:#iA', $file)) {
+ $file = dirname($parent) . '/' . $file;
+ }
+ return $file;
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Loaders/StringLoader.php b/vendor/latte/latte/src/Latte/Loaders/StringLoader.php
new file mode 100755
index 0000000..d09a629
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Loaders/StringLoader.php
@@ -0,0 +1,47 @@
+macro = $macro;
+ $this->name = (string) $name;
+ $this->modifiers = (string) $modifiers;
+ $this->parentNode = $parentNode;
+ $this->htmlNode = $htmlNode;
+ $this->prefix = $prefix;
+ $this->data = new \stdClass;
+ $this->setArgs($args);
+ }
+
+
+ public function setArgs($args)
+ {
+ $this->args = (string) $args;
+ $this->tokenizer = new MacroTokens($this->args);
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/MacroTokens.php b/vendor/latte/latte/src/Latte/MacroTokens.php
new file mode 100755
index 0000000..5a2edd3
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/MacroTokens.php
@@ -0,0 +1,138 @@
+parse($input));
+ $this->ignored = array(self::T_COMMENT, self::T_WHITESPACE);
+ }
+
+
+ public function parse($s)
+ {
+ self::$tokenizer = self::$tokenizer ?: new Tokenizer(array(
+ self::T_WHITESPACE => '\s+',
+ self::T_COMMENT => '(?s)/\*.*?\*/',
+ self::T_STRING => Parser::RE_STRING,
+ self::T_KEYWORD => '(?:true|false|null|and|or|xor|clone|new|instanceof|return|continue|break|[A-Z_][A-Z0-9_]{2,})(?![\w\pL_])', // keyword or const
+ self::T_CAST => '\((?:expand|string|array|int|integer|float|bool|boolean|object)\)', // type casting
+ self::T_VARIABLE => '\$[\w\pL_]+',
+ self::T_NUMBER => '[+-]?[0-9]+(?:\.[0-9]+)?(?:e[0-9]+)?',
+ self::T_SYMBOL => '[\w\pL_]+(?:-[\w\pL_]+)*',
+ self::T_CHAR => '::|=>|->|\+\+|--|<<|>>|<=|>=|===|!==|==|!=|<>|&&|\|\||[^"\']', // =>, any char except quotes
+ ), 'u');
+ return self::$tokenizer->tokenize($s);
+ }
+
+
+ /**
+ * Appends simple token or string (will be parsed).
+ * @return self
+ */
+ public function append($val, $position = NULL)
+ {
+ if ($val != NULL) { // intentionally @
+ array_splice(
+ $this->tokens,
+ $position === NULL ? count($this->tokens) : $position, 0,
+ is_array($val) ? array($val) : $this->parse($val)
+ );
+ }
+ return $this;
+ }
+
+
+ /**
+ * Prepends simple token or string (will be parsed).
+ * @return self
+ */
+ public function prepend($val)
+ {
+ if ($val != NULL) { // intentionally @
+ array_splice($this->tokens, 0, 0, is_array($val) ? array($val) : $this->parse($val));
+ }
+ return $this;
+ }
+
+
+ /**
+ * Reads single token (optionally delimited by comma) from string.
+ * @param string
+ * @return string
+ */
+ public function fetchWord()
+ {
+ $words = $this->fetchWords();
+ return $words ? implode(':', $words) : FALSE;
+ }
+
+
+ /**
+ * Reads single tokens delimited by colon from string.
+ * @param string
+ * @return array
+ */
+ public function fetchWords()
+ {
+ do {
+ $words[] = $this->joinUntil(self::T_WHITESPACE, ',', ':');
+ } while ($this->nextToken(':'));
+
+ if (count($words) === 1 && ($space = $this->nextValue(self::T_WHITESPACE))
+ && (($dot = $this->nextValue('.')) || $this->isPrev('.')))
+ {
+ $words[0] .= $space . $dot . $this->joinUntil(',');
+ }
+ $this->nextToken(',');
+ $this->nextAll(self::T_WHITESPACE, self::T_COMMENT);
+ return $words === array('') ? array() : $words;
+ }
+
+
+ public function reset()
+ {
+ $this->depth = 0;
+ return parent::reset();
+ }
+
+
+ protected function next()
+ {
+ parent::next();
+ if ($this->isCurrent('[', '(', '{')) {
+ $this->depth++;
+ } elseif ($this->isCurrent(']', ')', '}')) {
+ $this->depth--;
+ }
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Macros/BlockMacros.php b/vendor/latte/latte/src/Latte/Macros/BlockMacros.php
new file mode 100755
index 0000000..4973818
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Macros/BlockMacros.php
@@ -0,0 +1,319 @@
+addMacro('include', array($me, 'macroInclude'));
+ $me->addMacro('includeblock', array($me, 'macroIncludeBlock'));
+ $me->addMacro('extends', array($me, 'macroExtends'));
+ $me->addMacro('layout', array($me, 'macroExtends'));
+ $me->addMacro('block', array($me, 'macroBlock'), array($me, 'macroBlockEnd'));
+ $me->addMacro('define', array($me, 'macroBlock'), array($me, 'macroBlockEnd'));
+ $me->addMacro('snippet', array($me, 'macroBlock'), array($me, 'macroBlockEnd'));
+ $me->addMacro('snippetArea', array($me, 'macroBlock'), array($me, 'macroBlockEnd'));
+ $me->addMacro('ifset', array($me, 'macroIfset'), '}');
+ $me->addMacro('elseifset', array($me, 'macroIfset'), '}');
+ }
+
+
+ /**
+ * Initializes before template parsing.
+ * @return void
+ */
+ public function initialize()
+ {
+ $this->namedBlocks = array();
+ $this->extends = NULL;
+ }
+
+
+ /**
+ * Finishes template parsing.
+ * @return array(prolog, epilog)
+ */
+ public function finalize()
+ {
+ // try close last block
+ $last = $this->getCompiler()->getMacroNode();
+ if ($last && $last->name === 'block') {
+ $this->getCompiler()->closeMacro($last->name);
+ }
+
+ $epilog = $prolog = array();
+
+ if ($this->namedBlocks) {
+ foreach ($this->namedBlocks as $name => $code) {
+ $func = '_lb' . substr(md5($this->getCompiler()->getTemplateId() . $name), 0, 10) . '_' . preg_replace('#[^a-z0-9_]#i', '_', $name);
+ $snippet = $name[0] === '_';
+ $prolog[] = "//\n// block $name\n//\n"
+ . "if (!function_exists(\$_b->blocks[" . var_export($name, TRUE) . "][] = '$func')) { "
+ . "function $func(\$_b, \$_args) { foreach (\$_args as \$__k => \$__v) \$\$__k = \$__v"
+ . ($snippet ? '; $_control->redrawControl(' . var_export((string) substr($name, 1), TRUE) . ', FALSE)' : '')
+ . "\n?>$codenamedBlocks || $this->extends) {
+ $prolog[] = '// template extending';
+
+ $prolog[] = '$_l->extends = '
+ . ($this->extends ? $this->extends : 'empty($_g->extended) && isset($_control) && $_control instanceof Nette\Application\UI\Presenter ? $_control->findLayoutTemplateFile() : NULL')
+ . '; $_g->extended = TRUE;';
+
+ $prolog[] = 'if ($_l->extends) { ' . ($this->namedBlocks ? 'ob_start();' : 'return $template->renderChildTemplate($_l->extends, get_defined_vars());') . '}';
+ }
+
+ return array(implode("\n\n", $prolog), implode("\n", $epilog));
+ }
+
+
+ /********************* macros ****************d*g**/
+
+
+ /**
+ * {include #block}
+ */
+ public function macroInclude(MacroNode $node, PhpWriter $writer)
+ {
+ $destination = $node->tokenizer->fetchWord(); // destination [,] [params]
+ if (!preg_match('~#|[\w-]+\z~A', $destination)) {
+ return FALSE;
+ }
+
+ $destination = ltrim($destination, '#');
+ $parent = $destination === 'parent';
+ if ($destination === 'parent' || $destination === 'this') {
+ for ($item = $node->parentNode; $item && $item->name !== 'block' && !isset($item->data->name); $item = $item->parentNode);
+ if (!$item) {
+ throw new CompileException("Cannot include $destination block outside of any block.");
+ }
+ $destination = $item->data->name;
+ }
+
+ $name = strpos($destination, '$') === FALSE ? var_export($destination, TRUE) : $destination;
+ if (isset($this->namedBlocks[$destination]) && !$parent) {
+ $cmd = "call_user_func(reset(\$_b->blocks[$name]), \$_b, %node.array? + get_defined_vars())";
+ } else {
+ $cmd = 'Latte\Macros\BlockMacrosRuntime::callBlock' . ($parent ? 'Parent' : '') . "(\$_b, $name, %node.array? + " . ($parent ? 'get_defined_vars' : '$template->getParameters') . '())';
+ }
+
+ if ($node->modifiers) {
+ return $writer->write("ob_start(); $cmd; echo %modify(ob_get_clean())");
+ } else {
+ return $writer->write($cmd);
+ }
+ }
+
+
+ /**
+ * {includeblock "file"}
+ */
+ public function macroIncludeBlock(MacroNode $node, PhpWriter $writer)
+ {
+ return $writer->write('ob_start(); $_b->templates[%var]->renderChildTemplate(%node.word, %node.array? + get_defined_vars()); echo rtrim(ob_get_clean())',
+ $this->getCompiler()->getTemplateId());
+ }
+
+
+ /**
+ * {extends auto | none | $var | "file"}
+ */
+ public function macroExtends(MacroNode $node, PhpWriter $writer)
+ {
+ if (!$node->args) {
+ throw new CompileException("Missing destination in {{$node->name}}");
+ }
+ if (!empty($node->parentNode)) {
+ throw new CompileException("{{$node->name}} must be placed outside any macro.");
+ }
+ if ($this->extends !== NULL) {
+ throw new CompileException("Multiple {{$node->name}} declarations are not allowed.");
+ }
+ if ($node->args === 'none') {
+ $this->extends = 'FALSE';
+ } elseif ($node->args === 'auto') {
+ $this->extends = '$_presenter->findLayoutTemplateFile()';
+ } else {
+ $this->extends = $writer->write('%node.word%node.args');
+ }
+ return;
+ }
+
+
+ /**
+ * {block [[#]name]}
+ * {snippet [name [,]] [tag]}
+ * {snippetArea [name]}
+ * {define [#]name}
+ */
+ public function macroBlock(MacroNode $node, PhpWriter $writer)
+ {
+ $name = $node->tokenizer->fetchWord();
+
+ if ($node->name === '#') {
+ trigger_error('Shortcut {#block} is deprecated.', E_USER_DEPRECATED);
+
+ } elseif ($node->name === 'block' && $name === FALSE) { // anonymous block
+ return $node->modifiers === '' ? '' : 'ob_start()';
+ }
+
+ $node->data->name = $name = ltrim($name, '#');
+ if ($name == NULL) {
+ if ($node->name === 'define') {
+ throw new CompileException('Missing block name.');
+ }
+
+ } elseif (strpos($name, '$') !== FALSE) { // dynamic block/snippet
+ if ($node->name === 'snippet') {
+ for ($parent = $node->parentNode; $parent && !($parent->name === 'snippet' || $parent->name === 'snippetArea'); $parent = $parent->parentNode);
+ if (!$parent) {
+ throw new CompileException('Dynamic snippets are allowed only inside static snippet/snippetArea.');
+ }
+ $parent->data->dynamic = TRUE;
+ $node->data->leave = TRUE;
+ $node->closingCode = "dynSnippets[\$_l->dynSnippetId] = ob_get_flush() ?>";
+
+ if ($node->prefix) {
+ $node->attrCode = $writer->write("dynSnippetId = \$_control->getSnippetId({$writer->formatWord($name)})) . '\"' ?>");
+ return $writer->write('ob_start()');
+ }
+ $tag = trim($node->tokenizer->fetchWord(), '<>');
+ $tag = $tag ? $tag : 'div';
+ $node->closingCode .= "\n$tag>";
+ return $writer->write("?>\n<$tag id=\"dynSnippetId = \$_control->getSnippetId({$writer->formatWord($name)}) ?>\">data->leave = TRUE;
+ $fname = $writer->formatWord($name);
+ $node->closingCode = 'name === 'define' ? '' : "call_user_func(reset(\$_b->blocks[$fname]), \$_b, get_defined_vars())") . ' ?>';
+ $func = '_lb' . substr(md5($this->getCompiler()->getTemplateId() . $name), 0, 10) . '_' . preg_replace('#[^a-z0-9_]#i', '_', $name);
+ return "\n\n//\n// block $name\n//\n"
+ . "if (!function_exists(\$_b->blocks[$fname]['{$this->getCompiler()->getTemplateId()}'] = '$func')) { "
+ . "function $func(\$_b, \$_args) { foreach (\$_args as \$__k => \$__v) \$\$__k = \$__v";
+ }
+ }
+
+ // static snippet/snippetArea
+ if ($node->name === 'snippet' || $node->name === 'snippetArea') {
+ if ($node->prefix && isset($node->htmlNode->attrs['id'])) {
+ throw new CompileException('Cannot combine HTML attribute id with n:snippet.');
+ }
+ $node->data->name = $name = '_' . $name;
+ }
+
+ if (isset($this->namedBlocks[$name])) {
+ throw new CompileException("Cannot redeclare static {$node->name} '$name'");
+ }
+
+ $prolog = $this->namedBlocks ? '' : "if (\$_l->extends) { ob_end_clean(); return \$template->renderChildTemplate(\$_l->extends, get_defined_vars()); }\n";
+ $this->namedBlocks[$name] = TRUE;
+
+ $include = 'call_user_func(reset($_b->blocks[%var]), $_b, ' . (($node->name === 'snippet' || $node->name === 'snippetArea') ? '$template->getParameters()' : 'get_defined_vars()') . ')';
+ if ($node->modifiers) {
+ $include = "ob_start(); $include; echo %modify(ob_get_clean())";
+ }
+
+ if ($node->name === 'snippet') {
+ if ($node->prefix) {
+ $node->attrCode = $writer->write('getSnippetId(%var) . \'"\' ?>', (string) substr($name, 1));
+ return $writer->write($prolog . $include, $name);
+ }
+ $tag = trim($node->tokenizer->fetchWord(), '<>');
+ $tag = $tag ? $tag : 'div';
+ return $writer->write("$prolog ?>\n<$tag id=\"getSnippetId(%var) ?>\">\n$tag>name === 'define') {
+ return $prolog;
+
+ } else { // block, snippetArea
+ return $writer->write($prolog . $include, $name);
+ }
+ }
+
+
+ /**
+ * {/block}
+ * {/snippet}
+ * {/snippetArea}
+ * {/define}
+ */
+ public function macroBlockEnd(MacroNode $node, PhpWriter $writer)
+ {
+ if (isset($node->data->name)) { // block, snippet, define
+ if ($node->name === 'snippet' && $node->prefix === MacroNode::PREFIX_NONE // n:snippet -> n:inner-snippet
+ && preg_match('#^.*? n:\w+>\n?#s', $node->content, $m1) && preg_match('#[ \t]*<[^<]+\z#s', $node->content, $m2)
+ ) {
+ $node->openingCode = $m1[0] . $node->openingCode;
+ $node->content = substr($node->content, strlen($m1[0]), -strlen($m2[0]));
+ $node->closingCode .= $m2[0];
+ }
+
+ if (empty($node->data->leave)) {
+ if ($node->name === 'snippetArea') {
+ $node->content = "snippetMode = isset(\$_snippetMode) && \$_snippetMode; ?>{$node->content}snippetMode = FALSE; ?>";
+ }
+ if (!empty($node->data->dynamic)) {
+ $node->content .= 'dynSnippets)) return $_l->dynSnippets; ?>';
+ }
+ if ($node->name === 'snippetArea') {
+ $node->content .= '';
+ }
+ $this->namedBlocks[$node->data->name] = $tmp = rtrim(ltrim($node->content, "\n"), " \t");
+ $node->content = substr_replace($node->content, $node->openingCode . "\n", strspn($node->content, "\n"), strlen($tmp));
+ $node->openingCode = '';
+ }
+
+ } elseif ($node->modifiers) { // anonymous block with modifier
+ return $writer->write('echo %modify(ob_get_clean())');
+ }
+ }
+
+
+ /**
+ * {ifset #block}
+ * {elseifset #block}
+ */
+ public function macroIfset(MacroNode $node, PhpWriter $writer)
+ {
+ if (!preg_match('~#|[\w-]+\z~A', $node->args)) {
+ return FALSE;
+ }
+ $list = array();
+ while (($name = $node->tokenizer->fetchWord()) !== FALSE) {
+ $list[] = preg_match('~#|[\w-]+\z~A', $name)
+ ? '$_b->blocks["' . ltrim($name, '#') . '"]'
+ : $writer->formatArgs(new Latte\MacroTokens($name));
+ }
+ return ($node->name === 'elseifset' ? '} else' : '')
+ . 'if (isset(' . implode(', ', $list) . ')) {';
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Macros/BlockMacrosRuntime.php b/vendor/latte/latte/src/Latte/Macros/BlockMacrosRuntime.php
new file mode 100755
index 0000000..896077c
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Macros/BlockMacrosRuntime.php
@@ -0,0 +1,47 @@
+blocks[$name])) {
+ throw new RuntimeException("Cannot include undefined block '$name'.");
+ }
+ $block = reset($context->blocks[$name]);
+ $block($context, $params);
+ }
+
+
+ /**
+ * Calls parent block.
+ * @return void
+ */
+ public static function callBlockParent(\stdClass $context, $name, array $params)
+ {
+ if (empty($context->blocks[$name]) || ($block = next($context->blocks[$name])) === FALSE) {
+ throw new RuntimeException("Cannot include undefined parent block '$name'.");
+ }
+ $block($context, $params);
+ prev($context->blocks[$name]);
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Macros/CoreMacros.php b/vendor/latte/latte/src/Latte/Macros/CoreMacros.php
new file mode 100755
index 0000000..0643529
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Macros/CoreMacros.php
@@ -0,0 +1,426 @@
+ value} set template parameter
+ * - {default var => value} set default template parameter
+ * - {dump $var}
+ * - {debugbreak}
+ * - {contentType ...} HTTP Content-Type header
+ * - {status ...} HTTP status
+ * - {l} {r} to display { }
+ */
+class CoreMacros extends MacroSet
+{
+
+
+ public static function install(Latte\Compiler $compiler)
+ {
+ $me = new static($compiler);
+
+ $me->addMacro('if', array($me, 'macroIf'), array($me, 'macroEndIf'));
+ $me->addMacro('elseif', '} elseif (%node.args) {');
+ $me->addMacro('else', array($me, 'macroElse'));
+ $me->addMacro('ifset', 'if (isset(%node.args)) {', '}');
+ $me->addMacro('elseifset', '} elseif (isset(%node.args)) {');
+ $me->addMacro('ifcontent', array($me, 'macroIfContent'), array($me, 'macroEndIfContent'));
+
+ $me->addMacro('switch', '$_l->switch[] = (%node.args); if (FALSE) {', '} array_pop($_l->switch)');
+ $me->addMacro('case', '} elseif (end($_l->switch) === (%node.args)) {');
+
+ $me->addMacro('foreach', '', array($me, 'macroEndForeach'));
+ $me->addMacro('for', 'for (%node.args) {', '}');
+ $me->addMacro('while', 'while (%node.args) {', '}');
+ $me->addMacro('continueIf', array($me, 'macroBreakContinueIf'));
+ $me->addMacro('breakIf', array($me, 'macroBreakContinueIf'));
+ $me->addMacro('first', 'if ($iterator->isFirst(%node.args)) {', '}');
+ $me->addMacro('last', 'if ($iterator->isLast(%node.args)) {', '}');
+ $me->addMacro('sep', 'if (!$iterator->isLast(%node.args)) {', '}');
+
+ $me->addMacro('var', array($me, 'macroVar'));
+ $me->addMacro('default', array($me, 'macroVar'));
+ $me->addMacro('dump', array($me, 'macroDump'));
+ $me->addMacro('debugbreak', array($me, 'macroDebugbreak'));
+ $me->addMacro('l', '?>{addMacro('r', '?>}addMacro('_', array($me, 'macroTranslate'), array($me, 'macroTranslate'));
+ $me->addMacro('=', array($me, 'macroExpr'));
+ $me->addMacro('?', array($me, 'macroExpr'));
+
+ $me->addMacro('capture', array($me, 'macroCapture'), array($me, 'macroCaptureEnd'));
+ $me->addMacro('include', array($me, 'macroInclude'));
+ $me->addMacro('use', array($me, 'macroUse'));
+ $me->addMacro('contentType', array($me, 'macroContentType'));
+ $me->addMacro('status', array($me, 'macroStatus'));
+ $me->addMacro('php', array($me, 'macroExpr'));
+
+ $me->addMacro('class', NULL, NULL, array($me, 'macroClass'));
+ $me->addMacro('attr', NULL, NULL, array($me, 'macroAttr'));
+ }
+
+
+ /**
+ * Finishes template parsing.
+ * @return array(prolog, epilog)
+ */
+ public function finalize()
+ {
+ return array('list($_b, $_g, $_l) = $template->initialize('
+ . var_export($this->getCompiler()->getTemplateId(), TRUE) . ', '
+ . var_export($this->getCompiler()->getContentType(), TRUE)
+ . ')');
+ }
+
+
+ /********************* macros ****************d*g**/
+
+
+ /**
+ * {if ...}
+ */
+ public function macroIf(MacroNode $node, PhpWriter $writer)
+ {
+ if ($node->data->capture = ($node->args === '')) {
+ return 'ob_start()';
+ }
+ if ($node->prefix === $node::PREFIX_TAG) {
+ return $writer->write($node->htmlNode->closing ? 'if (array_pop($_l->ifs)) {' : 'if ($_l->ifs[] = (%node.args)) {');
+ }
+ return $writer->write('if (%node.args) {');
+ }
+
+
+ /**
+ * {/if ...}
+ */
+ public function macroEndIf(MacroNode $node, PhpWriter $writer)
+ {
+ if ($node->data->capture) {
+ if ($node->args === '') {
+ throw new CompileException('Missing condition in {if} macro.');
+ }
+ return $writer->write('if (%node.args) '
+ . (isset($node->data->else) ? '{ ob_end_clean(); ob_end_flush(); }' : 'ob_end_flush();')
+ . ' else '
+ . (isset($node->data->else) ? '{ $_l->else = ob_get_contents(); ob_end_clean(); ob_end_clean(); echo $_l->else; }' : 'ob_end_clean();')
+ );
+ }
+ return '}';
+ }
+
+
+ /**
+ * {else}
+ */
+ public function macroElse(MacroNode $node, PhpWriter $writer)
+ {
+ $ifNode = $node->parentNode;
+ if ($ifNode && $ifNode->name === 'if' && $ifNode->data->capture) {
+ if (isset($ifNode->data->else)) {
+ throw new CompileException('Macro {if} supports only one {else}.');
+ }
+ $ifNode->data->else = TRUE;
+ return 'ob_start()';
+ }
+ return '} else {';
+ }
+
+
+ /**
+ * n:ifcontent
+ */
+ public function macroIfContent(MacroNode $node, PhpWriter $writer)
+ {
+ if (!$node->prefix) {
+ throw new CompileException("Unknown macro {{$node->name}}, use n:{$node->name} attribute.");
+ } elseif ($node->prefix !== MacroNode::PREFIX_NONE) {
+ throw new CompileException("Unknown attribute n:{$node->prefix}-{$node->name}, use n:{$node->name} attribute.");
+ }
+
+ return $writer->write('ob_start()');
+ }
+
+
+ /**
+ * n:ifcontent
+ */
+ public function macroEndIfContent(MacroNode $node, PhpWriter $writer)
+ {
+ preg_match('#(^.*?>)(.*)(<.*\z)#s', $node->content, $parts);
+ $node->content = $parts[1]
+ . ''
+ . $parts[2]
+ . 'ifcontent = ob_get_contents(); ob_end_flush() ?>'
+ . $parts[3];
+ return 'rtrim($_l->ifcontent) === "" ? ob_end_clean() : ob_end_flush()';
+ }
+
+
+ /**
+ * {_$var |modifiers}
+ */
+ public function macroTranslate(MacroNode $node, PhpWriter $writer)
+ {
+ if ($node->closing) {
+ return $writer->write('echo %modify($template->translate(ob_get_clean()))');
+
+ } elseif ($node->isEmpty = ($node->args !== '')) {
+ return $writer->write('echo %modify($template->translate(%node.args))');
+
+ } else {
+ return 'ob_start()';
+ }
+ }
+
+
+ /**
+ * {include "file" [,] [params]}
+ */
+ public function macroInclude(MacroNode $node, PhpWriter $writer)
+ {
+ $code = $writer->write('$_b->templates[%var]->renderChildTemplate(%node.word, %node.array? + $template->getParameters())',
+ $this->getCompiler()->getTemplateId());
+
+ if ($node->modifiers) {
+ return $writer->write('ob_start(); %raw; echo %modify(ob_get_clean())', $code);
+ } else {
+ return $code;
+ }
+ }
+
+
+ /**
+ * {use class MacroSet}
+ */
+ public function macroUse(MacroNode $node, PhpWriter $writer)
+ {
+ call_user_func(Latte\Helpers::checkCallback(array($node->tokenizer->fetchWord(), 'install')), $this->getCompiler())
+ ->initialize();
+ }
+
+
+ /**
+ * {capture $variable}
+ */
+ public function macroCapture(MacroNode $node, PhpWriter $writer)
+ {
+ $variable = $node->tokenizer->fetchWord();
+ if (substr($variable, 0, 1) !== '$') {
+ throw new CompileException("Invalid capture block variable '$variable'");
+ }
+ $node->data->variable = $variable;
+ return 'ob_start()';
+ }
+
+
+ /**
+ * {/capture}
+ */
+ public function macroCaptureEnd(MacroNode $node, PhpWriter $writer)
+ {
+ return $node->data->variable . $writer->write(' = %modify(ob_get_clean())');
+ }
+
+
+ /**
+ * {foreach ...}
+ */
+ public function macroEndForeach(MacroNode $node, PhpWriter $writer)
+ {
+ if ($node->modifiers !== '|noiterator' && preg_match('#\W(\$iterator|include|require|get_defined_vars)\W#', $this->getCompiler()->expandTokens($node->content))) {
+ $node->openingCode = 'its[] = new Latte\Runtime\CachingIterator('
+ . preg_replace('#(.*)\s+as\s+#i', '$1) as ', $writer->formatArgs(), 1) . ') { ?>';
+ $node->closingCode = 'its); $iterator = end($_l->its) ?>';
+ } else {
+ $node->openingCode = 'formatArgs() . ') { ?>';
+ $node->closingCode = '';
+ }
+ }
+
+
+ /**
+ * {breakIf ...}
+ * {continueIf ...}
+ */
+ public function macroBreakContinueIf(MacroNode $node, PhpWriter $writer)
+ {
+ $cmd = str_replace('If', '', $node->name);
+ if ($node->parentNode && $node->parentNode->prefix === $node::PREFIX_NONE) {
+ return $writer->write("if (%node.args) { echo \"{$node->parentNode->htmlNode->name}>\\n\"; $cmd; }");
+ }
+ return $writer->write("if (%node.args) $cmd");
+ }
+
+
+ /**
+ * n:class="..."
+ */
+ public function macroClass(MacroNode $node, PhpWriter $writer)
+ {
+ if (isset($node->htmlNode->attrs['class'])) {
+ throw new CompileException('It is not possible to combine class with n:class.');
+ }
+ return $writer->write('if ($_l->tmp = array_filter(%node.array)) echo \' class="\', %escape(implode(" ", array_unique($_l->tmp))), \'"\'');
+ }
+
+
+ /**
+ * n:attr="..."
+ */
+ public function macroAttr(MacroNode $node, PhpWriter $writer)
+ {
+ return $writer->write('echo Latte\Runtime\Filters::htmlAttributes(%node.array)');
+ }
+
+
+ /**
+ * {dump ...}
+ */
+ public function macroDump(MacroNode $node, PhpWriter $writer)
+ {
+ $args = $writer->formatArgs();
+ return $writer->write(
+ 'Tracy\Debugger::barDump(' . ($args ? "($args)" : 'get_defined_vars()'). ', %var)',
+ $args ?: 'variables'
+ );
+ }
+
+
+ /**
+ * {debugbreak ...}
+ */
+ public function macroDebugbreak(MacroNode $node, PhpWriter $writer)
+ {
+ return $writer->write(($node->args == NULL ? '' : 'if (!(%node.args)); else')
+ . 'if (function_exists("debugbreak")) debugbreak(); elseif (function_exists("xdebug_break")) xdebug_break()');
+ }
+
+
+ /**
+ * {var ...}
+ * {default ...}
+ */
+ public function macroVar(MacroNode $node, PhpWriter $writer)
+ {
+ if ($node->args === '' && $node->parentNode && $node->parentNode->name === 'switch') {
+ return '} else {';
+ }
+
+ $var = TRUE;
+ $tokens = $writer->preprocess();
+ $res = new Latte\MacroTokens;
+ while ($tokens->nextToken()) {
+ if ($var && $tokens->isCurrent(Latte\MacroTokens::T_SYMBOL, Latte\MacroTokens::T_VARIABLE)) {
+ if ($node->name === 'default') {
+ $res->append("'" . ltrim($tokens->currentValue(), '$') . "'");
+ } else {
+ $res->append('$' . ltrim($tokens->currentValue(), '$'));
+ }
+ $var = NULL;
+
+ } elseif ($tokens->isCurrent('=', '=>') && $tokens->depth === 0) {
+ $res->append($node->name === 'default' ? '=>' : '=');
+ $var = FALSE;
+
+ } elseif ($tokens->isCurrent(',') && $tokens->depth === 0) {
+ if ($var === NULL) {
+ $res->append($node->name === 'default' ? '=>NULL' : '=NULL');
+ }
+ $res->append($node->name === 'default' ? ',' : ';');
+ $var = TRUE;
+
+ } elseif ($var === NULL && $node->name === 'default' && !$tokens->isCurrent(Latte\MacroTokens::T_WHITESPACE)) {
+ throw new CompileException("Unexpected '{$tokens->currentValue()}' in {default $node->args}");
+
+ } else {
+ $res->append($tokens->currentToken());
+ }
+ }
+ if ($var === NULL) {
+ $res->append($node->name === 'default' ? '=>NULL' : '=NULL');
+ }
+ $out = $writer->quoteFilter($res)->joinAll();
+ return $node->name === 'default' ? "extract(array($out), EXTR_SKIP)" : $out;
+ }
+
+
+ /**
+ * {= ...}
+ * {? ...}
+ */
+ public function macroExpr(MacroNode $node, PhpWriter $writer)
+ {
+ return $writer->write(($node->name === '=' ? 'echo ' : '') . '%modify(%node.args)');
+ }
+
+
+ /**
+ * {contentType ...}
+ */
+ public function macroContentType(MacroNode $node, PhpWriter $writer)
+ {
+ if (strpos($node->args, 'xhtml') !== FALSE) {
+ $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_XHTML);
+
+ } elseif (strpos($node->args, 'html') !== FALSE) {
+ $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_HTML);
+
+ } elseif (strpos($node->args, 'xml') !== FALSE) {
+ $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_XML);
+
+ } elseif (strpos($node->args, 'javascript') !== FALSE) {
+ $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_JS);
+
+ } elseif (strpos($node->args, 'css') !== FALSE) {
+ $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_CSS);
+
+ } elseif (strpos($node->args, 'calendar') !== FALSE) {
+ $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_ICAL);
+
+ } else {
+ $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_TEXT);
+ }
+
+ // temporary solution
+ if (strpos($node->args, '/')) {
+ return $writer->write('header(%var)', "Content-Type: $node->args");
+ }
+ }
+
+
+ /**
+ * {status ...}
+ */
+ public function macroStatus(MacroNode $node, PhpWriter $writer)
+ {
+ return $writer->write((substr($node->args, -1) === '?' ? 'if (!headers_sent()) ' : '') .
+ 'header((isset($_SERVER["SERVER_PROTOCOL"]) ? $_SERVER["SERVER_PROTOCOL"] : "HTTP/1.1") . " " . %0.var, TRUE, %0.var)', (int) $node->args
+ );
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Macros/MacroSet.php b/vendor/latte/latte/src/Latte/Macros/MacroSet.php
new file mode 100755
index 0000000..07d94b7
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Macros/MacroSet.php
@@ -0,0 +1,140 @@
+compiler = $compiler;
+ }
+
+
+ public function addMacro($name, $begin, $end = NULL, $attr = NULL)
+ {
+ if (!$begin && !$end && !$attr) {
+ throw new \InvalidArgumentException("At least one argument must be specified for macro '$name'.");
+ }
+ foreach (array($begin, $end, $attr) as $arg) {
+ if ($arg && !is_string($arg)) {
+ Latte\Helpers::checkCallback($arg);
+ }
+ }
+
+ $this->macros[$name] = array($begin, $end, $attr);
+ $this->compiler->addMacro($name, $this);
+ return $this;
+ }
+
+
+ /**
+ * Initializes before template parsing.
+ * @return void
+ */
+ public function initialize()
+ {
+ }
+
+
+ /**
+ * Finishes template parsing.
+ * @return array(prolog, epilog)
+ */
+ public function finalize()
+ {
+ }
+
+
+ /**
+ * New node is found.
+ * @return bool
+ */
+ public function nodeOpened(MacroNode $node)
+ {
+ list($begin, $end, $attr) = $this->macros[$node->name];
+ $node->isEmpty = !$end;
+
+ if ($attr && $node->prefix === $node::PREFIX_NONE) {
+ $node->isEmpty = TRUE;
+ $this->compiler->setContext(Latte\Compiler::CONTEXT_DOUBLE_QUOTED_ATTR);
+ $res = $this->compile($node, $attr);
+ if ($res === FALSE) {
+ return FALSE;
+ } elseif (!$node->attrCode) {
+ $node->attrCode = "";
+ }
+ $this->compiler->setContext(NULL);
+
+ } elseif ($begin) {
+ $res = $this->compile($node, $begin);
+ if ($res === FALSE || ($node->isEmpty && $node->prefix)) {
+ return FALSE;
+ } elseif (!$node->openingCode) {
+ $node->openingCode = "";
+ }
+
+ } elseif (!$end) {
+ return FALSE;
+ }
+ }
+
+
+ /**
+ * Node is closed.
+ * @return void
+ */
+ public function nodeClosed(MacroNode $node)
+ {
+ if (isset($this->macros[$node->name][1])) {
+ $res = $this->compile($node, $this->macros[$node->name][1]);
+ if (!$node->closingCode) {
+ $node->closingCode = "";
+ }
+ }
+ }
+
+
+ /**
+ * Generates code.
+ * @return string
+ */
+ private function compile(MacroNode $node, $def)
+ {
+ $node->tokenizer->reset();
+ $writer = Latte\PhpWriter::using($node, $this->compiler);
+ if (is_string($def)) {
+ return $writer->write($def);
+ } else {
+ return call_user_func($def, $node, $writer);
+ }
+ }
+
+
+ /**
+ * @return Latte\Compiler
+ */
+ public function getCompiler()
+ {
+ return $this->compiler;
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Object.php b/vendor/latte/latte/src/Latte/Object.php
new file mode 100755
index 0000000..5ac4223
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Object.php
@@ -0,0 +1,66 @@
+ array('\\{(?![\\s\'"{}])', '\\}'), // {...}
+ 'double' => array('\\{\\{(?![\\s\'"{}])', '\\}\\}'), // {{...}}
+ 'asp' => array('<%\s*', '\s*%>'), /* <%...%> */
+ 'python' => array('\\{[{%]\s*', '\s*[%}]\\}'), // {% ... %} | {{ ... }}
+ 'off' => array('[^\x00-\xFF]', ''),
+ );
+
+ /** @var string[] */
+ private $delimiters;
+
+ /** @var string source template */
+ private $input;
+
+ /** @var Token[] */
+ private $output;
+
+ /** @var int position on source template */
+ private $offset;
+
+ /** @var array */
+ private $context;
+
+ /** @var string */
+ private $lastHtmlTag;
+
+ /** @var string used by filter() */
+ private $syntaxEndTag;
+
+ /** @var int */
+ private $syntaxEndLevel = 0;
+
+ /** @var bool */
+ private $xmlMode;
+
+ /** @internal states */
+ const CONTEXT_HTML_TEXT = 'htmlText',
+ CONTEXT_CDATA = 'cdata',
+ CONTEXT_HTML_TAG = 'htmlTag',
+ CONTEXT_HTML_ATTRIBUTE = 'htmlAttribute',
+ CONTEXT_RAW = 'raw',
+ CONTEXT_HTML_COMMENT = 'htmlComment',
+ CONTEXT_MACRO = 'macro';
+
+
+ /**
+ * Process all {macros} and .
+ * @param string
+ * @return Token[]
+ */
+ public function parse($input)
+ {
+ if (substr($input, 0, 3) === "\xEF\xBB\xBF") { // BOM
+ $input = substr($input, 3);
+ }
+ if (!preg_match('##u', $input)) {
+ throw new \InvalidArgumentException('Template is not valid UTF-8 stream.');
+ }
+ $input = str_replace("\r\n", "\n", $input);
+ $this->input = $input;
+ $this->output = array();
+ $this->offset = $tokenCount = 0;
+
+ $this->setSyntax($this->defaultSyntax);
+ $this->setContext(self::CONTEXT_HTML_TEXT);
+ $this->lastHtmlTag = $this->syntaxEndTag = NULL;
+
+ while ($this->offset < strlen($input)) {
+ if ($this->{'context' . $this->context[0]}() === FALSE) {
+ break;
+ }
+ while ($tokenCount < count($this->output)) {
+ $this->filter($this->output[$tokenCount++]);
+ }
+ }
+ if ($this->context[0] === self::CONTEXT_MACRO) {
+ throw new CompileException('Malformed macro');
+ }
+
+ if ($this->offset < strlen($input)) {
+ $this->addToken(Token::TEXT, substr($this->input, $this->offset));
+ }
+ return $this->output;
+ }
+
+
+ /**
+ * Handles CONTEXT_HTML_TEXT.
+ */
+ private function contextHtmlText()
+ {
+ $matches = $this->match('~
+ (?:(?<=\n|^)[ \t]*)?<(?P/?)(?P[a-z0-9:]+)| ## begin of HTML tag !--(?!>))| ## begin of HTML comment
+ (?P' . $this->delimiters[0] . ')
+ ~xsi');
+
+ if (!empty($matches['htmlcomment'])) { // )| ## end of HTML comment
+ (?P' . $this->delimiters[0] . ')
+ ~xsi');
+
+ if (!empty($matches['htmlcomment'])) { // -->
+ $this->addToken(Token::HTML_TAG_END, $matches[0]);
+ $this->setContext(self::CONTEXT_HTML_TEXT);
+ } else {
+ return $this->processMacro($matches);
+ }
+ }
+
+
+ /**
+ * Handles CONTEXT_RAW.
+ */
+ private function contextRaw()
+ {
+ $matches = $this->match('~
+ (?P' . $this->delimiters[0] . ')
+ ~xsi');
+ return $this->processMacro($matches);
+ }
+
+
+ /**
+ * Handles CONTEXT_MACRO.
+ */
+ private function contextMacro()
+ {
+ $matches = $this->match('~
+ (?P\\*.*?\\*' . $this->delimiters[1] . '\n{0,2})|
+ (?P(?:
+ ' . self::RE_STRING . '|
+ \{(?:' . self::RE_STRING . '|[^\'"{}])*+\}|
+ [^\'"{}]
+ )+?)
+ ' . $this->delimiters[1] . '
+ (?P[ \t]*(?=\n))?
+ ~xsiA');
+
+ if (!empty($matches['macro'])) {
+ $token = $this->addToken(Token::MACRO_TAG, $this->context[1][1] . $matches[0]);
+ list($token->name, $token->value, $token->modifiers, $token->empty) = $this->parseMacroTag($matches['macro']);
+ $this->context = $this->context[1][0];
+
+ } elseif (!empty($matches['comment'])) {
+ $this->addToken(Token::COMMENT, $this->context[1][1] . $matches[0]);
+ $this->context = $this->context[1][0];
+
+ } else {
+ throw new CompileException('Malformed macro');
+ }
+ }
+
+
+ private function processMacro($matches)
+ {
+ if (!empty($matches['macro'])) { // {macro} or {* *}
+ $this->setContext(self::CONTEXT_MACRO, array($this->context, $matches['macro']));
+ } else {
+ return FALSE;
+ }
+ }
+
+
+ /**
+ * Matches next token.
+ * @param string
+ * @return array
+ */
+ private function match($re)
+ {
+ if (!preg_match($re, $this->input, $matches, PREG_OFFSET_CAPTURE, $this->offset)) {
+ if (preg_last_error()) {
+ throw new RegexpException(NULL, preg_last_error());
+ }
+ return array();
+ }
+
+ $value = substr($this->input, $this->offset, $matches[0][1] - $this->offset);
+ if ($value !== '') {
+ $this->addToken(Token::TEXT, $value);
+ }
+ $this->offset = $matches[0][1] + strlen($matches[0][0]);
+ foreach ($matches as $k => $v) {
+ $matches[$k] = $v[0];
+ }
+ return $matches;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setContentType($type)
+ {
+ if (strpos($type, 'html') !== FALSE) {
+ $this->xmlMode = FALSE;
+ $this->setContext(self::CONTEXT_HTML_TEXT);
+ } elseif (strpos($type, 'xml') !== FALSE) {
+ $this->xmlMode = TRUE;
+ $this->setContext(self::CONTEXT_HTML_TEXT);
+ } else {
+ $this->setContext(self::CONTEXT_RAW);
+ }
+ return $this;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setContext($context, $quote = NULL)
+ {
+ $this->context = array($context, $quote);
+ return $this;
+ }
+
+
+ /**
+ * Changes macro tag delimiters.
+ * @param string
+ * @return self
+ */
+ public function setSyntax($type)
+ {
+ $type = $type ?: $this->defaultSyntax;
+ if (isset($this->syntaxes[$type])) {
+ $this->setDelimiters($this->syntaxes[$type][0], $this->syntaxes[$type][1]);
+ } else {
+ throw new \InvalidArgumentException("Unknown syntax '$type'");
+ }
+ return $this;
+ }
+
+
+ /**
+ * Changes macro tag delimiters.
+ * @param string left regular expression
+ * @param string right regular expression
+ * @return self
+ */
+ public function setDelimiters($left, $right)
+ {
+ $this->delimiters = array($left, $right);
+ return $this;
+ }
+
+
+ /**
+ * Parses macro tag to name, arguments a modifiers parts.
+ * @param string {name arguments | modifiers}
+ * @return array
+ * @internal
+ */
+ public function parseMacroTag($tag)
+ {
+ if (!preg_match('~^
+ (
+ (?P\?|/?[a-z]\w*+(?:[.:]\w+)*+(?!::|\(|\\\\))| ## ?, name, /name, but not function( or class:: or namespace\
+ (?P!?)(?P/?[=\~#%^&_]?) ## !expression, !=expression, ...
+ )(?P.*?)
+ (?P\|[a-z](?:' . self::RE_STRING . '|[^\'"])*(?/?\z)
+ ()\z~isx', $tag, $match)) {
+ if (preg_last_error()) {
+ throw new RegexpException(NULL, preg_last_error());
+ }
+ return FALSE;
+ }
+ if ($match['name'] === '') {
+ $match['name'] = $match['shortname'] ?: '=';
+ if ($match['noescape']) {
+ if (!$this->shortNoEscape) {
+ trigger_error("The noescape shortcut {!...} is deprecated, use {...|noescape} modifier on line {$this->getLine()}.", E_USER_DEPRECATED);
+ }
+ $match['modifiers'] .= '|noescape';
+ }
+ }
+ return array($match['name'], trim($match['args']), $match['modifiers'], (bool) $match['empty']);
+ }
+
+
+ private function addToken($type, $text)
+ {
+ $this->output[] = $token = new Token;
+ $token->type = $type;
+ $token->text = $text;
+ $token->line = $this->getLine();
+ return $token;
+ }
+
+
+ public function getLine()
+ {
+ return substr_count($this->input, "\n", 0, max(1, $this->offset - 1)) + 1;
+ }
+
+
+ /**
+ * Process low-level macros.
+ */
+ protected function filter(Token $token)
+ {
+ if ($token->type === Token::MACRO_TAG && $token->name === '/syntax') {
+ $this->setSyntax($this->defaultSyntax);
+ $token->type = Token::COMMENT;
+
+ } elseif ($token->type === Token::MACRO_TAG && $token->name === 'syntax') {
+ $this->setSyntax($token->value);
+ $token->type = Token::COMMENT;
+
+ } elseif ($token->type === Token::HTML_ATTRIBUTE && $token->name === 'n:syntax') {
+ $this->setSyntax($token->value);
+ $this->syntaxEndTag = $this->lastHtmlTag;
+ $this->syntaxEndLevel = 1;
+ $token->type = Token::COMMENT;
+
+ } elseif ($token->type === Token::HTML_TAG_BEGIN && $this->lastHtmlTag === $this->syntaxEndTag) {
+ $this->syntaxEndLevel++;
+
+ } elseif ($token->type === Token::HTML_TAG_END && $this->lastHtmlTag === ('/' . $this->syntaxEndTag) && --$this->syntaxEndLevel === 0) {
+ $this->setSyntax($this->defaultSyntax);
+
+ } elseif ($token->type === Token::MACRO_TAG && $token->name === 'contentType') {
+ $this->setContentType($token->value);
+ }
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/PhpWriter.php b/vendor/latte/latte/src/Latte/PhpWriter.php
new file mode 100755
index 0000000..0894cb2
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/PhpWriter.php
@@ -0,0 +1,393 @@
+tokenizer, $node->modifiers, $compiler);
+ }
+
+
+ public function __construct(MacroTokens $tokens, $modifiers = NULL, Compiler $compiler = NULL)
+ {
+ $this->tokens = $tokens;
+ $this->modifiers = $modifiers;
+ $this->compiler = $compiler;
+ }
+
+
+ /**
+ * Expands %node.word, %node.array, %node.args, %escape(), %modify(), %var, %raw, %word in code.
+ * @param string
+ * @return string
+ */
+ public function write($mask)
+ {
+ $mask = preg_replace('#%(node|\d+)\.#', '%$1_', $mask);
+ $me = $this;
+ $mask = preg_replace_callback('#%escape(\(([^()]*+|(?1))+\))#', function ($m) use ($me) {
+ return $me->escapeFilter(new MacroTokens(substr($m[1], 1, -1)))->joinAll();
+ }, $mask);
+ $mask = preg_replace_callback('#%modify(\(([^()]*+|(?1))+\))#', function ($m) use ($me) {
+ return $me->formatModifiers(substr($m[1], 1, -1));
+ }, $mask);
+
+ $args = func_get_args();
+ $pos = $this->tokens->position;
+ $word = strpos($mask, '%node_word') === FALSE ? NULL : $this->tokens->fetchWord();
+
+ $code = preg_replace_callback('#([,+]\s*)?%(node_|\d+_|)(word|var|raw|array|args)(\?)?(\s*\+\s*)?()#',
+ function ($m) use ($me, $word, & $args) {
+ list(, $l, $source, $format, $cond, $r) = $m;
+
+ switch ($source) {
+ case 'node_':
+ $arg = $word; break;
+ case '':
+ $arg = next($args); break;
+ default:
+ $arg = $args[$source + 1]; break;
+ }
+
+ switch ($format) {
+ case 'word':
+ $code = $me->formatWord($arg); break;
+ case 'args':
+ $code = $me->formatArgs(); break;
+ case 'array':
+ $code = $me->formatArray();
+ $code = $cond && $code === 'array()' ? '' : $code; break;
+ case 'var':
+ $code = var_export($arg, TRUE); break;
+ case 'raw':
+ $code = (string) $arg; break;
+ }
+
+ if ($cond && $code === '') {
+ return $r ? $l : $r;
+ } else {
+ return $l . $code . $r;
+ }
+ }, $mask);
+
+ $this->tokens->position = $pos;
+ return $code;
+ }
+
+
+ /**
+ * Formats modifiers calling.
+ * @param string
+ * @return string
+ */
+ public function formatModifiers($var)
+ {
+ $tokens = new MacroTokens(ltrim($this->modifiers, '|'));
+ $tokens = $this->preprocess($tokens);
+ $tokens = $this->modifiersFilter($tokens, $var);
+ $tokens = $this->quoteFilter($tokens);
+ return $tokens->joinAll();
+ }
+
+
+ /**
+ * Formats macro arguments to PHP code. (It advances tokenizer to the end as a side effect.)
+ * @return string
+ */
+ public function formatArgs(MacroTokens $tokens = NULL)
+ {
+ $tokens = $this->preprocess($tokens);
+ $tokens = $this->quoteFilter($tokens);
+ return $tokens->joinAll();
+ }
+
+
+ /**
+ * Formats macro arguments to PHP array. (It advances tokenizer to the end as a side effect.)
+ * @return string
+ */
+ public function formatArray(MacroTokens $tokens = NULL)
+ {
+ $tokens = $this->preprocess($tokens);
+ $tokens = $this->expandFilter($tokens);
+ $tokens = $this->quoteFilter($tokens);
+ return $tokens->joinAll();
+ }
+
+
+ /**
+ * Formats parameter to PHP string.
+ * @param string
+ * @return string
+ */
+ public function formatWord($s)
+ {
+ return (is_numeric($s) || preg_match('#^\$|[\'"]|^true\z|^false\z|^null\z#i', $s))
+ ? $this->formatArgs(new MacroTokens($s))
+ : '"' . $s . '"';
+ }
+
+
+ /**
+ * Preprocessor for tokens. (It advances tokenizer to the end as a side effect.)
+ * @return MacroTokens
+ */
+ public function preprocess(MacroTokens $tokens = NULL)
+ {
+ $tokens = $tokens === NULL ? $this->tokens : $tokens;
+ $tokens = $this->removeCommentsFilter($tokens);
+ $tokens = $this->shortTernaryFilter($tokens);
+ $tokens = $this->shortArraysFilter($tokens);
+ return $tokens;
+ }
+
+
+ /**
+ * Removes PHP comments.
+ * @return MacroTokens
+ */
+ public function removeCommentsFilter(MacroTokens $tokens)
+ {
+ $res = new MacroTokens;
+ while ($tokens->nextToken()) {
+ if (!$tokens->isCurrent(MacroTokens::T_COMMENT)) {
+ $res->append($tokens->currentToken());
+ }
+ }
+ return $res;
+ }
+
+
+ /**
+ * Simplified ternary expressions without third part.
+ * @return MacroTokens
+ */
+ public function shortTernaryFilter(MacroTokens $tokens)
+ {
+ $res = new MacroTokens;
+ $inTernary = array();
+ while ($tokens->nextToken()) {
+ if ($tokens->isCurrent('?')) {
+ $inTernary[] = $tokens->depth;
+
+ } elseif ($tokens->isCurrent(':')) {
+ array_pop($inTernary);
+
+ } elseif ($tokens->isCurrent(',', ')', ']') && end($inTernary) === $tokens->depth + !$tokens->isCurrent(',')) {
+ $res->append(' : NULL');
+ array_pop($inTernary);
+ }
+ $res->append($tokens->currentToken());
+ }
+
+ if ($inTernary) {
+ $res->append(' : NULL');
+ }
+ return $res;
+ }
+
+
+ /**
+ * Simplified array syntax [...]
+ * @return MacroTokens
+ */
+ public function shortArraysFilter(MacroTokens $tokens)
+ {
+ $res = new MacroTokens;
+ $arrays = array();
+ while ($tokens->nextToken()) {
+ if ($tokens->isCurrent('[')) {
+ if ($arrays[] = !$tokens->isPrev(']', ')', MacroTokens::T_SYMBOL, MacroTokens::T_VARIABLE, MacroTokens::T_KEYWORD)) {
+ $res->append('array(');
+ continue;
+
+ }
+ } elseif ($tokens->isCurrent(']')) {
+ if (array_pop($arrays) === TRUE) {
+ $res->append(')');
+ continue;
+ }
+ }
+ $res->append($tokens->currentToken());
+ }
+ return $res;
+ }
+
+
+ /**
+ * Pseudocast (expand).
+ * @return MacroTokens
+ */
+ public function expandFilter(MacroTokens $tokens)
+ {
+ $res = new MacroTokens('array(');
+ $expand = NULL;
+ while ($tokens->nextToken()) {
+ if ($tokens->isCurrent('(expand)') && $tokens->depth === 0) {
+ $expand = TRUE;
+ $res->append('),');
+ } elseif ($expand && $tokens->isCurrent(',') && !$tokens->depth) {
+ $expand = FALSE;
+ $res->append(', array(');
+ } else {
+ $res->append($tokens->currentToken());
+ }
+ }
+
+ if ($expand !== NULL) {
+ $res->prepend('array_merge(')->append($expand ? ', array()' : ')');
+ }
+ return $res->append(')');
+ }
+
+
+ /**
+ * Quotes symbols to strings.
+ * @return MacroTokens
+ */
+ public function quoteFilter(MacroTokens $tokens)
+ {
+ $res = new MacroTokens;
+ while ($tokens->nextToken()) {
+ $res->append($tokens->isCurrent(MacroTokens::T_SYMBOL)
+ && (!$tokens->isPrev() || $tokens->isPrev(',', '(', '[', '=>', ':', '?', '.', '<', '>', '<=', '>=', '===', '!==', '==', '!=', '<>', '&&', '||', '=', 'and', 'or', 'xor'))
+ && (!$tokens->isNext() || $tokens->isNext(',', ';', ')', ']', '=>', ':', '?', '.', '<', '>', '<=', '>=', '===', '!==', '==', '!=', '<>', '&&', '||', 'and', 'or', 'xor'))
+ ? "'" . $tokens->currentValue() . "'"
+ : $tokens->currentToken()
+ );
+ }
+ return $res;
+ }
+
+
+ /**
+ * Formats modifiers calling.
+ * @param MacroTokens
+ * @param string
+ * @throws CompileException
+ * @return MacroTokens
+ */
+ public function modifiersFilter(MacroTokens $tokens, $var)
+ {
+ $inside = FALSE;
+ $res = new MacroTokens($var);
+ while ($tokens->nextToken()) {
+ if ($tokens->isCurrent(MacroTokens::T_WHITESPACE)) {
+ $res->append(' ');
+
+ } elseif ($inside) {
+ if ($tokens->isCurrent(':', ',')) {
+ $res->append(', ');
+ $tokens->nextAll(MacroTokens::T_WHITESPACE);
+
+ } elseif ($tokens->isCurrent('|')) {
+ $res->append(')');
+ $inside = FALSE;
+
+ } else {
+ $res->append($tokens->currentToken());
+ }
+ } else {
+ if ($tokens->isCurrent(MacroTokens::T_SYMBOL)) {
+ if ($this->compiler && $tokens->isCurrent('escape')) {
+ $res = $this->escapeFilter($res);
+ $tokens->nextToken('|');
+ } elseif (!strcasecmp($tokens->currentValue(), 'safeurl')) {
+ $res->prepend('Latte\Runtime\Filters::safeUrl(');
+ $inside = TRUE;
+ } else {
+ $res->prepend('$template->' . $tokens->currentValue() . '(');
+ $inside = TRUE;
+ }
+ } else {
+ throw new CompileException("Modifier name must be alphanumeric string, '{$tokens->currentValue()}' given.");
+ }
+ }
+ }
+ if ($inside) {
+ $res->append(')');
+ }
+ return $res;
+ }
+
+
+ /**
+ * Escapes expression in tokens.
+ * @return MacroTokens
+ */
+ public function escapeFilter(MacroTokens $tokens)
+ {
+ $tokens = clone $tokens;
+ switch ($this->compiler->getContentType()) {
+ case Compiler::CONTENT_XHTML:
+ case Compiler::CONTENT_HTML:
+ $context = $this->compiler->getContext();
+ switch ($context[0]) {
+ case Compiler::CONTEXT_SINGLE_QUOTED_ATTR:
+ case Compiler::CONTEXT_DOUBLE_QUOTED_ATTR:
+ case Compiler::CONTEXT_UNQUOTED_ATTR:
+ if ($context[1] === Compiler::CONTENT_JS) {
+ $tokens->prepend('Latte\Runtime\Filters::escapeJs(')->append(')');
+ } elseif ($context[1] === Compiler::CONTENT_CSS) {
+ $tokens->prepend('Latte\Runtime\Filters::escapeCss(')->append(')');
+ }
+ $tokens->prepend('Latte\Runtime\Filters::escapeHtml(')->append($context[0] === Compiler::CONTEXT_SINGLE_QUOTED_ATTR ? ', ENT_QUOTES)' : ', ENT_COMPAT)');
+ if ($context[0] === Compiler::CONTEXT_UNQUOTED_ATTR) {
+ $tokens->prepend("'\"', ")->append(", '\"'");
+ }
+ return $tokens;
+ case Compiler::CONTEXT_COMMENT:
+ return $tokens->prepend('Latte\Runtime\Filters::escapeHtmlComment(')->append(')');
+ case Compiler::CONTENT_JS:
+ case Compiler::CONTENT_CSS:
+ return $tokens->prepend('Latte\Runtime\Filters::escape' . ucfirst($context[0]) . '(')->append(')');
+ default:
+ return $tokens->prepend('Latte\Runtime\Filters::escapeHtml(')->append(', ENT_NOQUOTES)');
+ }
+
+ case Compiler::CONTENT_XML:
+ $context = $this->compiler->getContext();
+ switch ($context[0]) {
+ case Compiler::CONTEXT_COMMENT:
+ return $tokens->prepend('Latte\Runtime\Filters::escapeHtmlComment(')->append(')');
+ default:
+ $tokens->prepend('Latte\Runtime\Filters::escapeXml(')->append(')');
+ if ($context[0] === Compiler::CONTEXT_UNQUOTED_ATTR) {
+ $tokens->prepend("'\"', ")->append(", '\"'");
+ }
+ return $tokens;
+ }
+
+ case Compiler::CONTENT_JS:
+ case Compiler::CONTENT_CSS:
+ case Compiler::CONTENT_ICAL:
+ return $tokens->prepend('Latte\Runtime\Filters::escape' . ucfirst($this->compiler->getContentType()) . '(')->append(')');
+ case Compiler::CONTENT_TEXT:
+ return $tokens;
+ default:
+ return $tokens->prepend('$template->escape(')->append(')');
+ }
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Runtime/CachingIterator.php b/vendor/latte/latte/src/Latte/Runtime/CachingIterator.php
new file mode 100755
index 0000000..7828d2c
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Runtime/CachingIterator.php
@@ -0,0 +1,235 @@
+getIterator();
+ } while ($iterator instanceof \IteratorAggregate);
+
+ } elseif ($iterator instanceof \Traversable) {
+ if (!$iterator instanceof \Iterator) {
+ $iterator = new \IteratorIterator($iterator);
+ }
+ } else {
+ throw new \InvalidArgumentException(sprintf('Invalid argument passed to foreach; array or Traversable expected, %s given.', is_object($iterator) ? get_class($iterator) : gettype($iterator)));
+ }
+
+ parent::__construct($iterator, 0);
+ }
+
+
+ /**
+ * Is the current element the first one?
+ * @param int grid width
+ * @return bool
+ */
+ public function isFirst($width = NULL)
+ {
+ return $this->counter === 1 || ($width && $this->counter !== 0 && (($this->counter - 1) % $width) === 0);
+ }
+
+
+ /**
+ * Is the current element the last one?
+ * @param int grid width
+ * @return bool
+ */
+ public function isLast($width = NULL)
+ {
+ return !$this->hasNext() || ($width && ($this->counter % $width) === 0);
+ }
+
+
+ /**
+ * Is the iterator empty?
+ * @return bool
+ */
+ public function isEmpty()
+ {
+ return $this->counter === 0;
+ }
+
+
+ /**
+ * Is the counter odd?
+ * @return bool
+ */
+ public function isOdd()
+ {
+ return $this->counter % 2 === 1;
+ }
+
+
+ /**
+ * Is the counter even?
+ * @return bool
+ */
+ public function isEven()
+ {
+ return $this->counter % 2 === 0;
+ }
+
+
+ /**
+ * Returns the counter.
+ * @return int
+ */
+ public function getCounter()
+ {
+ return $this->counter;
+ }
+
+
+ /**
+ * Returns the count of elements.
+ * @return int
+ */
+ public function count()
+ {
+ $inner = $this->getInnerIterator();
+ if ($inner instanceof \Countable) {
+ return $inner->count();
+
+ } else {
+ throw new \LogicException('Iterator is not countable.');
+ }
+ }
+
+
+ /**
+ * Forwards to the next element.
+ * @return void
+ */
+ public function next()
+ {
+ parent::next();
+ if (parent::valid()) {
+ $this->counter++;
+ }
+ }
+
+
+ /**
+ * Rewinds the Iterator.
+ * @return void
+ */
+ public function rewind()
+ {
+ parent::rewind();
+ $this->counter = parent::valid() ? 1 : 0;
+ }
+
+
+ /**
+ * Returns the next key.
+ * @return mixed
+ */
+ public function getNextKey()
+ {
+ return $this->getInnerIterator()->key();
+ }
+
+
+ /**
+ * Returns the next element.
+ * @return mixed
+ */
+ public function getNextValue()
+ {
+ return $this->getInnerIterator()->current();
+ }
+
+
+ /********************* Latte\Object behaviour + property accessor ****************d*g**/
+
+
+ /**
+ * Call to undefined method.
+ * @throws \LogicException
+ */
+ public function __call($name, $args)
+ {
+ throw new \LogicException(sprintf('Call to undefined method %s::%s().', get_class($this), $name));
+ }
+
+
+ /**
+ * Returns property value.
+ * @throws \LogicException if the property is not defined.
+ */
+ public function &__get($name)
+ {
+ if (method_exists($this, $m = 'get' . $name) || method_exists($this, $m = 'is' . $name)) {
+ $ret = $this->$m();
+ return $ret;
+ }
+ throw new \LogicException(sprintf('Cannot read an undeclared property %s::$%s.', get_class($this), $name));
+ }
+
+
+ /**
+ * Access to undeclared property.
+ * @throws \LogicException
+ */
+ public function __set($name, $value)
+ {
+ throw new \LogicException(sprintf('Cannot write to an undeclared property %s::$%s.', get_class($this), $name));
+ }
+
+
+ /**
+ * Is property defined?
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ return method_exists($this, 'get' . $name) || method_exists($this, 'is' . $name);
+ }
+
+
+ /**
+ * Access to undeclared property.
+ * @throws \LogicException
+ */
+ public function __unset($name)
+ {
+ throw new \LogicException(sprintf('Cannot unset the property %s::$%s.', get_class($this), $name));
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Runtime/Filters.php b/vendor/latte/latte/src/Latte/Runtime/Filters.php
new file mode 100755
index 0000000..7f2a6ff
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Runtime/Filters.php
@@ -0,0 +1,440 @@
+__toString(TRUE);
+ }
+ $s = (string) $s;
+ if ($quotes !== ENT_NOQUOTES && strpos($s, '`') !== FALSE && strpbrk($s, ' <>"\'') === FALSE) {
+ $s .= ' ';
+ }
+ return htmlSpecialChars($s, $quotes, 'UTF-8');
+ }
+
+
+ /**
+ * Escapes string for use inside HTML comments.
+ * @param string UTF-8 encoding
+ * @return string
+ */
+ public static function escapeHtmlComment($s)
+ {
+ $s = (string) $s;
+ if ($s && ($s[0] === '-' || $s[0] === '>' || $s[0] === '!')) {
+ $s = ' ' . $s;
+ }
+ return str_replace('-', '- ', $s); // dash is very problematic character in comments
+ }
+
+
+ /**
+ * Escapes string for use inside XML 1.0 template.
+ * @param string UTF-8 encoding
+ * @return string
+ */
+ public static function escapeXML($s)
+ {
+ // XML 1.0: \x09 \x0A \x0D and C1 allowed directly, C0 forbidden
+ // XML 1.1: \x00 forbidden directly and as a character reference,
+ // \x09 \x0A \x0D \x85 allowed directly, C0, C1 and \x7F allowed as character references
+ return htmlSpecialChars(preg_replace('#[\x00-\x08\x0B\x0C\x0E-\x1F]+#', '', $s), ENT_QUOTES, 'UTF-8');
+ }
+
+
+ /**
+ * Escapes string for use inside CSS template.
+ * @param string UTF-8 encoding
+ * @return string
+ */
+ public static function escapeCss($s)
+ {
+ // http://www.w3.org/TR/2006/WD-CSS21-20060411/syndata.html#q6
+ return addcslashes($s, "\x00..\x1F!\"#$%&'()*+,./:;<=>?@[\\]^`{|}~");
+ }
+
+
+ /**
+ * Escapes variables for use inside = 1) {
+ $s = preg_replace_callback('#<(textarea|pre).*?\\1#si', function ($m) {
+ return strtr($m[0], " \t\r\n", "\x1F\x1E\x1D\x1A");
+ }, $s);
+ if (preg_last_error()) {
+ throw new Latte\RegexpException(NULL, preg_last_error());
+ }
+ $s = preg_replace('#(?:^|[\r\n]+)(?=[^\r\n])#', '$0' . str_repeat($chars, $level), $s);
+ $s = strtr($s, "\x1F\x1E\x1D\x1A", " \t\r\n");
+ }
+ return $s;
+ }
+
+
+ /**
+ * Date/time formatting.
+ * @param string|int|DateTime|DateInterval
+ * @param string
+ * @return string
+ */
+ public static function date($time, $format = NULL)
+ {
+ if ($time == NULL) { // intentionally ==
+ return NULL;
+ }
+
+ if (!isset($format)) {
+ $format = self::$dateFormat;
+ }
+
+ if ($time instanceof \DateInterval) {
+ return $time->format($format);
+
+ } elseif (is_numeric($time)) {
+ $time = new \DateTime('@' . $time);
+ $time->setTimeZone(new \DateTimeZone(date_default_timezone_get()));
+
+ } elseif (!$time instanceof \DateTime && !$time instanceof \DateTimeInterface) {
+ $time = new \DateTime($time);
+ }
+ return strpos($format, '%') === FALSE
+ ? $time->format($format) // formats using date()
+ : strftime($format, $time->format('U')); // formats according to locales
+ }
+
+
+ /**
+ * Converts to human readable file size.
+ * @param int
+ * @param int
+ * @return string
+ */
+ public static function bytes($bytes, $precision = 2)
+ {
+ $bytes = round($bytes);
+ $units = array('B', 'kB', 'MB', 'GB', 'TB', 'PB');
+ foreach ($units as $unit) {
+ if (abs($bytes) < 1024 || $unit === end($units)) {
+ break;
+ }
+ $bytes = $bytes / 1024;
+ }
+ return round($bytes, $precision) . ' ' . $unit;
+ }
+
+
+ /**
+ * Performs a search and replace.
+ * @param string
+ * @param string
+ * @param string
+ * @return string
+ */
+ public static function replace($subject, $search, $replacement = '')
+ {
+ return str_replace($search, $replacement, $subject);
+ }
+
+
+ /**
+ * Perform a regular expression search and replace.
+ * @param string
+ * @param string
+ * @return string
+ */
+ public static function replaceRe($subject, $pattern, $replacement = '')
+ {
+ $res = preg_replace($pattern, $replacement, $subject);
+ if (preg_last_error()) {
+ throw new Latte\RegexpException(NULL, preg_last_error());
+ }
+ return $res;
+ }
+
+
+ /**
+ * The data: URI generator.
+ * @param string
+ * @param string
+ * @return string
+ */
+ public static function dataStream($data, $type = NULL)
+ {
+ if ($type === NULL) {
+ $type = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $data);
+ }
+ return 'data:' . ($type ? "$type;" : '') . 'base64,' . base64_encode($data);
+ }
+
+
+ /**
+ * @param string
+ * @return string
+ */
+ public static function nl2br($value)
+ {
+ return nl2br($value, self::$xhtml);
+ }
+
+
+ /**
+ * Returns a part of UTF-8 string.
+ * @param string
+ * @param int
+ * @param int
+ * @return string
+ */
+ public static function substring($s, $start, $length = NULL)
+ {
+ if ($length === NULL) {
+ $length = self::length($s);
+ }
+ if (function_exists('mb_substr')) {
+ return mb_substr($s, $start, $length, 'UTF-8'); // MB is much faster
+ }
+ return iconv_substr($s, $start, $length, 'UTF-8');
+ }
+
+
+ /**
+ * Truncates string to maximal length.
+ * @param string UTF-8 encoding
+ * @param int
+ * @param string UTF-8 encoding
+ * @return string
+ */
+ public static function truncate($s, $maxLen, $append = "\xE2\x80\xA6")
+ {
+ if (self::length($s) > $maxLen) {
+ $maxLen = $maxLen - self::length($append);
+ if ($maxLen < 1) {
+ return $append;
+
+ } elseif (preg_match('#^.{1,'.$maxLen.'}(?=[\s\x00-/:-@\[-`{-~])#us', $s, $matches)) {
+ return $matches[0] . $append;
+
+ } else {
+ return self::substring($s, 0, $maxLen) . $append;
+ }
+ }
+ return $s;
+ }
+
+
+ /**
+ * Convert to lower case.
+ * @return string
+ */
+ public static function lower($s)
+ {
+ return mb_strtolower($s, 'UTF-8');
+ }
+
+
+ /**
+ * Convert to upper case.
+ * @return string
+ */
+ public static function upper($s)
+ {
+ return mb_strtoupper($s, 'UTF-8');
+ }
+
+
+ /**
+ * Convert first character to upper case.
+ * @return string
+ */
+ public static function firstUpper($s)
+ {
+ return self::upper(self::substring($s, 0, 1)) . self::substring($s, 1);
+ }
+
+
+ /**
+ * Capitalize string.
+ * @return string
+ */
+ public static function capitalize($s)
+ {
+ return mb_convert_case($s, MB_CASE_TITLE, 'UTF-8');
+ }
+
+
+ /**
+ * Returns UTF-8 string length.
+ * @return int
+ */
+ public static function length($s)
+ {
+ return strlen(utf8_decode($s)); // fastest way
+ }
+
+
+ /**
+ * Strips whitespace.
+ * @param string UTF-8 encoding
+ * @param string
+ * @return string
+ */
+ public static function trim($s, $charlist = " \t\n\r\0\x0B\xC2\xA0")
+ {
+ $charlist = preg_quote($charlist, '#');
+ $s = preg_replace('#^['.$charlist.']+|['.$charlist.']+\z#u', '', $s);
+ if (preg_last_error()) {
+ throw new Latte\RegexpException(NULL, preg_last_error());
+ }
+ return $s;
+ }
+
+
+ /**
+ * Returns element's attributes.
+ * @return string
+ */
+ public static function htmlAttributes($attrs)
+ {
+ if (!is_array($attrs)) {
+ return '';
+ }
+
+ $s = '';
+ foreach ($attrs as $key => $value) {
+ if ($value === NULL || $value === FALSE) {
+ continue;
+
+ } elseif ($value === TRUE) {
+ if (static::$xhtml) {
+ $s .= ' ' . $key . '="' . $key . '"';
+ } else {
+ $s .= ' ' . $key;
+ }
+ continue;
+
+ } elseif (is_array($value)) {
+ $tmp = NULL;
+ foreach ($value as $k => $v) {
+ if ($v != NULL) { // intentionally ==, skip NULLs & empty string
+ // composite 'style' vs. 'others'
+ $tmp[] = $v === TRUE ? $k : (is_string($k) ? $k . ':' . $v : $v);
+ }
+ }
+ if ($tmp === NULL) {
+ continue;
+ }
+
+ $value = implode($key === 'style' || !strncmp($key, 'on', 2) ? ';' : ' ', $tmp);
+
+ } else {
+ $value = (string) $value;
+ }
+
+ $q = strpos($value, '"') === FALSE ? '"' : "'";
+ $s .= ' ' . $key . '=' . $q
+ . str_replace(
+ array('&', $q, '<'),
+ array('&', $q === '"' ? '"' : ''', self::$xhtml ? '<' : '<'),
+ $value
+ )
+ . (strpos($value, '`') !== FALSE && strpbrk($value, ' <>"\'') === FALSE ? ' ' : '')
+ . $q;
+ }
+ return $s;
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Runtime/Html.php b/vendor/latte/latte/src/Latte/Runtime/Html.php
new file mode 100755
index 0000000..aaaf40a
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Runtime/Html.php
@@ -0,0 +1,36 @@
+value = (string) $value;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->value;
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Runtime/IHtmlString.php b/vendor/latte/latte/src/Latte/Runtime/IHtmlString.php
new file mode 100755
index 0000000..b79ebfa
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Runtime/IHtmlString.php
@@ -0,0 +1,19 @@
+setParameters($params);
+ $this->engine = $engine;
+ $this->name = $name;
+ }
+
+
+ /**
+ * @return Engine
+ */
+ public function getEngine()
+ {
+ return $this->engine;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+
+ /**
+ * Initializes block, global & local storage in template.
+ * @return [\stdClass, \stdClass, \stdClass]
+ * @internal
+ */
+ public function initialize($templateId, $contentType)
+ {
+ Runtime\Filters::$xhtml = (bool) preg_match('#xml|xhtml#', $contentType);
+
+ // local storage
+ $this->params['_l'] = new \stdClass;
+
+ // block storage
+ if (isset($this->params['_b'])) {
+ $block = $this->params['_b'];
+ unset($this->params['_b']);
+ } else {
+ $block = new \stdClass;
+ }
+ $block->templates[$templateId] = $this;
+
+ // global storage
+ if (!isset($this->params['_g'])) {
+ $this->params['_g'] = new \stdClass;
+ }
+
+ return array($block, $this->params['_g'], $this->params['_l']);
+ }
+
+
+ /**
+ * Renders template.
+ * @return void
+ * @internal
+ */
+ public function renderChildTemplate($name, array $params = array())
+ {
+ $name = $this->engine->getLoader()->getChildName($name, $this->name);
+ $this->engine->render($name, $params);
+ }
+
+
+ /**
+ * Call a template run-time filter. Do not call directly.
+ * @param string filter name
+ * @param array arguments
+ * @return mixed
+ */
+ public function __call($name, $args)
+ {
+ return $this->engine->invokeFilter($name, $args);
+ }
+
+
+ /********************* template parameters ****************d*g**/
+
+
+ /**
+ * Sets all parameters.
+ * @param array
+ * @return self
+ */
+ public function setParameters(array $params)
+ {
+ $this->params = $params;
+ $this->params['template'] = $this;
+ return $this;
+ }
+
+
+ /**
+ * Returns array of all parameters.
+ * @return array
+ */
+ public function getParameters()
+ {
+ return $this->params;
+ }
+
+
+ /**
+ * Sets a template parameter. Do not call directly.
+ * @return void
+ */
+ public function __set($name, $value)
+ {
+ $this->params[$name] = $value;
+ }
+
+
+ /**
+ * Returns a template parameter. Do not call directly.
+ * @return mixed value
+ */
+ public function &__get($name)
+ {
+ if (!array_key_exists($name, $this->params)) {
+ trigger_error("The variable '$name' does not exist in template.", E_USER_NOTICE);
+ }
+ return $this->params[$name];
+ }
+
+
+ /**
+ * Determines whether parameter is defined. Do not call directly.
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ return isset($this->params[$name]);
+ }
+
+
+ /**
+ * Removes a template parameter. Do not call directly.
+ * @param string name
+ * @return void
+ */
+ public function __unset($name)
+ {
+ unset($this->params[$name]);
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Token.php b/vendor/latte/latte/src/Latte/Token.php
new file mode 100755
index 0000000..5d0d71e
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Token.php
@@ -0,0 +1,47 @@
+? used for type HTML_TAG_BEGIN */
+ public $closing;
+
+ /** @var bool is tag empty {name/}? used for type MACRO_TAG */
+ public $empty;
+
+}
diff --git a/vendor/latte/latte/src/Latte/TokenIterator.php b/vendor/latte/latte/src/Latte/TokenIterator.php
new file mode 100755
index 0000000..ff078d2
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/TokenIterator.php
@@ -0,0 +1,228 @@
+tokens = $tokens;
+ }
+
+
+ /**
+ * Returns current token.
+ * @return array|NULL
+ */
+ public function currentToken()
+ {
+ return isset($this->tokens[$this->position])
+ ? $this->tokens[$this->position]
+ : NULL;
+ }
+
+
+ /**
+ * Returns current token value.
+ * @return string|NULL
+ */
+ public function currentValue()
+ {
+ return isset($this->tokens[$this->position])
+ ? $this->tokens[$this->position][Tokenizer::VALUE]
+ : NULL;
+ }
+
+
+ /**
+ * Returns next token.
+ * @param int|string (optional) desired token type or value
+ * @return array|NULL
+ */
+ public function nextToken()
+ {
+ return $this->scan(func_get_args(), TRUE, TRUE); // onlyFirst, advance
+ }
+
+
+ /**
+ * Returns next token value.
+ * @param int|string (optional) desired token type or value
+ * @return string|NULL
+ */
+ public function nextValue()
+ {
+ return $this->scan(func_get_args(), TRUE, TRUE, TRUE); // onlyFirst, advance, strings
+ }
+
+
+ /**
+ * Returns all next tokens.
+ * @param int|string (optional) desired token type or value
+ * @return array[]
+ */
+ public function nextAll()
+ {
+ return $this->scan(func_get_args(), FALSE, TRUE); // advance
+ }
+
+
+ /**
+ * Returns all next tokens until it sees a given token type or value.
+ * @param int|string token type or value to stop before
+ * @return array[]
+ */
+ public function nextUntil($arg)
+ {
+ return $this->scan(func_get_args(), FALSE, TRUE, FALSE, TRUE); // advance, until
+ }
+
+
+ /**
+ * Returns concatenation of all next token values.
+ * @param int|string (optional) token type or value to be joined
+ * @return string
+ */
+ public function joinAll()
+ {
+ return $this->scan(func_get_args(), FALSE, TRUE, TRUE); // advance, strings
+ }
+
+
+ /**
+ * Returns concatenation of all next tokens until it sees a given token type or value.
+ * @param int|string token type or value to stop before
+ * @return string
+ */
+ public function joinUntil($arg)
+ {
+ return $this->scan(func_get_args(), FALSE, TRUE, TRUE, TRUE); // advance, strings, until
+ }
+
+
+ /**
+ * Checks the current token.
+ * @param int|string token type or value
+ * @return bool
+ */
+ public function isCurrent($arg)
+ {
+ if (!isset($this->tokens[$this->position])) {
+ return FALSE;
+ }
+ $args = func_get_args();
+ $token = $this->tokens[$this->position];
+ return in_array($token[Tokenizer::VALUE], $args, TRUE)
+ || (isset($token[Tokenizer::TYPE]) && in_array($token[Tokenizer::TYPE], $args, TRUE));
+ }
+
+
+ /**
+ * Checks the next token existence.
+ * @param int|string (optional) token type or value
+ * @return bool
+ */
+ public function isNext()
+ {
+ return (bool) $this->scan(func_get_args(), TRUE, FALSE); // onlyFirst
+ }
+
+
+ /**
+ * Checks the previous token existence.
+ * @param int|string (optional) token type or value
+ * @return bool
+ */
+ public function isPrev()
+ {
+ return (bool) $this->scan(func_get_args(), TRUE, FALSE, FALSE, FALSE, TRUE); // onlyFirst, prev
+ }
+
+
+ /**
+ * @return self
+ */
+ public function reset()
+ {
+ $this->position = -1;
+ return $this;
+ }
+
+
+ /**
+ * Moves cursor to next token.
+ */
+ protected function next()
+ {
+ $this->position++;
+ }
+
+
+ /**
+ * Looks for (first) (not) wanted tokens.
+ * @param array of desired token types or values
+ * @param bool
+ * @param bool
+ * @param bool
+ * @param bool
+ * @param bool
+ * @return mixed
+ */
+ protected function scan($wanted, $onlyFirst, $advance, $strings = FALSE, $until = FALSE, $prev = FALSE)
+ {
+ $res = $onlyFirst ? NULL : ($strings ? '' : array());
+ $pos = $this->position + ($prev ? -1 : 1);
+ do {
+ if (!isset($this->tokens[$pos])) {
+ if (!$wanted && $advance && !$prev && $pos <= count($this->tokens)) {
+ $this->next();
+ }
+ return $res;
+ }
+
+ $token = $this->tokens[$pos];
+ $type = isset($token[Tokenizer::TYPE]) ? $token[Tokenizer::TYPE] : NULL;
+ if (!$wanted || (in_array($token[Tokenizer::VALUE], $wanted, TRUE) || in_array($type, $wanted, TRUE)) ^ $until) {
+ while ($advance && !$prev && $pos > $this->position) {
+ $this->next();
+ }
+
+ if ($onlyFirst) {
+ return $strings ? $token[Tokenizer::VALUE] : $token;
+ } elseif ($strings) {
+ $res .= $token[Tokenizer::VALUE];
+ } else {
+ $res[] = $token;
+ }
+
+ } elseif ($until || !in_array($type, $this->ignored, TRUE)) {
+ return $res;
+ }
+ $pos += $prev ? -1 : 1;
+ } while (TRUE);
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/Tokenizer.php b/vendor/latte/latte/src/Latte/Tokenizer.php
new file mode 100755
index 0000000..f8abffa
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/Tokenizer.php
@@ -0,0 +1,86 @@
+ pattern]
+ * @param string regular expression flag
+ */
+ public function __construct(array $patterns, $flags = '')
+ {
+ $this->re = '~(' . implode(')|(', $patterns) . ')~A' . $flags;
+ $this->types = array_keys($patterns);
+ }
+
+
+ /**
+ * Tokenizes string.
+ * @param string
+ * @return array
+ */
+ public function tokenize($input)
+ {
+ preg_match_all($this->re, $input, $tokens, PREG_SET_ORDER);
+ if (preg_last_error()) {
+ throw new RegexpException(NULL, preg_last_error());
+ }
+ $len = 0;
+ $count = count($this->types);
+ foreach ($tokens as & $match) {
+ $type = NULL;
+ for ($i = 1; $i <= $count; $i++) {
+ if (!isset($match[$i])) {
+ break;
+ } elseif ($match[$i] != NULL) {
+ $type = $this->types[$i - 1];
+ break;
+ }
+ }
+ $match = array(self::VALUE => $match[0], self::OFFSET => $len, self::TYPE => $type);
+ $len += strlen($match[self::VALUE]);
+ }
+ if ($len !== strlen($input)) {
+ list($line, $col) = $this->getCoordinates($input, $len);
+ $token = str_replace("\n", '\n', substr($input, $len, 10));
+ throw new CompileException("Unexpected '$token' on line $line, column $col.");
+ }
+ return $tokens;
+ }
+
+
+ /**
+ * Returns position of token in input string.
+ * @param string
+ * @param int
+ * @return array of [line, column]
+ */
+ public static function getCoordinates($text, $offset)
+ {
+ $text = substr($text, 0, $offset);
+ return array(substr_count($text, "\n") + 1, $offset - strrpos("\n" . $text, "\n") + 1);
+ }
+
+}
diff --git a/vendor/latte/latte/src/Latte/exceptions.php b/vendor/latte/latte/src/Latte/exceptions.php
new file mode 100755
index 0000000..c8b32c6
--- /dev/null
+++ b/vendor/latte/latte/src/Latte/exceptions.php
@@ -0,0 +1,67 @@
+sourceCode = (string) $code;
+ $this->sourceLine = (int) $line;
+ $this->sourceName = (string) $name;
+ if (@is_file($name)) { // @ - may trigger error
+ $this->message = rtrim($this->message, '.')
+ . ' in ' . str_replace(dirname(dirname($name)), '...', $name) . ($line ? ":$line" : '');
+ }
+ return $this;
+ }
+
+}
+
+
+/**
+ * The exception that indicates error of the last Regexp execution.
+ */
+class RegexpException extends \Exception
+{
+ public static $messages = array(
+ PREG_INTERNAL_ERROR => 'Internal error',
+ PREG_BACKTRACK_LIMIT_ERROR => 'Backtrack limit was exhausted',
+ PREG_RECURSION_LIMIT_ERROR => 'Recursion limit was exhausted',
+ PREG_BAD_UTF8_ERROR => 'Malformed UTF-8 data',
+ 5 => 'Offset didn\'t correspond to the begin of a valid UTF-8 code point', // PREG_BAD_UTF8_OFFSET_ERROR
+ );
+
+ public function __construct($message, $code = NULL)
+ {
+ parent::__construct($message ?: (isset(self::$messages[$code]) ? self::$messages[$code] : 'Unknown error'), $code);
+ }
+
+}
+
+
+/**
+ * The exception that indicates error during rendering template.
+ */
+class RuntimeException extends \Exception
+{
+}
diff --git a/vendor/latte/latte/src/latte.php b/vendor/latte/latte/src/latte.php
new file mode 100755
index 0000000..4b7ac52
--- /dev/null
+++ b/vendor/latte/latte/src/latte.php
@@ -0,0 +1,38 @@
+ 'exceptions.php',
+ 'Latte\\Compiler' => 'Compiler.php',
+ 'Latte\\Engine' => 'Engine.php',
+ 'Latte\\Helpers' => 'Helpers.php',
+ 'Latte\\HtmlNode' => 'HtmlNode.php',
+ 'Latte\\ILoader' => 'ILoader.php',
+ 'Latte\\IMacro' => 'IMacro.php',
+ 'Latte\\Loaders\\FileLoader' => 'Loaders/FileLoader.php',
+ 'Latte\\Loaders\\StringLoader' => 'Loaders/StringLoader.php',
+ 'Latte\\MacroNode' => 'MacroNode.php',
+ 'Latte\\MacroTokens' => 'MacroTokens.php',
+ 'Latte\\Macros\\BlockMacros' => 'Macros/BlockMacros.php',
+ 'Latte\\Macros\\BlockMacrosRuntime' => 'Macros/BlockMacrosRuntime.php',
+ 'Latte\\Macros\\CoreMacros' => 'Macros/CoreMacros.php',
+ 'Latte\\Macros\\MacroSet' => 'Macros/MacroSet.php',
+ 'Latte\\Object' => 'Object.php',
+ 'Latte\\Parser' => 'Parser.php',
+ 'Latte\\PhpWriter' => 'PhpWriter.php',
+ 'Latte\\RegexpException' => 'exceptions.php',
+ 'Latte\\RuntimeException' => 'exceptions.php',
+ 'Latte\\Runtime\\CachingIterator' => 'Runtime/CachingIterator.php',
+ 'Latte\\Runtime\\Filters' => 'Runtime/Filters.php',
+ 'Latte\\Runtime\\Html' => 'Runtime/Html.php',
+ 'Latte\\Runtime\\IHtmlString' => 'Runtime/IHtmlString.php',
+ 'Latte\\Template' => 'Template.php',
+ 'Latte\\Token' => 'Token.php',
+ 'Latte\\TokenIterator' => 'TokenIterator.php',
+ 'Latte\\Tokenizer' => 'Tokenizer.php',
+ );
+
+ if (isset($classMap[$className])) {
+ require __DIR__ . '/Latte/' . $classMap[$className];
+ }
+});
diff --git a/vendor/nette/application/composer.json b/vendor/nette/application/composer.json
new file mode 100755
index 0000000..c84468f
--- /dev/null
+++ b/vendor/nette/application/composer.json
@@ -0,0 +1,42 @@
+{
+ "name": "nette/application",
+ "description": "Nette Application MVC Component",
+ "homepage": "http://nette.org",
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.1",
+ "nette/component-model": "~2.2",
+ "nette/http": "~2.2",
+ "nette/reflection": "~2.2",
+ "nette/security": "~2.2",
+ "nette/utils": "~2.2"
+ },
+ "suggest": {
+ "nette/forms": "Allows to use Nette\\Application\\UI\\Form",
+ "latte/latte": "Allows using Latte in templates"
+ },
+ "require-dev": {
+ "nette/tester": "~1.3",
+ "nette/di": "~2.3",
+ "nette/forms": "~2.2",
+ "nette/robot-loader": "~2.2",
+ "latte/latte": "~2.3.0"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/application/license.md b/vendor/nette/application/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/application/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/application/src/Application/Application.php b/vendor/nette/application/src/Application/Application.php
new file mode 100755
index 0000000..6267fc2
--- /dev/null
+++ b/vendor/nette/application/src/Application/Application.php
@@ -0,0 +1,225 @@
+httpRequest = $httpRequest;
+ $this->httpResponse = $httpResponse;
+ $this->presenterFactory = $presenterFactory;
+ $this->router = $router;
+ }
+
+
+ /**
+ * Dispatch a HTTP request to a front controller.
+ * @return void
+ */
+ public function run()
+ {
+ try {
+ $this->onStartup($this);
+ $this->processRequest($this->createInitialRequest());
+ $this->onShutdown($this);
+
+ } catch (\Exception $e) {
+ $this->onError($this, $e);
+ if ($this->catchExceptions && $this->errorPresenter) {
+ try {
+ $this->processException($e);
+ $this->onShutdown($this, $e);
+ return;
+
+ } catch (\Exception $e) {
+ $this->onError($this, $e);
+ }
+ }
+ $this->onShutdown($this, $e);
+ throw $e;
+ }
+ }
+
+
+ /**
+ * @return Request
+ */
+ public function createInitialRequest()
+ {
+ $request = $this->router->match($this->httpRequest);
+
+ if (!$request instanceof Request) {
+ throw new BadRequestException('No route for HTTP request.');
+
+ } elseif (strcasecmp($request->getPresenterName(), $this->errorPresenter) === 0) {
+ throw new BadRequestException('Invalid request. Presenter is not achievable.');
+ }
+
+ try {
+ $name = $request->getPresenterName();
+ $this->presenterFactory->getPresenterClass($name);
+ } catch (InvalidPresenterException $e) {
+ throw new BadRequestException($e->getMessage(), 0, $e);
+ }
+
+ return $request;
+ }
+
+
+ /**
+ * @return void
+ */
+ public function processRequest(Request $request)
+ {
+ if (count($this->requests) > self::$maxLoop) {
+ throw new ApplicationException('Too many loops detected in application life cycle.');
+ }
+
+ $this->requests[] = $request;
+ $this->onRequest($this, $request);
+
+ $this->presenter = $this->presenterFactory->createPresenter($request->getPresenterName());
+ $this->onPresenter($this, $this->presenter);
+ $response = $this->presenter->run($request);
+
+ if ($response instanceof Responses\ForwardResponse) {
+ $this->processRequest($response->getRequest());
+
+ } elseif ($response) {
+ $this->onResponse($this, $response);
+ $response->send($this->httpRequest, $this->httpResponse);
+ }
+ }
+
+
+ /**
+ * @return void
+ */
+ public function processException(\Exception $e)
+ {
+ if (!$e instanceof BadRequestException && $this->httpResponse instanceof Nette\Http\Response) {
+ $this->httpResponse->warnOnBuffer = FALSE;
+ }
+ if (!$this->httpResponse->isSent()) {
+ $this->httpResponse->setCode($e instanceof BadRequestException ? ($e->getCode() ?: 404) : 500);
+ }
+
+ $args = array('exception' => $e, 'request' => end($this->requests) ?: NULL);
+ if ($this->presenter instanceof UI\Presenter) {
+ try {
+ $this->presenter->forward(":$this->errorPresenter:", $args);
+ } catch (AbortException $foo) {
+ $this->processRequest($this->presenter->getLastCreatedRequest());
+ }
+ } else {
+ $this->processRequest(new Request($this->errorPresenter, Request::FORWARD, $args));
+ }
+ }
+
+
+ /**
+ * Returns all processed requests.
+ * @return Request[]
+ */
+ public function getRequests()
+ {
+ return $this->requests;
+ }
+
+
+ /**
+ * Returns current presenter.
+ * @return IPresenter
+ */
+ public function getPresenter()
+ {
+ return $this->presenter;
+ }
+
+
+ /********************* services ****************d*g**/
+
+
+ /**
+ * Returns router.
+ * @return IRouter
+ */
+ public function getRouter()
+ {
+ return $this->router;
+ }
+
+
+ /**
+ * Returns presenter factory.
+ * @return IPresenterFactory
+ */
+ public function getPresenterFactory()
+ {
+ return $this->presenterFactory;
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/ErrorPresenter.php b/vendor/nette/application/src/Application/ErrorPresenter.php
new file mode 100755
index 0000000..013d9c7
--- /dev/null
+++ b/vendor/nette/application/src/Application/ErrorPresenter.php
@@ -0,0 +1,49 @@
+logger = $logger;
+ }
+
+
+ /**
+ * @return Application\IResponse
+ */
+ public function run(Application\Request $request)
+ {
+ $e = $request->parameters['exception'];
+ if ($e instanceof Application\BadRequestException) {
+ $code = $e->getCode();
+ } else {
+ $code = 500;
+ if ($this->logger) {
+ $this->logger->log($e, ILogger::EXCEPTION);
+ }
+ }
+ ob_start();
+ require __DIR__ . '/templates/error.phtml';
+ return new Application\Responses\TextResponse(ob_get_clean());
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/IPresenter.php b/vendor/nette/application/src/Application/IPresenter.php
new file mode 100755
index 0000000..ba3ab38
--- /dev/null
+++ b/vendor/nette/application/src/Application/IPresenter.php
@@ -0,0 +1,22 @@
+router = $router;
+ $this->refUrl = $refUrl;
+ $this->presenterFactory = $presenterFactory;
+ }
+
+
+ /**
+ * Generates URL to presenter.
+ * @param string destination in format "[[[module:]presenter:]action] [#fragment]"
+ * @return string
+ * @throws InvalidLinkException
+ */
+ public function link($dest, array $params = array())
+ {
+ if (!preg_match('~^([\w:]+):(\w*+)(#.*)?()\z~', $dest, $m)) {
+ throw new UI\InvalidLinkException("Invalid link destination '$dest'.");
+ }
+ list(, $presenter, $action, $frag) = $m;
+
+ try {
+ $class = $this->presenterFactory ? $this->presenterFactory->getPresenterClass($presenter) : NULL;
+ } catch (InvalidPresenterException $e) {
+ throw new UI\InvalidLinkException($e->getMessage(), NULL, $e);
+ }
+
+ if (is_subclass_of($class, 'Nette\Application\UI\Presenter')) {
+ if ($action === '') {
+ $action = UI\Presenter::DEFAULT_ACTION;
+ }
+ if ($params && (method_exists($class, $method = $class::formatActionMethod($action))
+ || method_exists($class, $method = $class::formatRenderMethod($action)))
+ ) {
+ UI\Presenter::argsToParams($class, $method, $params);
+ }
+ }
+
+ if ($action !== '') {
+ $params[UI\Presenter::ACTION_KEY] = $action;
+ }
+
+ $url = $this->router->constructUrl(new Request($presenter, NULL, $params), $this->refUrl);
+ if ($url === NULL) {
+ unset($params[UI\Presenter::ACTION_KEY]);
+ $params = urldecode(http_build_query($params, NULL, ', '));
+ throw new UI\InvalidLinkException("No route for $dest($params)");
+ }
+ return $url . $frag;
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/MicroPresenter.php b/vendor/nette/application/src/Application/MicroPresenter.php
new file mode 100755
index 0000000..5d9ecf7
--- /dev/null
+++ b/vendor/nette/application/src/Application/MicroPresenter.php
@@ -0,0 +1,167 @@
+context = $context;
+ $this->httpRequest = $httpRequest;
+ $this->router = $router;
+ }
+
+
+ /**
+ * Gets the context.
+ * @return Nette\DI\Container
+ */
+ public function getContext()
+ {
+ return $this->context;
+ }
+
+
+ /**
+ * @return Nette\Application\IResponse
+ */
+ public function run(Application\Request $request)
+ {
+ $this->request = $request;
+
+ if ($this->httpRequest && $this->router && !$this->httpRequest->isAjax() && ($request->isMethod('get') || $request->isMethod('head'))) {
+ $refUrl = clone $this->httpRequest->getUrl();
+ $url = $this->router->constructUrl($request, $refUrl->setPath($refUrl->getScriptPath()));
+ if ($url !== NULL && !$this->httpRequest->getUrl()->isEqual($url)) {
+ return new Responses\RedirectResponse($url, Http\IResponse::S301_MOVED_PERMANENTLY);
+ }
+ }
+
+ $params = $request->getParameters();
+ if (!isset($params['callback'])) {
+ throw new Application\BadRequestException('Parameter callback is missing.');
+ }
+ $params['presenter'] = $this;
+ $callback = $params['callback'];
+ $reflection = Nette\Utils\Callback::toReflection(Nette\Utils\Callback::check($callback));
+ $params = Application\UI\PresenterComponentReflection::combineArgs($reflection, $params);
+
+ if ($this->context) {
+ foreach ($reflection->getParameters() as $param) {
+ if ($param->getClassName()) {
+ unset($params[$param->getPosition()]);
+ }
+ }
+
+ $params = Nette\DI\Helpers::autowireArguments($reflection, $params, $this->context);
+ $params['presenter'] = $this;
+ }
+
+ $response = call_user_func_array($callback, $params);
+
+ if (is_string($response)) {
+ $response = array($response, array());
+ }
+ if (is_array($response)) {
+ list($templateSource, $templateParams) = $response;
+ $response = $this->createTemplate()->setParameters($templateParams);
+ if (!$templateSource instanceof \SplFileInfo) {
+ $response->getLatte()->setLoader(new Latte\Loaders\StringLoader);
+ }
+ $response->setFile($templateSource);
+ }
+ if ($response instanceof Application\UI\ITemplate) {
+ return new Responses\TextResponse($response);
+ } else {
+ return $response;
+ }
+ }
+
+
+ /**
+ * Template factory.
+ * @param string
+ * @param callable
+ * @return Application\UI\ITemplate
+ */
+ public function createTemplate($class = NULL, $latteFactory = NULL)
+ {
+ $latte = $latteFactory ? $latteFactory() : $this->getContext()->getByType('Nette\Bridges\ApplicationLatte\ILatteFactory')->create();
+ $template = $class ? new $class : new Nette\Bridges\ApplicationLatte\Template($latte);
+
+ $template->setParameters($this->request->getParameters());
+ $template->presenter = $this;
+ $template->context = $this->context;
+ if ($this->httpRequest) {
+ $url = $this->httpRequest->getUrl();
+ $template->baseUrl = rtrim($url->getBaseUrl(), '/');
+ $template->basePath = rtrim($url->getBasePath(), '/');
+ }
+ return $template;
+ }
+
+
+ /**
+ * Redirects to another URL.
+ * @param string
+ * @param int HTTP code
+ * @return Nette\Application\Responses\RedirectResponse
+ */
+ public function redirectUrl($url, $code = Http\IResponse::S302_FOUND)
+ {
+ return new Responses\RedirectResponse($url, $code);
+ }
+
+
+ /**
+ * Throws HTTP error.
+ * @param string
+ * @param int HTTP error code
+ * @return void
+ * @throws Nette\Application\BadRequestException
+ */
+ public function error($message = NULL, $code = Http\IResponse::S404_NOT_FOUND)
+ {
+ throw new Application\BadRequestException($message, $code);
+ }
+
+
+ /**
+ * @return Nette\Application\IRequest
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/PresenterFactory.php b/vendor/nette/application/src/Application/PresenterFactory.php
new file mode 100755
index 0000000..c44e072
--- /dev/null
+++ b/vendor/nette/application/src/Application/PresenterFactory.php
@@ -0,0 +1,148 @@
+ splited mask */
+ private $mapping = array(
+ '*' => array('', '*Module\\', '*Presenter'),
+ 'Nette' => array('NetteModule\\', '*\\', '*Presenter'),
+ );
+
+ /** @var array */
+ private $cache = array();
+
+ /** @var callable */
+ private $factory;
+
+
+ /**
+ * @param callable function (string $class): IPresenter
+ */
+ public function __construct($factory = NULL)
+ {
+ $this->factory = $factory ?: function ($class) { return new $class; };
+ }
+
+
+ /**
+ * Creates new presenter instance.
+ * @param string presenter name
+ * @return IPresenter
+ */
+ public function createPresenter($name)
+ {
+ return call_user_func($this->factory, $this->getPresenterClass($name));
+ }
+
+
+ /**
+ * Generates and checks presenter class name.
+ * @param string presenter name
+ * @return string class name
+ * @throws InvalidPresenterException
+ */
+ public function getPresenterClass(& $name)
+ {
+ if (isset($this->cache[$name])) {
+ return $this->cache[$name];
+ }
+
+ if (!is_string($name) || !Nette\Utils\Strings::match($name, '#^[a-zA-Z\x7f-\xff][a-zA-Z0-9\x7f-\xff:]*\z#')) {
+ throw new InvalidPresenterException("Presenter name must be alphanumeric string, '$name' is invalid.");
+ }
+
+ $class = $this->formatPresenterClass($name);
+ if (!class_exists($class)) {
+ throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' was not found.");
+ }
+
+ $reflection = new \ReflectionClass($class);
+ $class = $reflection->getName();
+
+ if (!$reflection->implementsInterface('Nette\Application\IPresenter')) {
+ throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' is not Nette\\Application\\IPresenter implementor.");
+ } elseif ($reflection->isAbstract()) {
+ throw new InvalidPresenterException("Cannot load presenter '$name', class '$class' is abstract.");
+ }
+
+ $this->cache[$name] = $class;
+
+ if ($name !== ($realName = $this->unformatPresenterClass($class))) {
+ trigger_error("Case mismatch on presenter name '$name', correct name is '$realName'.", E_USER_WARNING);
+ $name = $realName;
+ }
+
+ return $class;
+ }
+
+
+ /**
+ * Sets mapping as pairs [module => mask]
+ * @return self
+ */
+ public function setMapping(array $mapping)
+ {
+ foreach ($mapping as $module => $mask) {
+ if (!preg_match('#^\\\\?([\w\\\\]*\\\\)?(\w*\*\w*?\\\\)?([\w\\\\]*\*\w*)\z#', $mask, $m)) {
+ throw new Nette\InvalidStateException("Invalid mapping mask '$mask'.");
+ }
+ $this->mapping[$module] = array($m[1], $m[2] ?: '*Module\\', $m[3]);
+ }
+ return $this;
+ }
+
+
+ /**
+ * Formats presenter class name from its name.
+ * @param string
+ * @return string
+ * @internal
+ */
+ public function formatPresenterClass($presenter)
+ {
+ $parts = explode(':', $presenter);
+ $mapping = isset($parts[1], $this->mapping[$parts[0]])
+ ? $this->mapping[array_shift($parts)]
+ : $this->mapping['*'];
+
+ while ($part = array_shift($parts)) {
+ $mapping[0] .= str_replace('*', $part, $mapping[$parts ? 1 : 2]);
+ }
+ return $mapping[0];
+ }
+
+
+ /**
+ * Formats presenter name from class name.
+ * @param string
+ * @return string
+ * @internal
+ */
+ public function unformatPresenterClass($class)
+ {
+ foreach ($this->mapping as $module => $mapping) {
+ $mapping = str_replace(array('\\', '*'), array('\\\\', '(\w+)'), $mapping);
+ if (preg_match("#^\\\\?$mapping[0]((?:$mapping[1])*)$mapping[2]\\z#i", $class, $matches)) {
+ return ($module === '*' ? '' : $module . ':')
+ . preg_replace("#$mapping[1]#iA", '$1:', $matches[1]) . $matches[3];
+ }
+ }
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/Request.php b/vendor/nette/application/src/Application/Request.php
new file mode 100755
index 0000000..364fd3d
--- /dev/null
+++ b/vendor/nette/application/src/Application/Request.php
@@ -0,0 +1,243 @@
+name = $name;
+ $this->method = $method;
+ $this->params = $params;
+ $this->post = $post;
+ $this->files = $files;
+ $this->flags = $flags;
+ }
+
+
+ /**
+ * Sets the presenter name.
+ * @param string
+ * @return self
+ */
+ public function setPresenterName($name)
+ {
+ $this->name = $name;
+ return $this;
+ }
+
+
+ /**
+ * Retrieve the presenter name.
+ * @return string
+ */
+ public function getPresenterName()
+ {
+ return $this->name;
+ }
+
+
+ /**
+ * Sets variables provided to the presenter.
+ * @return self
+ */
+ public function setParameters(array $params)
+ {
+ $this->params = $params;
+ return $this;
+ }
+
+
+ /**
+ * Returns all variables provided to the presenter (usually via URL).
+ * @return array
+ */
+ public function getParameters()
+ {
+ return $this->params;
+ }
+
+
+ /**
+ * Returns a parameter provided to the presenter.
+ * @param string
+ * @return mixed
+ */
+ public function getParameter($key)
+ {
+ return isset($this->params[$key]) ? $this->params[$key] : NULL;
+ }
+
+
+ /**
+ * Sets variables provided to the presenter via POST.
+ * @return self
+ */
+ public function setPost(array $params)
+ {
+ $this->post = $params;
+ return $this;
+ }
+
+
+ /**
+ * Returns a variable provided to the presenter via POST.
+ * If no key is passed, returns the entire array.
+ * @param string
+ * @return mixed
+ */
+ public function getPost($key = NULL)
+ {
+ if (func_num_args() === 0) {
+ return $this->post;
+
+ } elseif (isset($this->post[$key])) {
+ return $this->post[$key];
+
+ } else {
+ return NULL;
+ }
+ }
+
+
+ /**
+ * Sets all uploaded files.
+ * @return self
+ */
+ public function setFiles(array $files)
+ {
+ $this->files = $files;
+ return $this;
+ }
+
+
+ /**
+ * Returns all uploaded files.
+ * @return array
+ */
+ public function getFiles()
+ {
+ return $this->files;
+ }
+
+
+ /**
+ * Sets the method.
+ * @param string|NULL
+ * @return self
+ */
+ public function setMethod($method)
+ {
+ $this->method = $method;
+ return $this;
+ }
+
+
+ /**
+ * Returns the method.
+ * @return string|NULL
+ */
+ public function getMethod()
+ {
+ return $this->method;
+ }
+
+
+ /**
+ * Checks if the method is the given one.
+ * @param string
+ * @return bool
+ */
+ public function isMethod($method)
+ {
+ return strcasecmp($this->method, $method) === 0;
+ }
+
+
+ /**
+ * @deprecated
+ */
+ public function isPost()
+ {
+ trigger_error('Method isPost() is deprecated, use isMethod(\'POST\') instead.', E_USER_DEPRECATED);
+ return strcasecmp($this->method, 'post') === 0;
+ }
+
+
+ /**
+ * Sets the flag.
+ * @param string
+ * @param bool
+ * @return self
+ */
+ public function setFlag($flag, $value = TRUE)
+ {
+ $this->flags[$flag] = (bool) $value;
+ return $this;
+ }
+
+
+ /**
+ * Checks the flag.
+ * @param string
+ * @return bool
+ */
+ public function hasFlag($flag)
+ {
+ return !empty($this->flags[$flag]);
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/Responses/FileResponse.php b/vendor/nette/application/src/Application/Responses/FileResponse.php
new file mode 100755
index 0000000..e63bd85
--- /dev/null
+++ b/vendor/nette/application/src/Application/Responses/FileResponse.php
@@ -0,0 +1,135 @@
+file = $file;
+ $this->name = $name ? $name : basename($file);
+ $this->contentType = $contentType ? $contentType : 'application/octet-stream';
+ $this->forceDownload = $forceDownload;
+ }
+
+
+ /**
+ * Returns the path to a downloaded file.
+ * @return string
+ */
+ public function getFile()
+ {
+ return $this->file;
+ }
+
+
+ /**
+ * Returns the file name.
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+
+ /**
+ * Returns the MIME content type of a downloaded file.
+ * @return string
+ */
+ public function getContentType()
+ {
+ return $this->contentType;
+ }
+
+
+ /**
+ * Sends response to output.
+ * @return void
+ */
+ public function send(Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse)
+ {
+ $httpResponse->setContentType($this->contentType);
+ $httpResponse->setHeader('Content-Disposition',
+ ($this->forceDownload ? 'attachment' : 'inline')
+ . '; filename="' . $this->name . '"'
+ . '; filename*=utf-8\'\'' . rawurlencode($this->name));
+
+ $filesize = $length = filesize($this->file);
+ $handle = fopen($this->file, 'r');
+
+ if ($this->resuming) {
+ $httpResponse->setHeader('Accept-Ranges', 'bytes');
+ if (preg_match('#^bytes=(\d*)-(\d*)\z#', $httpRequest->getHeader('Range'), $matches)) {
+ list(, $start, $end) = $matches;
+ if ($start === '') {
+ $start = max(0, $filesize - $end);
+ $end = $filesize - 1;
+
+ } elseif ($end === '' || $end > $filesize - 1) {
+ $end = $filesize - 1;
+ }
+ if ($end < $start) {
+ $httpResponse->setCode(416); // requested range not satisfiable
+ return;
+ }
+
+ $httpResponse->setCode(206);
+ $httpResponse->setHeader('Content-Range', 'bytes ' . $start . '-' . $end . '/' . $filesize);
+ $length = $end - $start + 1;
+ fseek($handle, $start);
+
+ } else {
+ $httpResponse->setHeader('Content-Range', 'bytes 0-' . ($filesize - 1) . '/' . $filesize);
+ }
+ }
+
+ $httpResponse->setHeader('Content-Length', $length);
+ while (!feof($handle) && $length > 0) {
+ echo $s = fread($handle, min(4e6, $length));
+ $length -= strlen($s);
+ }
+ fclose($handle);
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/Responses/ForwardResponse.php b/vendor/nette/application/src/Application/Responses/ForwardResponse.php
new file mode 100755
index 0000000..3d7d825
--- /dev/null
+++ b/vendor/nette/application/src/Application/Responses/ForwardResponse.php
@@ -0,0 +1,47 @@
+request = $request;
+ }
+
+
+ /**
+ * @return Nette\Application\Request
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+
+ /**
+ * Sends response to output.
+ * @return void
+ */
+ public function send(Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse)
+ {
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/Responses/JsonResponse.php b/vendor/nette/application/src/Application/Responses/JsonResponse.php
new file mode 100755
index 0000000..799946a
--- /dev/null
+++ b/vendor/nette/application/src/Application/Responses/JsonResponse.php
@@ -0,0 +1,72 @@
+payload = $payload;
+ $this->contentType = $contentType ? $contentType : 'application/json';
+ }
+
+
+ /**
+ * @return array|\stdClass
+ */
+ public function getPayload()
+ {
+ return $this->payload;
+ }
+
+
+ /**
+ * Returns the MIME content type of a downloaded file.
+ * @return string
+ */
+ public function getContentType()
+ {
+ return $this->contentType;
+ }
+
+
+ /**
+ * Sends response to output.
+ * @return void
+ */
+ public function send(Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse)
+ {
+ $httpResponse->setContentType($this->contentType);
+ $httpResponse->setExpiration(FALSE);
+ echo Nette\Utils\Json::encode($this->payload);
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/Responses/RedirectResponse.php b/vendor/nette/application/src/Application/Responses/RedirectResponse.php
new file mode 100755
index 0000000..00654c7
--- /dev/null
+++ b/vendor/nette/application/src/Application/Responses/RedirectResponse.php
@@ -0,0 +1,67 @@
+url = (string) $url;
+ $this->code = (int) $code;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getUrl()
+ {
+ return $this->url;
+ }
+
+
+ /**
+ * @return int
+ */
+ public function getCode()
+ {
+ return $this->code;
+ }
+
+
+ /**
+ * Sends response to output.
+ * @return void
+ */
+ public function send(Http\IRequest $httpRequest, Http\IResponse $httpResponse)
+ {
+ $httpResponse->redirect($this->url, $this->code);
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/Responses/TextResponse.php b/vendor/nette/application/src/Application/Responses/TextResponse.php
new file mode 100755
index 0000000..67e1985
--- /dev/null
+++ b/vendor/nette/application/src/Application/Responses/TextResponse.php
@@ -0,0 +1,56 @@
+source = $source;
+ }
+
+
+ /**
+ * @return mixed
+ */
+ public function getSource()
+ {
+ return $this->source;
+ }
+
+
+ /**
+ * Sends response to output.
+ * @return void
+ */
+ public function send(Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse)
+ {
+ if ($this->source instanceof Nette\Application\UI\ITemplate) {
+ $this->source->render();
+
+ } else {
+ echo $this->source;
+ }
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/Routers/CliRouter.php b/vendor/nette/application/src/Application/Routers/CliRouter.php
new file mode 100755
index 0000000..59ffb75
--- /dev/null
+++ b/vendor/nette/application/src/Application/Routers/CliRouter.php
@@ -0,0 +1,115 @@
+defaults = $defaults;
+ }
+
+
+ /**
+ * Maps command line arguments to a Request object.
+ * @return Nette\Application\Request|NULL
+ */
+ public function match(Nette\Http\IRequest $httpRequest)
+ {
+ if (empty($_SERVER['argv']) || !is_array($_SERVER['argv'])) {
+ return NULL;
+ }
+
+ $names = array(self::PRESENTER_KEY);
+ $params = $this->defaults;
+ $args = $_SERVER['argv'];
+ array_shift($args);
+ $args[] = '--';
+
+ foreach ($args as $arg) {
+ $opt = preg_replace('#/|-+#A', '', $arg);
+ if ($opt === $arg) {
+ if (isset($flag) || $flag = array_shift($names)) {
+ $params[$flag] = $arg;
+ } else {
+ $params[] = $arg;
+ }
+ $flag = NULL;
+ continue;
+ }
+
+ if (isset($flag)) {
+ $params[$flag] = TRUE;
+ $flag = NULL;
+ }
+
+ if ($opt !== '') {
+ $pair = explode('=', $opt, 2);
+ if (isset($pair[1])) {
+ $params[$pair[0]] = $pair[1];
+ } else {
+ $flag = $pair[0];
+ }
+ }
+ }
+
+ if (!isset($params[self::PRESENTER_KEY])) {
+ throw new Nette\InvalidStateException('Missing presenter & action in route definition.');
+ }
+ $presenter = $params[self::PRESENTER_KEY];
+ if ($a = strrpos($presenter, ':')) {
+ $params[self::PRESENTER_KEY] = substr($presenter, $a + 1);
+ $presenter = substr($presenter, 0, $a);
+ }
+
+ return new Application\Request(
+ $presenter,
+ 'CLI',
+ $params
+ );
+ }
+
+
+ /**
+ * This router is only unidirectional.
+ * @return NULL
+ */
+ public function constructUrl(Application\Request $appRequest, Nette\Http\Url $refUrl)
+ {
+ return NULL;
+ }
+
+
+ /**
+ * Returns default values.
+ * @return array
+ */
+ public function getDefaults()
+ {
+ return $this->defaults;
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/Routers/Route.php b/vendor/nette/application/src/Application/Routers/Route.php
new file mode 100755
index 0000000..64dfbb8
--- /dev/null
+++ b/vendor/nette/application/src/Application/Routers/Route.php
@@ -0,0 +1,835 @@
+ array( // default style for path parameters
+ self::PATTERN => '[^/]+',
+ self::FILTER_OUT => array(__CLASS__, 'param2path'),
+ ),
+ '?#' => array( // default style for query parameters
+ ),
+ 'module' => array(
+ self::PATTERN => '[a-z][a-z0-9.-]*',
+ self::FILTER_IN => array(__CLASS__, 'path2presenter'),
+ self::FILTER_OUT => array(__CLASS__, 'presenter2path'),
+ ),
+ 'presenter' => array(
+ self::PATTERN => '[a-z][a-z0-9.-]*',
+ self::FILTER_IN => array(__CLASS__, 'path2presenter'),
+ self::FILTER_OUT => array(__CLASS__, 'presenter2path'),
+ ),
+ 'action' => array(
+ self::PATTERN => '[a-z][a-z0-9-]*',
+ self::FILTER_IN => array(__CLASS__, 'path2action'),
+ self::FILTER_OUT => array(__CLASS__, 'action2path'),
+ ),
+ '?module' => array(
+ ),
+ '?presenter' => array(
+ ),
+ '?action' => array(
+ ),
+ );
+
+ /** @var string */
+ private $mask;
+
+ /** @var array */
+ private $sequence;
+
+ /** @var string regular expression pattern */
+ private $re;
+
+ /** @var string[] parameter aliases in regular expression */
+ private $aliases;
+
+ /** @var array of [value & fixity, filterIn, filterOut] */
+ private $metadata = array();
+
+ /** @var array */
+ private $xlat;
+
+ /** @var int HOST, PATH, RELATIVE */
+ private $type;
+
+ /** @var int */
+ private $flags;
+
+ /** @var Nette\Http\Url */
+ private $lastRefUrl;
+
+ /** @var string */
+ private $lastBaseUrl;
+
+
+ /**
+ * @param string URL mask, e.g. '//'
+ * @param array|string default values or metadata
+ * @param int flags
+ */
+ public function __construct($mask, $metadata = array(), $flags = 0)
+ {
+ if (is_string($metadata)) {
+ $a = strrpos($metadata, ':');
+ if (!$a) {
+ throw new Nette\InvalidArgumentException("Second argument must be array or string in format Presenter:action, '$metadata' given.");
+ }
+ $metadata = array(
+ self::PRESENTER_KEY => substr($metadata, 0, $a),
+ 'action' => $a === strlen($metadata) - 1 ? NULL : substr($metadata, $a + 1),
+ );
+ } elseif ($metadata instanceof \Closure || $metadata instanceof Nette\Callback) {
+ $metadata = array(
+ self::PRESENTER_KEY => 'Nette:Micro',
+ 'callback' => $metadata,
+ );
+ }
+
+ $this->flags = $flags | static::$defaultFlags;
+ $this->setMask($mask, $metadata);
+ }
+
+
+ /**
+ * Maps HTTP request to a Request object.
+ * @return Nette\Application\Request|NULL
+ */
+ public function match(Nette\Http\IRequest $httpRequest)
+ {
+ // combine with precedence: mask (params in URL-path), fixity, query, (post,) defaults
+
+ // 1) URL MASK
+ $url = $httpRequest->getUrl();
+ $re = $this->re;
+
+ if ($this->type === self::HOST) {
+ $host = $url->getHost();
+ $path = '//' . $host . $url->getPath();
+ $host = ip2long($host) ? array($host) : array_reverse(explode('.', $host));
+ $re = strtr($re, array(
+ '/%basePath%/' => preg_quote($url->getBasePath(), '#'),
+ '%tld%' => preg_quote($host[0], '#'),
+ '%domain%' => preg_quote(isset($host[1]) ? "$host[1].$host[0]" : $host[0], '#'),
+ ));
+
+ } elseif ($this->type === self::RELATIVE) {
+ $basePath = $url->getBasePath();
+ if (strncmp($url->getPath(), $basePath, strlen($basePath)) !== 0) {
+ return NULL;
+ }
+ $path = (string) substr($url->getPath(), strlen($basePath));
+
+ } else {
+ $path = $url->getPath();
+ }
+
+ if ($path !== '') {
+ $path = rtrim(rawurldecode($path), '/') . '/';
+ }
+
+ if (!$matches = Strings::match($path, $re)) {
+ // stop, not matched
+ return NULL;
+ }
+
+ // assigns matched values to parameters
+ $params = array();
+ foreach ($matches as $k => $v) {
+ if (is_string($k) && $v !== '') {
+ $params[$this->aliases[$k]] = $v;
+ }
+ }
+
+
+ // 2) CONSTANT FIXITY
+ foreach ($this->metadata as $name => $meta) {
+ if (!isset($params[$name]) && isset($meta['fixity']) && $meta['fixity'] !== self::OPTIONAL) {
+ $params[$name] = NULL; // cannot be overwriten in 3) and detected by isset() in 4)
+ }
+ }
+
+
+ // 3) QUERY
+ if ($this->xlat) {
+ $params += self::renameKeys($httpRequest->getQuery(), array_flip($this->xlat));
+ } else {
+ $params += $httpRequest->getQuery();
+ }
+
+
+ // 4) APPLY FILTERS & FIXITY
+ foreach ($this->metadata as $name => $meta) {
+ if (isset($params[$name])) {
+ if (!is_scalar($params[$name])) {
+
+ } elseif (isset($meta[self::FILTER_TABLE][$params[$name]])) { // applies filterTable only to scalar parameters
+ $params[$name] = $meta[self::FILTER_TABLE][$params[$name]];
+
+ } elseif (isset($meta[self::FILTER_TABLE]) && !empty($meta[self::FILTER_STRICT])) {
+ return NULL; // rejected by filterTable
+
+ } elseif (isset($meta[self::FILTER_IN])) { // applies filterIn only to scalar parameters
+ $params[$name] = call_user_func($meta[self::FILTER_IN], (string) $params[$name]);
+ if ($params[$name] === NULL && !isset($meta['fixity'])) {
+ return NULL; // rejected by filter
+ }
+ }
+
+ } elseif (isset($meta['fixity'])) {
+ $params[$name] = $meta[self::VALUE];
+ }
+ }
+
+ if (isset($this->metadata[NULL][self::FILTER_IN])) {
+ $params = call_user_func($this->metadata[NULL][self::FILTER_IN], $params);
+ if ($params === NULL) {
+ return NULL;
+ }
+ }
+
+ // 5) BUILD Request
+ if (!isset($params[self::PRESENTER_KEY])) {
+ throw new Nette\InvalidStateException('Missing presenter in route definition.');
+ } elseif (!is_string($params[self::PRESENTER_KEY])) {
+ return NULL;
+ }
+ if (isset($this->metadata[self::MODULE_KEY])) {
+ if (!isset($params[self::MODULE_KEY])) {
+ throw new Nette\InvalidStateException('Missing module in route definition.');
+ }
+ $presenter = $params[self::MODULE_KEY] . ':' . $params[self::PRESENTER_KEY];
+ unset($params[self::MODULE_KEY], $params[self::PRESENTER_KEY]);
+
+ } else {
+ $presenter = $params[self::PRESENTER_KEY];
+ unset($params[self::PRESENTER_KEY]);
+ }
+
+ return new Application\Request(
+ $presenter,
+ $httpRequest->getMethod(),
+ $params,
+ $httpRequest->getPost(),
+ $httpRequest->getFiles(),
+ array(Application\Request::SECURED => $httpRequest->isSecured())
+ );
+ }
+
+
+ /**
+ * Constructs absolute URL from Request object.
+ * @return string|NULL
+ */
+ public function constructUrl(Application\Request $appRequest, Nette\Http\Url $refUrl)
+ {
+ if ($this->flags & self::ONE_WAY) {
+ return NULL;
+ }
+
+ $params = $appRequest->getParameters();
+ $metadata = $this->metadata;
+
+ $presenter = $appRequest->getPresenterName();
+ $params[self::PRESENTER_KEY] = $presenter;
+
+ if (isset($metadata[NULL][self::FILTER_OUT])) {
+ $params = call_user_func($metadata[NULL][self::FILTER_OUT], $params);
+ if ($params === NULL) {
+ return NULL;
+ }
+ }
+
+ if (isset($metadata[self::MODULE_KEY])) { // try split into module and [submodule:]presenter parts
+ $module = $metadata[self::MODULE_KEY];
+ if (isset($module['fixity']) && strncmp($presenter, $module[self::VALUE] . ':', strlen($module[self::VALUE]) + 1) === 0) {
+ $a = strlen($module[self::VALUE]);
+ } else {
+ $a = strrpos($presenter, ':');
+ }
+ if ($a === FALSE) {
+ $params[self::MODULE_KEY] = '';
+ } else {
+ $params[self::MODULE_KEY] = substr($presenter, 0, $a);
+ $params[self::PRESENTER_KEY] = substr($presenter, $a + 1);
+ }
+ }
+
+ foreach ($metadata as $name => $meta) {
+ if (!isset($params[$name])) {
+ continue; // retains NULL values
+ }
+
+ if (isset($meta['fixity'])) {
+ if ($params[$name] === FALSE) {
+ $params[$name] = '0';
+ } elseif (is_scalar($params[$name])) {
+ $params[$name] = (string) $params[$name];
+ }
+
+ if ($params[$name] === $meta[self::VALUE]) { // remove default values; NULL values are retain
+ unset($params[$name]);
+ continue;
+
+ } elseif ($meta['fixity'] === self::CONSTANT) {
+ return NULL; // missing or wrong parameter '$name'
+ }
+ }
+
+ if (is_scalar($params[$name]) && isset($meta['filterTable2'][$params[$name]])) {
+ $params[$name] = $meta['filterTable2'][$params[$name]];
+
+ } elseif (isset($meta['filterTable2']) && !empty($meta[self::FILTER_STRICT])) {
+ return NULL;
+
+ } elseif (isset($meta[self::FILTER_OUT])) {
+ $params[$name] = call_user_func($meta[self::FILTER_OUT], $params[$name]);
+ }
+
+ if (isset($meta[self::PATTERN]) && !preg_match($meta[self::PATTERN], rawurldecode($params[$name]))) {
+ return NULL; // pattern not match
+ }
+ }
+
+ // compositing path
+ $sequence = $this->sequence;
+ $brackets = array();
+ $required = NULL; // NULL for auto-optional
+ $url = '';
+ $i = count($sequence) - 1;
+ do {
+ $url = $sequence[$i] . $url;
+ if ($i === 0) {
+ break;
+ }
+ $i--;
+
+ $name = $sequence[$i]; $i--; // parameter name
+
+ if ($name === ']') { // opening optional part
+ $brackets[] = $url;
+
+ } elseif ($name[0] === '[') { // closing optional part
+ $tmp = array_pop($brackets);
+ if ($required < count($brackets) + 1) { // is this level optional?
+ if ($name !== '[!') { // and not "required"-optional
+ $url = $tmp;
+ }
+ } else {
+ $required = count($brackets);
+ }
+
+ } elseif ($name[0] === '?') { // "foo" parameter
+ continue;
+
+ } elseif (isset($params[$name]) && $params[$name] != '') { // intentionally ==
+ $required = count($brackets); // make this level required
+ $url = $params[$name] . $url;
+ unset($params[$name]);
+
+ } elseif (isset($metadata[$name]['fixity'])) { // has default value?
+ if ($required === NULL && !$brackets) { // auto-optional
+ $url = '';
+ } else {
+ $url = $metadata[$name]['defOut'] . $url;
+ }
+
+ } else {
+ return NULL; // missing parameter '$name'
+ }
+ } while (TRUE);
+
+
+ if ($this->type !== self::HOST) {
+ if ($this->lastRefUrl !== $refUrl) {
+ $scheme = ($this->flags & self::SECURED ? 'https://' : 'http://');
+ $basePath = ($this->type === self::RELATIVE ? $refUrl->getBasePath() : '');
+ $this->lastBaseUrl = $scheme . $refUrl->getAuthority() . $basePath;
+ $this->lastRefUrl = $refUrl;
+ }
+ $url = $this->lastBaseUrl . $url;
+
+ } else {
+ $host = $refUrl->getHost();
+ $host = ip2long($host) ? array($host) : array_reverse(explode('.', $host));
+ $url = strtr($url, array(
+ '/%basePath%/' => $refUrl->getBasePath(),
+ '%tld%' => $host[0],
+ '%domain%' => isset($host[1]) ? "$host[1].$host[0]" : $host[0],
+ ));
+ $url = ($this->flags & self::SECURED ? 'https:' : 'http:') . $url;
+ }
+
+ if (strpos($url, '//', 7) !== FALSE) {
+ return NULL;
+ }
+
+ // build query string
+ if ($this->xlat) {
+ $params = self::renameKeys($params, $this->xlat);
+ }
+
+ $sep = ini_get('arg_separator.input');
+ $query = http_build_query($params, '', $sep ? $sep[0] : '&');
+ if ($query != '') { // intentionally ==
+ $url .= '?' . $query;
+ }
+
+ return $url;
+ }
+
+
+ /**
+ * Parse mask and array of default values; initializes object.
+ * @param string
+ * @param array
+ * @return void
+ */
+ private function setMask($mask, array $metadata)
+ {
+ $this->mask = $mask;
+
+ // detect '//host/path' vs. '/abs. path' vs. 'relative path'
+ if (substr($mask, 0, 2) === '//') {
+ $this->type = self::HOST;
+
+ } elseif (substr($mask, 0, 1) === '/') {
+ $this->type = self::PATH;
+
+ } else {
+ $this->type = self::RELATIVE;
+ }
+
+ foreach ($metadata as $name => $meta) {
+ if (!is_array($meta)) {
+ $metadata[$name] = $meta = array(self::VALUE => $meta);
+ }
+
+ if (array_key_exists(self::VALUE, $meta)) {
+ if (is_scalar($meta[self::VALUE])) {
+ $metadata[$name][self::VALUE] = (string) $meta[self::VALUE];
+ }
+ $metadata[$name]['fixity'] = self::CONSTANT;
+ }
+ }
+
+ if (strpbrk($mask, '?<[') === FALSE) {
+ $this->re = '#' . preg_quote($mask, '#') . '/?\z#A';
+ $this->sequence = array($mask);
+ $this->metadata = $metadata;
+ return;
+ }
+
+ // PARSE MASK
+ // or [ or ] or ?...
+ $parts = Strings::split($mask, '/<([^>#= ]+)(=[^># ]*)? *([^>#]*)(#?[^>\[\]]*)>|(\[!?|\]|\s*\?.*)/');
+
+ $this->xlat = array();
+ $i = count($parts) - 1;
+
+ // PARSE QUERY PART OF MASK
+ if (isset($parts[$i - 1]) && substr(ltrim($parts[$i - 1]), 0, 1) === '?') {
+ // name=
+ $matches = Strings::matchAll($parts[$i - 1], '/(?:([a-zA-Z0-9_.-]+)=)?<([^># ]+) *([^>#]*)(#?[^>]*)>/');
+
+ foreach ($matches as $match) {
+ list(, $param, $name, $pattern, $class) = $match; // $pattern is not used
+
+ if ($class !== '') {
+ if (!isset(static::$styles[$class])) {
+ throw new Nette\InvalidStateException("Parameter '$name' has '$class' flag, but Route::\$styles['$class'] is not set.");
+ }
+ $meta = static::$styles[$class];
+
+ } elseif (isset(static::$styles['?' . $name])) {
+ $meta = static::$styles['?' . $name];
+
+ } else {
+ $meta = static::$styles['?#'];
+ }
+
+ if (isset($metadata[$name])) {
+ $meta = $metadata[$name] + $meta;
+ }
+
+ if (array_key_exists(self::VALUE, $meta)) {
+ $meta['fixity'] = self::OPTIONAL;
+ }
+
+ unset($meta['pattern']);
+ $meta['filterTable2'] = empty($meta[self::FILTER_TABLE]) ? NULL : array_flip($meta[self::FILTER_TABLE]);
+
+ $metadata[$name] = $meta;
+ if ($param !== '') {
+ $this->xlat[$name] = $param;
+ }
+ }
+ $i -= 6;
+ }
+
+ // PARSE PATH PART OF MASK
+ $brackets = 0; // optional level
+ $re = '';
+ $sequence = array();
+ $autoOptional = TRUE;
+ $aliases = array();
+ do {
+ array_unshift($sequence, $parts[$i]);
+ $re = preg_quote($parts[$i], '#') . $re;
+ if ($i === 0) {
+ break;
+ }
+ $i--;
+
+ $part = $parts[$i]; // [ or ]
+ if ($part === '[' || $part === ']' || $part === '[!') {
+ $brackets += $part[0] === '[' ? -1 : 1;
+ if ($brackets < 0) {
+ throw new Nette\InvalidArgumentException("Unexpected '$part' in mask '$mask'.");
+ }
+ array_unshift($sequence, $part);
+ $re = ($part[0] === '[' ? '(?:' : ')?') . $re;
+ $i -= 5;
+ continue;
+ }
+
+ $class = $parts[$i]; $i--; // validation class
+ $pattern = trim($parts[$i]); $i--; // validation condition (as regexp)
+ $default = $parts[$i]; $i--; // default value
+ $name = $parts[$i]; $i--; // parameter name
+ array_unshift($sequence, $name);
+
+ if ($name[0] === '?') { // "foo" parameter
+ $name = substr($name, 1);
+ $re = $pattern ? '(?:' . preg_quote($name, '#') . "|$pattern)$re" : preg_quote($name, '#') . $re;
+ $sequence[1] = $name . $sequence[1];
+ continue;
+ }
+
+ // pattern, condition & metadata
+ if ($class !== '') {
+ if (!isset(static::$styles[$class])) {
+ throw new Nette\InvalidStateException("Parameter '$name' has '$class' flag, but Route::\$styles['$class'] is not set.");
+ }
+ $meta = static::$styles[$class];
+
+ } elseif (isset(static::$styles[$name])) {
+ $meta = static::$styles[$name];
+
+ } else {
+ $meta = static::$styles['#'];
+ }
+
+ if (isset($metadata[$name])) {
+ $meta = $metadata[$name] + $meta;
+ }
+
+ if ($pattern == '' && isset($meta[self::PATTERN])) {
+ $pattern = $meta[self::PATTERN];
+ }
+
+ if ($default !== '') {
+ $meta[self::VALUE] = (string) substr($default, 1);
+ $meta['fixity'] = self::PATH_OPTIONAL;
+ }
+
+ $meta['filterTable2'] = empty($meta[self::FILTER_TABLE]) ? NULL : array_flip($meta[self::FILTER_TABLE]);
+ if (array_key_exists(self::VALUE, $meta)) {
+ if (isset($meta['filterTable2'][$meta[self::VALUE]])) {
+ $meta['defOut'] = $meta['filterTable2'][$meta[self::VALUE]];
+
+ } elseif (isset($meta[self::FILTER_OUT])) {
+ $meta['defOut'] = call_user_func($meta[self::FILTER_OUT], $meta[self::VALUE]);
+
+ } else {
+ $meta['defOut'] = $meta[self::VALUE];
+ }
+ }
+ $meta[self::PATTERN] = "#(?:$pattern)\\z#A";
+
+ // include in expression
+ $aliases['p' . $i] = $name;
+ $re = '(?P(?U)' . $pattern . ')' . $re;
+ if ($brackets) { // is in brackets?
+ if (!isset($meta[self::VALUE])) {
+ $meta[self::VALUE] = $meta['defOut'] = NULL;
+ }
+ $meta['fixity'] = self::PATH_OPTIONAL;
+
+ } elseif (!$autoOptional) {
+ unset($meta['fixity']);
+
+ } elseif (isset($meta['fixity'])) { // auto-optional
+ $re = '(?:' . $re . ')?';
+ $meta['fixity'] = self::PATH_OPTIONAL;
+
+ } else {
+ $autoOptional = FALSE;
+ }
+
+ $metadata[$name] = $meta;
+ } while (TRUE);
+
+ if ($brackets) {
+ throw new Nette\InvalidArgumentException("Missing closing ']' in mask '$mask'.");
+ }
+
+ $this->aliases = $aliases;
+ $this->re = '#' . $re . '/?\z#A';
+ $this->metadata = $metadata;
+ $this->sequence = $sequence;
+ }
+
+
+ /**
+ * Returns mask.
+ * @return string
+ */
+ public function getMask()
+ {
+ return $this->mask;
+ }
+
+
+ /**
+ * Returns default values.
+ * @return array
+ */
+ public function getDefaults()
+ {
+ $defaults = array();
+ foreach ($this->metadata as $name => $meta) {
+ if (isset($meta['fixity'])) {
+ $defaults[$name] = $meta[self::VALUE];
+ }
+ }
+ return $defaults;
+ }
+
+
+ /**
+ * Returns flags.
+ * @return int
+ */
+ public function getFlags()
+ {
+ return $this->flags;
+ }
+
+
+ /********************* Utilities ****************d*g**/
+
+
+ /**
+ * Proprietary cache aim.
+ * @internal
+ * @return string[]|NULL
+ */
+ public function getTargetPresenters()
+ {
+ if ($this->flags & self::ONE_WAY) {
+ return array();
+ }
+
+ $m = $this->metadata;
+ $module = '';
+
+ if (isset($m[self::MODULE_KEY])) {
+ if (isset($m[self::MODULE_KEY]['fixity']) && $m[self::MODULE_KEY]['fixity'] === self::CONSTANT) {
+ $module = $m[self::MODULE_KEY][self::VALUE] . ':';
+ } else {
+ return NULL;
+ }
+ }
+
+ if (isset($m[self::PRESENTER_KEY]['fixity']) && $m[self::PRESENTER_KEY]['fixity'] === self::CONSTANT) {
+ return array($module . $m[self::PRESENTER_KEY][self::VALUE]);
+ }
+ return NULL;
+ }
+
+
+ /**
+ * Rename keys in array.
+ * @param array
+ * @param array
+ * @return array
+ */
+ private static function renameKeys($arr, $xlat)
+ {
+ if (empty($xlat)) {
+ return $arr;
+ }
+
+ $res = array();
+ $occupied = array_flip($xlat);
+ foreach ($arr as $k => $v) {
+ if (isset($xlat[$k])) {
+ $res[$xlat[$k]] = $v;
+
+ } elseif (!isset($occupied[$k])) {
+ $res[$k] = $v;
+ }
+ }
+ return $res;
+ }
+
+
+ /********************* Inflectors ****************d*g**/
+
+
+ /**
+ * camelCaseAction name -> dash-separated.
+ * @param string
+ * @return string
+ */
+ private static function action2path($s)
+ {
+ $s = preg_replace('#(.)(?=[A-Z])#', '$1-', $s);
+ $s = strtolower($s);
+ $s = rawurlencode($s);
+ return $s;
+ }
+
+
+ /**
+ * dash-separated -> camelCaseAction name.
+ * @param string
+ * @return string
+ */
+ private static function path2action($s)
+ {
+ $s = preg_replace('#-(?=[a-z])#', ' ', $s);
+ $s = lcfirst(ucwords($s));
+ $s = str_replace(' ', '', $s);
+ return $s;
+ }
+
+
+ /**
+ * PascalCase:Presenter name -> dash-and-dot-separated.
+ * @param string
+ * @return string
+ */
+ private static function presenter2path($s)
+ {
+ $s = strtr($s, ':', '.');
+ $s = preg_replace('#([^.])(?=[A-Z])#', '$1-', $s);
+ $s = strtolower($s);
+ $s = rawurlencode($s);
+ return $s;
+ }
+
+
+ /**
+ * dash-and-dot-separated -> PascalCase:Presenter name.
+ * @param string
+ * @return string
+ */
+ private static function path2presenter($s)
+ {
+ $s = preg_replace('#([.-])(?=[a-z])#', '$1 ', $s);
+ $s = ucwords($s);
+ $s = str_replace('. ', ':', $s);
+ $s = str_replace('- ', '', $s);
+ return $s;
+ }
+
+
+ /**
+ * Url encode.
+ * @param string
+ * @return string
+ */
+ private static function param2path($s)
+ {
+ return str_replace('%2F', '/', rawurlencode($s));
+ }
+
+
+ /********************* Route::$styles manipulator ****************d*g**/
+
+
+ /**
+ * @deprecated
+ */
+ public static function addStyle($style, $parent = '#')
+ {
+ trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
+ if (isset(static::$styles[$style])) {
+ throw new Nette\InvalidArgumentException("Style '$style' already exists.");
+ }
+
+ if ($parent !== NULL) {
+ if (!isset(static::$styles[$parent])) {
+ throw new Nette\InvalidArgumentException("Parent style '$parent' doesn't exist.");
+ }
+ static::$styles[$style] = static::$styles[$parent];
+
+ } else {
+ static::$styles[$style] = array();
+ }
+ }
+
+
+ /**
+ * @deprecated
+ */
+ public static function setStyleProperty($style, $key, $value)
+ {
+ trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
+ if (!isset(static::$styles[$style])) {
+ throw new Nette\InvalidArgumentException("Style '$style' doesn't exist.");
+ }
+ static::$styles[$style][$key] = $value;
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/Routers/RouteList.php b/vendor/nette/application/src/Application/Routers/RouteList.php
new file mode 100755
index 0000000..7bea1ed
--- /dev/null
+++ b/vendor/nette/application/src/Application/Routers/RouteList.php
@@ -0,0 +1,125 @@
+module = $module ? $module . ':' : '';
+ }
+
+
+ /**
+ * Maps HTTP request to a Request object.
+ * @return Nette\Application\Request|NULL
+ */
+ public function match(Nette\Http\IRequest $httpRequest)
+ {
+ foreach ($this as $route) {
+ $appRequest = $route->match($httpRequest);
+ if ($appRequest !== NULL) {
+ $name = $appRequest->getPresenterName();
+ if (strncmp($name, 'Nette:', 6)) {
+ $appRequest->setPresenterName($this->module . $name);
+ }
+ return $appRequest;
+ }
+ }
+ return NULL;
+ }
+
+
+ /**
+ * Constructs absolute URL from Request object.
+ * @return string|NULL
+ */
+ public function constructUrl(Nette\Application\Request $appRequest, Nette\Http\Url $refUrl)
+ {
+ if ($this->cachedRoutes === NULL) {
+ $routes = array();
+ $routes['*'] = array();
+
+ foreach ($this as $route) {
+ $presenters = $route instanceof Route && is_array($tmp = $route->getTargetPresenters())
+ ? $tmp : array_keys($routes);
+
+ foreach ($presenters as $presenter) {
+ if (!isset($routes[$presenter])) {
+ $routes[$presenter] = $routes['*'];
+ }
+ $routes[$presenter][] = $route;
+ }
+ }
+
+ $this->cachedRoutes = $routes;
+ }
+
+ if ($this->module) {
+ if (strncmp($tmp = $appRequest->getPresenterName(), $this->module, strlen($this->module)) === 0) {
+ $appRequest = clone $appRequest;
+ $appRequest->setPresenterName(substr($tmp, strlen($this->module)));
+ } else {
+ return NULL;
+ }
+ }
+
+ $presenter = $appRequest->getPresenterName();
+ if (!isset($this->cachedRoutes[$presenter])) {
+ $presenter = '*';
+ }
+
+ foreach ($this->cachedRoutes[$presenter] as $route) {
+ $url = $route->constructUrl($appRequest, $refUrl);
+ if ($url !== NULL) {
+ return $url;
+ }
+ }
+
+ return NULL;
+ }
+
+
+ /**
+ * Adds the router.
+ * @param mixed
+ * @param Nette\Application\IRouter
+ * @return void
+ */
+ public function offsetSet($index, $route)
+ {
+ if (!$route instanceof Nette\Application\IRouter) {
+ throw new Nette\InvalidArgumentException('Argument must be IRouter descendant.');
+ }
+ parent::offsetSet($index, $route);
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getModule()
+ {
+ return $this->module;
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/Routers/SimpleRouter.php b/vendor/nette/application/src/Application/Routers/SimpleRouter.php
new file mode 100755
index 0000000..7365f41
--- /dev/null
+++ b/vendor/nette/application/src/Application/Routers/SimpleRouter.php
@@ -0,0 +1,148 @@
+ substr($defaults, 0, $a),
+ 'action' => $a === strlen($defaults) - 1 ? Application\UI\Presenter::DEFAULT_ACTION : substr($defaults, $a + 1),
+ );
+ }
+
+ if (isset($defaults[self::MODULE_KEY])) {
+ $this->module = $defaults[self::MODULE_KEY] . ':';
+ unset($defaults[self::MODULE_KEY]);
+ }
+
+ $this->defaults = $defaults;
+ $this->flags = $flags;
+ }
+
+
+ /**
+ * Maps HTTP request to a Request object.
+ * @return Nette\Application\Request|NULL
+ */
+ public function match(Nette\Http\IRequest $httpRequest)
+ {
+ if ($httpRequest->getUrl()->getPathInfo() !== '') {
+ return NULL;
+ }
+ // combine with precedence: get, (post,) defaults
+ $params = $httpRequest->getQuery();
+ $params += $this->defaults;
+
+ if (!isset($params[self::PRESENTER_KEY]) || !is_string($params[self::PRESENTER_KEY])) {
+ return NULL;
+ }
+
+ $presenter = $this->module . $params[self::PRESENTER_KEY];
+ unset($params[self::PRESENTER_KEY]);
+
+ return new Application\Request(
+ $presenter,
+ $httpRequest->getMethod(),
+ $params,
+ $httpRequest->getPost(),
+ $httpRequest->getFiles(),
+ array(Application\Request::SECURED => $httpRequest->isSecured())
+ );
+ }
+
+
+ /**
+ * Constructs absolute URL from Request object.
+ * @return string|NULL
+ */
+ public function constructUrl(Application\Request $appRequest, Nette\Http\Url $refUrl)
+ {
+ if ($this->flags & self::ONE_WAY) {
+ return NULL;
+ }
+ $params = $appRequest->getParameters();
+
+ // presenter name
+ $presenter = $appRequest->getPresenterName();
+ if (strncmp($presenter, $this->module, strlen($this->module)) === 0) {
+ $params[self::PRESENTER_KEY] = substr($presenter, strlen($this->module));
+ } else {
+ return NULL;
+ }
+
+ // remove default values; NULL values are retain
+ foreach ($this->defaults as $key => $value) {
+ if (isset($params[$key]) && $params[$key] == $value) { // intentionally ==
+ unset($params[$key]);
+ }
+ }
+
+ $url = ($this->flags & self::SECURED ? 'https://' : 'http://') . $refUrl->getAuthority() . $refUrl->getPath();
+ $sep = ini_get('arg_separator.input');
+ $query = http_build_query($params, '', $sep ? $sep[0] : '&');
+ if ($query != '') { // intentionally ==
+ $url .= '?' . $query;
+ }
+ return $url;
+ }
+
+
+ /**
+ * Returns default values.
+ * @return array
+ */
+ public function getDefaults()
+ {
+ return $this->defaults;
+ }
+
+
+ /**
+ * Returns flags.
+ * @return int
+ */
+ public function getFlags()
+ {
+ return $this->flags;
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/UI/BadSignalException.php b/vendor/nette/application/src/Application/UI/BadSignalException.php
new file mode 100755
index 0000000..4d4b1d9
--- /dev/null
+++ b/vendor/nette/application/src/Application/UI/BadSignalException.php
@@ -0,0 +1,21 @@
+templateFactory = $templateFactory;
+ }
+
+
+ /**
+ * @return ITemplate
+ */
+ public function getTemplate()
+ {
+ if ($this->template === NULL) {
+ $value = $this->createTemplate();
+ if (!$value instanceof ITemplate && $value !== NULL) {
+ $class2 = get_class($value); $class = get_class($this);
+ throw new Nette\UnexpectedValueException("Object returned by $class::createTemplate() must be instance of Nette\\Application\\UI\\ITemplate, '$class2' given.");
+ }
+ $this->template = $value;
+ }
+ return $this->template;
+ }
+
+
+ /**
+ * @return ITemplate
+ */
+ protected function createTemplate()
+ {
+ $templateFactory = $this->templateFactory ?: $this->getPresenter()->getTemplateFactory();
+ return $templateFactory->createTemplate($this);
+ }
+
+
+ /**
+ * Descendant can override this method to customize template compile-time filters.
+ * @param ITemplate
+ * @return void
+ */
+ public function templatePrepareFilters($template)
+ {
+ }
+
+
+ /**
+ * Saves the message to template, that can be displayed after redirect.
+ * @param string
+ * @param string
+ * @return \stdClass
+ */
+ public function flashMessage($message, $type = 'info')
+ {
+ $id = $this->getParameterId('flash');
+ $messages = $this->getPresenter()->getFlashSession()->$id;
+ $messages[] = $flash = (object) array(
+ 'message' => $message,
+ 'type' => $type,
+ );
+ $this->getTemplate()->flashes = $messages;
+ $this->getPresenter()->getFlashSession()->$id = $messages;
+ return $flash;
+ }
+
+
+ /********************* rendering ****************d*g**/
+
+
+ /**
+ * Forces control or its snippet to repaint.
+ * @return void
+ */
+ public function redrawControl($snippet = NULL, $redraw = TRUE)
+ {
+ if ($redraw) {
+ $this->invalidSnippets[$snippet === NULL ? "\0" : $snippet] = TRUE;
+
+ } elseif ($snippet === NULL) {
+ $this->invalidSnippets = array();
+
+ } else {
+ unset($this->invalidSnippets[$snippet]);
+ }
+ }
+
+
+ /** @deprecated */
+ function invalidateControl($snippet = NULL)
+ {
+ $this->redrawControl($snippet);
+ }
+
+ /** @deprecated */
+ function validateControl($snippet = NULL)
+ {
+ $this->redrawControl($snippet, FALSE);
+ }
+
+
+ /**
+ * Is required to repaint the control or its snippet?
+ * @param string snippet name
+ * @return bool
+ */
+ public function isControlInvalid($snippet = NULL)
+ {
+ if ($snippet === NULL) {
+ if (count($this->invalidSnippets) > 0) {
+ return TRUE;
+
+ } else {
+ $queue = array($this);
+ do {
+ foreach (array_shift($queue)->getComponents() as $component) {
+ if ($component instanceof IRenderable) {
+ if ($component->isControlInvalid()) {
+ // $this->invalidSnippets['__child'] = TRUE; // as cache
+ return TRUE;
+ }
+
+ } elseif ($component instanceof Nette\ComponentModel\IContainer) {
+ $queue[] = $component;
+ }
+ }
+ } while ($queue);
+
+ return FALSE;
+ }
+
+ } else {
+ return isset($this->invalidSnippets["\0"]) || isset($this->invalidSnippets[$snippet]);
+ }
+ }
+
+
+ /**
+ * Returns snippet HTML ID.
+ * @param string snippet name
+ * @return string
+ */
+ public function getSnippetId($name = NULL)
+ {
+ // HTML 4 ID & NAME: [A-Za-z][A-Za-z0-9:_.-]*
+ return 'snippet-' . $this->getUniqueId() . '-' . $name;
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/UI/Form.php b/vendor/nette/application/src/Application/UI/Form.php
new file mode 100755
index 0000000..a70e74c
--- /dev/null
+++ b/vendor/nette/application/src/Application/UI/Form.php
@@ -0,0 +1,143 @@
+addComponent($this, $name);
+ }
+ }
+
+
+ /**
+ * @return void
+ */
+ protected function validateParent(Nette\ComponentModel\IContainer $parent)
+ {
+ parent::validateParent($parent);
+ $this->monitor('Nette\Application\UI\Presenter');
+ }
+
+
+ /**
+ * Returns the presenter where this component belongs to.
+ * @param bool throw exception if presenter doesn't exist?
+ * @return Presenter|NULL
+ */
+ public function getPresenter($need = TRUE)
+ {
+ return $this->lookup('Nette\Application\UI\Presenter', $need);
+ }
+
+
+ /**
+ * This method will be called when the component (or component's parent)
+ * becomes attached to a monitored object. Do not call this method yourself.
+ * @param Nette\ComponentModel\IComponent
+ * @return void
+ */
+ protected function attached($presenter)
+ {
+ if ($presenter instanceof Presenter) {
+ $name = $this->lookupPath('Nette\Application\UI\Presenter');
+
+ if (!isset($this->getElementPrototype()->id)) {
+ $this->getElementPrototype()->id = 'frm-' . $name;
+ }
+
+ if (iterator_count($this->getControls()) && $this->isSubmitted()) {
+ foreach ($this->getControls() as $control) {
+ if (!$control->isDisabled()) {
+ $control->loadHttpData();
+ }
+ }
+ }
+
+ if (!$this->getAction()) {
+ $this->setAction(new Link($presenter, 'this', array()));
+ $signal = new Nette\Forms\Controls\HiddenField($name . self::NAME_SEPARATOR . 'submit');
+ $signal->setOmitted()->setHtmlId(FALSE);
+ $this[Presenter::SIGNAL_KEY] = $signal;
+ }
+ }
+ parent::attached($presenter);
+ }
+
+
+ /**
+ * Tells if the form is anchored.
+ * @return bool
+ */
+ public function isAnchored()
+ {
+ return (bool) $this->getPresenter(FALSE);
+ }
+
+
+ /**
+ * Internal: returns submitted HTTP data or NULL when form was not submitted.
+ * @return array|NULL
+ */
+ protected function receiveHttpData()
+ {
+ $presenter = $this->getPresenter();
+ if (!$presenter->isSignalReceiver($this, 'submit')) {
+ return;
+ }
+
+ $isPost = $this->getMethod() === self::POST;
+ $request = $presenter->getRequest();
+ if ($request->isMethod('forward') || $request->isMethod('post') !== $isPost) {
+ return;
+ }
+
+ if ($isPost) {
+ return Nette\Utils\Arrays::mergeTree($request->getPost(), $request->getFiles());
+ } else {
+ return $request->getParameters();
+ }
+ }
+
+
+ /********************* interface ISignalReceiver ****************d*g**/
+
+
+ /**
+ * This method is called by presenter.
+ * @param string
+ * @return void
+ */
+ public function signalReceived($signal)
+ {
+ if ($signal === 'submit') {
+ if (!$this->getPresenter()->getRequest()->hasFlag(Nette\Application\Request::RESTORED)) {
+ $this->fireEvents();
+ }
+ } else {
+ $class = get_class($this);
+ throw new BadSignalException("Missing handler for signal '$signal' in $class.");
+ }
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/UI/IRenderable.php b/vendor/nette/application/src/Application/UI/IRenderable.php
new file mode 100755
index 0000000..101dda9
--- /dev/null
+++ b/vendor/nette/application/src/Application/UI/IRenderable.php
@@ -0,0 +1,29 @@
+component = $component;
+ $this->destination = $destination;
+ $this->params = $params;
+ }
+
+
+ /**
+ * Returns link destination.
+ * @return string
+ */
+ public function getDestination()
+ {
+ return $this->destination;
+ }
+
+
+ /**
+ * Changes link parameter.
+ * @param string
+ * @param mixed
+ * @return self
+ */
+ public function setParameter($key, $value)
+ {
+ $this->params[$key] = $value;
+ return $this;
+ }
+
+
+ /**
+ * Returns link parameter.
+ * @param string
+ * @return mixed
+ */
+ public function getParameter($key)
+ {
+ return isset($this->params[$key]) ? $this->params[$key] : NULL;
+ }
+
+
+ /**
+ * Returns link parameters.
+ * @return array
+ */
+ public function getParameters()
+ {
+ return $this->params;
+ }
+
+
+ /**
+ * Converts link to URL.
+ * @return string
+ */
+ public function __toString()
+ {
+ try {
+ return (string) $this->component->link($this->destination, $this->params);
+
+ } catch (\Exception $e) {
+ if (func_num_args()) {
+ throw $e;
+ }
+ trigger_error("Exception in " . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
+ }
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/UI/Multiplier.php b/vendor/nette/application/src/Application/UI/Multiplier.php
new file mode 100755
index 0000000..01ebd0c
--- /dev/null
+++ b/vendor/nette/application/src/Application/UI/Multiplier.php
@@ -0,0 +1,37 @@
+factory = Nette\Utils\Callback::check($factory);
+ }
+
+
+ protected function createComponent($name)
+ {
+ return call_user_func($this->factory, $name, $this);
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/UI/Presenter.php b/vendor/nette/application/src/Application/UI/Presenter.php
new file mode 100755
index 0000000..573c6b9
--- /dev/null
+++ b/vendor/nette/application/src/Application/UI/Presenter.php
@@ -0,0 +1,1403 @@
+payload = new \stdClass;
+ }
+
+
+ /**
+ * @return Nette\Application\Request
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+
+ /**
+ * Returns self.
+ * @return Presenter
+ */
+ public function getPresenter($need = TRUE)
+ {
+ return $this;
+ }
+
+
+ /**
+ * Returns a name that uniquely identifies component.
+ * @return string
+ */
+ public function getUniqueId()
+ {
+ return '';
+ }
+
+
+ /********************* interface IPresenter ****************d*g**/
+
+
+ /**
+ * @return Nette\Application\IResponse
+ */
+ public function run(Application\Request $request)
+ {
+ try {
+ // STARTUP
+ $this->request = $request;
+ $this->payload = $this->payload ?: new \stdClass;
+ $this->setParent($this->getParent(), $request->getPresenterName());
+
+ if (!$this->httpResponse->isSent()) {
+ $this->httpResponse->addHeader('Vary', 'X-Requested-With');
+ }
+
+ $this->initGlobalParameters();
+ $this->checkRequirements($this->getReflection());
+ $this->startup();
+ if (!$this->startupCheck) {
+ $class = $this->getReflection()->getMethod('startup')->getDeclaringClass()->getName();
+ throw new Nette\InvalidStateException("Method $class::startup() or its descendant doesn't call parent::startup().");
+ }
+ // calls $this->action()
+ $this->tryCall($this->formatActionMethod($this->action), $this->params);
+
+ // autoload components
+ foreach ($this->globalParams as $id => $foo) {
+ $this->getComponent($id, FALSE);
+ }
+
+ if ($this->autoCanonicalize) {
+ $this->canonicalize();
+ }
+ if ($this->httpRequest->isMethod('head')) {
+ $this->terminate();
+ }
+
+ // SIGNAL HANDLING
+ // calls $this->handle()
+ $this->processSignal();
+
+ // RENDERING VIEW
+ $this->beforeRender();
+ // calls $this->render()
+ $this->tryCall($this->formatRenderMethod($this->view), $this->params);
+ $this->afterRender();
+
+ // save component tree persistent state
+ $this->saveGlobalState();
+ if ($this->isAjax()) {
+ $this->payload->state = $this->getGlobalState();
+ }
+
+ // finish template rendering
+ if ($this->getTemplate()) {
+ $this->sendTemplate();
+ }
+
+ } catch (Application\AbortException $e) {
+ // continue with shutting down
+ if ($this->isAjax()) {
+ try {
+ $hasPayload = (array) $this->payload;
+ unset($hasPayload['state']);
+ if ($this->response instanceof Responses\TextResponse && $this->isControlInvalid()) {
+ $this->snippetMode = TRUE;
+ $this->response->send($this->httpRequest, $this->httpResponse);
+ $this->sendPayload();
+ } elseif (!$this->response && $hasPayload) { // back compatibility for use terminate() instead of sendPayload()
+ $this->sendPayload();
+ }
+ } catch (Application\AbortException $e) {
+ }
+ }
+
+ if ($this->hasFlashSession()) {
+ $this->getFlashSession()->setExpiration($this->response instanceof Responses\RedirectResponse ? '+ 30 seconds' : '+ 3 seconds');
+ }
+
+ // SHUTDOWN
+ $this->onShutdown($this, $this->response);
+ $this->shutdown($this->response);
+
+ return $this->response;
+ }
+ }
+
+
+ /**
+ * @return void
+ */
+ protected function startup()
+ {
+ $this->startupCheck = TRUE;
+ }
+
+
+ /**
+ * Common render method.
+ * @return void
+ */
+ protected function beforeRender()
+ {
+ }
+
+
+ /**
+ * Common render method.
+ * @return void
+ */
+ protected function afterRender()
+ {
+ }
+
+
+ /**
+ * @param Nette\Application\IResponse
+ * @return void
+ */
+ protected function shutdown($response)
+ {
+ }
+
+
+ /**
+ * Checks authorization.
+ * @return void
+ */
+ public function checkRequirements($element)
+ {
+ $user = (array) PresenterComponentReflection::parseAnnotation($element, 'User');
+ if (in_array('loggedIn', $user, TRUE) && !$this->getUser()->isLoggedIn()) {
+ throw new Application\ForbiddenRequestException;
+ }
+ }
+
+
+ /********************* signal handling ****************d*g**/
+
+
+ /**
+ * @return void
+ * @throws BadSignalException
+ */
+ public function processSignal()
+ {
+ if ($this->signal === NULL) {
+ return;
+ }
+
+ try {
+ $component = $this->signalReceiver === '' ? $this : $this->getComponent($this->signalReceiver, FALSE);
+ } catch (Nette\InvalidArgumentException $e) {
+ }
+
+ if (isset($e) || $component === NULL) {
+ throw new BadSignalException("The signal receiver component '$this->signalReceiver' is not found.", NULL, isset($e) ? $e : NULL);
+
+ } elseif (!$component instanceof ISignalReceiver) {
+ throw new BadSignalException("The signal receiver component '$this->signalReceiver' is not ISignalReceiver implementor.");
+ }
+
+ $component->signalReceived($this->signal);
+ $this->signal = NULL;
+ }
+
+
+ /**
+ * Returns pair signal receiver and name.
+ * @return array|NULL
+ */
+ public function getSignal()
+ {
+ return $this->signal === NULL ? NULL : array($this->signalReceiver, $this->signal);
+ }
+
+
+ /**
+ * Checks if the signal receiver is the given one.
+ * @param mixed component or its id
+ * @param string signal name (optional)
+ * @return bool
+ */
+ public function isSignalReceiver($component, $signal = NULL)
+ {
+ if ($component instanceof Nette\ComponentModel\Component) {
+ $component = $component === $this ? '' : $component->lookupPath(__CLASS__, TRUE);
+ }
+
+ if ($this->signal === NULL) {
+ return FALSE;
+
+ } elseif ($signal === TRUE) {
+ return $component === ''
+ || strncmp($this->signalReceiver . '-', $component . '-', strlen($component) + 1) === 0;
+
+ } elseif ($signal === NULL) {
+ return $this->signalReceiver === $component;
+
+ } else {
+ return $this->signalReceiver === $component && strcasecmp($signal, $this->signal) === 0;
+ }
+ }
+
+
+ /********************* rendering ****************d*g**/
+
+
+ /**
+ * Returns current action name.
+ * @return string
+ */
+ public function getAction($fullyQualified = FALSE)
+ {
+ return $fullyQualified ? ':' . $this->getName() . ':' . $this->action : $this->action;
+ }
+
+
+ /**
+ * Changes current action. Only alphanumeric characters are allowed.
+ * @param string
+ * @return void
+ */
+ public function changeAction($action)
+ {
+ if (is_string($action) && Nette\Utils\Strings::match($action, '#^[a-zA-Z0-9][a-zA-Z0-9_\x7f-\xff]*\z#')) {
+ $this->action = $action;
+ $this->view = $action;
+
+ } else {
+ $this->error('Action name is not alphanumeric string.');
+ }
+ }
+
+
+ /**
+ * Returns current view.
+ * @return string
+ */
+ public function getView()
+ {
+ return $this->view;
+ }
+
+
+ /**
+ * Changes current view. Any name is allowed.
+ * @param string
+ * @return self
+ */
+ public function setView($view)
+ {
+ $this->view = (string) $view;
+ return $this;
+ }
+
+
+ /**
+ * Returns current layout name.
+ * @return string|FALSE
+ */
+ public function getLayout()
+ {
+ return $this->layout;
+ }
+
+
+ /**
+ * Changes or disables layout.
+ * @param string|FALSE
+ * @return self
+ */
+ public function setLayout($layout)
+ {
+ $this->layout = $layout === FALSE ? FALSE : (string) $layout;
+ return $this;
+ }
+
+
+ /**
+ * @return void
+ * @throws Nette\Application\BadRequestException if no template found
+ * @throws Nette\Application\AbortException
+ */
+ public function sendTemplate()
+ {
+ $template = $this->getTemplate();
+ if (!$template->getFile()) {
+ $files = $this->formatTemplateFiles();
+ foreach ($files as $file) {
+ if (is_file($file)) {
+ $template->setFile($file);
+ break;
+ }
+ }
+
+ if (!$template->getFile()) {
+ $file = preg_replace('#^.*([/\\\\].{1,70})\z#U', "\xE2\x80\xA6\$1", reset($files));
+ $file = strtr($file, '/', DIRECTORY_SEPARATOR);
+ $this->error("Page not found. Missing template '$file'.");
+ }
+ }
+
+ $this->sendResponse(new Responses\TextResponse($template));
+ }
+
+
+ /**
+ * Finds layout template file name.
+ * @return string
+ * @internal
+ */
+ public function findLayoutTemplateFile()
+ {
+ if ($this->layout === FALSE) {
+ return;
+ }
+ $files = $this->formatLayoutTemplateFiles();
+ foreach ($files as $file) {
+ if (is_file($file)) {
+ return $file;
+ }
+ }
+
+ if ($this->layout) {
+ $file = preg_replace('#^.*([/\\\\].{1,70})\z#U', "\xE2\x80\xA6\$1", reset($files));
+ $file = strtr($file, '/', DIRECTORY_SEPARATOR);
+ throw new Nette\FileNotFoundException("Layout not found. Missing template '$file'.");
+ }
+ }
+
+
+ /**
+ * Formats layout template file names.
+ * @return array
+ */
+ public function formatLayoutTemplateFiles()
+ {
+ $name = $this->getName();
+ $presenter = substr($name, strrpos(':' . $name, ':'));
+ $layout = $this->layout ? $this->layout : 'layout';
+ $dir = dirname($this->getReflection()->getFileName());
+ $dir = is_dir("$dir/templates") ? $dir : dirname($dir);
+ $list = array(
+ "$dir/templates/$presenter/@$layout.latte",
+ "$dir/templates/$presenter.@$layout.latte",
+ );
+ do {
+ $list[] = "$dir/templates/@$layout.latte";
+ $dir = dirname($dir);
+ } while ($dir && ($name = substr($name, 0, strrpos($name, ':'))));
+ return $list;
+ }
+
+
+ /**
+ * Formats view template file names.
+ * @return array
+ */
+ public function formatTemplateFiles()
+ {
+ $name = $this->getName();
+ $presenter = substr($name, strrpos(':' . $name, ':'));
+ $dir = dirname($this->getReflection()->getFileName());
+ $dir = is_dir("$dir/templates") ? $dir : dirname($dir);
+ return array(
+ "$dir/templates/$presenter/$this->view.latte",
+ "$dir/templates/$presenter.$this->view.latte",
+ );
+ }
+
+
+ /**
+ * Formats action method name.
+ * @param string
+ * @return string
+ */
+ public static function formatActionMethod($action)
+ {
+ return 'action' . $action;
+ }
+
+
+ /**
+ * Formats render view method name.
+ * @param string
+ * @return string
+ */
+ public static function formatRenderMethod($view)
+ {
+ return 'render' . $view;
+ }
+
+
+ /**
+ * @return ITemplate
+ */
+ protected function createTemplate()
+ {
+ return $this->getTemplateFactory()->createTemplate($this);
+ }
+
+
+ /********************* partial AJAX rendering ****************d*g**/
+
+
+ /**
+ * @return \stdClass
+ */
+ public function getPayload()
+ {
+ return $this->payload;
+ }
+
+
+ /**
+ * Is AJAX request?
+ * @return bool
+ */
+ public function isAjax()
+ {
+ if ($this->ajaxMode === NULL) {
+ $this->ajaxMode = $this->httpRequest->isAjax();
+ }
+ return $this->ajaxMode;
+ }
+
+
+ /**
+ * Sends AJAX payload to the output.
+ * @return void
+ * @throws Nette\Application\AbortException
+ */
+ public function sendPayload()
+ {
+ $this->sendResponse(new Responses\JsonResponse($this->payload));
+ }
+
+
+ /**
+ * Sends JSON data to the output.
+ * @param mixed
+ * @return void
+ * @throws Nette\Application\AbortException
+ */
+ public function sendJson($data)
+ {
+ $this->sendResponse(new Responses\JsonResponse($data));
+ }
+
+
+ /********************* navigation & flow ****************d*g**/
+
+
+ /**
+ * Sends response and terminates presenter.
+ * @return void
+ * @throws Nette\Application\AbortException
+ */
+ public function sendResponse(Application\IResponse $response)
+ {
+ $this->response = $response;
+ $this->terminate();
+ }
+
+
+ /**
+ * Correctly terminates presenter.
+ * @return void
+ * @throws Nette\Application\AbortException
+ */
+ public function terminate()
+ {
+ throw new Application\AbortException();
+ }
+
+
+ /**
+ * Forward to another presenter or action.
+ * @param string|Request
+ * @param array|mixed
+ * @return void
+ * @throws Nette\Application\AbortException
+ */
+ public function forward($destination, $args = array())
+ {
+ if ($destination instanceof Application\Request) {
+ $this->sendResponse(new Responses\ForwardResponse($destination));
+ }
+
+ $this->createRequest($this, $destination, is_array($args) ? $args : array_slice(func_get_args(), 1), 'forward');
+ $this->sendResponse(new Responses\ForwardResponse($this->lastCreatedRequest));
+ }
+
+
+ /**
+ * Redirect to another URL and ends presenter execution.
+ * @param string
+ * @param int HTTP error code
+ * @return void
+ * @throws Nette\Application\AbortException
+ */
+ public function redirectUrl($url, $code = NULL)
+ {
+ if ($this->isAjax()) {
+ $this->payload->redirect = (string) $url;
+ $this->sendPayload();
+
+ } elseif (!$code) {
+ $code = $this->httpRequest->isMethod('post')
+ ? Http\IResponse::S303_POST_GET
+ : Http\IResponse::S302_FOUND;
+ }
+ $this->sendResponse(new Responses\RedirectResponse($url, $code));
+ }
+
+
+ /**
+ * Throws HTTP error.
+ * @param string
+ * @param int HTTP error code
+ * @return void
+ * @throws Nette\Application\BadRequestException
+ */
+ public function error($message = NULL, $code = Http\IResponse::S404_NOT_FOUND)
+ {
+ throw new Application\BadRequestException($message, $code);
+ }
+
+
+ /**
+ * Link to myself.
+ * @return string
+ * @deprecated
+ */
+ public function backlink()
+ {
+ return $this->getAction(TRUE);
+ }
+
+
+ /**
+ * Returns the last created Request.
+ * @return Nette\Application\Request
+ * @internal
+ */
+ public function getLastCreatedRequest()
+ {
+ return $this->lastCreatedRequest;
+ }
+
+
+ /**
+ * Returns the last created Request flag.
+ * @param string
+ * @return bool
+ * @internal
+ */
+ public function getLastCreatedRequestFlag($flag)
+ {
+ return !empty($this->lastCreatedRequestFlag[$flag]);
+ }
+
+
+ /**
+ * Conditional redirect to canonicalized URI.
+ * @return void
+ * @throws Nette\Application\AbortException
+ */
+ public function canonicalize()
+ {
+ if (!$this->isAjax() && ($this->request->isMethod('get') || $this->request->isMethod('head'))) {
+ try {
+ $url = $this->createRequest($this, $this->action, $this->getGlobalState() + $this->request->getParameters(), 'redirectX');
+ } catch (InvalidLinkException $e) {
+ }
+ if (isset($url) && !$this->httpRequest->getUrl()->isEqual($url)) {
+ $this->sendResponse(new Responses\RedirectResponse($url, Http\IResponse::S301_MOVED_PERMANENTLY));
+ }
+ }
+ }
+
+
+ /**
+ * Attempts to cache the sent entity by its last modification date.
+ * @param string|int|DateTime last modified time
+ * @param string strong entity tag validator
+ * @param mixed optional expiration time
+ * @return void
+ * @throws Nette\Application\AbortException
+ */
+ public function lastModified($lastModified, $etag = NULL, $expire = NULL)
+ {
+ if ($expire !== NULL) {
+ $this->httpResponse->setExpiration($expire);
+ }
+ $helper = new Http\Context($this->httpRequest, $this->httpResponse);
+ if (!$helper->isModified($lastModified, $etag)) {
+ $this->terminate();
+ }
+ }
+
+
+ /**
+ * Request/URL factory.
+ * @param PresenterComponent base
+ * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]"
+ * @param array array of arguments
+ * @param string forward|redirect|link
+ * @return string URL
+ * @throws InvalidLinkException
+ * @internal
+ */
+ protected function createRequest($component, $destination, array $args, $mode)
+ {
+ // note: createRequest supposes that saveState(), run() & tryCall() behaviour is final
+
+ $this->lastCreatedRequest = $this->lastCreatedRequestFlag = NULL;
+
+ // PARSE DESTINATION
+ // 1) fragment
+ $a = strpos($destination, '#');
+ if ($a === FALSE) {
+ $fragment = '';
+ } else {
+ $fragment = substr($destination, $a);
+ $destination = substr($destination, 0, $a);
+ }
+
+ // 2) ?query syntax
+ $a = strpos($destination, '?');
+ if ($a !== FALSE) {
+ parse_str(substr($destination, $a + 1), $args); // requires disabled magic quotes
+ $destination = substr($destination, 0, $a);
+ }
+
+ // 3) URL scheme
+ $a = strpos($destination, '//');
+ if ($a === FALSE) {
+ $scheme = FALSE;
+ } else {
+ $scheme = substr($destination, 0, $a);
+ $destination = substr($destination, $a + 2);
+ }
+
+ // 4) signal or empty
+ if (!$component instanceof self || substr($destination, -1) === '!') {
+ $signal = rtrim($destination, '!');
+ $a = strrpos($signal, ':');
+ if ($a !== FALSE) {
+ $component = $component->getComponent(strtr(substr($signal, 0, $a), ':', '-'));
+ $signal = (string) substr($signal, $a + 1);
+ }
+ if ($signal == NULL) { // intentionally ==
+ throw new InvalidLinkException('Signal must be non-empty string.');
+ }
+ $destination = 'this';
+ }
+
+ if ($destination == NULL) { // intentionally ==
+ throw new InvalidLinkException('Destination must be non-empty string.');
+ }
+
+ // 5) presenter: action
+ $current = FALSE;
+ $a = strrpos($destination, ':');
+ if ($a === FALSE) {
+ $action = $destination === 'this' ? $this->action : $destination;
+ $presenter = $this->getName();
+ $presenterClass = get_class($this);
+
+ } else {
+ $action = (string) substr($destination, $a + 1);
+ if ($destination[0] === ':') { // absolute
+ if ($a < 2) {
+ throw new InvalidLinkException("Missing presenter name in '$destination'.");
+ }
+ $presenter = substr($destination, 1, $a - 1);
+
+ } else { // relative
+ $presenter = $this->getName();
+ $b = strrpos($presenter, ':');
+ if ($b === FALSE) { // no module
+ $presenter = substr($destination, 0, $a);
+ } else { // with module
+ $presenter = substr($presenter, 0, $b + 1) . substr($destination, 0, $a);
+ }
+ }
+ if (!$this->presenterFactory) {
+ throw new Nette\InvalidStateException('Unable to create link to other presenter, service PresenterFactory has not been set.');
+ }
+ try {
+ $presenterClass = $this->presenterFactory->getPresenterClass($presenter);
+ } catch (Application\InvalidPresenterException $e) {
+ throw new InvalidLinkException($e->getMessage(), NULL, $e);
+ }
+ }
+
+ // PROCESS SIGNAL ARGUMENTS
+ if (isset($signal)) { // $component must be IStatePersistent
+ $reflection = new PresenterComponentReflection(get_class($component));
+ if ($signal === 'this') { // means "no signal"
+ $signal = '';
+ if (array_key_exists(0, $args)) {
+ throw new InvalidLinkException("Unable to pass parameters to 'this!' signal.");
+ }
+
+ } elseif (strpos($signal, self::NAME_SEPARATOR) === FALSE) {
+ // counterpart of signalReceived() & tryCall()
+ $method = $component->formatSignalMethod($signal);
+ if (!$reflection->hasCallableMethod($method)) {
+ throw new InvalidLinkException("Unknown signal '$signal', missing handler {$reflection->getName()}::$method()");
+ }
+ if ($args) { // convert indexed parameters to named
+ self::argsToParams(get_class($component), $method, $args);
+ }
+ }
+
+ // counterpart of IStatePersistent
+ if ($args && array_intersect_key($args, $reflection->getPersistentParams())) {
+ $component->saveState($args);
+ }
+
+ if ($args && $component !== $this) {
+ $prefix = $component->getUniqueId() . self::NAME_SEPARATOR;
+ foreach ($args as $key => $val) {
+ unset($args[$key]);
+ $args[$prefix . $key] = $val;
+ }
+ }
+ }
+
+ // PROCESS ARGUMENTS
+ if (is_subclass_of($presenterClass, __CLASS__)) {
+ if ($action === '') {
+ $action = self::DEFAULT_ACTION;
+ }
+
+ $current = ($action === '*' || strcasecmp($action, $this->action) === 0) && $presenterClass === get_class($this);
+
+ $reflection = new PresenterComponentReflection($presenterClass);
+ if ($args || $destination === 'this') {
+ // counterpart of run() & tryCall()
+ $method = $presenterClass::formatActionMethod($action);
+ if (!$reflection->hasCallableMethod($method)) {
+ $method = $presenterClass::formatRenderMethod($action);
+ if (!$reflection->hasCallableMethod($method)) {
+ $method = NULL;
+ }
+ }
+
+ // convert indexed parameters to named
+ if ($method === NULL) {
+ if (array_key_exists(0, $args)) {
+ throw new InvalidLinkException("Unable to pass parameters to action '$presenter:$action', missing corresponding method.");
+ }
+
+ } elseif ($destination === 'this') {
+ self::argsToParams($presenterClass, $method, $args, $this->params);
+
+ } else {
+ self::argsToParams($presenterClass, $method, $args);
+ }
+ }
+
+ // counterpart of IStatePersistent
+ if ($args && array_intersect_key($args, $reflection->getPersistentParams())) {
+ $this->saveState($args, $reflection);
+ }
+
+ if ($mode === 'redirect') {
+ $this->saveGlobalState();
+ }
+
+ $globalState = $this->getGlobalState($destination === 'this' ? NULL : $presenterClass);
+ if ($current && $args) {
+ $tmp = $globalState + $this->params;
+ foreach ($args as $key => $val) {
+ if (http_build_query(array($val)) !== (isset($tmp[$key]) ? http_build_query(array($tmp[$key])) : '')) {
+ $current = FALSE;
+ break;
+ }
+ }
+ }
+ $args += $globalState;
+ }
+
+ // ADD ACTION & SIGNAL & FLASH
+ if ($action) {
+ $args[self::ACTION_KEY] = $action;
+ }
+ if (!empty($signal)) {
+ $args[self::SIGNAL_KEY] = $component->getParameterId($signal);
+ $current = $current && $args[self::SIGNAL_KEY] === $this->getParameter(self::SIGNAL_KEY);
+ }
+ if (($mode === 'redirect' || $mode === 'forward') && $this->hasFlashSession()) {
+ $args[self::FLASH_KEY] = $this->getParameter(self::FLASH_KEY);
+ }
+
+ $this->lastCreatedRequest = new Application\Request(
+ $presenter,
+ Application\Request::FORWARD,
+ $args,
+ array(),
+ array()
+ );
+ $this->lastCreatedRequestFlag = array('current' => $current);
+
+ if ($mode === 'forward' || $mode === 'test') {
+ return;
+ }
+
+ // CONSTRUCT URL
+ static $refUrl;
+ if ($refUrl === NULL) {
+ $refUrl = new Http\Url($this->httpRequest->getUrl());
+ $refUrl->setPath($this->httpRequest->getUrl()->getScriptPath());
+ }
+ if (!$this->router) {
+ throw new Nette\InvalidStateException('Unable to generate URL, service Router has not been set.');
+ }
+ $url = $this->router->constructUrl($this->lastCreatedRequest, $refUrl);
+ if ($url === NULL) {
+ unset($args[self::ACTION_KEY]);
+ $params = urldecode(http_build_query($args, NULL, ', '));
+ throw new InvalidLinkException("No route for $presenter:$action($params)");
+ }
+
+ // make URL relative if possible
+ if ($mode === 'link' && $scheme === FALSE && !$this->absoluteUrls) {
+ $hostUrl = $refUrl->getHostUrl() . '/';
+ if (strncmp($url, $hostUrl, strlen($hostUrl)) === 0) {
+ $url = substr($url, strlen($hostUrl) - 1);
+ }
+ }
+
+ return $url . $fragment;
+ }
+
+
+ /**
+ * Converts list of arguments to named parameters.
+ * @param string class name
+ * @param string method name
+ * @param array arguments
+ * @param array supplemental arguments
+ * @return void
+ * @throws InvalidLinkException
+ * @internal
+ */
+ public static function argsToParams($class, $method, & $args, $supplemental = array())
+ {
+ $i = 0;
+ $rm = new \ReflectionMethod($class, $method);
+ foreach ($rm->getParameters() as $param) {
+ $name = $param->getName();
+ if (array_key_exists($i, $args)) {
+ $args[$name] = $args[$i];
+ unset($args[$i]);
+ $i++;
+
+ } elseif (array_key_exists($name, $args)) {
+ // continue with process
+
+ } elseif (array_key_exists($name, $supplemental)) {
+ $args[$name] = $supplemental[$name];
+
+ } else {
+ continue;
+ }
+
+ if ($args[$name] === NULL) {
+ continue;
+ }
+
+ $def = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : NULL;
+ $type = $param->isArray() ? 'array' : gettype($def);
+ if (!PresenterComponentReflection::convertType($args[$name], $type)) {
+ throw new InvalidLinkException("Invalid value for parameter '$name' in method $class::$method(), expected " . ($type === 'NULL' ? 'scalar' : $type) . ".");
+ }
+
+ if ($args[$name] === $def || ($def === NULL && is_scalar($args[$name]) && (string) $args[$name] === '')) {
+ $args[$name] = NULL; // value transmit is unnecessary
+ }
+ }
+
+ if (array_key_exists($i, $args)) {
+ $method = $rm->getName();
+ throw new InvalidLinkException("Passed more parameters than method $class::$method() expects.");
+ }
+ }
+
+
+ /**
+ * Invalid link handler. Descendant can override this method to change default behaviour.
+ * @return string
+ * @throws InvalidLinkException
+ */
+ protected function handleInvalidLink(InvalidLinkException $e)
+ {
+ if ($this->invalidLinkMode & self::INVALID_LINK_EXCEPTION) {
+ throw $e;
+ } elseif ($this->invalidLinkMode & self::INVALID_LINK_WARNING) {
+ trigger_error('Invalid link: ' . $e->getMessage(), E_USER_WARNING);
+ }
+ return $this->invalidLinkMode & self::INVALID_LINK_TEXTUAL
+ ? '#error: ' . $e->getMessage()
+ : '#';
+ }
+
+
+ /********************* request serialization ****************d*g**/
+
+
+ /**
+ * Stores current request to session.
+ * @param mixed optional expiration time
+ * @return string key
+ */
+ public function storeRequest($expiration = '+ 10 minutes')
+ {
+ $session = $this->getSession('Nette.Application/requests');
+ do {
+ $key = Nette\Utils\Random::generate(5);
+ } while (isset($session[$key]));
+
+ $session[$key] = array($this->getUser()->getId(), $this->request);
+ $session->setExpiration($expiration, $key);
+ return $key;
+ }
+
+
+ /**
+ * Restores request from session.
+ * @param string key
+ * @return void
+ */
+ public function restoreRequest($key)
+ {
+ $session = $this->getSession('Nette.Application/requests');
+ if (!isset($session[$key]) || ($session[$key][0] !== NULL && $session[$key][0] !== $this->getUser()->getId())) {
+ return;
+ }
+ $request = clone $session[$key][1];
+ unset($session[$key]);
+ $request->setFlag(Application\Request::RESTORED, TRUE);
+ $params = $request->getParameters();
+ $params[self::FLASH_KEY] = $this->getParameter(self::FLASH_KEY);
+ $request->setParameters($params);
+ $this->sendResponse(new Responses\ForwardResponse($request));
+ }
+
+
+ /********************* interface IStatePersistent ****************d*g**/
+
+
+ /**
+ * Returns array of persistent components.
+ * This default implementation detects components by class-level annotation @persistent(cmp1, cmp2).
+ * @return array
+ */
+ public static function getPersistentComponents()
+ {
+ return (array) PresenterComponentReflection::parseAnnotation(new \ReflectionClass(get_called_class()), 'persistent');
+ }
+
+
+ /**
+ * Saves state information for all subcomponents to $this->globalState.
+ * @return array
+ */
+ protected function getGlobalState($forClass = NULL)
+ {
+ $sinces = & $this->globalStateSinces;
+
+ if ($this->globalState === NULL) {
+ $state = array();
+ foreach ($this->globalParams as $id => $params) {
+ $prefix = $id . self::NAME_SEPARATOR;
+ foreach ($params as $key => $val) {
+ $state[$prefix . $key] = $val;
+ }
+ }
+ $this->saveState($state, $forClass ? new PresenterComponentReflection($forClass) : NULL);
+
+ if ($sinces === NULL) {
+ $sinces = array();
+ foreach ($this->getReflection()->getPersistentParams() as $name => $meta) {
+ $sinces[$name] = $meta['since'];
+ }
+ }
+
+ $components = $this->getReflection()->getPersistentComponents();
+ $iterator = $this->getComponents(TRUE, 'Nette\Application\UI\IStatePersistent');
+
+ foreach ($iterator as $name => $component) {
+ if ($iterator->getDepth() === 0) {
+ // counts with Nette\Application\RecursiveIteratorIterator::SELF_FIRST
+ $since = isset($components[$name]['since']) ? $components[$name]['since'] : FALSE; // FALSE = nonpersistent
+ }
+ $prefix = $component->getUniqueId() . self::NAME_SEPARATOR;
+ $params = array();
+ $component->saveState($params);
+ foreach ($params as $key => $val) {
+ $state[$prefix . $key] = $val;
+ $sinces[$prefix . $key] = $since;
+ }
+ }
+
+ } else {
+ $state = $this->globalState;
+ }
+
+ if ($forClass !== NULL) {
+ $since = NULL;
+ foreach ($state as $key => $foo) {
+ if (!isset($sinces[$key])) {
+ $x = strpos($key, self::NAME_SEPARATOR);
+ $x = $x === FALSE ? $key : substr($key, 0, $x);
+ $sinces[$key] = isset($sinces[$x]) ? $sinces[$x] : FALSE;
+ }
+ if ($since !== $sinces[$key]) {
+ $since = $sinces[$key];
+ $ok = $since && (is_subclass_of($forClass, $since) || $forClass === $since);
+ }
+ if (!$ok) {
+ unset($state[$key]);
+ }
+ }
+ }
+
+ return $state;
+ }
+
+
+ /**
+ * Permanently saves state information for all subcomponents to $this->globalState.
+ * @return void
+ */
+ protected function saveGlobalState()
+ {
+ $this->globalParams = array();
+ $this->globalState = $this->getGlobalState();
+ }
+
+
+ /**
+ * Initializes $this->globalParams, $this->signal & $this->signalReceiver, $this->action, $this->view. Called by run().
+ * @return void
+ * @throws Nette\Application\BadRequestException if action name is not valid
+ */
+ private function initGlobalParameters()
+ {
+ // init $this->globalParams
+ $this->globalParams = array();
+ $selfParams = array();
+
+ $params = $this->request->getParameters();
+ if ($this->isAjax()) {
+ $params += $this->request->getPost();
+ }
+ if (($tmp = $this->request->getPost(self::SIGNAL_KEY)) !== NULL) {
+ $params[self::SIGNAL_KEY] = $tmp;
+ }
+
+ foreach ($params as $key => $value) {
+ if (!preg_match('#^((?:[a-z0-9_]+-)*)((?!\d+\z)[a-z0-9_]+)\z#i', $key, $matches)) {
+ continue;
+ } elseif (!$matches[1]) {
+ $selfParams[$key] = $value;
+ } else {
+ $this->globalParams[substr($matches[1], 0, -1)][$matches[2]] = $value;
+ }
+ }
+
+ // init & validate $this->action & $this->view
+ $this->changeAction(isset($selfParams[self::ACTION_KEY]) ? $selfParams[self::ACTION_KEY] : self::DEFAULT_ACTION);
+
+ // init $this->signalReceiver and key 'signal' in appropriate params array
+ $this->signalReceiver = $this->getUniqueId();
+ if (isset($selfParams[self::SIGNAL_KEY])) {
+ $param = $selfParams[self::SIGNAL_KEY];
+ if (!is_string($param)) {
+ $this->error('Signal name is not string.');
+ }
+ $pos = strrpos($param, '-');
+ if ($pos) {
+ $this->signalReceiver = substr($param, 0, $pos);
+ $this->signal = substr($param, $pos + 1);
+ } else {
+ $this->signalReceiver = $this->getUniqueId();
+ $this->signal = $param;
+ }
+ if ($this->signal == NULL) { // intentionally ==
+ $this->signal = NULL;
+ }
+ }
+
+ $this->loadState($selfParams);
+ }
+
+
+ /**
+ * Pops parameters for specified component.
+ * @param string component id
+ * @return array
+ * @internal
+ */
+ public function popGlobalParameters($id)
+ {
+ if (isset($this->globalParams[$id])) {
+ $res = $this->globalParams[$id];
+ unset($this->globalParams[$id]);
+ return $res;
+
+ } else {
+ return array();
+ }
+ }
+
+
+ /********************* flash session ****************d*g**/
+
+
+ /**
+ * Checks if a flash session namespace exists.
+ * @return bool
+ */
+ public function hasFlashSession()
+ {
+ return !empty($this->params[self::FLASH_KEY])
+ && $this->getSession()->hasSection('Nette.Application.Flash/' . $this->params[self::FLASH_KEY]);
+ }
+
+
+ /**
+ * Returns session namespace provided to pass temporary data between redirects.
+ * @return Nette\Http\SessionSection
+ */
+ public function getFlashSession()
+ {
+ if (empty($this->params[self::FLASH_KEY])) {
+ $this->params[self::FLASH_KEY] = Nette\Utils\Random::generate(4);
+ }
+ return $this->getSession('Nette.Application.Flash/' . $this->params[self::FLASH_KEY]);
+ }
+
+
+ /********************* services ****************d*g**/
+
+
+ public function injectPrimary(Nette\DI\Container $context = NULL, Application\IPresenterFactory $presenterFactory = NULL, Application\IRouter $router = NULL,
+ Http\IRequest $httpRequest, Http\IResponse $httpResponse, Http\Session $session = NULL, Nette\Security\User $user = NULL, ITemplateFactory $templateFactory = NULL)
+ {
+ if ($this->presenterFactory !== NULL) {
+ throw new Nette\InvalidStateException('Method ' . __METHOD__ . ' is intended for initialization and should not be called more than once.');
+ }
+
+ $this->context = $context;
+ $this->presenterFactory = $presenterFactory;
+ $this->router = $router;
+ $this->httpRequest = $httpRequest;
+ $this->httpResponse = $httpResponse;
+ $this->session = $session;
+ $this->user = $user;
+ $this->templateFactory = $templateFactory;
+ }
+
+
+ /**
+ * Gets the context.
+ * @return Nette\DI\Container
+ * @deprecated
+ */
+ public function getContext()
+ {
+ if (!$this->context) {
+ throw new Nette\InvalidStateException('Context has not been set.');
+ }
+ return $this->context;
+ }
+
+
+ /**
+ * @return Nette\Http\IRequest
+ */
+ protected function getHttpRequest()
+ {
+ return $this->httpRequest;
+ }
+
+
+ /**
+ * @return Nette\Http\IResponse
+ */
+ protected function getHttpResponse()
+ {
+ return $this->httpResponse;
+ }
+
+
+ /**
+ * @param string
+ * @return Nette\Http\Session|Nette\Http\SessionSection
+ */
+ public function getSession($namespace = NULL)
+ {
+ if (!$this->session) {
+ throw new Nette\InvalidStateException('Service Session has not been set.');
+ }
+ return $namespace === NULL ? $this->session : $this->session->getSection($namespace);
+ }
+
+
+ /**
+ * @return Nette\Security\User
+ */
+ public function getUser()
+ {
+ if (!$this->user) {
+ throw new Nette\InvalidStateException('Service User has not been set.');
+ }
+ return $this->user;
+ }
+
+
+ /**
+ * @return ITemplateFactory
+ */
+ public function getTemplateFactory()
+ {
+ if (!$this->templateFactory) {
+ throw new Nette\InvalidStateException('Service TemplateFactory has not been set.');
+ }
+ return $this->templateFactory;
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/UI/PresenterComponent.php b/vendor/nette/application/src/Application/UI/PresenterComponent.php
new file mode 100755
index 0000000..e8b36c9
--- /dev/null
+++ b/vendor/nette/application/src/Application/UI/PresenterComponent.php
@@ -0,0 +1,395 @@
+lookup('Nette\Application\UI\Presenter', $need);
+ }
+
+
+ /**
+ * Returns a fully-qualified name that uniquely identifies the component
+ * within the presenter hierarchy.
+ * @return string
+ */
+ public function getUniqueId()
+ {
+ return $this->lookupPath('Nette\Application\UI\Presenter', TRUE);
+ }
+
+
+ /**
+ * This method will be called when the component (or component's parent)
+ * becomes attached to a monitored object. Do not call this method yourself.
+ * @param Nette\ComponentModel\IComponent
+ * @return void
+ */
+ protected function attached($presenter)
+ {
+ if ($presenter instanceof Presenter) {
+ $this->loadState($presenter->popGlobalParameters($this->getUniqueId()));
+ }
+ }
+
+
+ /**
+ * @return void
+ */
+ protected function validateParent(Nette\ComponentModel\IContainer $parent)
+ {
+ parent::validateParent($parent);
+ $this->monitor('Nette\Application\UI\Presenter');
+ }
+
+
+ /**
+ * Calls public method if exists.
+ * @param string
+ * @param array
+ * @return bool does method exist?
+ */
+ protected function tryCall($method, array $params)
+ {
+ $rc = $this->getReflection();
+ if ($rc->hasMethod($method)) {
+ $rm = $rc->getMethod($method);
+ if ($rm->isPublic() && !$rm->isAbstract() && !$rm->isStatic()) {
+ $this->checkRequirements($rm);
+ $rm->invokeArgs($this, $rc->combineArgs($rm, $params));
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+
+
+ /**
+ * Checks for requirements such as authorization.
+ * @return void
+ */
+ public function checkRequirements($element)
+ {
+ }
+
+
+ /**
+ * Access to reflection.
+ * @return PresenterComponentReflection
+ */
+ public static function getReflection()
+ {
+ return new PresenterComponentReflection(get_called_class());
+ }
+
+
+ /********************* interface IStatePersistent ****************d*g**/
+
+
+ /**
+ * Loads state informations.
+ * @param array
+ * @return void
+ */
+ public function loadState(array $params)
+ {
+ $reflection = $this->getReflection();
+ foreach ($reflection->getPersistentParams() as $name => $meta) {
+ if (isset($params[$name])) { // NULLs are ignored
+ $type = gettype($meta['def']);
+ if (!$reflection->convertType($params[$name], $type)) {
+ throw new Nette\Application\BadRequestException("Invalid value for persistent parameter '$name' in '{$this->getName()}', expected " . ($type === 'NULL' ? 'scalar' : $type) . ".");
+ }
+ $this->$name = $params[$name];
+ } else {
+ $params[$name] = $this->$name;
+ }
+ }
+ $this->params = $params;
+ }
+
+
+ /**
+ * Saves state informations for next request.
+ * @param array
+ * @param PresenterComponentReflection (internal, used by Presenter)
+ * @return void
+ */
+ public function saveState(array & $params, $reflection = NULL)
+ {
+ $reflection = $reflection === NULL ? $this->getReflection() : $reflection;
+ foreach ($reflection->getPersistentParams() as $name => $meta) {
+
+ if (isset($params[$name])) {
+ // injected value
+
+ } elseif (array_key_exists($name, $params)) { // NULLs are skipped
+ continue;
+
+ } elseif (!isset($meta['since']) || $this instanceof $meta['since']) {
+ $params[$name] = $this->$name; // object property value
+
+ } else {
+ continue; // ignored parameter
+ }
+
+ $type = gettype($meta['def']);
+ if (!PresenterComponentReflection::convertType($params[$name], $type)) {
+ throw new InvalidLinkException(sprintf("Invalid value for persistent parameter '%s' in '%s', expected %s.", $name, $this->getName(), $type === 'NULL' ? 'scalar' : $type));
+ }
+
+ if ($params[$name] === $meta['def'] || ($meta['def'] === NULL && is_scalar($params[$name]) && (string) $params[$name] === '')) {
+ $params[$name] = NULL; // value transmit is unnecessary
+ }
+ }
+ }
+
+
+ /**
+ * Returns component param.
+ * @param string key
+ * @param mixed default value
+ * @return mixed
+ */
+ public function getParameter($name, $default = NULL)
+ {
+ if (isset($this->params[$name])) {
+ return $this->params[$name];
+
+ } else {
+ return $default;
+ }
+ }
+
+
+ /**
+ * Returns component parameters.
+ * @return array
+ */
+ public function getParameters()
+ {
+ return $this->params;
+ }
+
+
+ /**
+ * Returns a fully-qualified name that uniquely identifies the parameter.
+ * @param string
+ * @return string
+ */
+ public function getParameterId($name)
+ {
+ $uid = $this->getUniqueId();
+ return $uid === '' ? $name : $uid . self::NAME_SEPARATOR . $name;
+ }
+
+
+ /** @deprecated */
+ function getParam($name = NULL, $default = NULL)
+ {
+ //trigger_error(__METHOD__ . '() is deprecated; use getParameter() instead.', E_USER_DEPRECATED);
+ return func_num_args() ? $this->getParameter($name, $default) : $this->getParameters();
+ }
+
+
+ /**
+ * Returns array of classes persistent parameters. They have public visibility and are non-static.
+ * This default implementation detects persistent parameters by annotation @persistent.
+ * @return array
+ */
+ public static function getPersistentParams()
+ {
+ $rc = new \ReflectionClass(get_called_class());
+ $params = array();
+ foreach ($rc->getProperties(\ReflectionProperty::IS_PUBLIC) as $rp) {
+ if (!$rp->isStatic() && PresenterComponentReflection::parseAnnotation($rp, 'persistent')) {
+ $params[] = $rp->getName();
+ }
+ }
+ return $params;
+ }
+
+
+ /********************* interface ISignalReceiver ****************d*g**/
+
+
+ /**
+ * Calls signal handler method.
+ * @param string
+ * @return void
+ * @throws BadSignalException if there is not handler method
+ */
+ public function signalReceived($signal)
+ {
+ if (!$this->tryCall($this->formatSignalMethod($signal), $this->params)) {
+ $class = get_class($this);
+ throw new BadSignalException("There is no handler for signal '$signal' in class $class.");
+ }
+ }
+
+
+ /**
+ * Formats signal handler method name -> case sensitivity doesn't matter.
+ * @param string
+ * @return string
+ */
+ public static function formatSignalMethod($signal)
+ {
+ return $signal == NULL ? NULL : 'handle' . $signal; // intentionally ==
+ }
+
+
+ /********************* navigation ****************d*g**/
+
+
+ /**
+ * Generates URL to presenter, action or signal.
+ * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]"
+ * @param array|mixed
+ * @return string
+ * @throws InvalidLinkException
+ */
+ public function link($destination, $args = array())
+ {
+ try {
+ return $this->getPresenter()->createRequest($this, $destination, is_array($args) ? $args : array_slice(func_get_args(), 1), 'link');
+
+ } catch (InvalidLinkException $e) {
+ return $this->getPresenter()->handleInvalidLink($e);
+ }
+ }
+
+
+ /**
+ * Returns destination as Link object.
+ * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]"
+ * @param array|mixed
+ * @return Link
+ */
+ public function lazyLink($destination, $args = array())
+ {
+ return new Link($this, $destination, is_array($args) ? $args : array_slice(func_get_args(), 1));
+ }
+
+
+ /**
+ * Determines whether it links to the current page.
+ * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]"
+ * @param array|mixed
+ * @return bool
+ * @throws InvalidLinkException
+ */
+ public function isLinkCurrent($destination = NULL, $args = array())
+ {
+ if ($destination !== NULL) {
+ $this->getPresenter()->createRequest($this, $destination, is_array($args) ? $args : array_slice(func_get_args(), 1), 'test');
+ }
+ return $this->getPresenter()->getLastCreatedRequestFlag('current');
+ }
+
+
+ /**
+ * Redirect to another presenter, action or signal.
+ * @param int [optional] HTTP error code
+ * @param string destination in format "[//] [[[module:]presenter:]action | signal! | this] [#fragment]"
+ * @param array|mixed
+ * @return void
+ * @throws Nette\Application\AbortException
+ */
+ public function redirect($code, $destination = NULL, $args = array())
+ {
+ if (!is_numeric($code)) { // first parameter is optional
+ $args = is_array($destination) ? $destination : array_slice(func_get_args(), 1);
+ $destination = $code;
+ $code = NULL;
+
+ } elseif (!is_array($args)) {
+ $args = array_slice(func_get_args(), 2);
+ }
+
+ $presenter = $this->getPresenter();
+ $presenter->redirectUrl($presenter->createRequest($this, $destination, $args, 'redirect'), $code);
+ }
+
+
+ /********************* interface \ArrayAccess ****************d*g**/
+
+
+ /**
+ * Adds the component to the container.
+ * @param string component name
+ * @param Nette\ComponentModel\IComponent
+ * @return void
+ */
+ public function offsetSet($name, $component)
+ {
+ $this->addComponent($component, $name);
+ }
+
+
+ /**
+ * Returns component specified by name. Throws exception if component doesn't exist.
+ * @param string component name
+ * @return Nette\ComponentModel\IComponent
+ * @throws Nette\InvalidArgumentException
+ */
+ public function offsetGet($name)
+ {
+ return $this->getComponent($name, TRUE);
+ }
+
+
+ /**
+ * Does component specified by name exists?
+ * @param string component name
+ * @return bool
+ */
+ public function offsetExists($name)
+ {
+ return $this->getComponent($name, FALSE) !== NULL;
+ }
+
+
+ /**
+ * Removes component from the container.
+ * @param string component name
+ * @return void
+ */
+ public function offsetUnset($name)
+ {
+ $component = $this->getComponent($name, FALSE);
+ if ($component !== NULL) {
+ $this->removeComponent($component);
+ }
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/UI/PresenterComponentReflection.php b/vendor/nette/application/src/Application/UI/PresenterComponentReflection.php
new file mode 100755
index 0000000..3712616
--- /dev/null
+++ b/vendor/nette/application/src/Application/UI/PresenterComponentReflection.php
@@ -0,0 +1,184 @@
+getName() : $class;
+ $params = & self::$ppCache[$class];
+ if ($params !== NULL) {
+ return $params;
+ }
+ $params = array();
+ if (is_subclass_of($class, 'Nette\Application\UI\PresenterComponent')) {
+ $defaults = get_class_vars($class);
+ foreach ($class::getPersistentParams() as $name => $default) {
+ if (is_int($name)) {
+ $name = $default;
+ $default = $defaults[$name];
+ }
+ $params[$name] = array(
+ 'def' => $default,
+ 'since' => $class,
+ );
+ }
+ foreach ($this->getPersistentParams(get_parent_class($class)) as $name => $param) {
+ if (isset($params[$name])) {
+ $params[$name]['since'] = $param['since'];
+ continue;
+ }
+
+ $params[$name] = $param;
+ }
+ }
+ return $params;
+ }
+
+
+ /**
+ * @param string|NULL
+ * @return array of persistent components.
+ */
+ public function getPersistentComponents($class = NULL)
+ {
+ $class = $class === NULL ? $this->getName() : $class;
+ $components = & self::$pcCache[$class];
+ if ($components !== NULL) {
+ return $components;
+ }
+ $components = array();
+ if (is_subclass_of($class, 'Nette\Application\UI\Presenter')) {
+ foreach ($class::getPersistentComponents() as $name => $meta) {
+ if (is_string($meta)) {
+ $name = $meta;
+ }
+ $components[$name] = array('since' => $class);
+ }
+ $components = $this->getPersistentComponents(get_parent_class($class)) + $components;
+ }
+ return $components;
+ }
+
+
+ /**
+ * Is a method callable? It means class is instantiable and method has
+ * public visibility, is non-static and non-abstract.
+ * @param string method name
+ * @return bool
+ */
+ public function hasCallableMethod($method)
+ {
+ $class = $this->getName();
+ $cache = & self::$mcCache[strtolower($class . ':' . $method)];
+ if ($cache === NULL) {
+ try {
+ $cache = FALSE;
+ $rm = new \ReflectionMethod($class, $method);
+ $cache = $this->isInstantiable() && $rm->isPublic() && !$rm->isAbstract() && !$rm->isStatic();
+ } catch (\ReflectionException $e) {
+ }
+ }
+ return $cache;
+ }
+
+
+ /**
+ * @return array
+ */
+ public static function combineArgs(\ReflectionFunctionAbstract $method, $args)
+ {
+ $res = array();
+ $i = 0;
+ foreach ($method->getParameters() as $param) {
+ $name = $param->getName();
+ if (isset($args[$name])) { // NULLs are ignored
+ $res[$i++] = $args[$name];
+ $type = $param->isArray() ? 'array' : ($param->isDefaultValueAvailable() ? gettype($param->getDefaultValue()) : 'NULL');
+ if (!self::convertType($res[$i - 1], $type)) {
+ $mName = $method instanceof \ReflectionMethod ? $method->getDeclaringClass()->getName() . '::' . $method->getName() : $method->getName();
+ throw new BadRequestException("Invalid value for parameter '$name' in method $mName(), expected " . ($type === 'NULL' ? 'scalar' : $type) . ".");
+ }
+ } else {
+ $res[$i++] = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : ($param->isArray() ? array() : NULL);
+ }
+ }
+ return $res;
+ }
+
+
+ /**
+ * Non data-loss type conversion.
+ * @param mixed
+ * @param string
+ * @return bool
+ */
+ public static function convertType(& $val, $type)
+ {
+ if ($val === NULL || is_object($val)) {
+ // ignore
+ } elseif ($type === 'array') {
+ if (!is_array($val)) {
+ return FALSE;
+ }
+ } elseif (!is_scalar($val)) {
+ return FALSE;
+
+ } elseif ($type !== 'NULL') {
+ $old = $tmp = ($val === FALSE ? '0' : (string) $val);
+ settype($tmp, $type);
+ if ($old !== ($tmp === FALSE ? '0' : (string) $tmp)) {
+ return FALSE; // data-loss occurs
+ }
+ $val = $tmp;
+ }
+ return TRUE;
+ }
+
+
+ /**
+ * Returns an annotation value.
+ * @return array|FALSE
+ */
+ public static function parseAnnotation(\Reflector $ref, $name)
+ {
+ if (!preg_match_all("#[\\s*]@$name(?:\(\\s*([^)]*)\\s*\))?#", $ref->getDocComment(), $m)) {
+ return FALSE;
+ }
+ $res = array();
+ foreach ($m[1] as $s) {
+ $arr = $s === '' ? array(TRUE) : preg_split('#\s*,\s*#', $s, -1, PREG_SPLIT_NO_EMPTY);
+ $res = array_merge($res, $arr);
+ }
+ return $res;
+ }
+
+}
diff --git a/vendor/nette/application/src/Application/exceptions.php b/vendor/nette/application/src/Application/exceptions.php
new file mode 100755
index 0000000..4a62e69
--- /dev/null
+++ b/vendor/nette/application/src/Application/exceptions.php
@@ -0,0 +1,61 @@
+ 504 ? $this->code : $code, $previous);
+ }
+
+}
+
+
+/**
+ * Forbidden request exception - access denied.
+ */
+class ForbiddenRequestException extends BadRequestException
+{
+ /** @var int */
+ protected $code = 403;
+
+}
diff --git a/vendor/nette/application/src/Application/templates/error.phtml b/vendor/nette/application/src/Application/templates/error.phtml
new file mode 100755
index 0000000..73970cf
--- /dev/null
+++ b/vendor/nette/application/src/Application/templates/error.phtml
@@ -0,0 +1,38 @@
+ array('Oops...', 'Your browser sent a request that this server could not understand or process.'),
+ 403 => array('Access Denied', 'You do not have permission to view this page. Please try contact the web site administrator if you believe you should be able to view this page.'),
+ 404 => array('Page Not Found', 'The page you requested could not be found. It is possible that the address is incorrect, or that the page no longer exists. Please use a search engine to find what you are looking for.'),
+ 405 => array('Method Not Allowed', 'The requested method is not allowed for the URL.'),
+ 410 => array('Page Not Found', 'The page you requested has been taken off the site. We apologize for the inconvenience.'),
+ 500 => array('Server Error', 'We\'re sorry! The server encountered an internal error and was unable to complete your request. Please try again later.'),
+);
+$message = isset($messages[$code]) ? $messages[$code] : $messages[0];
+
+?>
+
+
+
+
+
+
+
+
+
+
+
+
+error
diff --git a/vendor/nette/application/src/Bridges/ApplicationDI/ApplicationExtension.php b/vendor/nette/application/src/Bridges/ApplicationDI/ApplicationExtension.php
new file mode 100755
index 0000000..9b6f4cf
--- /dev/null
+++ b/vendor/nette/application/src/Bridges/ApplicationDI/ApplicationExtension.php
@@ -0,0 +1,159 @@
+ TRUE,
+ 'errorPresenter' => 'Nette:Error',
+ 'catchExceptions' => NULL,
+ 'mapping' => NULL,
+ 'scanDirs' => array(),
+ 'scanComposer' => NULL,
+ 'scanFilter' => 'Presenter',
+ 'silentLinks' => FALSE,
+ );
+
+ /** @var bool */
+ private $debugMode;
+
+ /** @var int */
+ private $invalidLinkMode;
+
+ /** @var string */
+ private $tempFile;
+
+
+ public function __construct($debugMode = FALSE, array $scanDirs = NULL, $tempDir = NULL)
+ {
+ $this->defaults['scanDirs'] = (array) $scanDirs;
+ $this->defaults['scanComposer'] = class_exists('Composer\Autoload\ClassLoader');
+ $this->defaults['catchExceptions'] = !$debugMode;
+ $this->debugMode = $debugMode;
+ $this->tempFile = $tempDir ? $tempDir . '/' . urlencode(__CLASS__) : NULL;
+ }
+
+
+ public function loadConfiguration()
+ {
+ $config = $this->validateConfig($this->defaults);
+ $container = $this->getContainerBuilder();
+ $container->addExcludedClasses(array('Nette\Application\UI\Control'));
+
+ $this->invalidLinkMode = $this->debugMode
+ ? UI\Presenter::INVALID_LINK_TEXTUAL | ($config['silentLinks'] ? 0 : UI\Presenter::INVALID_LINK_WARNING)
+ : UI\Presenter::INVALID_LINK_WARNING;
+
+ $application = $container->addDefinition($this->prefix('application'))
+ ->setClass('Nette\Application\Application')
+ ->addSetup('$catchExceptions', array($config['catchExceptions']))
+ ->addSetup('$errorPresenter', array($config['errorPresenter']));
+
+ if ($config['debugger']) {
+ $application->addSetup('Nette\Bridges\ApplicationTracy\RoutingPanel::initializePanel');
+ }
+
+ $touch = $this->debugMode && $config['scanDirs'] ? $this->tempFile : NULL;
+ $presenterFactory = $container->addDefinition($this->prefix('presenterFactory'))
+ ->setClass('Nette\Application\IPresenterFactory')
+ ->setFactory('Nette\Application\PresenterFactory', array(new Nette\DI\Statement(
+ 'Nette\Bridges\ApplicationDI\PresenterFactoryCallback', array(1 => $this->invalidLinkMode, $touch)
+ )));
+
+ if ($config['mapping']) {
+ $presenterFactory->addSetup('setMapping', array($config['mapping']));
+ }
+
+ $container->addDefinition($this->prefix('linkGenerator'))
+ ->setFactory('Nette\Application\LinkGenerator', array(
+ 1 => new Nette\DI\Statement('@Nette\Http\IRequest::getUrl'),
+ ));
+
+ if ($this->name === 'application') {
+ $container->addAlias('application', $this->prefix('application'));
+ $container->addAlias('nette.presenterFactory', $this->prefix('presenterFactory'));
+ }
+ }
+
+
+ public function beforeCompile()
+ {
+ $container = $this->getContainerBuilder();
+ $all = array();
+
+ foreach ($container->findByType('Nette\Application\IPresenter') as $def) {
+ $all[$def->getClass()] = $def;
+ }
+
+ $counter = 0;
+ foreach ($this->findPresenters() as $class) {
+ if (empty($all[$class])) {
+ $all[$class] = $container->addDefinition($this->prefix(++$counter))->setClass($class);
+ }
+ }
+
+ foreach ($all as $def) {
+ $def->setInject(TRUE)->setAutowired(FALSE)->addTag('nette.presenter', $def->getClass());
+ if (is_subclass_of($def->getClass(), 'Nette\Application\UI\Presenter')) {
+ $def->addSetup('$invalidLinkMode', array($this->invalidLinkMode));
+ }
+ }
+ }
+
+
+ /** @return string[] */
+ private function findPresenters()
+ {
+ $config = $this->getConfig();
+ $classes = array();
+
+ if ($config['scanDirs']) {
+ if (!class_exists('Nette\Loaders\RobotLoader')) {
+ throw new Nette\NotSupportedException("RobotLoader is required to find presenters, install package `nette/robot-loader` or disable option {$this->prefix('scanDirs')}: false");
+ }
+ $robot = new Nette\Loaders\RobotLoader;
+ $robot->setCacheStorage(new Nette\Caching\Storages\DevNullStorage);
+ $robot->addDirectory($config['scanDirs']);
+ $robot->acceptFiles = '*' . $config['scanFilter'] . '*.php';
+ $robot->rebuild();
+ $classes = array_keys($robot->getIndexedClasses());
+ $this->getContainerBuilder()->addDependency($this->tempFile);
+ }
+
+ if ($config['scanComposer']) {
+ $rc = new \ReflectionClass('Composer\Autoload\ClassLoader');
+ $classFile = dirname($rc->getFileName()) . '/autoload_classmap.php';
+ if (is_file($classFile)) {
+ $this->getContainerBuilder()->addDependency($classFile);
+ $classes = array_merge($classes, array_keys(call_user_func(function ($path) {
+ return require $path;
+ }, $classFile)));
+ }
+ }
+
+ $presenters = array();
+ foreach (array_unique($classes) as $class) {
+ if (strpos($class, $config['scanFilter']) !== FALSE && class_exists($class)
+ && ($rc = new \ReflectionClass($class)) && $rc->implementsInterface('Nette\Application\IPresenter')
+ && !$rc->isAbstract()
+ ) {
+ $presenters[] = $rc->getName();
+ }
+ }
+ return $presenters;
+ }
+
+}
diff --git a/vendor/nette/application/src/Bridges/ApplicationDI/LatteExtension.php b/vendor/nette/application/src/Bridges/ApplicationDI/LatteExtension.php
new file mode 100755
index 0000000..3321f61
--- /dev/null
+++ b/vendor/nette/application/src/Bridges/ApplicationDI/LatteExtension.php
@@ -0,0 +1,107 @@
+ FALSE,
+ 'macros' => array(),
+ );
+
+ /** @var bool */
+ private $debugMode;
+
+ /** @var string */
+ private $tempDir;
+
+
+ public function __construct($tempDir, $debugMode = FALSE)
+ {
+ $this->tempDir = $tempDir;
+ $this->debugMode = $debugMode;
+ }
+
+
+ public function loadConfiguration()
+ {
+ if (!class_exists('Latte\Engine')) {
+ return;
+ }
+
+ $config = $this->validateConfig($this->defaults);
+ $container = $this->getContainerBuilder();
+
+ $latteFactory = $container->addDefinition($this->prefix('latteFactory'))
+ ->setClass('Latte\Engine')
+ ->addSetup('setTempDirectory', array($this->tempDir))
+ ->addSetup('setAutoRefresh', array($this->debugMode))
+ ->addSetup('setContentType', array($config['xhtml'] ? Latte\Compiler::CONTENT_XHTML : Latte\Compiler::CONTENT_HTML))
+ ->addSetup('Nette\Utils\Html::$xhtml = ?', array((bool) $config['xhtml']))
+ ->setImplement('Nette\Bridges\ApplicationLatte\ILatteFactory');
+
+ $container->addDefinition($this->prefix('templateFactory'))
+ ->setClass('Nette\Application\UI\ITemplateFactory')
+ ->setFactory('Nette\Bridges\ApplicationLatte\TemplateFactory');
+
+ $container->addDefinition('nette.latte')
+ ->setClass('Latte\Engine')
+ ->addSetup('::trigger_error', array('Service nette.latte is deprecated, implement Nette\Bridges\ApplicationLatte\ILatteFactory.', E_USER_DEPRECATED))
+ ->addSetup('setTempDirectory', array($this->tempDir))
+ ->addSetup('setAutoRefresh', array($this->debugMode))
+ ->addSetup('setContentType', array($config['xhtml'] ? Latte\Compiler::CONTENT_XHTML : Latte\Compiler::CONTENT_HTML))
+ ->addSetup('Nette\Utils\Html::$xhtml = ?', array((bool) $config['xhtml']))
+ ->setAutowired(FALSE);
+
+ foreach ($config['macros'] as $macro) {
+ if (strpos($macro, '::') === FALSE && class_exists($macro)) {
+ $macro .= '::install';
+ }
+ $this->addMacro($macro);
+ }
+
+ if (class_exists('Nette\Templating\FileTemplate')) {
+ $container->addDefinition('nette.template')
+ ->setFactory('Nette\Templating\FileTemplate')
+ ->addSetup('::trigger_error', array('Service nette.template is deprecated.', E_USER_DEPRECATED))
+ ->addSetup('registerFilter', array(new Nette\DI\Statement(array($latteFactory, 'create'))))
+ ->addSetup('registerHelperLoader', array('Nette\Templating\Helpers::loader'))
+ ->setAutowired(FALSE);
+ }
+
+ if ($this->name === 'latte') {
+ $container->addAlias('nette.latteFactory', $this->prefix('latteFactory'));
+ $container->addAlias('nette.templateFactory', $this->prefix('templateFactory'));
+ }
+ }
+
+
+ /**
+ * @param callable
+ * @return void
+ */
+ public function addMacro($macro)
+ {
+ Nette\Utils\Validators::assert($macro, 'callable');
+
+ $container = $this->getContainerBuilder();
+ $container->getDefinition('nette.latte')
+ ->addSetup('?->onCompile[] = function ($engine) { ' . $macro . '($engine->getCompiler()); }', array('@self'));
+
+ $container->getDefinition($this->prefix('latteFactory'))
+ ->addSetup('?->onCompile[] = function ($engine) { ' . $macro . '($engine->getCompiler()); }', array('@self'));
+ }
+
+}
diff --git a/vendor/nette/application/src/Bridges/ApplicationDI/PresenterFactoryCallback.php b/vendor/nette/application/src/Bridges/ApplicationDI/PresenterFactoryCallback.php
new file mode 100755
index 0000000..9bd6021
--- /dev/null
+++ b/vendor/nette/application/src/Bridges/ApplicationDI/PresenterFactoryCallback.php
@@ -0,0 +1,62 @@
+container = $container;
+ $this->invalidLinkMode = $invalidLinkMode;
+ $this->touchToRefresh = $touchToRefresh;
+ }
+
+
+ /**
+ * @return Nette\Application\IPresenter
+ */
+ public function __invoke($class)
+ {
+ $services = array_keys($this->container->findByTag('nette.presenter'), $class);
+ if (count($services) > 1) {
+ throw new Nette\Application\InvalidPresenterException("Multiple services of type $class found: " . implode(', ', $services) . '.');
+
+ } elseif (!$services) {
+ if ($this->touchToRefresh) {
+ touch($this->touchToRefresh);
+ }
+
+ $presenter = $this->container->createInstance($class);
+ $this->container->callInjects($presenter);
+ if ($presenter instanceof Nette\Application\UI\Presenter && $presenter->invalidLinkMode === NULL) {
+ $presenter->invalidLinkMode = $this->invalidLinkMode;
+ }
+ return $presenter;
+ }
+
+ return $this->container->createService($services[0]);
+ }
+
+}
diff --git a/vendor/nette/application/src/Bridges/ApplicationDI/RoutingExtension.php b/vendor/nette/application/src/Bridges/ApplicationDI/RoutingExtension.php
new file mode 100755
index 0000000..a45e697
--- /dev/null
+++ b/vendor/nette/application/src/Bridges/ApplicationDI/RoutingExtension.php
@@ -0,0 +1,78 @@
+ TRUE,
+ 'routes' => array(), // of [mask => action]
+ 'cache' => FALSE,
+ );
+
+ /** @var bool */
+ private $debugMode;
+
+
+ public function __construct($debugMode = FALSE)
+ {
+ $this->debugMode = $debugMode;
+ }
+
+
+ public function loadConfiguration()
+ {
+ $config = $this->validateConfig($this->defaults);
+ $container = $this->getContainerBuilder();
+
+ $router = $container->addDefinition($this->prefix('router'))
+ ->setClass('Nette\Application\IRouter')
+ ->setFactory('Nette\Application\Routers\RouteList');
+
+ foreach ($config['routes'] as $mask => $action) {
+ $router->addSetup('$service[] = new Nette\Application\Routers\Route(?, ?);', array($mask, $action));
+ }
+
+ if ($this->name === 'routing') {
+ $container->addAlias('router', $this->prefix('router'));
+ }
+ }
+
+
+ public function beforeCompile()
+ {
+ $container = $this->getContainerBuilder();
+
+ if ($this->debugMode && $this->config['debugger'] && $application = $container->getByType('Nette\Application\Application')) {
+ $container->getDefinition($application)->addSetup('@Tracy\Bar::addPanel', array(
+ new Nette\DI\Statement('Nette\Bridges\ApplicationTracy\RoutingPanel'),
+ ));
+ }
+ }
+
+
+ public function afterCompile(Nette\PhpGenerator\ClassType $class)
+ {
+ if (!empty($this->config['cache'])) {
+ $method = $class->getMethod(Nette\DI\Container::getMethodName($this->prefix('router')));
+ try {
+ $router = serialize(eval($method->getBody()));
+ } catch (\Exception $e) {
+ throw new Nette\DI\ServiceCreationException('Unable to cache router due to error: ' . $e->getMessage(), 0, $e);
+ }
+ $method->setBody('return unserialize(?);', array($router));
+ }
+ }
+
+}
diff --git a/vendor/nette/application/src/Bridges/ApplicationLatte/ILatteFactory.php b/vendor/nette/application/src/Bridges/ApplicationLatte/ILatteFactory.php
new file mode 100755
index 0000000..0c19418
--- /dev/null
+++ b/vendor/nette/application/src/Bridges/ApplicationLatte/ILatteFactory.php
@@ -0,0 +1,21 @@
+presenter = $presenter;
+ }
+
+}
diff --git a/vendor/nette/application/src/Bridges/ApplicationLatte/Template.php b/vendor/nette/application/src/Bridges/ApplicationLatte/Template.php
new file mode 100755
index 0000000..2b5eb21
--- /dev/null
+++ b/vendor/nette/application/src/Bridges/ApplicationLatte/Template.php
@@ -0,0 +1,249 @@
+latte = $latte;
+ }
+
+
+ /**
+ * @return Latte\Engine
+ */
+ public function getLatte()
+ {
+ return $this->latte;
+ }
+
+
+ /**
+ * Renders template to output.
+ * @return void
+ */
+ public function render($file = NULL, array $params = array())
+ {
+ $this->latte->render($file ?: $this->file, $params + $this->params);
+ }
+
+
+ /**
+ * Renders template to string.
+ * @param can throw exceptions? (hidden parameter)
+ * @return string
+ */
+ public function __toString()
+ {
+ try {
+ return $this->latte->renderToString($this->file, $this->params);
+ } catch (\Exception $e) {
+ if (func_num_args()) {
+ throw $e;
+ }
+ trigger_error("Exception in " . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
+ }
+ }
+
+
+ /********************* template filters & helpers ****************d*g**/
+
+
+ /**
+ * Registers run-time filter.
+ * @param string|NULL
+ * @param callable
+ * @return self
+ */
+ public function addFilter($name, $callback)
+ {
+ return $this->latte->addFilter($name, $callback);
+ }
+
+
+ /**
+ * Alias for addFilter()
+ * @deprecated
+ */
+ public function registerHelper($name, $callback)
+ {
+ //trigger_error(__METHOD__ . '() is deprecated, use getLatte()->addFilter().', E_USER_DEPRECATED);
+ return $this->latte->addFilter($name, $callback);
+ }
+
+
+ /**
+ * Alias for addFilterLoader()
+ * @deprecated
+ */
+ public function registerHelperLoader($loader)
+ {
+ trigger_error(__METHOD__ . '() is deprecated, use dynamic getLatte()->addFilter().', E_USER_DEPRECATED);
+ $latte = $this->latte;
+ $this->latte->addFilter(NULL, function ($name) use ($loader, $latte) {
+ if ($callback = call_user_func($loader, $name)) {
+ $latte->addFilter($name, $callback);
+ }
+ });
+ return $this;
+ }
+
+
+ /**
+ * Sets translate adapter.
+ * @return self
+ */
+ public function setTranslator(Nette\Localization\ITranslator $translator = NULL)
+ {
+ $this->latte->addFilter('translate', $translator === NULL ? NULL : array($translator, 'translate'));
+ return $this;
+ }
+
+
+ /**
+ * @deprecated
+ */
+ public function registerFilter($callback)
+ {
+ throw new Nette\DeprecatedException(__METHOD__ . '() is deprecated.');
+ }
+
+
+ /********************* template parameters ****************d*g**/
+
+
+ /**
+ * Sets the path to the template file.
+ * @param string
+ * @return self
+ */
+ public function setFile($file)
+ {
+ $this->file = $file;
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getFile()
+ {
+ return $this->file;
+ }
+
+
+ /**
+ * Adds new template parameter.
+ * @return self
+ */
+ public function add($name, $value)
+ {
+ if (array_key_exists($name, $this->params)) {
+ throw new Nette\InvalidStateException("The variable '$name' already exists.");
+ }
+ $this->params[$name] = $value;
+ return $this;
+ }
+
+
+ /**
+ * Sets all parameters.
+ * @param array
+ * @return self
+ */
+ public function setParameters(array $params)
+ {
+ $this->params = $params + $this->params;
+ return $this;
+ }
+
+
+ /**
+ * Returns array of all parameters.
+ * @return array
+ */
+ public function getParameters()
+ {
+ return $this->params;
+ }
+
+
+ /**
+ * @deprecated
+ */
+ public function __call($name, $args)
+ {
+ trigger_error('Invoking filters on Template object is deprecated, use getLatte()->invokeFilter().', E_USER_DEPRECATED);
+ return $this->latte->invokeFilter($name, $args);
+ }
+
+
+ /**
+ * Sets a template parameter. Do not call directly.
+ * @return void
+ */
+ public function __set($name, $value)
+ {
+ $this->params[$name] = $value;
+ }
+
+
+ /**
+ * Returns a template parameter. Do not call directly.
+ * @return mixed value
+ */
+ public function &__get($name)
+ {
+ if (!array_key_exists($name, $this->params)) {
+ trigger_error("The variable '$name' does not exist in template.", E_USER_NOTICE);
+ }
+
+ return $this->params[$name];
+ }
+
+
+ /**
+ * Determines whether parameter is defined. Do not call directly.
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ return isset($this->params[$name]);
+ }
+
+
+ /**
+ * Removes a template parameter. Do not call directly.
+ * @param string name
+ * @return void
+ */
+ public function __unset($name)
+ {
+ unset($this->params[$name]);
+ }
+
+}
diff --git a/vendor/nette/application/src/Bridges/ApplicationLatte/TemplateFactory.php b/vendor/nette/application/src/Bridges/ApplicationLatte/TemplateFactory.php
new file mode 100755
index 0000000..c7972a1
--- /dev/null
+++ b/vendor/nette/application/src/Bridges/ApplicationLatte/TemplateFactory.php
@@ -0,0 +1,109 @@
+latteFactory = $latteFactory;
+ $this->httpRequest = $httpRequest;
+ $this->httpResponse = $httpResponse;
+ $this->user = $user;
+ $this->cacheStorage = $cacheStorage;
+ }
+
+
+ /**
+ * @return Template
+ */
+ public function createTemplate(UI\Control $control = NULL)
+ {
+ $latte = $this->latteFactory->create();
+ $template = new Template($latte);
+ $presenter = $control ? $control->getPresenter(FALSE) : NULL;
+
+ if ($control instanceof UI\Presenter) {
+ $latte->setLoader(new Loader($control));
+ }
+
+ if ($latte->onCompile instanceof \Traversable) {
+ $latte->onCompile = iterator_to_array($latte->onCompile);
+ }
+
+ array_unshift($latte->onCompile, function ($latte) use ($control, $template) {
+ $latte->getParser()->shortNoEscape = TRUE;
+ $latte->getCompiler()->addMacro('cache', new Nette\Bridges\CacheLatte\CacheMacro($latte->getCompiler()));
+ UIMacros::install($latte->getCompiler());
+ if (class_exists('Nette\Bridges\FormsLatte\FormMacros')) {
+ Nette\Bridges\FormsLatte\FormMacros::install($latte->getCompiler());
+ }
+ if ($control) {
+ $control->templatePrepareFilters($template);
+ }
+ });
+
+ $latte->addFilter('url', 'rawurlencode'); // back compatiblity
+ foreach (array('normalize', 'toAscii', 'webalize', 'padLeft', 'padRight', 'reverse') as $name) {
+ $latte->addFilter($name, 'Nette\Utils\Strings::' . $name);
+ }
+ $latte->addFilter('null', function () {});
+ $latte->addFilter('length', function ($var) {
+ return is_string($var) ? Nette\Utils\Strings::length($var) : count($var);
+ });
+ $latte->addFilter('modifyDate', function ($time, $delta, $unit = NULL) {
+ return $time == NULL ? NULL : Nette\Utils\DateTime::from($time)->modify($delta . $unit); // intentionally ==
+ });
+
+ // default parameters
+ $template->control = $template->_control = $control;
+ $template->presenter = $template->_presenter = $presenter;
+ $template->user = $this->user;
+ $template->netteHttpResponse = $this->httpResponse;
+ $template->netteCacheStorage = $this->cacheStorage;
+ $template->baseUri = $template->baseUrl = $this->httpRequest ? rtrim($this->httpRequest->getUrl()->getBaseUrl(), '/') : NULL;
+ $template->basePath = preg_replace('#https?://[^/]+#A', '', $template->baseUrl);
+ $template->flashes = array();
+
+ if ($presenter instanceof UI\Presenter && $presenter->hasFlashSession()) {
+ $id = $control->getParameterId('flash');
+ $template->flashes = (array) $presenter->getFlashSession()->$id;
+ }
+
+ return $template;
+ }
+
+}
diff --git a/vendor/nette/application/src/Bridges/ApplicationLatte/UIMacros.php b/vendor/nette/application/src/Bridges/ApplicationLatte/UIMacros.php
new file mode 100755
index 0000000..8f4e94c
--- /dev/null
+++ b/vendor/nette/application/src/Bridges/ApplicationLatte/UIMacros.php
@@ -0,0 +1,114 @@
+addMacro('control', array($me, 'macroControl'));
+
+ $me->addMacro('href', NULL, NULL, function (MacroNode $node, PhpWriter $writer) use ($me) {
+ return ' ?> href="macroLink($node, $writer) . ' ?>"addMacro('plink', array($me, 'macroLink'));
+ $me->addMacro('link', array($me, 'macroLink'));
+ $me->addMacro('ifCurrent', array($me, 'macroIfCurrent'), '}'); // deprecated; use n:class="$presenter->linkCurrent ? ..."
+ }
+
+
+ /**
+ * Finishes template parsing.
+ * @return array(prolog, epilog)
+ */
+ public function finalize()
+ {
+ $prolog = '
+// snippets support
+if (empty($_l->extends) && !empty($_control->snippetMode)) {
+ return Nette\Bridges\ApplicationLatte\UIRuntime::renderSnippets($_control, $_b, get_defined_vars());
+}';
+ return array($prolog, '');
+ }
+
+
+ /********************* macros ****************d*g**/
+
+
+ /**
+ * {control name[:method] [params]}
+ */
+ public function macroControl(MacroNode $node, PhpWriter $writer)
+ {
+ $words = $node->tokenizer->fetchWords();
+ if (!$words) {
+ throw new CompileException('Missing control name in {control}');
+ }
+ $name = $writer->formatWord($words[0]);
+ $method = isset($words[1]) ? ucfirst($words[1]) : '';
+ $method = Strings::match($method, '#^\w*\z#') ? "render$method" : "{\"render$method\"}";
+ $param = $writer->formatArray();
+ if (!Strings::contains($node->args, '=>')) {
+ $param = substr($param, $param[0] === '[' ? 1 : 6, -1); // removes array() or []
+ }
+ return ($name[0] === '$' ? "if (is_object($name)) \$_l->tmp = $name; else " : '')
+ . '$_l->tmp = $_control->getComponent(' . $name . '); '
+ . 'if ($_l->tmp instanceof Nette\Application\UI\IRenderable) $_l->tmp->redrawControl(NULL, FALSE); '
+ . ($node->modifiers === '' ? "\$_l->tmp->$method($param)" : $writer->write("ob_start(); \$_l->tmp->$method($param); echo %modify(ob_get_clean())"));
+ }
+
+
+ /**
+ * {link destination [,] [params]}
+ * {plink destination [,] [params]}
+ * n:href="destination [,] [params]"
+ */
+ public function macroLink(MacroNode $node, PhpWriter $writer)
+ {
+ $node->modifiers = preg_replace('#\|safeurl\s*(?=\||\z)#i', '', $node->modifiers);
+ return $writer->using($node, $this->getCompiler())
+ ->write('echo %escape(%modify(' . ($node->name === 'plink' ? '$_presenter' : '$_control') . '->link(%node.word, %node.array?)))');
+ }
+
+
+ /**
+ * {ifCurrent destination [,] [params]}
+ */
+ public function macroIfCurrent(MacroNode $node, PhpWriter $writer)
+ {
+ return $writer->write($node->args
+ ? 'if ($_presenter->isLinkCurrent(%node.word, %node.array?)) {'
+ : 'if ($_presenter->getLastCreatedRequestFlag("current")) {'
+ );
+ }
+
+
+ /** @deprecated */
+ public static function renderSnippets(Nette\Application\UI\Control $control, \stdClass $local, array $params)
+ {
+ UIRuntime::renderSnippets($control, $local, $params);
+ }
+
+}
diff --git a/vendor/nette/application/src/Bridges/ApplicationLatte/UIRuntime.php b/vendor/nette/application/src/Bridges/ApplicationLatte/UIRuntime.php
new file mode 100755
index 0000000..5e63e2b
--- /dev/null
+++ b/vendor/nette/application/src/Bridges/ApplicationLatte/UIRuntime.php
@@ -0,0 +1,61 @@
+snippetMode = FALSE;
+ $payload = $control->getPresenter()->getPayload();
+ if (isset($local->blocks)) {
+ foreach ($local->blocks as $name => $function) {
+ if ($name[0] !== '_' || !$control->isControlInvalid((string) substr($name, 1))) {
+ continue;
+ }
+ ob_start();
+ $function = reset($function);
+ $snippets = $function($local, $params + array('_snippetMode' => TRUE));
+ $payload->snippets[$id = $control->getSnippetId((string) substr($name, 1))] = ob_get_clean();
+ if ($snippets !== NULL) { // pass FALSE from snippetArea
+ if ($snippets) {
+ $payload->snippets += $snippets;
+ }
+ unset($payload->snippets[$id]);
+ }
+ }
+ }
+ $control->snippetMode = TRUE;
+ if ($control instanceof UI\IRenderable) {
+ $queue = array($control);
+ do {
+ foreach (array_shift($queue)->getComponents() as $child) {
+ if ($child instanceof UI\IRenderable) {
+ if ($child->isControlInvalid()) {
+ $child->snippetMode = TRUE;
+ $child->render();
+ $child->snippetMode = FALSE;
+ }
+ } elseif ($child instanceof Nette\ComponentModel\IContainer) {
+ $queue[] = $child;
+ }
+ }
+ } while ($queue);
+ }
+ }
+
+}
diff --git a/vendor/nette/application/src/Bridges/ApplicationTracy/RoutingPanel.php b/vendor/nette/application/src/Bridges/ApplicationTracy/RoutingPanel.php
new file mode 100755
index 0000000..71e061a
--- /dev/null
+++ b/vendor/nette/application/src/Bridges/ApplicationTracy/RoutingPanel.php
@@ -0,0 +1,155 @@
+addPanel(function ($e) use ($application) {
+ return $e ? NULL : array(
+ 'tab' => 'Nette Application',
+ 'panel' => 'Requests ' . Dumper::toHtml($application->getRequests(), array(Dumper::LIVE => TRUE))
+ . 'Presenter ' . Dumper::toHtml($application->getPresenter(), array(Dumper::LIVE => TRUE)),
+ );
+ });
+ }
+
+
+ public function __construct(Nette\Application\IRouter $router, Nette\Http\IRequest $httpRequest, Nette\Application\IPresenterFactory $presenterFactory)
+ {
+ $this->router = $router;
+ $this->httpRequest = $httpRequest;
+ $this->presenterFactory = $presenterFactory;
+ }
+
+
+ /**
+ * Renders tab.
+ * @return string
+ */
+ public function getTab()
+ {
+ $this->analyse($this->router);
+ ob_start();
+ $request = $this->request;
+ require __DIR__ . '/templates/RoutingPanel.tab.phtml';
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Renders panel.
+ * @return string
+ */
+ public function getPanel()
+ {
+ ob_start();
+ $request = $this->request;
+ $routers = $this->routers;
+ $source = $this->source;
+ $url = $this->httpRequest->getUrl();
+ require __DIR__ . '/templates/RoutingPanel.panel.phtml';
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Analyses simple route.
+ * @param Nette\Application\IRouter
+ * @return void
+ */
+ private function analyse($router, $module = '')
+ {
+ if ($router instanceof Routers\RouteList) {
+ foreach ($router as $subRouter) {
+ $this->analyse($subRouter, $module . $router->getModule());
+ }
+ return;
+ }
+
+ $matched = 'no';
+ $request = $router->match($this->httpRequest);
+ if ($request) {
+ $request->setPresenterName($module . $request->getPresenterName());
+ $matched = 'may';
+ if (empty($this->request)) {
+ $this->request = $request;
+ $this->findSource();
+ $matched = 'yes';
+ }
+ }
+
+ $this->routers[] = array(
+ 'matched' => $matched,
+ 'class' => get_class($router),
+ 'defaults' => $router instanceof Routers\Route || $router instanceof Routers\SimpleRouter ? $router->getDefaults() : array(),
+ 'mask' => $router instanceof Routers\Route ? $router->getMask() : NULL,
+ 'request' => $request,
+ 'module' => rtrim($module, ':'),
+ );
+ }
+
+
+ private function findSource()
+ {
+ $request = $this->request;
+ $presenter = $request->getPresenterName();
+ try {
+ $class = $this->presenterFactory->getPresenterClass($presenter);
+ } catch (Nette\Application\InvalidPresenterException $e) {
+ return;
+ }
+ $rc = new \ReflectionClass($class);
+
+ if ($rc->isSubclassOf('Nette\Application\UI\Presenter')) {
+ if (isset($request->parameters[Presenter::SIGNAL_KEY])) {
+ $method = $class::formatSignalMethod($request->parameters[Presenter::SIGNAL_KEY]);
+
+ } elseif (isset($request->parameters[Presenter::ACTION_KEY])) {
+ $action = $request->parameters[Presenter::ACTION_KEY];
+ $method = $class::formatActionMethod($action);
+ if (!$rc->hasMethod($method)) {
+ $method = $class::formatRenderMethod($action);
+ }
+ }
+ }
+
+ $this->source = isset($method) && $rc->hasMethod($method) ? $rc->getMethod($method) : $rc;
+ }
+
+}
diff --git a/vendor/nette/application/src/Bridges/ApplicationTracy/templates/RoutingPanel.panel.phtml b/vendor/nette/application/src/Bridges/ApplicationTracy/templates/RoutingPanel.panel.phtml
new file mode 100755
index 0000000..c47be8f
--- /dev/null
+++ b/vendor/nette/application/src/Bridges/ApplicationTracy/templates/RoutingPanel.panel.phtml
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+ no route
+
+ getPresenterName() . ':' . (isset($request->parameters[Presenter::ACTION_KEY]) ? $request->parameters[Presenter::ACTION_KEY] : Presenter::DEFAULT_ACTION) . (isset($request->parameters[Presenter::SIGNAL_KEY]) ? " {$request->parameters[Presenter::SIGNAL_KEY]}!" : ''), ENT_NOQUOTES, 'UTF-8') ?>
+
+
+
+
+
+
+
+
No routers defined.
+
+
+
+
+
+ Matched?
+ Class
+ Mask
+ Defaults
+ Module
+ Request
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $value): ?>
+ ' : Dumper::toHtml($value, array(Dumper::COLLAPSE => TRUE, Dumper::LIVE => TRUE)) ?>
+
+
+
+
+
+
+ getParameters(); ?>
+ getPresenterName() . ':' . (isset($params[Presenter::ACTION_KEY]) ? $params[Presenter::ACTION_KEY] : Presenter::DEFAULT_ACTION), ENT_NOQUOTES, 'UTF-8') ?>
+
+ $value): ?>
+ ' : Dumper::toHtml($value, array(Dumper::COLLAPSE => TRUE, Dumper::LIVE => TRUE)) ?>
+
+
+
+
+
+
+
+
+
+
getName() : $source->getDeclaringClass()->getName() . '::' . $source->getName() . '()' ?> in
+ getFileName(), $source->getStartLine()) ?>
+
+
+
+
diff --git a/vendor/nette/application/src/Bridges/ApplicationTracy/templates/RoutingPanel.tab.phtml b/vendor/nette/application/src/Bridges/ApplicationTracy/templates/RoutingPanel.tab.phtml
new file mode 100755
index 0000000..def8da7
--- /dev/null
+++ b/vendor/nette/application/src/Bridges/ApplicationTracy/templates/RoutingPanel.tab.phtml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ no routegetPresenterName() . ':' . (isset($request->parameters[Presenter::ACTION_KEY]) ? $request->parameters[Presenter::ACTION_KEY] : Presenter::DEFAULT_ACTION) . (isset($request->parameters[Presenter::SIGNAL_KEY]) ? " {$request->parameters[Presenter::SIGNAL_KEY]}!" : ''), ENT_NOQUOTES, 'UTF-8'); endif ?>
+
diff --git a/vendor/nette/bootstrap/composer.json b/vendor/nette/bootstrap/composer.json
new file mode 100755
index 0000000..e32f459
--- /dev/null
+++ b/vendor/nette/bootstrap/composer.json
@@ -0,0 +1,46 @@
+{
+ "name": "nette/bootstrap",
+ "description": "Nette Bootstrap",
+ "homepage": "http://nette.org",
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.1",
+ "nette/di": "~2.3",
+ "nette/utils": "~2.2"
+ },
+ "suggest": {
+ "nette/robot-loader": "to use Configurator::createRobotLoader()",
+ "tracy/tracy": "to use Configurator::enableDebugger()"
+ },
+ "require-dev": {
+ "nette/application": "~2.3",
+ "nette/caching": "~2.3",
+ "nette/database": "~2.3",
+ "nette/forms": "~2.3",
+ "nette/http": "~2.3",
+ "nette/mail": "~2.3",
+ "nette/robot-loader": "~2.2",
+ "nette/safe-stream": "~2.2",
+ "nette/security": "~2.3",
+ "nette/tester": "~1.3",
+ "latte/latte": "~2.2",
+ "tracy/tracy": "~2.3"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/bootstrap/license.md b/vendor/nette/bootstrap/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/bootstrap/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/bootstrap/src/Bootstrap/Configurator.php b/vendor/nette/bootstrap/src/Bootstrap/Configurator.php
new file mode 100755
index 0000000..459acec
--- /dev/null
+++ b/vendor/nette/bootstrap/src/Bootstrap/Configurator.php
@@ -0,0 +1,360 @@
+ 'Nette\DI\Extensions\PhpExtension',
+ 'constants' => 'Nette\DI\Extensions\ConstantsExtension',
+ 'extensions' => 'Nette\DI\Extensions\ExtensionsExtension',
+ 'application' => array('Nette\Bridges\ApplicationDI\ApplicationExtension', array('%debugMode%', array('%appDir%'), '%tempDir%/cache')),
+ 'decorator' => 'Nette\DI\Extensions\DecoratorExtension',
+ 'cache' => array('Nette\Bridges\CacheDI\CacheExtension', array('%tempDir%')),
+ 'database' => array('Nette\Bridges\DatabaseDI\DatabaseExtension', array('%debugMode%')),
+ 'di' => array('Nette\DI\Extensions\DIExtension', array('%debugMode%')),
+ 'forms' => 'Nette\Bridges\FormsDI\FormsExtension',
+ 'http' => 'Nette\Bridges\HttpDI\HttpExtension',
+ 'latte' => array('Nette\Bridges\ApplicationDI\LatteExtension', array('%tempDir%/cache/latte', '%debugMode%')),
+ 'mail' => 'Nette\Bridges\MailDI\MailExtension',
+ 'reflection' => array('Nette\Bridges\ReflectionDI\ReflectionExtension', array('%debugMode%')),
+ 'routing' => array('Nette\Bridges\ApplicationDI\RoutingExtension', array('%debugMode%')),
+ 'security' => array('Nette\Bridges\SecurityDI\SecurityExtension', array('%debugMode%')),
+ 'session' => array('Nette\Bridges\HttpDI\SessionExtension', array('%debugMode%')),
+ 'tracy' => array('Tracy\Bridges\Nette\TracyExtension', array('%debugMode%')),
+ 'inject' => 'Nette\DI\Extensions\InjectExtension',
+ );
+
+ /** @var string[] of classes which shouldn't be autowired */
+ public $autowireExcludedClasses = array(
+ 'stdClass',
+ );
+
+ /** @var array */
+ protected $parameters;
+
+ /** @var array */
+ protected $services = array();
+
+ /** @var array [file|array, section] */
+ protected $files = array();
+
+
+ public function __construct()
+ {
+ $this->parameters = $this->getDefaultParameters();
+ }
+
+
+ /**
+ * Set parameter %debugMode%.
+ * @param bool|string|array
+ * @return self
+ */
+ public function setDebugMode($value)
+ {
+ if (is_string($value) || is_array($value)) {
+ $value = static::detectDebugMode($value);
+ } elseif (!is_bool($value)) {
+ throw new Nette\InvalidArgumentException(sprintf('Value must be either a string, array, or boolean, %s given.', gettype($value)));
+ }
+ $this->parameters['debugMode'] = $value;
+ $this->parameters['productionMode'] = !$this->parameters['debugMode']; // compatibility
+ $this->parameters['environment'] = $this->parameters['debugMode'] ? 'development' : 'production';
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isDebugMode()
+ {
+ return $this->parameters['debugMode'];
+ }
+
+
+ /**
+ * Sets path to temporary directory.
+ * @return self
+ */
+ public function setTempDirectory($path)
+ {
+ $this->parameters['tempDir'] = $path;
+ return $this;
+ }
+
+
+ /**
+ * Adds new parameters. The %params% will be expanded.
+ * @return self
+ */
+ public function addParameters(array $params)
+ {
+ $this->parameters = DI\Config\Helpers::merge($params, $this->parameters);
+ return $this;
+ }
+
+
+ /**
+ * Add instances of services.
+ * @return self
+ */
+ public function addServices(array $services)
+ {
+ $this->services = $services + $this->services;
+ return $this;
+ }
+
+
+ /**
+ * @return array
+ */
+ protected function getDefaultParameters()
+ {
+ $trace = debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE);
+ $last = end($trace);
+ $debugMode = static::detectDebugMode();
+ return array(
+ 'appDir' => isset($trace[1]['file']) ? dirname($trace[1]['file']) : NULL,
+ 'wwwDir' => isset($last['file']) ? dirname($last['file']) : NULL,
+ 'debugMode' => $debugMode,
+ 'productionMode' => !$debugMode,
+ 'environment' => $debugMode ? 'development' : 'production',
+ 'consoleMode' => PHP_SAPI === 'cli',
+ 'container' => array(
+ 'class' => NULL,
+ 'parent' => NULL,
+ ),
+ );
+ }
+
+
+ /**
+ * @param string error log directory
+ * @param string administrator email
+ * @return void
+ */
+ public function enableDebugger($logDirectory = NULL, $email = NULL)
+ {
+ Tracy\Debugger::$strictMode = TRUE;
+ Tracy\Debugger::enable(!$this->parameters['debugMode'], $logDirectory, $email);
+ Nette\Bridges\Framework\TracyBridge::initialize();
+ }
+
+
+ /**
+ * @return Nette\Loaders\RobotLoader
+ * @throws Nette\NotSupportedException if RobotLoader is not available
+ */
+ public function createRobotLoader()
+ {
+ if (!class_exists('Nette\Loaders\RobotLoader')) {
+ throw new Nette\NotSupportedException('RobotLoader not found, do you have `nette/robot-loader` package installed?');
+ }
+
+ $loader = new Nette\Loaders\RobotLoader;
+ $loader->setCacheStorage(new Nette\Caching\Storages\FileStorage($this->getCacheDirectory()));
+ $loader->autoRebuild = $this->parameters['debugMode'];
+ return $loader;
+ }
+
+
+ /**
+ * Adds configuration file.
+ * @return self
+ */
+ public function addConfig($file, $section = NULL)
+ {
+ if ($section === NULL && is_string($file) && $this->parameters['debugMode']) { // back compatibility
+ try {
+ $loader = new DI\Config\Loader;
+ $loader->load($file, $this->parameters['environment']);
+ trigger_error("Config file '$file' has sections, call addConfig() with second parameter Configurator::AUTO.", E_USER_WARNING);
+ $section = $this->parameters['environment'];
+ } catch (\Exception $e) {
+ }
+ }
+ $this->files[] = array($file, $section === self::AUTO ? $this->parameters['environment'] : $section);
+ return $this;
+ }
+
+
+ /**
+ * Returns system DI container.
+ * @return DI\Container
+ */
+ public function createContainer()
+ {
+ $loader = new DI\ContainerLoader(
+ $this->getCacheDirectory() . '/Nette.Configurator',
+ $this->parameters['debugMode']
+ );
+ $class = $loader->load(
+ array($this->parameters, $this->files),
+ array($this, 'generateContainer')
+ );
+
+ $container = new $class;
+ foreach ($this->services as $name => $service) {
+ $container->addService($name, $service);
+ }
+ $container->initialize();
+ if (class_exists('Nette\Environment')) {
+ Nette\Environment::setContext($container); // back compatibility
+ }
+ return $container;
+ }
+
+
+ /**
+ * @return string
+ * @internal
+ */
+ public function generateContainer(DI\Compiler $compiler)
+ {
+ $loader = $this->createLoader();
+ $compiler->addConfig(array('parameters' => $this->parameters));
+ $fileInfo = array();
+ foreach ($this->files as $info) {
+ if (is_scalar($info[0])) {
+ $fileInfo[] = "// source: $info[0] $info[1]";
+ $info[0] = $loader->load($info[0], $info[1]);
+ }
+ $compiler->addConfig($this->fixCompatibility($info[0]));
+ }
+ $compiler->addDependencies($loader->getDependencies());
+
+ $builder = $compiler->getContainerBuilder();
+ $builder->addExcludedClasses($this->autowireExcludedClasses);
+
+ foreach ($this->defaultExtensions as $name => $extension) {
+ list($class, $args) = is_string($extension) ? array($extension, array()) : $extension;
+ if (class_exists($class)) {
+ $rc = new \ReflectionClass($class);
+ $args = DI\Helpers::expand($args, $this->parameters, TRUE);
+ $compiler->addExtension($name, $args ? $rc->newInstanceArgs($args) : $rc->newInstance());
+ }
+ }
+
+ $this->onCompile($this, $compiler);
+
+ $classes = $compiler->compile();
+
+ if (!empty($builder->parameters['container']['parent'])) {
+ $classes[0]->setExtends($builder->parameters['container']['parent']);
+ }
+
+ return implode("\n", $fileInfo) . "\n\n" . implode("\n\n\n", $classes)
+ . (($tmp = $builder->parameters['container']['class']) ? "\nclass $tmp extends {$builder->getClassName()} {}\n" : '');
+ }
+
+
+ /**
+ * @return DI\Config\Loader
+ */
+ protected function createLoader()
+ {
+ return new DI\Config\Loader;
+ }
+
+
+ protected function getCacheDirectory()
+ {
+ if (empty($this->parameters['tempDir'])) {
+ throw new Nette\InvalidStateException('Set path to temporary directory using setTempDirectory().');
+ }
+ $dir = $this->parameters['tempDir'] . '/cache';
+ if (!is_dir($dir)) {
+ @mkdir($dir); // @ - directory may already exist
+ }
+ return $dir;
+ }
+
+
+ /**
+ * Back compatibility with < v2.3
+ * @return array
+ */
+ protected function fixCompatibility($config)
+ {
+ if (isset($config['nette']['security']['frames'])) {
+ $config['nette']['http']['frames'] = $config['nette']['security']['frames'];
+ unset($config['nette']['security']['frames']);
+ }
+ foreach (array('application', 'cache', 'database', 'di' => 'container', 'forms', 'http',
+ 'latte', 'mail' => 'mailer', 'routing', 'security', 'session', 'tracy' => 'debugger') as $new => $old) {
+ if (isset($config['nette'][$old])) {
+ $new = is_int($new) ? $old : $new;
+ if (isset($config[$new])) {
+ throw new Nette\DeprecatedException("You can use (deprecated) section 'nette.$old' or new section '$new', but not both of them.");
+ }
+ $config[$new] = $config['nette'][$old];
+ unset($config['nette'][$old]);
+ }
+ }
+ if (isset($config['nette']['xhtml'])) {
+ trigger_error("Configuration option 'nette.xhtml' is deprecated, use section 'latte.xhtml' instead.", E_USER_DEPRECATED);
+ $config['latte']['xhtml'] = $config['nette']['xhtml'];
+ unset($config['nette']['xhtml']);
+ }
+
+ if (empty($config['nette'])) {
+ unset($config['nette']);
+ }
+ return $config;
+ }
+
+
+ /********************* tools ****************d*g**/
+
+
+ /**
+ * Detects debug mode by IP address.
+ * @param string|array IP addresses or computer names whitelist detection
+ * @return bool
+ */
+ public static function detectDebugMode($list = NULL)
+ {
+ $addr = isset($_SERVER['REMOTE_ADDR'])
+ ? $_SERVER['REMOTE_ADDR']
+ : php_uname('n');
+ $secret = isset($_COOKIE[self::COOKIE_SECRET]) && is_string($_COOKIE[self::COOKIE_SECRET])
+ ? $_COOKIE[self::COOKIE_SECRET]
+ : NULL;
+ $list = is_string($list)
+ ? preg_split('#[,\s]+#', $list)
+ : (array) $list;
+ if (!isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
+ $list[] = '127.0.0.1';
+ $list[] = '::1';
+ }
+ return in_array($addr, $list, TRUE) || in_array("$secret@$addr", $list, TRUE);
+ }
+
+}
diff --git a/vendor/nette/bootstrap/src/Bridges/Framework/TracyBridge.php b/vendor/nette/bootstrap/src/Bridges/Framework/TracyBridge.php
new file mode 100755
index 0000000..28a36fe
--- /dev/null
+++ b/vendor/nette/bootstrap/src/Bridges/Framework/TracyBridge.php
@@ -0,0 +1,63 @@
+getPanel('Tracy:info')->data['Nette Framework'] = $version;
+ $blueScreen->info[] = "Nette Framework $version";
+ }
+
+ $blueScreen->addPanel(function ($e) {
+ if ($e instanceof Latte\CompileException) {
+ return array(
+ 'tab' => 'Template',
+ 'panel' => (@is_file($e->sourceName) // @ - may trigger error
+ ? 'File: ' . Helpers::editorLink($e->sourceName, $e->sourceLine) . '
'
+ : '')
+ . ''
+ . BlueScreen::highlightLine(htmlspecialchars($e->sourceCode, ENT_IGNORE, 'UTF-8'), $e->sourceLine)
+ . ' ',
+ );
+ }
+ });
+
+ $blueScreen->addPanel(function ($e) {
+ if ($e instanceof Nette\Neon\Exception && preg_match('#line (\d+)#', $e->getMessage(), $m)
+ && ($trace = Helpers::findTrace($e->getTrace(), 'Nette\Neon\Decoder::decode'))
+ ) {
+ return array(
+ 'tab' => 'NEON',
+ 'panel' => ($trace2 = Helpers::findTrace($e->getTrace(), 'Nette\DI\Config\Adapters\NeonAdapter::load'))
+ ? 'File: ' . Helpers::editorLink($trace2['args'][0], $m[1]) . '
'
+ . BlueScreen::highlightFile($trace2['args'][0], $m[1])
+ : BlueScreen::highlightPhp($trace['args'][0], $m[1]),
+ );
+ }
+ });
+ }
+
+}
diff --git a/vendor/nette/caching/composer.json b/vendor/nette/caching/composer.json
new file mode 100755
index 0000000..16a1503
--- /dev/null
+++ b/vendor/nette/caching/composer.json
@@ -0,0 +1,38 @@
+{
+ "name": "nette/caching",
+ "description": "Nette Caching Component",
+ "homepage": "http://nette.org",
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.1",
+ "nette/finder": "~2.2",
+ "nette/utils": "~2.2"
+ },
+ "require-dev": {
+ "nette/tester": "~1.4",
+ "nette/di": "~2.3",
+ "latte/latte": "~2.3.0"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ }
+}
diff --git a/vendor/nette/caching/license.md b/vendor/nette/caching/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/caching/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/caching/src/Bridges/CacheDI/CacheExtension.php b/vendor/nette/caching/src/Bridges/CacheDI/CacheExtension.php
new file mode 100755
index 0000000..40c8595
--- /dev/null
+++ b/vendor/nette/caching/src/Bridges/CacheDI/CacheExtension.php
@@ -0,0 +1,74 @@
+tempDir = $tempDir;
+ }
+
+
+ public function loadConfiguration()
+ {
+ $container = $this->getContainerBuilder();
+
+ $container->addDefinition($this->prefix('journal'))
+ ->setClass('Nette\Caching\Storages\IJournal')
+ ->setFactory('Nette\Caching\Storages\FileJournal', array($this->tempDir));
+
+ $container->addDefinition($this->prefix('storage'))
+ ->setClass('Nette\Caching\IStorage')
+ ->setFactory('Nette\Caching\Storages\FileStorage', array($this->tempDir . '/cache'));
+
+ if ($this->name === 'cache') {
+ $container->addAlias('nette.cacheJournal', $this->prefix('journal'));
+ $container->addAlias('cacheStorage', $this->prefix('storage'));
+ }
+ }
+
+
+ public function afterCompile(Nette\PhpGenerator\ClassType $class)
+ {
+ if (!$this->checkTempDir($this->tempDir . '/cache')) {
+ $class->getMethod('initialize')->addBody('Nette\Caching\Storages\FileStorage::$useDirectories = FALSE;');
+ }
+ }
+
+
+ private function checkTempDir($dir)
+ {
+ @mkdir($dir); // @ - directory may exists
+
+ // checks whether directory is writable
+ $uniq = uniqid('_', TRUE);
+ if (!@mkdir("$dir/$uniq")) { // @ - is escalated to exception
+ throw new Nette\InvalidStateException("Unable to write to directory '$dir'. Make this directory writable.");
+ }
+
+ // checks whether subdirectory is writable
+ $isWritable = @file_put_contents("$dir/$uniq/_", '') !== FALSE; // @ - error is expected
+ if ($isWritable) {
+ unlink("$dir/$uniq/_");
+ }
+ rmdir("$dir/$uniq");
+ return $isWritable;
+ }
+
+}
diff --git a/vendor/nette/caching/src/Bridges/CacheLatte/CacheMacro.php b/vendor/nette/caching/src/Bridges/CacheLatte/CacheMacro.php
new file mode 100755
index 0000000..912755b
--- /dev/null
+++ b/vendor/nette/caching/src/Bridges/CacheLatte/CacheMacro.php
@@ -0,0 +1,121 @@
+used = FALSE;
+ }
+
+
+ /**
+ * Finishes template parsing.
+ * @return array(prolog, epilog)
+ */
+ public function finalize()
+ {
+ if ($this->used) {
+ return array('Nette\Bridges\CacheLatte\CacheMacro::initRuntime($template, $_g);');
+ }
+ }
+
+
+ /**
+ * New node is found.
+ * @return bool
+ */
+ public function nodeOpened(Latte\MacroNode $node)
+ {
+ $this->used = TRUE;
+ $node->isEmpty = FALSE;
+ $node->openingCode = Latte\PhpWriter::using($node)
+ ->write('caches, %node.array?)) { ?>',
+ Nette\Utils\Random::generate()
+ );
+ }
+
+
+ /**
+ * Node is closed.
+ * @return void
+ */
+ public function nodeClosed(Latte\MacroNode $node)
+ {
+ $node->closingCode = 'tmp = array_pop($_g->caches); if (!$_l->tmp instanceof stdClass) $_l->tmp->end(); } ?>';
+ }
+
+
+ /********************* run-time helpers ****************d*g**/
+
+
+ /**
+ * @return void
+ */
+ public static function initRuntime(Latte\Template $template, \stdClass $global)
+ {
+ if (!empty($global->caches) && $template->getEngine()->getLoader() instanceof Latte\Loaders\FileLoader) {
+ end($global->caches)->dependencies[Nette\Caching\Cache::FILES][] = $template->getName();
+ }
+ }
+
+
+ /**
+ * Starts the output cache. Returns Nette\Caching\OutputHelper object if buffering was started.
+ * @param Nette\Caching\IStorage
+ * @param string
+ * @param Nette\Caching\OutputHelper[]
+ * @param array
+ * @return Nette\Caching\OutputHelper
+ */
+ public static function createCache(Nette\Caching\IStorage $cacheStorage, $key, & $parents, array $args = NULL)
+ {
+ if ($args) {
+ if (array_key_exists('if', $args) && !$args['if']) {
+ return $parents[] = new \stdClass;
+ }
+ $key = array_merge(array($key), array_intersect_key($args, range(0, count($args))));
+ }
+ if ($parents) {
+ end($parents)->dependencies[Nette\Caching\Cache::ITEMS][] = $key;
+ }
+
+ $cache = new Nette\Caching\Cache($cacheStorage, 'Nette.Templating.Cache');
+ if ($helper = $cache->start($key)) {
+ if (isset($args['dependencies'])) {
+ $args += call_user_func($args['dependencies']);
+ }
+ if (isset($args['expire'])) {
+ $args['expiration'] = $args['expire']; // back compatibility
+ }
+ $helper->dependencies = array(
+ Nette\Caching\Cache::TAGS => isset($args['tags']) ? $args['tags'] : NULL,
+ Nette\Caching\Cache::EXPIRATION => isset($args['expiration']) ? $args['expiration'] : '+ 7 days',
+ );
+ $parents[] = $helper;
+ }
+ return $helper;
+ }
+
+}
diff --git a/vendor/nette/caching/src/Caching/Cache.php b/vendor/nette/caching/src/Caching/Cache.php
new file mode 100755
index 0000000..0bb1fde
--- /dev/null
+++ b/vendor/nette/caching/src/Caching/Cache.php
@@ -0,0 +1,372 @@
+storage = $storage;
+ $this->namespace = $namespace . self::NAMESPACE_SEPARATOR;
+ }
+
+
+ /**
+ * Returns cache storage.
+ * @return IStorage
+ */
+ public function getStorage()
+ {
+ return $this->storage;
+ }
+
+
+ /**
+ * Returns cache namespace.
+ * @return string
+ */
+ public function getNamespace()
+ {
+ return (string) substr($this->namespace, 0, -1);
+ }
+
+
+ /**
+ * Returns new nested cache object.
+ * @param string
+ * @return self
+ */
+ public function derive($namespace)
+ {
+ $derived = new static($this->storage, $this->namespace . $namespace);
+ return $derived;
+ }
+
+
+ /**
+ * Reads the specified item from the cache or generate it.
+ * @param mixed key
+ * @param callable
+ * @return mixed|NULL
+ */
+ public function load($key, $fallback = NULL)
+ {
+ $data = $this->storage->read($this->generateKey($key));
+ if ($data === NULL && $fallback) {
+ return $this->save($key, function (& $dependencies) use ($fallback) {
+ return call_user_func_array($fallback, array(& $dependencies));
+ });
+ }
+ return $data;
+ }
+
+
+ /**
+ * Writes item into the cache.
+ * Dependencies are:
+ * - Cache::PRIORITY => (int) priority
+ * - Cache::EXPIRATION => (timestamp) expiration
+ * - Cache::SLIDING => (bool) use sliding expiration?
+ * - Cache::TAGS => (array) tags
+ * - Cache::FILES => (array|string) file names
+ * - Cache::ITEMS => (array|string) cache items
+ * - Cache::CONSTS => (array|string) cache items
+ *
+ * @param mixed key
+ * @param mixed value
+ * @param array dependencies
+ * @return mixed value itself
+ * @throws Nette\InvalidArgumentException
+ */
+ public function save($key, $data, array $dependencies = NULL)
+ {
+ $this->key = $this->data = NULL;
+ $key = $this->generateKey($key);
+
+ if ($data instanceof Nette\Callback || $data instanceof \Closure) {
+ $this->storage->lock($key);
+ $data = call_user_func_array($data, array(& $dependencies));
+ }
+
+ if ($data === NULL) {
+ $this->storage->remove($key);
+ } else {
+ $this->storage->write($key, $data, $this->completeDependencies($dependencies, $data));
+ return $data;
+ }
+ }
+
+
+ private function completeDependencies($dp, $data)
+ {
+ // convert expire into relative amount of seconds
+ if (isset($dp[self::EXPIRATION])) {
+ $dp[self::EXPIRATION] = Nette\Utils\DateTime::from($dp[self::EXPIRATION])->format('U') - time();
+ }
+
+ // convert FILES into CALLBACKS
+ if (isset($dp[self::FILES])) {
+ foreach (array_unique((array) $dp[self::FILES]) as $item) {
+ $dp[self::CALLBACKS][] = array(array(__CLASS__, 'checkFile'), $item, @filemtime($item)); // @ - stat may fail
+ }
+ unset($dp[self::FILES]);
+ }
+
+ // add namespaces to items
+ if (isset($dp[self::ITEMS])) {
+ $dp[self::ITEMS] = array_unique(array_map(array($this, 'generateKey'), (array) $dp[self::ITEMS]));
+ }
+
+ // convert CONSTS into CALLBACKS
+ if (isset($dp[self::CONSTS])) {
+ foreach (array_unique((array) $dp[self::CONSTS]) as $item) {
+ $dp[self::CALLBACKS][] = array(array(__CLASS__, 'checkConst'), $item, constant($item));
+ }
+ unset($dp[self::CONSTS]);
+ }
+
+ if (!is_array($dp)) {
+ $dp = array();
+ }
+ return $dp;
+ }
+
+
+ /**
+ * Removes item from the cache.
+ * @param mixed key
+ * @return void
+ */
+ public function remove($key)
+ {
+ $this->save($key, NULL);
+ }
+
+
+ /**
+ * Removes items from the cache by conditions.
+ * Conditions are:
+ * - Cache::PRIORITY => (int) priority
+ * - Cache::TAGS => (array) tags
+ * - Cache::ALL => TRUE
+ * @return void
+ */
+ public function clean(array $conditions = NULL)
+ {
+ $this->key = $this->data = NULL;
+ $this->storage->clean((array) $conditions);
+ }
+
+
+ /**
+ * Caches results of function/method calls.
+ * @param mixed
+ * @return mixed
+ */
+ public function call($function)
+ {
+ $key = func_get_args();
+ if (is_array($function) && is_object($function[0])) {
+ $key[0][0] = get_class($function[0]);
+ }
+ return $this->load($key, function () use ($function, $key) {
+ return Callback::invokeArgs($function, array_slice($key, 1));
+ });
+ }
+
+
+ /**
+ * Caches results of function/method calls.
+ * @param mixed
+ * @param array dependencies
+ * @return \Closure
+ */
+ public function wrap($function, array $dependencies = NULL)
+ {
+ $cache = $this;
+ return function () use ($cache, $function, $dependencies) {
+ $key = array($function, func_get_args());
+ if (is_array($function) && is_object($function[0])) {
+ $key[0][0] = get_class($function[0]);
+ }
+ $data = $cache->load($key);
+ if ($data === NULL) {
+ $data = $cache->save($key, Callback::invokeArgs($function, $key[1]), $dependencies);
+ }
+ return $data;
+ };
+ }
+
+
+ /**
+ * Starts the output cache.
+ * @param mixed key
+ * @return OutputHelper|NULL
+ */
+ public function start($key)
+ {
+ $data = $this->load($key);
+ if ($data === NULL) {
+ return new OutputHelper($this, $key);
+ }
+ echo $data;
+ }
+
+
+ /**
+ * Generates internal cache key.
+ *
+ * @param string
+ * @return string
+ */
+ protected function generateKey($key)
+ {
+ return $this->namespace . md5(is_scalar($key) ? $key : serialize($key));
+ }
+
+
+ /********************* interface ArrayAccess ****************d*g**/
+
+
+ /**
+ * @deprecated
+ */
+ public function offsetSet($key, $data)
+ {
+ trigger_error('Using [] is deprecated; use Cache::save(key, data) instead.', E_USER_DEPRECATED);
+ $this->save($key, $data);
+ }
+
+
+ /**
+ * @deprecated
+ */
+ public function offsetGet($key)
+ {
+ trigger_error('Using [] is deprecated; use Cache::load(key) instead.', E_USER_DEPRECATED);
+ $key = is_scalar($key) ? (string) $key : serialize($key);
+ if ($this->key !== $key) {
+ $this->key = $key;
+ $this->data = $this->load($key);
+ }
+ return $this->data;
+ }
+
+
+ /**
+ * @deprecated
+ */
+ public function offsetExists($key)
+ {
+ trigger_error('Using [] is deprecated; use Cache::load(key) !== NULL instead.', E_USER_DEPRECATED);
+ $this->key = $this->data = NULL;
+ return $this->offsetGet($key) !== NULL;
+ }
+
+
+ /**
+ * @deprecated
+ */
+ public function offsetUnset($key)
+ {
+ trigger_error('Using [] is deprecated; use Cache::remove(key) instead.', E_USER_DEPRECATED);
+ $this->save($key, NULL);
+ }
+
+
+ /**
+ * @deprecated
+ */
+ public function release()
+ {
+ trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
+ $this->key = $this->data = NULL;
+ }
+
+
+ /********************* dependency checkers ****************d*g**/
+
+
+ /**
+ * Checks CALLBACKS dependencies.
+ * @param array
+ * @return bool
+ */
+ public static function checkCallbacks($callbacks)
+ {
+ foreach ($callbacks as $callback) {
+ if (!call_user_func_array(array_shift($callback), $callback)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+
+ /**
+ * Checks CONSTS dependency.
+ * @param string
+ * @param mixed
+ * @return bool
+ */
+ private static function checkConst($const, $value)
+ {
+ return defined($const) && constant($const) === $value;
+ }
+
+
+ /**
+ * Checks FILES dependency.
+ * @param string
+ * @param int
+ * @return bool
+ */
+ private static function checkFile($file, $time)
+ {
+ return @filemtime($file) == $time; // @ - stat may fail
+ }
+
+}
diff --git a/vendor/nette/caching/src/Caching/IStorage.php b/vendor/nette/caching/src/Caching/IStorage.php
new file mode 100755
index 0000000..1e4990f
--- /dev/null
+++ b/vendor/nette/caching/src/Caching/IStorage.php
@@ -0,0 +1,54 @@
+cache = $cache;
+ $this->key = $key;
+ ob_start();
+ }
+
+
+ /**
+ * Stops and saves the cache.
+ * @param array dependencies
+ * @return void
+ */
+ public function end(array $dependencies = NULL)
+ {
+ if ($this->cache === NULL) {
+ throw new Nette\InvalidStateException('Output cache has already been saved.');
+ }
+ $this->cache->save($this->key, ob_get_flush(), (array) $dependencies + (array) $this->dependencies);
+ $this->cache = NULL;
+ }
+
+}
diff --git a/vendor/nette/caching/src/Caching/Storages/DevNullStorage.php b/vendor/nette/caching/src/Caching/Storages/DevNullStorage.php
new file mode 100755
index 0000000..1a08c8d
--- /dev/null
+++ b/vendor/nette/caching/src/Caching/Storages/DevNullStorage.php
@@ -0,0 +1,70 @@
+ 0,
+ self::PRIORITY => 1,
+ self::ENTRIES => 2,
+ self::DATA => 3,
+ );
+
+
+ /**
+ * @param string Directory containing journal file
+ */
+ public function __construct($dir)
+ {
+ $this->file = $dir . '/' . self::FILE;
+ }
+
+
+ /**
+ * @return void
+ */
+ public function __destruct()
+ {
+ if ($this->handle) {
+ $this->headerCommit();
+ flock($this->handle, LOCK_UN); // Since PHP 5.3.3 is manual unlock necessary
+ fclose($this->handle);
+ $this->handle = FALSE;
+ }
+ }
+
+
+ /**
+ * Writes entry information into the journal.
+ * @param string
+ * @param array
+ * @return void
+ */
+ public function write($key, array $dependencies)
+ {
+ $this->lock();
+
+ $priority = !isset($dependencies[Cache::PRIORITY]) ? FALSE : (int) $dependencies[Cache::PRIORITY];
+ $tags = empty($dependencies[Cache::TAGS]) ? FALSE : (array) $dependencies[Cache::TAGS];
+
+ $exists = FALSE;
+ $keyHash = crc32($key);
+ list($entriesNodeId, $entriesNode) = $this->findIndexNode(self::ENTRIES, $keyHash);
+
+ if (isset($entriesNode[$keyHash])) {
+ $entries = $this->mergeIndexData($entriesNode[$keyHash]);
+ foreach ($entries as $link => $foo) {
+ $dataNode = $this->getNode($link >> self::BITROT);
+ if ($dataNode[$link][self::KEY] === $key) {
+ if ($dataNode[$link][self::TAGS] == $tags && $dataNode[$link][self::PRIORITY] === $priority) { // intentionally ==, the order of tags does not matter
+ if ($dataNode[$link][self::DELETED]) {
+ $dataNode[$link][self::DELETED] = FALSE;
+ $this->saveNode($link >> self::BITROT, $dataNode);
+ }
+ $exists = TRUE;
+ } else { // Already exists, but with other tags or priority
+ $toDelete = array();
+ foreach ($dataNode[$link][self::TAGS] as $tag) {
+ $toDelete[self::TAGS][$tag][$link] = TRUE;
+ }
+ if ($dataNode[$link][self::PRIORITY] !== FALSE) {
+ $toDelete[self::PRIORITY][$dataNode[$link][self::PRIORITY]][$link] = TRUE;
+ }
+ $toDelete[self::ENTRIES][$keyHash][$link] = TRUE;
+ $this->cleanFromIndex($toDelete);
+
+ unset($dataNode[$link]);
+ $this->saveNode($link >> self::BITROT, $dataNode);
+
+ // Node was changed but may be empty, find it again
+ list($entriesNodeId, $entriesNode) = $this->findIndexNode(self::ENTRIES, $keyHash);
+ }
+ break;
+ }
+ }
+ }
+
+ if ($exists === FALSE) {
+ // Magical constants
+ $requiredSize = strlen($key) + 75;
+ if ($tags) {
+ foreach ($tags as $tag) {
+ $requiredSize += strlen($tag) + 13;
+ }
+ }
+ $requiredSize += $priority ? 10 : 1;
+
+ $freeDataNode = $this->findFreeDataNode($requiredSize);
+ $data = $this->getNode($freeDataNode);
+
+ if ($data === FALSE) {
+ $data = array(
+ self::INFO => array(
+ self::LAST_INDEX => ($freeDataNode << self::BITROT),
+ self::TYPE => self::DATA,
+ ),
+ );
+ }
+
+ $dataNodeKey = $this->findNextFreeKey($freeDataNode, $data);
+ $data[$dataNodeKey] = array(
+ self::KEY => $key,
+ self::TAGS => $tags ? $tags : array(),
+ self::PRIORITY => $priority,
+ self::DELETED => FALSE,
+ );
+
+ $this->saveNode($freeDataNode, $data);
+
+ // Save to entries tree, ...
+ $entriesNode[$keyHash][$dataNodeKey] = 1;
+ $this->saveNode($entriesNodeId, $entriesNode);
+
+ // ...tags tree...
+ if ($tags) {
+ foreach ($tags as $tag) {
+ list($nodeId, $node) = $this->findIndexNode(self::TAGS, $tag);
+ $node[$tag][$dataNodeKey] = 1;
+ $this->saveNode($nodeId, $node);
+ }
+ }
+
+ // ...and priority tree.
+ if ($priority !== FALSE) {
+ list($nodeId, $node) = $this->findIndexNode(self::PRIORITY, $priority);
+ $node[$priority][$dataNodeKey] = 1;
+ $this->saveNode($nodeId, $node);
+ }
+ }
+
+ $this->commit();
+ $this->unlock();
+ }
+
+
+ /**
+ * Cleans entries from journal.
+ * @param array
+ * @return array of removed items or NULL when performing a full cleanup
+ */
+ public function clean(array $conditions)
+ {
+ $this->lock();
+
+ if (!empty($conditions[Cache::ALL])) {
+ $this->nodeCache = $this->nodeChanged = $this->dataNodeFreeSpace = array();
+ $this->deleteAll();
+ $this->unlock();
+ return NULL;
+ }
+
+ $toDelete = array(
+ self::TAGS => array(),
+ self::PRIORITY => array(),
+ self::ENTRIES => array(),
+ );
+
+ $entries = array();
+
+ if (!empty($conditions[Cache::TAGS])) {
+ $entries = $this->cleanTags((array) $conditions[Cache::TAGS], $toDelete);
+ }
+
+ if (isset($conditions[Cache::PRIORITY])) {
+ $this->arrayAppend($entries, $this->cleanPriority((int) $conditions[Cache::PRIORITY], $toDelete));
+ }
+
+ $this->deletedLinks = array();
+ $this->cleanFromIndex($toDelete);
+
+ $this->commit();
+ $this->unlock();
+
+ return $entries;
+ }
+
+
+ /**
+ * Cleans entries from journal by tags.
+ * @param array
+ * @param array
+ * @return array of removed items
+ */
+ private function cleanTags(array $tags, array & $toDelete)
+ {
+ $entries = array();
+
+ foreach ($tags as $tag) {
+ list(, $node) = $this->findIndexNode(self::TAGS, $tag);
+
+ if (isset($node[$tag])) {
+ $ent = $this->cleanLinks($this->mergeIndexData($node[$tag]), $toDelete);
+ $this->arrayAppend($entries, $ent);
+ }
+ }
+
+ return $entries;
+ }
+
+
+ /**
+ * Cleans entries from journal by priority.
+ * @param int
+ * @param array
+ * @return array of removed items
+ */
+ private function cleanPriority($priority, array & $toDelete)
+ {
+ list(, $node) = $this->findIndexNode(self::PRIORITY, $priority);
+
+ ksort($node);
+
+ $allData = array();
+
+ foreach ($node as $prior => $data) {
+ if ($prior === self::INFO) {
+ continue;
+ } elseif ($prior > $priority) {
+ break;
+ }
+
+ $this->arrayAppendKeys($allData, $this->mergeIndexData($data));
+ }
+
+ $nodeInfo = $node[self::INFO];
+ while ($nodeInfo[self::PREV_NODE] !== -1) {
+ $nodeId = $nodeInfo[self::PREV_NODE];
+ $node = $this->getNode($nodeId);
+
+ if ($node === FALSE) {
+ if (self::$debug) {
+ throw new Nette\InvalidStateException("Cannot load node number $nodeId.");
+ }
+ break;
+ }
+
+ $nodeInfo = $node[self::INFO];
+ unset($node[self::INFO]);
+
+ foreach ($node as $data) {
+ $this->arrayAppendKeys($allData, $this->mergeIndexData($data));
+ }
+ }
+
+ return $this->cleanLinks($allData, $toDelete);
+ }
+
+
+ /**
+ * Cleans links from $data.
+ * @param array
+ * @param array
+ * @return array of removed items
+ */
+ private function cleanLinks(array $data, array & $toDelete)
+ {
+ $return = array();
+
+ $data = array_keys($data);
+ sort($data);
+ $max = count($data);
+ $data[] = 0;
+ $i = 0;
+
+ while ($i < $max) {
+ $searchLink = $data[$i];
+
+ if (isset($this->deletedLinks[$searchLink])) {
+ ++$i;
+ continue;
+ }
+
+ $nodeId = $searchLink >> self::BITROT;
+ $node = $this->getNode($nodeId);
+
+ if ($node === FALSE) {
+ if (self::$debug) {
+ throw new Nette\InvalidStateException("Cannot load node number $nodeId.");
+ }
+ ++$i;
+ continue;
+ }
+
+ do {
+ $link = $data[$i];
+
+ if (isset($this->deletedLinks[$link])) {
+ continue;
+ } elseif (!isset($node[$link])) {
+ if (self::$debug) {
+ throw new Nette\InvalidStateException("Link with ID $searchLink is not in node $nodeId.");
+ }
+ continue;
+ }
+
+ $nodeLink = & $node[$link];
+ if (!$nodeLink[self::DELETED]) {
+ $nodeLink[self::DELETED] = TRUE;
+ $return[] = $nodeLink[self::KEY];
+ } else {
+ foreach ($nodeLink[self::TAGS] as $tag) {
+ $toDelete[self::TAGS][$tag][$link] = TRUE;
+ }
+ if ($nodeLink[self::PRIORITY] !== FALSE) {
+ $toDelete[self::PRIORITY][$nodeLink[self::PRIORITY]][$link] = TRUE;
+ }
+ $toDelete[self::ENTRIES][crc32($nodeLink[self::KEY])][$link] = TRUE;
+ unset($node[$link]);
+ $this->deletedLinks[$link] = TRUE;
+ }
+ } while (($data[++$i] >> self::BITROT) === $nodeId);
+
+ $this->saveNode($nodeId, $node);
+ }
+
+ return $return;
+ }
+
+
+ /**
+ * Remove links to deleted keys from index.
+ * @param array
+ */
+ private function cleanFromIndex(array $toDeleteFromIndex)
+ {
+ foreach ($toDeleteFromIndex as $type => $toDelete) {
+ ksort($toDelete);
+
+ while (!empty($toDelete)) {
+ reset($toDelete);
+ $searchKey = key($toDelete);
+ list($masterNodeId, $masterNode) = $this->findIndexNode($type, $searchKey);
+
+ if (!isset($masterNode[$searchKey])) {
+ if (self::$debug) {
+ throw new Nette\InvalidStateException('Bad index.');
+ }
+ unset($toDelete[$searchKey]);
+ continue;
+ }
+
+ foreach ($toDelete as $key => $links) {
+ if (isset($masterNode[$key])) {
+ foreach ($links as $link => $foo) {
+ if (isset($masterNode[$key][$link])) {
+ unset($masterNode[$key][$link], $links[$link]);
+ }
+ }
+
+ if (!empty($links) && isset($masterNode[$key][self::INDEX_DATA])) {
+ $this->cleanIndexData($masterNode[$key][self::INDEX_DATA], $links, $masterNode[$key]);
+ }
+
+ if (empty($masterNode[$key])) {
+ unset($masterNode[$key]);
+ }
+ unset($toDelete[$key]);
+ } else {
+ break;
+ }
+ }
+ $this->saveNode($masterNodeId, $masterNode);
+ }
+ }
+ }
+
+
+ /**
+ * Merge data with index data in other nodes.
+ * @param array
+ * @return array of merged items
+ */
+ private function mergeIndexData(array $data)
+ {
+ while (isset($data[self::INDEX_DATA])) {
+ $id = $data[self::INDEX_DATA];
+ unset($data[self::INDEX_DATA]);
+ $childNode = $this->getNode($id);
+
+ if ($childNode === FALSE) {
+ if (self::$debug) {
+ throw new Nette\InvalidStateException("Cannot load node number $id.");
+ }
+ break;
+ }
+
+ $this->arrayAppendKeys($data, $childNode[self::INDEX_DATA]);
+ }
+
+ return $data;
+ }
+
+
+ /**
+ * Cleans links from other nodes.
+ * @param int
+ * @param array
+ * @param array
+ * @return void
+ */
+ private function cleanIndexData($nextNodeId, array $links, & $masterNodeLink)
+ {
+ $prev = -1;
+
+ while ($nextNodeId && !empty($links)) {
+ $nodeId = $nextNodeId;
+ $node = $this->getNode($nodeId);
+
+ if ($node === FALSE) {
+ if (self::$debug) {
+ throw new Nette\InvalidStateException("Cannot load node number $nodeId.");
+ }
+ break;
+ }
+
+ foreach ($links as $link => $foo) {
+ if (isset($node[self::INDEX_DATA][$link])) {
+ unset($node[self::INDEX_DATA][$link], $links[$link]);
+ }
+ }
+
+ if (isset($node[self::INDEX_DATA][self::INDEX_DATA])) {
+ $nextNodeId = $node[self::INDEX_DATA][self::INDEX_DATA];
+ } else {
+ $nextNodeId = FALSE;
+ }
+
+ if (empty($node[self::INDEX_DATA]) || (count($node[self::INDEX_DATA]) === 1 && $nextNodeId)) {
+ if ($prev === -1) {
+ if ($nextNodeId === FALSE) {
+ unset($masterNodeLink[self::INDEX_DATA]);
+ } else {
+ $masterNodeLink[self::INDEX_DATA] = $nextNodeId;
+ }
+ } else {
+ $prevNode = $this->getNode($prev);
+ if ($prevNode === FALSE) {
+ if (self::$debug) {
+ throw new Nette\InvalidStateException("Cannot load node number $prev.");
+ }
+ } else {
+ if ($nextNodeId === FALSE) {
+ unset($prevNode[self::INDEX_DATA][self::INDEX_DATA]);
+ if (empty($prevNode[self::INDEX_DATA])) {
+ unset($prevNode[self::INDEX_DATA]);
+ }
+ } else {
+ $prevNode[self::INDEX_DATA][self::INDEX_DATA] = $nextNodeId;
+ }
+
+ $this->saveNode($prev, $prevNode);
+ }
+ }
+ unset($node[self::INDEX_DATA]);
+ } else {
+ $prev = $nodeId;
+ }
+
+ $this->saveNode($nodeId, $node);
+ }
+ }
+
+
+ /**
+ * Get node from journal.
+ * @param int
+ * @return array
+ */
+ private function getNode($id)
+ {
+ // Load from cache
+ if (isset($this->nodeCache[$id])) {
+ return $this->nodeCache[$id];
+ }
+
+ $binary = stream_get_contents($this->handle, self::NODE_SIZE, self::HEADER_SIZE + self::NODE_SIZE * $id);
+
+ if (empty($binary)) {
+ // empty node, no Exception
+ return FALSE;
+ }
+
+ list(, $magic, $length) = unpack('N2', $binary);
+ if ($magic !== self::INDEX_MAGIC && $magic !== self::DATA_MAGIC) {
+ if (!empty($magic)) {
+ if (self::$debug) {
+ throw new Nette\InvalidStateException("Node $id has malformed header.");
+ }
+ $this->deleteNode($id);
+ }
+ return FALSE;
+ }
+
+ $data = substr($binary, 2 * self::INT32_SIZE, $length - 2 * self::INT32_SIZE);
+
+ $node = @unserialize($data); // intentionally @
+ if ($node === FALSE) {
+ $this->deleteNode($id);
+ if (self::$debug) {
+ throw new Nette\InvalidStateException("Cannot unserialize node number $id.");
+ }
+ return FALSE;
+ }
+
+ // Save to cache and return
+ return $this->nodeCache[$id] = $node;
+ }
+
+
+ /**
+ * Save node to cache.
+ * @param int
+ * @param array
+ * @return void
+ */
+ private function saveNode($id, array $node)
+ {
+ if (count($node) === 1) { // Nod contains only INFO
+ $nodeInfo = $node[self::INFO];
+ if ($nodeInfo[self::TYPE] !== self::DATA) {
+
+ if ($nodeInfo[self::END] !== -1) {
+ $this->nodeCache[$id] = $node;
+ $this->nodeChanged[$id] = TRUE;
+ return;
+ }
+
+ if ($nodeInfo[self::MAX] === -1) {
+ $max = PHP_INT_MAX;
+ } else {
+ $max = $nodeInfo[self::MAX];
+ }
+
+ list(, , $parentId) = $this->findIndexNode($nodeInfo[self::TYPE], $max, $id);
+ if ($parentId !== -1 && $parentId !== $id) {
+ $parentNode = $this->getNode($parentId);
+ if ($parentNode === FALSE) {
+ if (self::$debug) {
+ throw new Nette\InvalidStateException("Cannot load node number $parentId.");
+ }
+ } else {
+ if ($parentNode[self::INFO][self::END] === $id) {
+ if (count($parentNode) === 1) {
+ $parentNode[self::INFO][self::END] = -1;
+ } else {
+ end($parentNode);
+ $lastKey = key($parentNode);
+ $parentNode[self::INFO][self::END] = $parentNode[$lastKey];
+ unset($parentNode[$lastKey]);
+ }
+ } else {
+ unset($parentNode[$nodeInfo[self::MAX]]);
+ }
+
+ $this->saveNode($parentId, $parentNode);
+ }
+ }
+
+ if ($nodeInfo[self::TYPE] === self::PRIORITY) { // only priority tree has link to prevNode
+ if ($nodeInfo[self::MAX] === -1) {
+ if ($nodeInfo[self::PREV_NODE] !== -1) {
+ $prevNode = $this->getNode($nodeInfo[self::PREV_NODE]);
+ if ($prevNode === FALSE) {
+ if (self::$debug) {
+ throw new Nette\InvalidStateException("Cannot load node number {$nodeInfo[self::PREV_NODE]}.");
+ }
+ } else {
+ $prevNode[self::INFO][self::MAX] = -1;
+ $this->saveNode($nodeInfo[self::PREV_NODE], $prevNode);
+ }
+ }
+ } else {
+ list($nextId, $nextNode) = $this->findIndexNode($nodeInfo[self::TYPE], $nodeInfo[self::MAX] + 1, NULL, $id);
+ if ($nextId !== -1 && $nextId !== $id) {
+ $nextNode[self::INFO][self::PREV_NODE] = $nodeInfo[self::PREV_NODE];
+ $this->saveNode($nextId, $nextNode);
+ }
+ }
+ }
+ }
+ $this->nodeCache[$id] = FALSE;
+ } else {
+ $this->nodeCache[$id] = $node;
+ }
+ $this->nodeChanged[$id] = TRUE;
+ }
+
+
+ /**
+ * Commit all changed nodes from cache to journal file.
+ * @return void
+ */
+ private function commit()
+ {
+ do {
+ foreach ($this->nodeChanged as $id => $foo) {
+ if ($this->prepareNode($id, $this->nodeCache[$id])) {
+ unset($this->nodeChanged[$id]);
+ }
+ }
+ } while (!empty($this->nodeChanged));
+
+ foreach ($this->toCommit as $node => $str) {
+ $this->commitNode($node, $str);
+ }
+ $this->toCommit = array();
+ }
+
+
+ /**
+ * Prepare node to journal file structure.
+ * @param int
+ * @param array|bool
+ * @return bool Successfully committed
+ */
+ private function prepareNode($id, $node)
+ {
+ if ($node === FALSE) {
+ if ($id < $this->lastNode) {
+ $this->lastNode = $id;
+ }
+ unset($this->nodeCache[$id]);
+ unset($this->dataNodeFreeSpace[$id]);
+ $this->deleteNode($id);
+ return TRUE;
+ }
+
+ $data = serialize($node);
+ $dataSize = strlen($data) + 2 * self::INT32_SIZE;
+
+ $isData = $node[self::INFO][self::TYPE] === self::DATA;
+ if ($dataSize > self::NODE_SIZE) {
+ if ($isData) {
+ throw new Nette\InvalidStateException('Saving node is bigger than maximum node size.');
+ } else {
+ $this->bisectNode($id, $node);
+ return FALSE;
+ }
+ }
+
+ $this->toCommit[$id] = pack('N2', $isData ? self::DATA_MAGIC : self::INDEX_MAGIC, $dataSize) . $data;
+
+ if ($this->lastNode < $id) {
+ $this->lastNode = $id;
+ }
+ if ($isData) {
+ $this->dataNodeFreeSpace[$id] = self::NODE_SIZE - $dataSize;
+ }
+
+ return TRUE;
+ }
+
+
+ /**
+ * Commit node string to journal file.
+ * @param int
+ * @param string
+ * @return void
+ */
+ private function commitNode($id, $str)
+ {
+ fseek($this->handle, self::HEADER_SIZE + self::NODE_SIZE * $id);
+ $written = fwrite($this->handle, $str);
+ if ($written === FALSE) {
+ throw new Nette\InvalidStateException("Cannot write node number $id to journal.");
+ }
+ }
+
+
+ /**
+ * Find right node in B+tree. .
+ * @param string Tree type (TAGS, PRIORITY or ENTRIES)
+ * @param int Searched item
+ * @return array Node
+ */
+ private function findIndexNode($type, $search, $childId = NULL, $prevId = NULL)
+ {
+ $nodeId = self::$startNode[$type];
+
+ $parentId = -1;
+ while (TRUE) {
+ $node = $this->getNode($nodeId);
+
+ if ($node === FALSE) {
+ return array(
+ $nodeId,
+ array(
+ self::INFO => array(
+ self::TYPE => $type,
+ self::IS_LEAF => TRUE,
+ self::PREV_NODE => -1,
+ self::END => -1,
+ self::MAX => -1,
+ ),
+ ),
+ $parentId,
+ ); // Init empty node
+ }
+
+ if ($node[self::INFO][self::IS_LEAF] || $nodeId === $childId || $node[self::INFO][self::PREV_NODE] === $prevId) {
+ return array($nodeId, $node, $parentId);
+ }
+
+ $parentId = $nodeId;
+
+ if (isset($node[$search])) {
+ $nodeId = $node[$search];
+ } else {
+ foreach ($node as $key => $childNode) {
+ if ($key > $search && $key !== self::INFO) {
+ $nodeId = $childNode;
+ continue 2;
+ }
+ }
+
+ $nodeId = $node[self::INFO][self::END];
+ }
+ }
+ }
+
+
+ /**
+ * Find complete free node.
+ * @param int
+ * @return array|int Node ID
+ */
+ private function findFreeNode($count = 1)
+ {
+ $id = $this->lastNode;
+ $nodesId = array();
+
+ do {
+ if (isset($this->nodeCache[$id])) {
+ ++$id;
+ continue;
+ }
+
+ $offset = self::HEADER_SIZE + self::NODE_SIZE * $id;
+
+ $binary = stream_get_contents($this->handle, self::INT32_SIZE, $offset);
+
+ if (empty($binary)) {
+ $nodesId[] = $id;
+ } else {
+ list(, $magic) = unpack('N', $binary);
+ if ($magic !== self::INDEX_MAGIC && $magic !== self::DATA_MAGIC) {
+ $nodesId[] = $id;
+ }
+ }
+
+ ++$id;
+ } while (count($nodesId) !== $count);
+
+ if ($count === 1) {
+ return $nodesId[0];
+ } else {
+ return $nodesId;
+ }
+ }
+
+
+ /**
+ * Find free data node that has $size bytes of free space.
+ * @param int size in bytes
+ * @return int Node ID
+ */
+ private function findFreeDataNode($size)
+ {
+ foreach ($this->dataNodeFreeSpace as $id => $freeSpace) {
+ if ($freeSpace > $size) {
+ return $id;
+ }
+ }
+
+ $id = self::$startNode[self::DATA];
+ while (TRUE) {
+ if (isset($this->dataNodeFreeSpace[$id]) || isset($this->nodeCache[$id])) {
+ ++$id;
+ continue;
+ }
+
+ $offset = self::HEADER_SIZE + self::NODE_SIZE * $id;
+ $binary = stream_get_contents($this->handle, 2 * self::INT32_SIZE, $offset);
+
+ if (empty($binary)) {
+ $this->dataNodeFreeSpace[$id] = self::NODE_SIZE;
+ return $id;
+ }
+
+ list(, $magic, $nodeSize) = unpack('N2', $binary);
+ if (empty($magic)) {
+ $this->dataNodeFreeSpace[$id] = self::NODE_SIZE;
+ return $id;
+ } elseif ($magic === self::DATA_MAGIC) {
+ $freeSpace = self::NODE_SIZE - $nodeSize;
+ $this->dataNodeFreeSpace[$id] = $freeSpace;
+
+ if ($freeSpace > $size) {
+ return $id;
+ }
+ }
+
+ ++$id;
+ }
+ }
+
+
+ /**
+ * Bisect node or when has only one key, move part to data node.
+ * @param int Node ID
+ * @param array Node
+ * @return void
+ */
+ private function bisectNode($id, array $node)
+ {
+ $nodeInfo = $node[self::INFO];
+ unset($node[self::INFO]);
+
+ if (count($node) === 1) {
+ $key = key($node);
+
+ $dataId = $this->findFreeDataNode(self::NODE_SIZE);
+ $this->saveNode($dataId, array(
+ self::INDEX_DATA => $node[$key],
+ self::INFO => array(
+ self::TYPE => self::DATA,
+ self::LAST_INDEX => ($dataId << self::BITROT),
+ )));
+
+ unset($node[$key]);
+ $node[$key][self::INDEX_DATA] = $dataId;
+ $node[self::INFO] = $nodeInfo;
+
+ $this->saveNode($id, $node);
+ return;
+ }
+
+ ksort($node);
+ $halfCount = ceil(count($node) / 2);
+
+ list($first, $second) = array_chunk($node, $halfCount, TRUE);
+
+ end($first);
+ $halfKey = key($first);
+
+ if ($id <= 2) { // Root
+ list($firstId, $secondId) = $this->findFreeNode(2);
+
+ $first[self::INFO] = array(
+ self::TYPE => $nodeInfo[self::TYPE],
+ self::IS_LEAF => $nodeInfo[self::IS_LEAF],
+ self::PREV_NODE => -1,
+ self::END => -1,
+ self::MAX => $halfKey,
+ );
+ $this->saveNode($firstId, $first);
+
+ $second[self::INFO] = array(
+ self::TYPE => $nodeInfo[self::TYPE],
+ self::IS_LEAF => $nodeInfo[self::IS_LEAF],
+ self::PREV_NODE => $firstId,
+ self::END => $nodeInfo[self::END],
+ self::MAX => -1,
+ );
+ $this->saveNode($secondId, $second);
+
+ $parentNode = array(
+ self::INFO => array(
+ self::TYPE => $nodeInfo[self::TYPE],
+ self::IS_LEAF => FALSE,
+ self::PREV_NODE => -1,
+ self::END => $secondId,
+ self::MAX => -1,
+ ),
+ $halfKey => $firstId,
+ );
+ $this->saveNode($id, $parentNode);
+ } else {
+ $firstId = $this->findFreeNode();
+
+ $first[self::INFO] = array(
+ self::TYPE => $nodeInfo[self::TYPE],
+ self::IS_LEAF => $nodeInfo[self::IS_LEAF],
+ self::PREV_NODE => $nodeInfo[self::PREV_NODE],
+ self::END => -1,
+ self::MAX => $halfKey,
+ );
+ $this->saveNode($firstId, $first);
+
+ $second[self::INFO] = array(
+ self::TYPE => $nodeInfo[self::TYPE],
+ self::IS_LEAF => $nodeInfo[self::IS_LEAF],
+ self::PREV_NODE => $firstId,
+ self::END => $nodeInfo[self::END],
+ self::MAX => $nodeInfo[self::MAX],
+ );
+ $this->saveNode($id, $second);
+
+ list(, , $parent) = $this->findIndexNode($nodeInfo[self::TYPE], $halfKey);
+ $parentNode = $this->getNode($parent);
+ if ($parentNode === FALSE) {
+ if (self::$debug) {
+ throw new Nette\InvalidStateException("Cannot load node number $parent.");
+ }
+ } else {
+ $parentNode[$halfKey] = $firstId;
+ ksort($parentNode); // Parent index must be always sorted.
+ $this->saveNode($parent, $parentNode);
+ }
+ }
+ }
+
+
+ /**
+ * Commit header to journal file.
+ * @return void
+ */
+ private function headerCommit()
+ {
+ fseek($this->handle, self::INT32_SIZE);
+ @fwrite($this->handle, pack('N', $this->lastNode)); // intentionally @, save is not necessary
+ }
+
+
+ /**
+ * Remove node from journal file.
+ * @param int
+ * @return void
+ */
+ private function deleteNode($id)
+ {
+ fseek($this->handle, 0, SEEK_END);
+ $end = ftell($this->handle);
+
+ if ($end <= (self::HEADER_SIZE + self::NODE_SIZE * ($id + 1))) {
+ $packedNull = pack('N', 0);
+
+ do {
+ $binary = stream_get_contents($this->handle, self::INT32_SIZE, (self::HEADER_SIZE + self::NODE_SIZE * --$id));
+ } while (empty($binary) || $binary === $packedNull);
+
+ if (!ftruncate($this->handle, self::HEADER_SIZE + self::NODE_SIZE * ($id + 1))) {
+ throw new Nette\InvalidStateException('Cannot truncate journal file.');
+ }
+ } else {
+ fseek($this->handle, self::HEADER_SIZE + self::NODE_SIZE * $id);
+ $written = fwrite($this->handle, pack('N', 0));
+ if ($written !== self::INT32_SIZE) {
+ throw new Nette\InvalidStateException("Cannot delete node number $id from journal.");
+ }
+ }
+ }
+
+
+ /**
+ * Complete delete all nodes from file.
+ * @throws Nette\InvalidStateException
+ */
+ private function deleteAll()
+ {
+ if (!ftruncate($this->handle, self::HEADER_SIZE)) {
+ throw new Nette\InvalidStateException('Cannot truncate journal file.');
+ }
+ }
+
+
+ /**
+ * Lock file for writing and reading and delete node cache when file has changed.
+ * @throws Nette\InvalidStateException
+ */
+ private function lock()
+ {
+ if (!$this->handle) {
+ $this->prepare();
+ }
+
+ if (!flock($this->handle, LOCK_EX)) {
+ throw new Nette\InvalidStateException("Cannot acquire exclusive lock on journal file '$this->file'.");
+ }
+
+ $lastProcessIdentifier = stream_get_contents($this->handle, self::INT32_SIZE, self::INT32_SIZE * 2);
+ if ($lastProcessIdentifier !== $this->processIdentifier) {
+ $this->nodeCache = $this->dataNodeFreeSpace = array();
+
+ // Write current processIdentifier to file header
+ fseek($this->handle, self::INT32_SIZE * 2);
+ fwrite($this->handle, $this->processIdentifier);
+ }
+ }
+
+
+ /**
+ * Open btfj.dat file (or create it if not exists) and load metainformation.
+ * @throws Nette\InvalidStateException
+ */
+ private function prepare()
+ {
+ // Create journal file when not exists
+ if (!file_exists($this->file)) {
+ $init = @fopen($this->file, 'xb'); // intentionally @
+ if (!$init) {
+ clearstatcache();
+ if (!file_exists($this->file)) {
+ throw new Nette\InvalidStateException("Cannot create journal file '$this->file'.");
+ }
+ } else {
+ $written = fwrite($init, pack('N2', self::FILE_MAGIC, $this->lastNode));
+ fclose($init);
+ if ($written !== self::INT32_SIZE * 2) {
+ throw new Nette\InvalidStateException('Cannot write journal header.');
+ }
+ }
+ }
+
+ $this->handle = fopen($this->file, 'r+b');
+
+ if (!$this->handle) {
+ throw new Nette\InvalidStateException("Cannot open journal file '$this->file'.");
+ }
+
+ if (!flock($this->handle, LOCK_SH)) {
+ throw new Nette\InvalidStateException('Cannot acquire shared lock on journal.');
+ }
+
+ $header = stream_get_contents($this->handle, 2 * self::INT32_SIZE, 0);
+
+ flock($this->handle, LOCK_UN);
+
+ list(, $fileMagic, $this->lastNode) = unpack('N2', $header);
+
+ if ($fileMagic !== self::FILE_MAGIC) {
+ fclose($this->handle);
+ $this->handle = FALSE;
+ throw new Nette\InvalidStateException("Malformed journal file '$this->file'.");
+ }
+
+ $this->processIdentifier = pack('N', mt_rand());
+ }
+
+
+ /**
+ * Unlock file and save last modified time.
+ * @return void
+ */
+ private function unlock()
+ {
+ if ($this->handle) {
+ fflush($this->handle);
+ flock($this->handle, LOCK_UN);
+ }
+ }
+
+
+ /**
+ * @param int
+ * @return int
+ * @throws Nette\InvalidStateException
+ */
+ private function findNextFreeKey($nodeId, array & $nodeData)
+ {
+ $newKey = $nodeData[self::INFO][self::LAST_INDEX] + 1;
+ $maxKey = ($nodeId + 1) << self::BITROT;
+
+ if ($newKey >= $maxKey) {
+ $start = $nodeId << self::BITROT;
+ for ($i = $start; $i < $maxKey; $i++) {
+ if (!isset($nodeData[$i])) {
+ return $i;
+ }
+ }
+ throw new Nette\InvalidStateException("Node $nodeId is full.");
+ } else {
+ return ++$nodeData[self::INFO][self::LAST_INDEX];
+ }
+ }
+
+
+ /**
+ * Append $append to $array.
+ * This function is much faster than $array = array_merge($array, $append)
+ * @param array
+ * @param array
+ * @return void
+ */
+ private function arrayAppend(array & $array, array $append)
+ {
+ foreach ($append as $value) {
+ $array[] = $value;
+ }
+ }
+
+
+ /**
+ * Append $append to $array with preserve keys.
+ * This function is much faster than $array = $array + $append
+ * @param array
+ * @param array
+ * @return void
+ */
+ private function arrayAppendKeys(array & $array, array $append)
+ {
+ foreach ($append as $key => $value) {
+ $array[$key] = $value;
+ }
+ }
+
+}
diff --git a/vendor/nette/caching/src/Caching/Storages/FileStorage.php b/vendor/nette/caching/src/Caching/Storages/FileStorage.php
new file mode 100755
index 0000000..a311f77
--- /dev/null
+++ b/vendor/nette/caching/src/Caching/Storages/FileStorage.php
@@ -0,0 +1,405 @@
+ timestamp)
+ META_CALLBACKS = 'callbacks'; // array of callbacks (function, args)
+
+ /** additional cache structure */
+ const FILE = 'file',
+ HANDLE = 'handle';
+
+
+ /** @var float probability that the clean() routine is started */
+ public static $gcProbability = 0.001;
+
+ /** @var bool */
+ public static $useDirectories = TRUE;
+
+ /** @var string */
+ private $dir;
+
+ /** @var bool */
+ private $useDirs;
+
+ /** @var IJournal */
+ private $journal;
+
+ /** @var array */
+ private $locks;
+
+
+ public function __construct($dir, IJournal $journal = NULL)
+ {
+ if (!is_dir($dir)) {
+ throw new Nette\DirectoryNotFoundException("Directory '$dir' not found.");
+ }
+
+ $this->dir = $dir;
+ $this->useDirs = (bool) static::$useDirectories;
+ $this->journal = $journal;
+
+ if (mt_rand() / mt_getrandmax() < static::$gcProbability) {
+ $this->clean(array());
+ }
+ }
+
+
+ /**
+ * Read from cache.
+ * @param string key
+ * @return mixed|NULL
+ */
+ public function read($key)
+ {
+ $meta = $this->readMetaAndLock($this->getCacheFile($key), LOCK_SH);
+ if ($meta && $this->verify($meta)) {
+ return $this->readData($meta); // calls fclose()
+
+ } else {
+ return NULL;
+ }
+ }
+
+
+ /**
+ * Verifies dependencies.
+ * @param array
+ * @return bool
+ */
+ private function verify($meta)
+ {
+ do {
+ if (!empty($meta[self::META_DELTA])) {
+ // meta[file] was added by readMetaAndLock()
+ if (filemtime($meta[self::FILE]) + $meta[self::META_DELTA] < time()) {
+ break;
+ }
+ touch($meta[self::FILE]);
+
+ } elseif (!empty($meta[self::META_EXPIRE]) && $meta[self::META_EXPIRE] < time()) {
+ break;
+ }
+
+ if (!empty($meta[self::META_CALLBACKS]) && !Cache::checkCallbacks($meta[self::META_CALLBACKS])) {
+ break;
+ }
+
+ if (!empty($meta[self::META_ITEMS])) {
+ foreach ($meta[self::META_ITEMS] as $depFile => $time) {
+ $m = $this->readMetaAndLock($depFile, LOCK_SH);
+ if ($m[self::META_TIME] !== $time || ($m && !$this->verify($m))) {
+ break 2;
+ }
+ }
+ }
+
+ return TRUE;
+ } while (FALSE);
+
+ $this->delete($meta[self::FILE], $meta[self::HANDLE]); // meta[handle] & meta[file] was added by readMetaAndLock()
+ return FALSE;
+ }
+
+
+ /**
+ * Prevents item reading and writing. Lock is released by write() or remove().
+ * @param string key
+ * @return void
+ */
+ public function lock($key)
+ {
+ $cacheFile = $this->getCacheFile($key);
+ if ($this->useDirs && !is_dir($dir = dirname($cacheFile))) {
+ @mkdir($dir); // @ - directory may already exist
+ }
+ $handle = fopen($cacheFile, 'c+b');
+ if ($handle) {
+ $this->locks[$key] = $handle;
+ flock($handle, LOCK_EX);
+ }
+ }
+
+
+ /**
+ * Writes item into the cache.
+ * @param string key
+ * @param mixed data
+ * @param array dependencies
+ * @return void
+ */
+ public function write($key, $data, array $dp)
+ {
+ $meta = array(
+ self::META_TIME => microtime(),
+ );
+
+ if (isset($dp[Cache::EXPIRATION])) {
+ if (empty($dp[Cache::SLIDING])) {
+ $meta[self::META_EXPIRE] = $dp[Cache::EXPIRATION] + time(); // absolute time
+ } else {
+ $meta[self::META_DELTA] = (int) $dp[Cache::EXPIRATION]; // sliding time
+ }
+ }
+
+ if (isset($dp[Cache::ITEMS])) {
+ foreach ((array) $dp[Cache::ITEMS] as $item) {
+ $depFile = $this->getCacheFile($item);
+ $m = $this->readMetaAndLock($depFile, LOCK_SH);
+ $meta[self::META_ITEMS][$depFile] = $m[self::META_TIME]; // may be NULL
+ unset($m);
+ }
+ }
+
+ if (isset($dp[Cache::CALLBACKS])) {
+ $meta[self::META_CALLBACKS] = $dp[Cache::CALLBACKS];
+ }
+
+ if (!isset($this->locks[$key])) {
+ $this->lock($key);
+ if (!isset($this->locks[$key])) {
+ return;
+ }
+ }
+ $handle = $this->locks[$key];
+ unset($this->locks[$key]);
+
+ $cacheFile = $this->getCacheFile($key);
+
+ if (isset($dp[Cache::TAGS]) || isset($dp[Cache::PRIORITY])) {
+ if (!$this->journal) {
+ throw new Nette\InvalidStateException('CacheJournal has not been provided.');
+ }
+ $this->journal->write($cacheFile, $dp);
+ }
+
+ ftruncate($handle, 0);
+
+ if (!is_string($data)) {
+ $data = serialize($data);
+ $meta[self::META_SERIALIZED] = TRUE;
+ }
+
+ $head = serialize($meta) . '?>';
+ $head = 'delete($cacheFile, $handle);
+ }
+
+
+ /**
+ * Removes item from the cache.
+ * @param string key
+ * @return void
+ */
+ public function remove($key)
+ {
+ unset($this->locks[$key]);
+ $this->delete($this->getCacheFile($key));
+ }
+
+
+ /**
+ * Removes items from the cache by conditions & garbage collector.
+ * @param array conditions
+ * @return void
+ */
+ public function clean(array $conditions)
+ {
+ $all = !empty($conditions[Cache::ALL]);
+ $collector = empty($conditions);
+
+ // cleaning using file iterator
+ if ($all || $collector) {
+ $now = time();
+ foreach (Nette\Utils\Finder::find('_*')->from($this->dir)->childFirst() as $entry) {
+ $path = (string) $entry;
+ if ($entry->isDir()) { // collector: remove empty dirs
+ @rmdir($path); // @ - removing dirs is not necessary
+ continue;
+ }
+ if ($all) {
+ $this->delete($path);
+
+ } else { // collector
+ $meta = $this->readMetaAndLock($path, LOCK_SH);
+ if (!$meta) {
+ continue;
+ }
+
+ if ((!empty($meta[self::META_DELTA]) && filemtime($meta[self::FILE]) + $meta[self::META_DELTA] < $now)
+ || (!empty($meta[self::META_EXPIRE]) && $meta[self::META_EXPIRE] < $now)
+ ) {
+ $this->delete($path, $meta[self::HANDLE]);
+ continue;
+ }
+
+ flock($meta[self::HANDLE], LOCK_UN);
+ fclose($meta[self::HANDLE]);
+ }
+ }
+
+ if ($this->journal) {
+ $this->journal->clean($conditions);
+ }
+ return;
+ }
+
+ // cleaning using journal
+ if ($this->journal) {
+ foreach ($this->journal->clean($conditions) as $file) {
+ $this->delete($file);
+ }
+ }
+ }
+
+
+ /**
+ * Reads cache data from disk.
+ * @param string file path
+ * @param int lock mode
+ * @return array|NULL
+ */
+ protected function readMetaAndLock($file, $lock)
+ {
+ $handle = @fopen($file, 'r+b'); // @ - file may not exist
+ if (!$handle) {
+ return NULL;
+ }
+
+ flock($handle, $lock);
+
+ $head = stream_get_contents($handle, self::META_HEADER_LEN);
+ if ($head && strlen($head) === self::META_HEADER_LEN) {
+ $size = (int) substr($head, -6);
+ $meta = stream_get_contents($handle, $size, self::META_HEADER_LEN);
+ $meta = @unserialize($meta); // intentionally @
+ if (is_array($meta)) {
+ $meta[self::FILE] = $file;
+ $meta[self::HANDLE] = $handle;
+ return $meta;
+ }
+ }
+
+ flock($handle, LOCK_UN);
+ fclose($handle);
+ return NULL;
+ }
+
+
+ /**
+ * Reads cache data from disk and closes cache file handle.
+ * @param array
+ * @return mixed
+ */
+ protected function readData($meta)
+ {
+ $data = stream_get_contents($meta[self::HANDLE]);
+ flock($meta[self::HANDLE], LOCK_UN);
+ fclose($meta[self::HANDLE]);
+
+ if (empty($meta[self::META_SERIALIZED])) {
+ return $data;
+ } else {
+ return @unserialize($data); // intentionally @
+ }
+ }
+
+
+ /**
+ * Returns file name.
+ * @param string
+ * @return string
+ */
+ protected function getCacheFile($key)
+ {
+ $file = urlencode($key);
+ if ($this->useDirs && $a = strrpos($file, '%00')) { // %00 = urlencode(Nette\Caching\Cache::NAMESPACE_SEPARATOR)
+ $file = substr_replace($file, '/_', $a, 3);
+ }
+ return $this->dir . '/_' . $file;
+ }
+
+
+ /**
+ * Deletes and closes file.
+ * @param string
+ * @param resource
+ * @return void
+ */
+ private static function delete($file, $handle = NULL)
+ {
+ if (@unlink($file)) { // @ - file may not already exist
+ if ($handle) {
+ flock($handle, LOCK_UN);
+ fclose($handle);
+ }
+ return;
+ }
+
+ if (!$handle) {
+ $handle = @fopen($file, 'r+'); // @ - file may not exist
+ }
+ if ($handle) {
+ flock($handle, LOCK_EX);
+ ftruncate($handle, 0);
+ flock($handle, LOCK_UN);
+ fclose($handle);
+ @unlink($file); // @ - file may not already exist
+ }
+ }
+
+}
diff --git a/vendor/nette/caching/src/Caching/Storages/IJournal.php b/vendor/nette/caching/src/Caching/Storages/IJournal.php
new file mode 100755
index 0000000..b8079ae
--- /dev/null
+++ b/vendor/nette/caching/src/Caching/Storages/IJournal.php
@@ -0,0 +1,33 @@
+prefix = $prefix;
+ $this->journal = $journal;
+ $this->memcache = new \Memcache;
+ if ($host) {
+ $this->addServer($host, $port);
+ }
+ }
+
+
+ public function addServer($host = 'localhost', $port = 11211, $timeout = 1)
+ {
+ if ($this->memcache->addServer($host, $port, TRUE, 1, $timeout) === FALSE) {
+ $error = error_get_last();
+ throw new Nette\InvalidStateException("Memcache::addServer(): $error[message].");
+ }
+ }
+
+
+ /**
+ * @return \Memcache
+ */
+ public function getConnection()
+ {
+ return $this->memcache;
+ }
+
+
+ /**
+ * Read from cache.
+ * @param string key
+ * @return mixed|NULL
+ */
+ public function read($key)
+ {
+ $key = urlencode($this->prefix . $key);
+ $meta = $this->memcache->get($key);
+ if (!$meta) {
+ return NULL;
+ }
+
+ // meta structure:
+ // array(
+ // data => stored data
+ // delta => relative (sliding) expiration
+ // callbacks => array of callbacks (function, args)
+ // )
+
+ // verify dependencies
+ if (!empty($meta[self::META_CALLBACKS]) && !Cache::checkCallbacks($meta[self::META_CALLBACKS])) {
+ $this->memcache->delete($key, 0);
+ return NULL;
+ }
+
+ if (!empty($meta[self::META_DELTA])) {
+ $this->memcache->replace($key, $meta, 0, $meta[self::META_DELTA] + time());
+ }
+
+ return $meta[self::META_DATA];
+ }
+
+
+ /**
+ * Prevents item reading and writing. Lock is released by write() or remove().
+ * @param string key
+ * @return void
+ */
+ public function lock($key)
+ {
+ }
+
+
+ /**
+ * Writes item into the cache.
+ * @param string key
+ * @param mixed data
+ * @param array dependencies
+ * @return void
+ */
+ public function write($key, $data, array $dp)
+ {
+ if (isset($dp[Cache::ITEMS])) {
+ throw new Nette\NotSupportedException('Dependent items are not supported by MemcachedStorage.');
+ }
+
+ $key = urlencode($this->prefix . $key);
+ $meta = array(
+ self::META_DATA => $data,
+ );
+
+ $expire = 0;
+ if (isset($dp[Cache::EXPIRATION])) {
+ $expire = (int) $dp[Cache::EXPIRATION];
+ if (!empty($dp[Cache::SLIDING])) {
+ $meta[self::META_DELTA] = $expire; // sliding time
+ }
+ }
+
+ if (isset($dp[Cache::CALLBACKS])) {
+ $meta[self::META_CALLBACKS] = $dp[Cache::CALLBACKS];
+ }
+
+ if (isset($dp[Cache::TAGS]) || isset($dp[Cache::PRIORITY])) {
+ if (!$this->journal) {
+ throw new Nette\InvalidStateException('CacheJournal has not been provided.');
+ }
+ $this->journal->write($key, $dp);
+ }
+
+ $this->memcache->set($key, $meta, 0, $expire);
+ }
+
+
+ /**
+ * Removes item from the cache.
+ * @param string key
+ * @return void
+ */
+ public function remove($key)
+ {
+ $this->memcache->delete(urlencode($this->prefix . $key), 0);
+ }
+
+
+ /**
+ * Removes items from the cache by conditions & garbage collector.
+ * @param array conditions
+ * @return void
+ */
+ public function clean(array $conditions)
+ {
+ if (!empty($conditions[Cache::ALL])) {
+ $this->memcache->flush();
+
+ } elseif ($this->journal) {
+ foreach ($this->journal->clean($conditions) as $entry) {
+ $this->memcache->delete($entry, 0);
+ }
+ }
+ }
+
+}
diff --git a/vendor/nette/caching/src/Caching/Storages/MemoryStorage.php b/vendor/nette/caching/src/Caching/Storages/MemoryStorage.php
new file mode 100755
index 0000000..49b3323
--- /dev/null
+++ b/vendor/nette/caching/src/Caching/Storages/MemoryStorage.php
@@ -0,0 +1,79 @@
+data[$key]) ? $this->data[$key] : NULL;
+ }
+
+
+ /**
+ * Prevents item reading and writing. Lock is released by write() or remove().
+ * @param string key
+ * @return void
+ */
+ public function lock($key)
+ {
+ }
+
+
+ /**
+ * Writes item into the cache.
+ * @param string key
+ * @param mixed data
+ * @param array dependencies
+ * @return void
+ */
+ public function write($key, $data, array $dependencies)
+ {
+ $this->data[$key] = $data;
+ }
+
+
+ /**
+ * Removes item from the cache.
+ * @param string key
+ * @return void
+ */
+ public function remove($key)
+ {
+ unset($this->data[$key]);
+ }
+
+
+ /**
+ * Removes items from the cache by conditions & garbage collector.
+ * @param array conditions
+ * @return void
+ */
+ public function clean(array $conditions)
+ {
+ if (!empty($conditions[Nette\Caching\Cache::ALL])) {
+ $this->data = array();
+ }
+ }
+
+}
diff --git a/vendor/nette/caching/src/Caching/Storages/SQLiteStorage.php b/vendor/nette/caching/src/Caching/Storages/SQLiteStorage.php
new file mode 100755
index 0000000..a5e4bb7
--- /dev/null
+++ b/vendor/nette/caching/src/Caching/Storages/SQLiteStorage.php
@@ -0,0 +1,122 @@
+pdo = new \PDO('sqlite:' . $path, NULL, NULL, array(\PDO::ATTR_PERSISTENT => TRUE));
+ $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+ $this->pdo->exec('
+ PRAGMA foreign_keys = ON;
+ CREATE TABLE IF NOT EXISTS cache (
+ key BLOB NOT NULL PRIMARY KEY,
+ data BLOB NOT NULL
+ );
+ CREATE TABLE IF NOT EXISTS tags (
+ key BLOB NOT NULL REFERENCES cache ON DELETE CASCADE,
+ tag BLOB NOT NULL
+ );
+ CREATE INDEX IF NOT EXISTS tags_key ON tags(key);
+ CREATE INDEX IF NOT EXISTS tags_tag ON tags(tag);
+ ');
+ }
+
+
+ /**
+ * Read from cache.
+ * @param string key
+ * @return mixed|NULL
+ */
+ public function read($key)
+ {
+ $stmt = $this->pdo->prepare('SELECT data FROM cache WHERE key=?');
+ $stmt->execute(array($key));
+ if ($res = $stmt->fetchColumn()) {
+ return unserialize($res);
+ }
+ }
+
+
+ /**
+ * Prevents item reading and writing. Lock is released by write() or remove().
+ * @param string key
+ * @return void
+ */
+ public function lock($key)
+ {
+ }
+
+
+ /**
+ * Writes item into the cache.
+ * @param string key
+ * @param mixed data
+ * @param array dependencies
+ * @return void
+ */
+ public function write($key, $data, array $dependencies)
+ {
+ $this->pdo->exec('BEGIN TRANSACTION');
+ $this->pdo->prepare('REPLACE INTO cache (key, data) VALUES (?, ?)')
+ ->execute(array($key, serialize($data)));
+
+ if (!empty($dependencies[Cache::TAGS])) {
+ foreach ((array) $dependencies[Cache::TAGS] as $tag) {
+ $arr[] = $key;
+ $arr[] = $tag;
+ }
+ $this->pdo->prepare('INSERT INTO tags (key, tag) SELECT ?, ?' . str_repeat('UNION SELECT ?, ?', count($arr) / 2 - 1))
+ ->execute($arr);
+ }
+ $this->pdo->exec('COMMIT');
+ }
+
+
+ /**
+ * Removes item from the cache.
+ * @param string key
+ * @return void
+ */
+ public function remove($key)
+ {
+ $this->pdo->prepare('DELETE FROM cache WHERE key=?')
+ ->execute(array($key));
+ }
+
+
+ /**
+ * Removes items from the cache by conditions & garbage collector.
+ * @param array conditions
+ * @return void
+ */
+ public function clean(array $conditions)
+ {
+ if (!empty($conditions[Cache::ALL])) {
+ $this->pdo->prepare('DELETE FROM cache')->execute();
+
+ } elseif (!empty($conditions[Cache::TAGS])) {
+ $tags = (array) $conditions[Cache::TAGS];
+ $this->pdo->prepare('DELETE FROM cache WHERE key IN (SELECT key FROM tags WHERE tag IN (?'
+ . str_repeat(',?', count($tags) - 1) . '))')->execute($tags);
+ }
+ }
+
+}
diff --git a/vendor/nette/component-model/composer.json b/vendor/nette/component-model/composer.json
new file mode 100755
index 0000000..895c1e6
--- /dev/null
+++ b/vendor/nette/component-model/composer.json
@@ -0,0 +1,30 @@
+{
+ "name": "nette/component-model",
+ "description": "Nette Component Model",
+ "homepage": "http://nette.org",
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.1",
+ "nette/utils": "~2.2"
+ },
+ "require-dev": {
+ "nette/tester": "~1.3"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/component-model/license.md b/vendor/nette/component-model/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/component-model/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/component-model/src/ComponentModel/Component.php b/vendor/nette/component-model/src/ComponentModel/Component.php
new file mode 100755
index 0000000..b0faf93
--- /dev/null
+++ b/vendor/nette/component-model/src/ComponentModel/Component.php
@@ -0,0 +1,330 @@
+ [obj, depth, path, is_monitored?]] */
+ private $monitors = array();
+
+
+ public function __construct(IContainer $parent = NULL, $name = NULL)
+ {
+ if ($parent !== NULL) {
+ $parent->addComponent($this, $name);
+
+ } elseif (is_string($name)) {
+ $this->name = $name;
+ }
+ }
+
+
+ /**
+ * Lookup hierarchy for component specified by class or interface name.
+ * @param string class/interface type
+ * @param bool throw exception if component doesn't exist?
+ * @return IComponent
+ */
+ public function lookup($type, $need = TRUE)
+ {
+ if (!isset($this->monitors[$type])) { // not monitored or not processed yet
+ $obj = $this->parent;
+ $path = self::NAME_SEPARATOR . $this->name;
+ $depth = 1;
+ while ($obj !== NULL) {
+ $parent = $obj->getParent();
+ if ($type ? $obj instanceof $type : $parent === NULL) {
+ break;
+ }
+ $path = self::NAME_SEPARATOR . $obj->getName() . $path;
+ $depth++;
+ $obj = $parent; // IComponent::getParent()
+ if ($obj === $this) {
+ $obj = NULL; // prevent cycling
+ }
+ }
+
+ if ($obj) {
+ $this->monitors[$type] = array($obj, $depth, substr($path, 1), FALSE);
+
+ } else {
+ $this->monitors[$type] = array(NULL, NULL, NULL, FALSE); // not found
+ }
+ }
+
+ if ($need && $this->monitors[$type][0] === NULL) {
+ throw new Nette\InvalidStateException("Component '$this->name' is not attached to '$type'.");
+ }
+
+ return $this->monitors[$type][0];
+ }
+
+
+ /**
+ * Lookup for component specified by class or interface name. Returns backtrace path.
+ * A path is the concatenation of component names separated by self::NAME_SEPARATOR.
+ * @param string class/interface type
+ * @param bool throw exception if component doesn't exist?
+ * @return string
+ */
+ public function lookupPath($type = NULL, $need = TRUE)
+ {
+ $this->lookup($type, $need);
+ return $this->monitors[$type][2];
+ }
+
+
+ /**
+ * Starts monitoring.
+ * @param string class/interface type
+ * @return void
+ */
+ public function monitor($type)
+ {
+ if (empty($this->monitors[$type][3])) {
+ if ($obj = $this->lookup($type, FALSE)) {
+ $this->attached($obj);
+ }
+ $this->monitors[$type][3] = TRUE; // mark as monitored
+ }
+ }
+
+
+ /**
+ * Stops monitoring.
+ * @param string class/interface type
+ * @return void
+ */
+ public function unmonitor($type)
+ {
+ unset($this->monitors[$type]);
+ }
+
+
+ /**
+ * This method will be called when the component (or component's parent)
+ * becomes attached to a monitored object. Do not call this method yourself.
+ * @param IComponent
+ * @return void
+ */
+ protected function attached($obj)
+ {
+ }
+
+
+ /**
+ * This method will be called before the component (or component's parent)
+ * becomes detached from a monitored object. Do not call this method yourself.
+ * @param IComponent
+ * @return void
+ */
+ protected function detached($obj)
+ {
+ }
+
+
+ /********************* interface IComponent ****************d*g**/
+
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+
+ /**
+ * Returns the container if any.
+ * @return IContainer|NULL
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+
+
+ /**
+ * Sets the parent of this component. This method is managed by containers and should
+ * not be called by applications
+ * @param IContainer New parent or null if this component is being removed from a parent
+ * @param string
+ * @return self
+ * @throws Nette\InvalidStateException
+ * @internal
+ */
+ public function setParent(IContainer $parent = NULL, $name = NULL)
+ {
+ if ($parent === NULL && $this->parent === NULL && $name !== NULL) {
+ $this->name = $name; // just rename
+ return $this;
+
+ } elseif ($parent === $this->parent && $name === NULL) {
+ return $this; // nothing to do
+ }
+
+ // A component cannot be given a parent if it already has a parent.
+ if ($this->parent !== NULL && $parent !== NULL) {
+ throw new Nette\InvalidStateException("Component '$this->name' already has a parent.");
+ }
+
+ // remove from parent?
+ if ($parent === NULL) {
+ $this->refreshMonitors(0);
+ $this->parent = NULL;
+
+ } else { // add to parent
+ $this->validateParent($parent);
+ $this->parent = $parent;
+ if ($name !== NULL) {
+ $this->name = $name;
+ }
+
+ $tmp = array();
+ $this->refreshMonitors(0, $tmp);
+ }
+ return $this;
+ }
+
+
+ /**
+ * Is called by a component when it is about to be set new parent. Descendant can
+ * override this method to disallow a parent change by throwing an Nette\InvalidStateException
+ * @return void
+ * @throws Nette\InvalidStateException
+ */
+ protected function validateParent(IContainer $parent)
+ {
+ }
+
+
+ /**
+ * Refreshes monitors.
+ * @param int
+ * @param array|NULL (array = attaching, NULL = detaching)
+ * @param array
+ * @return void
+ */
+ private function refreshMonitors($depth, & $missing = NULL, & $listeners = array())
+ {
+ if ($this instanceof IContainer) {
+ foreach ($this->getComponents() as $component) {
+ if ($component instanceof self) {
+ $component->refreshMonitors($depth + 1, $missing, $listeners);
+ }
+ }
+ }
+
+ if ($missing === NULL) { // detaching
+ foreach ($this->monitors as $type => $rec) {
+ if (isset($rec[1]) && $rec[1] > $depth) {
+ if ($rec[3]) { // monitored
+ $this->monitors[$type] = array(NULL, NULL, NULL, TRUE);
+ $listeners[] = array($this, $rec[0]);
+ } else { // not monitored, just randomly cached
+ unset($this->monitors[$type]);
+ }
+ }
+ }
+
+ } else { // attaching
+ foreach ($this->monitors as $type => $rec) {
+ if (isset($rec[0])) { // is in cache yet
+ continue;
+
+ } elseif (!$rec[3]) { // not monitored, just randomly cached
+ unset($this->monitors[$type]);
+
+ } elseif (isset($missing[$type])) { // known from previous lookup
+ $this->monitors[$type] = array(NULL, NULL, NULL, TRUE);
+
+ } else {
+ $this->monitors[$type] = NULL; // forces re-lookup
+ if ($obj = $this->lookup($type, FALSE)) {
+ $listeners[] = array($this, $obj);
+ } else {
+ $missing[$type] = TRUE;
+ }
+ $this->monitors[$type][3] = TRUE; // mark as monitored
+ }
+ }
+ }
+
+ if ($depth === 0) { // call listeners
+ $method = $missing === NULL ? 'detached' : 'attached';
+ $prev = array();
+ foreach ($listeners as $item) {
+ if (!in_array($item, $prev, TRUE)) {
+ $item[0]->$method($item[1]);
+ $prev[] = $item;
+ }
+ }
+ }
+ }
+
+
+ /********************* cloneable, serializable ****************d*g**/
+
+
+ /**
+ * Object cloning.
+ */
+ public function __clone()
+ {
+ if ($this->parent === NULL) {
+ return;
+
+ } elseif ($this->parent instanceof Container) {
+ $this->parent = $this->parent->_isCloning();
+ if ($this->parent === NULL) { // not cloning
+ $this->refreshMonitors(0);
+ }
+
+ } else {
+ $this->parent = NULL;
+ $this->refreshMonitors(0);
+ }
+ }
+
+
+ /**
+ * Prevents serialization.
+ */
+ public function __sleep()
+ {
+ throw new Nette\NotImplementedException('Object serialization is not supported by class ' . get_class($this));
+ }
+
+
+ /**
+ * Prevents unserialization.
+ */
+ public function __wakeup()
+ {
+ throw new Nette\NotImplementedException('Object unserialization is not supported by class ' . get_class($this));
+ }
+
+}
diff --git a/vendor/nette/component-model/src/ComponentModel/Container.php b/vendor/nette/component-model/src/ComponentModel/Container.php
new file mode 100755
index 0000000..0ad2ecc
--- /dev/null
+++ b/vendor/nette/component-model/src/ComponentModel/Container.php
@@ -0,0 +1,250 @@
+getName();
+ }
+
+ if (is_int($name)) {
+ $name = (string) $name;
+
+ } elseif (!is_string($name)) {
+ throw new Nette\InvalidArgumentException(sprintf('Component name must be integer or string, %s given.', gettype($name)));
+
+ } elseif (!preg_match('#^[a-zA-Z0-9_]+\z#', $name)) {
+ throw new Nette\InvalidArgumentException("Component name must be non-empty alphanumeric string, '$name' given.");
+ }
+
+ if (isset($this->components[$name])) {
+ throw new Nette\InvalidStateException("Component with name '$name' already exists.");
+ }
+
+ // check circular reference
+ $obj = $this;
+ do {
+ if ($obj === $component) {
+ throw new Nette\InvalidStateException("Circular reference detected while adding component '$name'.");
+ }
+ $obj = $obj->getParent();
+ } while ($obj !== NULL);
+
+ // user checking
+ $this->validateChildComponent($component);
+
+ try {
+ if (isset($this->components[$insertBefore])) {
+ $tmp = array();
+ foreach ($this->components as $k => $v) {
+ if ($k === $insertBefore) {
+ $tmp[$name] = $component;
+ }
+ $tmp[$k] = $v;
+ }
+ $this->components = $tmp;
+ } else {
+ $this->components[$name] = $component;
+ }
+ $component->setParent($this, $name);
+
+ } catch (\Exception $e) {
+ unset($this->components[$name]); // undo
+ throw $e;
+ }
+ return $this;
+ }
+
+
+ /**
+ * Removes a component from the IContainer.
+ * @return void
+ */
+ public function removeComponent(IComponent $component)
+ {
+ $name = $component->getName();
+ if (!isset($this->components[$name]) || $this->components[$name] !== $component) {
+ throw new Nette\InvalidArgumentException("Component named '$name' is not located in this container.");
+ }
+
+ unset($this->components[$name]);
+ $component->setParent(NULL);
+ }
+
+
+ /**
+ * Returns component specified by name or path.
+ * @param string
+ * @param bool throw exception if component doesn't exist?
+ * @return IComponent|NULL
+ */
+ public function getComponent($name, $need = TRUE)
+ {
+ if (is_int($name)) {
+ $name = (string) $name;
+
+ } elseif (!is_string($name)) {
+ throw new Nette\InvalidArgumentException(sprintf('Component name must be integer or string, %s given.', gettype($name)));
+
+ } else {
+ $a = strpos($name, self::NAME_SEPARATOR);
+ if ($a !== FALSE) {
+ $ext = (string) substr($name, $a + 1);
+ $name = substr($name, 0, $a);
+ }
+
+ if ($name === '') {
+ if ($need) {
+ throw new Nette\InvalidArgumentException('Component or subcomponent name must not be empty string.');
+ }
+ return;
+ }
+ }
+
+ if (!isset($this->components[$name])) {
+ $component = $this->createComponent($name);
+ if ($component) {
+ if (!$component instanceof IComponent) {
+ throw new Nette\UnexpectedValueException('Method createComponent() did not return Nette\ComponentModel\IComponent.');
+
+ } elseif (!isset($this->components[$name])) {
+ $this->addComponent($component, $name);
+ }
+ }
+ }
+
+ if (isset($this->components[$name])) {
+ if (!isset($ext)) {
+ return $this->components[$name];
+
+ } elseif ($this->components[$name] instanceof IContainer) {
+ return $this->components[$name]->getComponent($ext, $need);
+
+ } elseif ($need) {
+ throw new Nette\InvalidArgumentException("Component with name '$name' is not container and cannot have '$ext' component.");
+ }
+
+ } elseif ($need) {
+ throw new Nette\InvalidArgumentException("Component with name '$name' does not exist.");
+ }
+ }
+
+
+ /**
+ * Component factory. Delegates the creation of components to a createComponent method.
+ * @param string component name
+ * @return IComponent the created component (optionally)
+ */
+ protected function createComponent($name)
+ {
+ $ucname = ucfirst($name);
+ $method = 'createComponent' . $ucname;
+ if ($ucname !== $name && method_exists($this, $method) && $this->getReflection()->getMethod($method)->getName() === $method) {
+ $component = $this->$method($name);
+ if (!$component instanceof IComponent && !isset($this->components[$name])) {
+ $class = get_class($this);
+ throw new Nette\UnexpectedValueException("Method $class::$method() did not return or create the desired component.");
+ }
+ return $component;
+ }
+ }
+
+
+ /**
+ * Iterates over components.
+ * @param bool recursive?
+ * @param string class types filter
+ * @return \ArrayIterator
+ */
+ public function getComponents($deep = FALSE, $filterType = NULL)
+ {
+ $iterator = new RecursiveComponentIterator($this->components);
+ if ($deep) {
+ $deep = $deep > 0 ? \RecursiveIteratorIterator::SELF_FIRST : \RecursiveIteratorIterator::CHILD_FIRST;
+ $iterator = new \RecursiveIteratorIterator($iterator, $deep);
+ }
+ if ($filterType) {
+ $class = PHP_VERSION_ID < 50400 ? 'Nette\Iterators\Filter' : 'CallbackFilterIterator';
+ $iterator = new $class($iterator, function ($item) use ($filterType) {
+ return $item instanceof $filterType;
+ });
+ }
+ return $iterator;
+ }
+
+
+ /**
+ * Descendant can override this method to disallow insert a child by throwing an Nette\InvalidStateException.
+ * @return void
+ * @throws Nette\InvalidStateException
+ */
+ protected function validateChildComponent(IComponent $child)
+ {
+ }
+
+
+ /********************* cloneable, serializable ****************d*g**/
+
+
+ /**
+ * Object cloning.
+ */
+ public function __clone()
+ {
+ if ($this->components) {
+ $oldMyself = reset($this->components)->getParent();
+ $oldMyself->cloning = $this;
+ foreach ($this->components as $name => $component) {
+ $this->components[$name] = clone $component;
+ }
+ $oldMyself->cloning = NULL;
+ }
+ parent::__clone();
+ }
+
+
+ /**
+ * Is container cloning now?
+ * @return NULL|IComponent
+ * @internal
+ */
+ public function _isCloning()
+ {
+ return $this->cloning;
+ }
+
+}
diff --git a/vendor/nette/component-model/src/ComponentModel/IComponent.php b/vendor/nette/component-model/src/ComponentModel/IComponent.php
new file mode 100755
index 0000000..2bafe1a
--- /dev/null
+++ b/vendor/nette/component-model/src/ComponentModel/IComponent.php
@@ -0,0 +1,38 @@
+current() instanceof IContainer;
+ }
+
+
+ /**
+ * The sub-iterator for the current element.
+ * @return \RecursiveIterator
+ */
+ public function getChildren()
+ {
+ return $this->current()->getComponents();
+ }
+
+
+ /**
+ * Returns the count of elements.
+ * @return int
+ */
+ public function count()
+ {
+ return iterator_count($this);
+ }
+
+}
diff --git a/vendor/nette/database/composer.json b/vendor/nette/database/composer.json
new file mode 100755
index 0000000..1c1649b
--- /dev/null
+++ b/vendor/nette/database/composer.json
@@ -0,0 +1,34 @@
+{
+ "name": "nette/database",
+ "description": "Nette Database Component",
+ "homepage": "http://nette.org",
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.1",
+ "ext-pdo": "*",
+ "nette/caching": "~2.2",
+ "nette/utils": "~2.2"
+ },
+ "require-dev": {
+ "nette/tester": "~1.3",
+ "nette/di": "~2.3",
+ "mockery/mockery": "~0.9.1"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/database/license.md b/vendor/nette/database/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/database/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/database/src/Bridges/DatabaseDI/DatabaseExtension.php b/vendor/nette/database/src/Bridges/DatabaseDI/DatabaseExtension.php
new file mode 100755
index 0000000..5a038d8
--- /dev/null
+++ b/vendor/nette/database/src/Bridges/DatabaseDI/DatabaseExtension.php
@@ -0,0 +1,126 @@
+ NULL,
+ 'user' => NULL,
+ 'password' => NULL,
+ 'options' => NULL,
+ 'debugger' => TRUE,
+ 'explain' => TRUE,
+ 'reflection' => NULL, // BC
+ 'conventions' => 'discovered', // Nette\Database\Conventions\DiscoveredConventions
+ 'autowired' => NULL,
+ );
+
+ /** @var bool */
+ private $debugMode;
+
+
+ public function __construct($debugMode = FALSE)
+ {
+ $this->debugMode = $debugMode;
+ }
+
+
+ public function loadConfiguration()
+ {
+ $configs = $this->getConfig();
+ if (isset($configs['dsn'])) {
+ $configs = array('default' => $configs);
+ }
+
+ $defaults = $this->databaseDefaults;
+ $defaults['autowired'] = TRUE;
+ foreach ((array) $configs as $name => $config) {
+ if (!is_array($config)) {
+ continue;
+ }
+ $config = $this->validateConfig($defaults, $config, $this->prefix($name));
+ $defaults['autowired'] = FALSE;
+ $this->setupDatabase($config, $name);
+ }
+ }
+
+
+ private function setupDatabase($config, $name)
+ {
+ $container = $this->getContainerBuilder();
+
+ foreach ((array) $config['options'] as $key => $value) {
+ if (preg_match('#^PDO::\w+\z#', $key)) {
+ unset($config['options'][$key]);
+ $config['options'][constant($key)] = $value;
+ }
+ }
+
+ $connection = $container->addDefinition($this->prefix("$name.connection"))
+ ->setClass('Nette\Database\Connection', array($config['dsn'], $config['user'], $config['password'], $config['options']))
+ ->setAutowired($config['autowired']);
+
+ $structure = $container->addDefinition($this->prefix("$name.structure"))
+ ->setClass('Nette\Database\Structure')
+ ->setArguments(array($connection))
+ ->setAutowired($config['autowired']);
+
+ if (!empty($config['reflection'])) {
+ $conventionsServiceName = 'reflection';
+ $config['conventions'] = $config['reflection'];
+ if (strtolower($config['conventions']) === 'conventional') {
+ $config['conventions'] = 'Static';
+ }
+ } else {
+ $conventionsServiceName = 'conventions';
+ }
+
+ if (!$config['conventions']) {
+ $conventions = NULL;
+
+ } elseif (is_string($config['conventions'])) {
+ $conventions = $container->addDefinition($this->prefix("$name.$conventionsServiceName"))
+ ->setClass(preg_match('#^[a-z]+\z#i', $config['conventions'])
+ ? 'Nette\Database\Conventions\\' . ucfirst($config['conventions']) . 'Conventions'
+ : $config['conventions'])
+ ->setArguments(strtolower($config['conventions']) === 'discovered' ? array($structure) : array())
+ ->setAutowired($config['autowired']);
+
+ } else {
+ $tmp = Nette\DI\Compiler::filterArguments(array($config['conventions']));
+ $conventions = reset($tmp);
+ }
+
+ $container->addDefinition($this->prefix("$name.context"))
+ ->setClass('Nette\Database\Context', array($connection, $structure, $conventions))
+ ->setAutowired($config['autowired']);
+
+ if ($config['debugger']) {
+ $connection->addSetup('@Tracy\BlueScreen::addPanel', array(
+ 'Nette\Bridges\DatabaseTracy\ConnectionPanel::renderException'
+ ));
+ if ($this->debugMode) {
+ $connection->addSetup('Nette\Database\Helpers::createDebugPanel', array($connection, !empty($config['explain']), $name));
+ }
+ }
+
+ if ($this->name === 'database') {
+ $container->addAlias($this->prefix($name), $this->prefix("$name.connection"));
+ $container->addAlias("nette.database.$name", $this->prefix($name));
+ $container->addAlias("nette.database.$name.context", $this->prefix("$name.context"));
+ }
+ }
+
+}
diff --git a/vendor/nette/database/src/Bridges/DatabaseTracy/ConnectionPanel.php b/vendor/nette/database/src/Bridges/DatabaseTracy/ConnectionPanel.php
new file mode 100755
index 0000000..1e90988
--- /dev/null
+++ b/vendor/nette/database/src/Bridges/DatabaseTracy/ConnectionPanel.php
@@ -0,0 +1,139 @@
+onQuery[] = array($this, 'logQuery');
+ }
+
+
+ public function logQuery(Nette\Database\Connection $connection, $result)
+ {
+ if ($this->disabled) {
+ return;
+ }
+ $this->count++;
+
+ $source = NULL;
+ $trace = $result instanceof \PDOException ? $result->getTrace() : debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE);
+ foreach ($trace as $row) {
+ if (isset($row['file']) && is_file($row['file']) && !Tracy\Debugger::getBluescreen()->isCollapsed($row['file'])) {
+ if ((isset($row['function']) && strpos($row['function'], 'call_user_func') === 0)
+ || (isset($row['class']) && is_subclass_of($row['class'], '\\Nette\\Database\\Connection'))
+ ) {
+ continue;
+ }
+ $source = array($row['file'], (int) $row['line']);
+ break;
+ }
+ }
+ if ($result instanceof Nette\Database\ResultSet) {
+ $this->totalTime += $result->getTime();
+ if ($this->count < $this->maxQueries) {
+ $this->queries[] = array($connection, $result->getQueryString(), $result->getParameters(), $source, $result->getTime(), $result->getRowCount(), NULL);
+ }
+
+ } elseif ($result instanceof \PDOException && $this->count < $this->maxQueries) {
+ $this->queries[] = array($connection, $result->queryString, NULL, $source, NULL, NULL, $result->getMessage());
+ }
+ }
+
+
+ public static function renderException($e)
+ {
+ if (!$e instanceof \PDOException) {
+ return;
+ }
+ if (isset($e->queryString)) {
+ $sql = $e->queryString;
+
+ } elseif ($item = Tracy\Helpers::findTrace($e->getTrace(), 'PDO::prepare')) {
+ $sql = $item['args'][0];
+ }
+ return isset($sql) ? array(
+ 'tab' => 'SQL',
+ 'panel' => Helpers::dumpSql($sql),
+ ) : NULL;
+ }
+
+
+ public function getTab()
+ {
+ $name = $this->name;
+ $count = $this->count;
+ $totalTime = $this->totalTime;
+ ob_start();
+ require __DIR__ . '/templates/ConnectionPanel.tab.phtml';
+ return ob_get_clean();
+ }
+
+
+ public function getPanel()
+ {
+ $this->disabled = TRUE;
+ if (!$this->count) {
+ return;
+ }
+
+ $name = $this->name;
+ $count = $this->count;
+ $totalTime = $this->totalTime;
+ $queries = array();
+ foreach ($this->queries as $query) {
+ list($connection, $sql, $params, $source, $time, $rows, $error) = $query;
+ $explain = NULL;
+ if (!$error && $this->explain && preg_match('#\s*\(?\s*SELECT\s#iA', $sql)) {
+ try {
+ $cmd = is_string($this->explain) ? $this->explain : 'EXPLAIN';
+ $explain = $connection->queryArgs("$cmd $sql", $params)->fetchAll();
+ } catch (\PDOException $e) {
+ }
+ }
+ $query[] = $explain;
+ $queries[] = $query;
+ }
+
+ ob_start();
+ require __DIR__ . '/templates/ConnectionPanel.panel.phtml';
+ return ob_get_clean();
+ }
+
+}
diff --git a/vendor/nette/database/src/Bridges/DatabaseTracy/templates/ConnectionPanel.panel.phtml b/vendor/nette/database/src/Bridges/DatabaseTracy/templates/ConnectionPanel.panel.phtml
new file mode 100755
index 0000000..dad25c7
--- /dev/null
+++ b/vendor/nette/database/src/Bridges/DatabaseTracy/templates/ConnectionPanel.panel.phtml
@@ -0,0 +1,58 @@
+
+
+
+Queries:
+
+
+
+ Time ms SQL Query Rows
+
+
+
+
+ ERROR
+
+
+ explain
+
+
+
+
+
+
+ $foo): ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
...and more
+
diff --git a/vendor/nette/database/src/Bridges/DatabaseTracy/templates/ConnectionPanel.tab.phtml b/vendor/nette/database/src/Bridges/DatabaseTracy/templates/ConnectionPanel.tab.phtml
new file mode 100755
index 0000000..9781b57
--- /dev/null
+++ b/vendor/nette/database/src/Bridges/DatabaseTracy/templates/ConnectionPanel.tab.phtml
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/vendor/nette/database/src/Database/Connection.php b/vendor/nette/database/src/Database/Connection.php
new file mode 100755
index 0000000..e44fa4c
--- /dev/null
+++ b/vendor/nette/database/src/Database/Connection.php
@@ -0,0 +1,281 @@
+ 4) { // compatibility
+ $options['driverClass'] = func_get_arg(4);
+ }
+ $this->params = array($dsn, $user, $password);
+ $this->options = (array) $options;
+
+ if (empty($options['lazy'])) {
+ $this->connect();
+ }
+ }
+
+
+ /** @return void */
+ public function connect()
+ {
+ if ($this->pdo) {
+ return;
+ }
+
+ try {
+ $this->pdo = new PDO($this->params[0], $this->params[1], $this->params[2], $this->options);
+ $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ } catch (PDOException $e) {
+ throw ConnectionException::from($e);
+ }
+
+ $class = empty($this->options['driverClass'])
+ ? 'Nette\Database\Drivers\\' . ucfirst(str_replace('sql', 'Sql', $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME))) . 'Driver'
+ : $this->options['driverClass'];
+ $this->driver = new $class($this, $this->options);
+ $this->preprocessor = new SqlPreprocessor($this);
+ $this->onConnect($this);
+ }
+
+
+ /** @return void */
+ public function reconnect()
+ {
+ $this->disconnect();
+ $this->connect();
+ }
+
+
+ /** @return void */
+ public function disconnect()
+ {
+ $this->pdo = NULL;
+ }
+
+
+ /** @return string */
+ public function getDsn()
+ {
+ return $this->params[0];
+ }
+
+
+ /** @return PDO */
+ public function getPdo()
+ {
+ $this->connect();
+ return $this->pdo;
+ }
+
+
+ /** @return ISupplementalDriver */
+ public function getSupplementalDriver()
+ {
+ $this->connect();
+ return $this->driver;
+ }
+
+
+ /**
+ * @param string sequence object
+ * @return string
+ */
+ public function getInsertId($name = NULL)
+ {
+ try {
+ return $this->getPdo()->lastInsertId($name);
+ } catch (PDOException $e) {
+ throw $this->driver->convertException($e);
+ }
+ }
+
+
+ /**
+ * @param string string to be quoted
+ * @param int data type hint
+ * @return string
+ */
+ public function quote($string, $type = PDO::PARAM_STR)
+ {
+ try {
+ return $this->getPdo()->quote($string, $type);
+ } catch (PDOException $e) {
+ throw DriverException::from($e);
+ }
+ }
+
+
+ /** @return void */
+ function beginTransaction()
+ {
+ $this->query('::beginTransaction');
+ }
+
+
+ /** @return void */
+ function commit()
+ {
+ $this->query('::commit');
+ }
+
+
+ /** @return void */
+ public function rollBack()
+ {
+ $this->query('::rollBack');
+ }
+
+
+ /**
+ * Generates and executes SQL query.
+ * @param string statement
+ * @param mixed [parameters, ...]
+ * @return ResultSet
+ */
+ public function query($statement)
+ {
+ $this->connect();
+
+ $args = is_array($statement) ? $statement : func_get_args(); // accepts arrays only internally
+ list($statement, $params) = count($args) > 1
+ ? $this->preprocessor->process($args)
+ : array($args[0], array());
+
+ try {
+ $result = new ResultSet($this, $statement, $params);
+ } catch (PDOException $e) {
+ $this->onQuery($this, $e);
+ throw $e;
+ }
+ $this->onQuery($this, $result);
+ return $result;
+ }
+
+
+ /**
+ * @param string statement
+ * @param array
+ * @return ResultSet
+ */
+ public function queryArgs($statement, array $params)
+ {
+ array_unshift($params, $statement);
+ return $this->query($params);
+ }
+
+
+ /**
+ * @return [string, array]
+ */
+ public function preprocess($statement)
+ {
+ $this->connect();
+ return func_num_args() > 1
+ ? $this->preprocessor->process(func_get_args())
+ : array($statement, array());
+ }
+
+
+ /********************* shortcuts ****************d*g**/
+
+
+ /**
+ * Shortcut for query()->fetch()
+ * @param string statement
+ * @param mixed [parameters, ...]
+ * @return Row
+ */
+ public function fetch($args)
+ {
+ return $this->query(func_get_args())->fetch();
+ }
+
+
+ /**
+ * Shortcut for query()->fetchField()
+ * @param string statement
+ * @param mixed [parameters, ...]
+ * @return mixed
+ */
+ public function fetchField($args)
+ {
+ return $this->query(func_get_args())->fetchField();
+ }
+
+
+ /**
+ * Shortcut for query()->fetchPairs()
+ * @param string statement
+ * @param mixed [parameters, ...]
+ * @return array
+ */
+ public function fetchPairs($args)
+ {
+ return $this->query(func_get_args())->fetchPairs();
+ }
+
+
+ /**
+ * Shortcut for query()->fetchAll()
+ * @param string statement
+ * @param mixed [parameters, ...]
+ * @return array
+ */
+ public function fetchAll($args)
+ {
+ return $this->query(func_get_args())->fetchAll();
+ }
+
+
+ /**
+ * @return SqlLiteral
+ */
+ public static function literal($value)
+ {
+ $args = func_get_args();
+ return new SqlLiteral(array_shift($args), $args);
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Context.php b/vendor/nette/database/src/Database/Context.php
new file mode 100755
index 0000000..e4498bd
--- /dev/null
+++ b/vendor/nette/database/src/Database/Context.php
@@ -0,0 +1,194 @@
+connection = $connection;
+ $this->structure = $structure;
+ $this->conventions = $conventions ?: new StaticConventions;
+ $this->cacheStorage = $cacheStorage;
+ }
+
+
+ /** @return void */
+ public function beginTransaction()
+ {
+ $this->connection->beginTransaction();
+ }
+
+
+ /** @return void */
+ public function commit()
+ {
+ $this->connection->commit();
+ }
+
+
+ /** @return void */
+ public function rollBack()
+ {
+ $this->connection->rollBack();
+ }
+
+
+ /**
+ * @param string sequence object
+ * @return string
+ */
+ public function getInsertId($name = NULL)
+ {
+ return $this->connection->getInsertId($name);
+ }
+
+
+ /**
+ * Generates and executes SQL query.
+ * @param string statement
+ * @param mixed [parameters, ...]
+ * @return ResultSet
+ */
+ public function query($statement)
+ {
+ return $this->connection->query(func_get_args());
+ }
+
+
+ /**
+ * @param string statement
+ * @param array
+ * @return ResultSet
+ */
+ public function queryArgs($statement, array $params)
+ {
+ return $this->connection->queryArgs($statement, $params);
+ }
+
+
+ /**
+ * @param string
+ * @return Table\Selection
+ */
+ public function table($table)
+ {
+ return new Table\Selection($this, $this->conventions, $table, $this->cacheStorage);
+ }
+
+
+ /** @return Connection */
+ public function getConnection()
+ {
+ return $this->connection;
+ }
+
+
+ /** @return IStructure */
+ public function getStructure()
+ {
+ return $this->structure;
+ }
+
+
+ /** @return IConventions */
+ public function getConventions()
+ {
+ return $this->conventions;
+ }
+
+
+ /** @deprecated */
+ public function getDatabaseReflection()
+ {
+ trigger_error(__METHOD__ . '() is deprecated; use getConventions() instead.', E_USER_DEPRECATED);
+ return $this->conventions;
+ }
+
+
+ /********************* shortcuts ****************d*g**/
+
+
+ /**
+ * Shortcut for query()->fetch()
+ * @param string statement
+ * @param mixed [parameters, ...]
+ * @return Row
+ */
+ public function fetch($args)
+ {
+ return $this->connection->query(func_get_args())->fetch();
+ }
+
+
+ /**
+ * Shortcut for query()->fetchField()
+ * @param string statement
+ * @param mixed [parameters, ...]
+ * @return mixed
+ */
+ public function fetchField($args)
+ {
+ return $this->connection->query(func_get_args())->fetchField();
+ }
+
+
+ /**
+ * Shortcut for query()->fetchPairs()
+ * @param string statement
+ * @param mixed [parameters, ...]
+ * @return array
+ */
+ public function fetchPairs($args)
+ {
+ return $this->connection->query(func_get_args())->fetchPairs();
+ }
+
+
+ /**
+ * Shortcut for query()->fetchAll()
+ * @param string statement
+ * @param mixed [parameters, ...]
+ * @return array
+ */
+ public function fetchAll($args)
+ {
+ return $this->connection->query(func_get_args())->fetchAll();
+ }
+
+
+ /**
+ * @return SqlLiteral
+ */
+ public static function literal($value)
+ {
+ $args = func_get_args();
+ return new SqlLiteral(array_shift($args), $args);
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Conventions/DiscoveredConventions.php b/vendor/nette/database/src/Database/Conventions/DiscoveredConventions.php
new file mode 100755
index 0000000..112d8bc
--- /dev/null
+++ b/vendor/nette/database/src/Database/Conventions/DiscoveredConventions.php
@@ -0,0 +1,102 @@
+structure = $structure;
+ }
+
+
+ public function getPrimary($table)
+ {
+ return $this->structure->getPrimaryKey($table);
+ }
+
+
+ public function getHasManyReference($nsTable, $key)
+ {
+ $candidates = $columnCandidates = array();
+ $targets = $this->structure->getHasManyReference($nsTable);
+ $table = preg_replace('#^(.*\.)?(.*)$#', '$2', $nsTable);
+
+ foreach ($targets as $targetNsTable => $targetColumns) {
+ $targetTable = preg_replace('#^(.*\.)?(.*)$#', '$2', $targetNsTable);
+ if (stripos($targetNsTable, $key) === FALSE) {
+ continue;
+ }
+
+ foreach ($targetColumns as $targetColumn) {
+ if (stripos($targetColumn, $table) !== FALSE) {
+ $columnCandidates[] = $candidate = array($targetNsTable, $targetColumn);
+ if (strcmp($targetTable, $key) === 0 || strcmp($targetNsTable, $key) === 0) {
+ return $candidate;
+ }
+ }
+
+ $candidates[] = array($targetTable, array($targetNsTable, $targetColumn));
+ }
+ }
+
+ if (count($columnCandidates) === 1) {
+ return $columnCandidates[0];
+ } elseif (count($candidates) === 1) {
+ return $candidates[0][1];
+ }
+
+ foreach ($candidates as $candidate) {
+ if (strtolower($candidate[0]) === strtolower($key)) {
+ return $candidate[1];
+ }
+ }
+
+ if (!empty($candidates)) {
+ throw new AmbiguousReferenceKeyException('Ambiguous joining column in related call.');
+ }
+
+ if ($this->structure->isRebuilt()) {
+ return NULL;
+ }
+
+ $this->structure->rebuild();
+ return $this->getHasManyReference($nsTable, $key);
+ }
+
+
+ public function getBelongsToReference($table, $key)
+ {
+ $tableColumns = $this->structure->getBelongsToReference($table);
+
+ foreach ($tableColumns as $column => $targetTable) {
+ if (stripos($column, $key) !== FALSE) {
+ return array($targetTable, $column);
+ }
+ }
+
+ if ($this->structure->isRebuilt()) {
+ return NULL;
+ }
+
+ $this->structure->rebuild();
+ return $this->getBelongsToReference($table, $key);
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Conventions/StaticConventions.php b/vendor/nette/database/src/Database/Conventions/StaticConventions.php
new file mode 100755
index 0000000..14ecbe4
--- /dev/null
+++ b/vendor/nette/database/src/Database/Conventions/StaticConventions.php
@@ -0,0 +1,78 @@
+, %2$s for table name
+ * @param string %1$s stands for key used after ->, %2$s for table name
+ */
+ public function __construct($primary = 'id', $foreign = '%s_id', $table = '%s')
+ {
+ $this->primary = $primary;
+ $this->foreign = $foreign;
+ $this->table = $table;
+ }
+
+
+ public function getPrimary($table)
+ {
+ return sprintf($this->primary, $this->getColumnFromTable($table));
+ }
+
+
+ public function getHasManyReference($table, $key)
+ {
+ $table = $this->getColumnFromTable($table);
+ return array(
+ sprintf($this->table, $key, $table),
+ sprintf($this->foreign, $table, $key),
+ );
+ }
+
+
+ public function getBelongsToReference($table, $key)
+ {
+ $table = $this->getColumnFromTable($table);
+ return array(
+ sprintf($this->table, $key, $table),
+ sprintf($this->foreign, $key, $table),
+ );
+ }
+
+
+ protected function getColumnFromTable($name)
+ {
+ if ($this->table !== '%s' && preg_match('(^' . str_replace('%s', '(.*)', preg_quote($this->table)) . '\z)', $name, $match)) {
+ return $match[1];
+ }
+
+ return $name;
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Conventions/exceptions.php b/vendor/nette/database/src/Database/Conventions/exceptions.php
new file mode 100755
index 0000000..fdc6e02
--- /dev/null
+++ b/vendor/nette/database/src/Database/Conventions/exceptions.php
@@ -0,0 +1,16 @@
+message, NULL, $src);
+ if (!$src->errorInfo && preg_match('#SQLSTATE\[(.*?)\] \[(.*?)\] (.*)#A', $src->message, $m)) {
+ $m[2] = (int) $m[2];
+ $e->errorInfo = array_slice($m, 1);
+ $e->code = $m[1];
+ } else {
+ $e->errorInfo = $src->errorInfo;
+ $e->code = $src->code;
+ }
+ return $e;
+ }
+
+
+ /**
+ * @returns int|string|NULL Driver-specific error code
+ */
+ public function getDriverCode()
+ {
+ return isset($this->errorInfo[1]) ? $this->errorInfo[1] : NULL;
+ }
+
+
+ /**
+ * @returns string|NULL SQLSTATE error code
+ */
+ public function getSqlState()
+ {
+ return isset($this->errorInfo[0]) ? $this->errorInfo[0] : NULL;
+ }
+
+
+ /**
+ * @returns string|NULL SQL command
+ */
+ public function getQueryString()
+ {
+ return $this->queryString;
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Drivers/MsSqlDriver.php b/vendor/nette/database/src/Database/Drivers/MsSqlDriver.php
new file mode 100755
index 0000000..61bef98
--- /dev/null
+++ b/vendor/nette/database/src/Database/Drivers/MsSqlDriver.php
@@ -0,0 +1,159 @@
+format("'Y-m-d H:i:s'");
+ }
+
+
+ /**
+ * Formats date-time interval for use in a SQL statement.
+ */
+ public function formatDateInterval(\DateInterval $value)
+ {
+ throw new Nette\NotSupportedException;
+ }
+
+
+ /**
+ * Encodes string for use in a LIKE statement.
+ */
+ public function formatLike($value, $pos)
+ {
+ $value = strtr($value, array("'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]'));
+ return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
+ }
+
+
+ /**
+ * Injects LIMIT/OFFSET to the SQL query.
+ */
+ public function applyLimit(& $sql, $limit, $offset)
+ {
+ if ($limit >= 0) {
+ $sql = preg_replace('#^\s*(SELECT|UPDATE|DELETE)#i', '$0 TOP ' . (int) $limit, $sql, 1, $count);
+ if (!$count) {
+ throw new Nette\InvalidArgumentException('SQL query must begin with SELECT, UPDATE or DELETE command.');
+ }
+ }
+
+ if ($offset) {
+ throw new Nette\NotSupportedException('Offset is not supported by this database.');
+ }
+ }
+
+
+ /**
+ * Normalizes result row.
+ */
+ public function normalizeRow($row)
+ {
+ return $row;
+ }
+
+
+ /********************* reflection ****************d*g**/
+
+
+ /**
+ * Returns list of tables.
+ */
+ public function getTables()
+ {
+ throw new Nette\NotImplementedException;
+ }
+
+
+ /**
+ * Returns metadata for all columns in a table.
+ */
+ public function getColumns($table)
+ {
+ throw new Nette\NotImplementedException;
+ }
+
+
+ /**
+ * Returns metadata for all indexes in a table.
+ */
+ public function getIndexes($table)
+ {
+ throw new Nette\NotImplementedException;
+ }
+
+
+ /**
+ * Returns metadata for all foreign keys in a table.
+ */
+ public function getForeignKeys($table)
+ {
+ throw new Nette\NotImplementedException;
+ }
+
+
+ /**
+ * Returns associative array of detected types (IReflection::FIELD_*) in result set.
+ */
+ public function getColumnTypes(\PDOStatement $statement)
+ {
+ return Nette\Database\Helpers::detectTypes($statement);
+ }
+
+
+ /**
+ * @param string
+ * @return bool
+ */
+ public function isSupported($item)
+ {
+ return $item === self::SUPPORT_SUBSELECT;
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Drivers/MySqlDriver.php b/vendor/nette/database/src/Database/Drivers/MySqlDriver.php
new file mode 100755
index 0000000..9921ea8
--- /dev/null
+++ b/vendor/nette/database/src/Database/Drivers/MySqlDriver.php
@@ -0,0 +1,255 @@
+ character encoding to set (default is utf8 or utf8mb4 since MySQL 5.5.3)
+ * - sqlmode => see http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html
+ */
+ public function __construct(Nette\Database\Connection $connection, array $options)
+ {
+ $this->connection = $connection;
+ $charset = isset($options['charset'])
+ ? $options['charset']
+ : (version_compare($connection->getPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION), '5.5.3', '>=') ? 'utf8mb4' : 'utf8');
+ if ($charset) {
+ $connection->query("SET NAMES '$charset'");
+ }
+ if (isset($options['sqlmode'])) {
+ $connection->query("SET sql_mode='$options[sqlmode]'");
+ }
+ }
+
+
+ /**
+ * @return Nette\Database\DriverException
+ */
+ public function convertException(\PDOException $e)
+ {
+ $code = isset($e->errorInfo[1]) ? $e->errorInfo[1] : NULL;
+ if (in_array($code, array(1216, 1217, 1451, 1452, 1701), TRUE)) {
+ return Nette\Database\ForeignKeyConstraintViolationException::from($e);
+
+ } elseif (in_array($code, array(1062, 1557, 1569, 1586), TRUE)) {
+ return Nette\Database\UniqueConstraintViolationException::from($e);
+
+ } elseif ($code >= 2001 && $code <= 2028) {
+ return Nette\Database\ConnectionException::from($e);
+
+ } elseif (in_array($code, array(1048, 1121, 1138, 1171, 1252, 1263, 1566), TRUE)) {
+ return Nette\Database\NotNullConstraintViolationException::from($e);
+
+ } else {
+ return Nette\Database\DriverException::from($e);
+ }
+ }
+
+
+ /********************* SQL ****************d*g**/
+
+
+ /**
+ * Delimites identifier for use in a SQL statement.
+ */
+ public function delimite($name)
+ {
+ // @see http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
+ return '`' . str_replace('`', '``', $name) . '`';
+ }
+
+
+ /**
+ * Formats boolean for use in a SQL statement.
+ */
+ public function formatBool($value)
+ {
+ return $value ? '1' : '0';
+ }
+
+
+ /**
+ * Formats date-time for use in a SQL statement.
+ */
+ public function formatDateTime(/*\DateTimeInterface*/ $value)
+ {
+ return $value->format("'Y-m-d H:i:s'");
+ }
+
+
+ /**
+ * Formats date-time interval for use in a SQL statement.
+ */
+ public function formatDateInterval(\DateInterval $value)
+ {
+ return $value->format("'%r%h:%I:%S'");
+ }
+
+
+ /**
+ * Encodes string for use in a LIKE statement.
+ */
+ public function formatLike($value, $pos)
+ {
+ $value = addcslashes(str_replace('\\', '\\\\', $value), "\x00\n\r\\'%_");
+ return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
+ }
+
+
+ /**
+ * Injects LIMIT/OFFSET to the SQL query.
+ */
+ public function applyLimit(& $sql, $limit, $offset)
+ {
+ if ($limit >= 0 || $offset > 0) {
+ // see http://dev.mysql.com/doc/refman/5.0/en/select.html
+ $sql .= ' LIMIT ' . ($limit < 0 ? '18446744073709551615' : (int) $limit)
+ . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
+ }
+ }
+
+
+ /**
+ * Normalizes result row.
+ */
+ public function normalizeRow($row)
+ {
+ return $row;
+ }
+
+
+ /********************* reflection ****************d*g**/
+
+
+ /**
+ * Returns list of tables.
+ */
+ public function getTables()
+ {
+ $tables = array();
+ foreach ($this->connection->query('SHOW FULL TABLES') as $row) {
+ $tables[] = array(
+ 'name' => $row[0],
+ 'view' => isset($row[1]) && $row[1] === 'VIEW',
+ );
+ }
+ return $tables;
+ }
+
+
+ /**
+ * Returns metadata for all columns in a table.
+ */
+ public function getColumns($table)
+ {
+ $columns = array();
+ foreach ($this->connection->query('SHOW FULL COLUMNS FROM ' . $this->delimite($table)) as $row) {
+ $type = explode('(', $row['Type']);
+ $columns[] = array(
+ 'name' => $row['Field'],
+ 'table' => $table,
+ 'nativetype' => strtoupper($type[0]),
+ 'size' => isset($type[1]) ? (int) $type[1] : NULL,
+ 'unsigned' => (bool) strstr($row['Type'], 'unsigned'),
+ 'nullable' => $row['Null'] === 'YES',
+ 'default' => $row['Default'],
+ 'autoincrement' => $row['Extra'] === 'auto_increment',
+ 'primary' => $row['Key'] === 'PRI',
+ 'vendor' => (array) $row,
+ );
+ }
+ return $columns;
+ }
+
+
+ /**
+ * Returns metadata for all indexes in a table.
+ */
+ public function getIndexes($table)
+ {
+ $indexes = array();
+ foreach ($this->connection->query('SHOW INDEX FROM ' . $this->delimite($table)) as $row) {
+ $indexes[$row['Key_name']]['name'] = $row['Key_name'];
+ $indexes[$row['Key_name']]['unique'] = !$row['Non_unique'];
+ $indexes[$row['Key_name']]['primary'] = $row['Key_name'] === 'PRIMARY';
+ $indexes[$row['Key_name']]['columns'][$row['Seq_in_index'] - 1] = $row['Column_name'];
+ }
+ return array_values($indexes);
+ }
+
+
+ /**
+ * Returns metadata for all foreign keys in a table.
+ */
+ public function getForeignKeys($table)
+ {
+ $keys = array();
+ $query = 'SELECT CONSTRAINT_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE '
+ . 'WHERE TABLE_SCHEMA = DATABASE() AND REFERENCED_TABLE_NAME IS NOT NULL AND TABLE_NAME = ' . $this->connection->quote($table);
+
+ foreach ($this->connection->query($query) as $id => $row) {
+ $keys[$id]['name'] = $row['CONSTRAINT_NAME']; // foreign key name
+ $keys[$id]['local'] = $row['COLUMN_NAME']; // local columns
+ $keys[$id]['table'] = $row['REFERENCED_TABLE_NAME']; // referenced table
+ $keys[$id]['foreign'] = $row['REFERENCED_COLUMN_NAME']; // referenced columns
+ }
+
+ return array_values($keys);
+ }
+
+
+ /**
+ * Returns associative array of detected types (IReflection::FIELD_*) in result set.
+ */
+ public function getColumnTypes(\PDOStatement $statement)
+ {
+ $types = array();
+ $count = $statement->columnCount();
+ for ($col = 0; $col < $count; $col++) {
+ $meta = $statement->getColumnMeta($col);
+ if (isset($meta['native_type'])) {
+ $types[$meta['name']] = $type = Nette\Database\Helpers::detectType($meta['native_type']);
+ if ($type === Nette\Database\IStructure::FIELD_TIME) {
+ $types[$meta['name']] = Nette\Database\IStructure::FIELD_TIME_INTERVAL;
+ }
+ }
+ }
+ return $types;
+ }
+
+
+ /**
+ * @param string
+ * @return bool
+ */
+ public function isSupported($item)
+ {
+ // MULTI_COLUMN_AS_OR_COND due to mysql bugs:
+ // - http://bugs.mysql.com/bug.php?id=31188
+ // - http://bugs.mysql.com/bug.php?id=35819
+ // and more.
+ return $item === self::SUPPORT_SELECT_UNGROUPED_COLUMNS || $item === self::SUPPORT_MULTI_COLUMN_AS_OR_COND;
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Drivers/OciDriver.php b/vendor/nette/database/src/Database/Drivers/OciDriver.php
new file mode 100755
index 0000000..38f880a
--- /dev/null
+++ b/vendor/nette/database/src/Database/Drivers/OciDriver.php
@@ -0,0 +1,191 @@
+connection = $connection;
+ $this->fmtDateTime = isset($options['formatDateTime']) ? $options['formatDateTime'] : 'U';
+ }
+
+
+ public function convertException(\PDOException $e)
+ {
+ $code = isset($e->errorInfo[1]) ? $e->errorInfo[1] : NULL;
+ if (in_array($code, array(1, 2299, 38911), TRUE)) {
+ return Nette\Database\UniqueConstraintViolationException::from($e);
+
+ } elseif (in_array($code, array(1400), TRUE)) {
+ return Nette\Database\NotNullConstraintViolationException::from($e);
+
+ } elseif (in_array($code, array(2266, 2291, 2292), TRUE)) {
+ return Nette\Database\ForeignKeyConstraintViolationException::from($e);
+
+ } else {
+ return Nette\Database\DriverException::from($e);
+ }
+ }
+
+
+ /********************* SQL ****************d*g**/
+
+
+ /**
+ * Delimites identifier for use in a SQL statement.
+ */
+ public function delimite($name)
+ {
+ // @see http://download.oracle.com/docs/cd/B10500_01/server.920/a96540/sql_elements9a.htm
+ return '"' . str_replace('"', '""', $name) . '"';
+ }
+
+
+ /**
+ * Formats boolean for use in a SQL statement.
+ */
+ public function formatBool($value)
+ {
+ return $value ? '1' : '0';
+ }
+
+
+ /**
+ * Formats date-time for use in a SQL statement.
+ */
+ public function formatDateTime(/*\DateTimeInterface*/ $value)
+ {
+ return $value->format($this->fmtDateTime);
+ }
+
+
+ /**
+ * Formats date-time interval for use in a SQL statement.
+ */
+ public function formatDateInterval(\DateInterval $value)
+ {
+ throw new Nette\NotSupportedException;
+ }
+
+
+ /**
+ * Encodes string for use in a LIKE statement.
+ */
+ public function formatLike($value, $pos)
+ {
+ throw new Nette\NotImplementedException;
+ }
+
+
+ /**
+ * Injects LIMIT/OFFSET to the SQL query.
+ */
+ public function applyLimit(& $sql, $limit, $offset)
+ {
+ if ($offset > 0) {
+ // see http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
+ $sql = 'SELECT * FROM (SELECT t.*, ROWNUM AS "__rnum" FROM (' . $sql . ') t '
+ . ($limit >= 0 ? 'WHERE ROWNUM <= ' . ((int) $offset + (int) $limit) : '')
+ . ') WHERE "__rnum" > '. (int) $offset;
+
+ } elseif ($limit >= 0) {
+ $sql = 'SELECT * FROM (' . $sql . ') WHERE ROWNUM <= ' . (int) $limit;
+ }
+ }
+
+
+ /**
+ * Normalizes result row.
+ */
+ public function normalizeRow($row)
+ {
+ return $row;
+ }
+
+
+ /********************* reflection ****************d*g**/
+
+
+ /**
+ * Returns list of tables.
+ */
+ public function getTables()
+ {
+ $tables = array();
+ foreach ($this->connection->query('SELECT * FROM cat') as $row) {
+ if ($row[1] === 'TABLE' || $row[1] === 'VIEW') {
+ $tables[] = array(
+ 'name' => $row[0],
+ 'view' => $row[1] === 'VIEW',
+ );
+ }
+ }
+ return $tables;
+ }
+
+
+ /**
+ * Returns metadata for all columns in a table.
+ */
+ public function getColumns($table)
+ {
+ throw new Nette\NotImplementedException;
+ }
+
+
+ /**
+ * Returns metadata for all indexes in a table.
+ */
+ public function getIndexes($table)
+ {
+ throw new Nette\NotImplementedException;
+ }
+
+
+ /**
+ * Returns metadata for all foreign keys in a table.
+ */
+ public function getForeignKeys($table)
+ {
+ throw new Nette\NotImplementedException;
+ }
+
+
+ /**
+ * Returns associative array of detected types (IReflection::FIELD_*) in result set.
+ */
+ public function getColumnTypes(\PDOStatement $statement)
+ {
+ return Nette\Database\Helpers::detectTypes($statement);
+ }
+
+
+ /**
+ * @param string
+ * @return bool
+ */
+ public function isSupported($item)
+ {
+ return $item === self::SUPPORT_SEQUENCE || $item === self::SUPPORT_SUBSELECT;
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Drivers/OdbcDriver.php b/vendor/nette/database/src/Database/Drivers/OdbcDriver.php
new file mode 100755
index 0000000..903da51
--- /dev/null
+++ b/vendor/nette/database/src/Database/Drivers/OdbcDriver.php
@@ -0,0 +1,158 @@
+format('#m/d/Y H:i:s#');
+ }
+
+
+ /**
+ * Formats date-time interval for use in a SQL statement.
+ */
+ public function formatDateInterval(\DateInterval $value)
+ {
+ throw new Nette\NotSupportedException;
+ }
+
+
+ /**
+ * Encodes string for use in a LIKE statement.
+ */
+ public function formatLike($value, $pos)
+ {
+ $value = strtr($value, array("'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]'));
+ return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
+ }
+
+
+ /**
+ * Injects LIMIT/OFFSET to the SQL query.
+ */
+ public function applyLimit(& $sql, $limit, $offset)
+ {
+ if ($limit >= 0) {
+ $sql = preg_replace('#^\s*(SELECT|UPDATE|DELETE)#i', '$0 TOP ' . (int) $limit, $sql, 1, $count);
+ if (!$count) {
+ throw new Nette\InvalidArgumentException('SQL query must begin with SELECT, UPDATE or DELETE command.');
+ }
+ }
+
+ if ($offset) {
+ throw new Nette\NotSupportedException('Offset is not supported by this database.');
+ }
+ }
+
+
+ /**
+ * Normalizes result row.
+ */
+ public function normalizeRow($row)
+ {
+ return $row;
+ }
+
+
+ /********************* reflection ****************d*g**/
+
+
+ /**
+ * Returns list of tables.
+ */
+ public function getTables()
+ {
+ throw new Nette\NotImplementedException;
+ }
+
+
+ /**
+ * Returns metadata for all columns in a table.
+ */
+ public function getColumns($table)
+ {
+ throw new Nette\NotImplementedException;
+ }
+
+
+ /**
+ * Returns metadata for all indexes in a table.
+ */
+ public function getIndexes($table)
+ {
+ throw new Nette\NotImplementedException;
+ }
+
+
+ /**
+ * Returns metadata for all foreign keys in a table.
+ */
+ public function getForeignKeys($table)
+ {
+ throw new Nette\NotImplementedException;
+ }
+
+
+ /**
+ * Returns associative array of detected types (IReflection::FIELD_*) in result set.
+ */
+ public function getColumnTypes(\PDOStatement $statement)
+ {
+ return Nette\Database\Helpers::detectTypes($statement);
+ }
+
+
+ /**
+ * @param string
+ * @return bool
+ */
+ public function isSupported($item)
+ {
+ return $item === self::SUPPORT_SUBSELECT;
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Drivers/PgSqlDriver.php b/vendor/nette/database/src/Database/Drivers/PgSqlDriver.php
new file mode 100755
index 0000000..0a9a56c
--- /dev/null
+++ b/vendor/nette/database/src/Database/Drivers/PgSqlDriver.php
@@ -0,0 +1,287 @@
+connection = $connection;
+ }
+
+
+ public function convertException(\PDOException $e)
+ {
+ $code = isset($e->errorInfo[0]) ? $e->errorInfo[0] : NULL;
+ if ($code === '0A000' && strpos($e->getMessage(), 'truncate') !== FALSE) {
+ return Nette\Database\ForeignKeyConstraintViolationException::from($e);
+
+ } elseif ($code === '23502') {
+ return Nette\Database\NotNullConstraintViolationException::from($e);
+
+ } elseif ($code === '23503') {
+ return Nette\Database\ForeignKeyConstraintViolationException::from($e);
+
+ } elseif ($code === '23505') {
+ return Nette\Database\UniqueConstraintViolationException::from($e);
+
+ } elseif ($code === '08006') {
+ return Nette\Database\ConnectionException::from($e);
+
+ } else {
+ return Nette\Database\DriverException::from($e);
+ }
+ }
+
+
+ /********************* SQL ****************d*g**/
+
+
+ /**
+ * Delimites identifier for use in a SQL statement.
+ */
+ public function delimite($name)
+ {
+ // @see http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
+ return '"' . str_replace('"', '""', $name) . '"';
+ }
+
+
+ /**
+ * Formats boolean for use in a SQL statement.
+ */
+ public function formatBool($value)
+ {
+ return $value ? 'TRUE' : 'FALSE';
+ }
+
+
+ /**
+ * Formats date-time for use in a SQL statement.
+ */
+ public function formatDateTime(/*\DateTimeInterface*/ $value)
+ {
+ return $value->format("'Y-m-d H:i:s'");
+ }
+
+
+ /**
+ * Formats date-time interval for use in a SQL statement.
+ */
+ public function formatDateInterval(\DateInterval $value)
+ {
+ throw new Nette\NotSupportedException;
+ }
+
+
+ /**
+ * Encodes string for use in a LIKE statement.
+ */
+ public function formatLike($value, $pos)
+ {
+ $bs = substr($this->connection->quote('\\', \PDO::PARAM_STR), 1, -1); // standard_conforming_strings = on/off
+ $value = substr($this->connection->quote($value, \PDO::PARAM_STR), 1, -1);
+ $value = strtr($value, array('%' => $bs . '%', '_' => $bs . '_', '\\' => '\\\\'));
+ return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
+ }
+
+
+ /**
+ * Injects LIMIT/OFFSET to the SQL query.
+ */
+ public function applyLimit(& $sql, $limit, $offset)
+ {
+ if ($limit >= 0) {
+ $sql .= ' LIMIT ' . (int) $limit;
+ }
+ if ($offset > 0) {
+ $sql .= ' OFFSET ' . (int) $offset;
+ }
+ }
+
+
+ /**
+ * Normalizes result row.
+ */
+ public function normalizeRow($row)
+ {
+ return $row;
+ }
+
+
+ /********************* reflection ****************d*g**/
+
+
+ /**
+ * Returns list of tables.
+ */
+ public function getTables()
+ {
+ $tables = array();
+ foreach ($this->connection->query("
+ SELECT DISTINCT ON (c.relname)
+ c.relname::varchar AS name,
+ c.relkind = 'v' AS view,
+ n.nspname::varchar || '.' || c.relname::varchar AS \"fullName\"
+ FROM
+ pg_catalog.pg_class AS c
+ JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace
+ WHERE
+ c.relkind IN ('r', 'v')
+ AND n.nspname = ANY (pg_catalog.current_schemas(FALSE))
+ ORDER BY
+ c.relname
+ ") as $row) {
+ $tables[] = (array) $row;
+ }
+
+ return $tables;
+ }
+
+
+ /**
+ * Returns metadata for all columns in a table.
+ */
+ public function getColumns($table)
+ {
+ $columns = array();
+ foreach ($this->connection->query("
+ SELECT
+ a.attname::varchar AS name,
+ c.relname::varchar AS table,
+ upper(t.typname) AS nativetype,
+ CASE WHEN a.atttypmod = -1 THEN NULL ELSE a.atttypmod -4 END AS size,
+ FALSE AS unsigned,
+ NOT (a.attnotnull OR t.typtype = 'd' AND t.typnotnull) AS nullable,
+ pg_catalog.pg_get_expr(ad.adbin, 'pg_catalog.pg_attrdef'::regclass)::varchar AS default,
+ coalesce(co.contype = 'p' AND strpos(ad.adsrc, 'nextval') = 1, FALSE) AS autoincrement,
+ coalesce(co.contype = 'p', FALSE) AS primary,
+ substring(pg_catalog.pg_get_expr(ad.adbin, 'pg_catalog.pg_attrdef'::regclass) from 'nextval[(]''\"?([^''\"]+)') AS sequence
+ FROM
+ pg_catalog.pg_attribute AS a
+ JOIN pg_catalog.pg_class AS c ON a.attrelid = c.oid
+ JOIN pg_catalog.pg_type AS t ON a.atttypid = t.oid
+ LEFT JOIN pg_catalog.pg_attrdef AS ad ON ad.adrelid = c.oid AND ad.adnum = a.attnum
+ LEFT JOIN pg_catalog.pg_constraint AS co ON co.connamespace = c.relnamespace AND contype = 'p' AND co.conrelid = c.oid AND a.attnum = ANY(co.conkey)
+ WHERE
+ c.relkind IN ('r', 'v')
+ AND c.oid = {$this->connection->quote($this->delimiteFQN($table))}::regclass
+ AND a.attnum > 0
+ AND NOT a.attisdropped
+ ORDER BY
+ a.attnum
+ ") as $row) {
+ $column = (array) $row;
+ $column['vendor'] = $column;
+ unset($column['sequence']);
+
+ $columns[] = $column;
+ }
+
+ return $columns;
+ }
+
+
+ /**
+ * Returns metadata for all indexes in a table.
+ */
+ public function getIndexes($table)
+ {
+ $indexes = array();
+ foreach ($this->connection->query("
+ SELECT
+ c2.relname::varchar AS name,
+ i.indisunique AS unique,
+ i.indisprimary AS primary,
+ a.attname::varchar AS column
+ FROM
+ pg_catalog.pg_class AS c1
+ JOIN pg_catalog.pg_index AS i ON c1.oid = i.indrelid
+ JOIN pg_catalog.pg_class AS c2 ON i.indexrelid = c2.oid
+ LEFT JOIN pg_catalog.pg_attribute AS a ON c1.oid = a.attrelid AND a.attnum = ANY(i.indkey)
+ WHERE
+ c1.relkind = 'r'
+ AND c1.oid = {$this->connection->quote($this->delimiteFQN($table))}::regclass
+ ") as $row) {
+ $indexes[$row['name']]['name'] = $row['name'];
+ $indexes[$row['name']]['unique'] = $row['unique'];
+ $indexes[$row['name']]['primary'] = $row['primary'];
+ $indexes[$row['name']]['columns'][] = $row['column'];
+ }
+
+ return array_values($indexes);
+ }
+
+
+ /**
+ * Returns metadata for all foreign keys in a table.
+ */
+ public function getForeignKeys($table)
+ {
+ /* Does't work with multicolumn foreign keys */
+ return $this->connection->query("
+ SELECT
+ co.conname::varchar AS name,
+ al.attname::varchar AS local,
+ nf.nspname || '.' || cf.relname::varchar AS table,
+ af.attname::varchar AS foreign
+ FROM
+ pg_catalog.pg_constraint AS co
+ JOIN pg_catalog.pg_class AS cl ON co.conrelid = cl.oid
+ JOIN pg_catalog.pg_class AS cf ON co.confrelid = cf.oid
+ JOIN pg_catalog.pg_namespace AS nf ON nf.oid = cf.relnamespace
+ JOIN pg_catalog.pg_attribute AS al ON al.attrelid = cl.oid AND al.attnum = co.conkey[1]
+ JOIN pg_catalog.pg_attribute AS af ON af.attrelid = cf.oid AND af.attnum = co.confkey[1]
+ WHERE
+ co.contype = 'f'
+ AND cl.oid = {$this->connection->quote($this->delimiteFQN($table))}::regclass
+ AND nf.nspname = ANY (pg_catalog.current_schemas(FALSE))
+ ")->fetchAll();
+ }
+
+
+ /**
+ * Returns associative array of detected types (IReflection::FIELD_*) in result set.
+ */
+ public function getColumnTypes(\PDOStatement $statement)
+ {
+ return Nette\Database\Helpers::detectTypes($statement);
+ }
+
+
+ /**
+ * @param string
+ * @return bool
+ */
+ public function isSupported($item)
+ {
+ return $item === self::SUPPORT_SEQUENCE || $item === self::SUPPORT_SUBSELECT || $item === self::SUPPORT_SCHEMA;
+ }
+
+
+ /**
+ * Converts: schema.name => "schema"."name"
+ * @param string
+ * @return string
+ */
+ private function delimiteFQN($name)
+ {
+ return implode('.', array_map(array($this, 'delimite'), explode('.', $name)));
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Drivers/Sqlite2Driver.php b/vendor/nette/database/src/Database/Drivers/Sqlite2Driver.php
new file mode 100755
index 0000000..86d6834
--- /dev/null
+++ b/vendor/nette/database/src/Database/Drivers/Sqlite2Driver.php
@@ -0,0 +1,44 @@
+connection = $connection;
+ $this->fmtDateTime = isset($options['formatDateTime']) ? $options['formatDateTime'] : 'U';
+ }
+
+
+ public function convertException(\PDOException $e)
+ {
+ $code = isset($e->errorInfo[1]) ? $e->errorInfo[1] : NULL;
+ $msg = $e->getMessage();
+ if ($code !== 19) {
+ return Nette\Database\DriverException::from($e);
+
+ } elseif (strpos($msg, 'must be unique') !== FALSE
+ || strpos($msg, 'is not unique') !== FALSE
+ || strpos($msg, 'UNIQUE constraint failed') !== FALSE
+ ) {
+ return Nette\Database\UniqueConstraintViolationException::from($e);
+
+ } elseif (strpos($msg, 'may not be NULL') !== FALSE
+ || strpos($msg, 'NOT NULL constraint failed') !== FALSE
+ ) {
+ return Nette\Database\NotNullConstraintViolationException::from($e);
+
+ } elseif (strpos($msg, 'foreign key constraint failed') !== FALSE
+ || strpos($msg, 'FOREIGN KEY constraint failed') !== FALSE
+ ) {
+ return Nette\Database\ForeignKeyConstraintViolationException::from($e);
+
+ } else {
+ return Nette\Database\ConstraintViolationException::from($e);
+ }
+ }
+
+
+ /********************* SQL ****************d*g**/
+
+
+ /**
+ * Delimites identifier for use in a SQL statement.
+ */
+ public function delimite($name)
+ {
+ return '[' . strtr($name, '[]', ' ') . ']';
+ }
+
+
+ /**
+ * Formats boolean for use in a SQL statement.
+ */
+ public function formatBool($value)
+ {
+ return $value ? '1' : '0';
+ }
+
+
+ /**
+ * Formats date-time for use in a SQL statement.
+ */
+ public function formatDateTime(/*\DateTimeInterface*/ $value)
+ {
+ return $value->format($this->fmtDateTime);
+ }
+
+
+ /**
+ * Formats date-time interval for use in a SQL statement.
+ */
+ public function formatDateInterval(\DateInterval $value)
+ {
+ throw new Nette\NotSupportedException;
+ }
+
+
+ /**
+ * Encodes string for use in a LIKE statement.
+ */
+ public function formatLike($value, $pos)
+ {
+ $value = addcslashes(substr($this->connection->quote($value), 1, -1), '%_\\');
+ return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'") . " ESCAPE '\\'";
+ }
+
+
+ /**
+ * Injects LIMIT/OFFSET to the SQL query.
+ */
+ public function applyLimit(& $sql, $limit, $offset)
+ {
+ if ($limit >= 0 || $offset > 0) {
+ $sql .= ' LIMIT ' . (int) $limit . ($offset > 0 ? ' OFFSET ' . (int) $offset : '');
+ }
+ }
+
+
+ /**
+ * Normalizes result row.
+ */
+ public function normalizeRow($row)
+ {
+ foreach ($row as $key => $value) {
+ unset($row[$key]);
+ if ($key[0] === '[' || $key[0] === '"') {
+ $key = substr($key, 1, -1);
+ }
+ $row[$key] = $value;
+ }
+ return $row;
+ }
+
+
+ /********************* reflection ****************d*g**/
+
+
+ /**
+ * Returns list of tables.
+ */
+ public function getTables()
+ {
+ $tables = array();
+ foreach ($this->connection->query("
+ SELECT name, type = 'view' as view FROM sqlite_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'
+ UNION ALL
+ SELECT name, type = 'view' as view FROM sqlite_temp_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'
+ ORDER BY name
+ ") as $row) {
+ $tables[] = array(
+ 'name' => $row->name,
+ 'view' => (bool) $row->view,
+ );
+ }
+
+ return $tables;
+ }
+
+
+ /**
+ * Returns metadata for all columns in a table.
+ */
+ public function getColumns($table)
+ {
+ $meta = $this->connection->query("
+ SELECT sql FROM sqlite_master WHERE type = 'table' AND name = {$this->connection->quote($table)}
+ UNION ALL
+ SELECT sql FROM sqlite_temp_master WHERE type = 'table' AND name = {$this->connection->quote($table)}
+ ")->fetch();
+
+ $columns = array();
+ foreach ($this->connection->query("PRAGMA table_info({$this->delimite($table)})") as $row) {
+ $column = $row['name'];
+ $pattern = "/(\"$column\"|\[$column\]|$column)\\s+[^,]+\\s+PRIMARY\\s+KEY\\s+AUTOINCREMENT/Ui";
+ $type = explode('(', $row['type']);
+ $columns[] = array(
+ 'name' => $column,
+ 'table' => $table,
+ 'nativetype' => strtoupper($type[0]),
+ 'size' => isset($type[1]) ? (int) $type[1] : NULL,
+ 'unsigned' => FALSE,
+ 'nullable' => $row['notnull'] == '0',
+ 'default' => $row['dflt_value'],
+ 'autoincrement' => (bool) preg_match($pattern, $meta['sql']),
+ 'primary' => $row['pk'] > 0,
+ 'vendor' => (array) $row,
+ );
+ }
+ return $columns;
+ }
+
+
+ /**
+ * Returns metadata for all indexes in a table.
+ */
+ public function getIndexes($table)
+ {
+ $indexes = array();
+ foreach ($this->connection->query("PRAGMA index_list({$this->delimite($table)})") as $row) {
+ $indexes[$row['name']]['name'] = $row['name'];
+ $indexes[$row['name']]['unique'] = (bool) $row['unique'];
+ $indexes[$row['name']]['primary'] = FALSE;
+ }
+
+ foreach ($indexes as $index => $values) {
+ $res = $this->connection->query("PRAGMA index_info({$this->delimite($index)})");
+ while ($row = $res->fetch(TRUE)) {
+ $indexes[$index]['columns'][$row['seqno']] = $row['name'];
+ }
+ }
+
+ $columns = $this->getColumns($table);
+ foreach ($indexes as $index => $values) {
+ $column = $indexes[$index]['columns'][0];
+ foreach ($columns as $info) {
+ if ($column == $info['name']) {
+ $indexes[$index]['primary'] = (bool) $info['primary'];
+ break;
+ }
+ }
+ }
+ if (!$indexes) { // @see http://www.sqlite.org/lang_createtable.html#rowid
+ foreach ($columns as $column) {
+ if ($column['vendor']['pk']) {
+ $indexes[] = array(
+ 'name' => 'ROWID',
+ 'unique' => TRUE,
+ 'primary' => TRUE,
+ 'columns' => array($column['name']),
+ );
+ break;
+ }
+ }
+ }
+
+ return array_values($indexes);
+ }
+
+
+ /**
+ * Returns metadata for all foreign keys in a table.
+ */
+ public function getForeignKeys($table)
+ {
+ $keys = array();
+ foreach ($this->connection->query("PRAGMA foreign_key_list({$this->delimite($table)})") as $row) {
+ $keys[$row['id']]['name'] = $row['id']; // foreign key name
+ $keys[$row['id']]['local'] = $row['from']; // local columns
+ $keys[$row['id']]['table'] = $row['table']; // referenced table
+ $keys[$row['id']]['foreign'] = $row['to']; // referenced columns
+ $keys[$row['id']]['onDelete'] = $row['on_delete'];
+ $keys[$row['id']]['onUpdate'] = $row['on_update'];
+
+ if ($keys[$row['id']]['foreign'][0] == NULL) {
+ $keys[$row['id']]['foreign'] = NULL;
+ }
+ }
+ return array_values($keys);
+ }
+
+
+ /**
+ * Returns associative array of detected types (IReflection::FIELD_*) in result set.
+ */
+ public function getColumnTypes(\PDOStatement $statement)
+ {
+ $types = array();
+ $count = $statement->columnCount();
+ for ($col = 0; $col < $count; $col++) {
+ $meta = $statement->getColumnMeta($col);
+ if (isset($meta['sqlite:decl_type'])) {
+ if ($meta['sqlite:decl_type'] === 'DATE') {
+ $types[$meta['name']] = Nette\Database\IStructure::FIELD_UNIX_TIMESTAMP;
+ } else {
+ $types[$meta['name']] = Nette\Database\Helpers::detectType($meta['sqlite:decl_type']);
+ }
+ } elseif (isset($meta['native_type'])) {
+ $types[$meta['name']] = Nette\Database\Helpers::detectType($meta['native_type']);
+ }
+ }
+ return $types;
+ }
+
+
+ /**
+ * @param string
+ * @return bool
+ */
+ public function isSupported($item)
+ {
+ return $item === self::SUPPORT_MULTI_INSERT_AS_SELECT || $item === self::SUPPORT_SUBSELECT || $item === self::SUPPORT_MULTI_COLUMN_AS_OR_COND;
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Drivers/SqlsrvDriver.php b/vendor/nette/database/src/Database/Drivers/SqlsrvDriver.php
new file mode 100755
index 0000000..c8b6ff9
--- /dev/null
+++ b/vendor/nette/database/src/Database/Drivers/SqlsrvDriver.php
@@ -0,0 +1,282 @@
+connection = $connection;
+ }
+
+
+ public function convertException(\PDOException $e)
+ {
+ return Nette\Database\DriverException::from($e);
+ }
+
+
+ /********************* SQL ****************d*g**/
+
+
+ /**
+ * Delimites identifier for use in a SQL statement.
+ */
+ public function delimite($name)
+ {
+ /** @see http://msdn.microsoft.com/en-us/library/ms176027.aspx */
+ return '[' . str_replace(']', ']]', $name) . ']';
+ }
+
+
+ /**
+ * Formats boolean for use in a SQL statement.
+ */
+ public function formatBool($value)
+ {
+ return $value ? '1' : '0';
+ }
+
+
+ /**
+ * Formats date-time for use in a SQL statement.
+ */
+ public function formatDateTime(/*\DateTimeInterface*/ $value)
+ {
+ /** @see http://msdn.microsoft.com/en-us/library/ms187819.aspx */
+ return $value->format("'Y-m-d H:i:s'");
+ }
+
+
+ /**
+ * Formats date-time interval for use in a SQL statement.
+ */
+ public function formatDateInterval(\DateInterval $value)
+ {
+ throw new Nette\NotSupportedException;
+ }
+
+
+ /**
+ * Encodes string for use in a LIKE statement.
+ */
+ public function formatLike($value, $pos)
+ {
+ /** @see http://msdn.microsoft.com/en-us/library/ms179859.aspx */
+ $value = strtr($value, array("'" => "''", '%' => '[%]', '_' => '[_]', '[' => '[[]'));
+ return ($pos <= 0 ? "'%" : "'") . $value . ($pos >= 0 ? "%'" : "'");
+ }
+
+
+ /**
+ * Injects LIMIT/OFFSET to the SQL query.
+ */
+ public function applyLimit(& $sql, $limit, $offset)
+ {
+ if ($limit >= 0) {
+ $sql = preg_replace('#^\s*(SELECT|UPDATE|DELETE)#i', '$0 TOP ' . (int) $limit, $sql, 1, $count);
+ if (!$count) {
+ throw new Nette\InvalidArgumentException('SQL query must begin with SELECT, UPDATE or DELETE command.');
+ }
+ }
+
+ if ($offset > 0) {
+ throw new Nette\NotSupportedException('Offset is not supported by this database.');
+ }
+ }
+
+
+ /**
+ * Normalizes result row.
+ */
+ public function normalizeRow($row)
+ {
+ return $row;
+ }
+
+
+ /********************* reflection ****************d*g**/
+
+
+ /**
+ * Returns list of tables.
+ */
+ public function getTables()
+ {
+ $tables = array();
+ foreach ($this->connection->query("
+ SELECT
+ name,
+ CASE type
+ WHEN 'U' THEN 0
+ WHEN 'V' THEN 1
+ END AS [view]
+ FROM
+ sys.objects
+ WHERE
+ type IN ('U', 'V')
+ ") as $row) {
+ $tables[] = array(
+ 'name' => $row->name,
+ 'view' => (bool) $row->view,
+ );
+ }
+
+ return $tables;
+ }
+
+
+ /**
+ * Returns metadata for all columns in a table.
+ */
+ public function getColumns($table)
+ {
+ $columns = array();
+ foreach ($this->connection->query("
+ SELECT
+ c.name AS name,
+ o.name AS [table],
+ UPPER(t.name) AS nativetype,
+ NULL AS size,
+ 0 AS unsigned,
+ c.is_nullable AS nullable,
+ OBJECT_DEFINITION(c.default_object_id) AS [default],
+ c.is_identity AS autoincrement,
+ CASE WHEN i.index_id IS NULL
+ THEN 0
+ ELSE 1
+ END AS [primary]
+ FROM
+ sys.columns c
+ JOIN sys.objects o ON c.object_id = o.object_id
+ LEFT JOIN sys.types t ON c.user_type_id = t.user_type_id
+ LEFT JOIN sys.key_constraints k ON o.object_id = k.parent_object_id AND k.type = 'PK'
+ LEFT JOIN sys.index_columns i ON k.parent_object_id = i.object_id AND i.index_id = k.unique_index_id AND i.column_id = c.column_id
+ WHERE
+ o.type IN ('U', 'V')
+ AND o.name = {$this->connection->quote($table)}
+ ") as $row) {
+ $row = (array) $row;
+ $row['vendor'] = $row;
+ $row['unsigned'] = (bool) $row['unsigned'];
+ $row['nullable'] = (bool) $row['nullable'];
+ $row['autoincrement'] = (bool) $row['autoincrement'];
+ $row['primary'] = (bool) $row['primary'];
+
+ $columns[] = $row;
+ }
+
+ return $columns;
+ }
+
+
+ /**
+ * Returns metadata for all indexes in a table.
+ */
+ public function getIndexes($table)
+ {
+ $indexes = array();
+ foreach ($this->connection->query("
+ SELECT
+ i.name AS name,
+ CASE WHEN i.is_unique = 1 OR i.is_unique_constraint = 1
+ THEN 1
+ ELSE 0
+ END AS [unique],
+ i.is_primary_key AS [primary],
+ c.name AS [column]
+ FROM
+ sys.indexes i
+ JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
+ JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id
+ JOIN sys.tables t ON i.object_id = t.object_id
+ WHERE
+ t.name = {$this->connection->quote($table)}
+ ORDER BY
+ i.index_id,
+ ic.index_column_id
+ ") as $row) {
+ $indexes[$row->name]['name'] = $row->name;
+ $indexes[$row->name]['unique'] = (bool) $row->unique;
+ $indexes[$row->name]['primary'] = (bool) $row->primary;
+ $indexes[$row->name]['columns'][] = $row->column;
+ }
+
+ return array_values($indexes);
+ }
+
+
+ /**
+ * Returns metadata for all foreign keys in a table.
+ */
+ public function getForeignKeys($table)
+ {
+ // Does't work with multicolumn foreign keys
+ $keys = array();
+ foreach ($this->connection->query("
+ SELECT
+ fk.name AS name,
+ cl.name AS local,
+ tf.name AS [table],
+ cf.name AS [column]
+ FROM
+ sys.foreign_keys fk
+ JOIN sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id
+ JOIN sys.tables tl ON fkc.parent_object_id = tl.object_id
+ JOIN sys.columns cl ON fkc.parent_object_id = cl.object_id AND fkc.parent_column_id = cl.column_id
+ JOIN sys.tables tf ON fkc.referenced_object_id = tf.object_id
+ JOIN sys.columns cf ON fkc.referenced_object_id = cf.object_id AND fkc.referenced_column_id = cf.column_id
+ WHERE
+ tl.name = {$this->connection->quote($table)}
+ ") as $row) {
+ $keys[$row->name] = (array) $row;
+ }
+
+ return array_values($keys);
+ }
+
+
+ /**
+ * Returns associative array of detected types (IReflection::FIELD_*) in result set.
+ */
+ public function getColumnTypes(\PDOStatement $statement)
+ {
+ $types = array();
+ $count = $statement->columnCount();
+ for ($col = 0; $col < $count; $col++) {
+ $meta = $statement->getColumnMeta($col);
+ if (isset($meta['sqlsrv:decl_type']) && $meta['sqlsrv:decl_type'] !== 'timestamp') { // timestamp does not mean time in sqlsrv
+ $types[$meta['name']] = Nette\Database\Helpers::detectType($meta['sqlsrv:decl_type']);
+ } elseif (isset($meta['native_type'])) {
+ $types[$meta['name']] = Nette\Database\Helpers::detectType($meta['native_type']);
+ }
+ }
+ return $types;
+ }
+
+
+ /**
+ * @param string
+ * @return bool
+ */
+ public function isSupported($item)
+ {
+ return $item === self::SUPPORT_SUBSELECT;
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Helpers.php b/vendor/nette/database/src/Database/Helpers.php
new file mode 100755
index 0000000..370fb75
--- /dev/null
+++ b/vendor/nette/database/src/Database/Helpers.php
@@ -0,0 +1,268 @@
+ IStructure::FIELD_TEXT, // PostgreSQL arrays
+ 'BYTEA|BLOB|BIN' => IStructure::FIELD_BINARY,
+ 'TEXT|CHAR|POINT|INTERVAL' => IStructure::FIELD_TEXT,
+ 'YEAR|BYTE|COUNTER|SERIAL|INT|LONG|SHORT|^TINY$' => IStructure::FIELD_INTEGER,
+ 'CURRENCY|REAL|MONEY|FLOAT|DOUBLE|DECIMAL|NUMERIC|NUMBER' => IStructure::FIELD_FLOAT,
+ '^TIME$' => IStructure::FIELD_TIME,
+ 'TIME' => IStructure::FIELD_DATETIME, // DATETIME, TIMESTAMP
+ 'DATE' => IStructure::FIELD_DATE,
+ 'BOOL' => IStructure::FIELD_BOOL,
+ );
+
+
+ /**
+ * Displays complete result set as HTML table for debug purposes.
+ * @return void
+ */
+ public static function dumpResult(ResultSet $result)
+ {
+ echo "\n\n" . htmlSpecialChars($result->getQueryString(), ENT_IGNORE, 'UTF-8') . " \n";
+ if (!$result->getColumnCount()) {
+ echo "\t\n\t\tAffected rows: \n\t\t", $result->getRowCount(), " \n\t \n
\n";
+ return;
+ }
+ $i = 0;
+ foreach ($result as $row) {
+ if ($i === 0) {
+ echo "\n\t\n\t\t#row \n";
+ foreach ($row as $col => $foo) {
+ echo "\t\t" . htmlSpecialChars($col, ENT_NOQUOTES, 'UTF-8') . " \n";
+ }
+ echo "\t \n \n\n";
+ }
+ echo "\t\n\t\t", $i, " \n";
+ foreach ($row as $col) {
+ echo "\t\t", htmlSpecialChars($col, ENT_NOQUOTES, 'UTF-8'), " \n";
+ }
+ echo "\t \n";
+ $i++;
+ }
+
+ if ($i === 0) {
+ echo "\t\n\t\tempty result set \n\t \n
\n";
+ } else {
+ echo "\n
\n";
+ }
+ }
+
+
+ /**
+ * Returns syntax highlighted SQL command.
+ * @param string
+ * @return string
+ */
+ public static function dumpSql($sql, array $params = NULL, Connection $connection = NULL)
+ {
+ static $keywords1 = 'SELECT|(?:ON\s+DUPLICATE\s+KEY)?UPDATE|INSERT(?:\s+INTO)?|REPLACE(?:\s+INTO)?|DELETE|CALL|UNION|FROM|WHERE|HAVING|GROUP\s+BY|ORDER\s+BY|LIMIT|OFFSET|SET|VALUES|LEFT\s+JOIN|INNER\s+JOIN|TRUNCATE';
+ static $keywords2 = 'ALL|DISTINCT|DISTINCTROW|IGNORE|AS|USING|ON|AND|OR|IN|IS|NOT|NULL|[RI]?LIKE|REGEXP|TRUE|FALSE';
+
+ // insert new lines
+ $sql = " $sql ";
+ $sql = preg_replace("#(?<=[\\s,(])($keywords1)(?=[\\s,)])#i", "\n\$1", $sql);
+
+ // reduce spaces
+ $sql = preg_replace('#[ \t]{2,}#', ' ', $sql);
+
+ $sql = wordwrap($sql, 100);
+ $sql = preg_replace('#([ \t]*\r?\n){2,}#', "\n", $sql);
+
+ // syntax highlight
+ $sql = htmlSpecialChars($sql, ENT_IGNORE, 'UTF-8');
+ $sql = preg_replace_callback("#(/\\*.+?\\*/)|(\\*\\*.+?\\*\\*)|(?<=[\\s,(])($keywords1)(?=[\\s,)])|(?<=[\\s,(=])($keywords2)(?=[\\s,)=])#is", function ($matches) {
+ if (!empty($matches[1])) { // comment
+ return '' . $matches[1] . ' ';
+
+ } elseif (!empty($matches[2])) { // error
+ return '' . $matches[2] . ' ';
+
+ } elseif (!empty($matches[3])) { // most important keywords
+ return '' . $matches[3] . ' ';
+
+ } elseif (!empty($matches[4])) { // other keywords
+ return '' . $matches[4] . ' ';
+ }
+ }, $sql);
+
+ // parameters
+ $sql = preg_replace_callback('#\?#', function () use ($params, $connection) {
+ static $i = 0;
+ if (!isset($params[$i])) {
+ return '?';
+ }
+ $param = $params[$i++];
+ if (is_string($param) && (preg_match('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u', $param) || preg_last_error())) {
+ return '<binary> ';
+
+ } elseif (is_string($param)) {
+ $length = Nette\Utils\Strings::length($param);
+ $truncated = Nette\Utils\Strings::truncate($param, Helpers::$maxLength);
+ $text = htmlspecialchars($connection ? $connection->quote($truncated) : '\'' . $truncated . '\'', ENT_NOQUOTES, 'UTF-8');
+ return '' . $text . ' ';
+
+ } elseif (is_resource($param)) {
+ $type = get_resource_type($param);
+ if ($type === 'stream') {
+ $info = stream_get_meta_data($param);
+ }
+ return '<' . htmlSpecialChars($type, ENT_NOQUOTES, 'UTF-8') . ' resource> ';
+
+ } else {
+ return htmlspecialchars($param, ENT_NOQUOTES, 'UTF-8');
+ }
+ }, $sql);
+
+ return '' . trim($sql) . " \n";
+ }
+
+
+ /**
+ * Common column type detection.
+ * @return array
+ */
+ public static function detectTypes(\PDOStatement $statement)
+ {
+ $types = array();
+ $count = $statement->columnCount(); // driver must be meta-aware, see PHP bugs #53782, #54695
+ for ($col = 0; $col < $count; $col++) {
+ $meta = $statement->getColumnMeta($col);
+ if (isset($meta['native_type'])) {
+ $types[$meta['name']] = self::detectType($meta['native_type']);
+ }
+ }
+ return $types;
+ }
+
+
+ /**
+ * Heuristic column type detection.
+ * @param string
+ * @return string
+ * @internal
+ */
+ public static function detectType($type)
+ {
+ static $cache;
+ if (!isset($cache[$type])) {
+ $cache[$type] = 'string';
+ foreach (self::$typePatterns as $s => $val) {
+ if (preg_match("#$s#i", $type)) {
+ return $cache[$type] = $val;
+ }
+ }
+ }
+ return $cache[$type];
+ }
+
+
+ /**
+ * Import SQL dump from file - extremely fast.
+ * @return int count of commands
+ */
+ public static function loadFromFile(Connection $connection, $file)
+ {
+ @set_time_limit(0); // @ function may be disabled
+
+ $handle = @fopen($file, 'r'); // @ is escalated to exception
+ if (!$handle) {
+ throw new Nette\FileNotFoundException("Cannot open file '$file'.");
+ }
+
+ $count = 0;
+ $delimiter = ';';
+ $sql = '';
+ $pdo = $connection->getPdo(); // native query without logging
+ while (!feof($handle)) {
+ $s = rtrim(fgets($handle));
+ if (!strncasecmp($s, 'DELIMITER ', 10)) {
+ $delimiter = substr($s, 10);
+
+ } elseif (substr($s, -strlen($delimiter)) === $delimiter) {
+ $sql .= substr($s, 0, -strlen($delimiter));
+ $pdo->exec($sql);
+ $sql = '';
+ $count++;
+
+ } else {
+ $sql .= $s . "\n";
+ }
+ }
+ if (trim($sql) !== '') {
+ $pdo->exec($sql);
+ $count++;
+ }
+ fclose($handle);
+ return $count;
+ }
+
+
+ public static function createDebugPanel($connection, $explain = TRUE, $name = NULL)
+ {
+ $panel = new Nette\Bridges\DatabaseTracy\ConnectionPanel($connection);
+ $panel->explain = $explain;
+ $panel->name = $name;
+ Tracy\Debugger::getBar()->addPanel($panel);
+ return $panel;
+ }
+
+
+ /**
+ * Reformat source to key -> value pairs.
+ * @return array
+ */
+ public static function toPairs(array $rows, $key = NULL, $value = NULL)
+ {
+ if (!$rows) {
+ return array();
+ }
+
+ $keys = array_keys((array) reset($rows));
+ if (!count($keys)) {
+ throw new \LogicException('Result set does not contain any column.');
+
+ } elseif ($key === NULL && $value === NULL) {
+ if (count($keys) === 1) {
+ list($value) = $keys;
+ } else {
+ list($key, $value) = $keys;
+ }
+ }
+
+ $return = array();
+ if ($key === NULL) {
+ foreach ($rows as $row) {
+ $return[] = ($value === NULL ? $row : $row[$value]);
+ }
+ } else {
+ foreach ($rows as $row) {
+ $return[is_object($row[$key]) ? (string) $row[$key] : $row[$key]] = ($value === NULL ? $row : $row[$value]);
+ }
+ }
+
+ return $return;
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/IConventions.php b/vendor/nette/database/src/Database/IConventions.php
new file mode 100755
index 0000000..82c820f
--- /dev/null
+++ b/vendor/nette/database/src/Database/IConventions.php
@@ -0,0 +1,47 @@
+connection = $connection;
+ $this->supplementalDriver = $connection->getSupplementalDriver();
+ $this->queryString = $queryString;
+ $this->params = $params;
+
+ try {
+ if (substr($queryString, 0, 2) === '::') {
+ $connection->getPdo()->{substr($queryString, 2)}();
+ } elseif ($queryString !== NULL) {
+ static $types = array('boolean' => PDO::PARAM_BOOL, 'integer' => PDO::PARAM_INT,
+ 'resource' => PDO::PARAM_LOB, 'NULL' => PDO::PARAM_NULL);
+ $this->pdoStatement = $connection->getPdo()->prepare($queryString);
+ foreach ($params as $key => $value) {
+ $type = gettype($value);
+ $this->pdoStatement->bindValue(is_int($key) ? $key + 1 : $key, $value, isset($types[$type]) ? $types[$type] : PDO::PARAM_STR);
+ }
+ $this->pdoStatement->setFetchMode(PDO::FETCH_ASSOC);
+ $this->pdoStatement->execute();
+ }
+ } catch (\PDOException $e) {
+ $e = $this->supplementalDriver->convertException($e);
+ $e->queryString = $queryString;
+ throw $e;
+ }
+ $this->time = microtime(TRUE) - $time;
+ }
+
+
+ /**
+ * @return Connection
+ */
+ public function getConnection()
+ {
+ return $this->connection;
+ }
+
+
+ /**
+ * @internal
+ * @return \PDOStatement
+ */
+ public function getPdoStatement()
+ {
+ return $this->pdoStatement;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getQueryString()
+ {
+ return $this->queryString;
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getParameters()
+ {
+ return $this->params;
+ }
+
+
+ /**
+ * @return int
+ */
+ public function getColumnCount()
+ {
+ return $this->pdoStatement ? $this->pdoStatement->columnCount() : NULL;
+ }
+
+
+ /**
+ * @return int
+ */
+ public function getRowCount()
+ {
+ return $this->pdoStatement ? $this->pdoStatement->rowCount() : NULL;
+ }
+
+
+ /**
+ * @return float
+ */
+ public function getTime()
+ {
+ return $this->time;
+ }
+
+
+ /**
+ * Normalizes result row.
+ * @param array
+ * @return array
+ */
+ public function normalizeRow($row)
+ {
+ if ($this->types === NULL) {
+ $this->types = (array) $this->supplementalDriver->getColumnTypes($this->pdoStatement);
+ }
+
+ foreach ($this->types as $key => $type) {
+ $value = $row[$key];
+ if ($value === NULL || $value === FALSE || $type === IStructure::FIELD_TEXT) {
+
+ } elseif ($type === IStructure::FIELD_INTEGER) {
+ $row[$key] = is_float($tmp = $value * 1) ? $value : $tmp;
+
+ } elseif ($type === IStructure::FIELD_FLOAT) {
+ if (($pos = strpos($value, '.')) !== FALSE) {
+ $value = rtrim(rtrim($pos === 0 ? "0$value" : $value, '0'), '.');
+ }
+ $float = (float) $value;
+ $row[$key] = (string) $float === $value ? $float : $value;
+
+ } elseif ($type === IStructure::FIELD_BOOL) {
+ $row[$key] = ((bool) $value) && $value !== 'f' && $value !== 'F';
+
+ } elseif ($type === IStructure::FIELD_DATETIME || $type === IStructure::FIELD_DATE || $type === IStructure::FIELD_TIME) {
+ $row[$key] = new Nette\Utils\DateTime($value);
+
+ } elseif ($type === IStructure::FIELD_TIME_INTERVAL) {
+ preg_match('#^(-?)(\d+)\D(\d+)\D(\d+)\z#', $value, $m);
+ $row[$key] = new \DateInterval("PT$m[2]H$m[3]M$m[4]S");
+ $row[$key]->invert = (int) (bool) $m[1];
+
+ } elseif ($type === IStructure::FIELD_UNIX_TIMESTAMP) {
+ $row[$key] = Nette\Utils\DateTime::from($value);
+ }
+ }
+
+ return $this->supplementalDriver->normalizeRow($row);
+ }
+
+
+ /********************* misc tools ****************d*g**/
+
+
+ /**
+ * Displays complete result set as HTML table for debug purposes.
+ * @return void
+ */
+ public function dump()
+ {
+ Helpers::dumpResult($this);
+ }
+
+
+ /********************* interface Iterator ****************d*g**/
+
+
+ public function rewind()
+ {
+ if ($this->result === FALSE) {
+ throw new Nette\InvalidStateException('Nette\\Database\\ResultSet implements only one way iterator.');
+ }
+ }
+
+
+ public function current()
+ {
+ return $this->result;
+ }
+
+
+ public function key()
+ {
+ return $this->resultKey;
+ }
+
+
+ public function next()
+ {
+ $this->result = FALSE;
+ }
+
+
+ public function valid()
+ {
+ if ($this->result) {
+ return TRUE;
+ }
+
+ return $this->fetch() !== FALSE;
+ }
+
+
+ /********************* interface IRowContainer ****************d*g**/
+
+
+ /**
+ * @inheritDoc
+ */
+ public function fetch()
+ {
+ $data = $this->pdoStatement ? $this->pdoStatement->fetch() : NULL;
+ if (!$data) {
+ $this->pdoStatement->closeCursor();
+ return FALSE;
+ }
+
+ $row = new Row;
+ foreach ($this->normalizeRow($data) as $key => $value) {
+ if ($key !== '') {
+ $row->$key = $value;
+ }
+ }
+
+ if ($this->result === NULL && count($data) !== $this->pdoStatement->columnCount()) {
+ trigger_error('Found duplicate columns in database result set.', E_USER_NOTICE);
+ }
+
+ $this->resultKey++;
+ return $this->result = $row;
+ }
+
+
+ /**
+ * Fetches single field.
+ * @param int
+ * @return mixed|FALSE
+ */
+ public function fetchField($column = 0)
+ {
+ $row = $this->fetch();
+ return $row ? $row[$column] : FALSE;
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public function fetchPairs($key = NULL, $value = NULL)
+ {
+ return Helpers::toPairs($this->fetchAll(), $key, $value);
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public function fetchAll()
+ {
+ if ($this->results === NULL) {
+ $this->results = iterator_to_array($this);
+ }
+ return $this->results;
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public function fetchAssoc($path)
+ {
+ return Nette\Utils\Arrays::associate($this->fetchAll(), $path);
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Row.php b/vendor/nette/database/src/Database/Row.php
new file mode 100755
index 0000000..c0ff31e
--- /dev/null
+++ b/vendor/nette/database/src/Database/Row.php
@@ -0,0 +1,56 @@
+$key;
+ }
+
+
+ /**
+ * Checks if $key exists.
+ * @param mixed key or index
+ * @return bool
+ */
+ public function offsetExists($key)
+ {
+ if (is_int($key)) {
+ return (bool) current(array_slice((array) $this, $key, 1));
+ }
+ return parent::offsetExists($key);
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/SqlLiteral.php b/vendor/nette/database/src/Database/SqlLiteral.php
new file mode 100755
index 0000000..eceb319
--- /dev/null
+++ b/vendor/nette/database/src/Database/SqlLiteral.php
@@ -0,0 +1,49 @@
+value = (string) $value;
+ $this->parameters = $parameters;
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getParameters()
+ {
+ return $this->parameters;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->value;
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/SqlPreprocessor.php b/vendor/nette/database/src/Database/SqlPreprocessor.php
new file mode 100755
index 0000000..4fb4c90
--- /dev/null
+++ b/vendor/nette/database/src/Database/SqlPreprocessor.php
@@ -0,0 +1,262 @@
+connection = $connection;
+ $this->driver = $connection->getSupplementalDriver();
+ }
+
+
+ /**
+ * @param array
+ * @return array of [sql, params]
+ */
+ public function process($params)
+ {
+ $this->params = $params;
+ $this->counter = 0;
+ $prev = -1;
+ $this->remaining = array();
+ $this->arrayMode = NULL;
+ $res = array();
+
+ while ($this->counter < count($params)) {
+ $param = $params[$this->counter++];
+
+ if (($this->counter === 2 && count($params) === 2) || !is_scalar($param)) {
+ $res[] = $this->formatValue($param, 'auto');
+ $this->arrayMode = NULL;
+
+ } elseif (is_string($param) && $this->counter > $prev + 1) {
+ $prev = $this->counter;
+ $this->arrayMode = NULL;
+ $res[] = Nette\Utils\Strings::replace(
+ $param,
+ '~\'[^\']*+\'|"[^"]*+"|\?[a-z]*|^\s*+(?:INSERT|REPLACE)\b|\b(?:SET|WHERE|HAVING|ORDER BY|GROUP BY|KEY UPDATE)(?=[\s?]*+\z)|/\*.*?\*/|--[^\n]*~si',
+ array($this, 'callback')
+ );
+ } else {
+ throw new Nette\InvalidArgumentException('There are more parameters than placeholders.');
+ }
+ }
+
+ return array(implode(' ', $res), $this->remaining);
+ }
+
+
+ /** @internal */
+ public function callback($m)
+ {
+ $m = $m[0];
+ if ($m[0] === '?') { // placeholder
+ if ($this->counter >= count($this->params)) {
+ throw new Nette\InvalidArgumentException('There are more placeholders than passed parameters.');
+ }
+ return $this->formatValue($this->params[$this->counter++], substr($m, 1) ?: 'auto');
+
+ } elseif ($m[0] === "'" || $m[0] === '"' || $m[0] === '/' || $m[0] === '-') { // string or comment
+ return $m;
+
+ } else { // command
+ static $modes = array(
+ 'INSERT' => 'values',
+ 'REPLACE' => 'values',
+ 'KEY UPDATE' => 'set',
+ 'SET' => 'set',
+ 'WHERE' => 'and',
+ 'HAVING' => 'and',
+ 'ORDER BY' => 'order',
+ 'GROUP BY' => 'order',
+ );
+ $this->arrayMode = $modes[ltrim(strtoupper($m))];
+ return $m;
+ }
+ }
+
+
+ private function formatValue($value, $mode = NULL)
+ {
+ if (!$mode || $mode === 'auto') {
+ if (is_string($value)) {
+ if (strlen($value) > 20) {
+ $this->remaining[] = $value;
+ return '?';
+
+ } else {
+ return $this->connection->quote($value);
+ }
+
+ } elseif (is_int($value)) {
+ return (string) $value;
+
+ } elseif (is_float($value)) {
+ return rtrim(rtrim(number_format($value, 10, '.', ''), '0'), '.');
+
+ } elseif (is_bool($value)) {
+ return $this->driver->formatBool($value);
+
+ } elseif ($value === NULL) {
+ return 'NULL';
+
+ } elseif ($value instanceof Table\IRow) {
+ return $value->getPrimary();
+
+ } elseif ($value instanceof SqlLiteral) {
+ $prep = clone $this;
+ list($res, $params) = $prep->process(array_merge(array($value->__toString()), $value->getParameters()));
+ $this->remaining = array_merge($this->remaining, $params);
+ return $res;
+
+ } elseif ($value instanceof \DateTime || $value instanceof \DateTimeInterface) {
+ return $this->driver->formatDateTime($value);
+
+ } elseif ($value instanceof \DateInterval) {
+ return $this->driver->formatDateInterval($value);
+
+ } elseif (is_object($value) && method_exists($value, '__toString')) {
+ return $this->formatValue((string) $value);
+
+ } elseif (is_resource($value)) {
+ $this->remaining[] = $value;
+ return '?';
+ }
+
+ } elseif ($mode === 'name') {
+ if (!is_string($value)) {
+ $type = gettype($value);
+ throw new Nette\InvalidArgumentException("Placeholder ?$mode expects string, $type given.");
+ }
+ return $this->delimite($value);
+ }
+
+ if ($value instanceof \Traversable && !$value instanceof Table\IRow) {
+ $value = iterator_to_array($value);
+ }
+
+ if (is_array($value)) {
+ $vx = $kx = array();
+ if ($mode === 'auto') {
+ $mode = $this->arrayMode;
+ }
+
+ if ($mode === 'values') { // (key, key, ...) VALUES (value, value, ...)
+ if (array_key_exists(0, $value)) { // multi-insert
+ foreach ($value[0] as $k => $v) {
+ $kx[] = $this->delimite($k);
+ }
+ foreach ($value as $val) {
+ $vx2 = array();
+ foreach ($val as $v) {
+ $vx2[] = $this->formatValue($v);
+ }
+ $vx[] = implode(', ', $vx2);
+ }
+ $select = $this->driver->isSupported(ISupplementalDriver::SUPPORT_MULTI_INSERT_AS_SELECT);
+ return '(' . implode(', ', $kx) . ($select ? ') SELECT ' : ') VALUES (')
+ . implode($select ? ' UNION ALL SELECT ' : '), (', $vx) . ($select ? '' : ')');
+ }
+
+ foreach ($value as $k => $v) {
+ $kx[] = $this->delimite($k);
+ $vx[] = $this->formatValue($v);
+ }
+ return '(' . implode(', ', $kx) . ') VALUES (' . implode(', ', $vx) . ')';
+
+ } elseif (!$mode || $mode === 'set') {
+ foreach ($value as $k => $v) {
+ if (is_int($k)) { // value, value, ... OR (1, 2), (3, 4)
+ $vx[] = is_array($v) ? '(' . $this->formatValue($v) . ')' : $this->formatValue($v);
+ } elseif (substr($k, -1) === '=') { // key+=value, key-=value, ...
+ $k2 = $this->delimite(substr($k, 0, -2));
+ $vx[] = $k2 . '=' . $k2 . ' ' . substr($k, -2, 1) . ' ' . $this->formatValue($v);
+ } else { // key=value, key=value, ...
+ $vx[] = $this->delimite($k) . '=' . $this->formatValue($v);
+ }
+ }
+ return implode(', ', $vx);
+
+ } elseif ($mode === 'and' || $mode === 'or') { // (key [operator] value) AND ...
+ foreach ($value as $k => $v) {
+ if (is_int($k)) {
+ $vx[] = $this->formatValue($v);
+ continue;
+ }
+ list($k, $operator) = explode(' ', $k . ' ');
+ $k = $this->delimite($k);
+ if (is_array($v)) {
+ if ($v) {
+ $vx[] = $k . ' ' . ($operator ? $operator . ' ' : '') . 'IN (' . $this->formatValue(array_values($v)) . ')';
+ } elseif ($operator === 'NOT') {
+ } else {
+ $vx[] = '1=0';
+ }
+ } else {
+ $v = $this->formatValue($v);
+ $vx[] = $k . ' ' . ($operator ?: ($v === 'NULL' ? 'IS' : '=')) . ' ' . $v;
+ }
+ }
+ return $value ? '(' . implode(') ' . strtoupper($mode) . ' (', $vx) . ')' : '1=1';
+
+ } elseif ($mode === 'order') { // key, key DESC, ...
+ foreach ($value as $k => $v) {
+ $vx[] = $this->delimite($k) . ($v > 0 ? '' : ' DESC');
+ }
+ return implode(', ', $vx);
+
+ } else {
+ throw new Nette\InvalidArgumentException("Unknown placeholder ?$mode.");
+ }
+
+ } elseif (in_array($mode, array('and', 'or', 'set', 'values', 'order'), TRUE)) {
+ $type = gettype($value);
+ throw new Nette\InvalidArgumentException("Placeholder ?$mode expects array or Traversable object, $type given.");
+
+ } elseif ($mode && $mode !== 'auto') {
+ throw new Nette\InvalidArgumentException("Unknown placeholder ?$mode.");
+
+ } else {
+ throw new Nette\InvalidArgumentException('Unexpected type of parameter: ' . (is_object($value) ? get_class($value) : gettype($value)));
+ }
+ }
+
+
+ private function delimite($name)
+ {
+ return implode('.', array_map(array($this->driver, 'delimite'), explode('.', $name)));
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Structure.php b/vendor/nette/database/src/Database/Structure.php
new file mode 100755
index 0000000..185bb74
--- /dev/null
+++ b/vendor/nette/database/src/Database/Structure.php
@@ -0,0 +1,253 @@
+connection = $connection;
+ $this->cache = new Nette\Caching\Cache($cacheStorage, 'Nette.Database.Structure.' . md5($this->connection->getDsn()));
+ }
+
+
+ public function getTables()
+ {
+ $this->needStructure();
+ return $this->structure['tables'];
+ }
+
+
+ public function getColumns($table)
+ {
+ $this->needStructure();
+ $table = $this->resolveFQTableName($table);
+
+ return $this->structure['columns'][$table];
+ }
+
+
+ public function getPrimaryKey($table)
+ {
+ $this->needStructure();
+ $table = $this->resolveFQTableName($table);
+
+ if (!isset($this->structure['primary'][$table])) {
+ return NULL;
+ }
+
+ return $this->structure['primary'][$table];
+ }
+
+
+ public function getPrimaryKeySequence($table)
+ {
+ $this->needStructure();
+ $table = $this->resolveFQTableName($table);
+
+ if (!$this->connection->getSupplementalDriver()->isSupported(ISupplementalDriver::SUPPORT_SEQUENCE)) {
+ return NULL;
+ }
+
+ $primary = $this->getPrimaryKey($table);
+ if (!$primary || is_array($primary)) {
+ return NULL;
+ }
+
+ foreach ($this->structure['columns'][$table] as $columnMeta) {
+ if ($columnMeta['name'] === $primary) {
+ return isset($columnMeta['vendor']['sequence']) ? $columnMeta['vendor']['sequence'] : NULL;
+ }
+ }
+
+ return NULL;
+ }
+
+
+ public function getHasManyReference($table, $targetTable = NULL)
+ {
+ $this->needStructure();
+ $table = $this->resolveFQTableName($table);
+
+ if ($targetTable) {
+ $targetTable = $this->resolveFQTableName($targetTable);
+ foreach ($this->structure['hasMany'][$table] as $key => $value) {
+ if (strtolower($key) === $targetTable) {
+ return $this->structure['hasMany'][$table][$key];
+ }
+ }
+
+ return NULL;
+
+ } else {
+ if (!isset($this->structure['hasMany'][$table])) {
+ return array();
+ }
+ return $this->structure['hasMany'][$table];
+ }
+ }
+
+
+ public function getBelongsToReference($table, $column = NULL)
+ {
+ $this->needStructure();
+ $table = $this->resolveFQTableName($table);
+
+ if ($column) {
+ $column = strtolower($column);
+ if (!isset($this->structure['belongsTo'][$table][$column])) {
+ return NULL;
+ }
+ return $this->structure['belongsTo'][$table][$column];
+
+ } else {
+ if (!isset($this->structure['belongsTo'][$table])) {
+ return array();
+ }
+ return $this->structure['belongsTo'][$table];
+ }
+ }
+
+
+ public function rebuild()
+ {
+ $this->structure = $this->loadStructure();
+ $this->cache->save('structure', $this->structure);
+ }
+
+
+ public function isRebuilt()
+ {
+ return $this->isRebuilt;
+ }
+
+
+ protected function needStructure()
+ {
+ if ($this->structure !== NULL) {
+ return;
+ }
+
+ $this->structure = $this->cache->load('structure', array($this, 'loadStructure'));
+ }
+
+
+ /**
+ * @internal
+ */
+ public function loadStructure()
+ {
+ $driver = $this->connection->getSupplementalDriver();
+
+ $structure = array();
+ $structure['tables'] = $driver->getTables();
+
+ foreach ($structure['tables'] as $tablePair) {
+ if ($tablePair['view']) {
+ continue;
+ }
+
+ if (isset($tablePair['fullName'])) {
+ $table = $tablePair['fullName'];
+ $structure['aliases'][strtolower($tablePair['name'])] = strtolower($table);
+ } else {
+ $table = $tablePair['name'];
+ }
+
+ $structure['columns'][strtolower($table)] = $columns = $driver->getColumns($table);
+ $structure['primary'][strtolower($table)] = $this->analyzePrimaryKey($columns);
+ $this->analyzeForeignKeys($structure, $table);
+ }
+
+ if (isset($structure['hasMany'])) {
+ foreach ($structure['hasMany'] as & $table) {
+ uksort($table, function ($a, $b) {
+ return strlen($a) - strlen($b);
+ });
+ }
+ }
+
+ $this->isRebuilt = TRUE;
+
+ return $structure;
+ }
+
+
+ protected function analyzePrimaryKey(array $columns)
+ {
+ $primary = array();
+ foreach ($columns as $column) {
+ if ($column['primary']) {
+ $primary[] = $column['name'];
+ }
+ }
+
+ if (count($primary) === 0) {
+ return NULL;
+ } elseif (count($primary) === 1) {
+ return reset($primary);
+ } else {
+ return $primary;
+ }
+ }
+
+
+ protected function analyzeForeignKeys(& $structure, $table)
+ {
+ foreach ($this->connection->getSupplementalDriver()->getForeignKeys($table) as $row) {
+ $structure['belongsTo'][strtolower($table)][$row['local']] = $row['table'];
+ $structure['hasMany'][strtolower($row['table'])][$table][] = $row['local'];
+ }
+
+ if (isset($structure['belongsTo'][$table])) {
+ uksort($structure['belongsTo'][$table], function ($a, $b) {
+ return strlen($a) - strlen($b);
+ });
+ }
+ }
+
+
+ protected function resolveFQTableName($table)
+ {
+ $name = strtolower($table);
+ if (isset($this->structure['columns'][$name])) {
+ return $name;
+ }
+
+ if (isset($this->structure['aliases'][$name])) {
+ return $this->structure['aliases'][$name];
+ }
+
+ if (!$this->isRebuilt()) {
+ $this->rebuild();
+ return $this->resolveFQTableName($table);
+ }
+
+ throw new Nette\InvalidArgumentException("Table '$name' does not exist.");
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Table/ActiveRow.php b/vendor/nette/database/src/Database/Table/ActiveRow.php
new file mode 100755
index 0000000..467762d
--- /dev/null
+++ b/vendor/nette/database/src/Database/Table/ActiveRow.php
@@ -0,0 +1,331 @@
+data = $data;
+ $this->table = $table;
+ }
+
+
+ /**
+ * @internal
+ */
+ public function setTable(Selection $table)
+ {
+ $this->table = $table;
+ }
+
+
+ /**
+ * @internal
+ */
+ public function getTable()
+ {
+ return $this->table;
+ }
+
+
+ public function __toString()
+ {
+ try {
+ return (string) $this->getPrimary();
+ } catch (\Exception $e) {
+ if (func_num_args()) {
+ throw $e;
+ }
+ trigger_error("Exception in " . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
+ }
+ }
+
+
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ $this->accessColumn(NULL);
+ return $this->data;
+ }
+
+
+ /**
+ * Returns primary key value.
+ * @param bool
+ * @return mixed possible int, string, array, object (Nette\Utils\DateTime)
+ */
+ public function getPrimary($need = TRUE)
+ {
+ $primary = $this->table->getPrimary($need);
+ if ($primary === NULL) {
+ return NULL;
+
+ } elseif (!is_array($primary)) {
+ if (isset($this->data[$primary])) {
+ return $this->data[$primary];
+ } elseif ($need) {
+ throw new Nette\InvalidStateException("Row does not contain primary $primary column data.");
+ } else {
+ return NULL;
+ }
+
+ } else {
+ $primaryVal = array();
+ foreach ($primary as $key) {
+ if (!isset($this->data[$key])) {
+ if ($need) {
+ throw new Nette\InvalidStateException("Row does not contain primary $key column data.");
+ } else {
+ return NULL;
+ }
+ }
+ $primaryVal[$key] = $this->data[$key];
+ }
+ return $primaryVal;
+ }
+ }
+
+
+ /**
+ * Returns row signature (composition of primary keys)
+ * @param bool
+ * @return string
+ */
+ public function getSignature($need = TRUE)
+ {
+ return implode('|', (array) $this->getPrimary($need));
+ }
+
+
+ /**
+ * Returns referenced row.
+ * @param string
+ * @param string
+ * @return IRow or NULL if the row does not exist
+ */
+ public function ref($key, $throughColumn = NULL)
+ {
+ $row = $this->table->getReferencedTable($this, $key, $throughColumn);
+ if ($row === FALSE) {
+ throw new Nette\MemberAccessException("No reference found for \${$this->table->name}->ref($key).");
+ }
+
+ return $row;
+ }
+
+
+ /**
+ * Returns referencing rows.
+ * @param string
+ * @param string
+ * @return GroupedSelection
+ */
+ public function related($key, $throughColumn = NULL)
+ {
+ $groupedSelection = $this->table->getReferencingTable($key, $throughColumn, $this[$this->table->getPrimary()]);
+ if (!$groupedSelection) {
+ throw new Nette\MemberAccessException("No reference found for \${$this->table->name}->related($key).");
+ }
+
+ return $groupedSelection;
+ }
+
+
+ /**
+ * Updates row.
+ * @param array|\Traversable (column => value)
+ * @return bool
+ */
+ public function update($data)
+ {
+ if ($data instanceof \Traversable) {
+ $data = iterator_to_array($data);
+ }
+
+ $primary = $this->getPrimary();
+ if (!is_array($primary)) {
+ $primary = array($this->table->getPrimary() => $primary);
+ }
+
+ $selection = $this->table->createSelectionInstance()
+ ->wherePrimary($primary);
+
+ if ($selection->update($data)) {
+ if ($tmp = array_intersect_key($data, $primary)) {
+ $selection = $this->table->createSelectionInstance()
+ ->wherePrimary($tmp + $primary);
+ }
+ $selection->select('*');
+ if (($row = $selection->fetch()) === FALSE) {
+ throw new Nette\InvalidStateException('Database refetch failed; row does not exist!');
+ }
+ $this->data = $row->data;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+
+ /**
+ * Deletes row.
+ * @return int number of affected rows
+ */
+ public function delete()
+ {
+ $res = $this->table->createSelectionInstance()
+ ->wherePrimary($this->getPrimary())
+ ->delete();
+
+ if ($res > 0 && ($signature = $this->getSignature(FALSE))) {
+ unset($this->table[$signature]);
+ }
+
+ return $res;
+ }
+
+
+ /********************* interface IteratorAggregate ****************d*g**/
+
+
+ public function getIterator()
+ {
+ $this->accessColumn(NULL);
+ return new \ArrayIterator($this->data);
+ }
+
+
+ /********************* interface ArrayAccess & magic accessors ****************d*g**/
+
+
+ /**
+ * Stores value in column.
+ * @param string column name
+ * @param string value
+ * @return void
+ */
+ public function offsetSet($key, $value)
+ {
+ $this->__set($key, $value);
+ }
+
+
+ /**
+ * Returns value of column.
+ * @param string column name
+ * @return string
+ */
+ public function offsetGet($key)
+ {
+ return $this->__get($key);
+ }
+
+
+ /**
+ * Tests if column exists.
+ * @param string column name
+ * @return bool
+ */
+ public function offsetExists($key)
+ {
+ return $this->__isset($key);
+ }
+
+
+ /**
+ * Removes column from data.
+ * @param string column name
+ * @return void
+ */
+ public function offsetUnset($key)
+ {
+ $this->__unset($key);
+ }
+
+
+ public function __set($key, $value)
+ {
+ throw new Nette\DeprecatedException('ActiveRow is read-only; use update() method instead.');
+ }
+
+
+ public function &__get($key)
+ {
+ $this->accessColumn($key);
+ if (array_key_exists($key, $this->data)) {
+ return $this->data[$key];
+ }
+
+ $referenced = $this->table->getReferencedTable($this, $key);
+ if ($referenced !== FALSE) {
+ $this->accessColumn($key, FALSE);
+ return $referenced;
+ }
+
+ $this->removeAccessColumn($key);
+ throw new Nette\MemberAccessException("Cannot read an undeclared column '$key'.");
+ }
+
+
+ public function __isset($key)
+ {
+ $this->accessColumn($key);
+ if (array_key_exists($key, $this->data)) {
+ return isset($this->data[$key]);
+ }
+ $this->removeAccessColumn($key);
+ return FALSE;
+ }
+
+
+ public function __unset($key)
+ {
+ throw new Nette\DeprecatedException('ActiveRow is read-only.');
+ }
+
+
+ /**
+ * @internal
+ */
+ public function accessColumn($key, $selectColumn = TRUE)
+ {
+ $this->table->accessColumn($key, $selectColumn);
+ if ($this->table->getDataRefreshed() && !$this->dataRefreshed) {
+ $this->data = $this->table[$this->getSignature()]->data;
+ $this->dataRefreshed = TRUE;
+ }
+ return array_key_exists($key, $this->data);
+ }
+
+
+ protected function removeAccessColumn($key)
+ {
+ $this->table->removeAccessColumn($key);
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Table/GroupedSelection.php b/vendor/nette/database/src/Database/Table/GroupedSelection.php
new file mode 100755
index 0000000..57d016b
--- /dev/null
+++ b/vendor/nette/database/src/Database/Table/GroupedSelection.php
@@ -0,0 +1,251 @@
+refTable = $refTable;
+ $this->column = $column;
+ parent::__construct($context, $conventions, $tableName, $cacheStorage);
+ }
+
+
+ /**
+ * Sets active group.
+ * @internal
+ * @param int primary key of grouped rows
+ * @return GroupedSelection
+ */
+ public function setActive($active)
+ {
+ $this->active = $active;
+ return $this;
+ }
+
+
+ public function select($columns)
+ {
+ if (!$this->sqlBuilder->getSelect()) {
+ $this->sqlBuilder->addSelect("$this->name.$this->column");
+ }
+
+ return call_user_func_array('parent::select', func_get_args());
+ }
+
+
+ public function order($columns)
+ {
+ if (!$this->sqlBuilder->getOrder()) {
+ // improve index utilization
+ $this->sqlBuilder->addOrder("$this->name.$this->column" . (preg_match('~\bDESC\z~i', $columns) ? ' DESC' : ''));
+ }
+
+ return call_user_func_array('parent::order', func_get_args());
+ }
+
+
+ /********************* aggregations ****************d*g**/
+
+
+ public function aggregation($function)
+ {
+ $aggregation = & $this->getRefTable($refPath)->aggregation[$refPath . $function . $this->getSql() . json_encode($this->sqlBuilder->getParameters())];
+
+ if ($aggregation === NULL) {
+ $aggregation = array();
+
+ $selection = $this->createSelectionInstance();
+ $selection->getSqlBuilder()->importConditions($this->getSqlBuilder());
+ $selection->select($function);
+ $selection->select("$this->name.$this->column");
+ $selection->group("$this->name.$this->column");
+
+ foreach ($selection as $row) {
+ $aggregation[$row[$this->column]] = $row;
+ }
+ }
+
+ if (isset($aggregation[$this->active])) {
+ foreach ($aggregation[$this->active] as $val) {
+ return $val;
+ }
+ }
+ }
+
+
+ public function count($column = NULL)
+ {
+ $return = parent::count($column);
+ return isset($return) ? $return : 0;
+ }
+
+
+ /********************* internal ****************d*g**/
+
+
+ protected function execute()
+ {
+ if ($this->rows !== NULL) {
+ $this->observeCache = $this;
+ return;
+ }
+
+ $accessedColumns = $this->accessedColumns;
+ $this->loadRefCache();
+
+ if (!isset($this->refCacheCurrent['data'])) {
+ // we have not fetched any data yet => init accessedColumns by cached accessedColumns
+ $this->accessedColumns = $accessedColumns;
+
+ $limit = $this->sqlBuilder->getLimit();
+ $rows = count($this->refTable->rows);
+ if ($limit && $rows > 1) {
+ $this->sqlBuilder->setLimit(NULL, NULL);
+ }
+ parent::execute();
+ $this->sqlBuilder->setLimit($limit, NULL);
+ $data = array();
+ $offset = array();
+ $this->accessColumn($this->column);
+ foreach ((array) $this->rows as $key => $row) {
+ $ref = & $data[$row[$this->column]];
+ $skip = & $offset[$row[$this->column]];
+ if ($limit === NULL || $rows <= 1 || (count($ref) < $limit && $skip >= $this->sqlBuilder->getOffset())) {
+ $ref[$key] = $row;
+ } else {
+ unset($this->rows[$key]);
+ }
+ $skip++;
+ unset($ref, $skip);
+ }
+
+ $this->refCacheCurrent['data'] = $data;
+ $this->data = & $this->refCacheCurrent['data'][$this->active];
+ }
+
+ $this->observeCache = $this;
+ if ($this->data === NULL) {
+ $this->data = array();
+ } else {
+ foreach ($this->data as $row) {
+ $row->setTable($this); // injects correct parent GroupedSelection
+ }
+ reset($this->data);
+ }
+ }
+
+
+ protected function getRefTable(& $refPath)
+ {
+ $refObj = $this->refTable;
+ $refPath = $this->name . '.';
+ while ($refObj instanceof self) {
+ $refPath .= $refObj->name . '.';
+ $refObj = $refObj->refTable;
+ }
+
+ return $refObj;
+ }
+
+
+ protected function loadRefCache()
+ {
+ $hash = $this->getSpecificCacheKey();
+ $referencing = & $this->refCache['referencing'][$this->getGeneralCacheKey()];
+ $this->observeCache = & $referencing['observeCache'];
+ $this->refCacheCurrent = & $referencing[$hash];
+ $this->accessedColumns = & $referencing[$hash]['accessed'];
+ $this->specificCacheKey = & $referencing[$hash]['specificCacheKey'];
+ $this->rows = & $referencing[$hash]['rows'];
+
+ if (isset($referencing[$hash]['data'][$this->active])) {
+ $this->data = & $referencing[$hash]['data'][$this->active];
+ }
+ }
+
+
+ /********************* manipulation ****************d*g**/
+
+
+ public function insert($data)
+ {
+ if ($data instanceof \Traversable && !$data instanceof Selection) {
+ $data = iterator_to_array($data);
+ }
+
+ if (Nette\Utils\Arrays::isList($data)) {
+ foreach (array_keys($data) as $key) {
+ $data[$key][$this->column] = $this->active;
+ }
+ } else {
+ $data[$this->column] = $this->active;
+ }
+
+ return parent::insert($data);
+ }
+
+
+ public function update($data)
+ {
+ $builder = $this->sqlBuilder;
+
+ $this->sqlBuilder = clone $this->sqlBuilder;
+ $this->where($this->column, $this->active);
+ $return = parent::update($data);
+
+ $this->sqlBuilder = $builder;
+ return $return;
+ }
+
+
+ public function delete()
+ {
+ $builder = $this->sqlBuilder;
+
+ $this->sqlBuilder = clone $this->sqlBuilder;
+ $this->where($this->column, $this->active);
+ $return = parent::delete();
+
+ $this->sqlBuilder = $builder;
+ return $return;
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Table/IRow.php b/vendor/nette/database/src/Database/Table/IRow.php
new file mode 100755
index 0000000..266ba52
--- /dev/null
+++ b/vendor/nette/database/src/Database/Table/IRow.php
@@ -0,0 +1,31 @@
+ IRow] format */
+ protected $rows;
+
+ /** @var IRow[] modifiable data in [primary key => IRow] format */
+ protected $data;
+
+ /** @var bool */
+ protected $dataRefreshed = FALSE;
+
+ /** @var mixed cache array of Selection and GroupedSelection prototypes */
+ protected $globalRefCache;
+
+ /** @var mixed */
+ protected $refCache;
+
+ /** @var string */
+ protected $generalCacheKey;
+
+ /** @var array */
+ protected $generalCacheTraceKey;
+
+ /** @var string */
+ protected $specificCacheKey;
+
+ /** @var array of [conditions => [key => IRow]]; used by GroupedSelection */
+ protected $aggregation = array();
+
+ /** @var array of touched columns */
+ protected $accessedColumns;
+
+ /** @var array of earlier touched columns */
+ protected $previousAccessedColumns;
+
+ /** @var bool should instance observe accessed columns caching */
+ protected $observeCache = FALSE;
+
+ /** @var array of primary key values */
+ protected $keys = array();
+
+
+ /**
+ * Creates filtered table representation.
+ * @param Context
+ * @param IConventions
+ * @param string table name
+ * @param Nette\Caching\IStorage|NULL
+ */
+ public function __construct(Context $context, IConventions $conventions, $tableName, Nette\Caching\IStorage $cacheStorage = NULL)
+ {
+ $this->context = $context;
+ $this->conventions = $conventions;
+ $this->name = $tableName;
+
+ $this->cache = $cacheStorage ? new Nette\Caching\Cache($cacheStorage, 'Nette.Database.' . md5($context->getConnection()->getDsn())) : NULL;
+ $this->primary = $conventions->getPrimary($tableName);
+ $this->sqlBuilder = new SqlBuilder($tableName, $context);
+ $this->refCache = & $this->getRefTable($refPath)->globalRefCache[$refPath];
+ }
+
+
+ public function __destruct()
+ {
+ $this->saveCacheState();
+ }
+
+
+ public function __clone()
+ {
+ $this->sqlBuilder = clone $this->sqlBuilder;
+ }
+
+
+ /** @deprecated */
+ public function getConnection()
+ {
+ trigger_error(__METHOD__ . '() is deprecated; use DI container to autowire Nette\Database\Connection instead.', E_USER_DEPRECATED);
+ return $this->context->getConnection();
+ }
+
+
+ /** @deprecated */
+ public function getDatabaseReflection()
+ {
+ trigger_error(__METHOD__ . '() is deprecated; use DI container to autowire Nette\Database\IConventions instead.', E_USER_DEPRECATED);
+ return $this->conventions;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+
+ /**
+ * @param bool
+ * @return string|array
+ */
+ public function getPrimary($need = TRUE)
+ {
+ if ($this->primary === NULL && $need) {
+ throw new \LogicException("Table '{$this->name}' does not have a primary key.");
+ }
+ return $this->primary;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getPrimarySequence()
+ {
+ if ($this->primarySequence === FALSE) {
+ $this->primarySequence = $this->context->getStructure()->getPrimaryKeySequence($this->name);
+ }
+
+ return $this->primarySequence;
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function setPrimarySequence($sequence)
+ {
+ $this->primarySequence = $sequence;
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getSql()
+ {
+ return $this->sqlBuilder->buildSelectQuery($this->getPreviousAccessedColumns());
+ }
+
+
+ /**
+ * Loads cache of previous accessed columns and returns it.
+ * @internal
+ * @return array|false
+ */
+ public function getPreviousAccessedColumns()
+ {
+ if ($this->cache && $this->previousAccessedColumns === NULL) {
+ $this->accessedColumns = $this->previousAccessedColumns = $this->cache->load($this->getGeneralCacheKey());
+ if ($this->previousAccessedColumns === NULL) {
+ $this->previousAccessedColumns = array();
+ }
+ }
+
+ return array_keys(array_filter((array) $this->previousAccessedColumns));
+ }
+
+
+ /**
+ * @internal
+ * @return SqlBuilder
+ */
+ public function getSqlBuilder()
+ {
+ return $this->sqlBuilder;
+ }
+
+
+ /********************* quick access ****************d*g**/
+
+
+ /**
+ * Returns row specified by primary key.
+ * @param mixed primary key
+ * @return IRow or FALSE if there is no such row
+ */
+ public function get($key)
+ {
+ $clone = clone $this;
+ return $clone->wherePrimary($key)->fetch();
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public function fetch()
+ {
+ $this->execute();
+ $return = current($this->data);
+ next($this->data);
+ return $return;
+ }
+
+
+ /**
+ * Fetches single field.
+ * @param string|NULL
+ * @return mixed|FALSE
+ */
+ public function fetchField($column = NULL)
+ {
+ if ($column) {
+ $this->select($column);
+ }
+
+ $row = $this->fetch();
+ if ($row) {
+ return $column ? $row[$column] : array_values($row->toArray())[0];
+ }
+
+ return FALSE;
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public function fetchPairs($key = NULL, $value = NULL)
+ {
+ return Nette\Database\Helpers::toPairs($this->fetchAll(), $key, $value);
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public function fetchAll()
+ {
+ return iterator_to_array($this);
+ }
+
+
+ /**
+ * @inheritDoc
+ */
+ public function fetchAssoc($path)
+ {
+ $rows = array_map('iterator_to_array', $this->fetchAll());
+ return Nette\Utils\Arrays::associate($rows, $path);
+ }
+
+
+ /********************* sql selectors ****************d*g**/
+
+
+ /**
+ * Adds select clause, more calls appends to the end.
+ * @param string for example "column, MD5(column) AS column_md5"
+ * @return self
+ */
+ public function select($columns)
+ {
+ $this->emptyResultSet();
+ call_user_func_array(array($this->sqlBuilder, 'addSelect'), func_get_args());
+ return $this;
+ }
+
+
+ /**
+ * Adds condition for primary key.
+ * @param mixed
+ * @return self
+ */
+ public function wherePrimary($key)
+ {
+ if (is_array($this->primary) && Nette\Utils\Arrays::isList($key)) {
+ if (isset($key[0]) && is_array($key[0])) {
+ $this->where($this->primary, $key);
+ } else {
+ foreach ($this->primary as $i => $primary) {
+ $this->where($this->name . '.' . $primary, $key[$i]);
+ }
+ }
+ } elseif (is_array($key) && !Nette\Utils\Arrays::isList($key)) { // key contains column names
+ $this->where($key);
+ } else {
+ $this->where($this->name . '.' . $this->getPrimary(), $key);
+ }
+
+ return $this;
+ }
+
+
+ /**
+ * Adds where condition, more calls appends with AND.
+ * @param string condition possibly containing ?
+ * @param mixed
+ * @param mixed ...
+ * @return self
+ */
+ public function where($condition, $parameters = array())
+ {
+ if (is_array($condition) && $parameters === array()) { // where(array('column1' => 1, 'column2 > ?' => 2))
+ foreach ($condition as $key => $val) {
+ if (is_int($key)) {
+ $this->where($val); // where('full condition')
+ } else {
+ $this->where($key, $val); // where('column', 1)
+ }
+ }
+ return $this;
+ }
+
+ $this->emptyResultSet();
+ call_user_func_array(array($this->sqlBuilder, 'addWhere'), func_get_args());
+ return $this;
+ }
+
+
+ /**
+ * Adds order clause, more calls appends to the end.
+ * @param string for example 'column1, column2 DESC'
+ * @return self
+ */
+ public function order($columns)
+ {
+ $this->emptyResultSet();
+ call_user_func_array(array($this->sqlBuilder, 'addOrder'), func_get_args());
+ return $this;
+ }
+
+
+ /**
+ * Sets limit clause, more calls rewrite old values.
+ * @param int
+ * @param int
+ * @return self
+ */
+ public function limit($limit, $offset = NULL)
+ {
+ $this->emptyResultSet();
+ $this->sqlBuilder->setLimit($limit, $offset);
+ return $this;
+ }
+
+
+ /**
+ * Sets offset using page number, more calls rewrite old values.
+ * @param int
+ * @param int
+ * @return self
+ */
+ public function page($page, $itemsPerPage, & $numOfPages = NULL)
+ {
+ if (func_num_args() > 2) {
+ $numOfPages = (int) ceil($this->count('*') / $itemsPerPage);
+ }
+ return $this->limit($itemsPerPage, ($page - 1) * $itemsPerPage);
+ }
+
+
+ /**
+ * Sets group clause, more calls rewrite old value.
+ * @param string
+ * @return self
+ */
+ public function group($columns)
+ {
+ $this->emptyResultSet();
+ call_user_func_array(array($this->sqlBuilder, 'setGroup'), func_get_args());
+ return $this;
+ }
+
+
+ /**
+ * Sets having clause, more calls rewrite old value.
+ * @param string
+ * @return self
+ */
+ public function having($having)
+ {
+ $this->emptyResultSet();
+ call_user_func_array(array($this->sqlBuilder, 'setHaving'), func_get_args());
+ return $this;
+ }
+
+
+ /********************* aggregations ****************d*g**/
+
+
+ /**
+ * Executes aggregation function.
+ * @param string select call in "FUNCTION(column)" format
+ * @return string
+ */
+ public function aggregation($function)
+ {
+ $selection = $this->createSelectionInstance();
+ $selection->getSqlBuilder()->importConditions($this->getSqlBuilder());
+ $selection->select($function);
+ foreach ($selection->fetch() as $val) {
+ return $val;
+ }
+ }
+
+
+ /**
+ * Counts number of rows.
+ * @param string if it is not provided returns count of result rows, otherwise runs new sql counting query
+ * @return int
+ */
+ public function count($column = NULL)
+ {
+ if (!$column) {
+ $this->execute();
+ return count($this->data);
+ }
+ return $this->aggregation("COUNT($column)");
+ }
+
+
+ /**
+ * Returns minimum value from a column.
+ * @param string
+ * @return int
+ */
+ public function min($column)
+ {
+ return $this->aggregation("MIN($column)");
+ }
+
+
+ /**
+ * Returns maximum value from a column.
+ * @param string
+ * @return int
+ */
+ public function max($column)
+ {
+ return $this->aggregation("MAX($column)");
+ }
+
+
+ /**
+ * Returns sum of values in a column.
+ * @param string
+ * @return int
+ */
+ public function sum($column)
+ {
+ return $this->aggregation("SUM($column)");
+ }
+
+
+ /********************* internal ****************d*g**/
+
+
+ protected function execute()
+ {
+ if ($this->rows !== NULL) {
+ return;
+ }
+
+ $this->observeCache = $this;
+
+ if ($this->primary === NULL && $this->sqlBuilder->getSelect() === NULL) {
+ throw new Nette\InvalidStateException('Table with no primary key requires an explicit select clause.');
+ }
+
+ try {
+ $result = $this->query($this->getSql());
+
+ } catch (Nette\Database\DriverException $exception) {
+ if (!$this->sqlBuilder->getSelect() && $this->previousAccessedColumns) {
+ $this->previousAccessedColumns = FALSE;
+ $this->accessedColumns = array();
+ $result = $this->query($this->getSql());
+ } else {
+ throw $exception;
+ }
+ }
+
+ $this->rows = array();
+ $usedPrimary = TRUE;
+ foreach ($result->getPdoStatement() as $key => $row) {
+ $row = $this->createRow($result->normalizeRow($row));
+ $primary = $row->getSignature(FALSE);
+ $usedPrimary = $usedPrimary && $primary;
+ $this->rows[$primary ?: $key] = $row;
+ }
+ $this->data = $this->rows;
+
+ if ($usedPrimary && $this->accessedColumns !== FALSE) {
+ foreach ((array) $this->primary as $primary) {
+ $this->accessedColumns[$primary] = TRUE;
+ }
+ }
+ }
+
+
+ protected function createRow(array $row)
+ {
+ return new ActiveRow($row, $this);
+ }
+
+
+ public function createSelectionInstance($table = NULL)
+ {
+ return new self($this->context, $this->conventions, $table ?: $this->name, $this->cache ? $this->cache->getStorage() : NULL);
+ }
+
+
+ protected function createGroupedSelectionInstance($table, $column)
+ {
+ return new GroupedSelection($this->context, $this->conventions, $table, $column, $this, $this->cache ? $this->cache->getStorage() : NULL);
+ }
+
+
+ protected function query($query)
+ {
+ return $this->context->queryArgs($query, $this->sqlBuilder->getParameters());
+ }
+
+
+ protected function emptyResultSet($saveCache = TRUE)
+ {
+ if ($this->rows !== NULL && $saveCache) {
+ $this->saveCacheState();
+ }
+
+ if ($saveCache) {
+ // null only if missing some column
+ $this->generalCacheTraceKey = NULL;
+ }
+
+ $this->rows = NULL;
+ $this->specificCacheKey = NULL;
+ $this->generalCacheKey = NULL;
+ $this->refCache['referencingPrototype'] = array();
+ $this->refCache['referenced'] = array();
+ }
+
+
+ protected function saveCacheState()
+ {
+ if ($this->observeCache === $this && $this->cache && !$this->sqlBuilder->getSelect() && $this->accessedColumns !== $this->previousAccessedColumns) {
+ $previousAccessed = $this->cache->load($this->getGeneralCacheKey());
+ $accessed = $this->accessedColumns;
+ $needSave = is_array($accessed) && is_array($previousAccessed)
+ ? array_intersect_key($accessed, $previousAccessed) !== $accessed
+ : $accessed !== $previousAccessed;
+
+ if ($needSave) {
+ $save = is_array($accessed) && is_array($previousAccessed) ? $previousAccessed + $accessed : $accessed;
+ $this->cache->save($this->getGeneralCacheKey(), $save);
+ $this->previousAccessedColumns = NULL;
+ }
+ }
+ }
+
+
+ /**
+ * Returns Selection parent for caching.
+ * @return Selection
+ */
+ protected function getRefTable(& $refPath)
+ {
+ return $this;
+ }
+
+
+ /**
+ * Loads refCache references
+ */
+ protected function loadRefCache()
+ {
+ }
+
+
+ /**
+ * Returns general cache key independent on query parameters or sql limit
+ * Used e.g. for previously accessed columns caching
+ * @return string
+ */
+ protected function getGeneralCacheKey()
+ {
+ if ($this->generalCacheKey) {
+ return $this->generalCacheKey;
+ }
+
+ $key = array(__CLASS__, $this->name, $this->sqlBuilder->getConditions());
+ if (!$this->generalCacheTraceKey) {
+ $trace = array();
+ foreach (debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE) as $item) {
+ $trace[] = isset($item['file'], $item['line']) ? $item['file'] . $item['line'] : NULL;
+ };
+ $this->generalCacheTraceKey = $trace;
+ }
+
+ $key[] = $this->generalCacheTraceKey;
+ return $this->generalCacheKey = md5(serialize($key));
+ }
+
+
+ /**
+ * Returns object specific cache key dependent on query parameters
+ * Used e.g. for reference memory caching
+ * @return string
+ */
+ protected function getSpecificCacheKey()
+ {
+ if ($this->specificCacheKey) {
+ return $this->specificCacheKey;
+ }
+
+ return $this->specificCacheKey = md5($this->getSql() . json_encode($this->sqlBuilder->getParameters()));
+ }
+
+
+ /**
+ * @internal
+ * @param string|NULL column name or NULL to reload all columns
+ * @param bool
+ */
+ public function accessColumn($key, $selectColumn = TRUE)
+ {
+ if (!$this->cache) {
+ return;
+ }
+
+ if ($key === NULL) {
+ $this->accessedColumns = FALSE;
+ $currentKey = key((array) $this->data);
+ } elseif ($this->accessedColumns !== FALSE) {
+ $this->accessedColumns[$key] = $selectColumn;
+ }
+
+ if ($selectColumn && !$this->sqlBuilder->getSelect() && $this->previousAccessedColumns && ($key === NULL || !isset($this->previousAccessedColumns[$key]))) {
+ $this->previousAccessedColumns = array();
+
+ if ($this->sqlBuilder->getLimit()) {
+ $generalCacheKey = $this->generalCacheKey;
+ $sqlBuilder = $this->sqlBuilder;
+
+ $primaryValues = array();
+ foreach ((array) $this->rows as $row) {
+ $primary = $row->getPrimary();
+ $primaryValues[] = is_array($primary) ? array_values($primary) : $primary;
+ }
+
+ $this->emptyResultSet(FALSE);
+ $this->sqlBuilder = clone $this->sqlBuilder;
+ $this->sqlBuilder->setLimit(NULL, NULL);
+ $this->wherePrimary($primaryValues);
+
+ $this->generalCacheKey = $generalCacheKey;
+ $this->execute();
+ $this->sqlBuilder = $sqlBuilder;
+ } else {
+ $this->emptyResultSet(FALSE);
+ $this->execute();
+ }
+
+ $this->dataRefreshed = TRUE;
+
+ // move iterator to specific key
+ if (isset($currentKey)) {
+ while (key($this->data) !== $currentKey) {
+ next($this->data);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * @internal
+ * @param string
+ */
+ public function removeAccessColumn($key)
+ {
+ if ($this->cache && is_array($this->accessedColumns)) {
+ $this->accessedColumns[$key] = FALSE;
+ }
+ }
+
+
+ /**
+ * Returns if selection requeried for more columns.
+ * @return bool
+ */
+ public function getDataRefreshed()
+ {
+ return $this->dataRefreshed;
+ }
+
+
+ /********************* manipulation ****************d*g**/
+
+
+ /**
+ * Inserts row in a table.
+ * @param array|\Traversable|Selection array($column => $value)|\Traversable|Selection for INSERT ... SELECT
+ * @return IRow|int|bool Returns IRow or number of affected rows for Selection or table without primary key
+ */
+ public function insert($data)
+ {
+ if ($data instanceof self) {
+ $return = $this->context->queryArgs($this->sqlBuilder->buildInsertQuery() . ' ' . $data->getSql(), $data->getSqlBuilder()->getParameters());
+
+ } else {
+ if ($data instanceof \Traversable) {
+ $data = iterator_to_array($data);
+ }
+ $return = $this->context->query($this->sqlBuilder->buildInsertQuery() . ' ?values', $data);
+ }
+
+ $this->loadRefCache();
+
+ if ($data instanceof self || $this->primary === NULL) {
+ unset($this->refCache['referencing'][$this->getGeneralCacheKey()][$this->getSpecificCacheKey()]);
+ return $return->getRowCount();
+ }
+
+ $primarySequenceName = $this->getPrimarySequence();
+ $primaryKey = $this->context->getInsertId(
+ !empty($primarySequenceName)
+ ? $this->context->getConnection()->getSupplementalDriver()->delimite($primarySequenceName)
+ : $primarySequenceName
+ );
+ if ($primaryKey === FALSE) {
+ unset($this->refCache['referencing'][$this->getGeneralCacheKey()][$this->getSpecificCacheKey()]);
+ return $return->getRowCount();
+ }
+
+ if (is_array($this->getPrimary())) {
+ $primaryKey = array();
+
+ foreach ((array) $this->getPrimary() as $key) {
+ if (!isset($data[$key])) {
+ return $data;
+ }
+
+ $primaryKey[$key] = $data[$key];
+ }
+ if (count($primaryKey) === 1) {
+ $primaryKey = reset($primaryKey);
+ }
+ }
+
+ $row = $this->createSelectionInstance()
+ ->select('*')
+ ->wherePrimary($primaryKey)
+ ->fetch();
+
+ if ($this->rows !== NULL) {
+ if ($signature = $row->getSignature(FALSE)) {
+ $this->rows[$signature] = $row;
+ $this->data[$signature] = $row;
+ } else {
+ $this->rows[] = $row;
+ $this->data[] = $row;
+ }
+ }
+
+ return $row;
+ }
+
+
+ /**
+ * Updates all rows in result set.
+ * Joins in UPDATE are supported only in MySQL
+ * @param array|\Traversable ($column => $value)
+ * @return int number of affected rows
+ */
+ public function update($data)
+ {
+ if ($data instanceof \Traversable) {
+ $data = iterator_to_array($data);
+
+ } elseif (!is_array($data)) {
+ throw new Nette\InvalidArgumentException;
+ }
+
+ if (!$data) {
+ return 0;
+ }
+
+ return $this->context->queryArgs(
+ $this->sqlBuilder->buildUpdateQuery(),
+ array_merge(array($data), $this->sqlBuilder->getParameters())
+ )->getRowCount();
+ }
+
+
+ /**
+ * Deletes all rows in result set.
+ * @return int number of affected rows
+ */
+ public function delete()
+ {
+ return $this->query($this->sqlBuilder->buildDeleteQuery())->getRowCount();
+ }
+
+
+ /********************* references ****************d*g**/
+
+
+ /**
+ * Returns referenced row.
+ * @param ActiveRow
+ * @param string
+ * @param string|NULL
+ * @return ActiveRow|NULL|FALSE NULL if the row does not exist, FALSE if the relationship does not exist
+ */
+ public function getReferencedTable(ActiveRow $row, $table, $column = NULL)
+ {
+ if (!$column) {
+ $belongsTo = $this->conventions->getBelongsToReference($this->name, $table);
+ if (!$belongsTo) {
+ return FALSE;
+ }
+ list($table, $column) = $belongsTo;
+ }
+ if (!$row->accessColumn($column)) {
+ return FALSE;
+ }
+
+ $checkPrimaryKey = $row[$column];
+
+ $referenced = & $this->refCache['referenced'][$this->getSpecificCacheKey()]["$table.$column"];
+ $selection = & $referenced['selection'];
+ $cacheKeys = & $referenced['cacheKeys'];
+ if ($selection === NULL || ($checkPrimaryKey !== NULL && !isset($cacheKeys[$checkPrimaryKey]))) {
+ $this->execute();
+ $cacheKeys = array();
+ foreach ($this->rows as $row) {
+ if ($row[$column] === NULL) {
+ continue;
+ }
+
+ $key = $row[$column];
+ $cacheKeys[$key] = TRUE;
+ }
+
+ if ($cacheKeys) {
+ $selection = $this->createSelectionInstance($table);
+ $selection->where($selection->getPrimary(), array_keys($cacheKeys));
+ } else {
+ $selection = array();
+ }
+ }
+
+ return isset($selection[$checkPrimaryKey]) ? $selection[$checkPrimaryKey] : NULL;
+ }
+
+
+ /**
+ * Returns referencing rows.
+ * @param string
+ * @param string
+ * @param int primary key
+ * @return GroupedSelection
+ */
+ public function getReferencingTable($table, $column, $active = NULL)
+ {
+ if (strpos($table, '.') !== FALSE) {
+ list($table, $column) = explode('.', $table);
+ } elseif (!$column) {
+ $hasMany = $this->conventions->getHasManyReference($this->name, $table);
+ if (!$hasMany) {
+ return FALSE;
+ }
+ list($table, $column) = $hasMany;
+ }
+
+ $prototype = & $this->refCache['referencingPrototype'][$this->getSpecificCacheKey()]["$table.$column"];
+ if (!$prototype) {
+ $prototype = $this->createGroupedSelectionInstance($table, $column);
+ $prototype->where("$table.$column", array_keys((array) $this->rows));
+ }
+
+ $clone = clone $prototype;
+ $clone->setActive($active);
+ return $clone;
+ }
+
+
+ /********************* interface Iterator ****************d*g**/
+
+
+ public function rewind()
+ {
+ $this->execute();
+ $this->keys = array_keys($this->data);
+ reset($this->keys);
+ }
+
+
+ /** @return IRow */
+ public function current()
+ {
+ if (($key = current($this->keys)) !== FALSE) {
+ return $this->data[$key];
+ } else {
+ return FALSE;
+ }
+ }
+
+
+ /**
+ * @return string row ID
+ */
+ public function key()
+ {
+ return current($this->keys);
+ }
+
+
+ public function next()
+ {
+ next($this->keys);
+ }
+
+
+ public function valid()
+ {
+ return current($this->keys) !== FALSE;
+ }
+
+
+ /********************* interface ArrayAccess ****************d*g**/
+
+
+ /**
+ * Mimic row.
+ * @param string row ID
+ * @param IRow
+ * @return NULL
+ */
+ public function offsetSet($key, $value)
+ {
+ $this->execute();
+ $this->rows[$key] = $value;
+ }
+
+
+ /**
+ * Returns specified row.
+ * @param string row ID
+ * @return IRow or NULL if there is no such row
+ */
+ public function offsetGet($key)
+ {
+ $this->execute();
+ return $this->rows[$key];
+ }
+
+
+ /**
+ * Tests if row exists.
+ * @param string row ID
+ * @return bool
+ */
+ public function offsetExists($key)
+ {
+ $this->execute();
+ return isset($this->rows[$key]);
+ }
+
+
+ /**
+ * Removes row from result set.
+ * @param string row ID
+ * @return NULL
+ */
+ public function offsetUnset($key)
+ {
+ $this->execute();
+ unset($this->rows[$key], $this->data[$key]);
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/Table/SqlBuilder.php b/vendor/nette/database/src/Database/Table/SqlBuilder.php
new file mode 100755
index 0000000..68ecbbc
--- /dev/null
+++ b/vendor/nette/database/src/Database/Table/SqlBuilder.php
@@ -0,0 +1,572 @@
+ array(),
+ 'where' => array(),
+ 'group' => array(),
+ 'having' => array(),
+ 'order' => array(),
+ );
+
+ /** @var array or columns to order by */
+ protected $order = array();
+
+ /** @var int number of rows to fetch */
+ protected $limit = NULL;
+
+ /** @var int first row to fetch */
+ protected $offset = NULL;
+
+ /** @var string columns to grouping */
+ protected $group = '';
+
+ /** @var string grouping condition */
+ protected $having = '';
+
+ /** @var ISupplementalDriver */
+ private $driver;
+
+ /** @var IStructure */
+ private $structure;
+
+ /** @var array */
+ private $cacheTableList;
+
+
+ public function __construct($tableName, Context $context)
+ {
+ $this->tableName = $tableName;
+ $this->driver = $context->getConnection()->getSupplementalDriver();
+ $this->conventions = $context->getConventions();
+ $this->structure = $context->getStructure();
+
+ $this->delimitedTable = implode('.', array_map(array($this->driver, 'delimite'), explode('.', $tableName)));
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getTableName()
+ {
+ return $this->tableName;
+ }
+
+
+ public function buildInsertQuery()
+ {
+ return "INSERT INTO {$this->delimitedTable}";
+ }
+
+
+ public function buildUpdateQuery()
+ {
+ if ($this->limit !== NULL || $this->offset) {
+ throw new Nette\NotSupportedException('LIMIT clause is not supported in UPDATE query.');
+ }
+ return "UPDATE {$this->delimitedTable} SET ?set" . $this->tryDelimite($this->buildConditions());
+ }
+
+
+ public function buildDeleteQuery()
+ {
+ if ($this->limit !== NULL || $this->offset) {
+ throw new Nette\NotSupportedException('LIMIT clause is not supported in DELETE query.');
+ }
+ return "DELETE FROM {$this->delimitedTable}" . $this->tryDelimite($this->buildConditions());
+ }
+
+
+ /**
+ * Returns SQL query.
+ * @param string list of columns
+ * @return string
+ */
+ public function buildSelectQuery($columns = NULL)
+ {
+ $queryCondition = $this->buildConditions();
+ $queryEnd = $this->buildQueryEnd();
+
+ $joins = array();
+ $this->parseJoins($joins, $queryCondition);
+ $this->parseJoins($joins, $queryEnd);
+
+ if ($this->select) {
+ $querySelect = $this->buildSelect($this->select);
+ $this->parseJoins($joins, $querySelect);
+
+ } elseif ($columns) {
+ $prefix = $joins ? "{$this->delimitedTable}." : '';
+ $cols = array();
+ foreach ($columns as $col) {
+ $cols[] = $prefix . $col;
+ }
+ $querySelect = $this->buildSelect($cols);
+
+ } elseif ($this->group && !$this->driver->isSupported(ISupplementalDriver::SUPPORT_SELECT_UNGROUPED_COLUMNS)) {
+ $querySelect = $this->buildSelect(array($this->group));
+ $this->parseJoins($joins, $querySelect);
+
+ } else {
+ $prefix = $joins ? "{$this->delimitedTable}." : '';
+ $querySelect = $this->buildSelect(array($prefix . '*'));
+
+ }
+
+ $queryJoins = $this->buildQueryJoins($joins);
+ $query = "{$querySelect} FROM {$this->delimitedTable}{$queryJoins}{$queryCondition}{$queryEnd}";
+
+ if ($this->limit !== NULL || $this->offset) {
+ $this->driver->applyLimit($query, $this->limit, $this->offset);
+ }
+
+ return $this->tryDelimite($query);
+ }
+
+
+ public function getParameters()
+ {
+ return array_merge(
+ $this->parameters['select'],
+ $this->parameters['where'],
+ $this->parameters['group'],
+ $this->parameters['having'],
+ $this->parameters['order']
+ );
+ }
+
+
+ public function importConditions(SqlBuilder $builder)
+ {
+ $this->where = $builder->where;
+ $this->parameters['where'] = $builder->parameters['where'];
+ $this->conditions = $builder->conditions;
+ }
+
+
+ /********************* SQL selectors ****************d*g**/
+
+
+ public function addSelect($columns)
+ {
+ if (is_array($columns)) {
+ throw new Nette\InvalidArgumentException('Select column must be a string.');
+ }
+ $this->select[] = $columns;
+ $this->parameters['select'] = array_merge($this->parameters['select'], array_slice(func_get_args(), 1));
+ }
+
+
+ public function getSelect()
+ {
+ return $this->select;
+ }
+
+
+ public function addWhere($condition, $parameters = array())
+ {
+ if (is_array($condition) && is_array($parameters) && !empty($parameters)) {
+ return $this->addWhereComposition($condition, $parameters);
+ }
+
+ $args = func_get_args();
+ $hash = md5(json_encode($args));
+ if (isset($this->conditions[$hash])) {
+ return FALSE;
+ }
+
+ $this->conditions[$hash] = $condition;
+ $placeholderCount = substr_count($condition, '?');
+ if ($placeholderCount > 1 && count($args) === 2 && is_array($parameters)) {
+ $args = $parameters;
+ } else {
+ array_shift($args);
+ }
+
+ $condition = trim($condition);
+ if ($placeholderCount === 0 && count($args) === 1) {
+ $condition .= ' ?';
+ } elseif ($placeholderCount !== count($args)) {
+ throw new Nette\InvalidArgumentException('Argument count does not match placeholder count.');
+ }
+
+ $replace = NULL;
+ $placeholderNum = 0;
+ foreach ($args as $arg) {
+ preg_match('#(?:.*?\?.*?){' . $placeholderNum . '}(((?:&|\||^|~|\+|-|\*|/|%|\(|,|<|>|=|(?<=\W|^)(?:REGEXP|ALL|AND|ANY|BETWEEN|EXISTS|IN|[IR]?LIKE|OR|NOT|SOME|INTERVAL))\s*)?(?:\(\?\)|\?))#s', $condition, $match, PREG_OFFSET_CAPTURE);
+ $hasOperator = ($match[1][0] === '?' && $match[1][1] === 0) ? TRUE : !empty($match[2][0]);
+
+ if ($arg === NULL) {
+ $replace = 'IS NULL';
+ if ($hasOperator) {
+ if (trim($match[2][0]) === 'NOT') {
+ $replace = 'IS NOT NULL';
+ } else {
+ throw new Nette\InvalidArgumentException('Column operator does not accept NULL argument.');
+ }
+ }
+ } elseif (is_array($arg) || $arg instanceof Selection) {
+ if ($hasOperator) {
+ if (trim($match[2][0]) === 'NOT') {
+ $match[2][0] = rtrim($match[2][0]) . ' IN ';
+ } elseif (trim($match[2][0]) !== 'IN') {
+ throw new Nette\InvalidArgumentException('Column operator does not accept array argument.');
+ }
+ } else {
+ $match[2][0] = 'IN ';
+ }
+
+ if ($arg instanceof Selection) {
+ $clone = clone $arg;
+ if (!$clone->getSqlBuilder()->select) {
+ try {
+ $clone->select($clone->getPrimary());
+ } catch (\LogicException $e) {
+ throw new Nette\InvalidArgumentException('Selection argument must have defined a select column.', 0, $e);
+ }
+ }
+
+ if ($this->driver->isSupported(ISupplementalDriver::SUPPORT_SUBSELECT)) {
+ $arg = NULL;
+ $replace = $match[2][0] . '(' . $clone->getSql() . ')';
+ $this->parameters['where'] = array_merge($this->parameters['where'], $clone->getSqlBuilder()->getParameters());
+ } else {
+ $arg = array();
+ foreach ($clone as $row) {
+ $arg[] = array_values(iterator_to_array($row));
+ }
+ }
+ }
+
+ if ($arg !== NULL) {
+ if (!$arg) {
+ $hasBrackets = strpos($condition, '(') !== FALSE;
+ $hasOperators = preg_match('#AND|OR#', $condition);
+ $hasNot = strpos($condition, 'NOT') !== FALSE;
+ $hasPrefixNot = strpos($match[2][0], 'NOT') !== FALSE;
+ if (!$hasBrackets && ($hasOperators || ($hasNot && !$hasPrefixNot))) {
+ throw new Nette\InvalidArgumentException('Possible SQL query corruption. Add parentheses around operators.');
+ }
+ if ($hasPrefixNot) {
+ $replace = 'IS NULL OR TRUE';
+ } else {
+ $replace = 'IS NULL AND FALSE';
+ }
+ $arg = NULL;
+ } else {
+ $replace = $match[2][0] . '(?)';
+ $this->parameters['where'][] = $arg;
+ }
+ }
+ } elseif ($arg instanceof SqlLiteral) {
+ $this->parameters['where'][] = $arg;
+ } else {
+ if (!$hasOperator) {
+ $replace = '= ?';
+ }
+ $this->parameters['where'][] = $arg;
+ }
+
+ if ($replace) {
+ $condition = substr_replace($condition, $replace, $match[1][1], strlen($match[1][0]));
+ $replace = NULL;
+ }
+
+ if ($arg !== NULL) {
+ $placeholderNum++;
+ }
+ }
+
+ $this->where[] = $condition;
+ return TRUE;
+ }
+
+
+ public function getConditions()
+ {
+ return array_values($this->conditions);
+ }
+
+
+ public function addOrder($columns)
+ {
+ $this->order[] = $columns;
+ $this->parameters['order'] = array_merge($this->parameters['order'], array_slice(func_get_args(), 1));
+ }
+
+
+ public function setOrder(array $columns, array $parameters)
+ {
+ $this->order = $columns;
+ $this->parameters['order'] = $parameters;
+ }
+
+
+ public function getOrder()
+ {
+ return $this->order;
+ }
+
+
+ public function setLimit($limit, $offset)
+ {
+ $this->limit = $limit;
+ $this->offset = $offset;
+ }
+
+
+ public function getLimit()
+ {
+ return $this->limit;
+ }
+
+
+ public function getOffset()
+ {
+ return $this->offset;
+ }
+
+
+ public function setGroup($columns)
+ {
+ $this->group = $columns;
+ $this->parameters['group'] = array_slice(func_get_args(), 1);
+ }
+
+
+ public function getGroup()
+ {
+ return $this->group;
+ }
+
+
+ public function setHaving($having)
+ {
+ $this->having = $having;
+ $this->parameters['having'] = array_slice(func_get_args(), 1);
+ }
+
+
+ public function getHaving()
+ {
+ return $this->having;
+ }
+
+
+ /********************* SQL building ****************d*g**/
+
+
+ protected function buildSelect(array $columns)
+ {
+ return 'SELECT ' . implode(', ', $columns);
+ }
+
+
+ protected function parseJoins(& $joins, & $query)
+ {
+ $builder = $this;
+ $query = preg_replace_callback('~
+ (?(DEFINE)
+ (?P [\w_]*[a-z][\w_]* )
+ (?P [.:] )
+ (?P (?&del)? (?&word) (\((?&word)\))? )
+ )
+ (?P (?!\.) (?&node)*) \. (?P (?&word) | \* )
+ ~xi', function ($match) use (& $joins, $builder) {
+ return $builder->parseJoinsCb($joins, $match);
+ }, $query);
+ }
+
+
+ public function parseJoinsCb(& $joins, $match)
+ {
+ $chain = $match['chain'];
+ if (!empty($chain[0]) && ($chain[0] !== '.' && $chain[0] !== ':')) {
+ $chain = '.' . $chain; // unified chain format
+ }
+
+ preg_match_all('~
+ (?(DEFINE)
+ (?P [\w_]*[a-z][\w_]* )
+ )
+ (?P [.:])?(?P (?&word))(\((?P (?&word))\))?
+ ~xi', $chain, $keyMatches, PREG_SET_ORDER);
+
+ $parent = $this->tableName;
+ $parentAlias = preg_replace('#^(.*\.)?(.*)$#', '$2', $this->tableName);
+
+ // join schema keyMatch and table keyMatch to schema.table keyMatch
+ if ($this->driver->isSupported(ISupplementalDriver::SUPPORT_SCHEMA) && count($keyMatches) > 1) {
+ $tables = $this->getCachedTableList();
+ if (!isset($tables[$keyMatches[0]['key']]) && isset($tables[$keyMatches[0]['key'] . '.' . $keyMatches[1]['key']])) {
+ $keyMatch = array_shift($keyMatches);
+ $keyMatches[0]['key'] = $keyMatch['key'] . '.' . $keyMatches[0]['key'];
+ $keyMatches[0]['del'] = $keyMatch['del'];
+ }
+ }
+
+ // do not make a join when referencing to the current table column - inner conditions
+ // check it only when not making backjoin on itself - outer condition
+ if ($keyMatches[0]['del'] === '.') {
+ if ($parent === $keyMatches[0]['key']) {
+ return "{$parent}.{$match['column']}";
+ } elseif ($parentAlias === $keyMatches[0]['key']) {
+ return "{$parentAlias}.{$match['column']}";
+ }
+ }
+
+ foreach ($keyMatches as $keyMatch) {
+ if ($keyMatch['del'] === ':') {
+ if (isset($keyMatch['throughColumn'])) {
+ $table = $keyMatch['key'];
+ $belongsTo = $this->conventions->getBelongsToReference($table, $keyMatch['throughColumn']);
+ if (!$belongsTo) {
+ throw new Nette\InvalidArgumentException("No reference found for \${$parent}->{$keyMatch['key']}.");
+ }
+ list(, $primary) = $belongsTo;
+
+ } else {
+ $hasMany = $this->conventions->getHasManyReference($parent, $keyMatch['key']);
+ if (!$hasMany) {
+ throw new Nette\InvalidArgumentException("No reference found for \${$parent}->related({$keyMatch['key']}).");
+ }
+ list($table, $primary) = $hasMany;
+ }
+ $column = $this->conventions->getPrimary($parent);
+
+ } else {
+ $belongsTo = $this->conventions->getBelongsToReference($parent, $keyMatch['key']);
+ if (!$belongsTo) {
+ throw new Nette\InvalidArgumentException("No reference found for \${$parent}->{$keyMatch['key']}.");
+ }
+ list($table, $column) = $belongsTo;
+ $primary = $this->conventions->getPrimary($table);
+ }
+
+ $tableAlias = $keyMatch['key'] ?: preg_replace('#^(.*\.)?(.*)$#', '$2', $table);
+
+ // if we are joining itself (parent table), we must alias joining table
+ if ($parent === $table) {
+ $tableAlias = $parentAlias . '_ref';
+ }
+
+ $joins[$tableAlias . $column] = array($table, $tableAlias, $parentAlias, $column, $primary);
+ $parent = $table;
+ $parentAlias = $tableAlias;
+ }
+
+ return $tableAlias . ".{$match['column']}";
+ }
+
+
+ protected function buildQueryJoins(array $joins)
+ {
+ $return = '';
+ foreach ($joins as $join) {
+ list($joinTable, $joinAlias, $table, $tableColumn, $joinColumn) = $join;
+
+ $return .=
+ " LEFT JOIN {$joinTable}" . ($joinTable !== $joinAlias ? " AS {$joinAlias}" : '') .
+ " ON {$table}.{$tableColumn} = {$joinAlias}.{$joinColumn}";
+ }
+
+ return $return;
+ }
+
+
+ protected function buildConditions()
+ {
+ return $this->where ? ' WHERE (' . implode(') AND (', $this->where) . ')' : '';
+ }
+
+
+ protected function buildQueryEnd()
+ {
+ $return = '';
+ if ($this->group) {
+ $return .= ' GROUP BY '. $this->group;
+ }
+ if ($this->having) {
+ $return .= ' HAVING '. $this->having;
+ }
+ if ($this->order) {
+ $return .= ' ORDER BY ' . implode(', ', $this->order);
+ }
+ return $return;
+ }
+
+
+ protected function tryDelimite($s)
+ {
+ $driver = $this->driver;
+ return preg_replace_callback('#(?<=[^\w`"\[?]|^)[a-z_][a-z0-9_]*(?=[^\w`"(\]]|\z)#i', function ($m) use ($driver) {
+ return strtoupper($m[0]) === $m[0] ? $m[0] : $driver->delimite($m[0]);
+ }, $s);
+ }
+
+
+ protected function addWhereComposition(array $columns, array $parameters)
+ {
+ if ($this->driver->isSupported(ISupplementalDriver::SUPPORT_MULTI_COLUMN_AS_OR_COND)) {
+ $conditionFragment = '(' . implode(' = ? AND ', $columns) . ' = ?) OR ';
+ $condition = substr(str_repeat($conditionFragment, count($parameters)), 0, -4);
+ return $this->addWhere($condition, Nette\Utils\Arrays::flatten($parameters));
+ } else {
+ return $this->addWhere('(' . implode(', ', $columns) . ') IN', $parameters);
+ }
+ }
+
+
+ private function getCachedTableList()
+ {
+ if (!$this->cacheTableList) {
+ $this->cacheTableList = array_flip(array_map(function ($pair) {
+ return isset($pair['fullName']) ? $pair['fullName'] : $pair['name'];
+ }, $this->structure->getTables()));
+ }
+
+ return $this->cacheTableList;
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/deprecated/ConventionalReflection.php b/vendor/nette/database/src/Database/deprecated/ConventionalReflection.php
new file mode 100755
index 0000000..efdc2eb
--- /dev/null
+++ b/vendor/nette/database/src/Database/deprecated/ConventionalReflection.php
@@ -0,0 +1,23 @@
+connection = $connection;
+ if ($cacheStorage) {
+ $this->cache = new Nette\Caching\Cache($cacheStorage, 'Nette.Database.' . md5($connection->getDsn()));
+ $this->structure = $this->loadedStructure = $this->cache->load('structure') ?: array();
+ }
+ }
+
+
+ public function __destruct()
+ {
+ if ($this->cache && $this->structure !== $this->loadedStructure) {
+ $this->cache->save('structure', $this->structure);
+ }
+ }
+
+
+ public function getPrimary($table)
+ {
+ $primary = & $this->structure['primary'][strtolower($table)];
+ if (isset($primary)) {
+ return empty($primary) ? NULL : $primary;
+ }
+
+ $columns = $this->connection->getSupplementalDriver()->getColumns($table);
+ $primary = array();
+ foreach ($columns as $column) {
+ if ($column['primary']) {
+ $primary[] = $column['name'];
+ }
+ }
+
+ if (count($primary) === 0) {
+ return NULL;
+ } elseif (count($primary) === 1) {
+ $primary = reset($primary);
+ }
+
+ return $primary;
+ }
+
+
+ public function getHasManyReference($table, $key, $refresh = TRUE)
+ {
+ if (isset($this->structure['hasMany'][strtolower($table)])) {
+ $candidates = $columnCandidates = array();
+ foreach ($this->structure['hasMany'][strtolower($table)] as $targetPair) {
+ list($targetColumn, $targetTable) = $targetPair;
+ if (stripos($targetTable, $key) === FALSE) {
+ continue;
+ }
+
+ $candidates[] = array($targetTable, $targetColumn);
+ if (stripos($targetColumn, $table) !== FALSE) {
+ $columnCandidates[] = $candidate = array($targetTable, $targetColumn);
+ if (strtolower($targetTable) === strtolower($key)) {
+ return $candidate;
+ }
+ }
+ }
+
+ if (count($columnCandidates) === 1) {
+ return reset($columnCandidates);
+ } elseif (count($candidates) === 1) {
+ return reset($candidates);
+ }
+
+ foreach ($candidates as $candidate) {
+ if (strtolower($candidate[0]) === strtolower($key)) {
+ return $candidate;
+ }
+ }
+ }
+
+ if ($refresh) {
+ $this->reloadAllForeignKeys();
+ return $this->getHasManyReference($table, $key, FALSE);
+ }
+
+ if (empty($candidates)) {
+ throw new MissingReferenceException("No reference found for \${$table}->related({$key}).");
+ } else {
+ throw new AmbiguousReferenceKeyException('Ambiguous joining column in related call.');
+ }
+ }
+
+
+ public function getBelongsToReference($table, $key, $refresh = TRUE)
+ {
+ if (isset($this->structure['belongsTo'][strtolower($table)])) {
+ foreach ($this->structure['belongsTo'][strtolower($table)] as $column => $targetTable) {
+ if (stripos($column, $key) !== FALSE) {
+ return array($targetTable, $column);
+ }
+ }
+ }
+
+ if ($refresh) {
+ $this->reloadForeignKeys($table);
+ return $this->getBelongsToReference($table, $key, FALSE);
+ }
+
+ throw new MissingReferenceException("No reference found for \${$table}->{$key}.");
+ }
+
+
+ protected function reloadAllForeignKeys()
+ {
+ $this->structure['hasMany'] = $this->structure['belongsTo'] = array();
+
+ foreach ($this->connection->getSupplementalDriver()->getTables() as $table) {
+ if ($table['view'] == FALSE) {
+ $this->reloadForeignKeys($table['name']);
+ }
+ }
+
+ foreach ($this->structure['hasMany'] as & $table) {
+ uksort($table, function ($a, $b) {
+ return strlen($a) - strlen($b);
+ });
+ }
+ }
+
+
+ protected function reloadForeignKeys($table)
+ {
+ foreach ($this->connection->getSupplementalDriver()->getForeignKeys($table) as $row) {
+ $this->structure['belongsTo'][strtolower($table)][$row['local']] = $row['table'];
+ $this->structure['hasMany'][strtolower($row['table'])][$row['local'] . $table] = array($row['local'], $table);
+ }
+
+ if (isset($this->structure['belongsTo'][$table])) {
+ uksort($this->structure['belongsTo'][$table], function ($a, $b) {
+ return strlen($a) - strlen($b);
+ });
+ }
+ }
+
+}
diff --git a/vendor/nette/database/src/Database/deprecated/IReflection.php b/vendor/nette/database/src/Database/deprecated/IReflection.php
new file mode 100755
index 0000000..9e50035
--- /dev/null
+++ b/vendor/nette/database/src/Database/deprecated/IReflection.php
@@ -0,0 +1,29 @@
+=5.3.1",
+ "nette/neon": "~2.3",
+ "nette/php-generator": "~2.3",
+ "nette/utils": "~2.3"
+ },
+ "require-dev": {
+ "nette/tester": "~1.3"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/di/license.md b/vendor/nette/di/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/di/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/di/src/Bridges/DITracy/ContainerPanel.php b/vendor/nette/di/src/Bridges/DITracy/ContainerPanel.php
new file mode 100755
index 0000000..38a01f6
--- /dev/null
+++ b/vendor/nette/di/src/Bridges/DITracy/ContainerPanel.php
@@ -0,0 +1,86 @@
+container = $container;
+ $this->elapsedTime = self::$compilationTime ? microtime(TRUE) - self::$compilationTime : NULL;
+ }
+
+
+ /**
+ * Renders tab.
+ * @return string
+ */
+ public function getTab()
+ {
+ ob_start();
+ $elapsedTime = $this->elapsedTime;
+ require __DIR__ . '/templates/ContainerPanel.tab.phtml';
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Renders panel.
+ * @return string
+ */
+ public function getPanel()
+ {
+ $container = $this->container;
+ $registry = $this->getContainerProperty('registry');
+ $rc = new \ReflectionClass($container);
+ $file = $rc->getFileName();
+ $tags = array();
+ $meta = $this->getContainerProperty('meta');
+ $services = $meta[Container::SERVICES];
+ ksort($services);
+ if (isset($meta[Container::TAGS])) {
+ foreach ($meta[Container::TAGS] as $tag => $tmp) {
+ foreach ($tmp as $service => $val) {
+ $tags[$service][$tag] = $val;
+ }
+ }
+ }
+
+ ob_start();
+ require __DIR__ . '/templates/ContainerPanel.panel.phtml';
+ return ob_get_clean();
+ }
+
+
+ private function getContainerProperty($name)
+ {
+ $rc = new \ReflectionClass('Nette\DI\Container');
+ $prop = $rc->getProperty($name);
+ $prop->setAccessible(TRUE);
+ return $prop->getValue($this->container);
+ }
+
+}
diff --git a/vendor/nette/di/src/Bridges/DITracy/templates/ContainerPanel.panel.phtml b/vendor/nette/di/src/Bridges/DITracy/templates/ContainerPanel.panel.phtml
new file mode 100755
index 0000000..b7e9516
--- /dev/null
+++ b/vendor/nette/di/src/Bridges/DITracy/templates/ContainerPanel.panel.phtml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
Services
+
+
+
+
+ Name
+ Autowired
+ Service
+ Tags
+
+
+
+ $class): ?>
+
+
+
+
+
+
+ TRUE, Dumper::LIVE => TRUE)); ?>
+
+
+
+
+
+
+ TRUE)); } ?>
+
+
+
+
+
+
Parameters
+
+
+ parameters); ?>
+
+
+
Source:
+
+
diff --git a/vendor/nette/di/src/Bridges/DITracy/templates/ContainerPanel.tab.phtml b/vendor/nette/di/src/Bridges/DITracy/templates/ContainerPanel.tab.phtml
new file mode 100755
index 0000000..c4db8f9
--- /dev/null
+++ b/vendor/nette/di/src/Bridges/DITracy/templates/ContainerPanel.tab.phtml
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/vendor/nette/di/src/DI/Compiler.php b/vendor/nette/di/src/DI/Compiler.php
new file mode 100755
index 0000000..c196c28
--- /dev/null
+++ b/vendor/nette/di/src/DI/Compiler.php
@@ -0,0 +1,425 @@
+ 1, 'parameters' => 1);
+
+
+ public function __construct(ContainerBuilder $builder = NULL)
+ {
+ $this->builder = $builder ?: new ContainerBuilder;
+ }
+
+
+ /**
+ * Add custom configurator extension.
+ * @return self
+ */
+ public function addExtension($name, CompilerExtension $extension)
+ {
+ if (isset($this->extensions[$name]) || isset(self::$reserved[$name])) {
+ throw new Nette\InvalidArgumentException("Name '$name' is already used or reserved.");
+ }
+ $this->extensions[$name] = $extension->setCompiler($this, $name);
+ return $this;
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getExtensions($type = NULL)
+ {
+ return $type
+ ? array_filter($this->extensions, function ($item) use ($type) { return $item instanceof $type; })
+ : $this->extensions;
+ }
+
+
+ /**
+ * @return ContainerBuilder
+ */
+ public function getContainerBuilder()
+ {
+ return $this->builder;
+ }
+
+
+ /**
+ * Adds new configuration.
+ * @return self
+ */
+ public function addConfig(array $config)
+ {
+ $this->config = Config\Helpers::merge($config, $this->config);
+ return $this;
+ }
+
+
+ /**
+ * Adds new configuration from file.
+ * @return self
+ */
+ public function loadConfig($file)
+ {
+ $loader = new Config\Loader;
+ $this->addConfig($loader->load($file));
+ $this->addDependencies($loader->getDependencies());
+ return $this;
+ }
+
+
+ /**
+ * Returns configuration.
+ * @return array
+ */
+ public function getConfig()
+ {
+ return $this->config;
+ }
+
+
+ /**
+ * Adds a files to the list of dependencies.
+ * @return self
+ */
+ public function addDependencies(array $files)
+ {
+ $this->dependencies = array_merge($this->dependencies, $files);
+ return $this;
+ }
+
+
+ /**
+ * Returns the unique list of dependent files.
+ * @return array
+ */
+ public function getDependencies()
+ {
+ return array_values(array_unique(array_filter($this->dependencies)));
+ }
+
+
+ /**
+ * @return Nette\PhpGenerator\ClassType[]
+ */
+ public function compile(array $config = NULL, $className = NULL, $parentName = NULL)
+ {
+ $this->config = $config ?: $this->config;
+ $this->processParameters();
+ $this->processExtensions();
+ $this->processServices();
+ $classes = $this->generateCode($className, $parentName);
+ return func_num_args()
+ ? implode("\n\n\n", $classes) // back compatiblity
+ : $classes;
+ }
+
+
+ /** @internal */
+ public function processParameters()
+ {
+ if (isset($this->config['parameters'])) {
+ $this->builder->parameters = Helpers::expand($this->config['parameters'], $this->config['parameters'], TRUE);
+ }
+ }
+
+
+ /** @internal */
+ public function processExtensions()
+ {
+ $last = $this->getExtensions('Nette\DI\Extensions\InjectExtension');
+ $this->extensions = array_merge(array_diff_key($this->extensions, $last), $last);
+
+ $this->config = Helpers::expand(array_diff_key($this->config, self::$reserved), $this->builder->parameters)
+ + array_intersect_key($this->config, self::$reserved);
+
+ foreach ($first = $this->getExtensions('Nette\DI\Extensions\ExtensionsExtension') as $name => $extension) {
+ $extension->setConfig(isset($this->config[$name]) ? $this->config[$name] : array());
+ $extension->loadConfiguration();
+ }
+
+ $extensions = array_diff_key($this->extensions, $first);
+ foreach (array_intersect_key($extensions, $this->config) as $name => $extension) {
+ if (isset($this->config[$name]['services'])) {
+ trigger_error("Support for inner section 'services' inside extension was removed (used in '$name').", E_USER_DEPRECATED);
+ }
+ $extension->setConfig($this->config[$name] ?: array());
+ }
+
+ foreach ($extensions as $extension) {
+ $extension->loadConfiguration();
+ }
+
+ if ($extra = array_diff_key($this->extensions, $extensions, $first)) {
+ $extra = implode("', '", array_keys($extra));
+ throw new Nette\DeprecatedException("Extensions '$extra' were added while container was being compiled.");
+
+ } elseif ($extra = array_diff_key($this->config, self::$reserved, $this->extensions)) {
+ $extra = implode("', '", array_keys($extra));
+ throw new Nette\InvalidStateException("Found sections '$extra' in configuration, but corresponding extensions are missing.");
+ }
+ }
+
+
+ /** @internal */
+ public function processServices()
+ {
+ $this->parseServices($this->builder, $this->config);
+ }
+
+
+ /** @internal */
+ public function generateCode($className, $parentName = NULL)
+ {
+ $this->builder->prepareClassList();
+
+ foreach ($this->extensions as $extension) {
+ $extension->beforeCompile();
+ $rc = new \ReflectionClass($extension);
+ $this->dependencies[] = $rc->getFileName();
+ }
+
+ $classes = $this->builder->generateClasses($className, $parentName);
+ $classes[0]->addMethod('initialize');
+ $this->addDependencies($this->builder->getDependencies());
+
+ foreach ($this->extensions as $extension) {
+ $extension->afterCompile($classes[0]);
+ }
+ return $classes;
+ }
+
+
+ /********************* tools ****************d*g**/
+
+
+ /**
+ * Parses section 'services' from (unexpanded) configuration file.
+ * @return void
+ */
+ public static function parseServices(ContainerBuilder $builder, array $config, $namespace = NULL)
+ {
+ if (!empty($config['factories'])) {
+ throw new Nette\DeprecatedException("Section 'factories' is deprecated, move definitions to section 'services' and append key 'autowired: no'.");
+ }
+
+ $services = isset($config['services']) ? $config['services'] : array();
+ $depths = array();
+ foreach ($services as $name => $def) {
+ $path = array();
+ while (Config\Helpers::isInheriting($def)) {
+ $path[] = $def;
+ $def = isset($services[$def[Config\Helpers::EXTENDS_KEY]]) ? $services[$def[Config\Helpers::EXTENDS_KEY]] : array();
+ if (in_array($def, $path, TRUE)) {
+ throw new ServiceCreationException("Circular reference detected for service '$name'.");
+ }
+ }
+ $depths[$name] = count($path);
+ }
+ array_multisort($depths, $services);
+
+ foreach ($services as $origName => $def) {
+ if ((string) (int) $origName === (string) $origName) {
+ $postfix = $def instanceof Statement && is_string($def->getEntity()) ? '.' . $def->getEntity() : (is_scalar($def) ? ".$def" : '');
+ $name = (count($builder->getDefinitions()) + 1) . preg_replace('#\W+#', '_', $postfix);
+ } else {
+ $name = ($namespace ? $namespace . '.' : '') . strtr($origName, '\\', '_');
+ }
+
+ $params = $builder->parameters;
+ if (is_array($def) && isset($def['parameters'])) {
+ foreach ((array) $def['parameters'] as $k => $v) {
+ $v = explode(' ', is_int($k) ? $v : $k);
+ $params[end($v)] = $builder::literal('$' . end($v));
+ }
+ }
+ $def = Helpers::expand($def, $params);
+
+ if (($parent = Config\Helpers::takeParent($def)) && $parent !== $name) {
+ $builder->removeDefinition($name);
+ $definition = $builder->addDefinition(
+ $name,
+ $parent === Config\Helpers::OVERWRITE ? NULL : unserialize(serialize($builder->getDefinition($parent))) // deep clone
+ );
+ } elseif ($builder->hasDefinition($name)) {
+ $definition = $builder->getDefinition($name);
+ } else {
+ $definition = $builder->addDefinition($name);
+ }
+
+ try {
+ static::parseService($definition, $def);
+ } catch (\Exception $e) {
+ throw new ServiceCreationException("Service '$name': " . $e->getMessage(), NULL, $e);
+ }
+
+ if ($definition->getClass() === 'self' || ($definition->getFactory() && $definition->getFactory()->getEntity() === 'self')) {
+ throw new Nette\DeprecatedException("Replace service definition '$origName: self' with '- $origName'.");
+ }
+ }
+ }
+
+
+ /**
+ * Parses single service from configuration file.
+ * @return void
+ */
+ public static function parseService(ServiceDefinition $definition, $config)
+ {
+ if ($config === NULL) {
+ return;
+
+ } elseif (is_string($config) && interface_exists($config)) {
+ $config = array('class' => NULL, 'implement' => $config);
+
+ } elseif ($config instanceof Statement && is_string($config->getEntity()) && interface_exists($config->getEntity())) {
+ $config = array('class' => NULL, 'implement' => $config->getEntity(), 'factory' => array_shift($config->arguments));
+
+ } elseif (!is_array($config) || isset($config[0], $config[1])) {
+ $config = array('class' => NULL, 'create' => $config);
+ }
+
+ if (array_key_exists('factory', $config)) {
+ $config['create'] = $config['factory'];
+ unset($config['factory']);
+ };
+
+ $known = array('class', 'create', 'arguments', 'setup', 'autowired', 'dynamic', 'inject', 'parameters', 'implement', 'run', 'tags');
+ if ($error = array_diff(array_keys($config), $known)) {
+ throw new Nette\InvalidStateException(sprintf("Unknown or deprecated key '%s' in definition of service.", implode("', '", $error)));
+ }
+
+ $config = self::filterArguments($config);
+
+ $arguments = array();
+ if (array_key_exists('arguments', $config)) {
+ Validators::assertField($config, 'arguments', 'array');
+ $arguments = $config['arguments'];
+ $definition->setArguments($arguments);
+ }
+
+ if (array_key_exists('class', $config) || array_key_exists('create', $config)) {
+ $definition->setClass(NULL);
+ $definition->setFactory(NULL);
+ }
+
+ if (array_key_exists('class', $config)) {
+ Validators::assertField($config, 'class', 'string|Nette\DI\Statement|null');
+ if (!$config['class'] instanceof Statement) {
+ $definition->setClass($config['class']);
+ }
+ $definition->setFactory($config['class'], $arguments);
+ }
+
+ if (array_key_exists('create', $config)) {
+ Validators::assertField($config, 'create', 'callable|Nette\DI\Statement|null');
+ $definition->setFactory($config['create'], $arguments);
+ }
+
+ if (isset($config['setup'])) {
+ if (Config\Helpers::takeParent($config['setup'])) {
+ $definition->setSetup(array());
+ }
+ Validators::assertField($config, 'setup', 'list');
+ foreach ($config['setup'] as $id => $setup) {
+ Validators::assert($setup, 'callable|Nette\DI\Statement', "setup item #$id");
+ $definition->addSetup($setup);
+ }
+ }
+
+ if (isset($config['parameters'])) {
+ Validators::assertField($config, 'parameters', 'array');
+ $definition->setParameters($config['parameters']);
+ }
+
+ if (isset($config['implement'])) {
+ Validators::assertField($config, 'implement', 'string');
+ $definition->setImplement($config['implement']);
+ $definition->setAutowired(TRUE);
+ }
+
+ if (isset($config['autowired'])) {
+ Validators::assertField($config, 'autowired', 'bool');
+ $definition->setAutowired($config['autowired']);
+ }
+
+ if (isset($config['dynamic'])) {
+ Validators::assertField($config, 'dynamic', 'bool');
+ $definition->setDynamic($config['dynamic']);
+ }
+
+ if (isset($config['inject'])) {
+ Validators::assertField($config, 'inject', 'bool');
+ $definition->addTag(Extensions\InjectExtension::TAG_INJECT, $config['inject']);
+ }
+
+ if (isset($config['run'])) {
+ $config['tags']['run'] = (bool) $config['run'];
+ }
+
+ if (isset($config['tags'])) {
+ Validators::assertField($config, 'tags', 'array');
+ if (Config\Helpers::takeParent($config['tags'])) {
+ $definition->setTags(array());
+ }
+ foreach ($config['tags'] as $tag => $attrs) {
+ if (is_int($tag) && is_string($attrs)) {
+ $definition->addTag($attrs);
+ } else {
+ $definition->addTag($tag, $attrs);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Removes ... and process constants recursively.
+ * @return array
+ */
+ public static function filterArguments(array $args)
+ {
+ foreach ($args as $k => $v) {
+ if ($v === '...') {
+ unset($args[$k]);
+ } elseif (is_string($v) && preg_match('#^[\w\\\\]*::[A-Z][A-Z0-9_]*\z#', $v, $m)) {
+ $args[$k] = ContainerBuilder::literal(ltrim($v, ':'));
+ } elseif (is_array($v)) {
+ $args[$k] = self::filterArguments($v);
+ } elseif ($v instanceof Statement) {
+ $tmp = self::filterArguments(array($v->getEntity()));
+ $args[$k] = new Statement($tmp[0], self::filterArguments($v->arguments));
+ }
+ }
+ return $args;
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/CompilerExtension.php b/vendor/nette/di/src/DI/CompilerExtension.php
new file mode 100755
index 0000000..0b49c00
--- /dev/null
+++ b/vendor/nette/di/src/DI/CompilerExtension.php
@@ -0,0 +1,135 @@
+compiler = $compiler;
+ $this->name = $name;
+ return $this;
+ }
+
+
+ public function setConfig(array $config)
+ {
+ $this->config = $config;
+ return $this;
+ }
+
+
+ /**
+ * Returns extension configuration.
+ * @return array
+ */
+ public function getConfig()
+ {
+ if (func_num_args()) { // deprecated
+ return Config\Helpers::merge($this->config, $this->getContainerBuilder()->expand(func_get_arg(0)));
+ }
+ return $this->config;
+ }
+
+
+ /**
+ * Checks whether $config contains only $expected items and returns combined array.
+ * @return array
+ * @throws Nette\InvalidStateException
+ */
+ public function validateConfig(array $expected, array $config = NULL, $name = NULL)
+ {
+ if (func_num_args() === 1) {
+ return $this->config = $this->validateConfig($expected, $this->config);
+ }
+ if ($extra = array_diff_key((array) $config, $expected)) {
+ $name = $name ?: $this->name;
+ $extra = implode(", $name.", array_keys($extra));
+ throw new Nette\InvalidStateException("Unknown configuration option $name.$extra.");
+ }
+ return Config\Helpers::merge($config, $expected);
+ }
+
+
+ /**
+ * @return ContainerBuilder
+ */
+ public function getContainerBuilder()
+ {
+ return $this->compiler->getContainerBuilder();
+ }
+
+
+ /**
+ * Reads configuration from file.
+ * @param string file name
+ * @return array
+ */
+ public function loadFromFile($file)
+ {
+ $loader = new Config\Loader;
+ $res = $loader->load($file);
+ $this->compiler->addDependencies($loader->getDependencies());
+ return $res;
+ }
+
+
+ /**
+ * Prepend extension name to identifier or service name.
+ * @param string
+ * @return string
+ */
+ public function prefix($id)
+ {
+ return substr_replace($id, $this->name . '.', substr($id, 0, 1) === '@' ? 1 : 0, 0);
+ }
+
+
+ /**
+ * Processes configuration data. Intended to be overridden by descendant.
+ * @return void
+ */
+ public function loadConfiguration()
+ {
+ }
+
+
+ /**
+ * Adjusts DI container before is compiled to PHP class. Intended to be overridden by descendant.
+ * @return void
+ */
+ public function beforeCompile()
+ {
+ }
+
+
+ /**
+ * Adjusts DI container compiled to PHP class. Intended to be overridden by descendant.
+ * @return void
+ */
+ public function afterCompile(Nette\PhpGenerator\ClassType $class)
+ {
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/Config/Adapters/IniAdapter.php b/vendor/nette/di/src/DI/Config/Adapters/IniAdapter.php
new file mode 100755
index 0000000..c573000
--- /dev/null
+++ b/vendor/nette/di/src/DI/Config/Adapters/IniAdapter.php
@@ -0,0 +1,141 @@
+ $secData) {
+ if (is_array($secData)) { // is section?
+ if (substr($secName, -1) === self::RAW_SECTION) {
+ $secName = substr($secName, 0, -1);
+ } else { // process key nesting separator (key1.key2.key3)
+ $tmp = array();
+ foreach ($secData as $key => $val) {
+ $cursor = & $tmp;
+ $key = str_replace(self::ESCAPED_KEY_SEPARATOR, "\xFF", $key);
+ foreach (explode(self::KEY_SEPARATOR, $key) as $part) {
+ $part = str_replace("\xFF", self::KEY_SEPARATOR, $part);
+ if (!isset($cursor[$part]) || is_array($cursor[$part])) {
+ $cursor = & $cursor[$part];
+ } else {
+ throw new Nette\InvalidStateException("Invalid key '$key' in section [$secName] in file '$file'.");
+ }
+ }
+ $cursor = $val;
+ }
+ $secData = $tmp;
+ }
+
+ $parts = explode(self::INHERITING_SEPARATOR, $secName);
+ if (count($parts) > 1) {
+ $secName = trim($parts[0]);
+ $secData[Helpers::EXTENDS_KEY] = trim($parts[1]);
+ }
+ }
+
+ $cursor = & $data; // nesting separator in section name
+ foreach (explode(self::KEY_SEPARATOR, $secName) as $part) {
+ if (!isset($cursor[$part]) || is_array($cursor[$part])) {
+ $cursor = & $cursor[$part];
+ } else {
+ throw new Nette\InvalidStateException("Invalid section [$secName] in file '$file'.");
+ }
+ }
+
+ if (is_array($secData) && is_array($cursor)) {
+ $secData = Helpers::merge($secData, $cursor);
+ }
+
+ $cursor = $secData;
+ }
+
+ return $data;
+ }
+
+
+ /**
+ * Generates configuration in INI format.
+ * @return string
+ */
+ public function dump(array $data)
+ {
+ $output = array();
+ foreach ($data as $name => $secData) {
+ if (!is_array($secData)) {
+ $output = array();
+ self::build($data, $output, '');
+ break;
+ }
+ if ($parent = Helpers::takeParent($secData)) {
+ $output[] = "[$name " . self::INHERITING_SEPARATOR . " $parent]";
+ } else {
+ $output[] = "[$name]";
+ }
+ self::build($secData, $output, '');
+ $output[] = '';
+ }
+ return "; generated by Nette\n\n" . implode(PHP_EOL, $output);
+ }
+
+
+ /**
+ * Recursive builds INI list.
+ * @return void
+ */
+ private static function build($input, & $output, $prefix)
+ {
+ foreach ($input as $key => $val) {
+ $key = str_replace(self::KEY_SEPARATOR, self::ESCAPED_KEY_SEPARATOR, $key);
+ if (is_array($val)) {
+ self::build($val, $output, $prefix . $key . self::KEY_SEPARATOR);
+
+ } elseif (is_bool($val)) {
+ $output[] = "$prefix$key = " . ($val ? 'true' : 'false');
+
+ } elseif (is_numeric($val)) {
+ $output[] = "$prefix$key = $val";
+
+ } elseif (is_string($val)) {
+ $output[] = "$prefix$key = \"$val\"";
+
+ } else {
+ throw new Nette\InvalidArgumentException(sprintf("The '%s' item must be scalar or array, %s given.", $prefix . $key, gettype($val)));
+ }
+ }
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/Config/Adapters/NeonAdapter.php b/vendor/nette/di/src/DI/Config/Adapters/NeonAdapter.php
new file mode 100755
index 0000000..4a1d9fc
--- /dev/null
+++ b/vendor/nette/di/src/DI/Config/Adapters/NeonAdapter.php
@@ -0,0 +1,97 @@
+process((array) Neon\Neon::decode(file_get_contents($file)));
+ }
+
+
+ private function process(array $arr)
+ {
+ $res = array();
+ foreach ($arr as $key => $val) {
+ if (substr($key, -1) === self::PREVENT_MERGING) {
+ if (!is_array($val) && $val !== NULL) {
+ throw new Nette\InvalidStateException("Replacing operator is available only for arrays, item '$key' is not array.");
+ }
+ $key = substr($key, 0, -1);
+ $val[Helpers::EXTENDS_KEY] = Helpers::OVERWRITE;
+
+ } elseif (preg_match('#^(\S+)\s+' . self::INHERITING_SEPARATOR . '\s+(\S+)\z#', $key, $matches)) {
+ if (!is_array($val) && $val !== NULL) {
+ throw new Nette\InvalidStateException("Inheritance operator is available only for arrays, item '$key' is not array.");
+ }
+ list(, $key, $val[Helpers::EXTENDS_KEY]) = $matches;
+ if (isset($res[$key])) {
+ throw new Nette\InvalidStateException("Duplicated key '$key'.");
+ }
+ }
+
+ if (is_array($val)) {
+ $val = $this->process($val);
+
+ } elseif ($val instanceof Neon\Entity) {
+ if ($val->value === Neon\Neon::CHAIN) {
+ $tmp = NULL;
+ foreach ($this->process($val->attributes) as $st) {
+ $tmp = new Statement(
+ $tmp === NULL ? $st->getEntity() : array($tmp, ltrim($st->getEntity(), ':')),
+ $st->arguments
+ );
+ }
+ $val = $tmp;
+ } else {
+ $tmp = $this->process(array($val->value));
+ $val = new Statement($tmp[0], $this->process($val->attributes));
+ }
+ }
+ $res[$key] = $val;
+ }
+ return $res;
+ }
+
+
+ /**
+ * Generates configuration in NEON format.
+ * @return string
+ */
+ public function dump(array $data)
+ {
+ $tmp = array();
+ foreach ($data as $name => $secData) {
+ if ($parent = Helpers::takeParent($secData)) {
+ $name .= ' ' . self::INHERITING_SEPARATOR . ' ' . $parent;
+ }
+ $tmp[$name] = $secData;
+ }
+ return "# generated by Nette\n\n" . Neon\Neon::encode($tmp, Neon\Neon::BLOCK);
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/Config/Adapters/PhpAdapter.php b/vendor/nette/di/src/DI/Config/Adapters/PhpAdapter.php
new file mode 100755
index 0000000..2f6e93b
--- /dev/null
+++ b/vendor/nette/di/src/DI/Config/Adapters/PhpAdapter.php
@@ -0,0 +1,39 @@
+ $val) {
+ if (is_int($key)) {
+ $right[] = $val;
+ } else {
+ if (is_array($val) && isset($val[self::EXTENDS_KEY])) {
+ if ($val[self::EXTENDS_KEY] === self::OVERWRITE) {
+ unset($val[self::EXTENDS_KEY]);
+ }
+ } elseif (isset($right[$key])) {
+ $val = static::merge($val, $right[$key]);
+ }
+ $right[$key] = $val;
+ }
+ }
+ return $right;
+
+ } elseif ($left === NULL && is_array($right)) {
+ return $right;
+
+ } else {
+ return $left;
+ }
+ }
+
+
+ /**
+ * Finds out and removes information about the parent.
+ * @return mixed
+ */
+ public static function takeParent(& $data)
+ {
+ if (is_array($data) && isset($data[self::EXTENDS_KEY])) {
+ $parent = $data[self::EXTENDS_KEY];
+ unset($data[self::EXTENDS_KEY]);
+ return $parent;
+ }
+ }
+
+
+ /**
+ * @return bool
+ */
+ public static function isOverwriting(& $data)
+ {
+ return is_array($data) && isset($data[self::EXTENDS_KEY]) && $data[self::EXTENDS_KEY] === self::OVERWRITE;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public static function isInheriting(& $data)
+ {
+ return is_array($data) && isset($data[self::EXTENDS_KEY]) && $data[self::EXTENDS_KEY] !== self::OVERWRITE;
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/Config/IAdapter.php b/vendor/nette/di/src/DI/Config/IAdapter.php
new file mode 100755
index 0000000..391296c
--- /dev/null
+++ b/vendor/nette/di/src/DI/Config/IAdapter.php
@@ -0,0 +1,30 @@
+ 'Nette\DI\Config\Adapters\PhpAdapter',
+ 'ini' => 'Nette\DI\Config\Adapters\IniAdapter',
+ 'neon' => 'Nette\DI\Config\Adapters\NeonAdapter',
+ );
+
+ private $dependencies = array();
+
+
+ /**
+ * Reads configuration from file.
+ * @param string file name
+ * @param string optional section to load
+ * @return array
+ */
+ public function load($file, $section = NULL)
+ {
+ if (!is_file($file) || !is_readable($file)) {
+ throw new Nette\FileNotFoundException("File '$file' is missing or is not readable.");
+ }
+ $this->dependencies[] = realpath($file);
+ $data = $this->getAdapter($file)->load($file);
+
+ if ($section) {
+ if (isset($data[self::INCLUDES_KEY])) {
+ throw new Nette\InvalidStateException("Section 'includes' must be placed under some top section in file '$file'.");
+ }
+ $data = $this->getSection($data, $section, $file);
+ }
+
+ // include child files
+ $merged = array();
+ if (isset($data[self::INCLUDES_KEY])) {
+ Validators::assert($data[self::INCLUDES_KEY], 'list', "section 'includes' in file '$file'");
+ foreach ($data[self::INCLUDES_KEY] as $include) {
+ $merged = Helpers::merge($this->load(dirname($file) . '/' . $include), $merged);
+ }
+ }
+ unset($data[self::INCLUDES_KEY]);
+
+ return Helpers::merge($data, $merged);
+ }
+
+
+ /**
+ * Save configuration to file.
+ * @param array
+ * @param string file
+ * @return void
+ */
+ public function save($data, $file)
+ {
+ if (file_put_contents($file, $this->getAdapter($file)->dump($data)) === FALSE) {
+ throw new Nette\IOException("Cannot write file '$file'.");
+ }
+ }
+
+
+ /**
+ * Returns configuration files.
+ * @return array
+ */
+ public function getDependencies()
+ {
+ return array_unique($this->dependencies);
+ }
+
+
+ /**
+ * Registers adapter for given file extension.
+ * @param string file extension
+ * @param string|Nette\DI\Config\IAdapter
+ * @return self
+ */
+ public function addAdapter($extension, $adapter)
+ {
+ $this->adapters[strtolower($extension)] = $adapter;
+ return $this;
+ }
+
+
+ /** @return IAdapter */
+ private function getAdapter($file)
+ {
+ $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
+ if (!isset($this->adapters[$extension])) {
+ throw new Nette\InvalidArgumentException("Unknown file extension '$file'.");
+ }
+ return is_object($this->adapters[$extension]) ? $this->adapters[$extension] : new $this->adapters[$extension];
+ }
+
+
+ private function getSection(array $data, $key, $file)
+ {
+ Validators::assertField($data, $key, 'array|null', "section '%' in file '$file'");
+ $item = $data[$key];
+ if ($parent = Helpers::takeParent($item)) {
+ $item = Helpers::merge($item, $this->getSection($data, $parent, $file));
+ }
+ return $item;
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/Container.php b/vendor/nette/di/src/DI/Container.php
new file mode 100755
index 0000000..23fadb6
--- /dev/null
+++ b/vendor/nette/di/src/DI/Container.php
@@ -0,0 +1,334 @@
+parameters = $params + $this->parameters;
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getParameters()
+ {
+ return $this->parameters;
+ }
+
+
+ /**
+ * Adds the service to the container.
+ * @param string
+ * @param object
+ * @return self
+ */
+ public function addService($name, $service)
+ {
+ if (!is_string($name) || !$name) {
+ throw new Nette\InvalidArgumentException(sprintf('Service name must be a non-empty string, %s given.', gettype($name)));
+
+ }
+ $name = isset($this->meta[self::ALIASES][$name]) ? $this->meta[self::ALIASES][$name] : $name;
+ if (isset($this->registry[$name])) {
+ throw new Nette\InvalidStateException("Service '$name' already exists.");
+
+ } elseif (!is_object($service)) {
+ throw new Nette\InvalidArgumentException(sprintf("Service '%s' must be a object, %s given.", $name, gettype($service)));
+
+ } elseif (isset($this->meta[self::SERVICES][$name]) && !$service instanceof $this->meta[self::SERVICES][$name]) {
+ throw new Nette\InvalidArgumentException(sprintf("Service '%s' must be instance of %s, %s given.", $name, $this->meta[self::SERVICES][$name], get_class($service)));
+ }
+
+ $this->registry[$name] = $service;
+ return $this;
+ }
+
+
+ /**
+ * Removes the service from the container.
+ * @param string
+ * @return void
+ */
+ public function removeService($name)
+ {
+ $name = isset($this->meta[self::ALIASES][$name]) ? $this->meta[self::ALIASES][$name] : $name;
+ unset($this->registry[$name]);
+ }
+
+
+ /**
+ * Gets the service object by name.
+ * @param string
+ * @return object
+ * @throws MissingServiceException
+ */
+ public function getService($name)
+ {
+ if (!isset($this->registry[$name])) {
+ if (isset($this->meta[self::ALIASES][$name])) {
+ return $this->getService($this->meta[self::ALIASES][$name]);
+ }
+ $this->registry[$name] = $this->createService($name);
+ }
+ return $this->registry[$name];
+ }
+
+
+ /**
+ * Does the service exist?
+ * @param string service name
+ * @return bool
+ */
+ public function hasService($name)
+ {
+ $name = isset($this->meta[self::ALIASES][$name]) ? $this->meta[self::ALIASES][$name] : $name;
+ return isset($this->registry[$name])
+ || (method_exists($this, $method = self::getMethodName($name))
+ && ($rm = new \ReflectionMethod($this, $method)) && $rm->getName() === $method);
+ }
+
+
+ /**
+ * Is the service created?
+ * @param string service name
+ * @return bool
+ */
+ public function isCreated($name)
+ {
+ if (!$this->hasService($name)) {
+ throw new MissingServiceException("Service '$name' not found.");
+ }
+ $name = isset($this->meta[self::ALIASES][$name]) ? $this->meta[self::ALIASES][$name] : $name;
+ return isset($this->registry[$name]);
+ }
+
+
+ /**
+ * Creates new instance of the service.
+ * @param string service name
+ * @return object
+ * @throws MissingServiceException
+ */
+ public function createService($name, array $args = array())
+ {
+ $name = isset($this->meta[self::ALIASES][$name]) ? $this->meta[self::ALIASES][$name] : $name;
+ $method = self::getMethodName($name);
+ if (isset($this->creating[$name])) {
+ throw new Nette\InvalidStateException(sprintf('Circular reference detected for services: %s.', implode(', ', array_keys($this->creating))));
+
+ } elseif (!method_exists($this, $method) || !($rm = new \ReflectionMethod($this, $method)) || $rm->getName() !== $method) {
+ throw new MissingServiceException("Service '$name' not found.");
+ }
+
+ $this->creating[$name] = TRUE;
+ try {
+ $service = call_user_func_array(array($this, $method), $args);
+ } catch (\Exception $e) {
+ unset($this->creating[$name]);
+ throw $e;
+ }
+ unset($this->creating[$name]);
+
+ if (!is_object($service)) {
+ throw new Nette\UnexpectedValueException("Unable to create service '$name', value returned by method $method() is not object.");
+ }
+
+ return $service;
+ }
+
+
+ /**
+ * Resolves service by type.
+ * @param string class or interface
+ * @param bool throw exception if service doesn't exist?
+ * @return object service or NULL
+ * @throws MissingServiceException
+ */
+ public function getByType($class, $need = TRUE)
+ {
+ $class = ltrim($class, '\\');
+ $names = & $this->meta[self::TYPES][$class][TRUE];
+ if (count($names) === 1) {
+ return $this->getService($names[0]);
+ } elseif (count($names) > 1) {
+ throw new MissingServiceException("Multiple services of type $class found: " . implode(', ', $names) . '.');
+ } elseif ($need) {
+ throw new MissingServiceException("Service of type $class not found.");
+ }
+ }
+
+
+ /**
+ * Gets the service names of the specified type.
+ * @param string
+ * @return string[]
+ */
+ public function findByType($class)
+ {
+ $class = ltrim($class, '\\');
+ $meta = & $this->meta[self::TYPES];
+ return array_merge(
+ isset($meta[$class][TRUE]) ? $meta[$class][TRUE] : array(),
+ isset($meta[$class][FALSE]) ? $meta[$class][FALSE] : array()
+ );
+ }
+
+
+ /**
+ * Gets the service names of the specified tag.
+ * @param string
+ * @return array of [service name => tag attributes]
+ */
+ public function findByTag($tag)
+ {
+ return isset($this->meta[self::TAGS][$tag]) ? $this->meta[self::TAGS][$tag] : array();
+ }
+
+
+ /********************* autowiring ****************d*g**/
+
+
+ /**
+ * Creates new instance using autowiring.
+ * @param string class
+ * @param array arguments
+ * @return object
+ * @throws Nette\InvalidArgumentException
+ */
+ public function createInstance($class, array $args = array())
+ {
+ $rc = new \ReflectionClass($class);
+ if (!$rc->isInstantiable()) {
+ throw new ServiceCreationException("Class $class is not instantiable.");
+
+ } elseif ($constructor = $rc->getConstructor()) {
+ return $rc->newInstanceArgs(Helpers::autowireArguments($constructor, $args, $this));
+
+ } elseif ($args) {
+ throw new ServiceCreationException("Unable to pass arguments, class $class has no constructor.");
+ }
+ return new $class;
+ }
+
+
+ /**
+ * Calls all methods starting with with "inject" using autowiring.
+ * @param object
+ * @return void
+ */
+ public function callInjects($service)
+ {
+ Extensions\InjectExtension::callInjects($this, $service);
+ }
+
+
+ /**
+ * Calls method using autowiring.
+ * @param mixed class, object, function, callable
+ * @param array arguments
+ * @return mixed
+ */
+ public function callMethod($function, array $args = array())
+ {
+ return call_user_func_array(
+ $function,
+ Helpers::autowireArguments(Nette\Utils\Callback::toReflection($function), $args, $this)
+ );
+ }
+
+
+ /********************* shortcuts ****************d*g**/
+
+
+ /**
+ * Expands %placeholders%.
+ * @param mixed
+ * @return mixed
+ * @deprecated
+ */
+ public function expand($s)
+ {
+ return Helpers::expand($s, $this->parameters);
+ }
+
+
+ /** @deprecated */
+ public function &__get($name)
+ {
+ $this->error(__METHOD__, 'getService');
+ $tmp = $this->getService($name);
+ return $tmp;
+ }
+
+
+ /** @deprecated */
+ public function __set($name, $service)
+ {
+ $this->error(__METHOD__, 'addService');
+ $this->addService($name, $service);
+ }
+
+
+ /** @deprecated */
+ public function __isset($name)
+ {
+ $this->error(__METHOD__, 'hasService');
+ return $this->hasService($name);
+ }
+
+
+ /** @deprecated */
+ public function __unset($name)
+ {
+ $this->error(__METHOD__, 'removeService');
+ $this->removeService($name);
+ }
+
+
+ private function error($oldName, $newName)
+ {
+ if (empty($this->parameters['container']['accessors'])) {
+ trigger_error("$oldName() is deprecated; use $newName() or enable di.accessors in configuration.", E_USER_DEPRECATED);
+ }
+ }
+
+
+ public static function getMethodName($name)
+ {
+ $uname = ucfirst($name);
+ return 'createService' . ((string) $name === $uname ? '__' : '') . str_replace('.', '__', $uname);
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/ContainerBuilder.php b/vendor/nette/di/src/DI/ContainerBuilder.php
new file mode 100755
index 0000000..191ae60
--- /dev/null
+++ b/vendor/nette/di/src/DI/ContainerBuilder.php
@@ -0,0 +1,872 @@
+ service */
+ private $aliases = array();
+
+ /** @var array for auto-wiring */
+ private $classes;
+
+ /** @var string[] of classes excluded from auto-wiring */
+ private $excludedClasses = array();
+
+ /** @var array of file names */
+ private $dependencies = array();
+
+ /** @var Nette\PhpGenerator\ClassType[] */
+ private $generatedClasses = array();
+
+ /** @var string */
+ /*private in 5.4*/public $currentService;
+
+
+ /**
+ * Adds new service definition.
+ * @param string
+ * @return ServiceDefinition
+ */
+ public function addDefinition($name, ServiceDefinition $definition = NULL)
+ {
+ if (!is_string($name) || !$name) { // builder is not ready for falsy names such as '0'
+ throw new Nette\InvalidArgumentException(sprintf('Service name must be a non-empty string, %s given.', gettype($name)));
+ }
+ $name = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;
+ if (isset($this->definitions[$name])) {
+ throw new Nette\InvalidStateException("Service '$name' has already been added.");
+ }
+ return $this->definitions[$name] = $definition ?: new ServiceDefinition;
+ }
+
+
+ /**
+ * Removes the specified service definition.
+ * @param string
+ * @return void
+ */
+ public function removeDefinition($name)
+ {
+ $name = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;
+ unset($this->definitions[$name]);
+
+ if ($this->classes) {
+ foreach ($this->classes as & $tmp) {
+ foreach ($tmp as & $names) {
+ $names = array_values(array_diff($names, array($name)));
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Gets the service definition.
+ * @param string
+ * @return ServiceDefinition
+ */
+ public function getDefinition($name)
+ {
+ $service = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;
+ if (!isset($this->definitions[$service])) {
+ throw new MissingServiceException("Service '$name' not found.");
+ }
+ return $this->definitions[$service];
+ }
+
+
+ /**
+ * Gets all service definitions.
+ * @return ServiceDefinition[]
+ */
+ public function getDefinitions()
+ {
+ return $this->definitions;
+ }
+
+
+ /**
+ * Does the service definition or alias exist?
+ * @param string
+ * @return bool
+ */
+ public function hasDefinition($name)
+ {
+ $name = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;
+ return isset($this->definitions[$name]);
+ }
+
+
+ /**
+ * @param string
+ * @param string
+ */
+ public function addAlias($alias, $service)
+ {
+ if (!is_string($alias) || !$alias) { // builder is not ready for falsy names such as '0'
+ throw new Nette\InvalidArgumentException(sprintf('Alias name must be a non-empty string, %s given.', gettype($alias)));
+
+ } elseif (!is_string($service) || !$service) { // builder is not ready for falsy names such as '0'
+ throw new Nette\InvalidArgumentException(sprintf('Service name must be a non-empty string, %s given.', gettype($service)));
+
+ } elseif (isset($this->aliases[$alias])) {
+ throw new Nette\InvalidStateException("Alias '$alias' has already been added.");
+
+ } elseif (isset($this->definitions[$alias])) {
+ throw new Nette\InvalidStateException("Service '$alias' has already been added.");
+
+ }
+ $this->aliases[$alias] = $service;
+ }
+
+
+ /**
+ * Gets all service aliases.
+ * @return array
+ */
+ public function getAliases()
+ {
+ return $this->aliases;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setClassName($name)
+ {
+ $this->className = (string) $name;
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getClassName()
+ {
+ return $this->className;
+ }
+
+
+ /********************* class resolving ****************d*g**/
+
+
+ /**
+ * Resolves service name by type.
+ * @param string class or interface
+ * @return string service name or NULL
+ * @throws ServiceCreationException
+ */
+ public function getByType($class)
+ {
+ $class = ltrim($class, '\\');
+
+ if ($this->currentService !== NULL) {
+ $rc = new ReflectionClass($this->definitions[$this->currentService]->getClass());
+ if ($class === $rc->getName() || $rc->isSubclassOf($class)) {
+ return $this->currentService;
+ }
+ }
+
+ if (!isset($this->classes[$class][TRUE])) {
+ self::checkCase($class);
+ return;
+
+ } elseif (count($this->classes[$class][TRUE]) === 1) {
+ return $this->classes[$class][TRUE][0];
+
+ } else {
+ throw new ServiceCreationException("Multiple services of type $class found: " . implode(', ', $this->classes[$class][TRUE]));
+ }
+ }
+
+
+ /**
+ * Gets the service names and definitions of the specified type.
+ * @param string
+ * @return ServiceDefinition[]
+ */
+ public function findByType($class)
+ {
+ $class = ltrim($class, '\\');
+ self::checkCase($class);
+ $found = array();
+ foreach (array(TRUE, FALSE) as $mode) {
+ if (!empty($this->classes[$class][$mode])) {
+ foreach ($this->classes[$class][$mode] as $name) {
+ $found[$name] = $this->definitions[$name];
+ }
+ }
+ }
+ return $found;
+ }
+
+
+ /**
+ * Gets the service objects of the specified tag.
+ * @param string
+ * @return array of [service name => tag attributes]
+ */
+ public function findByTag($tag)
+ {
+ $found = array();
+ foreach ($this->definitions as $name => $def) {
+ if (($tmp = $def->getTag($tag)) !== NULL) {
+ $found[$name] = $tmp;
+ }
+ }
+ return $found;
+ }
+
+
+ /**
+ * Creates a list of arguments using autowiring.
+ * @return array
+ */
+ public function autowireArguments($class, $method, array $arguments)
+ {
+ $rc = new ReflectionClass($class);
+ if (!$rc->hasMethod($method)) {
+ if (!Nette\Utils\Arrays::isList($arguments)) {
+ throw new ServiceCreationException("Unable to pass specified arguments to $class::$method().");
+ }
+ return $arguments;
+ }
+
+ $rm = $rc->getMethod($method);
+ if (!$rm->isPublic()) {
+ throw new ServiceCreationException("$class::$method() is not callable.");
+ }
+ $this->addDependency($rm->getFileName());
+ return Helpers::autowireArguments($rm, $arguments, $this);
+ }
+
+
+ /**
+ * Generates $dependencies, $classes and normalizes class names.
+ * @return array
+ * @internal
+ */
+ public function prepareClassList()
+ {
+ unset($this->definitions[self::THIS_CONTAINER]);
+ $this->addDefinition(self::THIS_CONTAINER)->setClass('Nette\DI\Container');
+
+ $this->classes = FALSE;
+
+ foreach ($this->definitions as $name => $def) {
+ // prepare generated factories
+ if ($def->getImplement()) {
+ $this->resolveImplement($def, $name);
+ }
+
+ if ($def->isDynamic()) {
+ if (!$def->getClass()) {
+ throw new ServiceCreationException("Class is missing in definition of service '$name'.");
+ }
+ $def->setFactory(NULL);
+ continue;
+ }
+
+ // complete class-factory pairs
+ if (!$def->getEntity()) {
+ if (!$def->getClass()) {
+ throw new ServiceCreationException("Class and factory are missing in definition of service '$name'.");
+ }
+ $def->setFactory($def->getClass(), ($factory = $def->getFactory()) ? $factory->arguments : array());
+ }
+
+ // auto-disable autowiring for aliases
+ if (($alias = $this->getServiceName($def->getFactory()->getEntity())) &&
+ (!$def->getImplement() || (!Strings::contains($alias, '\\') && $this->definitions[$alias]->getImplement()))
+ ) {
+ $def->setAutowired(FALSE);
+ }
+ }
+
+ // resolve and check classes
+ foreach ($this->definitions as $name => $def) {
+ $this->resolveServiceClass($name);
+ }
+
+ // build auto-wiring list
+ $excludedClasses = array();
+ foreach ($this->excludedClasses as $class) {
+ self::checkCase($class);
+ $excludedClasses += class_parents($class) + class_implements($class) + array($class => $class);
+ }
+
+ $this->classes = array();
+ foreach ($this->definitions as $name => $def) {
+ if ($class = $def->getImplement() ?: $def->getClass()) {
+ foreach (class_parents($class) + class_implements($class) + array($class) as $parent) {
+ $this->classes[$parent][$def->isAutowired() && empty($excludedClasses[$parent])][] = (string) $name;
+ }
+ }
+ }
+
+ foreach ($this->classes as $class => $foo) {
+ $rc = new ReflectionClass($class);
+ $this->addDependency($rc->getFileName());
+ }
+ }
+
+
+ private function resolveImplement(ServiceDefinition $def, $name)
+ {
+ $interface = $def->getImplement();
+ if (!interface_exists($interface)) {
+ throw new ServiceCreationException("Interface $interface used in service '$name' not found.");
+ }
+ self::checkCase($interface);
+ $rc = new ReflectionClass($interface);
+ $method = $rc->hasMethod('create') ? $rc->getMethod('create') : ($rc->hasMethod('get') ? $rc->getMethod('get') : NULL);
+ if (count($rc->getMethods()) !== 1 || !$method || $method->isStatic()) {
+ throw new ServiceCreationException("Interface $interface used in service '$name' must have just one non-static method create() or get().");
+ }
+ $def->setImplementType($methodName = $rc->hasMethod('create') ? 'create' : 'get');
+
+ if (!$def->getClass() && !$def->getEntity()) {
+ $returnType = PhpReflection::parseAnnotation($method, 'return');
+ if (!$returnType) {
+ throw new ServiceCreationException("Method $interface::$methodName() used in service '$name' has no @return annotation.");
+ }
+
+ $returnType = PhpReflection::expandClassName(preg_replace('#[|\s].*#', '', $returnType), $rc);
+ if (!class_exists($returnType)) {
+ throw new ServiceCreationException("Please check a @return annotation of the $interface::$methodName() method used in service '$name'. Class '$returnType' cannot be found.");
+ }
+ $def->setClass($returnType);
+ }
+
+ if ($methodName === 'get') {
+ if ($method->getParameters()) {
+ throw new ServiceCreationException("Method $interface::get() used in service '$name' must have no arguments.");
+ }
+ if (!$def->getEntity()) {
+ $def->setFactory('@\\' . ltrim($def->getClass(), '\\'));
+ } elseif (!$this->getServiceName($def->getFactory()->getEntity())) {
+ throw new ServiceCreationException("Invalid factory in service '$name' definition.");
+ }
+ }
+
+ if (!$def->parameters) {
+ $ctorParams = array();
+ if (!$def->getEntity()) {
+ $def->setFactory($def->getClass(), $def->getFactory() ? $def->getFactory()->arguments : array());
+ }
+ if (($class = $this->resolveEntityClass($def->getFactory(), array($name => 1)))
+ && ($rc = new ReflectionClass($class)) && ($ctor = $rc->getConstructor())
+ ) {
+ foreach ($ctor->getParameters() as $param) {
+ $ctorParams[$param->getName()] = $param;
+ }
+ }
+
+ foreach ($method->getParameters() as $param) {
+ $hint = $param->isArray() ? 'array' : PhpReflection::getPropertyType($param);
+ if (isset($ctorParams[$param->getName()])) {
+ $arg = $ctorParams[$param->getName()];
+ if ($hint !== ($arg->isArray() ? 'array' : PhpReflection::getPropertyType($arg))) {
+ throw new ServiceCreationException("Type hint for \${$param->getName()} in $interface::$methodName() doesn't match type hint in $class constructor.");
+ }
+ $def->getFactory()->arguments[$arg->getPosition()] = self::literal('$' . $arg->getName());
+ }
+ $paramDef = $hint . ' ' . $param->getName();
+ if ($param->isOptional()) {
+ $def->parameters[$paramDef] = $param->getDefaultValue();
+ } else {
+ $def->parameters[] = $paramDef;
+ }
+ }
+ }
+ }
+
+
+ /** @return string|NULL */
+ private function resolveServiceClass($name, $recursive = array())
+ {
+ if (isset($recursive[$name])) {
+ throw new ServiceCreationException(sprintf('Circular reference detected for services: %s.', implode(', ', array_keys($recursive))));
+ }
+ $recursive[$name] = TRUE;
+
+ $def = $this->definitions[$name];
+ $class = $def->getFactory() ? $this->resolveEntityClass($def->getFactory()->getEntity(), $recursive) : NULL; // call always to check entities
+ if ($class = $def->getClass() ?: $class) {
+ $def->setClass($class);
+ if (!class_exists($class) && !interface_exists($class)) {
+ throw new ServiceCreationException("Class or interface $class used in service '$name' not found.");
+ }
+ self::checkCase($class);
+
+ } elseif ($def->isAutowired()) {
+ trigger_error("Type of service '$name' is unknown.", E_USER_NOTICE);
+ }
+ return $class;
+ }
+
+
+ /** @return string|NULL */
+ private function resolveEntityClass($entity, $recursive = array())
+ {
+ $entity = $this->normalizeEntity($entity instanceof Statement ? $entity->getEntity() : $entity);
+
+ if (is_array($entity)) {
+ if (($service = $this->getServiceName($entity[0])) || $entity[0] instanceof Statement) {
+ $entity[0] = $this->resolveEntityClass($entity[0], $recursive);
+ if (!$entity[0]) {
+ return;
+ } elseif (isset($this->definitions[$service]) && $this->definitions[$service]->getImplement()) { // @Implement::create
+ return $entity[1] === 'create' ? $this->resolveServiceClass($service, $recursive) : NULL;
+ }
+ }
+
+ try {
+ $reflection = Nette\Utils\Callback::toReflection($entity[0] === '' ? $entity[1] : $entity);
+ $refClass = $reflection instanceof \ReflectionMethod ? $reflection->getDeclaringClass() : NULL;
+ } catch (\ReflectionException $e) {
+ }
+
+ if (isset($e) || ($refClass && (!$reflection->isPublic()
+ || (PHP_VERSION_ID >= 50400 && $refClass->isTrait() && !$reflection->isStatic())
+ ))) {
+ $name = array_slice(array_keys($recursive), -1);
+ throw new ServiceCreationException(sprintf("Factory '%s' used in service '%s' is not callable.", Nette\Utils\Callback::toString($entity), $name[0]));
+ }
+
+ $class = preg_replace('#[|\s].*#', '', PhpReflection::parseAnnotation($reflection, 'return'));
+ if ($class) {
+ $class = $refClass ? PhpReflection::expandClassName($class, $refClass) : ltrim($class, '\\');
+ }
+ return $class;
+
+ } elseif ($service = $this->getServiceName($entity)) { // alias or factory
+ if (Strings::contains($service, '\\')) { // @\Class
+ return ltrim($service, '\\');
+ }
+ return $this->definitions[$service]->getImplement() ?: $this->resolveServiceClass($service, $recursive);
+
+ } elseif (is_string($entity)) {
+ if (!class_exists($entity) || !($rc = new ReflectionClass($entity)) || !$rc->isInstantiable()) {
+ $name = array_slice(array_keys($recursive), -1);
+ throw new ServiceCreationException("Class $entity used in service '$name[0]' not found or is not instantiable.");
+ }
+ return ltrim($entity, '\\');
+ }
+ }
+
+
+ private function checkCase($class)
+ {
+ if (class_exists($class) && ($rc = new ReflectionClass($class)) && $class !== $rc->getName()) {
+ throw new ServiceCreationException("Case mismatch on class name '$class', correct name is '{$rc->getName()}'.");
+ }
+ }
+
+
+ /**
+ * @param string[]
+ * @return self
+ */
+ public function addExcludedClasses(array $classes)
+ {
+ $this->excludedClasses = array_merge($this->excludedClasses, $classes);
+ return $this;
+ }
+
+
+ /**
+ * Adds a file to the list of dependencies.
+ * @return self
+ * @internal
+ */
+ public function addDependency($file)
+ {
+ $this->dependencies[$file] = TRUE;
+ return $this;
+ }
+
+
+ /**
+ * Returns the list of dependent files.
+ * @return array
+ */
+ public function getDependencies()
+ {
+ unset($this->dependencies[FALSE]);
+ return array_keys($this->dependencies);
+ }
+
+
+ /********************* code generator ****************d*g**/
+
+
+ /**
+ * Generates PHP classes. First class is the container.
+ * @return Nette\PhpGenerator\ClassType[]
+ */
+ public function generateClasses($className = NULL, $parentName = NULL)
+ {
+ $this->prepareClassList();
+
+ $this->generatedClasses = array();
+ $this->className = $className ?: $this->className;
+ $containerClass = $this->generatedClasses[] = new Nette\PhpGenerator\ClassType($this->className);
+ $containerClass->setExtends($parentName ?: 'Nette\DI\Container');
+ $containerClass->addMethod('__construct')
+ ->addBody('parent::__construct(?);', array($this->parameters));
+
+ $definitions = $this->definitions;
+ ksort($definitions);
+
+ $meta = $containerClass->addProperty('meta', array())
+ ->setVisibility('protected')
+ ->setValue(array(Container::TYPES => $this->classes));
+
+ foreach ($definitions as $name => $def) {
+ $meta->value[Container::SERVICES][$name] = $def->getClass() ?: NULL;
+ foreach ($def->getTags() as $tag => $value) {
+ $meta->value[Container::TAGS][$tag][$name] = $value;
+ }
+ }
+
+ foreach ($definitions as $name => $def) {
+ try {
+ $name = (string) $name;
+ $methodName = Container::getMethodName($name);
+ if (!PhpHelpers::isIdentifier($methodName)) {
+ throw new ServiceCreationException('Name contains invalid characters.');
+ }
+ $containerClass->addMethod($methodName)
+ ->addDocument('@return ' . ($def->getImplement() ?: $def->getClass()))
+ ->setBody($name === self::THIS_CONTAINER ? 'return $this;' : $this->generateService($name))
+ ->setParameters($def->getImplement() ? array() : $this->convertParameters($def->parameters));
+ } catch (\Exception $e) {
+ throw new ServiceCreationException("Service '$name': " . $e->getMessage(), NULL, $e);
+ }
+ }
+
+ $aliases = $this->aliases;
+ ksort($aliases);
+ $meta->value[Container::ALIASES] = $aliases;
+
+ return $this->generatedClasses;
+ }
+
+
+ /**
+ * Generates body of service method.
+ * @return string
+ */
+ private function generateService($name)
+ {
+ $this->currentService = NULL;
+ $def = $this->definitions[$name];
+
+ if ($def->isDynamic()) {
+ return PhpHelpers::formatArgs('throw new Nette\\DI\\ServiceCreationException(?);',
+ array("Unable to create dynamic service '$name', it must be added using addService()")
+ );
+ }
+
+ $entity = $def->getFactory()->getEntity();
+ $serviceRef = $this->getServiceName($entity);
+ $factory = $serviceRef && !$def->getFactory()->arguments && !$def->getSetup() && $def->getImplementType() !== 'create'
+ ? new Statement(array('@' . self::THIS_CONTAINER, 'getService'), array($serviceRef))
+ : $def->getFactory();
+
+ $code = '$service = ' . $this->formatStatement($factory) . ";\n";
+ $this->currentService = $name;
+
+ if (($class = $def->getClass()) && !$serviceRef && $class !== $entity
+ && !(is_string($entity) && preg_match('#^[\w\\\\]+\z#', $entity) && is_subclass_of($entity, $class))
+ ) {
+ $code .= PhpHelpers::formatArgs("if (!\$service instanceof $class) {\n"
+ . "\tthrow new Nette\\UnexpectedValueException(?);\n}\n",
+ array("Unable to create service '$name', value returned by factory is not $class type.")
+ );
+ }
+
+ foreach ($def->getSetup() as $setup) {
+ if (is_string($setup->getEntity()) && strpbrk($setup->getEntity(), ':@?\\') === FALSE) { // auto-prepend @self
+ $setup->setEntity(array('@self', $setup->getEntity()));
+ }
+ $code .= $this->formatStatement($setup) . ";\n";
+ }
+ $this->currentService = NULL;
+
+ $code .= 'return $service;';
+
+ if (!$def->getImplement()) {
+ return $code;
+ }
+
+ $factoryClass = $this->generatedClasses[] = new Nette\PhpGenerator\ClassType;
+ $factoryClass->setName(str_replace(array('\\', '.'), '_', "{$this->className}_{$def->getImplement()}Impl_{$name}"))
+ ->addImplement($def->getImplement())
+ ->setFinal(TRUE);
+
+ $factoryClass->addProperty('container')
+ ->setVisibility('private');
+
+ $factoryClass->addMethod('__construct')
+ ->addBody('$this->container = $container;')
+ ->addParameter('container')
+ ->setTypeHint($this->className);
+
+ $factoryClass->addMethod($def->getImplementType())
+ ->setParameters($this->convertParameters($def->parameters))
+ ->setBody(str_replace('$this', '$this->container', $code));
+
+ return "return new {$factoryClass->getName()}(\$this);";
+ }
+
+
+ /**
+ * Converts parameters from ServiceDefinition to PhpGenerator.
+ * @return Nette\PhpGenerator\Parameter[]
+ */
+ private function convertParameters(array $parameters)
+ {
+ $res = array();
+ foreach ($parameters as $k => $v) {
+ $tmp = explode(' ', is_int($k) ? $v : $k);
+ $param = $res[] = new Nette\PhpGenerator\Parameter;
+ $param->setName(end($tmp));
+ if (!is_int($k)) {
+ $param = $param->setOptional(TRUE)->setDefaultValue($v);
+ }
+ if (isset($tmp[1])) {
+ $param->setTypeHint($tmp[0]);
+ }
+ }
+ return $res;
+ }
+
+
+ /**
+ * Formats PHP code for class instantiating, function calling or property setting in PHP.
+ * @return string
+ * @internal
+ */
+ public function formatStatement(Statement $statement)
+ {
+ $entity = $this->normalizeEntity($statement->getEntity());
+ $arguments = $statement->arguments;
+
+ if (is_string($entity) && Strings::contains($entity, '?')) { // PHP literal
+ return $this->formatPhp($entity, $arguments);
+
+ } elseif ($service = $this->getServiceName($entity)) { // factory calling
+ $params = array();
+ foreach ($this->definitions[$service]->parameters as $k => $v) {
+ $params[] = preg_replace('#\w+\z#', '\$$0', (is_int($k) ? $v : $k)) . (is_int($k) ? '' : ' = ' . PhpHelpers::dump($v));
+ }
+ $rm = new \ReflectionFunction(create_function(implode(', ', $params), ''));
+ $arguments = Helpers::autowireArguments($rm, $arguments, $this);
+ return $this->formatPhp('$this->?(?*)', array(Container::getMethodName($service), $arguments));
+
+ } elseif ($entity === 'not') { // operator
+ return $this->formatPhp('!?', array($arguments[0]));
+
+ } elseif (is_string($entity)) { // class name
+ $rc = new ReflectionClass($entity);
+ if ($constructor = $rc->getConstructor()) {
+ $this->addDependency($constructor->getFileName());
+ $arguments = Helpers::autowireArguments($constructor, $arguments, $this);
+ } elseif ($arguments) {
+ throw new ServiceCreationException("Unable to pass arguments, class $entity has no constructor.");
+ }
+ return $this->formatPhp("new $entity" . ($arguments ? '(?*)' : ''), array($arguments));
+
+ } elseif (!Nette\Utils\Arrays::isList($entity) || count($entity) !== 2) {
+ throw new ServiceCreationException(sprintf('Expected class, method or property, %s given.', PhpHelpers::dump($entity)));
+
+ } elseif (!preg_match('#^\$?' . PhpHelpers::PHP_IDENT . '\z#', $entity[1])) {
+ throw new ServiceCreationException("Expected function, method or property name, '$entity[1]' given.");
+
+ } elseif ($entity[0] === '') { // globalFunc
+ return $this->formatPhp("$entity[1](?*)", array($arguments));
+
+ } elseif ($entity[0] instanceof Statement) {
+ $inner = $this->formatPhp('?', array($entity[0]));
+ if (substr($inner, 0, 4) === 'new ') {
+ $inner = PHP_VERSION_ID < 50400 ? "current(array($inner))" : "($inner)";
+ }
+ return $this->formatPhp("$inner->?(?*)", array($entity[1], $arguments));
+
+ } elseif (Strings::contains($entity[1], '$')) { // property setter
+ Validators::assert($arguments, 'list:1', "setup arguments for '" . Nette\Utils\Callback::toString($entity) . "'");
+ if ($this->getServiceName($entity[0])) {
+ return $this->formatPhp('?->? = ?', array($entity[0], substr($entity[1], 1), $arguments[0]));
+ } else {
+ return $this->formatPhp($entity[0] . '::$? = ?', array(substr($entity[1], 1), $arguments[0]));
+ }
+
+ } elseif ($service = $this->getServiceName($entity[0])) { // service method
+ $class = $this->definitions[$service]->getImplement();
+ if (!$class || !method_exists($class, $entity[1])) {
+ $class = $this->definitions[$service]->getClass();
+ }
+ if ($class) {
+ $arguments = $this->autowireArguments($class, $entity[1], $arguments);
+ }
+ return $this->formatPhp('?->?(?*)', array($entity[0], $entity[1], $arguments));
+
+ } else { // static method
+ $arguments = $this->autowireArguments($entity[0], $entity[1], $arguments);
+ return $this->formatPhp("$entity[0]::$entity[1](?*)", array($arguments));
+ }
+ }
+
+
+ /**
+ * Formats PHP statement.
+ * @return string
+ * @internal
+ */
+ public function formatPhp($statement, $args)
+ {
+ $that = $this;
+ array_walk_recursive($args, function (& $val) use ($that) {
+ if ($val instanceof Statement) {
+ $val = ContainerBuilder::literal($that->formatStatement($val));
+
+ } elseif ($val === $that) {
+ $val = ContainerBuilder::literal('$this');
+
+ } elseif ($val instanceof ServiceDefinition) {
+ $val = '@' . current(array_keys($that->getDefinitions(), $val, TRUE));
+ }
+
+ if (!is_string($val)) {
+ return;
+
+ } elseif (substr($val, 0, 2) === '@@') {
+ $val = substr($val, 1);
+
+ } elseif (substr($val, 0, 1) === '@') {
+ $pair = explode('::', $val, 2);
+ $name = $that->getServiceName($pair[0]);
+ if (isset($pair[1]) && preg_match('#^[A-Z][A-Z0-9_]*\z#', $pair[1], $m)) {
+ $val = $that->getDefinition($name)->getClass() . '::' . $pair[1];
+ } else {
+ if ($name === ContainerBuilder::THIS_CONTAINER) {
+ $val = '$this';
+ } elseif ($name === $that->currentService) {
+ $val = '$service';
+ } else {
+ $val = $that->formatStatement(new Statement(array('@' . ContainerBuilder::THIS_CONTAINER, 'getService'), array($name)));
+ }
+ $val .= (isset($pair[1]) ? PhpHelpers::formatArgs('->?', array($pair[1])) : '');
+ }
+ $val = ContainerBuilder::literal($val);
+ }
+ });
+ return PhpHelpers::formatArgs($statement, $args);
+ }
+
+
+ /**
+ * Expands %placeholders% in strings.
+ * @return mixed
+ * @deprecated
+ */
+ public function expand($value)
+ {
+ return Helpers::expand($value, $this->parameters);
+ }
+
+
+ /**
+ * @return Nette\PhpGenerator\PhpLiteral
+ */
+ public static function literal($phpCode)
+ {
+ return new Nette\PhpGenerator\PhpLiteral($phpCode);
+ }
+
+
+ /** @internal */
+ public function normalizeEntity($entity)
+ {
+ if (is_string($entity) && Strings::contains($entity, '::') && !Strings::contains($entity, '?')) { // Class::method -> [Class, method]
+ $entity = explode('::', $entity);
+ }
+
+ if (is_array($entity) && $entity[0] instanceof ServiceDefinition) { // [ServiceDefinition, ...] -> [@serviceName, ...]
+ $entity[0] = '@' . current(array_keys($this->definitions, $entity[0], TRUE));
+
+ } elseif ($entity instanceof ServiceDefinition) { // ServiceDefinition -> @serviceName
+ $entity = '@' . current(array_keys($this->definitions, $entity, TRUE));
+
+ } elseif (is_array($entity) && $entity[0] === $this) { // [$this, ...] -> [@container, ...]
+ $entity[0] = '@' . self::THIS_CONTAINER;
+ }
+ return $entity; // Class, @service, [Class, member], [@service, member], [, globalFunc], Statement
+ }
+
+
+ /**
+ * Converts @service or @\Class -> service name and checks its existence.
+ * @return string of FALSE, if argument is not service name
+ * @internal
+ */
+ public function getServiceName($arg)
+ {
+ $arg = $this->normalizeEntity($arg);
+ if (!is_string($arg) || !preg_match('#^@[\w\\\\.].*\z#', $arg)) {
+ return FALSE;
+ }
+ $service = substr($arg, 1);
+ if ($service === self::THIS_SERVICE) {
+ $service = $this->currentService;
+ }
+ if (Strings::contains($service, '\\')) {
+ if ($this->classes === FALSE) { // may be disabled by prepareClassList
+ return $service;
+ }
+ $res = $this->getByType($service);
+ if (!$res) {
+ throw new ServiceCreationException("Reference to missing service of type $service.");
+ }
+ return $res;
+ }
+ $service = isset($this->aliases[$service]) ? $this->aliases[$service] : $service;
+ if (!isset($this->definitions[$service])) {
+ throw new ServiceCreationException("Reference to missing service '$service'.");
+ }
+ return $service;
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/ContainerFactory.php b/vendor/nette/di/src/DI/ContainerFactory.php
new file mode 100755
index 0000000..b0bacae
--- /dev/null
+++ b/vendor/nette/di/src/DI/ContainerFactory.php
@@ -0,0 +1,170 @@
+tempDirectory = $tempDirectory;
+ }
+
+
+ /**
+ * @return Container
+ */
+ public function create()
+ {
+ if (!class_exists($this->class)) {
+ $this->loadClass();
+ }
+ return new $this->class;
+ }
+
+
+ /**
+ * @return string
+ */
+ protected function generateCode()
+ {
+ $compiler = $this->createCompiler();
+ $config = $this->generateConfig();
+ $this->onCompile($this, $compiler, $config);
+
+ $code = "configFiles as $info) {
+ if (is_scalar($info[0])) {
+ $code .= "// source: $info[0] $info[1]\n";
+ }
+ }
+ $code .= "\n" . $compiler->compile($config, $this->class, $this->parentClass);
+
+ if ($this->autoRebuild !== 'compat') { // back compatibility
+ $this->dependencies = array_merge($this->dependencies, $compiler->getContainerBuilder()->getDependencies());
+ }
+ return $code;
+ }
+
+
+ /**
+ * @return array
+ */
+ protected function generateConfig()
+ {
+ $config = array();
+ $loader = $this->createLoader();
+ foreach ($this->configFiles as $info) {
+ $info = is_scalar($info[0]) ? $loader->load($info[0], $info[1]) : $info[0];
+ $config = Config\Helpers::merge($info, $config);
+ }
+ $this->dependencies = array_merge($this->dependencies, $loader->getDependencies());
+
+ return Config\Helpers::merge($config, $this->config);
+ }
+
+
+ /**
+ * @return void
+ */
+ private function loadClass()
+ {
+ $key = md5(serialize(array($this->config, $this->configFiles, $this->class, $this->parentClass)));
+ $file = "$this->tempDirectory/$key.php";
+ if (!$this->isExpired($file) && (@include $file) !== FALSE) {
+ return;
+ }
+
+ $handle = fopen("$file.lock", 'c+');
+ if (!$handle || !flock($handle, LOCK_EX)) {
+ throw new Nette\IOException("Unable to acquire exclusive lock on '$file.lock'.");
+ }
+
+ if (!is_file($file) || $this->isExpired($file)) {
+ $this->dependencies = array();
+ $toWrite[$file] = $this->generateCode();
+ $files = $this->dependencies ? array_combine($this->dependencies, $this->dependencies) : array();
+ $toWrite["$file.meta"] = serialize(@array_map('filemtime', $files)); // @ - file may not exist
+
+ foreach ($toWrite as $name => $content) {
+ if (file_put_contents("$name.tmp", $content) !== strlen($content) || !rename("$name.tmp", $name)) {
+ @unlink("$name.tmp"); // @ - file may not exist
+ throw new Nette\IOException("Unable to create file '$name'.");
+ }
+ }
+ }
+
+ if ((@include $file) === FALSE) { // @ - error escalated to exception
+ throw new Nette\IOException("Unable to include '$file'.");
+ }
+ flock($handle, LOCK_UN);
+ }
+
+
+ private function isExpired($file)
+ {
+ if ($this->autoRebuild) {
+ $meta = @unserialize(file_get_contents("$file.meta")); // @ - files may not exist
+ $files = $meta ? array_combine($tmp = array_keys($meta), $tmp) : array();
+ return $meta !== @array_map('filemtime', $files); // @ - files may not exist
+ }
+ return FALSE;
+ }
+
+
+ /**
+ * @return Compiler
+ */
+ protected function createCompiler()
+ {
+ return new Compiler;
+ }
+
+
+ /**
+ * @return Config\Loader
+ */
+ protected function createLoader()
+ {
+ return new Config\Loader;
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/ContainerLoader.php b/vendor/nette/di/src/DI/ContainerLoader.php
new file mode 100755
index 0000000..ea0e7ea
--- /dev/null
+++ b/vendor/nette/di/src/DI/ContainerLoader.php
@@ -0,0 +1,121 @@
+tempDirectory = $tempDirectory;
+ $this->autoRebuild = $autoRebuild;
+ }
+
+
+ /**
+ * @param mixed
+ * @param callable function (Nette\DI\Compiler $compiler): string|NULL
+ * @return string
+ */
+ public function load($key, $generator)
+ {
+ $class = $this->getClassName($key);
+ if (!class_exists($class, FALSE)) {
+ $this->loadFile($class, $generator);
+ }
+ return $class;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getClassName($key)
+ {
+ return 'Container_' . substr(md5(serialize($key)), 0, 10);
+ }
+
+
+ /**
+ * @return void
+ */
+ private function loadFile($class, $generator)
+ {
+ $file = "$this->tempDirectory/$class.php";
+ if (!$this->isExpired($file) && (@include $file) !== FALSE) {
+ return;
+ }
+
+ if (!is_dir($this->tempDirectory)) {
+ @mkdir($this->tempDirectory); // @ - directory may already exist
+ }
+
+ $handle = fopen("$file.lock", 'c+');
+ if (!$handle || !flock($handle, LOCK_EX)) {
+ throw new Nette\IOException("Unable to acquire exclusive lock on '$file.lock'.");
+ }
+
+ if (!is_file($file) || $this->isExpired($file)) {
+ list($toWrite[$file], $toWrite["$file.meta"]) = $this->generate($class, $generator);
+
+ foreach ($toWrite as $name => $content) {
+ if (file_put_contents("$name.tmp", $content) !== strlen($content) || !rename("$name.tmp", $name)) {
+ @unlink("$name.tmp"); // @ - file may not exist
+ throw new Nette\IOException("Unable to create file '$name'.");
+ }
+ }
+ }
+
+ if ((@include $file) === FALSE) { // @ - error escalated to exception
+ throw new Nette\IOException("Unable to include '$file'.");
+ }
+ flock($handle, LOCK_UN);
+ }
+
+
+ private function isExpired($file)
+ {
+ if ($this->autoRebuild) {
+ $meta = @unserialize(file_get_contents("$file.meta")); // @ - files may not exist
+ $files = $meta ? array_combine($tmp = array_keys($meta), $tmp) : array();
+ return $meta !== @array_map('filemtime', $files); // @ - files may not exist
+ }
+ return FALSE;
+ }
+
+
+ /**
+ * @return array of (code, file[])
+ */
+ protected function generate($class, $generator)
+ {
+ $compiler = new Compiler;
+ $compiler->getContainerBuilder()->setClassName($class);
+ $code = call_user_func_array($generator, array(& $compiler));
+ $code = $code ?: implode("\n\n\n", $compiler->compile());
+ $files = $compiler->getDependencies();
+ $files = $files ? array_combine($files, $files) : array(); // workaround for PHP 5.3 array_combine
+ return array(
+ "getConfig() as $name => $value) {
+ $class->getMethod('initialize')->addBody('define(?, ?);', array($name, $value));
+ }
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/Extensions/DIExtension.php b/vendor/nette/di/src/DI/Extensions/DIExtension.php
new file mode 100755
index 0000000..a5d9c98
--- /dev/null
+++ b/vendor/nette/di/src/DI/Extensions/DIExtension.php
@@ -0,0 +1,74 @@
+ FALSE,
+ 'accessors' => FALSE,
+ );
+
+ /** @var bool */
+ private $debugMode;
+
+ /** @var int */
+ private $time;
+
+
+ public function __construct($debugMode = FALSE)
+ {
+ $this->debugMode = $debugMode;
+ $this->time = microtime(TRUE);
+ }
+
+
+ public function loadConfiguration()
+ {
+ $config = $this->validateConfig($this->defaults);
+ if ($config['accessors']) {
+ $this->getContainerBuilder()->parameters['container']['accessors'] = TRUE;
+ }
+ }
+
+
+ public function afterCompile(Nette\PhpGenerator\ClassType $class)
+ {
+ $initialize = $class->getMethod('initialize');
+ $container = $this->getContainerBuilder();
+
+ if ($this->debugMode && $this->config['debugger']) {
+ Nette\Bridges\DITracy\ContainerPanel::$compilationTime = $this->time;
+ $initialize->addBody($container->formatPhp('?;', array(
+ new Nette\DI\Statement('@Tracy\Bar::addPanel', array(new Nette\DI\Statement('Nette\Bridges\DITracy\ContainerPanel'))),
+ )));
+ }
+
+ foreach (array_filter($container->findByTag('run')) as $name => $on) {
+ $initialize->addBody('$this->getService(?);', array($name));
+ }
+
+ if (!empty($this->config['accessors'])) {
+ $definitions = $container->getDefinitions();
+ ksort($definitions);
+ foreach ($definitions as $name => $def) {
+ if (Nette\PhpGenerator\Helpers::isIdentifier($name)) {
+ $type = $def->getImplement() ?: $def->getClass();
+ $class->addDocument("@property $type \$$name");
+ }
+ }
+ }
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/Extensions/DecoratorExtension.php b/vendor/nette/di/src/DI/Extensions/DecoratorExtension.php
new file mode 100755
index 0000000..456971f
--- /dev/null
+++ b/vendor/nette/di/src/DI/Extensions/DecoratorExtension.php
@@ -0,0 +1,67 @@
+ array(),
+ 'tags' => array(),
+ 'inject' => NULL,
+ );
+
+
+ public function beforeCompile()
+ {
+ foreach ($this->getConfig() as $class => $info) {
+ $info = $this->validateConfig($this->defaults, $info, $this->prefix($class));
+ if ($info['inject'] !== NULL) {
+ $info['tags'][InjectExtension::TAG_INJECT] = $info['inject'];
+ }
+ $this->addSetups($class, (array) $info['setup']);
+ $this->addTags($class, (array) $info['tags']);
+ }
+ }
+
+
+ public function addSetups($type, array $setups)
+ {
+ foreach ($this->findByType($type) as $def) {
+ foreach ($setups as $setup) {
+ $def->addSetup($setup);
+ }
+ }
+ }
+
+
+ public function addTags($type, array $tags)
+ {
+ $tags = Nette\Utils\Arrays::normalize($tags, TRUE);
+ foreach ($this->findByType($type) as $def) {
+ $def->setTags($def->getTags() + $tags);
+ }
+ }
+
+
+ private function findByType($type)
+ {
+ $type = ltrim($type, '\\');
+ return array_filter($this->getContainerBuilder()->getDefinitions(), function ($def) use ($type) {
+ return $def->getClass() === $type
+ || is_subclass_of($def->getClass(), $type)
+ || (PHP_VERSION_ID < 50307 && array_key_exists($type, class_implements($def->getClass())));
+ });
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/Extensions/ExtensionsExtension.php b/vendor/nette/di/src/DI/Extensions/ExtensionsExtension.php
new file mode 100755
index 0000000..14a3a3c
--- /dev/null
+++ b/vendor/nette/di/src/DI/Extensions/ExtensionsExtension.php
@@ -0,0 +1,31 @@
+getConfig() as $name => $class) {
+ if ($class instanceof Nette\DI\Statement) {
+ $rc = new \ReflectionClass($class->getEntity());
+ $this->compiler->addExtension($name, $rc->newInstanceArgs($class->arguments));
+ } else {
+ $this->compiler->addExtension($name, new $class);
+ }
+ }
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/Extensions/InjectExtension.php b/vendor/nette/di/src/DI/Extensions/InjectExtension.php
new file mode 100755
index 0000000..177ab61
--- /dev/null
+++ b/vendor/nette/di/src/DI/Extensions/InjectExtension.php
@@ -0,0 +1,130 @@
+getContainerBuilder()->getDefinitions() as $def) {
+ if ($def->getTag(self::TAG_INJECT) && $def->getClass()) {
+ $this->updateDefinition($def);
+ }
+ }
+ }
+
+
+ private function updateDefinition($def)
+ {
+ $class = $def->getClass();
+ $builder = $this->getContainerBuilder();
+ $injects = array();
+ foreach (self::getInjectProperties($class) as $property => $type) {
+ self::checkType($class, $property, $type, $builder);
+ $injects[] = new DI\Statement('$' . $property, array('@\\' . ltrim($type, '\\')));
+ }
+
+ foreach (self::getInjectMethods($def->getClass()) as $method) {
+ $injects[] = new DI\Statement($method);
+ }
+
+ $setups = $def->getSetup();
+ foreach ($injects as $inject) {
+ foreach ($setups as $key => $setup) {
+ if ($setup->getEntity() === $inject->getEntity()) {
+ $inject = $setup;
+ unset($setups[$key]);
+ }
+ }
+ array_unshift($setups, $inject);
+ }
+ $def->setSetup($setups);
+ }
+
+
+ /**
+ * Generates list of inject methods.
+ * @return array
+ * @internal
+ */
+ public static function getInjectMethods($class)
+ {
+ return array_values(array_filter(get_class_methods($class), function ($name) {
+ return substr($name, 0, 6) === 'inject';
+ }));
+ }
+
+
+ /**
+ * Generates list of properties with annotation @inject.
+ * @return array
+ * @internal
+ */
+ public static function getInjectProperties($class)
+ {
+ $res = array();
+ foreach (get_class_vars($class) as $name => $foo) {
+ $rp = new \ReflectionProperty($class, $name);
+ if (PhpReflection::parseAnnotation($rp, 'inject') !== NULL) {
+ if ($type = PhpReflection::parseAnnotation($rp, 'var')) {
+ $type = PhpReflection::expandClassName($type, PhpReflection::getDeclaringClass($rp));
+ }
+ $res[$name] = $type;
+ }
+ }
+ return $res;
+ }
+
+
+ /**
+ * Calls all methods starting with with "inject" using autowiring.
+ * @return void
+ */
+ public static function callInjects(DI\Container $container, $service)
+ {
+ if (!is_object($service)) {
+ throw new Nette\InvalidArgumentException(sprintf('Service must be object, %s given.', gettype($service)));
+ }
+
+ foreach (array_reverse(self::getInjectMethods($service)) as $method) {
+ $container->callMethod(array($service, $method));
+ }
+
+ foreach (self::getInjectProperties(get_class($service)) as $property => $type) {
+ self::checkType($service, $property, $type, $container);
+ $service->$property = $container->getByType($type);
+ }
+ }
+
+
+ /** @internal */
+ private static function checkType($class, $name, $type, $container)
+ {
+ $rc = PhpReflection::getDeclaringClass(new \ReflectionProperty($class, $name));
+ $fullname = $rc->getName() . '::$' . $name;
+ if (!$type) {
+ throw new Nette\InvalidStateException("Property $fullname has no @var annotation.");
+ } elseif (!class_exists($type) && !interface_exists($type)) {
+ throw new Nette\InvalidStateException("Class or interface '$type' used in @var annotation at $fullname not found. Check annotation and 'use' statements.");
+ } elseif (!$container->getByType($type, FALSE)) {
+ throw new Nette\InvalidStateException("Service of type {$type} used in @var annotation at $fullname not found. Did you register it in configuration file?");
+ }
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/Extensions/PhpExtension.php b/vendor/nette/di/src/DI/Extensions/PhpExtension.php
new file mode 100755
index 0000000..c2da441
--- /dev/null
+++ b/vendor/nette/di/src/DI/Extensions/PhpExtension.php
@@ -0,0 +1,47 @@
+getMethod('initialize');
+ foreach ($this->getConfig() as $name => $value) {
+ if (!is_scalar($value)) {
+ throw new Nette\InvalidStateException("Configuration value for directive '$name' is not scalar.");
+
+ } elseif ($name === 'include_path') {
+ $initialize->addBody('set_include_path(?);', array(str_replace(';', PATH_SEPARATOR, $value)));
+
+ } elseif ($name === 'ignore_user_abort') {
+ $initialize->addBody('ignore_user_abort(?);', array($value));
+
+ } elseif ($name === 'max_execution_time') {
+ $initialize->addBody('set_time_limit(?);', array($value));
+
+ } elseif ($name === 'date.timezone') {
+ $initialize->addBody('date_default_timezone_set(?);', array($value));
+
+ } elseif (function_exists('ini_set')) {
+ $initialize->addBody('ini_set(?, ?);', array($name, $value));
+
+ } elseif (ini_get($name) != $value) { // intentionally ==
+ throw new Nette\NotSupportedException('Required function ini_set() is disabled.');
+ }
+ }
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/Helpers.php b/vendor/nette/di/src/DI/Helpers.php
new file mode 100755
index 0000000..b023cf0
--- /dev/null
+++ b/vendor/nette/di/src/DI/Helpers.php
@@ -0,0 +1,142 @@
+ $val) {
+ $res[$key] = self::expand($val, $params, $recursive);
+ }
+ return $res;
+
+ } elseif ($var instanceof Statement) {
+ return new Statement(self::expand($var->getEntity(), $params, $recursive), self::expand($var->arguments, $params, $recursive));
+
+ } elseif (!is_string($var)) {
+ return $var;
+ }
+
+ $parts = preg_split('#%([\w.-]*)%#i', $var, -1, PREG_SPLIT_DELIM_CAPTURE);
+ $res = '';
+ foreach ($parts as $n => $part) {
+ if ($n % 2 === 0) {
+ $res .= $part;
+
+ } elseif ($part === '') {
+ $res .= '%';
+
+ } elseif (isset($recursive[$part])) {
+ throw new Nette\InvalidArgumentException(sprintf('Circular reference detected for variables: %s.', implode(', ', array_keys($recursive))));
+
+ } else {
+ try {
+ $val = Nette\Utils\Arrays::get($params, explode('.', $part));
+ } catch (Nette\InvalidArgumentException $e) {
+ throw new Nette\InvalidArgumentException("Missing parameter '$part'.", 0, $e);
+ }
+ if ($recursive) {
+ $val = self::expand($val, $params, (is_array($recursive) ? $recursive : array()) + array($part => 1));
+ }
+ if (strlen($part) + 2 === strlen($var)) {
+ return $val;
+ }
+ if (!is_scalar($val)) {
+ throw new Nette\InvalidArgumentException("Unable to concatenate non-scalar parameter '$part' into '$var'.");
+ }
+ $res .= $val;
+ }
+ }
+ return $res;
+ }
+
+
+ /**
+ * Generates list of arguments using autowiring.
+ * @return array
+ */
+ public static function autowireArguments(\ReflectionFunctionAbstract $method, array $arguments, $container)
+ {
+ $optCount = 0;
+ $num = -1;
+ $res = array();
+ $methodName = ($method instanceof \ReflectionMethod ? $method->getDeclaringClass()->getName() . '::' : '')
+ . $method->getName() . '()';
+
+ foreach ($method->getParameters() as $num => $parameter) {
+ if (array_key_exists($num, $arguments)) {
+ $res[$num] = $arguments[$num];
+ unset($arguments[$num]);
+ $optCount = 0;
+
+ } elseif (array_key_exists($parameter->getName(), $arguments)) {
+ $res[$num] = $arguments[$parameter->getName()];
+ unset($arguments[$parameter->getName()]);
+ $optCount = 0;
+
+ } elseif ($class = PhpReflection::getPropertyType($parameter)) { // has object type hint
+ $res[$num] = $container->getByType($class, FALSE);
+ if ($res[$num] === NULL) {
+ if ($parameter->allowsNull()) {
+ $optCount++;
+ } elseif (class_exists($class) || interface_exists($class)) {
+ throw new ServiceCreationException("Service of type {$class} needed by $methodName not found. Did you register it in configuration file?");
+ } else {
+ throw new ServiceCreationException("Class {$class} needed by $methodName not found. Check type hint and 'use' statements.");
+ }
+ } else {
+ if ($container instanceof ContainerBuilder) {
+ $res[$num] = '@' . $res[$num];
+ }
+ $optCount = 0;
+ }
+
+ } elseif ($parameter->isOptional() || $parameter->isDefaultValueAvailable()) {
+ // !optional + defaultAvailable = func($a = NULL, $b) since 5.3.17 & 5.4.7
+ // optional + !defaultAvailable = i.e. Exception::__construct, mysqli::mysqli, ...
+ $res[$num] = $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : NULL;
+ $optCount++;
+
+ } else {
+ throw new ServiceCreationException("Parameter \${$parameter->getName()} in $methodName has no type hint, so its value must be specified.");
+ }
+ }
+
+ // extra parameters
+ while (array_key_exists(++$num, $arguments)) {
+ $res[$num] = $arguments[$num];
+ unset($arguments[$num]);
+ $optCount = 0;
+ }
+ if ($arguments) {
+ throw new ServiceCreationException("Unable to pass specified arguments to $methodName.");
+ }
+
+ return $optCount ? array_slice($res, 0, -$optCount) : $res;
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/PhpReflection.php b/vendor/nette/di/src/DI/PhpReflection.php
new file mode 100755
index 0000000..1f3cedf
--- /dev/null
+++ b/vendor/nette/di/src/DI/PhpReflection.php
@@ -0,0 +1,191 @@
+getDocComment()) {
+ throw new Nette\InvalidStateException('You have to enable phpDoc comments in opcode cache.');
+ }
+ $ok = TRUE;
+ }
+ if (preg_match("#[\\s*]@$name(?:\\s++([^@]\\S*)?|$)#", trim($ref->getDocComment(), '/*'), $m)) {
+ return isset($m[1]) ? $m[1] : '';
+ }
+ }
+
+
+ /**
+ * Returns declaring class or trait.
+ * @return \ReflectionClass
+ */
+ public static function getDeclaringClass(\ReflectionProperty $prop)
+ {
+ if (PHP_VERSION_ID >= 50400) {
+ foreach ($prop->getDeclaringClass()->getTraits() as $trait) {
+ if ($trait->hasProperty($prop->getName())) {
+ return self::getDeclaringClass($trait->getProperty($prop->getName()));
+ }
+ }
+ }
+ return $prop->getDeclaringClass();
+ }
+
+
+ /**
+ * @return string
+ */
+ public static function getPropertyType(\ReflectionParameter $prop)
+ {
+ try {
+ return ($ref = $prop->getClass()) ? $ref->getName() : NULL;
+ } catch (\ReflectionException $e) {
+ if (preg_match('#Class (.+) does not exist#', $e->getMessage(), $m)) {
+ return $m[1];
+ }
+ throw $e;
+ }
+ }
+
+
+ /**
+ * Expands class name into full name.
+ * @param string
+ * @return string full name
+ * @throws Nette\InvalidArgumentException
+ */
+ public static function expandClassName($name, \ReflectionClass $rc)
+ {
+ if (empty($name)) {
+ throw new Nette\InvalidArgumentException('Class name must not be empty.');
+
+ } elseif ($name === 'self') {
+ return $rc->getName();
+
+ } elseif ($name[0] === '\\') { // fully qualified name
+ return ltrim($name, '\\');
+ }
+
+ $uses = & self::$cache[$rc->getName()];
+ if ($uses === NULL) {
+ self::$cache = self::parseUseStatemenets(file_get_contents($rc->getFileName()), $rc->getName()) + self::$cache;
+ $uses = & self::$cache[$rc->getName()];
+ }
+ $parts = explode('\\', $name, 2);
+ if (isset($uses[$parts[0]])) {
+ $parts[0] = $uses[$parts[0]];
+ return implode('\\', $parts);
+
+ } elseif ($rc->inNamespace()) {
+ return $rc->getNamespaceName() . '\\' . $name;
+
+ } else {
+ return $name;
+ }
+ }
+
+
+ /**
+ * Parses PHP code.
+ * @param string
+ * @return array
+ */
+ public static function parseUseStatemenets($code, $forClass = NULL)
+ {
+ $tokens = token_get_all($code);
+ $namespace = $class = $classLevel = $level = NULL;
+ $res = $uses = array();
+
+ while (list(, $token) = each($tokens)) {
+ switch (is_array($token) ? $token[0] : $token) {
+ case T_NAMESPACE:
+ $namespace = self::fetch($tokens, array(T_STRING, T_NS_SEPARATOR)) . '\\';
+ $uses = array();
+ break;
+
+ case T_CLASS:
+ case T_INTERFACE:
+ case PHP_VERSION_ID < 50400 ? -1 : T_TRAIT:
+ if ($name = self::fetch($tokens, T_STRING)) {
+ $class = $namespace . $name;
+ $classLevel = $level + 1;
+ $res[$class] = $uses;
+ if ($class === $forClass) {
+ return $res;
+ }
+ }
+ break;
+
+ case T_USE:
+ while (!$class && ($name = self::fetch($tokens, array(T_STRING, T_NS_SEPARATOR)))) {
+ if (self::fetch($tokens, T_AS)) {
+ $uses[self::fetch($tokens, T_STRING)] = ltrim($name, '\\');
+ } else {
+ $tmp = explode('\\', $name);
+ $uses[end($tmp)] = $name;
+ }
+ if (!self::fetch($tokens, ',')) {
+ break;
+ }
+ }
+ break;
+
+ case T_CURLY_OPEN:
+ case T_DOLLAR_OPEN_CURLY_BRACES:
+ case '{':
+ $level++;
+ break;
+
+ case '}':
+ if ($level === $classLevel) {
+ $class = $classLevel = NULL;
+ }
+ $level--;
+ }
+ }
+
+ return $res;
+ }
+
+
+ private static function fetch(& $tokens, $take)
+ {
+ $res = NULL;
+ while ($token = current($tokens)) {
+ list($token, $s) = is_array($token) ? $token : array($token, $token);
+ if (in_array($token, (array) $take, TRUE)) {
+ $res .= $s;
+ } elseif (!in_array($token, array(T_DOC_COMMENT, T_WHITESPACE, T_COMMENT), TRUE)) {
+ break;
+ }
+ next($tokens);
+ }
+ return $res;
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/ServiceDefinition.php b/vendor/nette/di/src/DI/ServiceDefinition.php
new file mode 100755
index 0000000..e5badd2
--- /dev/null
+++ b/vendor/nette/di/src/DI/ServiceDefinition.php
@@ -0,0 +1,312 @@
+class = ltrim($class, '\\');
+ if ($args) {
+ $this->setFactory($class, $args);
+ }
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getClass()
+ {
+ return $this->class;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setFactory($factory, array $args = array())
+ {
+ $this->factory = $factory instanceof Statement ? $factory : new Statement($factory, $args);
+ return $this;
+ }
+
+
+ /**
+ * @return Statement|NULL
+ */
+ public function getFactory()
+ {
+ return $this->factory;
+ }
+
+
+ public function getEntity()
+ {
+ return $this->factory ? $this->factory->getEntity() : NULL;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setArguments(array $args = array())
+ {
+ if (!$this->factory) {
+ $this->factory = new Statement($this->class);
+ }
+ $this->factory->arguments = $args;
+ return $this;
+ }
+
+
+ /**
+ * @param Statement[]
+ * @return self
+ */
+ public function setSetup(array $setup)
+ {
+ foreach ($setup as $v) {
+ if (!$v instanceof Statement) {
+ throw new Nette\InvalidArgumentException('Argument must be Nette\DI\Statement[].');
+ }
+ }
+ $this->setup = $setup;
+ return $this;
+ }
+
+
+ /**
+ * @return Statement[]
+ */
+ public function getSetup()
+ {
+ return $this->setup;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function addSetup($entity, array $args = array())
+ {
+ $this->setup[] = $entity instanceof Statement ? $entity : new Statement($entity, $args);
+ return $this;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setParameters(array $params)
+ {
+ $this->parameters = $params;
+ return $this;
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getParameters()
+ {
+ return $this->parameters;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setTags(array $tags)
+ {
+ $this->tags = $tags;
+ return $this;
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getTags()
+ {
+ return $this->tags;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function addTag($tag, $attr = TRUE)
+ {
+ $this->tags[$tag] = $attr;
+ return $this;
+ }
+
+
+ /**
+ * @return mixed
+ */
+ public function getTag($tag)
+ {
+ return isset($this->tags[$tag]) ? $this->tags[$tag] : NULL;
+ }
+
+
+ /**
+ * @param bool
+ * @return self
+ */
+ public function setAutowired($state = TRUE)
+ {
+ $this->autowired = (bool) $state;
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isAutowired()
+ {
+ return $this->autowired;
+ }
+
+
+ /**
+ * @param bool
+ * @return self
+ */
+ public function setDynamic($state = TRUE)
+ {
+ $this->dynamic = (bool) $state;
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isDynamic()
+ {
+ return $this->dynamic;
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function setImplement($interface)
+ {
+ $this->implement = ltrim($interface, '\\');
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getImplement()
+ {
+ return $this->implement;
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function setImplementType($type)
+ {
+ if (!in_array($type, array('get', 'create'), TRUE)) {
+ throw new Nette\InvalidArgumentException('Argument must be get|create.');
+ }
+ $this->implementType = $type;
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getImplementType()
+ {
+ return $this->implementType;
+ }
+
+
+ /** @deprecated */
+ public function setShared($on)
+ {
+ trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
+ $this->autowired = $on ? $this->autowired : FALSE;
+ return $this;
+ }
+
+
+ /** @deprecated */
+ public function isShared()
+ {
+ trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
+ }
+
+
+ /** @return self */
+ public function setInject($state = TRUE)
+ {
+ //trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
+ return $this->addTag(Extensions\InjectExtension::TAG_INJECT, $state);
+ }
+
+
+ /** @return self */
+ public function getInject()
+ {
+ //trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
+ return $this->getTag(Extensions\InjectExtension::TAG_INJECT);
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/Statement.php b/vendor/nette/di/src/DI/Statement.php
new file mode 100755
index 0000000..37cea4a
--- /dev/null
+++ b/vendor/nette/di/src/DI/Statement.php
@@ -0,0 +1,56 @@
+setEntity($entity);
+ $this->arguments = $arguments;
+ }
+
+
+ /**
+ * @param string|array|ServiceDefinition|NULL
+ * @return self
+ */
+ public function setEntity($entity)
+ {
+ if (!is_string($entity) && !(is_array($entity) && isset($entity[0], $entity[1]))
+ && !$entity instanceof ServiceDefinition && $entity !== NULL
+ ) {
+ throw new Nette\InvalidArgumentException('Argument is not valid Statement entity.');
+ }
+ $this->entity = $entity;
+ return $this;
+ }
+
+
+ public function getEntity()
+ {
+ return $this->entity;
+ }
+
+}
diff --git a/vendor/nette/di/src/DI/exceptions.php b/vendor/nette/di/src/DI/exceptions.php
new file mode 100755
index 0000000..7a2589f
--- /dev/null
+++ b/vendor/nette/di/src/DI/exceptions.php
@@ -0,0 +1,26 @@
+=5.3.1",
+ "nette/utils": "~2.2"
+ },
+ "require-dev": {
+ "nette/tester": "~1.4"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/finder/license.md b/vendor/nette/finder/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/finder/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/finder/src/Finder/CallbackFilterIterator.php b/vendor/nette/finder/src/Finder/CallbackFilterIterator.php
new file mode 100755
index 0000000..d3d67de
--- /dev/null
+++ b/vendor/nette/finder/src/Finder/CallbackFilterIterator.php
@@ -0,0 +1,34 @@
+callback = $callback;
+ }
+
+
+ public function accept()
+ {
+ return call_user_func($this->callback, $this->current(), $this->key(), $this);
+ }
+
+}
diff --git a/vendor/nette/finder/src/Finder/Finder.php b/vendor/nette/finder/src/Finder/Finder.php
new file mode 100755
index 0000000..0b00632
--- /dev/null
+++ b/vendor/nette/finder/src/Finder/Finder.php
@@ -0,0 +1,396 @@
+
+ * Finder::findFiles('*.php')
+ * ->size('> 10kB')
+ * ->from('.')
+ * ->exclude('temp');
+ *
+ */
+class Finder extends Nette\Object implements \IteratorAggregate, \Countable
+{
+ /** @var array */
+ private $paths = array();
+
+ /** @var array of filters */
+ private $groups;
+
+ /** @var filter for recursive traversing */
+ private $exclude = array();
+
+ /** @var int */
+ private $order = RecursiveIteratorIterator::SELF_FIRST;
+
+ /** @var int */
+ private $maxDepth = -1;
+
+ /** @var array */
+ private $cursor;
+
+
+ /**
+ * Begins search for files matching mask and all directories.
+ * @param mixed
+ * @return Finder
+ */
+ public static function find($mask)
+ {
+ if (!is_array($mask)) {
+ $mask = func_get_args();
+ }
+ $finder = new static;
+ return $finder->select($mask, 'isDir')->select($mask, 'isFile');
+ }
+
+
+ /**
+ * Begins search for files matching mask.
+ * @param mixed
+ * @return Finder
+ */
+ public static function findFiles($mask)
+ {
+ if (!is_array($mask)) {
+ $mask = func_get_args();
+ }
+ $finder = new static;
+ return $finder->select($mask, 'isFile');
+ }
+
+
+ /**
+ * Begins search for directories matching mask.
+ * @param mixed
+ * @return Finder
+ */
+ public static function findDirectories($mask)
+ {
+ if (!is_array($mask)) {
+ $mask = func_get_args();
+ }
+ $finder = new static;
+ return $finder->select($mask, 'isDir');
+ }
+
+
+ /**
+ * Creates filtering group by mask & type selector.
+ * @param array
+ * @param string
+ * @return self
+ */
+ private function select($masks, $type)
+ {
+ $this->cursor = & $this->groups[];
+ $pattern = self::buildPattern($masks);
+ if ($type || $pattern) {
+ $this->filter(function (FilesystemIterator $file) use ($type, $pattern) {
+ return !$file->isDot()
+ && (!$type || $file->$type())
+ && (!$pattern || preg_match($pattern, '/' . strtr($file->getSubPathName(), '\\', '/')));
+ });
+ }
+ return $this;
+ }
+
+
+ /**
+ * Searchs in the given folder(s).
+ * @param string|array
+ * @return self
+ */
+ public function in($path)
+ {
+ if (!is_array($path)) {
+ $path = func_get_args();
+ }
+ $this->maxDepth = 0;
+ return $this->from($path);
+ }
+
+
+ /**
+ * Searchs recursively from the given folder(s).
+ * @param string|array
+ * @return self
+ */
+ public function from($path)
+ {
+ if ($this->paths) {
+ throw new Nette\InvalidStateException('Directory to search has already been specified.');
+ }
+ if (!is_array($path)) {
+ $path = func_get_args();
+ }
+ $this->paths = $path;
+ $this->cursor = & $this->exclude;
+ return $this;
+ }
+
+
+ /**
+ * Shows folder content prior to the folder.
+ * @return self
+ */
+ public function childFirst()
+ {
+ $this->order = RecursiveIteratorIterator::CHILD_FIRST;
+ return $this;
+ }
+
+
+ /**
+ * Converts Finder pattern to regular expression.
+ * @param array
+ * @return string
+ */
+ private static function buildPattern($masks)
+ {
+ $pattern = array();
+ foreach ($masks as $mask) {
+ $mask = rtrim(strtr($mask, '\\', '/'), '/');
+ $prefix = '';
+ if ($mask === '') {
+ continue;
+
+ } elseif ($mask === '*') {
+ return NULL;
+
+ } elseif ($mask[0] === '/') { // absolute fixing
+ $mask = ltrim($mask, '/');
+ $prefix = '(?<=^/)';
+ }
+ $pattern[] = $prefix . strtr(preg_quote($mask, '#'),
+ array('\*\*' => '.*', '\*' => '[^/]*', '\?' => '[^/]', '\[\!' => '[^', '\[' => '[', '\]' => ']', '\-' => '-'));
+ }
+ return $pattern ? '#/(' . implode('|', $pattern) . ')\z#i' : NULL;
+ }
+
+
+ /********************* iterator generator ****************d*g**/
+
+
+ /**
+ * Get the number of found files and/or directories.
+ * @return int
+ */
+ public function count()
+ {
+ return iterator_count($this->getIterator());
+ }
+
+
+ /**
+ * Returns iterator.
+ * @return \Iterator
+ */
+ public function getIterator()
+ {
+ if (!$this->paths) {
+ throw new Nette\InvalidStateException('Call in() or from() to specify directory to search.');
+
+ } elseif (count($this->paths) === 1) {
+ return $this->buildIterator($this->paths[0]);
+
+ } else {
+ $iterator = new \AppendIterator();
+ $iterator->append($workaround = new \ArrayIterator(array('workaround PHP bugs #49104, #63077')));
+ foreach ($this->paths as $path) {
+ $iterator->append($this->buildIterator($path));
+ }
+ unset($workaround[0]);
+ return $iterator;
+ }
+ }
+
+
+ /**
+ * Returns per-path iterator.
+ * @param string
+ * @return \Iterator
+ */
+ private function buildIterator($path)
+ {
+ $iterator = new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::FOLLOW_SYMLINKS);
+
+ if ($this->exclude) {
+ $filters = $this->exclude;
+ $iterator = new RecursiveCallbackFilterIterator($iterator, function ($foo, $bar, RecursiveCallbackFilterIterator $iterator) use ($filters) {
+ $file = $iterator->getInnerIterator();
+ if (!$file->isDot() && !$file->isFile()) {
+ foreach ($filters as $filter) {
+ if (!call_user_func($filter, $file)) {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+ });
+ }
+
+ if ($this->maxDepth !== 0) {
+ $iterator = new RecursiveIteratorIterator($iterator, $this->order);
+ $iterator->setMaxDepth($this->maxDepth);
+ }
+
+ if ($this->groups) {
+ $groups = $this->groups;
+ $iterator = new CallbackFilterIterator($iterator, function ($foo, $bar, CallbackFilterIterator $file) use ($groups) {
+ do {
+ $file = $file->getInnerIterator();
+ } while (!$file instanceof FilesystemIterator);
+
+ foreach ($groups as $filters) {
+ foreach ($filters as $filter) {
+ if (!call_user_func($filter, $file)) {
+ continue 2;
+ }
+ }
+ return TRUE;
+ }
+ return FALSE;
+ });
+ }
+
+ return $iterator;
+ }
+
+
+ /********************* filtering ****************d*g**/
+
+
+ /**
+ * Restricts the search using mask.
+ * Excludes directories from recursive traversing.
+ * @param mixed
+ * @return self
+ */
+ public function exclude($masks)
+ {
+ if (!is_array($masks)) {
+ $masks = func_get_args();
+ }
+ $pattern = self::buildPattern($masks);
+ if ($pattern) {
+ $this->filter(function (FilesystemIterator $file) use ($pattern) {
+ return !preg_match($pattern, '/' . strtr($file->getSubPathName(), '\\', '/'));
+ });
+ }
+ return $this;
+ }
+
+
+ /**
+ * Restricts the search using callback.
+ * @param callable function (FilesystemIterator $file)
+ * @return self
+ */
+ public function filter($callback)
+ {
+ $this->cursor[] = $callback;
+ return $this;
+ }
+
+
+ /**
+ * Limits recursion level.
+ * @param int
+ * @return self
+ */
+ public function limitDepth($depth)
+ {
+ $this->maxDepth = $depth;
+ return $this;
+ }
+
+
+ /**
+ * Restricts the search by size.
+ * @param string "[operator] [size] [unit]" example: >=10kB
+ * @param int
+ * @return self
+ */
+ public function size($operator, $size = NULL)
+ {
+ if (func_num_args() === 1) { // in $operator is predicate
+ if (!preg_match('#^(?:([=<>!]=?|<>)\s*)?((?:\d*\.)?\d+)\s*(K|M|G|)B?\z#i', $operator, $matches)) {
+ throw new Nette\InvalidArgumentException('Invalid size predicate format.');
+ }
+ list(, $operator, $size, $unit) = $matches;
+ static $units = array('' => 1, 'k' => 1e3, 'm' => 1e6, 'g' => 1e9);
+ $size *= $units[strtolower($unit)];
+ $operator = $operator ? $operator : '=';
+ }
+ return $this->filter(function (FilesystemIterator $file) use ($operator, $size) {
+ return Finder::compare($file->getSize(), $operator, $size);
+ });
+ }
+
+
+ /**
+ * Restricts the search by modified time.
+ * @param string "[operator] [date]" example: >1978-01-23
+ * @param mixed
+ * @return self
+ */
+ public function date($operator, $date = NULL)
+ {
+ if (func_num_args() === 1) { // in $operator is predicate
+ if (!preg_match('#^(?:([=<>!]=?|<>)\s*)?(.+)\z#i', $operator, $matches)) {
+ throw new Nette\InvalidArgumentException('Invalid date predicate format.');
+ }
+ list(, $operator, $date) = $matches;
+ $operator = $operator ? $operator : '=';
+ }
+ $date = DateTime::from($date)->format('U');
+ return $this->filter(function (FilesystemIterator $file) use ($operator, $date) {
+ return Finder::compare($file->getMTime(), $operator, $date);
+ });
+ }
+
+
+ /**
+ * Compares two values.
+ * @param mixed
+ * @param mixed
+ * @return bool
+ */
+ public static function compare($l, $operator, $r)
+ {
+ switch ($operator) {
+ case '>':
+ return $l > $r;
+ case '>=':
+ return $l >= $r;
+ case '<':
+ return $l < $r;
+ case '<=':
+ return $l <= $r;
+ case '=':
+ case '==':
+ return $l == $r;
+ case '!':
+ case '!=':
+ case '<>':
+ return $l != $r;
+ default:
+ throw new Nette\InvalidArgumentException("Unknown operator $operator.");
+ }
+ }
+
+}
diff --git a/vendor/nette/finder/src/Finder/RecursiveCallbackFilterIterator.php b/vendor/nette/finder/src/Finder/RecursiveCallbackFilterIterator.php
new file mode 100755
index 0000000..7642042
--- /dev/null
+++ b/vendor/nette/finder/src/Finder/RecursiveCallbackFilterIterator.php
@@ -0,0 +1,36 @@
+getInnerIterator()->hasChildren();
+ }
+
+
+ public function getChildren()
+ {
+ return new static($this->getInnerIterator()->getChildren(), $this->callback);
+ }
+
+}
diff --git a/vendor/nette/forms/composer.json b/vendor/nette/forms/composer.json
new file mode 100755
index 0000000..4ddd17a
--- /dev/null
+++ b/vendor/nette/forms/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "nette/forms",
+ "description": "Nette Forms: greatly facilitates web forms",
+ "homepage": "http://nette.org",
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.1",
+ "nette/component-model": "~2.2",
+ "nette/http": "~2.2",
+ "nette/utils": "~2.2"
+ },
+ "require-dev": {
+ "nette/di": "~2.3",
+ "nette/tester": "~1.3",
+ "latte/latte": "~2.3.2",
+ "tracy/tracy": "~2.2"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/forms/license.md b/vendor/nette/forms/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/forms/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/forms/src/Bridges/FormsDI/FormsExtension.php b/vendor/nette/forms/src/Bridges/FormsDI/FormsExtension.php
new file mode 100755
index 0000000..855bd57
--- /dev/null
+++ b/vendor/nette/forms/src/Bridges/FormsDI/FormsExtension.php
@@ -0,0 +1,39 @@
+ array(),
+ );
+
+
+ public function afterCompile(Nette\PhpGenerator\ClassType $class)
+ {
+ $initialize = $class->getMethod('initialize');
+ $config = $this->validateConfig($this->defaults);
+
+ foreach ((array) $config['messages'] as $name => $text) {
+ if (defined('Nette\Forms\Form::' . $name)) {
+ $initialize->addBody('Nette\Forms\Validator::$messages[Nette\Forms\Form::?] = ?;', array($name, $text));
+ } elseif (defined($name)) {
+ $initialize->addBody('Nette\Forms\Validator::$messages[' . $name . '] = ?;', array($text));
+ } else {
+ throw new Nette\InvalidArgumentException('Constant Nette\Forms\Form::' . $name . ' or constant ' . $name . ' does not exist.');
+ }
+ }
+ }
+
+}
diff --git a/vendor/nette/forms/src/Bridges/FormsLatte/FormMacros.php b/vendor/nette/forms/src/Bridges/FormsLatte/FormMacros.php
new file mode 100755
index 0000000..1025ff3
--- /dev/null
+++ b/vendor/nette/forms/src/Bridges/FormsLatte/FormMacros.php
@@ -0,0 +1,240 @@
+addMacro('form', array($me, 'macroForm'), 'echo Nette\Bridges\FormsLatte\Runtime::renderFormEnd($_form)');
+ $me->addMacro('formContainer', array($me, 'macroFormContainer'), '$formContainer = $_form = array_pop($_formStack)');
+ $me->addMacro('label', array($me, 'macroLabel'), array($me, 'macroLabelEnd'));
+ $me->addMacro('input', array($me, 'macroInput'), NULL, array($me, 'macroInputAttr'));
+ $me->addMacro('name', array($me, 'macroName'), array($me, 'macroNameEnd'), array($me, 'macroNameAttr'));
+ $me->addMacro('inputError', array($me, 'macroInputError'));
+ }
+
+
+ /********************* macros ****************d*g**/
+
+
+ /**
+ * {form ...}
+ */
+ public function macroForm(MacroNode $node, PhpWriter $writer)
+ {
+ if ($node->prefix) {
+ throw new CompileException('Did you mean ?');
+ }
+ $name = $node->tokenizer->fetchWord();
+ if ($name === FALSE) {
+ throw new CompileException("Missing form name in {{$node->name}}.");
+ }
+ $node->tokenizer->reset();
+ return $writer->write(
+ 'echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form = $_form = '
+ . ($name[0] === '$' ? 'is_object(%node.word) ? %node.word : ' : '')
+ . '$_control[%node.word], %node.array)'
+ );
+ }
+
+
+ /**
+ * {formContainer ...}
+ */
+ public function macroFormContainer(MacroNode $node, PhpWriter $writer)
+ {
+ $name = $node->tokenizer->fetchWord();
+ if ($name === FALSE) {
+ throw new CompileException("Missing name in {{$node->name}}.");
+ }
+ $node->tokenizer->reset();
+ return $writer->write(
+ '$_formStack[] = $_form; $formContainer = $_form = ' . ($name[0] === '$' ? 'is_object(%node.word) ? %node.word : ' : '') . '$_form[%node.word]'
+ );
+ }
+
+
+ /**
+ * {label ...}
+ */
+ public function macroLabel(MacroNode $node, PhpWriter $writer)
+ {
+ $words = $node->tokenizer->fetchWords();
+ if (!$words) {
+ throw new CompileException("Missing name in {{$node->name}}.");
+ }
+ $name = array_shift($words);
+ return $writer->write(
+ ($name[0] === '$' ? '$_input = is_object(%0.word) ? %0.word : $_form[%0.word]; if ($_label = $_input' : 'if ($_label = $_form[%0.word]')
+ . '->%1.raw) echo $_label'
+ . ($node->tokenizer->isNext() ? '->addAttributes(%node.array)' : ''),
+ $name,
+ $words ? ('getLabelPart(' . implode(', ', array_map(array($writer, 'formatWord'), $words)) . ')') : 'getLabel()'
+ );
+ }
+
+
+ /**
+ * {/label}
+ */
+ public function macroLabelEnd(MacroNode $node, PhpWriter $writer)
+ {
+ if ($node->content != NULL) {
+ $node->openingCode = rtrim($node->openingCode, '?> ') . '->startTag() ?>';
+ return $writer->write('if ($_label) echo $_label->endTag()');
+ }
+ }
+
+
+ /**
+ * {input ...}
+ */
+ public function macroInput(MacroNode $node, PhpWriter $writer)
+ {
+ $words = $node->tokenizer->fetchWords();
+ if (!$words) {
+ throw new CompileException("Missing name in {{$node->name}}.");
+ }
+ $name = array_shift($words);
+ return $writer->write(
+ ($name[0] === '$' ? '$_input = is_object(%0.word) ? %0.word : $_form[%0.word]; echo $_input' : 'echo $_form[%0.word]')
+ . '->%1.raw'
+ . ($node->tokenizer->isNext() ? '->addAttributes(%node.array)' : ''),
+ $name,
+ $words ? 'getControlPart(' . implode(', ', array_map(array($writer, 'formatWord'), $words)) . ')' : 'getControl()'
+ );
+ }
+
+
+ /**
+ * deprecated n:input
+ */
+ public function macroInputAttr(MacroNode $node, PhpWriter $writer)
+ {
+ throw new CompileException('Use n:name instead of n:input.');
+ }
+
+
+ /**
+ * , , , , and
+ */
+ public function macroNameAttr(MacroNode $node, PhpWriter $writer)
+ {
+ $words = $node->tokenizer->fetchWords();
+ if (!$words) {
+ throw new CompileException("Missing name in n:{$node->name}.");
+ }
+ $name = array_shift($words);
+ $tagName = strtolower($node->htmlNode->name);
+ $node->isEmpty = $tagName === 'input';
+
+ if ($tagName === 'form') {
+ return $writer->write(
+ 'echo Nette\Bridges\FormsLatte\Runtime::renderFormBegin($form = $_form = '
+ . ($name[0] === '$' ? 'is_object(%0.word) ? %0.word : ' : '')
+ . '$_control[%0.word], %1.var, FALSE)',
+ $name,
+ array_fill_keys(array_keys($node->htmlNode->attrs), NULL)
+ );
+ } else {
+ $method = $tagName === 'label' ? 'getLabel' : 'getControl';
+ return $writer->write(
+ '$_input = ' . ($name[0] === '$' ? 'is_object(%0.word) ? %0.word : ' : '')
+ . '$_form[%0.word]; echo $_input->%1.raw'
+ . ($node->htmlNode->attrs ? '->addAttributes(%2.var)' : '') . '->attributes()',
+ $name,
+ $words
+ ? $method . 'Part(' . implode(', ', array_map(array($writer, 'formatWord'), $words)) . ')'
+ : "{method_exists(\$_input, '{$method}Part')?'{$method}Part':'{$method}'}()",
+ array_fill_keys(array_keys($node->htmlNode->attrs), NULL)
+ );
+ }
+ }
+
+
+ public function macroName(MacroNode $node, PhpWriter $writer)
+ {
+ if (!$node->prefix) {
+ throw new CompileException("Unknown macro {{$node->name}}, use n:{$node->name} attribute.");
+ } elseif ($node->prefix !== MacroNode::PREFIX_NONE) {
+ throw new CompileException("Unknown attribute n:{$node->prefix}-{$node->name}, use n:{$node->name} attribute.");
+ }
+ }
+
+
+ public function macroNameEnd(MacroNode $node, PhpWriter $writer)
+ {
+ preg_match('#^(.*? n:\w+>)(.*)(<[^?].*)\z#s', $node->content, $parts);
+ $tagName = strtolower($node->htmlNode->name);
+ if ($tagName === 'form') {
+ $node->content = $parts[1] . $parts[2] . '' . $parts[3];
+ } elseif ($tagName === 'label') {
+ if ($node->htmlNode->isEmpty) {
+ $node->content = $parts[1] . "{method_exists(\$_input, 'getLabelPart')?'getLabelPart':'getLabel'}()->getHtml() ?>" . $parts[3];
+ }
+ } elseif ($tagName === 'button') {
+ if ($node->htmlNode->isEmpty) {
+ $node->content = $parts[1] . 'caption) ?>' . $parts[3];
+ }
+ } else { // select, textarea
+ $node->content = $parts[1] . 'getControl()->getHtml() ?>' . $parts[3];
+ }
+ }
+
+
+ /**
+ * {inputError ...}
+ */
+ public function macroInputError(MacroNode $node, PhpWriter $writer)
+ {
+ $name = $node->tokenizer->fetchWord();
+ if (!$name) {
+ return $writer->write('echo %escape($_input->getError())');
+ } elseif ($name[0] === '$') {
+ return $writer->write('$_input = is_object(%0.word) ? %0.word : $_form[%0.word]; echo %escape($_input->getError())', $name);
+ } else {
+ return $writer->write('echo %escape($_form[%0.word]->getError())', $name);
+ }
+ }
+
+
+ /** @deprecated */
+ public static function renderFormBegin(Form $form, array $attrs, $withTags = TRUE)
+ {
+ echo Runtime::renderFormBegin($form, $attrs, $withTags);
+ }
+
+
+ /** @deprecated */
+ public static function renderFormEnd(Form $form, $withTags = TRUE)
+ {
+ echo Runtime::renderFormEnd($form, $withTags);
+ }
+
+}
diff --git a/vendor/nette/forms/src/Bridges/FormsLatte/Runtime.php b/vendor/nette/forms/src/Bridges/FormsLatte/Runtime.php
new file mode 100755
index 0000000..36f3cc1
--- /dev/null
+++ b/vendor/nette/forms/src/Bridges/FormsLatte/Runtime.php
@@ -0,0 +1,72 @@
+getControls() as $control) {
+ $control->setOption('rendered', FALSE);
+ }
+ $el = $form->getElementPrototype();
+ $el->action = (string) $el->action;
+ $el = clone $el;
+ if (strcasecmp($form->getMethod(), 'get') === 0) {
+ $el->action = preg_replace('~\?[^#]*~', '', $el->action, 1);
+ }
+ $el->addAttributes($attrs);
+ return $withTags ? $el->startTag() : $el->attributes();
+ }
+
+
+ /**
+ * Renders form end.
+ * @return string
+ */
+ public static function renderFormEnd(Form $form, $withTags = TRUE)
+ {
+ $s = '';
+ if (strcasecmp($form->getMethod(), 'get') === 0) {
+ foreach (preg_split('#[;&]#', parse_url($form->getElementPrototype()->action, PHP_URL_QUERY), NULL, PREG_SPLIT_NO_EMPTY) as $param) {
+ $parts = explode('=', $param, 2);
+ $name = urldecode($parts[0]);
+ if (!isset($form[$name])) {
+ $s .= Html::el('input', array('type' => 'hidden', 'name' => $name, 'value' => urldecode($parts[1])));
+ }
+ }
+ }
+
+ foreach ($form->getComponents(TRUE, 'Nette\Forms\Controls\HiddenField') as $control) {
+ if (!$control->getOption('rendered')) {
+ $s .= $control->getControl();
+ }
+ }
+
+ if (iterator_count($form->getComponents(TRUE, 'Nette\Forms\Controls\TextInput')) < 2) {
+ $s .= "\n";
+ }
+
+ return $s . ($withTags ? $form->getElementPrototype()->endTag() . "\n" : '');
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Container.php b/vendor/nette/forms/src/Forms/Container.php
new file mode 100755
index 0000000..7e5f4a4
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Container.php
@@ -0,0 +1,496 @@
+getForm(FALSE);
+ if (!$form || !$form->isAnchored() || !$form->isSubmitted()) {
+ $this->setValues($values, $erase);
+ }
+ return $this;
+ }
+
+
+ /**
+ * Fill-in with values.
+ * @param array|\Traversable values used to fill the form
+ * @param bool erase other controls?
+ * @return self
+ */
+ public function setValues($values, $erase = FALSE)
+ {
+ if ($values instanceof \Traversable) {
+ $values = iterator_to_array($values);
+
+ } elseif (!is_array($values)) {
+ throw new Nette\InvalidArgumentException(sprintf('First parameter must be an array, %s given.', gettype($values)));
+ }
+
+ foreach ($this->getComponents() as $name => $control) {
+ if ($control instanceof IControl) {
+ if (array_key_exists($name, $values)) {
+ $control->setValue($values[$name]);
+
+ } elseif ($erase) {
+ $control->setValue(NULL);
+ }
+
+ } elseif ($control instanceof self) {
+ if (array_key_exists($name, $values)) {
+ $control->setValues($values[$name], $erase);
+
+ } elseif ($erase) {
+ $control->setValues(array(), $erase);
+ }
+ }
+ }
+ return $this;
+ }
+
+
+ /**
+ * Returns the values submitted by the form.
+ * @param bool return values as an array?
+ * @return Nette\Utils\ArrayHash|array
+ */
+ public function getValues($asArray = FALSE)
+ {
+ $values = $asArray ? array() : new Nette\Utils\ArrayHash;
+ foreach ($this->getComponents() as $name => $control) {
+ if ($control instanceof IControl && !$control->isOmitted()) {
+ $values[$name] = $control->getValue();
+
+ } elseif ($control instanceof self) {
+ $values[$name] = $control->getValues($asArray);
+ }
+ }
+ return $values;
+ }
+
+
+ /********************* validation ****************d*g**/
+
+
+ /**
+ * Is form valid?
+ * @return bool
+ */
+ public function isValid()
+ {
+ if (!$this->validated) {
+ if ($this->getErrors()) {
+ return FALSE;
+ }
+ $this->validate();
+ }
+ return !$this->getErrors();
+ }
+
+
+ /**
+ * Performs the server side validation.
+ * @param IControl[]
+ * @return void
+ */
+ public function validate(array $controls = NULL)
+ {
+ foreach ($controls === NULL ? $this->getComponents() : $controls as $control) {
+ $control->validate();
+ }
+ foreach ($this->onValidate ?: array() as $handler) {
+ $params = Nette\Utils\Callback::toReflection($handler)->getParameters();
+ $values = isset($params[1]) ? $this->getValues($params[1]->isArray()) : NULL;
+ Nette\Utils\Callback::invoke($handler, $this, $values);
+ }
+ $this->validated = TRUE;
+ }
+
+
+ /**
+ * Returns all validation errors.
+ * @return array
+ */
+ public function getErrors()
+ {
+ $errors = array();
+ foreach ($this->getControls() as $control) {
+ $errors = array_merge($errors, $control->getErrors());
+ }
+ return array_unique($errors);
+ }
+
+
+ /********************* form building ****************d*g**/
+
+
+ /**
+ * @return self
+ */
+ public function setCurrentGroup(ControlGroup $group = NULL)
+ {
+ $this->currentGroup = $group;
+ return $this;
+ }
+
+
+ /**
+ * Returns current group.
+ * @return ControlGroup
+ */
+ public function getCurrentGroup()
+ {
+ return $this->currentGroup;
+ }
+
+
+ /**
+ * Adds the specified component to the IContainer.
+ * @param Nette\ComponentModel\IComponent
+ * @param string
+ * @param string
+ * @return self
+ * @throws Nette\InvalidStateException
+ */
+ public function addComponent(Nette\ComponentModel\IComponent $component, $name, $insertBefore = NULL)
+ {
+ parent::addComponent($component, $name, $insertBefore);
+ if ($this->currentGroup !== NULL && $component instanceof IControl) {
+ $this->currentGroup->add($component);
+ }
+ return $this;
+ }
+
+
+ /**
+ * Iterates over all form controls.
+ * @return \ArrayIterator
+ */
+ public function getControls()
+ {
+ return $this->getComponents(TRUE, 'Nette\Forms\IControl');
+ }
+
+
+ /**
+ * Returns form.
+ * @param bool throw exception if form doesn't exist?
+ * @return Form
+ */
+ public function getForm($need = TRUE)
+ {
+ return $this->lookup('Nette\Forms\Form', $need);
+ }
+
+
+ /********************* control factories ****************d*g**/
+
+
+ /**
+ * Adds single-line text input control to the form.
+ * @param string control name
+ * @param string label
+ * @param int width of the control (deprecated)
+ * @param int maximum number of characters the user may enter
+ * @return Nette\Forms\Controls\TextInput
+ */
+ public function addText($name, $label = NULL, $cols = NULL, $maxLength = NULL)
+ {
+ $control = new Controls\TextInput($label, $maxLength);
+ $control->setAttribute('size', $cols);
+ return $this[$name] = $control;
+ }
+
+
+ /**
+ * Adds single-line text input control used for sensitive input such as passwords.
+ * @param string control name
+ * @param string label
+ * @param int width of the control (deprecated)
+ * @param int maximum number of characters the user may enter
+ * @return Nette\Forms\Controls\TextInput
+ */
+ public function addPassword($name, $label = NULL, $cols = NULL, $maxLength = NULL)
+ {
+ $control = new Controls\TextInput($label, $maxLength);
+ $control->setAttribute('size', $cols);
+ return $this[$name] = $control->setType('password');
+ }
+
+
+ /**
+ * Adds multi-line text input control to the form.
+ * @param string control name
+ * @param string label
+ * @param int width of the control
+ * @param int height of the control in text lines
+ * @return Nette\Forms\Controls\TextArea
+ */
+ public function addTextArea($name, $label = NULL, $cols = NULL, $rows = NULL)
+ {
+ $control = new Controls\TextArea($label);
+ $control->setAttribute('cols', $cols)->setAttribute('rows', $rows);
+ return $this[$name] = $control;
+ }
+
+
+ /**
+ * Adds control that allows the user to upload files.
+ * @param string control name
+ * @param string label
+ * @param bool allows to upload multiple files
+ * @return Nette\Forms\Controls\UploadControl
+ */
+ public function addUpload($name, $label = NULL, $multiple = FALSE)
+ {
+ return $this[$name] = new Controls\UploadControl($label, $multiple);
+ }
+
+
+ /**
+ * Adds control that allows the user to upload multiple files.
+ * @param string control name
+ * @param string label
+ * @return Nette\Forms\Controls\UploadControl
+ */
+ public function addMultiUpload($name, $label = NULL)
+ {
+ return $this[$name] = new Controls\UploadControl($label, TRUE);
+ }
+
+
+ /**
+ * Adds hidden form control used to store a non-displayed value.
+ * @param string control name
+ * @param mixed default value
+ * @return Nette\Forms\Controls\HiddenField
+ */
+ public function addHidden($name, $default = NULL)
+ {
+ $control = new Controls\HiddenField;
+ $control->setDefaultValue($default);
+ return $this[$name] = $control;
+ }
+
+
+ /**
+ * Adds check box control to the form.
+ * @param string control name
+ * @param string caption
+ * @return Nette\Forms\Controls\Checkbox
+ */
+ public function addCheckbox($name, $caption = NULL)
+ {
+ return $this[$name] = new Controls\Checkbox($caption);
+ }
+
+
+ /**
+ * Adds set of radio button controls to the form.
+ * @param string control name
+ * @param string label
+ * @param array options from which to choose
+ * @return Nette\Forms\Controls\RadioList
+ */
+ public function addRadioList($name, $label = NULL, array $items = NULL)
+ {
+ return $this[$name] = new Controls\RadioList($label, $items);
+ }
+
+
+ /**
+ * Adds set of checkbox controls to the form.
+ * @return Nette\Forms\Controls\CheckboxList
+ */
+ public function addCheckboxList($name, $label = NULL, array $items = NULL)
+ {
+ return $this[$name] = new Controls\CheckboxList($label, $items);
+ }
+
+
+ /**
+ * Adds select box control that allows single item selection.
+ * @param string control name
+ * @param string label
+ * @param array items from which to choose
+ * @param int number of rows that should be visible
+ * @return Nette\Forms\Controls\SelectBox
+ */
+ public function addSelect($name, $label = NULL, array $items = NULL, $size = NULL)
+ {
+ $control = new Controls\SelectBox($label, $items);
+ if ($size > 1) {
+ $control->setAttribute('size', (int) $size);
+ }
+ return $this[$name] = $control;
+ }
+
+
+ /**
+ * Adds select box control that allows multiple item selection.
+ * @param string control name
+ * @param string label
+ * @param array options from which to choose
+ * @param int number of rows that should be visible
+ * @return Nette\Forms\Controls\MultiSelectBox
+ */
+ public function addMultiSelect($name, $label = NULL, array $items = NULL, $size = NULL)
+ {
+ $control = new Controls\MultiSelectBox($label, $items);
+ if ($size > 1) {
+ $control->setAttribute('size', (int) $size);
+ }
+ return $this[$name] = $control;
+ }
+
+
+ /**
+ * Adds button used to submit form.
+ * @param string control name
+ * @param string caption
+ * @return Nette\Forms\Controls\SubmitButton
+ */
+ public function addSubmit($name, $caption = NULL)
+ {
+ return $this[$name] = new Controls\SubmitButton($caption);
+ }
+
+
+ /**
+ * Adds push buttons with no default behavior.
+ * @param string control name
+ * @param string caption
+ * @return Nette\Forms\Controls\Button
+ */
+ public function addButton($name, $caption = NULL)
+ {
+ return $this[$name] = new Controls\Button($caption);
+ }
+
+
+ /**
+ * Adds graphical button used to submit form.
+ * @param string control name
+ * @param string URI of the image
+ * @param string alternate text for the image
+ * @return Nette\Forms\Controls\ImageButton
+ */
+ public function addImage($name, $src = NULL, $alt = NULL)
+ {
+ return $this[$name] = new Controls\ImageButton($src, $alt);
+ }
+
+
+ /**
+ * Adds naming container to the form.
+ * @param string name
+ * @return Container
+ */
+ public function addContainer($name)
+ {
+ $control = new self;
+ $control->currentGroup = $this->currentGroup;
+ return $this[$name] = $control;
+ }
+
+
+ /********************* interface \ArrayAccess ****************d*g**/
+
+
+ /**
+ * Adds the component to the container.
+ * @param string component name
+ * @param Nette\ComponentModel\IComponent
+ * @return void
+ */
+ public function offsetSet($name, $component)
+ {
+ $this->addComponent($component, $name);
+ }
+
+
+ /**
+ * Returns component specified by name. Throws exception if component doesn't exist.
+ * @param string component name
+ * @return Nette\ComponentModel\IComponent
+ * @throws Nette\InvalidArgumentException
+ */
+ public function offsetGet($name)
+ {
+ return $this->getComponent($name, TRUE);
+ }
+
+
+ /**
+ * Does component specified by name exists?
+ * @param string component name
+ * @return bool
+ */
+ public function offsetExists($name)
+ {
+ return $this->getComponent($name, FALSE) !== NULL;
+ }
+
+
+ /**
+ * Removes component from the container.
+ * @param string component name
+ * @return void
+ */
+ public function offsetUnset($name)
+ {
+ $component = $this->getComponent($name, FALSE);
+ if ($component !== NULL) {
+ $this->removeComponent($component);
+ }
+ }
+
+
+ /**
+ * Prevents cloning.
+ */
+ public function __clone()
+ {
+ throw new Nette\NotImplementedException('Form cloning is not supported yet.');
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/ControlGroup.php b/vendor/nette/forms/src/Forms/ControlGroup.php
new file mode 100755
index 0000000..b7042f1
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/ControlGroup.php
@@ -0,0 +1,111 @@
+controls = new \SplObjectStorage;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function add()
+ {
+ foreach (func_get_args() as $num => $item) {
+ if ($item instanceof IControl) {
+ $this->controls->attach($item);
+
+ } elseif ($item instanceof \Traversable || is_array($item)) {
+ foreach ($item as $control) {
+ $this->controls->attach($control);
+ }
+
+ } else {
+ throw new Nette\InvalidArgumentException("Only IFormControl items are allowed, the #$num parameter is invalid.");
+ }
+ }
+ return $this;
+ }
+
+
+ /**
+ * @return array IFormControl
+ */
+ public function getControls()
+ {
+ return iterator_to_array($this->controls);
+ }
+
+
+ /**
+ * Sets user-specific option.
+ * Options recognized by DefaultFormRenderer
+ * - 'label' - textual or Html object label
+ * - 'visual' - indicates visual group
+ * - 'container' - container as Html object
+ * - 'description' - textual or Html object description
+ * - 'embedNext' - describes how render next group
+ *
+ * @param string key
+ * @param mixed value
+ * @return self
+ */
+ public function setOption($key, $value)
+ {
+ if ($value === NULL) {
+ unset($this->options[$key]);
+
+ } else {
+ $this->options[$key] = $value;
+ }
+ return $this;
+ }
+
+
+ /**
+ * Returns user-specific option.
+ * @param string key
+ * @param mixed default value
+ * @return mixed
+ */
+ public function getOption($key, $default = NULL)
+ {
+ return isset($this->options[$key]) ? $this->options[$key] : $default;
+ }
+
+
+ /**
+ * Returns user-specific options.
+ * @return array
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/BaseControl.php b/vendor/nette/forms/src/Forms/Controls/BaseControl.php
new file mode 100755
index 0000000..d52317f
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/BaseControl.php
@@ -0,0 +1,559 @@
+monitor('Nette\Forms\Form');
+ parent::__construct();
+ $this->control = Html::el('input', array('type' => NULL, 'name' => NULL));
+ $this->label = Html::el('label');
+ $this->caption = $caption;
+ $this->rules = new Nette\Forms\Rules($this);
+ $this->setValue(NULL);
+ }
+
+
+ /**
+ * This method will be called when the component becomes attached to Form.
+ * @param Nette\ComponentModel\IComponent
+ * @return void
+ */
+ protected function attached($form)
+ {
+ if (!$this->isDisabled() && $form instanceof Form && $form->isAnchored() && $form->isSubmitted()) {
+ $this->loadHttpData();
+ }
+ }
+
+
+ /**
+ * Returns form.
+ * @param bool throw exception if form doesn't exist?
+ * @return Form
+ */
+ public function getForm($need = TRUE)
+ {
+ return $this->lookup('Nette\Forms\Form', $need);
+ }
+
+
+ /**
+ * Loads HTTP data.
+ * @return void
+ */
+ public function loadHttpData()
+ {
+ $this->setValue($this->getHttpData(Form::DATA_TEXT));
+ }
+
+
+ /**
+ * Loads HTTP data.
+ * @return mixed
+ */
+ public function getHttpData($type, $htmlTail = NULL)
+ {
+ return $this->getForm()->getHttpData($type, $this->getHtmlName() . $htmlTail);
+ }
+
+
+ /**
+ * Returns HTML name of control.
+ * @return string
+ */
+ public function getHtmlName()
+ {
+ return Nette\Forms\Helpers::generateHtmlName($this->lookupPath('Nette\Forms\Form'));
+ }
+
+
+ /********************* interface IFormControl ****************d*g**/
+
+
+ /**
+ * Sets control's value.
+ * @return self
+ */
+ public function setValue($value)
+ {
+ $this->value = $value;
+ return $this;
+ }
+
+
+ /**
+ * Returns control's value.
+ * @return mixed
+ */
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+
+ /**
+ * Is control filled?
+ * @return bool
+ */
+ public function isFilled()
+ {
+ $value = $this->getValue();
+ return $value !== NULL && $value !== array() && $value !== '';
+ }
+
+
+ /**
+ * Sets control's default value.
+ * @return self
+ */
+ public function setDefaultValue($value)
+ {
+ $form = $this->getForm(FALSE);
+ if ($this->isDisabled() || !$form || !$form->isAnchored() || !$form->isSubmitted()) {
+ $this->setValue($value);
+ }
+ return $this;
+ }
+
+
+ /**
+ * Disables or enables control.
+ * @param bool
+ * @return self
+ */
+ public function setDisabled($value = TRUE)
+ {
+ if ($this->disabled = (bool) $value) {
+ $this->omitted = TRUE;
+ $this->setValue(NULL);
+ }
+ return $this;
+ }
+
+
+ /**
+ * Is control disabled?
+ * @return bool
+ */
+ public function isDisabled()
+ {
+ return $this->disabled === TRUE;
+ }
+
+
+ /**
+ * Sets whether control value is excluded from $form->getValues() result.
+ * @param bool
+ * @return self
+ */
+ public function setOmitted($value = TRUE)
+ {
+ $this->omitted = (bool) $value;
+ return $this;
+ }
+
+
+ /**
+ * Is control value excluded from $form->getValues() result?
+ * @return bool
+ */
+ public function isOmitted()
+ {
+ return $this->omitted;
+ }
+
+
+ /********************* rendering ****************d*g**/
+
+
+ /**
+ * Generates control's HTML element.
+ * @return Html|string
+ */
+ public function getControl()
+ {
+ $this->setOption('rendered', TRUE);
+ $el = clone $this->control;
+ return $el->addAttributes(array(
+ 'name' => $this->getHtmlName(),
+ 'id' => $this->getHtmlId(),
+ 'required' => $this->isRequired(),
+ 'disabled' => $this->isDisabled(),
+ 'data-nette-rules' => Nette\Forms\Helpers::exportRules($this->rules) ?: NULL,
+ ));
+ }
+
+
+ /**
+ * Generates label's HTML element.
+ * @param string
+ * @return Html|string
+ */
+ public function getLabel($caption = NULL)
+ {
+ $label = clone $this->label;
+ $label->for = $this->getHtmlId();
+ $label->setText($this->translate($caption === NULL ? $this->caption : $caption));
+ return $label;
+ }
+
+
+ /**
+ * Returns control's HTML element template.
+ * @return Html
+ */
+ public function getControlPrototype()
+ {
+ return $this->control;
+ }
+
+
+ /**
+ * Returns label's HTML element template.
+ * @return Html
+ */
+ public function getLabelPrototype()
+ {
+ return $this->label;
+ }
+
+
+ /**
+ * Changes control's HTML id.
+ * @param string new ID, or FALSE or NULL
+ * @return self
+ */
+ public function setHtmlId($id)
+ {
+ $this->control->id = $id;
+ return $this;
+ }
+
+
+ /**
+ * Returns control's HTML id.
+ * @return string
+ */
+ public function getHtmlId()
+ {
+ if (!isset($this->control->id)) {
+ $this->control->id = sprintf(self::$idMask, $this->lookupPath());
+ }
+ return $this->control->id;
+ }
+
+
+ /**
+ * Changes control's HTML attribute.
+ * @param string name
+ * @param mixed value
+ * @return self
+ */
+ public function setAttribute($name, $value = TRUE)
+ {
+ $this->control->$name = $value;
+ return $this;
+ }
+
+
+ /********************* translator ****************d*g**/
+
+
+ /**
+ * Sets translate adapter.
+ * @return self
+ */
+ public function setTranslator(Nette\Localization\ITranslator $translator = NULL)
+ {
+ $this->translator = $translator;
+ return $this;
+ }
+
+
+ /**
+ * Returns translate adapter.
+ * @return Nette\Localization\ITranslator|NULL
+ */
+ public function getTranslator()
+ {
+ if ($this->translator === TRUE) {
+ return $this->getForm(FALSE) ? $this->getForm()->getTranslator() : NULL;
+ }
+ return $this->translator;
+ }
+
+
+ /**
+ * Returns translated string.
+ * @param mixed
+ * @param int plural count
+ * @return string
+ */
+ public function translate($value, $count = NULL)
+ {
+ if ($translator = $this->getTranslator()) {
+ $tmp = is_array($value) ? array(& $value) : array(array(& $value));
+ foreach ($tmp[0] as & $v) {
+ if ($v != NULL && !$v instanceof Html) { // intentionally ==
+ $v = $translator->translate($v, $count);
+ }
+ }
+ }
+ return $value;
+ }
+
+
+ /********************* rules ****************d*g**/
+
+
+ /**
+ * Adds a validation rule.
+ * @param mixed rule type
+ * @param string message to display for invalid data
+ * @param mixed optional rule arguments
+ * @return self
+ */
+ public function addRule($validator, $message = NULL, $arg = NULL)
+ {
+ $this->rules->addRule($validator, $message, $arg);
+ return $this;
+ }
+
+
+ /**
+ * Adds a validation condition a returns new branch.
+ * @param mixed condition type
+ * @param mixed optional condition arguments
+ * @return Nette\Forms\Rules new branch
+ */
+ public function addCondition($validator, $value = NULL)
+ {
+ return $this->rules->addCondition($validator, $value);
+ }
+
+
+ /**
+ * Adds a validation condition based on another control a returns new branch.
+ * @param IControl form control
+ * @param mixed condition type
+ * @param mixed optional condition arguments
+ * @return Nette\Forms\Rules new branch
+ */
+ public function addConditionOn(IControl $control, $validator, $value = NULL)
+ {
+ return $this->rules->addConditionOn($control, $validator, $value);
+ }
+
+
+ /**
+ * @return Nette\Forms\Rules
+ */
+ public function getRules()
+ {
+ return $this->rules;
+ }
+
+
+ /**
+ * Makes control mandatory.
+ * @param mixed state or error message
+ * @return self
+ */
+ public function setRequired($value = TRUE)
+ {
+ $this->rules->setRequired($value);
+ return $this;
+ }
+
+
+ /**
+ * Is control mandatory?
+ * @return bool
+ */
+ public function isRequired()
+ {
+ return $this->rules->isRequired();
+ }
+
+
+ /**
+ * Performs the server side validation.
+ * @return void
+ */
+ public function validate()
+ {
+ if ($this->isDisabled()) {
+ return;
+ }
+ $this->cleanErrors();
+ $this->rules->validate();
+ }
+
+
+ /**
+ * Adds error message to the list.
+ * @param string error message
+ * @return void
+ */
+ public function addError($message)
+ {
+ $this->errors[] = $message;
+ }
+
+
+ /**
+ * Returns errors corresponding to control.
+ * @return string
+ */
+ public function getError()
+ {
+ return $this->errors ? implode(' ', array_unique($this->errors)) : NULL;
+ }
+
+
+ /**
+ * Returns errors corresponding to control.
+ * @return array
+ */
+ public function getErrors()
+ {
+ return array_unique($this->errors);
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function hasErrors()
+ {
+ return (bool) $this->errors;
+ }
+
+
+ /**
+ * @return void
+ */
+ public function cleanErrors()
+ {
+ $this->errors = array();
+ }
+
+
+ /** @deprecated */
+ protected static function exportRules($rules)
+ {
+ trigger_error(__METHOD__ . '() is deprecated; use Nette\Forms\Helpers::exportRules() instead.', E_USER_DEPRECATED);
+ return Nette\Forms\Helpers::exportRules($rules);
+ }
+
+
+ /********************* user data ****************d*g**/
+
+
+ /**
+ * Sets user-specific option.
+ * @return self
+ */
+ public function setOption($key, $value)
+ {
+ if ($value === NULL) {
+ unset($this->options[$key]);
+ } else {
+ $this->options[$key] = $value;
+ }
+ return $this;
+ }
+
+
+ /**
+ * Returns user-specific option.
+ * @return mixed
+ */
+ public function getOption($key, $default = NULL)
+ {
+ return isset($this->options[$key]) ? $this->options[$key] : $default;
+ }
+
+
+ /**
+ * Returns user-specific options.
+ * @return array
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/Button.php b/vendor/nette/forms/src/Forms/Controls/Button.php
new file mode 100755
index 0000000..971a924
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/Button.php
@@ -0,0 +1,66 @@
+control->type = 'button';
+ }
+
+
+ /**
+ * Is button pressed?
+ * @return bool
+ */
+ public function isFilled()
+ {
+ $value = $this->getValue();
+ return $value !== NULL && $value !== array();
+ }
+
+
+ /**
+ * Bypasses label generation.
+ * @return void
+ */
+ public function getLabel($caption = NULL)
+ {
+ return NULL;
+ }
+
+
+ /**
+ * Generates control's HTML element.
+ * @param string
+ * @return Nette\Utils\Html
+ */
+ public function getControl($caption = NULL)
+ {
+ $this->setOption('rendered', TRUE);
+ $el = clone $this->control;
+ return $el->addAttributes(array(
+ 'name' => $this->getHtmlName(),
+ 'disabled' => $this->isDisabled(),
+ 'value' => $this->translate($caption === NULL ? $this->caption : $caption),
+ ));
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/Checkbox.php b/vendor/nette/forms/src/Forms/Controls/Checkbox.php
new file mode 100755
index 0000000..0be898e
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/Checkbox.php
@@ -0,0 +1,105 @@
+control->type = 'checkbox';
+ $this->wrapper = Nette\Utils\Html::el();
+ }
+
+
+ /**
+ * Sets control's value.
+ * @param bool
+ * @return self
+ */
+ public function setValue($value)
+ {
+ if (!is_scalar($value) && $value !== NULL) {
+ throw new Nette\InvalidArgumentException(sprintf("Value must be scalar or NULL, %s given in field '%s'.", gettype($value), $this->name));
+ }
+ $this->value = (bool) $value;
+ return $this;
+ }
+
+
+ /**
+ * Is control filled?
+ * @return bool
+ */
+ public function isFilled()
+ {
+ return $this->getValue() !== FALSE; // back compatibility
+ }
+
+
+ /**
+ * Generates control's HTML element.
+ * @return Nette\Utils\Html
+ */
+ public function getControl()
+ {
+ return $this->wrapper->setHtml($this->getLabelPart()->insert(0, $this->getControlPart()));
+ }
+
+
+ /**
+ * Bypasses label generation.
+ * @return void
+ */
+ public function getLabel($caption = NULL)
+ {
+ return NULL;
+ }
+
+
+ /**
+ * @return Nette\Utils\Html
+ */
+ public function getControlPart()
+ {
+ return parent::getControl()->checked($this->value);
+ }
+
+
+ /**
+ * @return Nette\Utils\Html
+ */
+ public function getLabelPart()
+ {
+ return parent::getLabel();
+ }
+
+
+ /**
+ * Returns wrapper HTML element template.
+ * @return Nette\Utils\Html
+ */
+ public function getSeparatorPrototype()
+ {
+ return $this->wrapper;
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/CheckboxList.php b/vendor/nette/forms/src/Forms/Controls/CheckboxList.php
new file mode 100755
index 0000000..f64df25
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/CheckboxList.php
@@ -0,0 +1,104 @@
+control->type = 'checkbox';
+ $this->separator = Html::el('br');
+ }
+
+
+ /**
+ * Generates control's HTML element.
+ * @return string
+ */
+ public function getControl()
+ {
+ $items = $this->getItems();
+ reset($items);
+ $input = parent::getControl();
+ return Nette\Forms\Helpers::createInputList(
+ $this->translate($items),
+ array_merge($input->attrs, array(
+ 'id' => NULL,
+ 'checked?' => $this->value,
+ 'disabled:' => $this->disabled,
+ 'required' => NULL,
+ 'data-nette-rules:' => array(key($items) => $input->attrs['data-nette-rules']),
+ )),
+ $this->label->attrs,
+ $this->separator
+ );
+ }
+
+
+ /**
+ * Generates label's HTML element.
+ * @param string
+ * @return Html
+ */
+ public function getLabel($caption = NULL)
+ {
+ return parent::getLabel($caption)->for(NULL);
+ }
+
+
+ /**
+ * Returns separator HTML element template.
+ * @return Html
+ */
+ public function getSeparatorPrototype()
+ {
+ return $this->separator;
+ }
+
+
+ /**
+ * @return Html
+ */
+ public function getControlPart($key)
+ {
+ $key = key(array((string) $key => NULL));
+ return parent::getControl()->addAttributes(array(
+ 'id' => $this->getHtmlId() . '-' . $key,
+ 'checked' => in_array($key, (array) $this->value, TRUE),
+ 'disabled' => is_array($this->disabled) ? isset($this->disabled[$key]) : $this->disabled,
+ 'required' => NULL,
+ 'value' => $key,
+ ));
+ }
+
+
+ /**
+ * @return Html
+ */
+ public function getLabelPart($key = NULL)
+ {
+ return func_num_args()
+ ? parent::getLabel($this->items[$key])->for($this->getHtmlId() . '-' . $key)
+ : $this->getLabel();
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/ChoiceControl.php b/vendor/nette/forms/src/Forms/Controls/ChoiceControl.php
new file mode 100755
index 0000000..d7e7653
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/ChoiceControl.php
@@ -0,0 +1,154 @@
+setItems($items);
+ }
+ }
+
+
+ /**
+ * Loads HTTP data.
+ * @return void
+ */
+ public function loadHttpData()
+ {
+ $this->value = $this->getHttpData(Nette\Forms\Form::DATA_TEXT);
+ if ($this->value !== NULL) {
+ if (is_array($this->disabled) && isset($this->disabled[$this->value])) {
+ $this->value = NULL;
+ } else {
+ $this->value = key(array($this->value => NULL));
+ }
+ }
+ }
+
+
+ /**
+ * Sets selected item (by key).
+ * @param scalar
+ * @return self
+ */
+ public function setValue($value)
+ {
+ if ($this->checkAllowedValues && $value !== NULL && !array_key_exists((string) $value, $this->items)) {
+ $set = Nette\Utils\Strings::truncate(implode(', ', array_map(function ($s) { return var_export($s, TRUE); }, array_keys($this->items))), 70, '...');
+ throw new Nette\InvalidArgumentException("Value '$value' is out of allowed set [$set] in field '{$this->name}'.");
+ }
+ $this->value = $value === NULL ? NULL : key(array((string) $value => NULL));
+ return $this;
+ }
+
+
+ /**
+ * Returns selected key.
+ * @return scalar
+ */
+ public function getValue()
+ {
+ return array_key_exists($this->value, $this->items) ? $this->value : NULL;
+ }
+
+
+ /**
+ * Returns selected key (not checked).
+ * @return scalar
+ */
+ public function getRawValue()
+ {
+ return $this->value;
+ }
+
+
+ /**
+ * Is any item selected?
+ * @return bool
+ */
+ public function isFilled()
+ {
+ return $this->getValue() !== NULL;
+ }
+
+
+ /**
+ * Sets items from which to choose.
+ * @param array
+ * @param bool
+ * @return self
+ */
+ public function setItems(array $items, $useKeys = TRUE)
+ {
+ $this->items = $useKeys ? $items : array_combine($items, $items);
+ return $this;
+ }
+
+
+ /**
+ * Returns items from which to choose.
+ * @return array
+ */
+ public function getItems()
+ {
+ return $this->items;
+ }
+
+
+ /**
+ * Returns selected value.
+ * @return mixed
+ */
+ public function getSelectedItem()
+ {
+ $value = $this->getValue();
+ return $value === NULL ? NULL : $this->items[$value];
+ }
+
+
+ /**
+ * Disables or enables control or items.
+ * @param bool|array
+ * @return self
+ */
+ public function setDisabled($value = TRUE)
+ {
+ if (!is_array($value)) {
+ return parent::setDisabled($value);
+ }
+
+ parent::setDisabled(FALSE);
+ $this->disabled = array_fill_keys($value, TRUE);
+ if (isset($this->disabled[$this->value])) {
+ $this->value = NULL;
+ }
+ return $this;
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/CsrfProtection.php b/vendor/nette/forms/src/Forms/Controls/CsrfProtection.php
new file mode 100755
index 0000000..fbd4700
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/CsrfProtection.php
@@ -0,0 +1,124 @@
+setOmitted()->addRule(self::PROTECTION, $message);
+ $this->monitor('Nette\Application\UI\Presenter');
+ }
+
+
+ protected function attached($parent)
+ {
+ parent::attached($parent);
+ if (!$this->session && $parent instanceof Nette\Application\UI\Presenter) {
+ $this->session = $parent->getSession();
+ }
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setValue($value)
+ {
+ return $this;
+ }
+
+
+ /**
+ * Loads HTTP data.
+ * @return void
+ */
+ public function loadHttpData()
+ {
+ $this->value = $this->getHttpData(Nette\Forms\Form::DATA_TEXT);
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getToken()
+ {
+ $session = $this->getSession()->getSection(__CLASS__);
+ if (!isset($session->token)) {
+ $session->token = Nette\Utils\Random::generate();
+ }
+ return $session->token ^ $this->getSession()->getId();
+ }
+
+
+ /**
+ * @return string
+ */
+ private function generateToken($random = NULL)
+ {
+ if ($random === NULL) {
+ $random = Nette\Utils\Random::generate(10);
+ }
+ return $random . base64_encode(sha1($this->getToken() . $random, TRUE));
+ }
+
+
+ /**
+ * Generates control's HTML element.
+ * @return Nette\Utils\Html
+ */
+ public function getControl()
+ {
+ return parent::getControl()->value($this->generateToken());
+ }
+
+
+ /**
+ * @return bool
+ * @internal
+ */
+ public static function validateCsrf(CsrfProtection $control)
+ {
+ $value = $control->getValue();
+ return $control->generateToken(substr($value, 0, 10)) === $value;
+ }
+
+
+ /********************* backend ****************d*g**/
+
+
+ /**
+ * @return Nette\Http\Session
+ */
+ private function getSession()
+ {
+ if (!$this->session) {
+ $this->session = new Nette\Http\Session($this->getForm()->httpRequest, new Nette\Http\Response);
+ }
+ return $this->session;
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/HiddenField.php b/vendor/nette/forms/src/Forms/Controls/HiddenField.php
new file mode 100755
index 0000000..ccd8974
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/HiddenField.php
@@ -0,0 +1,87 @@
+control->type = 'hidden';
+ if ($persistentValue !== NULL) {
+ $this->unmonitor('Nette\Forms\Form');
+ $this->persistValue = TRUE;
+ $this->value = (string) $persistentValue;
+ }
+ }
+
+
+ /**
+ * Sets control's value.
+ * @param string
+ * @return self
+ */
+ public function setValue($value)
+ {
+ if (!is_scalar($value) && $value !== NULL && !method_exists($value, '__toString')) {
+ throw new Nette\InvalidArgumentException(sprintf("Value must be scalar or NULL, %s given in field '%s'.", gettype($value), $this->name));
+ }
+ if (!$this->persistValue) {
+ $this->value = (string) $value;
+ }
+ return $this;
+ }
+
+
+ /**
+ * Generates control's HTML element.
+ * @return Nette\Utils\Html
+ */
+ public function getControl()
+ {
+ $this->setOption('rendered', TRUE);
+ $el = clone $this->control;
+ return $el->addAttributes(array(
+ 'name' => $this->getHtmlName(),
+ 'disabled' => $this->isDisabled(),
+ 'value' => $this->value,
+ ));
+ }
+
+
+ /**
+ * Bypasses label generation.
+ * @return void
+ */
+ public function getLabel($caption = NULL)
+ {
+ return NULL;
+ }
+
+
+ /**
+ * Adds error message to the list.
+ * @param string error message
+ * @return void
+ */
+ public function addError($message)
+ {
+ $this->getForm()->addError($message);
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/ImageButton.php b/vendor/nette/forms/src/Forms/Controls/ImageButton.php
new file mode 100755
index 0000000..164a3df
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/ImageButton.php
@@ -0,0 +1,52 @@
+control->type = 'image';
+ $this->control->src = $src;
+ $this->control->alt = $alt;
+ }
+
+
+ /**
+ * Loads HTTP data.
+ * @return void
+ */
+ public function loadHttpData()
+ {
+ parent::loadHttpData();
+ $this->value = $this->value
+ ? array((int) array_shift($this->value), (int) array_shift($this->value))
+ : NULL;
+ }
+
+
+ /**
+ * Returns HTML name of control.
+ * @return string
+ */
+ public function getHtmlName()
+ {
+ return parent::getHtmlName() . '[]';
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/MultiChoiceControl.php b/vendor/nette/forms/src/Forms/Controls/MultiChoiceControl.php
new file mode 100755
index 0000000..4581ab1
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/MultiChoiceControl.php
@@ -0,0 +1,171 @@
+setItems($items);
+ }
+ }
+
+
+ /**
+ * Loads HTTP data.
+ * @return void
+ */
+ public function loadHttpData()
+ {
+ $this->value = array_keys(array_flip($this->getHttpData(Nette\Forms\Form::DATA_TEXT)));
+ if (is_array($this->disabled)) {
+ $this->value = array_diff($this->value, array_keys($this->disabled));
+ }
+ }
+
+
+ /**
+ * Sets selected items (by keys).
+ * @param array
+ * @return self
+ */
+ public function setValue($values)
+ {
+ if (is_scalar($values) || $values === NULL) {
+ $values = (array) $values;
+ } elseif (!is_array($values)) {
+ throw new Nette\InvalidArgumentException(sprintf("Value must be array or NULL, %s given in field '%s'.", gettype($values), $this->name));
+ }
+ $flip = array();
+ foreach ($values as $value) {
+ if (!is_scalar($value) && !method_exists($value, '__toString')) {
+ throw new Nette\InvalidArgumentException(sprintf("Values must be scalar, %s given in field '%s'.", gettype($value), $this->name));
+ }
+ $flip[(string) $value] = TRUE;
+ }
+ $values = array_keys($flip);
+ if ($this->checkAllowedValues && ($diff = array_diff($values, array_keys($this->items)))) {
+ $set = Nette\Utils\Strings::truncate(implode(', ', array_map(function ($s) { return var_export($s, TRUE); }, array_keys($this->items))), 70, '...');
+ $vals = (count($diff) > 1 ? 's' : '') . " '" . implode("', '", $diff) . "'";
+ throw new Nette\InvalidArgumentException("Value$vals are out of allowed set [$set] in field '{$this->name}'.");
+ }
+ $this->value = $values;
+ return $this;
+ }
+
+
+ /**
+ * Returns selected keys.
+ * @return array
+ */
+ public function getValue()
+ {
+ return array_values(array_intersect($this->value, array_keys($this->items)));
+ }
+
+
+ /**
+ * Returns selected keys (not checked).
+ * @return array
+ */
+ public function getRawValue()
+ {
+ return $this->value;
+ }
+
+
+ /**
+ * Is any item selected?
+ * @return bool
+ */
+ public function isFilled()
+ {
+ return $this->getValue() !== array();
+ }
+
+
+ /**
+ * Sets items from which to choose.
+ * @param array
+ * @param bool
+ * @return self
+ */
+ public function setItems(array $items, $useKeys = TRUE)
+ {
+ $this->items = $useKeys ? $items : array_combine($items, $items);
+ return $this;
+ }
+
+
+ /**
+ * Returns items from which to choose.
+ * @return array
+ */
+ public function getItems()
+ {
+ return $this->items;
+ }
+
+
+ /**
+ * Returns selected values.
+ * @return array
+ */
+ public function getSelectedItems()
+ {
+ return array_intersect_key($this->items, array_flip($this->value));
+ }
+
+
+ /**
+ * Disables or enables control or items.
+ * @param bool|array
+ * @return self
+ */
+ public function setDisabled($value = TRUE)
+ {
+ if (!is_array($value)) {
+ return parent::setDisabled($value);
+ }
+
+ parent::setDisabled(FALSE);
+ $this->disabled = array_fill_keys($value, TRUE);
+ $this->value = array_diff($this->value, $value);
+ return $this;
+ }
+
+
+ /**
+ * Returns HTML name of control.
+ * @return string
+ */
+ public function getHtmlName()
+ {
+ return parent::getHtmlName() . '[]';
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/MultiSelectBox.php b/vendor/nette/forms/src/Forms/Controls/MultiSelectBox.php
new file mode 100755
index 0000000..2049d43
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/MultiSelectBox.php
@@ -0,0 +1,67 @@
+ $value) {
+ unset($items[$key]);
+ if (is_array($value)) {
+ foreach ($value as $val) {
+ $res[$key][(string) $val] = $val;
+ }
+ } else {
+ $res[(string) $value] = $value;
+ }
+ }
+ $items = $res;
+ }
+ $this->options = $items;
+ return parent::setItems(Nette\Utils\Arrays::flatten($items, TRUE));
+ }
+
+
+ /**
+ * Generates control's HTML element.
+ * @return Nette\Utils\Html
+ */
+ public function getControl()
+ {
+ $items = array();
+ foreach ($this->options as $key => $value) {
+ $items[is_array($value) ? $this->translate($key) : $key] = $this->translate($value);
+ }
+
+ return Nette\Forms\Helpers::createSelectBox(
+ $items,
+ array(
+ 'selected?' => $this->value,
+ 'disabled:' => is_array($this->disabled) ? $this->disabled : NULL,
+ )
+ )->addAttributes(parent::getControl()->attrs)->multiple(TRUE);
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/RadioList.php b/vendor/nette/forms/src/Forms/Controls/RadioList.php
new file mode 100755
index 0000000..cabe4ed
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/RadioList.php
@@ -0,0 +1,157 @@
+control->type = 'radio';
+ $this->container = Html::el();
+ $this->separator = Html::el('br');
+ $this->itemLabel = Html::el();
+ }
+
+
+ /**
+ * Returns selected radio value.
+ * @return mixed
+ */
+ public function getValue()
+ {
+ return parent::getValue();
+ }
+
+
+ /**
+ * Returns separator HTML element template.
+ * @return Html
+ */
+ public function getSeparatorPrototype()
+ {
+ return $this->separator;
+ }
+
+
+ /**
+ * Returns container HTML element template.
+ * @return Html
+ */
+ public function getContainerPrototype()
+ {
+ return $this->container;
+ }
+
+
+ /**
+ * Returns item label HTML element template.
+ * @return Html
+ */
+ public function getItemLabelPrototype()
+ {
+ return $this->itemLabel;
+ }
+
+
+ /**
+ * Generates control's HTML element.
+ * @return Html
+ */
+ public function getControl()
+ {
+ $input = parent::getControl();
+ $items = $this->getItems();
+ $ids = array();
+ if ($this->generateId) {
+ foreach ($items as $value => $label) {
+ $ids[$value] = $input->id . '-' . $value;
+ }
+ }
+
+ return $this->container->setHtml(
+ Nette\Forms\Helpers::createInputList(
+ $this->translate($items),
+ array_merge($input->attrs, array(
+ 'id:' => $ids,
+ 'checked?' => $this->value,
+ 'disabled:' => $this->disabled,
+ 'data-nette-rules:' => array(key($items) => $input->attrs['data-nette-rules']),
+ )),
+ array('for:' => $ids) + $this->itemLabel->attrs,
+ $this->separator
+ )
+ );
+ }
+
+
+ /**
+ * Generates label's HTML element.
+ * @param string
+ * @return Html
+ */
+ public function getLabel($caption = NULL)
+ {
+ return parent::getLabel($caption)->for(NULL);
+ }
+
+
+ /**
+ * @return Html
+ */
+ public function getControlPart($key)
+ {
+ $key = key(array((string) $key => NULL));
+ return parent::getControl()->addAttributes(array(
+ 'id' => $this->getHtmlId() . '-' . $key,
+ 'checked' => in_array($key, (array) $this->value, TRUE),
+ 'disabled' => is_array($this->disabled) ? isset($this->disabled[$key]) : $this->disabled,
+ 'value' => $key,
+ ));
+ }
+
+
+ /**
+ * @return Html
+ */
+ public function getLabelPart($key = NULL)
+ {
+ return func_num_args()
+ ? parent::getLabel($this->items[$key])->for($this->getHtmlId() . '-' . $key)
+ : $this->getLabel();
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/SelectBox.php b/vendor/nette/forms/src/Forms/Controls/SelectBox.php
new file mode 100755
index 0000000..8e522ff
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/SelectBox.php
@@ -0,0 +1,110 @@
+prompt = $prompt;
+ return $this;
+ }
+
+
+ /**
+ * Returns first prompt item?
+ * @return mixed
+ */
+ public function getPrompt()
+ {
+ return $this->prompt;
+ }
+
+
+ /**
+ * Sets options and option groups from which to choose.
+ * @return self
+ */
+ public function setItems(array $items, $useKeys = TRUE)
+ {
+ if (!$useKeys) {
+ $res = array();
+ foreach ($items as $key => $value) {
+ unset($items[$key]);
+ if (is_array($value)) {
+ foreach ($value as $val) {
+ $res[$key][(string) $val] = $val;
+ }
+ } else {
+ $res[(string) $value] = $value;
+ }
+ }
+ $items = $res;
+ }
+ $this->options = $items;
+ return parent::setItems(Nette\Utils\Arrays::flatten($items, TRUE));
+ }
+
+
+ /**
+ * Generates control's HTML element.
+ * @return Nette\Utils\Html
+ */
+ public function getControl()
+ {
+ $items = $this->prompt === FALSE ? array() : array('' => $this->translate($this->prompt));
+ foreach ($this->options as $key => $value) {
+ $items[is_array($value) ? $this->translate($key) : $key] = $this->translate($value);
+ }
+
+ return Nette\Forms\Helpers::createSelectBox(
+ $items,
+ array(
+ 'selected?' => $this->value,
+ 'disabled:' => is_array($this->disabled) ? $this->disabled : NULL,
+ )
+ )->addAttributes(parent::getControl()->attrs);
+ }
+
+
+ /**
+ * Performs the server side validation.
+ * @return void
+ */
+ public function validate()
+ {
+ parent::validate();
+ if (!$this->isDisabled() && $this->prompt === FALSE && $this->getValue() === NULL && $this->options) {
+ $this->addError(Nette\Forms\Validator::$messages[self::VALID]);
+ }
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/SubmitButton.php b/vendor/nette/forms/src/Forms/Controls/SubmitButton.php
new file mode 100755
index 0000000..6ad896e
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/SubmitButton.php
@@ -0,0 +1,123 @@
+control->type = 'submit';
+ $this->setOmitted(TRUE);
+ }
+
+
+ /**
+ * Loads HTTP data.
+ * @return void
+ */
+ public function loadHttpData()
+ {
+ parent::loadHttpData();
+ if ($this->isFilled()) {
+ $this->getForm()->setSubmittedBy($this);
+ }
+ }
+
+
+ /**
+ * Tells if the form was submitted by this button.
+ * @return bool
+ */
+ public function isSubmittedBy()
+ {
+ return $this->getForm()->isSubmitted() === $this;
+ }
+
+
+ /**
+ * Sets the validation scope. Clicking the button validates only the controls within the specified scope.
+ * @return self
+ */
+ public function setValidationScope(/*array*/$scope = NULL)
+ {
+ if ($scope === NULL || $scope === TRUE) {
+ $this->validationScope = NULL;
+ } else {
+ $this->validationScope = array();
+ foreach ($scope ?: array() as $control) {
+ if (!$control instanceof Nette\Forms\Container && !$control instanceof Nette\Forms\IControl) {
+ throw new Nette\InvalidArgumentException('Validation scope accepts only Nette\Forms\Container or Nette\Forms\IControl instances.');
+ }
+ $this->validationScope[] = $control;
+ }
+ }
+ return $this;
+ }
+
+
+ /**
+ * Gets the validation scope.
+ * @return array|NULL
+ */
+ public function getValidationScope()
+ {
+ return $this->validationScope;
+ }
+
+
+ /**
+ * Fires click event.
+ * @return void
+ */
+ public function click()
+ {
+ $this->onClick($this);
+ }
+
+
+ /**
+ * Generates control's HTML element.
+ * @param string
+ * @return Nette\Utils\Html
+ */
+ public function getControl($caption = NULL)
+ {
+ $scope = array();
+ foreach ((array) $this->validationScope as $control) {
+ $scope[] = $control->lookupPath('Nette\Forms\Form');
+ }
+ return parent::getControl($caption)->addAttributes(array(
+ 'formnovalidate' => $this->validationScope !== NULL,
+ 'data-nette-validation-scope' => $scope ?: NULL,
+ ));
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/TextArea.php b/vendor/nette/forms/src/Forms/Controls/TextArea.php
new file mode 100755
index 0000000..318bf46
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/TextArea.php
@@ -0,0 +1,43 @@
+control->setName('textarea');
+ }
+
+
+ /**
+ * Generates control's HTML element.
+ * @return Nette\Utils\Html
+ */
+ public function getControl()
+ {
+ $value = $this->getValue();
+ if ($value === '') {
+ $value = $this->translate($this->emptyValue);
+ }
+ return parent::getControl()
+ ->setText($value);
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/TextBase.php b/vendor/nette/forms/src/Forms/Controls/TextBase.php
new file mode 100755
index 0000000..a19e6e4
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/TextBase.php
@@ -0,0 +1,126 @@
+name));
+ }
+ $this->rawValue = $this->value = $value;
+ return $this;
+ }
+
+
+ /**
+ * Returns control's value.
+ * @return string
+ */
+ public function getValue()
+ {
+ return $this->value === Strings::trim($this->translate($this->emptyValue)) ? '' : $this->value;
+ }
+
+
+ /**
+ * Sets the special value which is treated as empty string.
+ * @param string
+ * @return self
+ */
+ public function setEmptyValue($value)
+ {
+ $this->emptyValue = (string) $value;
+ return $this;
+ }
+
+
+ /**
+ * Returns the special value which is treated as empty string.
+ * @return string
+ */
+ public function getEmptyValue()
+ {
+ return $this->emptyValue;
+ }
+
+
+ /**
+ * Sets the maximum number of allowed characters.
+ * @param int
+ * @return self
+ */
+ public function setMaxLength($length)
+ {
+ $this->control->maxlength = $length;
+ return $this;
+ }
+
+
+ /**
+ * Appends input string filter callback.
+ * @param callable
+ * @return self
+ */
+ public function addFilter($filter)
+ {
+ $this->rules->addFilter($filter);
+ return $this;
+ }
+
+
+ public function getControl()
+ {
+ $el = parent::getControl();
+ if ($this->emptyValue !== '') {
+ $el->attrs['data-nette-empty-value'] = Strings::trim($this->translate($this->emptyValue));
+ }
+ if (isset($el->placeholder)) {
+ $el->placeholder = $this->translate($el->placeholder);
+ }
+ return $el;
+ }
+
+
+ public function addRule($validator, $message = NULL, $arg = NULL)
+ {
+ if ($validator === Form::LENGTH || $validator === Form::MAX_LENGTH) {
+ $tmp = is_array($arg) ? $arg[1] : $arg;
+ if (is_scalar($tmp)) {
+ $this->control->maxlength = isset($this->control->maxlength) ? min($this->control->maxlength, $tmp) : $tmp;
+ }
+ }
+ return parent::addRule($validator, $message, $arg);
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/TextInput.php b/vendor/nette/forms/src/Forms/Controls/TextInput.php
new file mode 100755
index 0000000..4f20481
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/TextInput.php
@@ -0,0 +1,98 @@
+control->type = 'text';
+ $this->control->maxlength = $maxLength;
+ }
+
+
+ /**
+ * Loads HTTP data.
+ * @return void
+ */
+ public function loadHttpData()
+ {
+ $this->setValue($this->getHttpData(Form::DATA_LINE));
+ }
+
+
+ /**
+ * Changes control's type attribute.
+ * @param string
+ * @return self
+ */
+ public function setType($type)
+ {
+ $this->control->type = $type;
+ return $this;
+ }
+
+
+ /**
+ * Generates control's HTML element.
+ * @return Nette\Utils\Html
+ */
+ public function getControl()
+ {
+ $input = parent::getControl();
+
+ foreach ($this->getRules() as $rule) {
+ if ($rule->isNegative || $rule->branch) {
+
+ } elseif (in_array($rule->validator, array(Form::MIN, Form::MAX, Form::RANGE), TRUE)
+ && in_array($input->type, array('number', 'range', 'datetime-local', 'datetime', 'date', 'month', 'week', 'time'), TRUE)
+ ) {
+ if ($rule->validator === Form::MIN) {
+ $range = array($rule->arg, NULL);
+ } elseif ($rule->validator === Form::MAX) {
+ $range = array(NULL, $rule->arg);
+ } else {
+ $range = $rule->arg;
+ }
+ if (isset($range[0]) && is_scalar($range[0])) {
+ $input->min = isset($input->min) ? max($input->min, $range[0]) : $range[0];
+ }
+ if (isset($range[1]) && is_scalar($range[1])) {
+ $input->max = isset($input->max) ? min($input->max, $range[1]) : $range[1];
+ }
+
+ } elseif ($rule->validator === Form::PATTERN && is_scalar($rule->arg)
+ && in_array($input->type, array('text', 'search', 'tel', 'url', 'email', 'password'), TRUE)
+ ) {
+ $input->pattern = $rule->arg;
+ }
+ }
+
+ if ($input->type !== 'password' && ($this->rawValue !== '' || $this->emptyValue !== '')) {
+ $input->value = $this->rawValue === ''
+ ? $this->translate($this->emptyValue)
+ : $this->rawValue;
+ }
+ return $input;
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Controls/UploadControl.php b/vendor/nette/forms/src/Forms/Controls/UploadControl.php
new file mode 100755
index 0000000..fb2141b
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Controls/UploadControl.php
@@ -0,0 +1,91 @@
+control->type = 'file';
+ $this->control->multiple = (bool) $multiple;
+ }
+
+
+ /**
+ * This method will be called when the component (or component's parent)
+ * becomes attached to a monitored object. Do not call this method yourself.
+ * @param Nette\ComponentModel\IComponent
+ * @return void
+ */
+ protected function attached($form)
+ {
+ if ($form instanceof Nette\Forms\Form) {
+ if ($form->getMethod() !== Nette\Forms\Form::POST) {
+ throw new Nette\InvalidStateException('File upload requires method POST.');
+ }
+ $form->getElementPrototype()->enctype = 'multipart/form-data';
+ }
+ parent::attached($form);
+ }
+
+
+ /**
+ * Loads HTTP data.
+ * @return void
+ */
+ public function loadHttpData()
+ {
+ $this->value = $this->getHttpData(Nette\Forms\Form::DATA_FILE);
+ if ($this->value === NULL) {
+ $this->value = new FileUpload(NULL);
+ }
+ }
+
+
+ /**
+ * Returns HTML name of control.
+ * @return string
+ */
+ public function getHtmlName()
+ {
+ return parent::getHtmlName() . ($this->control->multiple ? '[]' : '');
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setValue($value)
+ {
+ return $this;
+ }
+
+
+ /**
+ * Has been any file uploaded?
+ * @return bool
+ */
+ public function isFilled()
+ {
+ return $this->value instanceof FileUpload ? $this->value->isOk() : (bool) $this->value; // ignore NULL object
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Form.php b/vendor/nette/forms/src/Forms/Form.php
new file mode 100755
index 0000000..8fbb459
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Form.php
@@ -0,0 +1,639 @@
+ element */
+ private $element;
+
+ /** @var IFormRenderer */
+ private $renderer;
+
+ /** @var Nette\Localization\ITranslator */
+ private $translator;
+
+ /** @var ControlGroup[] */
+ private $groups = array();
+
+ /** @var array */
+ private $errors = array();
+
+ /** @var Nette\Http\IRequest used only by standalone form */
+ public $httpRequest;
+
+
+ /**
+ * Form constructor.
+ * @param string
+ */
+ public function __construct($name = NULL)
+ {
+ if ($name !== NULL) {
+ $this->getElementPrototype()->id = 'frm-' . $name;
+ $tracker = new Controls\HiddenField($name);
+ $tracker->setOmitted();
+ $this[self::TRACKER_ID] = $tracker;
+ }
+ parent::__construct(NULL, $name);
+ }
+
+
+ /**
+ * @return void
+ */
+ protected function validateParent(Nette\ComponentModel\IContainer $parent)
+ {
+ parent::validateParent($parent);
+ $this->monitor(__CLASS__);
+ }
+
+
+ /**
+ * This method will be called when the component (or component's parent)
+ * becomes attached to a monitored object. Do not call this method yourself.
+ * @param Nette\ComponentModel\IComponent
+ * @return void
+ */
+ protected function attached($obj)
+ {
+ if ($obj instanceof self) {
+ throw new Nette\InvalidStateException('Nested forms are forbidden.');
+ }
+ }
+
+
+ /**
+ * Returns self.
+ * @return self
+ */
+ public function getForm($need = TRUE)
+ {
+ return $this;
+ }
+
+
+ /**
+ * Sets form's action.
+ * @param mixed URI
+ * @return self
+ */
+ public function setAction($url)
+ {
+ $this->getElementPrototype()->action = $url;
+ return $this;
+ }
+
+
+ /**
+ * Returns form's action.
+ * @return mixed URI
+ */
+ public function getAction()
+ {
+ return $this->getElementPrototype()->action;
+ }
+
+
+ /**
+ * Sets form's method.
+ * @param string get | post
+ * @return self
+ */
+ public function setMethod($method)
+ {
+ if ($this->httpData !== NULL) {
+ throw new Nette\InvalidStateException(__METHOD__ . '() must be called until the form is empty.');
+ }
+ $this->getElementPrototype()->method = strtolower($method);
+ return $this;
+ }
+
+
+ /**
+ * Returns form's method.
+ * @return string get | post
+ */
+ public function getMethod()
+ {
+ return $this->getElementPrototype()->method;
+ }
+
+
+ /**
+ * Cross-Site Request Forgery (CSRF) form protection.
+ * @param string
+ * @return Controls\CsrfProtection
+ */
+ public function addProtection($message = NULL)
+ {
+ return $this[self::PROTECTOR_ID] = new Controls\CsrfProtection($message);
+ }
+
+
+ /**
+ * Adds fieldset group to the form.
+ * @param string caption
+ * @param bool set this group as current
+ * @return ControlGroup
+ */
+ public function addGroup($caption = NULL, $setAsCurrent = TRUE)
+ {
+ $group = new ControlGroup;
+ $group->setOption('label', $caption);
+ $group->setOption('visual', TRUE);
+
+ if ($setAsCurrent) {
+ $this->setCurrentGroup($group);
+ }
+
+ if (!is_scalar($caption) || isset($this->groups[$caption])) {
+ return $this->groups[] = $group;
+ } else {
+ return $this->groups[$caption] = $group;
+ }
+ }
+
+
+ /**
+ * Removes fieldset group from form.
+ * @param string|ControlGroup
+ * @return void
+ */
+ public function removeGroup($name)
+ {
+ if (is_string($name) && isset($this->groups[$name])) {
+ $group = $this->groups[$name];
+
+ } elseif ($name instanceof ControlGroup && in_array($name, $this->groups, TRUE)) {
+ $group = $name;
+ $name = array_search($group, $this->groups, TRUE);
+
+ } else {
+ throw new Nette\InvalidArgumentException("Group not found in form '$this->name'");
+ }
+
+ foreach ($group->getControls() as $control) {
+ $control->getParent()->removeComponent($control);
+ }
+
+ unset($this->groups[$name]);
+ }
+
+
+ /**
+ * Returns all defined groups.
+ * @return ControlGroup[]
+ */
+ public function getGroups()
+ {
+ return $this->groups;
+ }
+
+
+ /**
+ * Returns the specified group.
+ * @param string name
+ * @return ControlGroup
+ */
+ public function getGroup($name)
+ {
+ return isset($this->groups[$name]) ? $this->groups[$name] : NULL;
+ }
+
+
+ /********************* translator ****************d*g**/
+
+
+ /**
+ * Sets translate adapter.
+ * @return self
+ */
+ public function setTranslator(Nette\Localization\ITranslator $translator = NULL)
+ {
+ $this->translator = $translator;
+ return $this;
+ }
+
+
+ /**
+ * Returns translate adapter.
+ * @return Nette\Localization\ITranslator|NULL
+ */
+ public function getTranslator()
+ {
+ return $this->translator;
+ }
+
+
+ /********************* submission ****************d*g**/
+
+
+ /**
+ * Tells if the form is anchored.
+ * @return bool
+ */
+ public function isAnchored()
+ {
+ return TRUE;
+ }
+
+
+ /**
+ * Tells if the form was submitted.
+ * @return ISubmitterControl|FALSE submittor control
+ */
+ public function isSubmitted()
+ {
+ if ($this->submittedBy === NULL) {
+ $this->getHttpData();
+ }
+ return $this->submittedBy;
+ }
+
+
+ /**
+ * Tells if the form was submitted and successfully validated.
+ * @return bool
+ */
+ public function isSuccess()
+ {
+ return $this->isSubmitted() && $this->isValid();
+ }
+
+
+ /**
+ * Sets the submittor control.
+ * @return self
+ */
+ public function setSubmittedBy(ISubmitterControl $by = NULL)
+ {
+ $this->submittedBy = $by === NULL ? FALSE : $by;
+ return $this;
+ }
+
+
+ /**
+ * Returns submitted HTTP data.
+ * @return mixed
+ */
+ public function getHttpData($type = NULL, $htmlName = NULL)
+ {
+ if ($this->httpData === NULL) {
+ if (!$this->isAnchored()) {
+ throw new Nette\InvalidStateException('Form is not anchored and therefore can not determine whether it was submitted.');
+ }
+ $data = $this->receiveHttpData();
+ $this->httpData = (array) $data;
+ $this->submittedBy = is_array($data);
+ }
+ if ($htmlName === NULL) {
+ return $this->httpData;
+ }
+ return Helpers::extractHttpData($this->httpData, $htmlName, $type);
+ }
+
+
+ /**
+ * Fires submit/click events.
+ * @return void
+ */
+ public function fireEvents()
+ {
+ if (!$this->isSubmitted()) {
+ return;
+
+ } elseif (!$this->getErrors()) {
+ $this->validate();
+ }
+
+ if ($this->submittedBy instanceof ISubmitterControl) {
+ if ($this->isValid()) {
+ $this->submittedBy->onClick($this->submittedBy);
+ } else {
+ $this->submittedBy->onInvalidClick($this->submittedBy);
+ }
+ }
+
+ if (!$this->isValid()) {
+ $this->onError($this);
+ } elseif ($this->onSuccess) {
+ foreach ($this->onSuccess as $handler) {
+ $params = Nette\Utils\Callback::toReflection($handler)->getParameters();
+ $values = isset($params[1]) ? $this->getValues($params[1]->isArray()) : NULL;
+ Nette\Utils\Callback::invoke($handler, $this, $values);
+ if (!$this->isValid()) {
+ $this->onError($this);
+ break;
+ }
+ }
+ }
+
+ $this->onSubmit($this);
+ }
+
+
+ /**
+ * Internal: returns submitted HTTP data or NULL when form was not submitted.
+ * @return array|NULL
+ */
+ protected function receiveHttpData()
+ {
+ $httpRequest = $this->getHttpRequest();
+ if (strcasecmp($this->getMethod(), $httpRequest->getMethod())) {
+ return;
+ }
+
+ if ($httpRequest->isMethod('post')) {
+ $data = Nette\Utils\Arrays::mergeTree($httpRequest->getPost(), $httpRequest->getFiles());
+ } else {
+ $data = $httpRequest->getQuery();
+ if (!$data) {
+ return;
+ }
+ }
+
+ if ($tracker = $this->getComponent(self::TRACKER_ID, FALSE)) {
+ if (!isset($data[self::TRACKER_ID]) || $data[self::TRACKER_ID] !== $tracker->getValue()) {
+ return;
+ }
+ }
+
+ return $data;
+ }
+
+
+ /********************* validation ****************d*g**/
+
+
+ public function validate(array $controls = NULL)
+ {
+ $this->cleanErrors();
+ if ($controls === NULL && $this->submittedBy instanceof ISubmitterControl) {
+ $controls = $this->submittedBy->getValidationScope();
+ }
+ $this->validateMaxPostSize();
+ parent::validate($controls);
+ }
+
+
+ /** @internal */
+ public function validateMaxPostSize()
+ {
+ if (!$this->submittedBy || strcasecmp($this->getMethod(), 'POST') || empty($_SERVER['CONTENT_LENGTH'])) {
+ return;
+ }
+ $maxSize = ini_get('post_max_size');
+ $units = array('k' => 10, 'm' => 20, 'g' => 30);
+ if (isset($units[$ch = strtolower(substr($maxSize, -1))])) {
+ $maxSize <<= $units[$ch];
+ }
+ if ($maxSize > 0 && $maxSize < $_SERVER['CONTENT_LENGTH']) {
+ $this->addError(sprintf(Validator::$messages[self::MAX_FILE_SIZE], $maxSize));
+ }
+ }
+
+
+ /**
+ * Adds global error message.
+ * @param string error message
+ * @return void
+ */
+ public function addError($message)
+ {
+ $this->errors[] = $message;
+ }
+
+
+ /**
+ * Returns global validation errors.
+ * @return array
+ */
+ public function getErrors()
+ {
+ return array_unique(array_merge($this->errors, parent::getErrors()));
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function hasErrors()
+ {
+ return (bool) $this->getErrors();
+ }
+
+
+ /**
+ * @return void
+ */
+ public function cleanErrors()
+ {
+ $this->errors = array();
+ }
+
+
+ /**
+ * Returns form's validation errors.
+ * @return array
+ */
+ public function getOwnErrors()
+ {
+ return array_unique($this->errors);
+ }
+
+
+ /********************* rendering ****************d*g**/
+
+
+ /**
+ * Returns form's HTML element template.
+ * @return Nette\Utils\Html
+ */
+ public function getElementPrototype()
+ {
+ if (!$this->element) {
+ $this->element = Nette\Utils\Html::el('form');
+ $this->element->action = ''; // RFC 1808 -> empty uri means 'this'
+ $this->element->method = self::POST;
+ }
+ return $this->element;
+ }
+
+
+ /**
+ * Sets form renderer.
+ * @return self
+ */
+ public function setRenderer(IFormRenderer $renderer = NULL)
+ {
+ $this->renderer = $renderer;
+ return $this;
+ }
+
+
+ /**
+ * Returns form renderer.
+ * @return IFormRenderer
+ */
+ public function getRenderer()
+ {
+ if ($this->renderer === NULL) {
+ $this->renderer = new Rendering\DefaultFormRenderer;
+ }
+ return $this->renderer;
+ }
+
+
+ /**
+ * Renders form.
+ * @return void
+ */
+ public function render()
+ {
+ $args = func_get_args();
+ array_unshift($args, $this);
+ echo call_user_func_array(array($this->getRenderer(), 'render'), $args);
+ }
+
+
+ /**
+ * Renders form to string.
+ * @param can throw exceptions? (hidden parameter)
+ * @return string
+ */
+ public function __toString()
+ {
+ try {
+ return $this->getRenderer()->render($this);
+
+ } catch (\Exception $e) {
+ if (func_num_args()) {
+ throw $e;
+ }
+ trigger_error("Exception in " . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
+ }
+ }
+
+
+ /********************* backend ****************d*g**/
+
+
+ /**
+ * @return Nette\Http\IRequest
+ */
+ private function getHttpRequest()
+ {
+ if (!$this->httpRequest) {
+ $factory = new Nette\Http\RequestFactory;
+ $this->httpRequest = $factory->createHttpRequest();
+ }
+ return $this->httpRequest;
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getToggles()
+ {
+ $toggles = array();
+ foreach ($this->getControls() as $control) {
+ $toggles = $control->getRules()->getToggleStates($toggles);
+ }
+ return $toggles;
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Helpers.php b/vendor/nette/forms/src/Forms/Helpers.php
new file mode 100755
index 0000000..3dac500
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Helpers.php
@@ -0,0 +1,223 @@
+ $v) {
+ $data[$k] = $v = static::sanitize($itype, $v);
+ if ($v === NULL) {
+ unset($data[$k]);
+ }
+ }
+ if ($type & Form::DATA_KEYS) {
+ return $data;
+ }
+ return array_values($data);
+ } else {
+ return static::sanitize($itype, $data);
+ }
+ }
+
+
+ private static function sanitize($type, $value)
+ {
+ if ($type === Form::DATA_TEXT) {
+ return is_scalar($value) ? Strings::normalizeNewLines($value) : NULL;
+
+ } elseif ($type === Form::DATA_LINE) {
+ return is_scalar($value) ? Strings::trim(strtr($value, "\r\n", ' ')) : NULL;
+
+ } elseif ($type === Form::DATA_FILE) {
+ return $value instanceof Nette\Http\FileUpload ? $value : NULL;
+
+ } else {
+ throw new Nette\InvalidArgumentException('Unknown data type');
+ }
+ }
+
+
+ /**
+ * Converts control name to HTML name.
+ * @return string
+ */
+ public static function generateHtmlName($id)
+ {
+ $name = str_replace(Nette\ComponentModel\IComponent::NAME_SEPARATOR, '][', $id, $count);
+ if ($count) {
+ $name = substr_replace($name, '', strpos($name, ']'), 1) . ']';
+ }
+ if (is_numeric($name) || in_array($name, self::$unsafeNames, TRUE)) {
+ $name = '_' . $name;
+ }
+ return $name;
+ }
+
+
+ /**
+ * @return array
+ */
+ public static function exportRules(Rules $rules)
+ {
+ $payload = array();
+ foreach ($rules as $rule) {
+ if (!is_string($op = $rule->validator)) {
+ if (!Nette\Utils\Callback::isStatic($op)) {
+ continue;
+ }
+ $op = Nette\Utils\Callback::toString($op);
+ }
+ if ($rule->branch) {
+ $item = array(
+ 'op' => ($rule->isNegative ? '~' : '') . $op,
+ 'rules' => static::exportRules($rule->branch),
+ 'control' => $rule->control->getHtmlName(),
+ );
+ if ($rule->branch->getToggles()) {
+ $item['toggle'] = $rule->branch->getToggles();
+ }
+ } else {
+ $item = array('op' => ($rule->isNegative ? '~' : '') . $op, 'msg' => Validator::formatMessage($rule, FALSE));
+ }
+
+ if (is_array($rule->arg)) {
+ foreach ($rule->arg as $key => $value) {
+ $item['arg'][$key] = $value instanceof IControl ? array('control' => $value->getHtmlName()) : $value;
+ }
+ } elseif ($rule->arg !== NULL) {
+ $item['arg'] = $rule->arg instanceof IControl ? array('control' => $rule->arg->getHtmlName()) : $rule->arg;
+ }
+
+ $payload[] = $item;
+ }
+ return $payload;
+ }
+
+
+ /**
+ * @return string
+ */
+ public static function createInputList(array $items, array $inputAttrs = NULL, array $labelAttrs = NULL, $wrapper = NULL)
+ {
+ list($inputAttrs, $inputTag) = self::prepareAttrs($inputAttrs, 'input');
+ list($labelAttrs, $labelTag) = self::prepareAttrs($labelAttrs, 'label');
+ $res = '';
+ $input = Html::el();
+ $label = Html::el();
+ list($wrapper, $wrapperEnd) = $wrapper instanceof Html ? array($wrapper->startTag(), $wrapper->endTag()) : array((string) $wrapper, '');
+
+ foreach ($items as $value => $caption) {
+ foreach ($inputAttrs as $k => $v) {
+ $input->attrs[$k] = isset($v[$value]) ? $v[$value] : NULL;
+ }
+ foreach ($labelAttrs as $k => $v) {
+ $label->attrs[$k] = isset($v[$value]) ? $v[$value] : NULL;
+ }
+ $input->value = $value;
+ $res .= ($res === '' && $wrapperEnd === '' ? '' : $wrapper)
+ . $labelTag . $label->attributes() . '>'
+ . $inputTag . $input->attributes() . (Html::$xhtml ? ' />' : '>')
+ . ($caption instanceof Html ? $caption : htmlspecialchars($caption, ENT_NOQUOTES, 'UTF-8'))
+ . ' '
+ . $wrapperEnd;
+ }
+ return $res;
+ }
+
+
+ /**
+ * @return Html
+ */
+ public static function createSelectBox(array $items, array $optionAttrs = NULL, $selected = NULL)
+ {
+ if ($selected !== NULL) {
+ $optionAttrs['selected?'] = $selected;
+ }
+ list($optionAttrs, $optionTag) = self::prepareAttrs($optionAttrs, 'option');
+ $option = Html::el();
+ $res = $tmp = '';
+ foreach ($items as $group => $subitems) {
+ if (is_array($subitems)) {
+ $res .= Html::el('optgroup')->label($group)->startTag();
+ $tmp = '';
+ } else {
+ $subitems = array($group => $subitems);
+ }
+ foreach ($subitems as $value => $caption) {
+ $option->value = $value;
+ foreach ($optionAttrs as $k => $v) {
+ $option->attrs[$k] = isset($v[$value]) ? $v[$value] : NULL;
+ }
+ if ($caption instanceof Html) {
+ $caption = clone $caption;
+ $res .= $caption->setName('option')->addAttributes($option->attrs);
+ } else {
+ $res .= $optionTag . $option->attributes() . '>'
+ . htmlspecialchars($caption, ENT_NOQUOTES, 'UTF-8')
+ . '';
+ }
+ }
+ $res .= $tmp;
+ $tmp = '';
+ }
+ return Html::el('select')->setHtml($res);
+ }
+
+
+ private static function prepareAttrs($attrs, $name)
+ {
+ $dynamic = array();
+ foreach ((array) $attrs as $k => $v) {
+ $p = str_split($k, strlen($k) - 1);
+ if ($p[1] === '?' || $p[1] === ':') {
+ unset($attrs[$k], $attrs[$p[0]]);
+ if ($p[1] === '?') {
+ $dynamic[$p[0]] = array_fill_keys((array) $v, TRUE);
+ } elseif (is_array($v) && $v) {
+ $dynamic[$p[0]] = $v;
+ } else {
+ $attrs[$p[0]] = $v;
+ }
+ }
+ }
+ return array($dynamic, '<' . $name . Html::el(NULL, $attrs)->attributes());
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/IControl.php b/vendor/nette/forms/src/Forms/IControl.php
new file mode 100755
index 0000000..4a54869
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/IControl.php
@@ -0,0 +1,55 @@
+getValues() result?
+ * @return bool
+ */
+ function isOmitted();
+
+ /**
+ * Returns translated string.
+ * @param string
+ * @param int plural count
+ * @return string
+ */
+ function translate($s, $count = NULL);
+
+}
diff --git a/vendor/nette/forms/src/Forms/IFormRenderer.php b/vendor/nette/forms/src/Forms/IFormRenderer.php
new file mode 100755
index 0000000..f7c073d
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/IFormRenderer.php
@@ -0,0 +1,23 @@
+ array(
+ 'container' => NULL,
+ ),
+
+ 'error' => array(
+ 'container' => 'ul class=error',
+ 'item' => 'li',
+ ),
+
+ 'group' => array(
+ 'container' => 'fieldset',
+ 'label' => 'legend',
+ 'description' => 'p',
+ ),
+
+ 'controls' => array(
+ 'container' => 'table',
+ ),
+
+ 'pair' => array(
+ 'container' => 'tr',
+ '.required' => 'required',
+ '.optional' => NULL,
+ '.odd' => NULL,
+ '.error' => NULL,
+ ),
+
+ 'control' => array(
+ 'container' => 'td',
+ '.odd' => NULL,
+
+ 'description' => 'small',
+ 'requiredsuffix' => '',
+ 'errorcontainer' => 'span class=error',
+ 'erroritem' => '',
+
+ '.required' => 'required',
+ '.text' => 'text',
+ '.password' => 'text',
+ '.file' => 'text',
+ '.submit' => 'button',
+ '.image' => 'imagebutton',
+ '.button' => 'button',
+ ),
+
+ 'label' => array(
+ 'container' => 'th',
+ 'suffix' => NULL,
+ 'requiredsuffix' => '',
+ ),
+
+ 'hidden' => array(
+ 'container' => 'div',
+ ),
+ );
+
+ /** @var Nette\Forms\Form */
+ protected $form;
+
+ /** @var int */
+ protected $counter;
+
+
+ /**
+ * Provides complete form rendering.
+ * @param Nette\Forms\Form
+ * @param string 'begin', 'errors', 'ownerrors', 'body', 'end' or empty to render all
+ * @return string
+ */
+ public function render(Nette\Forms\Form $form, $mode = NULL)
+ {
+ if ($this->form !== $form) {
+ $this->form = $form;
+ }
+
+ $s = '';
+ if (!$mode || $mode === 'begin') {
+ $s .= $this->renderBegin();
+ }
+ if (!$mode || strtolower($mode) === 'ownerrors') {
+ $s .= $this->renderErrors();
+
+ } elseif ($mode === 'errors') {
+ $s .= $this->renderErrors(NULL, FALSE);
+ }
+ if (!$mode || $mode === 'body') {
+ $s .= $this->renderBody();
+ }
+ if (!$mode || $mode === 'end') {
+ $s .= $this->renderEnd();
+ }
+ return $s;
+ }
+
+
+ /**
+ * Renders form begin.
+ * @return string
+ */
+ public function renderBegin()
+ {
+ $this->counter = 0;
+
+ foreach ($this->form->getControls() as $control) {
+ $control->setOption('rendered', FALSE);
+ }
+
+ if (strcasecmp($this->form->getMethod(), 'get') === 0) {
+ $el = clone $this->form->getElementPrototype();
+ $query = parse_url($el->action, PHP_URL_QUERY);
+ $el->action = str_replace("?$query", '', $el->action);
+ $s = '';
+ foreach (preg_split('#[;&]#', $query, NULL, PREG_SPLIT_NO_EMPTY) as $param) {
+ $parts = explode('=', $param, 2);
+ $name = urldecode($parts[0]);
+ if (!isset($this->form[$name])) {
+ $s .= Html::el('input', array('type' => 'hidden', 'name' => $name, 'value' => urldecode($parts[1])));
+ }
+ }
+ return $el->startTag() . ($s ? "\n\t" . $this->getWrapper('hidden container')->setHtml($s) : '');
+
+ } else {
+ return $this->form->getElementPrototype()->startTag();
+ }
+ }
+
+
+ /**
+ * Renders form end.
+ * @return string
+ */
+ public function renderEnd()
+ {
+ $s = '';
+ foreach ($this->form->getControls() as $control) {
+ if ($control instanceof Nette\Forms\Controls\HiddenField && !$control->getOption('rendered')) {
+ $s .= $control->getControl();
+ }
+ }
+ if (iterator_count($this->form->getComponents(TRUE, 'Nette\Forms\Controls\TextInput')) < 2) {
+ $s .= '';
+ }
+ if ($s) {
+ $s = $this->getWrapper('hidden container')->setHtml($s) . "\n";
+ }
+
+ return $s . $this->form->getElementPrototype()->endTag() . "\n";
+ }
+
+
+ /**
+ * Renders validation errors (per form or per control).
+ * @return string
+ */
+ public function renderErrors(Nette\Forms\IControl $control = NULL, $own = TRUE)
+ {
+ $errors = $control
+ ? $control->getErrors()
+ : ($own ? $this->form->getOwnErrors() : $this->form->getErrors());
+ if (!$errors) {
+ return;
+ }
+ $container = $this->getWrapper($control ? 'control errorcontainer' : 'error container');
+ $item = $this->getWrapper($control ? 'control erroritem' : 'error item');
+
+ foreach ($errors as $error) {
+ $item = clone $item;
+ if ($error instanceof Html) {
+ $item->add($error);
+ } else {
+ $item->setText($error);
+ }
+ $container->add($item);
+ }
+ return "\n" . $container->render($control ? 1 : 0);
+ }
+
+
+ /**
+ * Renders form body.
+ * @return string
+ */
+ public function renderBody()
+ {
+ $s = $remains = '';
+
+ $defaultContainer = $this->getWrapper('group container');
+ $translator = $this->form->getTranslator();
+
+ foreach ($this->form->getGroups() as $group) {
+ if (!$group->getControls() || !$group->getOption('visual')) {
+ continue;
+ }
+
+ $container = $group->getOption('container', $defaultContainer);
+ $container = $container instanceof Html ? clone $container : Html::el($container);
+
+ $id = $group->getOption('id');
+ if ($id) {
+ $container->id = $id;
+ }
+
+ $s .= "\n" . $container->startTag();
+
+ $text = $group->getOption('label');
+ if ($text instanceof Html) {
+ $s .= $this->getWrapper('group label')->add($text);
+
+ } elseif (is_string($text)) {
+ if ($translator !== NULL) {
+ $text = $translator->translate($text);
+ }
+ $s .= "\n" . $this->getWrapper('group label')->setText($text) . "\n";
+ }
+
+ $text = $group->getOption('description');
+ if ($text instanceof Html) {
+ $s .= $text;
+
+ } elseif (is_string($text)) {
+ if ($translator !== NULL) {
+ $text = $translator->translate($text);
+ }
+ $s .= $this->getWrapper('group description')->setText($text) . "\n";
+ }
+
+ $s .= $this->renderControls($group);
+
+ $remains = $container->endTag() . "\n" . $remains;
+ if (!$group->getOption('embedNext')) {
+ $s .= $remains;
+ $remains = '';
+ }
+ }
+
+ $s .= $remains . $this->renderControls($this->form);
+
+ $container = $this->getWrapper('form container');
+ $container->setHtml($s);
+ return $container->render(0);
+ }
+
+
+ /**
+ * Renders group of controls.
+ * @param Nette\Forms\Container|Nette\Forms\ControlGroup
+ * @return string
+ */
+ public function renderControls($parent)
+ {
+ if (!($parent instanceof Nette\Forms\Container || $parent instanceof Nette\Forms\ControlGroup)) {
+ throw new Nette\InvalidArgumentException('Argument must be Nette\Forms\Container or Nette\Forms\ControlGroup instance.');
+ }
+
+ $container = $this->getWrapper('controls container');
+
+ $buttons = NULL;
+ foreach ($parent->getControls() as $control) {
+ if ($control->getOption('rendered') || $control instanceof Nette\Forms\Controls\HiddenField || $control->getForm(FALSE) !== $this->form) {
+ // skip
+
+ } elseif ($control instanceof Nette\Forms\Controls\Button) {
+ $buttons[] = $control;
+
+ } else {
+ if ($buttons) {
+ $container->add($this->renderPairMulti($buttons));
+ $buttons = NULL;
+ }
+ $container->add($this->renderPair($control));
+ }
+ }
+
+ if ($buttons) {
+ $container->add($this->renderPairMulti($buttons));
+ }
+
+ $s = '';
+ if (count($container)) {
+ $s .= "\n" . $container . "\n";
+ }
+
+ return $s;
+ }
+
+
+ /**
+ * Renders single visual row.
+ * @return string
+ */
+ public function renderPair(Nette\Forms\IControl $control)
+ {
+ $pair = $this->getWrapper('pair container');
+ $pair->add($this->renderLabel($control));
+ $pair->add($this->renderControl($control));
+ $pair->class($this->getValue($control->isRequired() ? 'pair .required' : 'pair .optional'), TRUE);
+ $pair->class($control->hasErrors() ? $this->getValue('pair .error') : NULL, TRUE);
+ $pair->class($control->getOption('class'), TRUE);
+ if (++$this->counter % 2) {
+ $pair->class($this->getValue('pair .odd'), TRUE);
+ }
+ $pair->id = $control->getOption('id');
+ return $pair->render(0);
+ }
+
+
+ /**
+ * Renders single visual row of multiple controls.
+ * @param Nette\Forms\IControl[]
+ * @return string
+ */
+ public function renderPairMulti(array $controls)
+ {
+ $s = array();
+ foreach ($controls as $control) {
+ if (!$control instanceof Nette\Forms\IControl) {
+ throw new Nette\InvalidArgumentException('Argument must be array of Nette\Forms\IControl instances.');
+ }
+ $description = $control->getOption('description');
+ if ($description instanceof Html) {
+ $description = ' ' . $control->getOption('description');
+
+ } elseif (is_string($description)) {
+ $description = ' ' . $this->getWrapper('control description')->setText($control->translate($description));
+
+ } else {
+ $description = '';
+ }
+
+ $control->setOption('rendered', TRUE);
+ $el = $control->getControl();
+ if ($el instanceof Html && $el->getName() === 'input') {
+ $el->class($this->getValue("control .$el->type"), TRUE);
+ }
+ $s[] = $el . $description;
+ }
+ $pair = $this->getWrapper('pair container');
+ $pair->add($this->renderLabel($control));
+ $pair->add($this->getWrapper('control container')->setHtml(implode(' ', $s)));
+ return $pair->render(0);
+ }
+
+
+ /**
+ * Renders 'label' part of visual row of controls.
+ * @return string
+ */
+ public function renderLabel(Nette\Forms\IControl $control)
+ {
+ $suffix = $this->getValue('label suffix') . ($control->isRequired() ? $this->getValue('label requiredsuffix') : '');
+ $label = $control->getLabel();
+ if ($label instanceof Html) {
+ $label->add($suffix);
+ if ($control->isRequired()) {
+ $label->class($this->getValue('control .required'), TRUE);
+ }
+ } elseif ($label != NULL) { // @intentionally ==
+ $label .= $suffix;
+ }
+ return $this->getWrapper('label container')->setHtml($label);
+ }
+
+
+ /**
+ * Renders 'control' part of visual row of controls.
+ * @return string
+ */
+ public function renderControl(Nette\Forms\IControl $control)
+ {
+ $body = $this->getWrapper('control container');
+ if ($this->counter % 2) {
+ $body->class($this->getValue('control .odd'), TRUE);
+ }
+
+ $description = $control->getOption('description');
+ if ($description instanceof Html) {
+ $description = ' ' . $description;
+
+ } elseif (is_string($description)) {
+ $description = ' ' . $this->getWrapper('control description')->setText($control->translate($description));
+
+ } else {
+ $description = '';
+ }
+
+ if ($control->isRequired()) {
+ $description = $this->getValue('control requiredsuffix') . $description;
+ }
+
+ $control->setOption('rendered', TRUE);
+ $el = $control->getControl();
+ if ($el instanceof Html && $el->getName() === 'input') {
+ $el->class($this->getValue("control .$el->type"), TRUE);
+ }
+ return $body->setHtml($el . $description . $this->renderErrors($control));
+ }
+
+
+ /**
+ * @param string
+ * @return Html
+ */
+ protected function getWrapper($name)
+ {
+ $data = $this->getValue($name);
+ return $data instanceof Html ? clone $data : Html::el($data);
+ }
+
+
+ /**
+ * @param string
+ * @return string
+ */
+ protected function getValue($name)
+ {
+ $name = explode(' ', $name);
+ $data = & $this->wrappers[$name[0]][$name[1]];
+ return $data;
+ }
+
+}
diff --git a/vendor/nette/forms/src/Forms/Rule.php b/vendor/nette/forms/src/Forms/Rule.php
new file mode 100755
index 0000000..e330d0d
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Rule.php
@@ -0,0 +1,36 @@
+control = $control;
+ }
+
+
+ /**
+ * Makes control mandatory.
+ * @param mixed state or error message
+ * @return self
+ */
+ public function setRequired($value = TRUE)
+ {
+ if ($value) {
+ $this->addRule(Form::REQUIRED, is_string($value) ? $value : NULL);
+ } else {
+ $this->required = NULL;
+ }
+ return $this;
+ }
+
+
+ /**
+ * Is control mandatory?
+ * @return bool
+ */
+ public function isRequired()
+ {
+ return $this->required instanceof Rule ? !$this->required->isNegative : FALSE;
+ }
+
+
+ /**
+ * Adds a validation rule for the current control.
+ * @param mixed rule type
+ * @param string message to display for invalid data
+ * @param mixed optional rule arguments
+ * @return self
+ */
+ public function addRule($validator, $message = NULL, $arg = NULL)
+ {
+ $rule = new Rule;
+ $rule->control = $this->control;
+ $rule->validator = $validator;
+ $this->adjustOperation($rule);
+ $rule->arg = $arg;
+ $rule->message = $message;
+ if ($rule->validator === Form::REQUIRED) {
+ $this->required = $rule;
+ } else {
+ $this->rules[] = $rule;
+ }
+ return $this;
+ }
+
+
+ /**
+ * Adds a validation condition and returns new branch.
+ * @param mixed condition type
+ * @param mixed optional condition arguments
+ * @return self new branch
+ */
+ public function addCondition($validator, $arg = NULL)
+ {
+ return $this->addConditionOn($this->control, $validator, $arg);
+ }
+
+
+ /**
+ * Adds a validation condition on specified control a returns new branch.
+ * @param IControl form control
+ * @param mixed condition type
+ * @param mixed optional condition arguments
+ * @return self new branch
+ */
+ public function addConditionOn(IControl $control, $validator, $arg = NULL)
+ {
+ $rule = new Rule;
+ $rule->control = $control;
+ $rule->validator = $validator;
+ $this->adjustOperation($rule);
+ $rule->arg = $arg;
+ $rule->branch = new static($this->control);
+ $rule->branch->parent = $this;
+
+ $this->rules[] = $rule;
+ return $rule->branch;
+ }
+
+
+ /**
+ * Adds a else statement.
+ * @return self else branch
+ */
+ public function elseCondition()
+ {
+ $rule = clone end($this->parent->rules);
+ $rule->isNegative = !$rule->isNegative;
+ $rule->branch = new static($this->parent->control);
+ $rule->branch->parent = $this->parent;
+ $this->parent->rules[] = $rule;
+ return $rule->branch;
+ }
+
+
+ /**
+ * Ends current validation condition.
+ * @return Rules parent branch
+ */
+ public function endCondition()
+ {
+ return $this->parent;
+ }
+
+
+ /**
+ * Adds a filter callback.
+ * @param callable
+ * @return self
+ */
+ public function addFilter($filter)
+ {
+ Nette\Utils\Callback::check($filter);
+ $this->rules[] = $rule = new Rule;
+ $rule->control = $this->control;
+ $rule->validator = function (IControl $control) use ($filter) {
+ $control->setValue(call_user_func($filter, $control->getValue()));
+ return TRUE;
+ };
+ return $this;
+ }
+
+
+ /**
+ * Toggles HTML element visibility.
+ * @param string element id
+ * @param bool hide element?
+ * @return self
+ */
+ public function toggle($id, $hide = TRUE)
+ {
+ $this->toggles[$id] = $hide;
+ return $this;
+ }
+
+
+ /**
+ * @param bool
+ * @return array
+ */
+ public function getToggles($actual = FALSE)
+ {
+ return $actual ? $this->getToggleStates() : $this->toggles;
+ }
+
+
+ /**
+ * @internal
+ * @return array
+ */
+ public function getToggleStates($toggles = array(), $success = TRUE)
+ {
+ foreach ($this->toggles as $id => $hide) {
+ $toggles[$id] = ($success xor !$hide) || !empty($toggles[$id]);
+ }
+
+ foreach ($this as $rule) {
+ if ($rule->branch) {
+ $toggles = $rule->branch->getToggleStates($toggles, $success && static::validateRule($rule));
+ }
+ }
+ return $toggles;
+ }
+
+
+ /**
+ * Validates against ruleset.
+ * @return bool
+ */
+ public function validate()
+ {
+ foreach ($this as $rule) {
+ $success = $this->validateRule($rule);
+
+ if ($success && $rule->branch && !$rule->branch->validate()) {
+ return FALSE;
+
+ } elseif (!$success && !$rule->branch) {
+ $rule->control->addError(Validator::formatMessage($rule, TRUE));
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+
+ /**
+ * Validates single rule.
+ * @return bool
+ */
+ public static function validateRule(Rule $rule)
+ {
+ $args = is_array($rule->arg) ? $rule->arg : array($rule->arg);
+ foreach ($args as & $val) {
+ $val = $val instanceof IControl ? $val->getValue() : $val;
+ }
+ return $rule->isNegative
+ xor call_user_func(self::getCallback($rule), $rule->control, is_array($rule->arg) ? $args : $args[0]);
+ }
+
+
+ /**
+ * Iterates over complete ruleset.
+ * @return \ArrayIterator
+ */
+ public function getIterator()
+ {
+ $rules = $this->rules;
+ if ($this->required) {
+ array_unshift($rules, $this->required);
+ }
+ return new \ArrayIterator($rules);
+ }
+
+
+ /**
+ * Process 'operation' string.
+ * @param Rule
+ * @return void
+ */
+ private function adjustOperation($rule)
+ {
+ if (is_string($rule->validator) && ord($rule->validator[0]) > 127) {
+ $rule->isNegative = TRUE;
+ $rule->validator = ~$rule->validator;
+ }
+
+ if (!is_callable($this->getCallback($rule))) {
+ $validator = is_scalar($rule->validator) ? " '$rule->validator'" : '';
+ throw new Nette\InvalidArgumentException("Unknown validator$validator for control '{$rule->control->name}'.");
+ }
+ }
+
+
+ private static function getCallback($rule)
+ {
+ $op = $rule->validator;
+ if (is_string($op) && strncmp($op, ':', 1) === 0) {
+ return 'Nette\Forms\Validator::validate' . ltrim($op, ':');
+ } else {
+ return $op;
+ }
+ }
+
+}
+
+Rules::$defaultMessages = & Validator::$messages;
diff --git a/vendor/nette/forms/src/Forms/Validator.php b/vendor/nette/forms/src/Forms/Validator.php
new file mode 100755
index 0000000..424278a
--- /dev/null
+++ b/vendor/nette/forms/src/Forms/Validator.php
@@ -0,0 +1,338 @@
+ 'Your session has expired. Please return to the home page and try again.',
+ Form::EQUAL => 'Please enter %s.',
+ Form::NOT_EQUAL => 'This value should not be %s.',
+ Form::FILLED => 'This field is required.',
+ Form::BLANK => 'This field should be blank.',
+ Form::MIN_LENGTH => 'Please enter at least %d characters.',
+ Form::MAX_LENGTH => 'Please enter no more than %d characters.',
+ Form::LENGTH => 'Please enter a value between %d and %d characters long.',
+ Form::EMAIL => 'Please enter a valid email address.',
+ Form::URL => 'Please enter a valid URL.',
+ Form::INTEGER => 'Please enter a valid integer.',
+ Form::FLOAT => 'Please enter a valid number.',
+ Form::MIN => 'Please enter a value greater than or equal to %d.',
+ Form::MAX => 'Please enter a value less than or equal to %d.',
+ Form::RANGE => 'Please enter a value between %d and %d.',
+ Form::MAX_FILE_SIZE => 'The size of the uploaded file can be up to %d bytes.',
+ Form::MAX_POST_SIZE => 'The uploaded data exceeds the limit of %d bytes.',
+ Form::MIME_TYPE => 'The uploaded file is not in the expected format.',
+ Form::IMAGE => 'The uploaded file must be image in format JPEG, GIF or PNG.',
+ Controls\SelectBox::VALID => 'Please select a valid option.',
+ );
+
+
+ /** @internal */
+ public static function formatMessage(Rule $rule, $withValue = TRUE)
+ {
+ $message = $rule->message;
+ if ($message instanceof Nette\Utils\Html) {
+ return $message;
+
+ } elseif ($message === NULL && is_string($rule->validator) && isset(static::$messages[$rule->validator])) {
+ $message = static::$messages[$rule->validator];
+
+ } elseif ($message == NULL) { // intentionally ==
+ trigger_error("Missing validation message for control '{$rule->control->getName()}'.", E_USER_WARNING);
+ }
+
+ if ($translator = $rule->control->getForm()->getTranslator()) {
+ $message = $translator->translate($message, is_int($rule->arg) ? $rule->arg : NULL);
+ }
+
+ $message = preg_replace_callback('#%(name|label|value|\d+\$[ds]|[ds])#', function ($m) use ($rule, $withValue) {
+ static $i = -1;
+ switch ($m[1]) {
+ case 'name': return $rule->control->getName();
+ case 'label': return $rule->control->translate($rule->control->caption);
+ case 'value': return $withValue ? $rule->control->getValue() : $m[0];
+ default:
+ $args = is_array($rule->arg) ? $rule->arg : array($rule->arg);
+ $i = (int) $m[1] ? $m[1] - 1 : $i + 1;
+ return isset($args[$i]) ? ($args[$i] instanceof IControl ? ($withValue ? $args[$i]->getValue() : "%$i") : $args[$i]) : '';
+ }
+ }, $message);
+ return $message;
+ }
+
+
+ /********************* default validators ****************d*g**/
+
+
+ /**
+ * Is control's value equal with second parameter?
+ * @return bool
+ */
+ public static function validateEqual(IControl $control, $arg)
+ {
+ $value = $control->getValue();
+ foreach ((is_array($value) ? $value : array($value)) as $val) {
+ foreach ((is_array($arg) ? $arg : array($arg)) as $item) {
+ if ((string) $val === (string) $item) {
+ continue 2;
+ }
+ }
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+
+ /**
+ * Is control's value not equal with second parameter?
+ * @return bool
+ */
+ public static function validateNotEqual(IControl $control, $arg)
+ {
+ return !static::validateEqual($control, $arg);
+ }
+
+
+ /**
+ * Is control filled?
+ * @return bool
+ */
+ public static function validateFilled(IControl $control)
+ {
+ return $control->isFilled();
+ }
+
+
+ /**
+ * Is control not filled?
+ * @return bool
+ */
+ public static function validateBlank(IControl $control)
+ {
+ return !$control->isFilled();
+ }
+
+
+ /**
+ * Is control valid?
+ * @return bool
+ */
+ public static function validateValid(IControl $control)
+ {
+ return $control->getRules()->validate();
+ }
+
+
+ /**
+ * Is a control's value number in specified range?
+ * @return bool
+ */
+ public static function validateRange(IControl $control, $range)
+ {
+ return Validators::isInRange($control->getValue(), $range);
+ }
+
+
+ /**
+ * Is a control's value number greater than or equal to the specified minimum?
+ * @return bool
+ */
+ public static function validateMin(IControl $control, $minimum)
+ {
+ return Validators::isInRange($control->getValue(), array($minimum, NULL));
+ }
+
+
+ /**
+ * Is a control's value number less than or equal to the specified maximum?
+ * @return bool
+ */
+ public static function validateMax(IControl $control, $maximum)
+ {
+ return Validators::isInRange($control->getValue(), array(NULL, $maximum));
+ }
+
+
+ /**
+ * Count/length validator. Range is array, min and max length pair.
+ * @return bool
+ */
+ public static function validateLength(IControl $control, $range)
+ {
+ if (!is_array($range)) {
+ $range = array($range, $range);
+ }
+ $value = $control->getValue();
+ return Validators::isInRange(is_array($value) ? count($value) : Strings::length($value), $range);
+ }
+
+
+ /**
+ * Has control's value minimal count/length?
+ * @return bool
+ */
+ public static function validateMinLength(IControl $control, $length)
+ {
+ return static::validateLength($control, array($length, NULL));
+ }
+
+
+ /**
+ * Is control's value count/length in limit?
+ * @return bool
+ */
+ public static function validateMaxLength(IControl $control, $length)
+ {
+ return static::validateLength($control, array(NULL, $length));
+ }
+
+
+ /**
+ * Has been button pressed?
+ * @return bool
+ */
+ public static function validateSubmitted(Controls\SubmitButton $control)
+ {
+ return $control->isSubmittedBy();
+ }
+
+
+ /**
+ * Is control's value valid email address?
+ * @return bool
+ */
+ public static function validateEmail(IControl $control)
+ {
+ return Validators::isEmail($control->getValue());
+ }
+
+
+ /**
+ * Is control's value valid URL?
+ * @return bool
+ */
+ public static function validateUrl(IControl $control)
+ {
+ if (Validators::isUrl($value = $control->getValue())) {
+ return TRUE;
+
+ } elseif (Validators::isUrl($value = "http://$value")) {
+ $control->setValue($value);
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+
+ /**
+ * Matches control's value regular expression?
+ * @return bool
+ */
+ public static function validatePattern(IControl $control, $pattern)
+ {
+ return (bool) Strings::match($control->getValue(), "\x01^($pattern)\\z\x01u");
+ }
+
+
+ /**
+ * Is a control's value decimal number?
+ * @return bool
+ */
+ public static function validateInteger(IControl $control)
+ {
+ if (Validators::isNumericInt($value = $control->getValue())) {
+ if (!is_float($tmp = $value * 1)) { // bigint leave as string
+ $control->setValue($tmp);
+ }
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+
+ /**
+ * Is a control's value float number?
+ * @return bool
+ */
+ public static function validateFloat(IControl $control)
+ {
+ $value = str_replace(array(' ', ','), array('', '.'), $control->getValue());
+ if (Validators::isNumeric($value)) {
+ $control->setValue((float) $value);
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+
+ /**
+ * Is file size in limit?
+ * @return bool
+ */
+ public static function validateFileSize(Controls\UploadControl $control, $limit)
+ {
+ foreach (static::toArray($control->getValue()) as $file) {
+ if ($file->getSize() > $limit || $file->getError() === UPLOAD_ERR_INI_SIZE) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+
+ /**
+ * Has file specified mime type?
+ * @return bool
+ */
+ public static function validateMimeType(Controls\UploadControl $control, $mimeType)
+ {
+ $mimeTypes = is_array($mimeType) ? $mimeType : explode(',', $mimeType);
+ foreach (static::toArray($control->getValue()) as $file) {
+ $type = strtolower($file->getContentType());
+ if (!in_array($type, $mimeTypes, TRUE) && !in_array(preg_replace('#/.*#', '/*', $type), $mimeTypes, TRUE)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+
+ /**
+ * Is file image?
+ * @return bool
+ */
+ public static function validateImage(Controls\UploadControl $control)
+ {
+ foreach (static::toArray($control->getValue()) as $file) {
+ if (!$file->isImage()) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+
+ /**
+ * @return array
+ */
+ private static function toArray($value)
+ {
+ return $value instanceof Nette\Http\FileUpload ? array($value) : (array) $value;
+ }
+
+}
diff --git a/vendor/nette/forms/src/assets/netteForms.js b/vendor/nette/forms/src/assets/netteForms.js
new file mode 100755
index 0000000..d204c64
--- /dev/null
+++ b/vendor/nette/forms/src/assets/netteForms.js
@@ -0,0 +1,597 @@
+/**
+ * NetteForms - simple form validation.
+ *
+ * This file is part of the Nette Framework (http://nette.org)
+ * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
+ */
+
+(function(global, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define(function() {
+ return factory(global);
+ });
+ } else if (typeof module === 'object' && typeof module.exports === 'object') {
+ module.exports = factory(global);
+ } else {
+ global.Nette = factory(global);
+ global.Nette.initOnLoad();
+ }
+
+}(typeof window !== 'undefined' ? window : this, function(window) {
+
+'use strict';
+
+var Nette = {};
+
+/**
+ * Attaches a handler to an event for the element.
+ */
+Nette.addEvent = function(element, on, callback) {
+ var original = element['on' + on];
+ element['on' + on] = function() {
+ if (typeof original === 'function' && original.apply(element, arguments) === false) {
+ return false;
+ }
+ return callback.apply(element, arguments);
+ };
+};
+
+
+/**
+ * Returns the value of form element.
+ */
+Nette.getValue = function(elem) {
+ var i;
+ if (!elem) {
+ return null;
+
+ } else if (!elem.tagName) { // RadioNodeList, HTMLCollection, array
+ return elem[0] ? Nette.getValue(elem[0]) : null;
+
+ } else if (elem.type === 'radio') {
+ var elements = elem.form.elements; // prevents problem with name 'item' or 'namedItem'
+ for (i = 0; i < elements.length; i++) {
+ if (elements[i].name === elem.name && elements[i].checked) {
+ return elements[i].value;
+ }
+ }
+ return null;
+
+ } else if (elem.type === 'file') {
+ return elem.files || elem.value;
+
+ } else if (elem.tagName.toLowerCase() === 'select') {
+ var index = elem.selectedIndex,
+ options = elem.options,
+ values = [];
+
+ if (elem.type === 'select-one') {
+ return index < 0 ? null : options[index].value;
+ }
+
+ for (i = 0; i < options.length; i++) {
+ if (options[i].selected) {
+ values.push(options[i].value);
+ }
+ }
+ return values;
+
+ } else if (elem.name && elem.name.match(/\[\]$/)) { // multiple elements []
+ var elements = elem.form.elements[elem.name].tagName ? [elem] : elem.form.elements[elem.name],
+ values = [];
+
+ for (i = 0; i < elements.length; i++) {
+ if (elements[i].type !== 'checkbox' || elements[i].checked) {
+ values.push(elements[i].value);
+ }
+ }
+ return values;
+
+ } else if (elem.type === 'checkbox') {
+ return elem.checked;
+
+ } else if (elem.tagName.toLowerCase() === 'textarea') {
+ return elem.value.replace("\r", '');
+
+ } else {
+ return elem.value.replace("\r", '').replace(/^\s+|\s+$/g, '');
+ }
+};
+
+
+/**
+ * Returns the effective value of form element.
+ */
+Nette.getEffectiveValue = function(elem) {
+ var val = Nette.getValue(elem);
+ if (elem.getAttribute) {
+ if (val === elem.getAttribute('data-nette-empty-value')) {
+ val = '';
+ }
+ }
+ return val;
+};
+
+
+/**
+ * Validates form element against given rules.
+ */
+Nette.validateControl = function(elem, rules, onlyCheck, value) {
+ elem = elem.tagName ? elem : elem[0]; // RadioNodeList
+ rules = rules || Nette.parseJSON(elem.getAttribute('data-nette-rules'));
+ value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
+
+ for (var id = 0, len = rules.length; id < len; id++) {
+ var rule = rules[id],
+ op = rule.op.match(/(~)?([^?]+)/),
+ curElem = rule.control ? elem.form.elements.namedItem(rule.control) : elem;
+
+ if (!curElem) {
+ continue;
+ }
+
+ rule.neg = op[1];
+ rule.op = op[2];
+ rule.condition = !!rule.rules;
+ curElem = curElem.tagName ? curElem : curElem[0]; // RadioNodeList
+
+ var curValue = elem === curElem ? value : {value: Nette.getEffectiveValue(curElem)},
+ success = Nette.validateRule(curElem, rule.op, rule.arg, curValue);
+
+ if (success === null) {
+ continue;
+ } else if (rule.neg) {
+ success = !success;
+ }
+
+ if (rule.condition && success) {
+ if (!Nette.validateControl(elem, rule.rules, onlyCheck, value)) {
+ return false;
+ }
+ } else if (!rule.condition && !success) {
+ if (Nette.isDisabled(curElem)) {
+ continue;
+ }
+ if (!onlyCheck) {
+ var arr = Nette.isArray(rule.arg) ? rule.arg : [rule.arg],
+ message = rule.msg.replace(/%(value|\d+)/g, function(foo, m) {
+ return Nette.getValue(m === 'value' ? curElem : elem.form.elements.namedItem(arr[m].control));
+ });
+ Nette.addError(curElem, message);
+ }
+ return false;
+ }
+ }
+ return true;
+};
+
+
+/**
+ * Validates whole form.
+ */
+Nette.validateForm = function(sender) {
+ var form = sender.form || sender,
+ scope = false;
+
+ if (form['nette-submittedBy'] && form['nette-submittedBy'].getAttribute('formnovalidate') !== null) {
+ var scopeArr = Nette.parseJSON(form['nette-submittedBy'].getAttribute('data-nette-validation-scope'));
+ if (scopeArr.length) {
+ scope = new RegExp('^(' + scopeArr.join('-|') + '-)');
+ } else {
+ return true;
+ }
+ }
+
+ var radios = {}, i, elem;
+
+ for (i = 0; i < form.elements.length; i++) {
+ elem = form.elements[i];
+
+ if (elem.tagName && !(elem.tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1})) {
+ continue;
+
+ } else if (elem.type === 'radio') {
+ if (radios[elem.name]) {
+ continue;
+ }
+ radios[elem.name] = true;
+ }
+
+ if ((scope && !elem.name.replace(/]\[|\[|]|$/g, '-').match(scope)) || Nette.isDisabled(elem)) {
+ continue;
+ }
+
+ if (!Nette.validateControl(elem)) {
+ return false;
+ }
+ }
+ return true;
+};
+
+
+/**
+ * Check if input is disabled.
+ */
+Nette.isDisabled = function(elem) {
+ if (elem.type === 'radio') {
+ for (var i = 0, elements = elem.form.elements; i < elements.length; i++) {
+ if (elements[i].name === elem.name && !elements[i].disabled) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return elem.disabled;
+};
+
+
+/**
+ * Display error message.
+ */
+Nette.addError = function(elem, message) {
+ if (message) {
+ alert(message);
+ }
+ if (elem.focus) {
+ elem.focus();
+ }
+};
+
+
+/**
+ * Expand rule argument.
+ */
+Nette.expandRuleArgument = function(form, arg) {
+ if (arg && arg.control) {
+ arg = Nette.getEffectiveValue(form.elements.namedItem(arg.control));
+ }
+ return arg;
+};
+
+
+/**
+ * Validates single rule.
+ */
+Nette.validateRule = function(elem, op, arg, value) {
+ value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
+
+ if (op.charAt(0) === ':') {
+ op = op.substr(1);
+ }
+ op = op.replace('::', '_');
+ op = op.replace(/\\/g, '');
+
+ var arr = Nette.isArray(arg) ? arg.slice(0) : [arg];
+ for (var i = 0, len = arr.length; i < len; i++) {
+ arr[i] = Nette.expandRuleArgument(elem.form, arr[i]);
+ }
+ return Nette.validators[op]
+ ? Nette.validators[op](elem, Nette.isArray(arg) ? arr : arr[0], value.value, value)
+ : null;
+};
+
+
+Nette.validators = {
+ filled: function(elem, arg, val) {
+ return val !== '' && val !== false && val !== null
+ && (!Nette.isArray(val) || !!val.length)
+ && (!window.FileList || !(val instanceof window.FileList) || val.length);
+ },
+
+ blank: function(elem, arg, val) {
+ return !Nette.validators.filled(elem, arg, val);
+ },
+
+ valid: function(elem, arg, val) {
+ return Nette.validateControl(elem, null, true);
+ },
+
+ equal: function(elem, arg, val) {
+ if (arg === undefined) {
+ return null;
+ }
+ val = Nette.isArray(val) ? val : [val];
+ arg = Nette.isArray(arg) ? arg : [arg];
+ loop:
+ for (var i1 = 0, len1 = val.length; i1 < len1; i1++) {
+ for (var i2 = 0, len2 = arg.length; i2 < len2; i2++) {
+ /* jshint eqeqeq: false */
+ if (val[i1] == arg[i2]) {
+ continue loop;
+ }
+ }
+ return false;
+ }
+ return true;
+ },
+
+ notEqual: function(elem, arg, val) {
+ return arg === undefined ? null : !Nette.validators.equal(elem, arg, val);
+ },
+
+ minLength: function(elem, arg, val) {
+ return val.length >= arg;
+ },
+
+ maxLength: function(elem, arg, val) {
+ return val.length <= arg;
+ },
+
+ length: function(elem, arg, val) {
+ arg = Nette.isArray(arg) ? arg : [arg, arg];
+ return (arg[0] === null || val.length >= arg[0]) && (arg[1] === null || val.length <= arg[1]);
+ },
+
+ email: function(elem, arg, val) {
+ return (/^("([ !\x23-\x5B\x5D-\x7E]*|\\[ -~])+"|[-a-z0-9!#$%&'*+\/=?^_`{|}~]+(\.[-a-z0-9!#$%&'*+\/=?^_`{|}~]+)*)@([0-9a-z\u00C0-\u02FF\u0370-\u1EFF]([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,61}[0-9a-z\u00C0-\u02FF\u0370-\u1EFF])?\.)+[a-z\u00C0-\u02FF\u0370-\u1EFF][-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,17}[a-z\u00C0-\u02FF\u0370-\u1EFF]$/i).test(val);
+ },
+
+ url: function(elem, arg, val, value) {
+ if (!(/^[a-z\d+.-]+:/).test(val)) {
+ val = 'http://' + val;
+ }
+ if ((/^https?:\/\/([0-9a-z\u00C0-\u02FF\u0370-\u1EFF](([-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,61}[0-9a-z\u00C0-\u02FF\u0370-\u1EFF])?\.)*[a-z\u00C0-\u02FF\u0370-\u1EFF][-0-9a-z\u00C0-\u02FF\u0370-\u1EFF]{0,17}[a-z\u00C0-\u02FF\u0370-\u1EFF]|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|\[[0-9a-f:]{3,39}\])(:\d{1,5})?(\/\S*)?$/i).test(val)) {
+ value.value = val;
+ return true;
+ }
+ return false;
+ },
+
+ regexp: function(elem, arg, val) {
+ var parts = typeof arg === 'string' ? arg.match(/^\/(.*)\/([imu]*)$/) : false;
+ try {
+ return parts && (new RegExp(parts[1], parts[2].replace('u', ''))).test(val);
+ } catch (e) {}
+ },
+
+ pattern: function(elem, arg, val) {
+ try {
+ return typeof arg === 'string' ? (new RegExp('^(' + arg + ')$')).test(val) : null;
+ } catch (e) {}
+ },
+
+ integer: function(elem, arg, val) {
+ return (/^-?[0-9]+$/).test(val);
+ },
+
+ 'float': function(elem, arg, val, value) {
+ val = val.replace(' ', '').replace(',', '.');
+ if ((/^-?[0-9]*[.,]?[0-9]+$/).test(val)) {
+ value.value = val;
+ return true;
+ }
+ return false;
+ },
+
+ min: function(elem, arg, val) {
+ return Nette.validators.range(elem, [arg, null], val);
+ },
+
+ max: function(elem, arg, val) {
+ return Nette.validators.range(elem, [null, arg], val);
+ },
+
+ range: function(elem, arg, val) {
+ return Nette.isArray(arg) ?
+ ((arg[0] === null || parseFloat(val) >= arg[0]) && (arg[1] === null || parseFloat(val) <= arg[1])) : null;
+ },
+
+ submitted: function(elem, arg, val) {
+ return elem.form['nette-submittedBy'] === elem;
+ },
+
+ fileSize: function(elem, arg, val) {
+ if (window.FileList) {
+ for (var i = 0; i < val.length; i++) {
+ if (val[i].size > arg) {
+ return false;
+ }
+ }
+ }
+ return true;
+ },
+
+ image: function (elem, arg, val) {
+ if (window.FileList && val instanceof window.FileList) {
+ for (var i = 0; i < val.length; i++) {
+ var type = val[i].type;
+ if (type && type !== 'image/gif' && type !== 'image/png' && type !== 'image/jpeg') {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+};
+
+
+/**
+ * Process all toggles in form.
+ */
+Nette.toggleForm = function(form, elem) {
+ var i;
+ Nette.toggles = {};
+ for (i = 0; i < form.elements.length; i++) {
+ if (form.elements[i].tagName.toLowerCase() in {input: 1, select: 1, textarea: 1, button: 1}) {
+ Nette.toggleControl(form.elements[i], null, null, !elem);
+ }
+ }
+
+ for (i in Nette.toggles) {
+ Nette.toggle(i, Nette.toggles[i], elem);
+ }
+};
+
+
+/**
+ * Process toggles on form element.
+ */
+Nette.toggleControl = function(elem, rules, success, firsttime, value) {
+ rules = rules || Nette.parseJSON(elem.getAttribute('data-nette-rules'));
+ value = value === undefined ? {value: Nette.getEffectiveValue(elem)} : value;
+
+ var has = false,
+ handled = [],
+ handler = function () {
+ Nette.toggleForm(elem.form, elem);
+ },
+ curSuccess;
+
+ for (var id = 0, len = rules.length; id < len; id++) {
+ var rule = rules[id],
+ op = rule.op.match(/(~)?([^?]+)/),
+ curElem = rule.control ? elem.form.elements.namedItem(rule.control) : elem;
+
+ if (!curElem) {
+ continue;
+ }
+
+ curSuccess = success;
+ if (success !== false) {
+ rule.neg = op[1];
+ rule.op = op[2];
+ var curValue = elem === curElem ? value : {value: Nette.getEffectiveValue(curElem)};
+ curSuccess = Nette.validateRule(curElem, rule.op, rule.arg, curValue);
+ if (curSuccess === null) {
+ continue;
+
+ } else if (rule.neg) {
+ curSuccess = !curSuccess;
+ }
+ if (!rule.rules) {
+ success = curSuccess;
+ }
+ }
+
+ if ((rule.rules && Nette.toggleControl(elem, rule.rules, curSuccess, firsttime, value)) || rule.toggle) {
+ has = true;
+ if (firsttime) {
+ var oldIE = !document.addEventListener, // IE < 9
+ name = curElem.tagName ? curElem.name : curElem[0].name,
+ els = curElem.tagName ? curElem.form.elements : curElem;
+
+ for (var i = 0; i < els.length; i++) {
+ if (els[i].name === name && !Nette.inArray(handled, els[i])) {
+ Nette.addEvent(els[i], oldIE && els[i].type in {checkbox: 1, radio: 1} ? 'click' : 'change', handler);
+ handled.push(els[i]);
+ }
+ }
+ }
+ for (var id2 in rule.toggle || []) {
+ if (Object.prototype.hasOwnProperty.call(rule.toggle, id2)) {
+ Nette.toggles[id2] = Nette.toggles[id2] || (rule.toggle[id2] ? curSuccess : !curSuccess);
+ }
+ }
+ }
+ }
+ return has;
+};
+
+
+Nette.parseJSON = function(s) {
+ s = s || '[]';
+ if (s.substr(0, 3) === '{op') {
+ return eval('[' + s + ']'); // backward compatibility
+ }
+ return window.JSON && window.JSON.parse ? JSON.parse(s) : eval(s);
+};
+
+
+/**
+ * Displays or hides HTML element.
+ */
+Nette.toggle = function(id, visible, srcElement) {
+ var elem = document.getElementById(id);
+ if (elem) {
+ elem.style.display = visible ? '' : 'none';
+ }
+};
+
+
+/**
+ * Setup handlers.
+ */
+Nette.initForm = function(form) {
+ form.noValidate = 'novalidate';
+
+ Nette.addEvent(form, 'submit', function(e) {
+ if (!Nette.validateForm(form)) {
+ if (e && e.stopPropagation) {
+ e.stopPropagation();
+ } else if (window.event) {
+ event.cancelBubble = true;
+ }
+ return false;
+ }
+ });
+
+ Nette.addEvent(form, 'click', function(e) {
+ e = e || event;
+ var target = e.target || e.srcElement;
+ form['nette-submittedBy'] = (target.type in {submit: 1, image: 1}) ? target : null;
+ });
+
+ Nette.toggleForm(form);
+};
+
+
+/**
+ * @private
+ */
+Nette.initOnLoad = function() {
+ Nette.addEvent(window, 'load', function() {
+ for (var i = 0; i < document.forms.length; i++) {
+ var form = document.forms[i];
+ for (var j = 0; j < form.elements.length; j++) {
+ if (form.elements[j].getAttribute('data-nette-rules')) {
+ Nette.initForm(form);
+ break;
+ }
+ }
+ }
+ });
+};
+
+
+/**
+ * Determines whether the argument is an array.
+ */
+Nette.isArray = function(arg) {
+ return Object.prototype.toString.call(arg) === '[object Array]';
+};
+
+
+/**
+ * Search for a specified value within an array.
+ */
+Nette.inArray = function(arr, val) {
+ if ([].indexOf) {
+ return arr.indexOf(val) > -1;
+ } else {
+ for (var i = 0; i < arr.length; i++) {
+ if (arr[i] === val) {
+ return true;
+ }
+ }
+ return false;
+ }
+};
+
+
+/**
+ * Converts string to web safe characters [a-z0-9-] text.
+ */
+Nette.webalize = function(s) {
+ s = s.toLowerCase();
+ var res = '', i, ch;
+ for (i = 0; i < s.length; i++) {
+ ch = Nette.webalizeTable[s.charAt(i)];
+ res += ch ? ch : s.charAt(i);
+ }
+ return res.replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
+};
+
+Nette.webalizeTable = {\u00e1: 'a', \u00e4: 'a', \u010d: 'c', \u010f: 'd', \u00e9: 'e', \u011b: 'e', \u00ed: 'i', \u013e: 'l', \u0148: 'n', \u00f3: 'o', \u00f4: 'o', \u0159: 'r', \u0161: 's', \u0165: 't', \u00fa: 'u', \u016f: 'u', \u00fd: 'y', \u017e: 'z'};
+
+return Nette;
+}));
diff --git a/vendor/nette/http/composer.json b/vendor/nette/http/composer.json
new file mode 100755
index 0000000..b08431f
--- /dev/null
+++ b/vendor/nette/http/composer.json
@@ -0,0 +1,34 @@
+{
+ "name": "nette/http",
+ "description": "Nette HTTP Component",
+ "homepage": "http://nette.org",
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.1",
+ "nette/utils": "~2.2, >=2.2.2"
+ },
+ "require-dev": {
+ "nette/di": "~2.3",
+ "nette/tester": "~1.4"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "suggest": {
+ "ext-fileinfo": "to detect type of uploaded files"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/http/license.md b/vendor/nette/http/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/http/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/http/src/Bridges/HttpDI/HttpExtension.php b/vendor/nette/http/src/Bridges/HttpDI/HttpExtension.php
new file mode 100755
index 0000000..0b9ef40
--- /dev/null
+++ b/vendor/nette/http/src/Bridges/HttpDI/HttpExtension.php
@@ -0,0 +1,82 @@
+ array(),
+ 'headers' => array(
+ 'X-Powered-By' => 'Nette Framework',
+ 'Content-Type' => 'text/html; charset=utf-8',
+ ),
+ 'frames' => 'SAMEORIGIN', // X-Frame-Options
+ );
+
+
+ public function loadConfiguration()
+ {
+ $container = $this->getContainerBuilder();
+ $config = $this->validateConfig($this->defaults);
+
+ $container->addDefinition($this->prefix('requestFactory'))
+ ->setClass('Nette\Http\RequestFactory')
+ ->addSetup('setProxy', array($config['proxy']));
+
+ $container->addDefinition($this->prefix('request'))
+ ->setClass('Nette\Http\Request')
+ ->setFactory('@Nette\Http\RequestFactory::createHttpRequest');
+
+ $container->addDefinition($this->prefix('response'))
+ ->setClass('Nette\Http\Response');
+
+ $container->addDefinition($this->prefix('context'))
+ ->setClass('Nette\Http\Context');
+
+ if ($this->name === 'http') {
+ $container->addAlias('nette.httpRequestFactory', $this->prefix('requestFactory'));
+ $container->addAlias('nette.httpContext', $this->prefix('context'));
+ $container->addAlias('httpRequest', $this->prefix('request'));
+ $container->addAlias('httpResponse', $this->prefix('response'));
+ }
+ }
+
+
+ public function afterCompile(Nette\PhpGenerator\ClassType $class)
+ {
+ if (PHP_SAPI === 'cli') {
+ return;
+ }
+
+ $initialize = $class->getMethod('initialize');
+ $config = $this->getConfig();
+
+ if (isset($config['frames']) && $config['frames'] !== TRUE) {
+ $frames = $config['frames'];
+ if ($frames === FALSE) {
+ $frames = 'DENY';
+ } elseif (preg_match('#^https?:#', $frames)) {
+ $frames = "ALLOW-FROM $frames";
+ }
+ $initialize->addBody('header(?);', array("X-Frame-Options: $frames"));
+ }
+
+ foreach ($config['headers'] as $key => $value) {
+ if ($value != NULL) { // intentionally ==
+ $initialize->addBody('header(?);', array("$key: $value"));
+ }
+ }
+ }
+
+}
diff --git a/vendor/nette/http/src/Bridges/HttpDI/SessionExtension.php b/vendor/nette/http/src/Bridges/HttpDI/SessionExtension.php
new file mode 100755
index 0000000..5824de9
--- /dev/null
+++ b/vendor/nette/http/src/Bridges/HttpDI/SessionExtension.php
@@ -0,0 +1,82 @@
+ FALSE,
+ 'autoStart' => 'smart', // true|false|smart
+ 'expiration' => NULL,
+ );
+
+ /** @var bool */
+ private $debugMode;
+
+
+ public function __construct($debugMode = FALSE)
+ {
+ $this->debugMode = $debugMode;
+ }
+
+
+ public function loadConfiguration()
+ {
+ $container = $this->getContainerBuilder();
+ $config = $this->getConfig() + $this->defaults;
+ $this->setConfig($config);
+
+ $session = $container->addDefinition($this->prefix('session'))
+ ->setClass('Nette\Http\Session');
+
+ if ($config['expiration']) {
+ $session->addSetup('setExpiration', array($config['expiration']));
+ }
+
+ if ($this->debugMode && $config['debugger']) {
+ $session->addSetup('@Tracy\Bar::addPanel', array(
+ new Nette\DI\Statement('Nette\Bridges\HttpTracy\SessionPanel'),
+ ));
+ }
+
+ unset($config['expiration'], $config['autoStart'], $config['debugger']);
+ if (!empty($config)) {
+ $session->addSetup('setOptions', array($config));
+ }
+
+ if ($this->name === 'session') {
+ $container->addAlias('session', $this->prefix('session'));
+ }
+ }
+
+
+ public function afterCompile(Nette\PhpGenerator\ClassType $class)
+ {
+ if (PHP_SAPI === 'cli') {
+ return;
+ }
+
+ $initialize = $class->getMethod('initialize');
+ $config = $this->getConfig();
+ $name = $this->prefix('session');
+
+ if ($config['autoStart'] === 'smart') {
+ $initialize->addBody('$this->getService(?)->exists() && $this->getService(?)->start();', array($name, $name));
+
+ } elseif ($config['autoStart']) {
+ $initialize->addBody('$this->getService(?)->start();', array($name));
+ }
+ }
+
+}
diff --git a/vendor/nette/http/src/Bridges/HttpTracy/SessionPanel.php b/vendor/nette/http/src/Bridges/HttpTracy/SessionPanel.php
new file mode 100755
index 0000000..b0c3f6a
--- /dev/null
+++ b/vendor/nette/http/src/Bridges/HttpTracy/SessionPanel.php
@@ -0,0 +1,43 @@
+
+
+
+
+
Session # (Lifetime: )
+
+
+
+
empty
+
+
+ $v) {
+ if ($k === '__NF') {
+ $k = 'Nette Session'; $v = isset($v['DATA']) ? $v['DATA'] : NULL;
+ }
+ echo '', htmlspecialchars($k, ENT_IGNORE, 'UTF-8'), ' ', Dumper::toHtml($v, array(Dumper::LIVE => TRUE)), " \n";
+ }?>
+
+
+
+
diff --git a/vendor/nette/http/src/Bridges/HttpTracy/templates/SessionPanel.tab.phtml b/vendor/nette/http/src/Bridges/HttpTracy/templates/SessionPanel.tab.phtml
new file mode 100755
index 0000000..de842de
--- /dev/null
+++ b/vendor/nette/http/src/Bridges/HttpTracy/templates/SessionPanel.tab.phtml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/vendor/nette/http/src/Http/Context.php b/vendor/nette/http/src/Http/Context.php
new file mode 100755
index 0000000..994d06f
--- /dev/null
+++ b/vendor/nette/http/src/Http/Context.php
@@ -0,0 +1,103 @@
+request = $request;
+ $this->response = $response;
+ }
+
+
+ /**
+ * Attempts to cache the sent entity by its last modification date.
+ * @param string|int|\DateTime last modified time
+ * @param string strong entity tag validator
+ * @return bool
+ */
+ public function isModified($lastModified = NULL, $etag = NULL)
+ {
+ if ($lastModified) {
+ $this->response->setHeader('Last-Modified', Helpers::formatDate($lastModified));
+ }
+ if ($etag) {
+ $this->response->setHeader('ETag', '"' . addslashes($etag) . '"');
+ }
+
+ $ifNoneMatch = $this->request->getHeader('If-None-Match');
+ if ($ifNoneMatch === '*') {
+ $match = TRUE; // match, check if-modified-since
+
+ } elseif ($ifNoneMatch !== NULL) {
+ $etag = $this->response->getHeader('ETag');
+
+ if ($etag == NULL || strpos(' ' . strtr($ifNoneMatch, ",\t", ' '), ' ' . $etag) === FALSE) {
+ return TRUE;
+
+ } else {
+ $match = TRUE; // match, check if-modified-since
+ }
+ }
+
+ $ifModifiedSince = $this->request->getHeader('If-Modified-Since');
+ if ($ifModifiedSince !== NULL) {
+ $lastModified = $this->response->getHeader('Last-Modified');
+ if ($lastModified != NULL && strtotime($lastModified) <= strtotime($ifModifiedSince)) {
+ $match = TRUE;
+
+ } else {
+ return TRUE;
+ }
+ }
+
+ if (empty($match)) {
+ return TRUE;
+ }
+
+ $this->response->setCode(IResponse::S304_NOT_MODIFIED);
+ return FALSE;
+ }
+
+
+ /**
+ * @return IRequest
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+
+ /**
+ * @return IResponse
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+}
diff --git a/vendor/nette/http/src/Http/FileUpload.php b/vendor/nette/http/src/Http/FileUpload.php
new file mode 100755
index 0000000..e681b63
--- /dev/null
+++ b/vendor/nette/http/src/Http/FileUpload.php
@@ -0,0 +1,202 @@
+error = UPLOAD_ERR_NO_FILE;
+ return; // or throw exception?
+ }
+ }
+ $this->name = $value['name'];
+ $this->size = $value['size'];
+ $this->tmpName = $value['tmp_name'];
+ $this->error = $value['error'];
+ }
+
+
+ /**
+ * Returns the file name.
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+
+ /**
+ * Returns the sanitized file name.
+ * @return string
+ */
+ public function getSanitizedName()
+ {
+ return trim(Nette\Utils\Strings::webalize($this->name, '.', FALSE), '.-');
+ }
+
+
+ /**
+ * Returns the MIME content type of an uploaded file.
+ * @return string|NULL
+ */
+ public function getContentType()
+ {
+ if ($this->isOk() && $this->type === NULL) {
+ $this->type = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $this->tmpName);
+ }
+ return $this->type;
+ }
+
+
+ /**
+ * Returns the size of an uploaded file.
+ * @return int
+ */
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+
+ /**
+ * Returns the path to an uploaded file.
+ * @return string
+ */
+ public function getTemporaryFile()
+ {
+ return $this->tmpName;
+ }
+
+
+ /**
+ * Returns the path to an uploaded file.
+ * @return string
+ */
+ public function __toString()
+ {
+ return (string) $this->tmpName;
+ }
+
+
+ /**
+ * Returns the error code. {@link http://php.net/manual/en/features.file-upload.errors.php}
+ * @return int
+ */
+ public function getError()
+ {
+ return $this->error;
+ }
+
+
+ /**
+ * Is there any error?
+ * @return bool
+ */
+ public function isOk()
+ {
+ return $this->error === UPLOAD_ERR_OK;
+ }
+
+
+ /**
+ * Move uploaded file to new location.
+ * @param string
+ * @return self
+ */
+ public function move($dest)
+ {
+ @mkdir(dirname($dest), 0777, TRUE); // @ - dir may already exist
+ @unlink($dest); // @ - file may not exists
+ if (!call_user_func(is_uploaded_file($this->tmpName) ? 'move_uploaded_file' : 'rename', $this->tmpName, $dest)) {
+ throw new Nette\InvalidStateException("Unable to move uploaded file '$this->tmpName' to '$dest'.");
+ }
+ chmod($dest, 0666);
+ $this->tmpName = $dest;
+ return $this;
+ }
+
+
+ /**
+ * Is uploaded file GIF, PNG or JPEG?
+ * @return bool
+ */
+ public function isImage()
+ {
+ return in_array($this->getContentType(), array('image/gif', 'image/png', 'image/jpeg'), TRUE);
+ }
+
+
+ /**
+ * Returns the image.
+ * @return Nette\Utils\Image
+ * @throws Nette\Utils\ImageException
+ */
+ public function toImage()
+ {
+ return Nette\Utils\Image::fromFile($this->tmpName);
+ }
+
+
+ /**
+ * Returns the dimensions of an uploaded image as array.
+ * @return array|NULL
+ */
+ public function getImageSize()
+ {
+ return $this->isOk() ? @getimagesize($this->tmpName) : NULL; // @ - files smaller than 12 bytes causes read error
+ }
+
+
+ /**
+ * Get file contents.
+ * @return string|NULL
+ */
+ public function getContents()
+ {
+ // future implementation can try to work around safe_mode and open_basedir limitations
+ return $this->isOk() ? file_get_contents($this->tmpName) : NULL;
+ }
+
+}
diff --git a/vendor/nette/http/src/Http/Helpers.php b/vendor/nette/http/src/Http/Helpers.php
new file mode 100755
index 0000000..30fa388
--- /dev/null
+++ b/vendor/nette/http/src/Http/Helpers.php
@@ -0,0 +1,89 @@
+setTimezone(new \DateTimeZone('GMT'));
+ return $time->format('D, d M Y H:i:s \G\M\T');
+ }
+
+
+ /**
+ * Is IP address in CIDR block?
+ * @return bool
+ */
+ public static function ipMatch($ip, $mask)
+ {
+ list($mask, $size) = explode('/', $mask . '/');
+ $tmp = function ($n) { return sprintf('%032b', $n); };
+ $ip = implode('', array_map($tmp, unpack('N*', inet_pton($ip))));
+ $mask = implode('', array_map($tmp, unpack('N*', inet_pton($mask))));
+ $max = strlen($ip);
+ if (!$max || $max !== strlen($mask) || $size < 0 || $size > $max) {
+ return FALSE;
+ }
+ return strncmp($ip, $mask, $size === '' ? $max : $size) === 0;
+ }
+
+
+ /**
+ * Removes duplicate cookies from response.
+ * @return void
+ * @internal
+ */
+ public static function removeDuplicateCookies()
+ {
+ if (headers_sent($file, $line) || ini_get('suhosin.cookie.encrypt')) {
+ return;
+ }
+
+ $flatten = array();
+ foreach (headers_list() as $header) {
+ if (preg_match('#^Set-Cookie: .+?=#', $header, $m)) {
+ $flatten[$m[0]] = $header;
+ header_remove('Set-Cookie');
+ }
+ }
+ foreach (array_values($flatten) as $key => $header) {
+ header($header, $key === 0);
+ }
+ }
+
+
+ /**
+ * @internal
+ */
+ public static function stripSlashes($arr, $onlyKeys = FALSE)
+ {
+ $res = array();
+ foreach ($arr as $k => $v) {
+ $res[stripslashes($k)] = is_array($v)
+ ? self::stripSlashes($v, $onlyKeys)
+ : ($onlyKeys ? $v : stripslashes($v));
+ }
+ return $res;
+ }
+
+}
diff --git a/vendor/nette/http/src/Http/IRequest.php b/vendor/nette/http/src/Http/IRequest.php
new file mode 100755
index 0000000..412fee1
--- /dev/null
+++ b/vendor/nette/http/src/Http/IRequest.php
@@ -0,0 +1,137 @@
+ value)
+ */
+ function getHeaders();
+
+ /**
+ * Sends a cookie.
+ * @param string name of the cookie
+ * @param string value
+ * @param mixed expiration as unix timestamp or number of seconds; Value 0 means "until the browser is closed"
+ * @param string
+ * @param string
+ * @param bool
+ * @param bool
+ * @return void
+ */
+ function setCookie($name, $value, $expire, $path = NULL, $domain = NULL, $secure = NULL, $httpOnly = NULL);
+
+ /**
+ * Deletes a cookie.
+ * @param string name of the cookie.
+ * @param string
+ * @param string
+ * @param bool
+ * @return void
+ */
+ function deleteCookie($name, $path = NULL, $domain = NULL, $secure = NULL);
+
+}
diff --git a/vendor/nette/http/src/Http/ISessionStorage.php b/vendor/nette/http/src/Http/ISessionStorage.php
new file mode 100755
index 0000000..7f6d4ed
--- /dev/null
+++ b/vendor/nette/http/src/Http/ISessionStorage.php
@@ -0,0 +1,31 @@
+url = $url;
+ if ($query !== NULL) {
+ trigger_error('Nette\Http\Request::__construct(): parameter $query is deprecated.', E_USER_DEPRECATED);
+ $url->setQuery($query);
+ }
+ $this->post = (array) $post;
+ $this->files = (array) $files;
+ $this->cookies = (array) $cookies;
+ $this->headers = array_change_key_case((array) $headers, CASE_LOWER);
+ $this->method = $method ?: 'GET';
+ $this->remoteAddress = $remoteAddress;
+ $this->remoteHost = $remoteHost;
+ $this->rawBodyCallback = $rawBodyCallback;
+ }
+
+
+ /**
+ * Returns URL object.
+ * @return UrlScript
+ */
+ public function getUrl()
+ {
+ return clone $this->url;
+ }
+
+
+ /********************* query, post, files & cookies ****************d*g**/
+
+
+ /**
+ * Returns variable provided to the script via URL query ($_GET).
+ * If no key is passed, returns the entire array.
+ * @param string key
+ * @param mixed default value
+ * @return mixed
+ */
+ public function getQuery($key = NULL, $default = NULL)
+ {
+ if (func_num_args() === 0) {
+ return $this->url->getQueryParameters();
+ } else {
+ return $this->url->getQueryParameter($key, $default);
+ }
+ }
+
+
+ /**
+ * Returns variable provided to the script via POST method ($_POST).
+ * If no key is passed, returns the entire array.
+ * @param string key
+ * @param mixed default value
+ * @return mixed
+ */
+ public function getPost($key = NULL, $default = NULL)
+ {
+ if (func_num_args() === 0) {
+ return $this->post;
+
+ } elseif (isset($this->post[$key])) {
+ return $this->post[$key];
+
+ } else {
+ return $default;
+ }
+ }
+
+
+ /**
+ * Returns uploaded file.
+ * @param string key
+ * @return FileUpload|NULL
+ */
+ public function getFile($key)
+ {
+ if (func_num_args() > 1) {
+ trigger_error('Calling getFile() with multiple keys is deprecated.', E_USER_DEPRECATED);
+ return Nette\Utils\Arrays::get($this->files, func_get_args(), NULL);
+ }
+
+ return isset($this->files[$key]) ? $this->files[$key] : NULL;
+ }
+
+
+ /**
+ * Returns uploaded files.
+ * @return array
+ */
+ public function getFiles()
+ {
+ return $this->files;
+ }
+
+
+ /**
+ * Returns variable provided to the script via HTTP cookies.
+ * @param string key
+ * @param mixed default value
+ * @return mixed
+ */
+ public function getCookie($key, $default = NULL)
+ {
+ return isset($this->cookies[$key]) ? $this->cookies[$key] : $default;
+ }
+
+
+ /**
+ * Returns variables provided to the script via HTTP cookies.
+ * @return array
+ */
+ public function getCookies()
+ {
+ return $this->cookies;
+ }
+
+
+ /********************* method & headers ****************d*g**/
+
+
+ /**
+ * Returns HTTP request method (GET, POST, HEAD, PUT, ...). The method is case-sensitive.
+ * @return string
+ */
+ public function getMethod()
+ {
+ return $this->method;
+ }
+
+
+ /**
+ * Checks if the request method is the given one.
+ * @param string
+ * @return bool
+ */
+ public function isMethod($method)
+ {
+ return strcasecmp($this->method, $method) === 0;
+ }
+
+
+ /**
+ * @deprecated
+ */
+ public function isPost()
+ {
+ return $this->isMethod('POST');
+ }
+
+
+ /**
+ * Return the value of the HTTP header. Pass the header name as the
+ * plain, HTTP-specified header name (e.g. 'Accept-Encoding').
+ * @param string
+ * @param mixed
+ * @return mixed
+ */
+ public function getHeader($header, $default = NULL)
+ {
+ $header = strtolower($header);
+ return isset($this->headers[$header]) ? $this->headers[$header] : $default;
+ }
+
+
+ /**
+ * Returns all HTTP headers.
+ * @return array
+ */
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+
+
+ /**
+ * Returns referrer.
+ * @return Url|NULL
+ */
+ public function getReferer()
+ {
+ return isset($this->headers['referer']) ? new Url($this->headers['referer']) : NULL;
+ }
+
+
+ /**
+ * Is the request is sent via secure channel (https).
+ * @return bool
+ */
+ public function isSecured()
+ {
+ return $this->url->getScheme() === 'https';
+ }
+
+
+ /**
+ * Is AJAX request?
+ * @return bool
+ */
+ public function isAjax()
+ {
+ return $this->getHeader('X-Requested-With') === 'XMLHttpRequest';
+ }
+
+
+ /**
+ * Returns the IP address of the remote client.
+ * @return string|NULL
+ */
+ public function getRemoteAddress()
+ {
+ return $this->remoteAddress;
+ }
+
+
+ /**
+ * Returns the host of the remote client.
+ * @return string|NULL
+ */
+ public function getRemoteHost()
+ {
+ if ($this->remoteHost === NULL && $this->remoteAddress !== NULL) {
+ $this->remoteHost = getHostByAddr($this->remoteAddress);
+ }
+ return $this->remoteHost;
+ }
+
+
+ /**
+ * Returns raw content of HTTP request body.
+ * @return string|NULL
+ */
+ public function getRawBody()
+ {
+ return $this->rawBodyCallback ? call_user_func($this->rawBodyCallback) : NULL;
+ }
+
+
+ /**
+ * Parse Accept-Language header and returns preferred language.
+ * @param string[] supported languages
+ * @return string|NULL
+ */
+ public function detectLanguage(array $langs)
+ {
+ $header = $this->getHeader('Accept-Language');
+ if (!$header) {
+ return NULL;
+ }
+
+ $s = strtolower($header); // case insensitive
+ $s = strtr($s, '_', '-'); // cs_CZ means cs-CZ
+ rsort($langs); // first more specific
+ preg_match_all('#(' . implode('|', $langs) . ')(?:-[^\s,;=]+)?\s*(?:;\s*q=([0-9.]+))?#', $s, $matches);
+
+ if (!$matches[0]) {
+ return NULL;
+ }
+
+ $max = 0;
+ $lang = NULL;
+ foreach ($matches[1] as $key => $value) {
+ $q = $matches[2][$key] === '' ? 1.0 : (float) $matches[2][$key];
+ if ($q > $max) {
+ $max = $q;
+ $lang = $value;
+ }
+ }
+
+ return $lang;
+ }
+
+}
diff --git a/vendor/nette/http/src/Http/RequestFactory.php b/vendor/nette/http/src/Http/RequestFactory.php
new file mode 100755
index 0000000..b7c80d1
--- /dev/null
+++ b/vendor/nette/http/src/Http/RequestFactory.php
@@ -0,0 +1,238 @@
+ array('#/{2,}#' => '/'), // '%20' => ''
+ 'url' => array(), // '#[.,)]\z#' => ''
+ );
+
+ /** @var bool */
+ private $binary = FALSE;
+
+ /** @var array */
+ private $proxies = array();
+
+
+ /**
+ * @param bool
+ * @return self
+ */
+ public function setBinary($binary = TRUE)
+ {
+ $this->binary = (bool) $binary;
+ return $this;
+ }
+
+
+ /**
+ * @param array|string
+ * @return self
+ */
+ public function setProxy($proxy)
+ {
+ $this->proxies = (array) $proxy;
+ return $this;
+ }
+
+
+ /**
+ * Creates current HttpRequest object.
+ * @return Request
+ */
+ public function createHttpRequest()
+ {
+ // DETECTS URI, base path and script path of the request.
+ $url = new UrlScript;
+ $url->setScheme(!empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'off') ? 'https' : 'http');
+ $url->setUser(isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '');
+ $url->setPassword(isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '');
+
+ // host & port
+ if ((isset($_SERVER[$tmp = 'HTTP_HOST']) || isset($_SERVER[$tmp = 'SERVER_NAME']))
+ && preg_match('#^([a-z0-9_.-]+|\[[a-f0-9:]+\])(:\d+)?\z#i', $_SERVER[$tmp], $pair)
+ ) {
+ $url->setHost(strtolower($pair[1]));
+ if (isset($pair[2])) {
+ $url->setPort(substr($pair[2], 1));
+ } elseif (isset($_SERVER['SERVER_PORT'])) {
+ $url->setPort($_SERVER['SERVER_PORT']);
+ }
+ }
+
+ // path & query
+ $requestUrl = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '/';
+ $requestUrl = Strings::replace($requestUrl, $this->urlFilters['url']);
+ $tmp = explode('?', $requestUrl, 2);
+ $path = Url::unescape($tmp[0], '%/?#');
+ $path = Strings::fixEncoding(Strings::replace($path, $this->urlFilters['path']));
+ $url->setPath($path);
+ $url->setQuery(isset($tmp[1]) ? $tmp[1] : '');
+
+ // detect script path
+ $lpath = strtolower($path);
+ $script = isset($_SERVER['SCRIPT_NAME']) ? strtolower($_SERVER['SCRIPT_NAME']) : '';
+ if ($lpath !== $script) {
+ $max = min(strlen($lpath), strlen($script));
+ for ($i = 0; $i < $max && $lpath[$i] === $script[$i]; $i++);
+ $path = $i ? substr($path, 0, strrpos($path, '/', $i - strlen($path) - 1) + 1) : '/';
+ }
+ $url->setScriptPath($path);
+
+ // GET, POST, COOKIE
+ $useFilter = (!in_array(ini_get('filter.default'), array('', 'unsafe_raw')) || ini_get('filter.default_flags'));
+
+ $query = $url->getQueryParameters();
+ $post = $useFilter ? filter_input_array(INPUT_POST, FILTER_UNSAFE_RAW) : (empty($_POST) ? array() : $_POST);
+ $cookies = $useFilter ? filter_input_array(INPUT_COOKIE, FILTER_UNSAFE_RAW) : (empty($_COOKIE) ? array() : $_COOKIE);
+
+ if (get_magic_quotes_gpc()) {
+ $post = Helpers::stripslashes($post, $useFilter);
+ $cookies = Helpers::stripslashes($cookies, $useFilter);
+ }
+
+ // remove invalid characters
+ $reChars = '#^[' . self::CHARS . ']*+\z#u';
+ if (!$this->binary) {
+ $list = array(& $query, & $post, & $cookies);
+ while (list($key, $val) = each($list)) {
+ foreach ($val as $k => $v) {
+ if (is_string($k) && (!preg_match($reChars, $k) || preg_last_error())) {
+ unset($list[$key][$k]);
+
+ } elseif (is_array($v)) {
+ $list[$key][$k] = $v;
+ $list[] = & $list[$key][$k];
+
+ } else {
+ $list[$key][$k] = (string) preg_replace('#[^' . self::CHARS . ']+#u', '', $v);
+ }
+ }
+ }
+ unset($list, $key, $val, $k, $v);
+ }
+ $url->setQuery($query);
+
+
+ // FILES and create FileUpload objects
+ $files = array();
+ $list = array();
+ if (!empty($_FILES)) {
+ foreach ($_FILES as $k => $v) {
+ if (!$this->binary && is_string($k) && (!preg_match($reChars, $k) || preg_last_error())) {
+ continue;
+ }
+ $v['@'] = & $files[$k];
+ $list[] = $v;
+ }
+ }
+
+ while (list(, $v) = each($list)) {
+ if (!isset($v['name'])) {
+ continue;
+
+ } elseif (!is_array($v['name'])) {
+ if (get_magic_quotes_gpc()) {
+ $v['name'] = stripSlashes($v['name']);
+ }
+ if (!$this->binary && (!preg_match($reChars, $v['name']) || preg_last_error())) {
+ $v['name'] = '';
+ }
+ if ($v['error'] !== UPLOAD_ERR_NO_FILE) {
+ $v['@'] = new FileUpload($v);
+ }
+ continue;
+ }
+
+ foreach ($v['name'] as $k => $foo) {
+ if (!$this->binary && is_string($k) && (!preg_match($reChars, $k) || preg_last_error())) {
+ continue;
+ }
+ $list[] = array(
+ 'name' => $v['name'][$k],
+ 'type' => $v['type'][$k],
+ 'size' => $v['size'][$k],
+ 'tmp_name' => $v['tmp_name'][$k],
+ 'error' => $v['error'][$k],
+ '@' => & $v['@'][$k],
+ );
+ }
+ }
+
+
+ // HEADERS
+ if (function_exists('apache_request_headers')) {
+ $headers = apache_request_headers();
+ } else {
+ $headers = array();
+ foreach ($_SERVER as $k => $v) {
+ if (strncmp($k, 'HTTP_', 5) == 0) {
+ $k = substr($k, 5);
+ } elseif (strncmp($k, 'CONTENT_', 8)) {
+ continue;
+ }
+ $headers[ strtr($k, '_', '-') ] = $v;
+ }
+ }
+
+
+ $remoteAddr = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : NULL;
+ $remoteHost = isset($_SERVER['REMOTE_HOST']) ? $_SERVER['REMOTE_HOST'] : NULL;
+
+ // proxy
+ foreach ($this->proxies as $proxy) {
+ if (Helpers::ipMatch($remoteAddr, $proxy)) {
+ if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
+ $remoteAddr = trim(current(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])));
+ }
+ if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
+ $remoteHost = trim(current(explode(',', $_SERVER['HTTP_X_FORWARDED_HOST'])));
+ }
+ break;
+ }
+ }
+
+
+ $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : NULL;
+ if ($method === 'POST' && isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])
+ && preg_match('#^[A-Z]+\z#', $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])
+ ) {
+ $method = $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'];
+ }
+
+ // raw body
+ $rawBodyCallback = function () {
+ static $rawBody;
+
+ if (PHP_VERSION_ID >= 50600) {
+ return file_get_contents('php://input');
+
+ } elseif ($rawBody === NULL) { // can be read only once in PHP < 5.6
+ $rawBody = (string) file_get_contents('php://input');
+ }
+
+ return $rawBody;
+ };
+
+ return new Request($url, NULL, $post, $files, $cookies, $headers, $method, $remoteAddr, $remoteHost, $rawBodyCallback);
+ }
+
+}
diff --git a/vendor/nette/http/src/Http/Response.php b/vendor/nette/http/src/Http/Response.php
new file mode 100755
index 0000000..684c218
--- /dev/null
+++ b/vendor/nette/http/src/Http/Response.php
@@ -0,0 +1,309 @@
+= 50400) {
+ if (is_int($code = http_response_code())) {
+ $this->code = $code;
+ }
+ }
+
+ if (PHP_VERSION_ID >= 50401) { // PHP bug #61106
+ $rm = new \ReflectionMethod('Nette\Http\Helpers::removeDuplicateCookies');
+ header_register_callback($rm->getClosure()); // requires closure due PHP bug #66375
+ }
+ }
+
+
+ /**
+ * Sets HTTP response code.
+ * @param int
+ * @return self
+ * @throws Nette\InvalidArgumentException if code is invalid
+ * @throws Nette\InvalidStateException if HTTP headers have been sent
+ */
+ public function setCode($code)
+ {
+ $code = (int) $code;
+ if ($code < 100 || $code > 599) {
+ throw new Nette\InvalidArgumentException("Bad HTTP response '$code'.");
+ }
+ self::checkHeaders();
+ $this->code = $code;
+ $protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
+ header($protocol . ' ' . $code, TRUE, $code);
+ return $this;
+ }
+
+
+ /**
+ * Returns HTTP response code.
+ * @return int
+ */
+ public function getCode()
+ {
+ return $this->code;
+ }
+
+
+ /**
+ * Sends a HTTP header and replaces a previous one.
+ * @param string header name
+ * @param string header value
+ * @return self
+ * @throws Nette\InvalidStateException if HTTP headers have been sent
+ */
+ public function setHeader($name, $value)
+ {
+ self::checkHeaders();
+ if ($value === NULL) {
+ header_remove($name);
+ } elseif (strcasecmp($name, 'Content-Length') === 0 && ini_get('zlib.output_compression')) {
+ // ignore, PHP bug #44164
+ } else {
+ header($name . ': ' . $value, TRUE, $this->code);
+ }
+ return $this;
+ }
+
+
+ /**
+ * Adds HTTP header.
+ * @param string header name
+ * @param string header value
+ * @return self
+ * @throws Nette\InvalidStateException if HTTP headers have been sent
+ */
+ public function addHeader($name, $value)
+ {
+ self::checkHeaders();
+ header($name . ': ' . $value, FALSE, $this->code);
+ return $this;
+ }
+
+
+ /**
+ * Sends a Content-type HTTP header.
+ * @param string mime-type
+ * @param string charset
+ * @return self
+ * @throws Nette\InvalidStateException if HTTP headers have been sent
+ */
+ public function setContentType($type, $charset = NULL)
+ {
+ $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
+ return $this;
+ }
+
+
+ /**
+ * Redirects to a new URL. Note: call exit() after it.
+ * @param string URL
+ * @param int HTTP code
+ * @return void
+ * @throws Nette\InvalidStateException if HTTP headers have been sent
+ */
+ public function redirect($url, $code = self::S302_FOUND)
+ {
+ $this->setCode($code);
+ $this->setHeader('Location', $url);
+ if (preg_match('#^https?:|^\s*+[a-z0-9+.-]*+[^:]#i', $url)) {
+ $escapedUrl = htmlSpecialChars($url, ENT_IGNORE | ENT_QUOTES, 'UTF-8');
+ echo "Redirect \n\nPlease click here to continue .
";
+ }
+ }
+
+
+ /**
+ * Sets the number of seconds before a page cached on a browser expires.
+ * @param string|int|\DateTime time, value 0 means "until the browser is closed"
+ * @return self
+ * @throws Nette\InvalidStateException if HTTP headers have been sent
+ */
+ public function setExpiration($time)
+ {
+ if (!$time) { // no cache
+ $this->setHeader('Cache-Control', 's-maxage=0, max-age=0, must-revalidate');
+ $this->setHeader('Expires', 'Mon, 23 Jan 1978 10:00:00 GMT');
+ return $this;
+ }
+
+ $time = DateTime::from($time);
+ $this->setHeader('Cache-Control', 'max-age=' . ($time->format('U') - time()));
+ $this->setHeader('Expires', Helpers::formatDate($time));
+ return $this;
+ }
+
+
+ /**
+ * Checks if headers have been sent.
+ * @return bool
+ */
+ public function isSent()
+ {
+ return headers_sent();
+ }
+
+
+ /**
+ * Returns value of an HTTP header.
+ * @param string
+ * @param mixed
+ * @return mixed
+ */
+ public function getHeader($header, $default = NULL)
+ {
+ $header .= ':';
+ $len = strlen($header);
+ foreach (headers_list() as $item) {
+ if (strncasecmp($item, $header, $len) === 0) {
+ return ltrim(substr($item, $len));
+ }
+ }
+ return $default;
+ }
+
+
+ /**
+ * Returns a list of headers to sent.
+ * @return array (name => value)
+ */
+ public function getHeaders()
+ {
+ $headers = array();
+ foreach (headers_list() as $header) {
+ $a = strpos($header, ':');
+ $headers[substr($header, 0, $a)] = (string) substr($header, $a + 2);
+ }
+ return $headers;
+ }
+
+
+ /**
+ * @deprecated
+ */
+ public static function date($time = NULL)
+ {
+ return Helpers::formatDate($time);
+ }
+
+
+ /**
+ * @return void
+ */
+ public function __destruct()
+ {
+ if (self::$fixIE && isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE ') !== FALSE
+ && in_array($this->code, array(400, 403, 404, 405, 406, 408, 409, 410, 500, 501, 505), TRUE)
+ && preg_match('#^text/html(?:;|$)#', $this->getHeader('Content-Type', 'text/html'))
+ ) {
+ echo Nette\Utils\Random::generate(2e3, " \t\r\n"); // sends invisible garbage for IE
+ self::$fixIE = FALSE;
+ }
+ }
+
+
+ /**
+ * Sends a cookie.
+ * @param string name of the cookie
+ * @param string value
+ * @param string|int|\DateTime expiration time, value 0 means "until the browser is closed"
+ * @param string
+ * @param string
+ * @param bool
+ * @param bool
+ * @return self
+ * @throws Nette\InvalidStateException if HTTP headers have been sent
+ */
+ public function setCookie($name, $value, $time, $path = NULL, $domain = NULL, $secure = NULL, $httpOnly = NULL)
+ {
+ self::checkHeaders();
+ setcookie(
+ $name,
+ $value,
+ $time ? DateTime::from($time)->format('U') : 0,
+ $path === NULL ? $this->cookiePath : (string) $path,
+ $domain === NULL ? $this->cookieDomain : (string) $domain,
+ $secure === NULL ? $this->cookieSecure : (bool) $secure,
+ $httpOnly === NULL ? $this->cookieHttpOnly : (bool) $httpOnly
+ );
+ Helpers::removeDuplicateCookies();
+ return $this;
+ }
+
+
+ /**
+ * Deletes a cookie.
+ * @param string name of the cookie.
+ * @param string
+ * @param string
+ * @param bool
+ * @return void
+ * @throws Nette\InvalidStateException if HTTP headers have been sent
+ */
+ public function deleteCookie($name, $path = NULL, $domain = NULL, $secure = NULL)
+ {
+ $this->setCookie($name, FALSE, 0, $path, $domain, $secure);
+ }
+
+
+ /** @internal @deprecated */
+ public function removeDuplicateCookies()
+ {
+ trigger_error('Use Nette\Http\Helpers::removeDuplicateCookies()', E_USER_WARNING);
+ }
+
+
+ private function checkHeaders()
+ {
+ if (headers_sent($file, $line)) {
+ throw new Nette\InvalidStateException('Cannot send header after HTTP headers have been sent' . ($file ? " (output started at $file:$line)." : '.'));
+
+ } elseif ($this->warnOnBuffer && ob_get_length() && !array_filter(ob_get_status(TRUE), function ($i) { return !$i['chunk_size']; })) {
+ trigger_error('Possible problem: you are sending a HTTP header while already having some data in output buffer. Try Tracy\OutputDebugger or start session earlier.', E_USER_NOTICE);
+ }
+ }
+
+}
diff --git a/vendor/nette/http/src/Http/Session.php b/vendor/nette/http/src/Http/Session.php
new file mode 100755
index 0000000..a5d2504
--- /dev/null
+++ b/vendor/nette/http/src/Http/Session.php
@@ -0,0 +1,564 @@
+ '', // must be disabled because PHP implementation is invalid
+ 'use_cookies' => 1, // must be enabled to prevent Session Hijacking and Fixation
+ 'use_only_cookies' => 1, // must be enabled to prevent Session Fixation
+ 'use_trans_sid' => 0, // must be disabled to prevent Session Hijacking and Fixation
+
+ // cookies
+ 'cookie_lifetime' => 0, // until the browser is closed
+ 'cookie_path' => '/', // cookie is available within the entire domain
+ 'cookie_domain' => '', // cookie is available on current subdomain only
+ 'cookie_secure' => FALSE, // cookie is available on HTTP & HTTPS
+ 'cookie_httponly' => TRUE,// must be enabled to prevent Session Hijacking
+
+ // other
+ 'gc_maxlifetime' => self::DEFAULT_FILE_LIFETIME,// 3 hours
+ 'cache_limiter' => NULL, // (default "nocache", special value "\0")
+ 'cache_expire' => NULL, // (default "180")
+ 'hash_function' => NULL, // (default "0", means MD5)
+ 'hash_bits_per_character' => NULL, // (default "4")
+ );
+
+ /** @var IRequest */
+ private $request;
+
+ /** @var IResponse */
+ private $response;
+
+ /** @var \SessionHandlerInterface */
+ private $handler;
+
+
+ public function __construct(IRequest $request, IResponse $response)
+ {
+ $this->request = $request;
+ $this->response = $response;
+ }
+
+
+ /**
+ * Starts and initializes session data.
+ * @throws Nette\InvalidStateException
+ * @return void
+ */
+ public function start()
+ {
+ if (self::$started) {
+ return;
+ }
+
+ $this->configure($this->options);
+
+ $id = $this->request->getCookie(session_name());
+ if (is_string($id) && preg_match('#^[0-9a-zA-Z,-]{22,128}\z#i', $id)) {
+ session_id($id);
+ } else {
+ unset($_COOKIE[session_name()]);
+ }
+
+ try {
+ // session_start returns FALSE on failure only sometimes
+ Nette\Utils\Callback::invokeSafe('session_start', array(), function ($message) use (& $e) {
+ $e = new Nette\InvalidStateException($message);
+ });
+ } catch (\Exception $e) {
+ }
+
+ Helpers::removeDuplicateCookies();
+ if ($e) {
+ @session_write_close(); // this is needed
+ throw $e;
+ }
+
+ self::$started = TRUE;
+
+ /* structure:
+ __NF: BrowserKey, Data, Meta, Time
+ DATA: section->variable = data
+ META: section->variable = Timestamp, Browser
+ */
+ $nf = & $_SESSION['__NF'];
+
+ // regenerate empty session
+ if (empty($nf['Time'])) {
+ $nf['Time'] = time();
+ $this->regenerated = TRUE;
+ }
+
+ // browser closing detection
+ $browserKey = $this->request->getCookie('nette-browser');
+ if (!is_string($browserKey) || !preg_match('#^[0-9a-z]{10}\z#', $browserKey)) {
+ $browserKey = Nette\Utils\Random::generate();
+ }
+ $browserClosed = !isset($nf['B']) || $nf['B'] !== $browserKey;
+ $nf['B'] = $browserKey;
+
+ // resend cookie
+ $this->sendCookie();
+
+ // process meta metadata
+ if (isset($nf['META'])) {
+ $now = time();
+ // expire section variables
+ foreach ($nf['META'] as $section => $metadata) {
+ if (is_array($metadata)) {
+ foreach ($metadata as $variable => $value) {
+ if ((!empty($value['B']) && $browserClosed) || (!empty($value['T']) && $now > $value['T'])) { // whenBrowserIsClosed || Time
+ if ($variable === '') { // expire whole section
+ unset($nf['META'][$section], $nf['DATA'][$section]);
+ continue 2;
+ }
+ unset($nf['META'][$section][$variable], $nf['DATA'][$section][$variable]);
+ }
+ }
+ }
+ }
+ }
+
+ if ($this->regenerated) {
+ $this->regenerated = FALSE;
+ $this->regenerateId();
+ }
+
+ register_shutdown_function(array($this, 'clean'));
+ }
+
+
+ /**
+ * Has been session started?
+ * @return bool
+ */
+ public function isStarted()
+ {
+ return (bool) self::$started;
+ }
+
+
+ /**
+ * Ends the current session and store session data.
+ * @return void
+ */
+ public function close()
+ {
+ if (self::$started) {
+ $this->clean();
+ session_write_close();
+ self::$started = FALSE;
+ }
+ }
+
+
+ /**
+ * Destroys all data registered to a session.
+ * @return void
+ */
+ public function destroy()
+ {
+ if (!self::$started) {
+ throw new Nette\InvalidStateException('Session is not started.');
+ }
+
+ session_destroy();
+ $_SESSION = NULL;
+ self::$started = FALSE;
+ if (!$this->response->isSent()) {
+ $params = session_get_cookie_params();
+ $this->response->deleteCookie(session_name(), $params['path'], $params['domain'], $params['secure']);
+ }
+ }
+
+
+ /**
+ * Does session exists for the current request?
+ * @return bool
+ */
+ public function exists()
+ {
+ return self::$started || $this->request->getCookie($this->getName()) !== NULL;
+ }
+
+
+ /**
+ * Regenerates the session ID.
+ * @throws Nette\InvalidStateException
+ * @return void
+ */
+ public function regenerateId()
+ {
+ if (self::$started && !$this->regenerated) {
+ if (headers_sent($file, $line)) {
+ throw new Nette\InvalidStateException('Cannot regenerate session ID after HTTP headers have been sent' . ($file ? " (output started at $file:$line)." : '.'));
+ }
+ if (session_id() !== '') {
+ session_regenerate_id(TRUE);
+ }
+ session_write_close();
+ $backup = $_SESSION;
+ session_start();
+ $_SESSION = $backup;
+ Helpers::removeDuplicateCookies();
+ }
+ $this->regenerated = TRUE;
+ }
+
+
+ /**
+ * Returns the current session ID. Don't make dependencies, can be changed for each request.
+ * @return string
+ */
+ public function getId()
+ {
+ return session_id();
+ }
+
+
+ /**
+ * Sets the session name to a specified one.
+ * @param string
+ * @return self
+ */
+ public function setName($name)
+ {
+ if (!is_string($name) || !preg_match('#[^0-9.][^.]*\z#A', $name)) {
+ throw new Nette\InvalidArgumentException('Session name must be a string and cannot contain dot.');
+ }
+
+ session_name($name);
+ return $this->setOptions(array(
+ 'name' => $name,
+ ));
+ }
+
+
+ /**
+ * Gets the session name.
+ * @return string
+ */
+ public function getName()
+ {
+ return isset($this->options['name']) ? $this->options['name'] : session_name();
+ }
+
+
+ /********************* sections management ****************d*g**/
+
+
+ /**
+ * Returns specified session section.
+ * @param string
+ * @param string
+ * @return SessionSection
+ * @throws Nette\InvalidArgumentException
+ */
+ public function getSection($section, $class = 'Nette\Http\SessionSection')
+ {
+ return new $class($this, $section);
+ }
+
+
+ /**
+ * Checks if a session section exist and is not empty.
+ * @param string
+ * @return bool
+ */
+ public function hasSection($section)
+ {
+ if ($this->exists() && !self::$started) {
+ $this->start();
+ }
+
+ return !empty($_SESSION['__NF']['DATA'][$section]);
+ }
+
+
+ /**
+ * Iteration over all sections.
+ * @return \ArrayIterator
+ */
+ public function getIterator()
+ {
+ if ($this->exists() && !self::$started) {
+ $this->start();
+ }
+
+ if (isset($_SESSION['__NF']['DATA'])) {
+ return new \ArrayIterator(array_keys($_SESSION['__NF']['DATA']));
+
+ } else {
+ return new \ArrayIterator;
+ }
+ }
+
+
+ /**
+ * Cleans and minimizes meta structures. This method is called automatically on shutdown, do not call it directly.
+ * @internal
+ * @return void
+ */
+ public function clean()
+ {
+ if (!self::$started || empty($_SESSION)) {
+ return;
+ }
+
+ $nf = & $_SESSION['__NF'];
+ if (isset($nf['META']) && is_array($nf['META'])) {
+ foreach ($nf['META'] as $name => $foo) {
+ if (empty($nf['META'][$name])) {
+ unset($nf['META'][$name]);
+ }
+ }
+ }
+
+ if (empty($nf['META'])) {
+ unset($nf['META']);
+ }
+
+ if (empty($nf['DATA'])) {
+ unset($nf['DATA']);
+ }
+ }
+
+
+ /********************* configuration ****************d*g**/
+
+
+ /**
+ * Sets session options.
+ * @param array
+ * @return self
+ * @throws Nette\NotSupportedException
+ * @throws Nette\InvalidStateException
+ */
+ public function setOptions(array $options)
+ {
+ if (self::$started) {
+ $this->configure($options);
+ }
+ $this->options = $options + $this->options;
+ if (!empty($options['auto_start'])) {
+ $this->start();
+ }
+ return $this;
+ }
+
+
+ /**
+ * Returns all session options.
+ * @return array
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+
+ /**
+ * Configures session environment.
+ * @param array
+ * @return void
+ */
+ private function configure(array $config)
+ {
+ $special = array('cache_expire' => 1, 'cache_limiter' => 1, 'save_path' => 1, 'name' => 1);
+
+ foreach ($config as $key => $value) {
+ if (!strncmp($key, 'session.', 8)) { // back compatibility
+ $key = substr($key, 8);
+ }
+ $key = strtolower(preg_replace('#(.)(?=[A-Z])#', '$1_', $key));
+
+ if ($value === NULL || ini_get("session.$key") == $value) { // intentionally ==
+ continue;
+
+ } elseif (strncmp($key, 'cookie_', 7) === 0) {
+ if (!isset($cookie)) {
+ $cookie = session_get_cookie_params();
+ }
+ $cookie[substr($key, 7)] = $value;
+
+ } else {
+ if (defined('SID')) {
+ throw new Nette\InvalidStateException("Unable to set 'session.$key' to value '$value' when session has been started" . ($this->started ? '.' : ' by session.auto_start or session_start().'));
+ }
+ if (isset($special[$key])) {
+ $key = "session_$key";
+ $key($value);
+
+ } elseif (function_exists('ini_set')) {
+ ini_set("session.$key", $value);
+
+ } elseif (ini_get("session.$key") != $value) { // intentionally ==
+ throw new Nette\NotSupportedException("Unable to set 'session.$key' to '$value' because function ini_set() is disabled.");
+ }
+ }
+ }
+
+ if (isset($cookie)) {
+ session_set_cookie_params(
+ $cookie['lifetime'], $cookie['path'], $cookie['domain'],
+ $cookie['secure'], $cookie['httponly']
+ );
+ if (self::$started) {
+ $this->sendCookie();
+ }
+ }
+
+ if ($this->handler) {
+ session_set_save_handler($this->handler);
+ }
+ }
+
+
+ /**
+ * Sets the amount of time allowed between requests before the session will be terminated.
+ * @param string|int|\DateTime time, value 0 means "until the browser is closed"
+ * @return self
+ */
+ public function setExpiration($time)
+ {
+ if (empty($time)) {
+ return $this->setOptions(array(
+ 'gc_maxlifetime' => self::DEFAULT_FILE_LIFETIME,
+ 'cookie_lifetime' => 0,
+ ));
+
+ } else {
+ $time = Nette\Utils\DateTime::from($time)->format('U') - time();
+ return $this->setOptions(array(
+ 'gc_maxlifetime' => $time,
+ 'cookie_lifetime' => $time,
+ ));
+ }
+ }
+
+
+ /**
+ * Sets the session cookie parameters.
+ * @param string path
+ * @param string domain
+ * @param bool secure
+ * @return self
+ */
+ public function setCookieParameters($path, $domain = NULL, $secure = NULL)
+ {
+ return $this->setOptions(array(
+ 'cookie_path' => $path,
+ 'cookie_domain' => $domain,
+ 'cookie_secure' => $secure,
+ ));
+ }
+
+
+ /**
+ * Returns the session cookie parameters.
+ * @return array containing items: lifetime, path, domain, secure, httponly
+ */
+ public function getCookieParameters()
+ {
+ return session_get_cookie_params();
+ }
+
+
+ /**
+ * Sets path of the directory used to save session data.
+ * @return self
+ */
+ public function setSavePath($path)
+ {
+ return $this->setOptions(array(
+ 'save_path' => $path,
+ ));
+ }
+
+
+ /**
+ * Sets user session storage for PHP < 5.4. For PHP >= 5.4, use setHandler().
+ * @return self
+ */
+ public function setStorage(ISessionStorage $storage)
+ {
+ if (self::$started) {
+ throw new Nette\InvalidStateException('Unable to set storage when session has been started.');
+ }
+ session_set_save_handler(
+ array($storage, 'open'), array($storage, 'close'), array($storage, 'read'),
+ array($storage, 'write'), array($storage, 'remove'), array($storage, 'clean')
+ );
+ return $this;
+ }
+
+
+ /**
+ * Sets user session handler.
+ * @return self
+ */
+ public function setHandler(\SessionHandlerInterface $handler)
+ {
+ if (self::$started) {
+ throw new Nette\InvalidStateException('Unable to set handler when session has been started.');
+ }
+ $this->handler = $handler;
+ return $this;
+ }
+
+
+ /**
+ * Sends the session cookies.
+ * @return void
+ */
+ private function sendCookie()
+ {
+ if (!headers_sent() && ob_get_level() && ob_get_length()) {
+ trigger_error('Possible problem: you are starting session while already having some data in output buffer. This may not work if the outputted data grows. Try starting the session earlier.', E_USER_NOTICE);
+ }
+
+ $cookie = $this->getCookieParameters();
+ $this->response->setCookie(
+ session_name(), session_id(),
+ $cookie['lifetime'] ? $cookie['lifetime'] + time() : 0,
+ $cookie['path'], $cookie['domain'], $cookie['secure'], $cookie['httponly']
+ );
+ $this->response->setCookie(
+ 'nette-browser', $_SESSION['__NF']['B'],
+ Response::BROWSER, $cookie['path'], $cookie['domain']
+ );
+ }
+
+}
diff --git a/vendor/nette/http/src/Http/SessionSection.php b/vendor/nette/http/src/Http/SessionSection.php
new file mode 100755
index 0000000..bbad9ac
--- /dev/null
+++ b/vendor/nette/http/src/Http/SessionSection.php
@@ -0,0 +1,230 @@
+session = $session;
+ $this->name = $name;
+ }
+
+
+ /**
+ * Do not call directly. Use Session::getNamespace().
+ */
+ private function start()
+ {
+ if ($this->meta === FALSE) {
+ $this->session->start();
+ $this->data = & $_SESSION['__NF']['DATA'][$this->name];
+ $this->meta = & $_SESSION['__NF']['META'][$this->name];
+ }
+ }
+
+
+ /**
+ * Returns an iterator over all section variables.
+ * @return \ArrayIterator
+ */
+ public function getIterator()
+ {
+ $this->start();
+ if (isset($this->data)) {
+ return new \ArrayIterator($this->data);
+ } else {
+ return new \ArrayIterator;
+ }
+ }
+
+
+ /**
+ * Sets a variable in this session section.
+ * @param string name
+ * @param mixed value
+ * @return void
+ */
+ public function __set($name, $value)
+ {
+ $this->start();
+ $this->data[$name] = $value;
+ }
+
+
+ /**
+ * Gets a variable from this session section.
+ * @param string name
+ * @return mixed
+ */
+ public function &__get($name)
+ {
+ $this->start();
+ if ($this->warnOnUndefined && !array_key_exists($name, $this->data)) {
+ trigger_error("The variable '$name' does not exist in session section", E_USER_NOTICE);
+ }
+
+ return $this->data[$name];
+ }
+
+
+ /**
+ * Determines whether a variable in this session section is set.
+ * @param string name
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ if ($this->session->exists()) {
+ $this->start();
+ }
+ return isset($this->data[$name]);
+ }
+
+
+ /**
+ * Unsets a variable in this session section.
+ * @param string name
+ * @return void
+ */
+ public function __unset($name)
+ {
+ $this->start();
+ unset($this->data[$name], $this->meta[$name]);
+ }
+
+
+ /**
+ * Sets a variable in this session section.
+ * @param string name
+ * @param mixed value
+ * @return void
+ */
+ public function offsetSet($name, $value)
+ {
+ $this->__set($name, $value);
+ }
+
+
+ /**
+ * Gets a variable from this session section.
+ * @param string name
+ * @return mixed
+ */
+ public function offsetGet($name)
+ {
+ return $this->__get($name);
+ }
+
+
+ /**
+ * Determines whether a variable in this session section is set.
+ * @param string name
+ * @return bool
+ */
+ public function offsetExists($name)
+ {
+ return $this->__isset($name);
+ }
+
+
+ /**
+ * Unsets a variable in this session section.
+ * @param string name
+ * @return void
+ */
+ public function offsetUnset($name)
+ {
+ $this->__unset($name);
+ }
+
+
+ /**
+ * Sets the expiration of the section or specific variables.
+ * @param string|int|\DateTime time, value 0 means "until the browser is closed"
+ * @param mixed optional list of variables / single variable to expire
+ * @return self
+ */
+ public function setExpiration($time, $variables = NULL)
+ {
+ $this->start();
+ if (empty($time)) {
+ $time = NULL;
+ $whenBrowserIsClosed = TRUE;
+ } else {
+ $time = Nette\Utils\DateTime::from($time)->format('U');
+ $max = (int) ini_get('session.gc_maxlifetime');
+ if ($max !== 0 && ($time - time() > $max + 3)) { // 0 - unlimited in memcache handler, 3 - bulgarian constant
+ trigger_error("The expiration time is greater than the session expiration $max seconds", E_USER_NOTICE);
+ }
+ $whenBrowserIsClosed = FALSE;
+ }
+
+ foreach (is_array($variables) ? $variables : array($variables) as $variable) {
+ $this->meta[$variable]['T'] = $time;
+ $this->meta[$variable]['B'] = $whenBrowserIsClosed;
+ }
+ return $this;
+ }
+
+
+ /**
+ * Removes the expiration from the section or specific variables.
+ * @param mixed optional list of variables / single variable to expire
+ * @return void
+ */
+ public function removeExpiration($variables = NULL)
+ {
+ $this->start();
+ foreach (is_array($variables) ? $variables : array($variables) as $variable) {
+ unset($this->meta['']['T'], $this->meta['']['B']);
+ }
+ }
+
+
+ /**
+ * Cancels the current session section.
+ * @return void
+ */
+ public function remove()
+ {
+ $this->start();
+ $this->data = NULL;
+ $this->meta = NULL;
+ }
+
+}
diff --git a/vendor/nette/http/src/Http/Url.php b/vendor/nette/http/src/Http/Url.php
new file mode 100755
index 0000000..d6c099d
--- /dev/null
+++ b/vendor/nette/http/src/Http/Url.php
@@ -0,0 +1,499 @@
+
+ * scheme user password host port basePath relativeUrl
+ * | | | | | | |
+ * /--\ /--\ /------\ /-------\ /--\/--\/----------------------------\
+ * http://john:x0y17575@nette.org:8042/en/manual.php?name=param#fragment <-- absoluteUrl
+ * \__________________________/\____________/^\________/^\______/
+ * | | | |
+ * authority path query fragment
+ *
+ *
+ * - authority: [user[:password]@]host[:port]
+ * - hostUrl: http://user:password@nette.org:8042
+ * - basePath: /en/ (everything before relative URI not including the script name)
+ * - baseUrl: http://user:password@nette.org:8042/en/
+ * - relativeUrl: manual.php
+ *
+ * @property string $scheme
+ * @property string $user
+ * @property string $password
+ * @property string $host
+ * @property int $port
+ * @property string $path
+ * @property string $query
+ * @property string $fragment
+ * @property-read string $absoluteUrl
+ * @property-read string $authority
+ * @property-read string $hostUrl
+ * @property-read string $basePath
+ * @property-read string $baseUrl
+ * @property-read string $relativeUrl
+ * @property-read array $queryParameters
+ */
+class Url extends Nette\Object
+{
+ /** @var array */
+ public static $defaultPorts = array(
+ 'http' => 80,
+ 'https' => 443,
+ 'ftp' => 21,
+ 'news' => 119,
+ 'nntp' => 119,
+ );
+
+ /** @var string */
+ private $scheme = '';
+
+ /** @var string */
+ private $user = '';
+
+ /** @var string */
+ private $password = '';
+
+ /** @var string */
+ private $host = '';
+
+ /** @var int */
+ private $port;
+
+ /** @var string */
+ private $path = '';
+
+ /** @var array */
+ private $query = array();
+
+ /** @var string */
+ private $fragment = '';
+
+
+ /**
+ * @param string|self
+ * @throws Nette\InvalidArgumentException if URL is malformed
+ */
+ public function __construct($url = NULL)
+ {
+ if (is_string($url)) {
+ $p = @parse_url($url); // @ - is escalated to exception
+ if ($p === FALSE) {
+ throw new Nette\InvalidArgumentException("Malformed or unsupported URI '$url'.");
+ }
+
+ $this->scheme = isset($p['scheme']) ? $p['scheme'] : '';
+ $this->port = isset($p['port']) ? $p['port'] : NULL;
+ $this->host = isset($p['host']) ? rawurldecode($p['host']) : '';
+ $this->user = isset($p['user']) ? rawurldecode($p['user']) : '';
+ $this->password = isset($p['pass']) ? rawurldecode($p['pass']) : '';
+ $this->setPath(isset($p['path']) ? $p['path'] : '');
+ $this->setQuery(isset($p['query']) ? $p['query'] : array());
+ $this->fragment = isset($p['fragment']) ? rawurldecode($p['fragment']) : '';
+
+ } elseif ($url instanceof self) {
+ foreach ($this as $key => $val) {
+ $this->$key = $url->$key;
+ }
+ }
+ }
+
+
+ /**
+ * Sets the scheme part of URI.
+ * @param string
+ * @return self
+ */
+ public function setScheme($value)
+ {
+ $this->scheme = (string) $value;
+ return $this;
+ }
+
+
+ /**
+ * Returns the scheme part of URI.
+ * @return string
+ */
+ public function getScheme()
+ {
+ return $this->scheme;
+ }
+
+
+ /**
+ * Sets the user name part of URI.
+ * @param string
+ * @return self
+ */
+ public function setUser($value)
+ {
+ $this->user = (string) $value;
+ return $this;
+ }
+
+
+ /**
+ * Returns the user name part of URI.
+ * @return string
+ */
+ public function getUser()
+ {
+ return $this->user;
+ }
+
+
+ /**
+ * Sets the password part of URI.
+ * @param string
+ * @return self
+ */
+ public function setPassword($value)
+ {
+ $this->password = (string) $value;
+ return $this;
+ }
+
+
+ /**
+ * Returns the password part of URI.
+ * @return string
+ */
+ public function getPassword()
+ {
+ return $this->password;
+ }
+
+
+ /**
+ * Sets the host part of URI.
+ * @param string
+ * @return self
+ */
+ public function setHost($value)
+ {
+ $this->host = (string) $value;
+ $this->setPath($this->path);
+ return $this;
+ }
+
+
+ /**
+ * Returns the host part of URI.
+ * @return string
+ */
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+
+ /**
+ * Sets the port part of URI.
+ * @param int
+ * @return self
+ */
+ public function setPort($value)
+ {
+ $this->port = (int) $value;
+ return $this;
+ }
+
+
+ /**
+ * Returns the port part of URI.
+ * @return int
+ */
+ public function getPort()
+ {
+ return $this->port
+ ? $this->port
+ : (isset(self::$defaultPorts[$this->scheme]) ? self::$defaultPorts[$this->scheme] : NULL);
+ }
+
+
+ /**
+ * Sets the path part of URI.
+ * @param string
+ * @return self
+ */
+ public function setPath($value)
+ {
+ $this->path = (string) $value;
+ if ($this->host && substr($this->path, 0, 1) !== '/') {
+ $this->path = '/' . $this->path;
+ }
+ return $this;
+ }
+
+
+ /**
+ * Returns the path part of URI.
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+
+ /**
+ * Sets the query part of URI.
+ * @param string|array
+ * @return self
+ */
+ public function setQuery($value)
+ {
+ $this->query = is_array($value) ? $value : self::parseQuery($value);
+ return $this;
+ }
+
+
+ /**
+ * Appends the query part of URI.
+ * @param string|array
+ * @return self
+ */
+ public function appendQuery($value)
+ {
+ $this->query = is_array($value)
+ ? $value + $this->query
+ : self::parseQuery($this->getQuery() . '&' . $value);
+ return $this;
+ }
+
+
+ /**
+ * Returns the query part of URI.
+ * @return string
+ */
+ public function getQuery()
+ {
+ if (PHP_VERSION_ID < 50400) {
+ return str_replace('+', '%20', http_build_query($this->query, '', '&'));
+ }
+ return http_build_query($this->query, '', '&', PHP_QUERY_RFC3986);
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getQueryParameters()
+ {
+ return $this->query;
+ }
+
+
+ /**
+ * @param string
+ * @param mixed
+ * @return mixed
+ */
+ public function getQueryParameter($name, $default = NULL)
+ {
+ return isset($this->query[$name]) ? $this->query[$name] : $default;
+ }
+
+
+ /**
+ * @param string
+ * @param mixed NULL unsets the parameter
+ * @return self
+ */
+ public function setQueryParameter($name, $value)
+ {
+ $this->query[$name] = $value;
+ return $this;
+ }
+
+
+ /**
+ * Sets the fragment part of URI.
+ * @param string
+ * @return self
+ */
+ public function setFragment($value)
+ {
+ $this->fragment = (string) $value;
+ return $this;
+ }
+
+
+ /**
+ * Returns the fragment part of URI.
+ * @return string
+ */
+ public function getFragment()
+ {
+ return $this->fragment;
+ }
+
+
+ /**
+ * Returns the entire URI including query string and fragment.
+ * @return string
+ */
+ public function getAbsoluteUrl()
+ {
+ return $this->getHostUrl() . $this->path
+ . (($tmp = $this->getQuery()) ? '?' . $tmp : '')
+ . ($this->fragment === '' ? '' : '#' . $this->fragment);
+ }
+
+
+ /**
+ * Returns the [user[:pass]@]host[:port] part of URI.
+ * @return string
+ */
+ public function getAuthority()
+ {
+ return $this->host === ''
+ ? ''
+ : ($this->user !== '' && $this->scheme !== 'http' && $this->scheme !== 'https'
+ ? rawurlencode($this->user) . ($this->password === '' ? '' : ':' . rawurlencode($this->password)) . '@'
+ : '')
+ . $this->host
+ . ($this->port && (!isset(self::$defaultPorts[$this->scheme]) || $this->port !== self::$defaultPorts[$this->scheme])
+ ? ':' . $this->port
+ : '');
+ }
+
+
+ /**
+ * Returns the scheme and authority part of URI.
+ * @return string
+ */
+ public function getHostUrl()
+ {
+ return ($this->scheme ? $this->scheme . ':' : '') . '//' . $this->getAuthority();
+ }
+
+
+ /**
+ * Returns the base-path.
+ * @return string
+ */
+ public function getBasePath()
+ {
+ $pos = strrpos($this->path, '/');
+ return $pos === FALSE ? '' : substr($this->path, 0, $pos + 1);
+ }
+
+
+ /**
+ * Returns the base-URI.
+ * @return string
+ */
+ public function getBaseUrl()
+ {
+ return $this->getHostUrl() . $this->getBasePath();
+ }
+
+
+ /**
+ * Returns the relative-URI.
+ * @return string
+ */
+ public function getRelativeUrl()
+ {
+ return (string) substr($this->getAbsoluteUrl(), strlen($this->getBaseUrl()));
+ }
+
+
+ /**
+ * URL comparison.
+ * @param string|self
+ * @return bool
+ */
+ public function isEqual($url)
+ {
+ $url = new self($url);
+ $query = $url->query;
+ ksort($query);
+ $query2 = $this->query;
+ ksort($query2);
+ $http = in_array($this->scheme, array('http', 'https'), TRUE);
+ return $url->scheme === $this->scheme
+ && !strcasecmp($url->host, $this->host)
+ && $url->getPort() === $this->getPort()
+ && ($http || $url->user === $this->user)
+ && ($http || $url->password === $this->password)
+ && self::unescape($url->path, '%/') === self::unescape($this->path, '%/')
+ && $query === $query2
+ && $url->fragment === $this->fragment;
+ }
+
+
+ /**
+ * Transforms URL to canonical form.
+ * @return self
+ */
+ public function canonicalize()
+ {
+ $this->path = preg_replace_callback(
+ '#[^!$&\'()*+,/:;=@%]+#',
+ function ($m) { return rawurlencode($m[0]); },
+ self::unescape($this->path, '%/')
+ );
+ $this->host = strtolower($this->host);
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->getAbsoluteUrl();
+ }
+
+
+ /**
+ * Similar to rawurldecode, but preserves reserved chars encoded.
+ * @param string to decode
+ * @param string reserved characters
+ * @return string
+ */
+ public static function unescape($s, $reserved = '%;/?:@&=+$,')
+ {
+ // reserved (@see RFC 2396) = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
+ // within a path segment, the characters "/", ";", "=", "?" are reserved
+ // within a query component, the characters ";", "/", "?", ":", "@", "&", "=", "+", ",", "$" are reserved.
+ if ($reserved !== '') {
+ $s = preg_replace_callback(
+ '#%(' . substr(chunk_split(bin2hex($reserved), 2, '|'), 0, -1) . ')#i',
+ function ($m) { return '%25' . strtoupper($m[1]); },
+ $s
+ );
+ }
+ return rawurldecode($s);
+ }
+
+
+ /**
+ * Parses query string.
+ * @return array
+ */
+ public static function parseQuery($s)
+ {
+ parse_str($s, $res);
+ if (get_magic_quotes_gpc()) { // for PHP 5.3
+ $res = Helpers::stripSlashes($res);
+ }
+ return $res;
+ }
+
+}
diff --git a/vendor/nette/http/src/Http/UrlScript.php b/vendor/nette/http/src/Http/UrlScript.php
new file mode 100755
index 0000000..294eff9
--- /dev/null
+++ b/vendor/nette/http/src/Http/UrlScript.php
@@ -0,0 +1,75 @@
+
+ * http://nette.org/admin/script.php/pathinfo/?name=param#fragment
+ * \_______________/\________/
+ * | |
+ * scriptPath pathInfo
+ *
+ *
+ * - scriptPath: /admin/script.php (or simply /admin/ when script is directory index)
+ * - pathInfo: /pathinfo/ (additional path information)
+ *
+ * @property string $scriptPath
+ * @property-read string $pathInfo
+ */
+class UrlScript extends Url
+{
+ /** @var string */
+ private $scriptPath = '/';
+
+
+ /**
+ * Sets the script-path part of URI.
+ * @param string
+ * @return self
+ */
+ public function setScriptPath($value)
+ {
+ $this->scriptPath = (string) $value;
+ return $this;
+ }
+
+
+ /**
+ * Returns the script-path part of URI.
+ * @return string
+ */
+ public function getScriptPath()
+ {
+ return $this->scriptPath;
+ }
+
+
+ /**
+ * Returns the base-path.
+ * @return string
+ */
+ public function getBasePath()
+ {
+ $pos = strrpos($this->scriptPath, '/');
+ return $pos === FALSE ? '' : substr($this->getPath(), 0, $pos + 1);
+ }
+
+
+ /**
+ * Returns the additional path information.
+ * @return string
+ */
+ public function getPathInfo()
+ {
+ return (string) substr($this->getPath(), strlen($this->scriptPath));
+ }
+
+}
diff --git a/vendor/nette/http/src/Http/UserStorage.php b/vendor/nette/http/src/Http/UserStorage.php
new file mode 100755
index 0000000..2bcbad7
--- /dev/null
+++ b/vendor/nette/http/src/Http/UserStorage.php
@@ -0,0 +1,203 @@
+sessionHandler = $sessionHandler;
+ }
+
+
+ /**
+ * Sets the authenticated status of this user.
+ * @param bool
+ * @return self
+ */
+ public function setAuthenticated($state)
+ {
+ $section = $this->getSessionSection(TRUE);
+ $section->authenticated = (bool) $state;
+
+ // Session Fixation defence
+ $this->sessionHandler->regenerateId();
+
+ if ($state) {
+ $section->reason = NULL;
+ $section->authTime = time(); // informative value
+
+ } else {
+ $section->reason = self::MANUAL;
+ $section->authTime = NULL;
+ }
+ return $this;
+ }
+
+
+ /**
+ * Is this user authenticated?
+ * @return bool
+ */
+ public function isAuthenticated()
+ {
+ $session = $this->getSessionSection(FALSE);
+ return $session && $session->authenticated;
+ }
+
+
+ /**
+ * Sets the user identity.
+ * @return self
+ */
+ public function setIdentity(IIdentity $identity = NULL)
+ {
+ $this->getSessionSection(TRUE)->identity = $identity;
+ return $this;
+ }
+
+
+ /**
+ * Returns current user identity, if any.
+ * @return Nette\Security\IIdentity|NULL
+ */
+ public function getIdentity()
+ {
+ $session = $this->getSessionSection(FALSE);
+ return $session ? $session->identity : NULL;
+ }
+
+
+ /**
+ * Changes namespace; allows more users to share a session.
+ * @param string
+ * @return self
+ */
+ public function setNamespace($namespace)
+ {
+ if ($this->namespace !== $namespace) {
+ $this->namespace = (string) $namespace;
+ $this->sessionSection = NULL;
+ }
+ return $this;
+ }
+
+
+ /**
+ * Returns current namespace.
+ * @return string
+ */
+ public function getNamespace()
+ {
+ return $this->namespace;
+ }
+
+
+ /**
+ * Enables log out after inactivity.
+ * @param string|int|\DateTime Number of seconds or timestamp
+ * @param int Log out when the browser is closed | Clear the identity from persistent storage?
+ * @return self
+ */
+ public function setExpiration($time, $flags = 0)
+ {
+ $section = $this->getSessionSection(TRUE);
+ if ($time) {
+ $time = Nette\Utils\DateTime::from($time)->format('U');
+ $section->expireTime = $time;
+ $section->expireDelta = $time - time();
+
+ } else {
+ unset($section->expireTime, $section->expireDelta);
+ }
+
+ $section->expireIdentity = (bool) ($flags & self::CLEAR_IDENTITY);
+ $section->expireBrowser = (bool) ($flags & self::BROWSER_CLOSED);
+ $section->browserCheck = TRUE;
+ $section->setExpiration(0, 'browserCheck');
+ $section->setExpiration($time, 'foo'); // time check
+ return $this;
+ }
+
+
+ /**
+ * Why was user logged out?
+ * @return int|NULL
+ */
+ public function getLogoutReason()
+ {
+ $session = $this->getSessionSection(FALSE);
+ return $session ? $session->reason : NULL;
+ }
+
+
+ /**
+ * Returns and initializes $this->sessionSection.
+ * @return SessionSection
+ */
+ protected function getSessionSection($need)
+ {
+ if ($this->sessionSection !== NULL) {
+ return $this->sessionSection;
+ }
+
+ if (!$need && !$this->sessionHandler->exists()) {
+ return NULL;
+ }
+
+ $this->sessionSection = $section = $this->sessionHandler->getSection('Nette.Http.UserStorage/' . $this->namespace);
+
+ if (!$section->identity instanceof IIdentity || !is_bool($section->authenticated)) {
+ $section->remove();
+ }
+
+ if ($section->authenticated && $section->expireBrowser && !$section->browserCheck) { // check if browser was closed?
+ $section->reason = self::BROWSER_CLOSED;
+ $section->authenticated = FALSE;
+ if ($section->expireIdentity) {
+ unset($section->identity);
+ }
+ }
+
+ if ($section->authenticated && $section->expireDelta > 0) { // check time expiration
+ if ($section->expireTime < time()) {
+ $section->reason = self::INACTIVITY;
+ $section->authenticated = FALSE;
+ if ($section->expireIdentity) {
+ unset($section->identity);
+ }
+ }
+ $section->expireTime = time() + $section->expireDelta; // sliding expiration
+ }
+
+ if (!$section->authenticated) {
+ unset($section->expireTime, $section->expireDelta, $section->expireIdentity,
+ $section->expireBrowser, $section->browserCheck, $section->authTime);
+ }
+
+ return $this->sessionSection;
+ }
+
+}
diff --git a/vendor/nette/mail/composer.json b/vendor/nette/mail/composer.json
new file mode 100755
index 0000000..5737f5f
--- /dev/null
+++ b/vendor/nette/mail/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "nette/mail",
+ "description": "Nette Mail: Sending E-mails",
+ "homepage": "http://nette.org",
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.1",
+ "ext-iconv": "*",
+ "nette/utils": "~2.2"
+ },
+ "require-dev": {
+ "nette/di": "~2.3",
+ "nette/tester": "~1.3"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "suggest": {
+ "ext-fileinfo": "to detect type of attached files"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/mail/license.md b/vendor/nette/mail/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/mail/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/mail/src/Bridges/MailDI/MailExtension.php b/vendor/nette/mail/src/Bridges/MailDI/MailExtension.php
new file mode 100755
index 0000000..79e2b01
--- /dev/null
+++ b/vendor/nette/mail/src/Bridges/MailDI/MailExtension.php
@@ -0,0 +1,49 @@
+ FALSE,
+ 'host' => NULL,
+ 'port' => NULL,
+ 'username' => NULL,
+ 'password' => NULL,
+ 'secure' => NULL,
+ 'timeout' => NULL,
+ );
+
+
+ public function loadConfiguration()
+ {
+ $container = $this->getContainerBuilder();
+ $config = $this->validateConfig($this->defaults);
+
+ $mailer = $container->addDefinition($this->prefix('mailer'))
+ ->setClass('Nette\Mail\IMailer');
+
+ if (empty($config['smtp'])) {
+ $mailer->setFactory('Nette\Mail\SendmailMailer');
+ } else {
+ $mailer->setFactory('Nette\Mail\SmtpMailer', array($config));
+ }
+
+ if ($this->name === 'mail') {
+ $container->addAlias('nette.mailer', $this->prefix('mailer'));
+ }
+ }
+
+}
diff --git a/vendor/nette/mail/src/Mail/IMailer.php b/vendor/nette/mail/src/Mail/IMailer.php
new file mode 100755
index 0000000..dd2adb3
--- /dev/null
+++ b/vendor/nette/mail/src/Mail/IMailer.php
@@ -0,0 +1,24 @@
+ '1.0',
+ 'X-Mailer' => 'Nette Framework',
+ );
+
+ /** @var array */
+ private $attachments = array();
+
+ /** @var array */
+ private $inlines = array();
+
+ /** @var mixed */
+ private $html;
+
+
+ public function __construct()
+ {
+ foreach (static::$defaultHeaders as $name => $value) {
+ $this->setHeader($name, $value);
+ }
+ $this->setHeader('Date', date('r'));
+ }
+
+
+ /**
+ * Sets the sender of the message.
+ * @param string email or format "John Doe"
+ * @param string
+ * @return self
+ */
+ public function setFrom($email, $name = NULL)
+ {
+ $this->setHeader('From', $this->formatEmail($email, $name));
+ return $this;
+ }
+
+
+ /**
+ * Returns the sender of the message.
+ * @return array
+ */
+ public function getFrom()
+ {
+ return $this->getHeader('From');
+ }
+
+
+ /**
+ * Adds the reply-to address.
+ * @param string email or format "John Doe"
+ * @param string
+ * @return self
+ */
+ public function addReplyTo($email, $name = NULL)
+ {
+ $this->setHeader('Reply-To', $this->formatEmail($email, $name), TRUE);
+ return $this;
+ }
+
+
+ /**
+ * Sets the subject of the message.
+ * @param string
+ * @return self
+ */
+ public function setSubject($subject)
+ {
+ $this->setHeader('Subject', $subject);
+ return $this;
+ }
+
+
+ /**
+ * Returns the subject of the message.
+ * @return string
+ */
+ public function getSubject()
+ {
+ return $this->getHeader('Subject');
+ }
+
+
+ /**
+ * Adds email recipient.
+ * @param string email or format "John Doe"
+ * @param string
+ * @return self
+ */
+ public function addTo($email, $name = NULL) // addRecipient()
+ {
+ $this->setHeader('To', $this->formatEmail($email, $name), TRUE);
+ return $this;
+ }
+
+
+ /**
+ * Adds carbon copy email recipient.
+ * @param string email or format "John Doe"
+ * @param string
+ * @return self
+ */
+ public function addCc($email, $name = NULL)
+ {
+ $this->setHeader('Cc', $this->formatEmail($email, $name), TRUE);
+ return $this;
+ }
+
+
+ /**
+ * Adds blind carbon copy email recipient.
+ * @param string email or format "John Doe"
+ * @param string
+ * @return self
+ */
+ public function addBcc($email, $name = NULL)
+ {
+ $this->setHeader('Bcc', $this->formatEmail($email, $name), TRUE);
+ return $this;
+ }
+
+
+ /**
+ * Formats recipient email.
+ * @param string
+ * @param string
+ * @return array
+ */
+ private function formatEmail($email, $name)
+ {
+ if (!$name && preg_match('#^(.+) +<(.*)>\z#', $email, $matches)) {
+ return array($matches[2] => $matches[1]);
+ } else {
+ return array($email => $name);
+ }
+ }
+
+
+ /**
+ * Sets the Return-Path header of the message.
+ * @param string email
+ * @return self
+ */
+ public function setReturnPath($email)
+ {
+ $this->setHeader('Return-Path', $email);
+ return $this;
+ }
+
+
+ /**
+ * Returns the Return-Path header.
+ * @return string
+ */
+ public function getReturnPath()
+ {
+ return $this->getHeader('Return-Path');
+ }
+
+
+ /**
+ * Sets email priority.
+ * @param int
+ * @return self
+ */
+ public function setPriority($priority)
+ {
+ $this->setHeader('X-Priority', (int) $priority);
+ return $this;
+ }
+
+
+ /**
+ * Returns email priority.
+ * @return int
+ */
+ public function getPriority()
+ {
+ return $this->getHeader('X-Priority');
+ }
+
+
+ /**
+ * Sets HTML body.
+ * @param string
+ * @param mixed base-path
+ * @return self
+ */
+ public function setHtmlBody($html, $basePath = NULL)
+ {
+ if ($basePath === NULL && ($html instanceof Nette\Templating\IFileTemplate || $html instanceof Nette\Application\UI\ITemplate)) {
+ $basePath = dirname($html->getFile());
+ $bc = TRUE;
+ }
+ $html = (string) $html;
+
+ if ($basePath) {
+ $cids = array();
+ $matches = Strings::matchAll(
+ $html,
+ '#(src\s*=\s*|background\s*=\s*|url\()(["\']?)(?![a-z]+:|[/\\#])([^"\')\s]+)#i',
+ PREG_OFFSET_CAPTURE
+ );
+ if ($matches && isset($bc)) {
+ trigger_error(__METHOD__ . '() missing second argument with image base path.', E_USER_WARNING);
+ }
+ foreach (array_reverse($matches) as $m) {
+ $file = rtrim($basePath, '/\\') . '/' . urldecode($m[3][0]);
+ if (!isset($cids[$file])) {
+ $cids[$file] = substr($this->addEmbeddedFile($file)->getHeader('Content-ID'), 1, -1);
+ }
+ $html = substr_replace($html,
+ "{$m[1][0]}{$m[2][0]}cid:{$cids[$file]}",
+ $m[0][1], strlen($m[0][0])
+ );
+ }
+ }
+
+ if ($this->getSubject() == NULL) { // intentionally ==
+ $html = Strings::replace($html, '#(.+?) #is', function ($m) use (& $title) {
+ $title = $m[1];
+ });
+ $this->setSubject(html_entity_decode($title, ENT_QUOTES, 'UTF-8'));
+ }
+
+ $this->html = ltrim(str_replace("\r", '', $html), "\n");
+
+ if ($this->getBody() == NULL && $html != NULL) { // intentionally ==
+ $this->setBody($this->buildText($html));
+ }
+
+ return $this;
+ }
+
+
+ /**
+ * Gets HTML body.
+ * @return mixed
+ */
+ public function getHtmlBody()
+ {
+ return $this->html;
+ }
+
+
+ /**
+ * Adds embedded file.
+ * @param string
+ * @param string
+ * @param string
+ * @return MimePart
+ */
+ public function addEmbeddedFile($file, $content = NULL, $contentType = NULL)
+ {
+ return $this->inlines[$file] = $this->createAttachment($file, $content, $contentType, 'inline')
+ ->setHeader('Content-ID', $this->getRandomId());
+ }
+
+
+ /**
+ * Adds attachment.
+ * @param string
+ * @param string
+ * @param string
+ * @return MimePart
+ */
+ public function addAttachment($file, $content = NULL, $contentType = NULL)
+ {
+ return $this->attachments[] = $this->createAttachment($file, $content, $contentType, 'attachment');
+ }
+
+
+ /**
+ * Gets all email attachments.
+ * @return MimePart[]
+ */
+ public function getAttachments()
+ {
+ return $this->attachments;
+ }
+
+
+ /**
+ * Creates file MIME part.
+ * @return MimePart
+ */
+ private function createAttachment($file, $content, $contentType, $disposition)
+ {
+ $part = new MimePart;
+ if ($content === NULL) {
+ $content = @file_get_contents($file); // intentionally @
+ if ($content === FALSE) {
+ throw new Nette\FileNotFoundException("Unable to read file '$file'.");
+ }
+ } else {
+ $content = (string) $content;
+ }
+ $part->setBody($content);
+ $part->setContentType($contentType ? $contentType : finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $content));
+ $part->setEncoding(preg_match('#(multipart|message)/#A', $contentType) ? self::ENCODING_8BIT : self::ENCODING_BASE64);
+ $part->setHeader('Content-Disposition', $disposition . '; filename="' . Strings::fixEncoding(basename($file)) . '"');
+ return $part;
+ }
+
+
+ /********************* building and sending ****************d*g**/
+
+
+ /**
+ * Returns encoded message.
+ * @return string
+ */
+ public function generateMessage()
+ {
+ return $this->build()->getEncodedMessage();
+ }
+
+
+ /**
+ * Builds email. Does not modify itself, but returns a new object.
+ * @return self
+ */
+ protected function build()
+ {
+ $mail = clone $this;
+ $mail->setHeader('Message-ID', $this->getRandomId());
+
+ $cursor = $mail;
+ if ($mail->attachments) {
+ $tmp = $cursor->setContentType('multipart/mixed');
+ $cursor = $cursor->addPart();
+ foreach ($mail->attachments as $value) {
+ $tmp->addPart($value);
+ }
+ }
+
+ if ($mail->html != NULL) { // intentionally ==
+ $tmp = $cursor->setContentType('multipart/alternative');
+ $cursor = $cursor->addPart();
+ $alt = $tmp->addPart();
+ if ($mail->inlines) {
+ $tmp = $alt->setContentType('multipart/related');
+ $alt = $alt->addPart();
+ foreach ($mail->inlines as $value) {
+ $tmp->addPart($value);
+ }
+ }
+ $alt->setContentType('text/html', 'UTF-8')
+ ->setEncoding(preg_match('#[^\n]{990}#', $mail->html)
+ ? self::ENCODING_QUOTED_PRINTABLE
+ : (preg_match('#[\x80-\xFF]#', $mail->html) ? self::ENCODING_8BIT : self::ENCODING_7BIT))
+ ->setBody($mail->html);
+ }
+
+ $text = $mail->getBody();
+ $mail->setBody(NULL);
+ $cursor->setContentType('text/plain', 'UTF-8')
+ ->setEncoding(preg_match('#[^\n]{990}#', $text)
+ ? self::ENCODING_QUOTED_PRINTABLE
+ : (preg_match('#[\x80-\xFF]#', $text) ? self::ENCODING_8BIT : self::ENCODING_7BIT))
+ ->setBody($text);
+
+ return $mail;
+ }
+
+
+ /**
+ * Builds text content.
+ * @return string
+ */
+ protected function buildText($html)
+ {
+ $text = Strings::replace($html, array(
+ '#<(style|script|head).*\\1>#Uis' => '',
+ '#]#i' => ' $0',
+ '#[\r\n]+#' => ' ',
+ '#<(/?p|/?h\d|li|br|/tr)[ >/]#i' => "\n$0",
+ ));
+ $text = html_entity_decode(strip_tags($text), ENT_QUOTES, 'UTF-8');
+ $text = Strings::replace($text, '#[ \t]+#', ' ');
+ return trim($text);
+ }
+
+
+ /** @return string */
+ private function getRandomId()
+ {
+ return '<' . Nette\Utils\Random::generate() . '@'
+ . preg_replace('#[^\w.-]+#', '', isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : php_uname('n'))
+ . '>';
+ }
+
+}
diff --git a/vendor/nette/mail/src/Mail/MimePart.php b/vendor/nette/mail/src/Mail/MimePart.php
new file mode 100755
index 0000000..0308b51
--- /dev/null
+++ b/vendor/nette/mail/src/Mail/MimePart.php
@@ -0,0 +1,331 @@
+ name
+ * @param bool
+ * @return self
+ */
+ public function setHeader($name, $value, $append = FALSE)
+ {
+ if (!$name || preg_match('#[^a-z0-9-]#i', $name)) {
+ throw new Nette\InvalidArgumentException("Header name must be non-empty alphanumeric string, '$name' given.");
+ }
+
+ if ($value == NULL) { // intentionally ==
+ if (!$append) {
+ unset($this->headers[$name]);
+ }
+
+ } elseif (is_array($value)) { // email
+ $tmp = & $this->headers[$name];
+ if (!$append || !is_array($tmp)) {
+ $tmp = array();
+ }
+
+ foreach ($value as $email => $recipient) {
+ if ($recipient !== NULL && !Strings::checkEncoding($recipient)) {
+ Nette\Utils\Validators::assert($recipient, 'unicode', "header '$name'");
+ }
+ if (preg_match('#[\r\n]#', $recipient)) {
+ throw new Nette\InvalidArgumentException('Name must not contain line separator.');
+ }
+ Nette\Utils\Validators::assert($email, 'email', "header '$name'");
+ $tmp[$email] = $recipient;
+ }
+
+ } else {
+ $value = (string) $value;
+ if (!Strings::checkEncoding($value)) {
+ throw new Nette\InvalidArgumentException('Header is not valid UTF-8 string.');
+ }
+ $this->headers[$name] = preg_replace('#[\r\n]+#', ' ', $value);
+ }
+ return $this;
+ }
+
+
+ /**
+ * Returns a header.
+ * @param string
+ * @return mixed
+ */
+ public function getHeader($name)
+ {
+ return isset($this->headers[$name]) ? $this->headers[$name] : NULL;
+ }
+
+
+ /**
+ * Removes a header.
+ * @param string
+ * @return self
+ */
+ public function clearHeader($name)
+ {
+ unset($this->headers[$name]);
+ return $this;
+ }
+
+
+ /**
+ * Returns an encoded header.
+ * @param string
+ * @param string
+ * @return string
+ */
+ public function getEncodedHeader($name)
+ {
+ $offset = strlen($name) + 2; // colon + space
+
+ if (!isset($this->headers[$name])) {
+ return NULL;
+
+ } elseif (is_array($this->headers[$name])) {
+ $s = '';
+ foreach ($this->headers[$name] as $email => $name) {
+ if ($name != NULL) { // intentionally ==
+ $s .= self::encodeHeader($name, $offset, TRUE);
+ $email = " <$email>";
+ }
+ $s .= self::append($email . ',', $offset);
+ }
+ return ltrim(substr($s, 0, -1)); // last comma
+
+ } elseif (preg_match('#^(\S+; (?:file)?name=)"(.*)"\z#', $this->headers[$name], $m)) { // Content-Disposition
+ $offset += strlen($m[1]);
+ return $m[1] . '"' . self::encodeHeader($m[2], $offset) . '"';
+
+ } else {
+ return ltrim(self::encodeHeader($this->headers[$name], $offset));
+ }
+ }
+
+
+ /**
+ * Returns all headers.
+ * @return array
+ */
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+
+
+ /**
+ * Sets Content-Type header.
+ * @param string
+ * @param string
+ * @return self
+ */
+ public function setContentType($contentType, $charset = NULL)
+ {
+ $this->setHeader('Content-Type', $contentType . ($charset ? "; charset=$charset" : ''));
+ return $this;
+ }
+
+
+ /**
+ * Sets Content-Transfer-Encoding header.
+ * @param string
+ * @return self
+ */
+ public function setEncoding($encoding)
+ {
+ $this->setHeader('Content-Transfer-Encoding', $encoding);
+ return $this;
+ }
+
+
+ /**
+ * Returns Content-Transfer-Encoding header.
+ * @return string
+ */
+ public function getEncoding()
+ {
+ return $this->getHeader('Content-Transfer-Encoding');
+ }
+
+
+ /**
+ * Adds or creates new multipart.
+ * @return MimePart
+ */
+ public function addPart(MimePart $part = NULL)
+ {
+ return $this->parts[] = $part === NULL ? new self : $part;
+ }
+
+
+ /**
+ * Sets textual body.
+ * @return self
+ */
+ public function setBody($body)
+ {
+ $this->body = (string) $body;
+ return $this;
+ }
+
+
+ /**
+ * Gets textual body.
+ * @return mixed
+ */
+ public function getBody()
+ {
+ return $this->body;
+ }
+
+
+ /********************* building ****************d*g**/
+
+
+ /**
+ * Returns encoded message.
+ * @return string
+ */
+ public function getEncodedMessage()
+ {
+ $output = '';
+ $boundary = '--------' . Nette\Utils\Random::generate();
+
+ foreach ($this->headers as $name => $value) {
+ $output .= $name . ': ' . $this->getEncodedHeader($name);
+ if ($this->parts && $name === 'Content-Type') {
+ $output .= ';' . self::EOL . "\tboundary=\"$boundary\"";
+ }
+ $output .= self::EOL;
+ }
+ $output .= self::EOL;
+
+ $body = (string) $this->body;
+ if ($body !== '') {
+ switch ($this->getEncoding()) {
+ case self::ENCODING_QUOTED_PRINTABLE:
+ $output .= quoted_printable_encode($body);
+ break;
+
+ case self::ENCODING_BASE64:
+ $output .= rtrim(chunk_split(base64_encode($body), self::LINE_LENGTH, self::EOL));
+ break;
+
+ case self::ENCODING_7BIT:
+ $body = preg_replace('#[\x80-\xFF]+#', '', $body);
+ // break intentionally omitted
+
+ case self::ENCODING_8BIT:
+ $body = str_replace(array("\x00", "\r"), '', $body);
+ $body = str_replace("\n", self::EOL, $body);
+ $output .= $body;
+ break;
+
+ default:
+ throw new Nette\InvalidStateException('Unknown encoding.');
+ }
+ }
+
+ if ($this->parts) {
+ if (substr($output, -strlen(self::EOL)) !== self::EOL) {
+ $output .= self::EOL;
+ }
+ foreach ($this->parts as $part) {
+ $output .= '--' . $boundary . self::EOL . $part->getEncodedMessage() . self::EOL;
+ }
+ $output .= '--' . $boundary.'--';
+ }
+
+ return $output;
+ }
+
+
+ /********************* QuotedPrintable helpers ****************d*g**/
+
+
+ /**
+ * Converts a 8 bit header to a string.
+ * @param string
+ * @param int
+ * @param bool
+ * @return string
+ */
+ private static function encodeHeader($s, & $offset = 0, $quotes = FALSE)
+ {
+ if (strspn($s, "!\"#$%&\'()*+,-./0123456789:;<>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^`abcdefghijklmnopqrstuvwxyz{|}~=? _\r\n\t") === strlen($s)) {
+ if ($quotes && preg_match('#[^ a-zA-Z0-9!\#$%&\'*+/?^_`{|}~-]#', $s)) { // RFC 2822 atext except =
+ return self::append('"' . addcslashes($s, '"\\') . '"', $offset);
+ }
+ return self::append($s, $offset);
+ }
+
+ $o = '';
+ if ($offset >= 55) { // maximum for iconv_mime_encode
+ $o = self::EOL . "\t";
+ $offset = 1;
+ }
+
+ $s = iconv_mime_encode(str_repeat(' ', $old = $offset), $s, array(
+ 'scheme' => 'B', // Q is broken
+ 'input-charset' => 'UTF-8',
+ 'output-charset' => 'UTF-8',
+ ));
+
+ $offset = strlen($s) - strrpos($s, "\n");
+ $s = str_replace("\n ", "\n\t", substr($s, $old + 2)); // adds ': '
+ return $o . $s;
+ }
+
+
+ private static function append($s, & $offset = 0)
+ {
+ if ($offset + strlen($s) > self::LINE_LENGTH) {
+ $offset = 1;
+ $s = self::EOL . "\t" . $s;
+ }
+ $offset += strlen($s);
+ return $s;
+ }
+
+}
diff --git a/vendor/nette/mail/src/Mail/SendmailMailer.php b/vendor/nette/mail/src/Mail/SendmailMailer.php
new file mode 100755
index 0000000..b4c373f
--- /dev/null
+++ b/vendor/nette/mail/src/Mail/SendmailMailer.php
@@ -0,0 +1,52 @@
+setHeader('Subject', NULL);
+ $tmp->setHeader('To', NULL);
+
+ $parts = explode(Message::EOL . Message::EOL, $tmp->generateMessage(), 2);
+
+ $args = array(
+ str_replace(Message::EOL, PHP_EOL, $mail->getEncodedHeader('To')),
+ str_replace(Message::EOL, PHP_EOL, $mail->getEncodedHeader('Subject')),
+ str_replace(Message::EOL, PHP_EOL, $parts[1]),
+ str_replace(Message::EOL, PHP_EOL, $parts[0]),
+ );
+ if ($this->commandArgs) {
+ $args[] = (string) $this->commandArgs;
+ }
+ $res = Nette\Utils\Callback::invokeSafe('mail', $args, function ($message) use (& $info) {
+ $info = ": $message";
+ });
+ if ($res === FALSE) {
+ throw new SendException("Unable to send email$info.");
+ }
+ }
+
+}
diff --git a/vendor/nette/mail/src/Mail/SmtpMailer.php b/vendor/nette/mail/src/Mail/SmtpMailer.php
new file mode 100755
index 0000000..88a7fe1
--- /dev/null
+++ b/vendor/nette/mail/src/Mail/SmtpMailer.php
@@ -0,0 +1,195 @@
+host = $options['host'];
+ $this->port = isset($options['port']) ? (int) $options['port'] : NULL;
+ } else {
+ $this->host = ini_get('SMTP');
+ $this->port = (int) ini_get('smtp_port');
+ }
+ $this->username = isset($options['username']) ? $options['username'] : '';
+ $this->password = isset($options['password']) ? $options['password'] : '';
+ $this->secure = isset($options['secure']) ? $options['secure'] : '';
+ $this->timeout = isset($options['timeout']) ? (int) $options['timeout'] : 20;
+ if (!$this->port) {
+ $this->port = $this->secure === 'ssl' ? 465 : 25;
+ }
+ $this->persistent = !empty($options['persistent']);
+ }
+
+
+ /**
+ * Sends email.
+ * @return void
+ * @throws SmtpException
+ */
+ public function send(Message $mail)
+ {
+ $mail = clone $mail;
+
+ try {
+ if (!$this->connection) {
+ $this->connect();
+ }
+
+ if (($from = $mail->getHeader('Return-Path'))
+ || ($from = key($mail->getHeader('From')))
+ ) {
+ $this->write("MAIL FROM:<$from>", 250);
+ }
+
+ foreach (array_merge(
+ (array) $mail->getHeader('To'),
+ (array) $mail->getHeader('Cc'),
+ (array) $mail->getHeader('Bcc')
+ ) as $email => $name) {
+ $this->write("RCPT TO:<$email>", array(250, 251));
+ }
+
+ $mail->setHeader('Bcc', NULL);
+ $data = $mail->generateMessage();
+ $this->write('DATA', 354);
+ $data = preg_replace('#^\.#m', '..', $data);
+ $this->write($data);
+ $this->write('.', 250);
+
+ if (!$this->persistent) {
+ $this->write('QUIT', 221);
+ $this->disconnect();
+ }
+ } catch (SmtpException $e) {
+ if ($this->connection) {
+ $this->disconnect();
+ }
+ throw $e;
+ }
+ }
+
+
+ /**
+ * Connects and authenticates to SMTP server.
+ * @return void
+ */
+ protected function connect()
+ {
+ $this->connection = @fsockopen( // intentionally @
+ ($this->secure === 'ssl' ? 'ssl://' : '') . $this->host,
+ $this->port, $errno, $error, $this->timeout
+ );
+ if (!$this->connection) {
+ throw new SmtpException($error, $errno);
+ }
+ stream_set_timeout($this->connection, $this->timeout, 0);
+ $this->read(); // greeting
+
+ $self = isset($_SERVER['HTTP_HOST']) && preg_match('#^[\w.-]+\z#', $_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
+ $this->write("EHLO $self");
+ if ((int) $this->read() !== 250) {
+ $this->write("HELO $self", 250);
+ }
+
+ if ($this->secure === 'tls') {
+ $this->write('STARTTLS', 220);
+ if (!stream_socket_enable_crypto($this->connection, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
+ throw new SmtpException('Unable to connect via TLS.');
+ }
+ $this->write("EHLO $self", 250);
+ }
+
+ if ($this->username != NULL && $this->password != NULL) {
+ $this->write('AUTH LOGIN', 334);
+ $this->write(base64_encode($this->username), 334, 'username');
+ $this->write(base64_encode($this->password), 235, 'password');
+ }
+ }
+
+
+ /**
+ * Disconnects from SMTP server.
+ * @return void
+ */
+ protected function disconnect()
+ {
+ fclose($this->connection);
+ $this->connection = NULL;
+ }
+
+
+ /**
+ * Writes data to server and checks response against expected code if some provided.
+ * @param string
+ * @param int response code
+ * @param string error message
+ * @return void
+ */
+ protected function write($line, $expectedCode = NULL, $message = NULL)
+ {
+ fwrite($this->connection, $line . Message::EOL);
+ if ($expectedCode) {
+ $response = $this->read();
+ if (!in_array((int) $response, (array) $expectedCode, TRUE)) {
+ throw new SmtpException('SMTP server did not accept ' . ($message ? $message : $line) . ' with error: ' . trim($response));
+ }
+ }
+ }
+
+
+ /**
+ * Reads response from server.
+ * @return string
+ */
+ protected function read()
+ {
+ $s = '';
+ while (($line = fgets($this->connection, 1e3)) != NULL) { // intentionally ==
+ $s .= $line;
+ if (substr($line, 3, 1) === ' ') {
+ break;
+ }
+ }
+ return $s;
+ }
+
+}
diff --git a/vendor/nette/mail/src/Mail/exceptions.php b/vendor/nette/mail/src/Mail/exceptions.php
new file mode 100755
index 0000000..b93209f
--- /dev/null
+++ b/vendor/nette/mail/src/Mail/exceptions.php
@@ -0,0 +1,26 @@
+=5.3.1",
+ "ext-iconv": "*"
+ },
+ "require-dev": {
+ "nette/tester": "~1.4"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/neon/license.md b/vendor/nette/neon/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/neon/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/neon/src/Neon/Decoder.php b/vendor/nette/neon/src/Neon/Decoder.php
new file mode 100755
index 0000000..9ec268b
--- /dev/null
+++ b/vendor/nette/neon/src/Neon/Decoder.php
@@ -0,0 +1,332 @@
+ ']',
+ '{' => '}',
+ '(' => ')',
+ );
+
+ /** @var string */
+ private $input;
+
+ /** @var array */
+ private $tokens;
+
+ /** @var int */
+ private $pos;
+
+
+
+ /**
+ * Decodes a NEON string.
+ * @param string
+ * @return mixed
+ */
+ public function decode($input)
+ {
+ if (!is_string($input)) {
+ throw new \InvalidArgumentException(sprintf('Argument must be a string, %s given.', gettype($input)));
+
+ } elseif (substr($input, 0, 3) === "\xEF\xBB\xBF") { // BOM
+ $input = substr($input, 3);
+ }
+ $this->input = "\n" . str_replace("\r", '', $input); // \n forces indent detection
+
+ $pattern = '~(' . implode(')|(', self::$patterns) . ')~Amix';
+ $this->tokens = preg_split($pattern, $this->input, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE | PREG_SPLIT_DELIM_CAPTURE);
+
+ $last = end($this->tokens);
+ if ($this->tokens && !preg_match($pattern, $last[0])) {
+ $this->pos = count($this->tokens) - 1;
+ $this->error();
+ }
+
+ $this->pos = 0;
+ $res = $this->parse(NULL);
+
+ while (isset($this->tokens[$this->pos])) {
+ if ($this->tokens[$this->pos][0][0] === "\n") {
+ $this->pos++;
+ } else {
+ $this->error();
+ }
+ }
+ return $res;
+ }
+
+
+ /**
+ * @param string indentation (for block-parser)
+ * @param mixed
+ * @return array
+ */
+ private function parse($indent, $result = NULL, $key = NULL, $hasKey = FALSE)
+ {
+ $inlineParser = $indent === FALSE;
+ $value = NULL;
+ $hasValue = FALSE;
+ $tokens = $this->tokens;
+ $n = & $this->pos;
+ $count = count($tokens);
+ $mainResult = & $result;
+
+ for (; $n < $count; $n++) {
+ $t = $tokens[$n][0];
+
+ if ($t === ',') { // ArrayEntry separator
+ if ((!$hasKey && !$hasValue) || !$inlineParser) {
+ $this->error();
+ }
+ $this->addValue($result, $hasKey ? $key : NULL, $hasValue ? $value : NULL);
+ $hasKey = $hasValue = FALSE;
+
+ } elseif ($t === ':' || $t === '=') { // KeyValuePair separator
+ if ($hasValue && (is_array($value) || is_object($value))) {
+ $this->error('Unacceptable key');
+
+ } elseif ($hasKey && $key === NULL && $hasValue && !$inlineParser) {
+ $n++;
+ $result[] = $this->parse($indent . ' ', array(), $value, TRUE);
+ $newIndent = isset($tokens[$n], $tokens[$n + 1]) ? (string) substr($tokens[$n][0], 1) : ''; // not last
+ if (strlen($newIndent) > strlen($indent)) {
+ $n++;
+ $this->error('Bad indentation');
+ } elseif (strlen($newIndent) < strlen($indent)) {
+ return $mainResult; // block parser exit point
+ }
+ $hasKey = $hasValue = FALSE;
+
+ } elseif ($hasKey || !$hasValue) {
+ $this->error();
+
+ } else {
+ $key = (string) $value;
+ $hasKey = TRUE;
+ $hasValue = FALSE;
+ $result = & $mainResult;
+ }
+
+ } elseif ($t === '-') { // BlockArray bullet
+ if ($hasKey || $hasValue || $inlineParser) {
+ $this->error();
+ }
+ $key = NULL;
+ $hasKey = TRUE;
+
+ } elseif (isset(self::$brackets[$t])) { // Opening bracket [ ( {
+ if ($hasValue) {
+ if ($t !== '(') {
+ $this->error();
+ }
+ $n++;
+ if ($value instanceof Entity && $value->value === Neon::CHAIN) {
+ end($value->attributes)->attributes = $this->parse(FALSE, array());
+ } else {
+ $value = new Entity($value, $this->parse(FALSE, array()));
+ }
+ } else {
+ $n++;
+ $value = $this->parse(FALSE, array());
+ }
+ $hasValue = TRUE;
+ if (!isset($tokens[$n]) || $tokens[$n][0] !== self::$brackets[$t]) { // unexpected type of bracket or block-parser
+ $this->error();
+ }
+
+ } elseif ($t === ']' || $t === '}' || $t === ')') { // Closing bracket ] ) }
+ if (!$inlineParser) {
+ $this->error();
+ }
+ break;
+
+ } elseif ($t[0] === "\n") { // Indent
+ if ($inlineParser) {
+ if ($hasKey || $hasValue) {
+ $this->addValue($result, $hasKey ? $key : NULL, $hasValue ? $value : NULL);
+ $hasKey = $hasValue = FALSE;
+ }
+
+ } else {
+ while (isset($tokens[$n + 1]) && $tokens[$n + 1][0][0] === "\n") {
+ $n++; // skip to last indent
+ }
+ if (!isset($tokens[$n + 1])) {
+ break;
+ }
+
+ $newIndent = (string) substr($tokens[$n][0], 1);
+ if ($indent === NULL) { // first iteration
+ $indent = $newIndent;
+ }
+ $minlen = min(strlen($newIndent), strlen($indent));
+ if ($minlen && (string) substr($newIndent, 0, $minlen) !== (string) substr($indent, 0, $minlen)) {
+ $n++;
+ $this->error('Invalid combination of tabs and spaces');
+ }
+
+ if (strlen($newIndent) > strlen($indent)) { // open new block-array or hash
+ if ($hasValue || !$hasKey) {
+ $n++;
+ $this->error('Bad indentation');
+ }
+ $this->addValue($result, $key, $this->parse($newIndent));
+ $newIndent = isset($tokens[$n], $tokens[$n + 1]) ? (string) substr($tokens[$n][0], 1) : ''; // not last
+ if (strlen($newIndent) > strlen($indent)) {
+ $n++;
+ $this->error('Bad indentation');
+ }
+ $hasKey = FALSE;
+
+ } else {
+ if ($hasValue && !$hasKey) { // block items must have "key"; NULL key means list item
+ break;
+
+ } elseif ($hasKey) {
+ $this->addValue($result, $key, $hasValue ? $value : NULL);
+ if ($key !== NULL && !$hasValue && $newIndent === $indent && isset($tokens[$n + 1]) && $tokens[$n + 1][0] === '-') {
+ $result = & $result[$key];
+ }
+ $hasKey = $hasValue = FALSE;
+ }
+ }
+
+ if (strlen($newIndent) < strlen($indent)) { // close block
+ return $mainResult; // block parser exit point
+ }
+ }
+
+ } elseif ($hasValue) { // Value
+ if ($value instanceof Entity) { // Entity chaining
+ if ($value->value !== Neon::CHAIN) {
+ $value = new Entity(Neon::CHAIN, array($value));
+ }
+ $value->attributes[] = new Entity($t);
+ } else {
+ $this->error();
+ }
+ } else { // Value
+ static $consts = array(
+ 'true' => TRUE, 'True' => TRUE, 'TRUE' => TRUE, 'yes' => TRUE, 'Yes' => TRUE, 'YES' => TRUE, 'on' => TRUE, 'On' => TRUE, 'ON' => TRUE,
+ 'false' => FALSE, 'False' => FALSE, 'FALSE' => FALSE, 'no' => FALSE, 'No' => FALSE, 'NO' => FALSE, 'off' => FALSE, 'Off' => FALSE, 'OFF' => FALSE,
+ 'null' => 0, 'Null' => 0, 'NULL' => 0,
+ );
+ if ($t[0] === '"') {
+ $value = preg_replace_callback('#\\\\(?:ud[89ab][0-9a-f]{2}\\\\ud[c-f][0-9a-f]{2}|u[0-9a-f]{4}|x[0-9a-f]{2}|.)#i', array($this, 'cbString'), substr($t, 1, -1));
+ } elseif ($t[0] === "'") {
+ $value = substr($t, 1, -1);
+ } elseif (isset($consts[$t]) && (!isset($tokens[$n + 1][0]) || ($tokens[$n + 1][0] !== ':' && $tokens[$n + 1][0] !== '='))) {
+ $value = $consts[$t] === 0 ? NULL : $consts[$t];
+ } elseif (is_numeric($t)) {
+ $value = $t * 1;
+ } elseif (preg_match('#0x[0-9a-fA-F]+\z#A', $t)) {
+ $value = hexdec($t);
+ } elseif (preg_match('#\d\d\d\d-\d\d?-\d\d?(?:(?:[Tt]| +)\d\d?:\d\d:\d\d(?:\.\d*)? *(?:Z|[-+]\d\d?(?::\d\d)?)?)?\z#A', $t)) {
+ $value = new \DateTime($t);
+ } else { // literal
+ $value = $t;
+ }
+ $hasValue = TRUE;
+ }
+ }
+
+ if ($inlineParser) {
+ if ($hasKey || $hasValue) {
+ $this->addValue($result, $hasKey ? $key : NULL, $hasValue ? $value : NULL);
+ }
+ } else {
+ if ($hasValue && !$hasKey) { // block items must have "key"
+ if ($result === NULL) {
+ $result = $value; // simple value parser
+ } else {
+ $this->error();
+ }
+ } elseif ($hasKey) {
+ $this->addValue($result, $key, $hasValue ? $value : NULL);
+ }
+ }
+ return $mainResult;
+ }
+
+
+ private function addValue(& $result, $key, $value)
+ {
+ if ($key === NULL) {
+ $result[] = $value;
+ } elseif ($result && array_key_exists($key, $result)) {
+ $this->error("Duplicated key '$key'");
+ } else {
+ $result[$key] = $value;
+ }
+ }
+
+
+ private function cbString($m)
+ {
+ static $mapping = array('t' => "\t", 'n' => "\n", 'r' => "\r", 'f' => "\x0C", 'b' => "\x08", '"' => '"', '\\' => '\\', '/' => '/', '_' => "\xc2\xa0");
+ $sq = $m[0];
+ if (isset($mapping[$sq[1]])) {
+ return $mapping[$sq[1]];
+ } elseif ($sq[1] === 'u' && strlen($sq) >= 6) {
+ $lead = hexdec(substr($sq, 2, 4));
+ $tail = hexdec(substr($sq, 8, 4));
+ $code = $tail ? (0x2400 + (($lead - 0xD800) << 10) + $tail) : $lead;
+ if ($code >= 0xD800 && $code <= 0xDFFF) {
+ $this->error("Invalid UTF-8 (lone surrogate) $sq");
+ }
+ return iconv('UTF-32BE', 'UTF-8//IGNORE', pack('N', $code));
+ } elseif ($sq[1] === 'x' && strlen($sq) === 4) {
+ return chr(hexdec(substr($sq, 2)));
+ } else {
+ $this->error("Invalid escaping sequence $sq");
+ }
+ }
+
+
+ private function error($message = "Unexpected '%s'")
+ {
+ $last = isset($this->tokens[$this->pos]) ? $this->tokens[$this->pos] : NULL;
+ $offset = $last ? $last[1] : strlen($this->input);
+ $text = substr($this->input, 0, $offset);
+ $line = substr_count($text, "\n");
+ $col = $offset - strrpos("\n" . $text, "\n") + 1;
+ $token = $last ? str_replace("\n", '', substr($last[0], 0, 40)) : 'end';
+ throw new Exception(str_replace('%s', $token, $message) . " on line $line, column $col.");
+ }
+
+}
diff --git a/vendor/nette/neon/src/Neon/Encoder.php b/vendor/nette/neon/src/Neon/Encoder.php
new file mode 100755
index 0000000..3698f96
--- /dev/null
+++ b/vendor/nette/neon/src/Neon/Encoder.php
@@ -0,0 +1,84 @@
+format('Y-m-d H:i:s O');
+
+ } elseif ($var instanceof Entity) {
+ if ($var->value === Neon::CHAIN) {
+ return implode('', array_map(array($this, 'encode'), $var->attributes));
+ }
+ return $this->encode($var->value) . '('
+ . (is_array($var->attributes) ? substr($this->encode($var->attributes), 1, -1) : '') . ')';
+ }
+
+ if (is_object($var)) {
+ $obj = $var;
+ $var = array();
+ foreach ($obj as $k => $v) {
+ $var[$k] = $v;
+ }
+ }
+
+ if (is_array($var)) {
+ $isList = !$var || array_keys($var) === range(0, count($var) - 1);
+ $s = '';
+ if ($options & self::BLOCK) {
+ if (count($var) === 0) {
+ return '[]';
+ }
+ foreach ($var as $k => $v) {
+ $v = $this->encode($v, self::BLOCK);
+ $s .= ($isList ? '-' : $this->encode($k) . ':')
+ . (strpos($v, "\n") === FALSE
+ ? ' ' . $v . "\n"
+ : "\n" . preg_replace('#^(?=.)#m', "\t", $v) . (substr($v, -2, 1) === "\n" ? '' : "\n"));
+ }
+ return $s;
+
+ } else {
+ foreach ($var as $k => $v) {
+ $s .= ($isList ? '' : $this->encode($k) . ': ') . $this->encode($v) . ', ';
+ }
+ return ($isList ? '[' : '{') . substr($s, 0, -2) . ($isList ? ']' : '}');
+ }
+
+ } elseif (is_string($var) && !is_numeric($var)
+ && !preg_match('~[\x00-\x1F]|^\d{4}|^(true|false|yes|no|on|off|null)\z~i', $var)
+ && preg_match('~^' . Decoder::$patterns[1] . '\z~x', $var) // 1 = literals
+ ) {
+ return $var;
+
+ } elseif (is_float($var)) {
+ $var = json_encode($var);
+ return strpos($var, '.') === FALSE ? $var . '.0' : $var;
+
+ } else {
+ return json_encode($var, PHP_VERSION_ID >= 50400 ? JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES : 0);
+ }
+ }
+
+}
diff --git a/vendor/nette/neon/src/Neon/Entity.php b/vendor/nette/neon/src/Neon/Entity.php
new file mode 100755
index 0000000..92399fe
--- /dev/null
+++ b/vendor/nette/neon/src/Neon/Entity.php
@@ -0,0 +1,29 @@
+value = $value;
+ $this->attributes = (array) $attrs;
+ }
+
+}
diff --git a/vendor/nette/neon/src/Neon/Exception.php b/vendor/nette/neon/src/Neon/Exception.php
new file mode 100755
index 0000000..94d01c1
--- /dev/null
+++ b/vendor/nette/neon/src/Neon/Exception.php
@@ -0,0 +1,16 @@
+encode($var, $options);
+ }
+
+
+ /**
+ * Decodes a NEON string.
+ * @param string
+ * @return mixed
+ */
+ public static function decode($input)
+ {
+ $decoder = new Decoder;
+ return $decoder->decode($input);
+ }
+
+}
diff --git a/vendor/nette/neon/src/neon.php b/vendor/nette/neon/src/neon.php
new file mode 100755
index 0000000..2bbd1fe
--- /dev/null
+++ b/vendor/nette/neon/src/neon.php
@@ -0,0 +1,7 @@
+=5.3.1",
+ "nette/utils": "~2.2"
+ },
+ "require-dev": {
+ "nette/tester": "~1.4"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/php-generator/license.md b/vendor/nette/php-generator/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/php-generator/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/php-generator/src/PhpGenerator/ClassType.php b/vendor/nette/php-generator/src/PhpGenerator/ClassType.php
new file mode 100755
index 0000000..4e4bf24
--- /dev/null
+++ b/vendor/nette/php-generator/src/PhpGenerator/ClassType.php
@@ -0,0 +1,512 @@
+ value */
+ private $consts = array();
+
+ /** @var Property[] name => Property */
+ private $properties = array();
+
+ /** @var Method[] name => Method */
+ private $methods = array();
+
+
+ /**
+ * @param \ReflectionClass|string
+ * @return self
+ */
+ public static function from($from)
+ {
+ $from = $from instanceof \ReflectionClass ? $from : new \ReflectionClass($from);
+ $class = new static($from->getShortName());
+ $class->type = $from->isInterface() ? 'interface' : (PHP_VERSION_ID >= 50400 && $from->isTrait() ? 'trait' : 'class');
+ $class->final = $from->isFinal() && $class->type === 'class';
+ $class->abstract = $from->isAbstract() && $class->type === 'class';
+ $class->implements = $from->getInterfaceNames();
+ $class->documents = $from->getDocComment() ? array(preg_replace('#^\s*\* ?#m', '', trim($from->getDocComment(), "/* \r\n\t"))) : array();
+ $namespace = $from->getNamespaceName();
+ if ($from->getParentClass()) {
+ $class->extends = $from->getParentClass()->getName();
+ if ($namespace) {
+ $class->extends = Strings::startsWith($class->extends, "$namespace\\") ? substr($class->extends, strlen($namespace) + 1) : '\\' . $class->extends;
+ }
+ $class->implements = array_diff($class->implements, $from->getParentClass()->getInterfaceNames());
+ }
+ if ($namespace) {
+ foreach ($class->implements as & $interface) {
+ $interface = Strings::startsWith($interface, "$namespace\\") ? substr($interface, strlen($namespace) + 1) : '\\' . $interface;
+ }
+ }
+ foreach ($from->getProperties() as $prop) {
+ if ($prop->getDeclaringClass() == $from) { // intentionally ==
+ $class->properties[$prop->getName()] = Property::from($prop);
+ }
+ }
+ foreach ($from->getMethods() as $method) {
+ if ($method->getDeclaringClass() == $from) { // intentionally ==
+ $class->methods[$method->getName()] = Method::from($method);
+ }
+ }
+ return $class;
+ }
+
+
+ public function __construct($name = NULL, PhpNamespace $namespace = NULL)
+ {
+ $this->setName($name);
+ $this->namespace = $namespace;
+ }
+
+
+ /**
+ * @return string PHP code
+ */
+ public function __toString()
+ {
+ $consts = array();
+ foreach ($this->consts as $name => $value) {
+ $consts[] = "const $name = " . Helpers::dump($value) . ";\n";
+ }
+
+ $properties = array();
+ foreach ($this->properties as $property) {
+ $doc = str_replace("\n", "\n * ", implode("\n", $property->getDocuments()));
+ $properties[] = ($property->getDocuments() ? (strpos($doc, "\n") === FALSE ? "/** $doc */\n" : "/**\n * $doc\n */\n") : '')
+ . $property->getVisibility() . ($property->isStatic() ? ' static' : '') . ' $' . $property->getName()
+ . ($property->value === NULL ? '' : ' = ' . Helpers::dump($property->value))
+ . ";\n";
+ }
+
+ $extends = (array) $this->extends;
+ $implements = $this->implements;
+ $traits = $this->traits;
+ if ($this->namespace) {
+ $extends = array_map(array($this->namespace, 'unresolveName'), $extends);
+ $implements = array_map(array($this->namespace, 'unresolveName'), $implements);
+ $traits = array_map(array($this->namespace, 'unresolveName'), $traits);
+ }
+
+ foreach ($this->methods as $method) {
+ $method->setNamespace($this->namespace);
+ }
+
+ return Strings::normalize(
+ ($this->documents ? str_replace("\n", "\n * ", "/**\n" . implode("\n", $this->documents)) . "\n */\n" : '')
+ . ($this->abstract ? 'abstract ' : '')
+ . ($this->final ? 'final ' : '')
+ . $this->type . ' '
+ . $this->name . ' '
+ . ($extends ? 'extends ' . implode(', ', $extends) . ' ' : '')
+ . ($implements ? 'implements ' . implode(', ', $implements) . ' ' : '')
+ . "\n{\n"
+ . Strings::indent(
+ ($traits ? 'use ' . implode(', ', $traits) . ";\n\n" : '')
+ . ($this->consts ? implode('', $consts) . "\n" : '')
+ . ($this->properties ? implode("\n", $properties) . "\n" : '')
+ . ($this->methods ? "\n" . implode("\n\n\n", $this->methods) . "\n\n" : ''), 1)
+ . '}'
+ ) . "\n";
+ }
+
+
+ /**
+ * @return PhpNamespace
+ */
+ public function getNamespace()
+ {
+ return $this->namespace;
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function setName($name)
+ {
+ $this->name = (string) $name;
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function setType($type)
+ {
+ if (!in_array($type, array('class', 'interface', 'trait'), TRUE)) {
+ throw new Nette\InvalidArgumentException('Argument must be class|interface|trait.');
+ }
+ $this->type = $type;
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+
+ /**
+ * @param bool
+ * @return self
+ */
+ public function setFinal($state = TRUE)
+ {
+ $this->final = (bool) $state;
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isFinal()
+ {
+ return $this->final;
+ }
+
+
+ /**
+ * @param bool
+ * @return self
+ */
+ public function setAbstract($state = TRUE)
+ {
+ $this->abstract = (bool) $state;
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isAbstract()
+ {
+ return $this->abstract;
+ }
+
+
+ /**
+ * @param string|string[]
+ * @return self
+ */
+ public function setExtends($types)
+ {
+ if (!is_string($types) && !(is_array($types) && array_filter($types, 'is_string') === $types)) {
+ throw new Nette\InvalidArgumentException('Argument must be string or string[].');
+ }
+ $this->extends = $types;
+ return $this;
+ }
+
+
+ /**
+ * @return string|string[]
+ */
+ public function getExtends()
+ {
+ return $this->extends;
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function addExtend($type)
+ {
+ $this->extends = (array) $this->extends;
+ $this->extends[] = (string) $type;
+ return $this;
+ }
+
+
+ /**
+ * @param string[]
+ * @return self
+ */
+ public function setImplements(array $types)
+ {
+ $this->implements = $types;
+ return $this;
+ }
+
+
+ /**
+ * @return string[]
+ */
+ public function getImplements()
+ {
+ return $this->implements;
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function addImplement($type)
+ {
+ $this->implements[] = (string) $type;
+ return $this;
+ }
+
+
+ /**
+ * @param string[]
+ * @return self
+ */
+ public function setTraits(array $traits)
+ {
+ $this->traits = $traits;
+ return $this;
+ }
+
+
+ /**
+ * @return string[]
+ */
+ public function getTraits()
+ {
+ return $this->traits;
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function addTrait($trait)
+ {
+ $this->traits[] = (string) $trait;
+ return $this;
+ }
+
+
+ /**
+ * @param string[]
+ * @return self
+ */
+ public function setDocuments(array $s)
+ {
+ $this->documents = $s;
+ return $this;
+ }
+
+
+ /**
+ * @return string[]
+ */
+ public function getDocuments()
+ {
+ return $this->documents;
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function addDocument($s)
+ {
+ $this->documents[] = (string) $s;
+ return $this;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setConsts(array $consts)
+ {
+ $this->consts = $consts;
+ return $this;
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getConsts()
+ {
+ return $this->consts;
+ }
+
+
+ /**
+ * @param string
+ * @param mixed
+ * @return self
+ */
+ public function addConst($name, $value)
+ {
+ $this->consts[$name] = $value;
+ return $this;
+ }
+
+
+ /**
+ * @param Property[]
+ * @return self
+ */
+ public function setProperties(array $props)
+ {
+ foreach ($props as $v) {
+ if (!$v instanceof Property) {
+ throw new Nette\InvalidArgumentException('Argument must be Nette\PhpGenerator\Property[].');
+ }
+ }
+ $this->properties = $props;
+ return $this;
+ }
+
+
+ /**
+ * @return Property[]
+ */
+ public function getProperties()
+ {
+ return $this->properties;
+ }
+
+
+ /**
+ * @return Property
+ */
+ public function getProperty($name)
+ {
+ if (!isset($this->properties[$name])) {
+ throw new Nette\InvalidArgumentException("Property '$name' not found.");
+ }
+ return $this->properties[$name];
+ }
+
+
+ /**
+ * @param string without $
+ * @param mixed
+ * @return Property
+ */
+ public function addProperty($name, $value = NULL)
+ {
+ $property = new Property;
+ return $this->properties[$name] = $property->setName($name)->setValue($value);
+ }
+
+
+ /**
+ * @param Method[]
+ * @return self
+ */
+ public function setMethods(array $methods)
+ {
+ foreach ($methods as $v) {
+ if (!$v instanceof Method) {
+ throw new Nette\InvalidArgumentException('Argument must be Nette\PhpGenerator\Method[].');
+ }
+ }
+ $this->methods = $methods;
+ return $this;
+ }
+
+
+ /**
+ * @return Method[]
+ */
+ public function getMethods()
+ {
+ return $this->methods;
+ }
+
+
+ /**
+ * @return Method
+ */
+ public function getMethod($name)
+ {
+ if (!isset($this->methods[$name])) {
+ throw new Nette\InvalidArgumentException("Method '$name' not found.");
+ }
+ return $this->methods[$name];
+ }
+
+
+ /**
+ * @param string
+ * @return Method
+ */
+ public function addMethod($name)
+ {
+ $method = new Method;
+ if ($this->type === 'interface') {
+ $method->setVisibility(NULL)->setBody(FALSE);
+ } else {
+ $method->setVisibility('public');
+ }
+ return $this->methods[$name] = $method->setName($name);
+ }
+
+}
diff --git a/vendor/nette/php-generator/src/PhpGenerator/Helpers.php b/vendor/nette/php-generator/src/PhpGenerator/Helpers.php
new file mode 100755
index 0000000..4c198df
--- /dev/null
+++ b/vendor/nette/php-generator/src/PhpGenerator/Helpers.php
@@ -0,0 +1,229 @@
+ self::MAX_DEPTH || isset($var[$marker])) {
+ throw new Nette\InvalidArgumentException('Nesting level too deep or recursive dependency.');
+
+ } else {
+ $out = '';
+ $outAlt = "\n$space";
+ $var[$marker] = TRUE;
+ $counter = 0;
+ foreach ($var as $k => & $v) {
+ if ($k !== $marker) {
+ $item = ($k === $counter ? '' : self::_dump($k, $level + 1) . ' => ') . self::_dump($v, $level + 1);
+ $counter = is_int($k) ? max($k + 1, $counter) : $counter;
+ $out .= ($out === '' ? '' : ', ') . $item;
+ $outAlt .= "\t$item,\n$space";
+ }
+ }
+ unset($var[$marker]);
+ }
+ return 'array(' . (strpos($out, "\n") === FALSE && strlen($out) < 40 ? $out : $outAlt) . ')';
+
+ } elseif ($var instanceof \Serializable) {
+ $var = serialize($var);
+ return 'unserialize(' . self::_dump($var, $level) . ')';
+
+ } elseif (is_object($var)) {
+ $arr = (array) $var;
+ $space = str_repeat("\t", $level);
+ $class = get_class($var);
+
+ static $list = array();
+ if ($level > self::MAX_DEPTH || in_array($var, $list, TRUE)) {
+ throw new Nette\InvalidArgumentException('Nesting level too deep or recursive dependency.');
+
+ } else {
+ $out = "\n";
+ $list[] = $var;
+ if (method_exists($var, '__sleep')) {
+ foreach ($var->__sleep() as $v) {
+ $props[$v] = $props["\x00*\x00$v"] = $props["\x00$class\x00$v"] = TRUE;
+ }
+ }
+ foreach ($arr as $k => & $v) {
+ if (!isset($props) || isset($props[$k])) {
+ $out .= "$space\t" . self::_dump($k, $level + 1) . ' => ' . self::_dump($v, $level + 1) . ",\n";
+ }
+ }
+ array_pop($list);
+ $out .= $space;
+ }
+ return $class === 'stdClass'
+ ? "(object) array($out)"
+ : __CLASS__ . "::createObject('$class', array($out))";
+
+ } elseif (is_resource($var)) {
+ throw new Nette\InvalidArgumentException('Cannot dump resource.');
+
+ } else {
+ return var_export($var, TRUE);
+ }
+ }
+
+
+ /**
+ * Generates PHP statement.
+ * @return string
+ */
+ public static function format($statement)
+ {
+ $args = func_get_args();
+ return self::formatArgs(array_shift($args), $args);
+ }
+
+
+ /**
+ * Generates PHP statement.
+ * @return string
+ */
+ public static function formatArgs($statement, array $args)
+ {
+ $a = strpos($statement, '?');
+ while ($a !== FALSE) {
+ if (!$args) {
+ throw new Nette\InvalidArgumentException('Insufficient number of arguments.');
+ }
+ $arg = array_shift($args);
+ if (substr($statement, $a + 1, 1) === '*') { // ?*
+ if (!is_array($arg)) {
+ throw new Nette\InvalidArgumentException('Argument must be an array.');
+ }
+ $s = substr($statement, 0, $a);
+ $sep = '';
+ foreach ($arg as $tmp) {
+ $s .= $sep . self::dump($tmp);
+ $sep = strlen($s) - strrpos($s, "\n") > 100 ? ",\n\t" : ', ';
+ }
+ $statement = $s . substr($statement, $a + 2);
+ $a = strlen($s);
+
+ } else {
+ $arg = substr($statement, $a - 1, 1) === '$' || in_array(substr($statement, $a - 2, 2), array('->', '::'), TRUE)
+ ? self::formatMember($arg) : self::_dump($arg);
+ $statement = substr_replace($statement, $arg, $a, 1);
+ $a += strlen($arg);
+ }
+ $a = strpos($statement, '?', $a);
+ }
+ return $statement;
+ }
+
+
+ /**
+ * Returns a PHP representation of a object member.
+ * @return string
+ */
+ public static function formatMember($name)
+ {
+ return $name instanceof PhpLiteral || !self::isIdentifier($name)
+ ? '{' . self::_dump($name) . '}'
+ : $name;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public static function isIdentifier($value)
+ {
+ return is_string($value) && preg_match('#^' . self::PHP_IDENT . '\z#', $value);
+ }
+
+
+ /** @internal */
+ public static function createObject($class, array $props)
+ {
+ return unserialize('O' . substr(serialize((string) $class), 1, -1) . substr(serialize($props), 1));
+ }
+
+
+ /**
+ * @param string
+ * @return string
+ */
+ public static function extractNamespace($name)
+ {
+ return ($pos = strrpos($name, '\\')) ? substr($name, 0, $pos) : '';
+ }
+
+
+ /**
+ * @param string
+ * @return string
+ */
+ public static function extractShortName($name)
+ {
+ return ($pos = strrpos($name, '\\')) === FALSE ? $name : substr($name, $pos + 1);
+ }
+
+}
diff --git a/vendor/nette/php-generator/src/PhpGenerator/Method.php b/vendor/nette/php-generator/src/PhpGenerator/Method.php
new file mode 100755
index 0000000..61bd5b4
--- /dev/null
+++ b/vendor/nette/php-generator/src/PhpGenerator/Method.php
@@ -0,0 +1,406 @@
+ Parameter */
+ private $parameters = array();
+
+ /** @var array of name => bool */
+ private $uses = array();
+
+ /** @var string|FALSE */
+ private $body = '';
+
+ /** @var bool */
+ private $static = FALSE;
+
+ /** @var string|NULL public|protected|private */
+ private $visibility;
+
+ /** @var bool */
+ private $final = FALSE;
+
+ /** @var bool */
+ private $abstract = FALSE;
+
+ /** @var bool */
+ private $returnReference = FALSE;
+
+ /** @var bool */
+ private $variadic = FALSE;
+
+ /** @var string[] */
+ private $documents = array();
+
+ /** @var PhpNamespace|NULL */
+ private $namespace;
+
+
+ /**
+ * @return self
+ */
+ public static function from($from)
+ {
+ if (is_string($from) && strpos($from, '::')) {
+ $from = new \ReflectionMethod($from);
+ } elseif (is_array($from)) {
+ $from = new \ReflectionMethod($from[0], $from[1]);
+ } elseif (!$from instanceof \ReflectionFunctionAbstract) {
+ $from = new \ReflectionFunction($from);
+ }
+
+ $method = new static;
+ $method->name = $from->isClosure() ? NULL : $from->getName();
+ foreach ($from->getParameters() as $param) {
+ $method->parameters[$param->getName()] = Parameter::from($param);
+ }
+ if ($from instanceof \ReflectionMethod) {
+ $method->static = $from->isStatic();
+ $method->visibility = $from->isPrivate() ? 'private' : ($from->isProtected() ? 'protected' : NULL);
+ $method->final = $from->isFinal();
+ $method->abstract = $from->isAbstract() && !$from->getDeclaringClass()->isInterface();
+ $method->body = $from->isAbstract() ? FALSE : '';
+ }
+ $method->returnReference = $from->returnsReference();
+ $method->variadic = PHP_VERSION_ID >= 50600 && $from->isVariadic();
+ $method->documents = $from->getDocComment() ? array(preg_replace('#^\s*\* ?#m', '', trim($from->getDocComment(), "/* \r\n\t"))) : array();
+ return $method;
+ }
+
+
+ /**
+ * @return string PHP code
+ */
+ public function __toString()
+ {
+ static $builtinTypes = array('array', 'self', 'parent', 'callable', NULL);
+ $parameters = array();
+ foreach ($this->parameters as $param) {
+ $variadic = $this->variadic && $param === end($this->parameters);
+ $hint = !$this->namespace || in_array($param->getTypeHint(), $builtinTypes, TRUE)
+ ? $param->getTypeHint()
+ : $this->namespace->unresolveName($param->getTypeHint());
+
+ $parameters[] = ($hint ? $hint . ' ' : '')
+ . ($param->isReference() ? '&' : '')
+ . ($variadic ? '...' : '')
+ . '$' . $param->getName()
+ . ($param->isOptional() && !$variadic ? ' = ' . Helpers::dump($param->defaultValue) : '');
+ }
+ $uses = array();
+ foreach ($this->uses as $param) {
+ $uses[] = ($param->isReference() ? '&' : '') . '$' . $param->getName();
+ }
+
+ return ($this->documents ? str_replace("\n", "\n * ", "/**\n" . implode("\n", $this->documents)) . "\n */\n" : '')
+ . ($this->abstract ? 'abstract ' : '')
+ . ($this->final ? 'final ' : '')
+ . ($this->visibility ? $this->visibility . ' ' : '')
+ . ($this->static ? 'static ' : '')
+ . 'function'
+ . ($this->returnReference ? ' &' : '')
+ . ' ' . $this->name
+ . '(' . implode(', ', $parameters) . ')'
+ . ($this->uses ? ' use (' . implode(', ', $uses) . ')' : '')
+ . ($this->abstract || $this->body === FALSE ? ';'
+ : ($this->name ? "\n" : ' ') . "{\n" . Nette\Utils\Strings::indent(ltrim(rtrim($this->body) . "\n"), 1) . '}');
+ }
+
+
+ /**
+ * @param string|NULL
+ * @return self
+ */
+ public function setName($name)
+ {
+ $this->name = $name ? (string) $name : NULL;
+ return $this;
+ }
+
+
+ /**
+ * @return string|NULL
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+
+ /**
+ * @param Parameter[]
+ * @return self
+ */
+ public function setParameters(array $val)
+ {
+ foreach ($val as $v) {
+ if (!$v instanceof Parameter) {
+ throw new Nette\InvalidArgumentException('Argument must be Nette\PhpGenerator\Parameter[].');
+ }
+ }
+ $this->parameters = $val;
+ return $this;
+ }
+
+
+ /**
+ * @return Parameter[]
+ */
+ public function getParameters()
+ {
+ return $this->parameters;
+ }
+
+
+ /**
+ * @param string without $
+ * @return Parameter
+ */
+ public function addParameter($name, $defaultValue = NULL)
+ {
+ $param = new Parameter;
+ if (func_num_args() > 1) {
+ $param->setOptional(TRUE)->setDefaultValue($defaultValue);
+ }
+ return $this->parameters[$name] = $param->setName($name);
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setUses(array $val)
+ {
+ $this->uses = $val;
+ return $this;
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getUses()
+ {
+ return $this->uses;
+ }
+
+
+ /**
+ * @return Parameter
+ */
+ public function addUse($name)
+ {
+ $param = new Parameter;
+ return $this->uses[] = $param->setName($name);
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setBody($statement, array $args = NULL)
+ {
+ $this->body = func_num_args() > 1 ? Helpers::formatArgs($statement, $args) : $statement;
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getBody()
+ {
+ return $this->body;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function addBody($statement, array $args = NULL)
+ {
+ $this->body .= (func_num_args() > 1 ? Helpers::formatArgs($statement, $args) : $statement) . "\n";
+ return $this;
+ }
+
+
+ /**
+ * @param bool
+ * @return self
+ */
+ public function setStatic($val)
+ {
+ $this->static = (bool) $val;
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isStatic()
+ {
+ return $this->static;
+ }
+
+
+ /**
+ * @param string|NULL public|protected|private
+ * @return self
+ */
+ public function setVisibility($val)
+ {
+ if (!in_array($val, array('public', 'protected', 'private', NULL), TRUE)) {
+ throw new Nette\InvalidArgumentException('Argument must be public|protected|private|NULL.');
+ }
+ $this->visibility = $val ? (string) $val : NULL;
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getVisibility()
+ {
+ return $this->visibility;
+ }
+
+
+ /**
+ * @param bool
+ * @return self
+ */
+ public function setFinal($val)
+ {
+ $this->final = (bool) $val;
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isFinal()
+ {
+ return $this->final;
+ }
+
+
+ /**
+ * @param bool
+ * @return self
+ */
+ public function setAbstract($val)
+ {
+ $this->abstract = (bool) $val;
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isAbstract()
+ {
+ return $this->abstract;
+ }
+
+
+ /**
+ * @param bool
+ * @return self
+ */
+ public function setReturnReference($val)
+ {
+ $this->returnReference = (bool) $val;
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function getReturnReference()
+ {
+ return $this->returnReference;
+ }
+
+
+ /**
+ * @param bool
+ * @return self
+ */
+ public function setVariadic($val)
+ {
+ $this->variadic = (bool) $val;
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isVariadic()
+ {
+ return $this->variadic;
+ }
+
+
+ /**
+ * @param string[]
+ * @return self
+ */
+ public function setDocuments(array $val)
+ {
+ $this->documents = $val;
+ return $this;
+ }
+
+
+ /**
+ * @return string[]
+ */
+ public function getDocuments()
+ {
+ return $this->documents;
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function addDocument($val)
+ {
+ $this->documents[] = (string) $val;
+ return $this;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setNamespace(PhpNamespace $val = NULL)
+ {
+ $this->namespace = $val;
+ return $this;
+ }
+
+}
diff --git a/vendor/nette/php-generator/src/PhpGenerator/Parameter.php b/vendor/nette/php-generator/src/PhpGenerator/Parameter.php
new file mode 100755
index 0000000..e17aca8
--- /dev/null
+++ b/vendor/nette/php-generator/src/PhpGenerator/Parameter.php
@@ -0,0 +1,167 @@
+name = $from->getName();
+ $param->reference = $from->isPassedByReference();
+ if ($from->isArray()) {
+ $param->typeHint = 'array';
+ } elseif (PHP_VERSION_ID >= 50400 && $from->isCallable()) {
+ $param->typeHint = 'callable';
+ } else {
+ try {
+ $param->typeHint = $from->getClass() ? '\\' . $from->getClass()->getName() : NULL;
+ } catch (\ReflectionException $e) {
+ if (preg_match('#Class (.+) does not exist#', $e->getMessage(), $m)) {
+ $param->typeHint = '\\' . $m[1];
+ } else {
+ throw $e;
+ }
+ }
+ }
+ $param->optional = PHP_VERSION_ID < 50407 ? $from->isOptional() || ($param->typeHint && $from->allowsNull()) : $from->isDefaultValueAvailable();
+ $param->defaultValue = (PHP_VERSION_ID === 50316 ? $from->isOptional() : $from->isDefaultValueAvailable()) ? $from->getDefaultValue() : NULL;
+
+ $namespace = $from->getDeclaringClass() ? $from->getDeclaringClass()->getNamespaceName() : NULL;
+ $namespace = $namespace ? "\\$namespace\\" : '\\';
+ if (Nette\Utils\Strings::startsWith($param->typeHint, $namespace)) {
+ $param->typeHint = substr($param->typeHint, strlen($namespace));
+ }
+ return $param;
+ }
+
+
+ /**
+ * @param string without $
+ * @return self
+ */
+ public function setName($name)
+ {
+ $this->name = (string) $name;
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+
+ /**
+ * @param bool
+ * @return self
+ */
+ public function setReference($state = TRUE)
+ {
+ $this->reference = (bool) $state;
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isReference()
+ {
+ return $this->reference;
+ }
+
+
+ /**
+ * @param string|NULL
+ * @return self
+ */
+ public function setTypeHint($hint)
+ {
+ $this->typeHint = $hint ? (string) $hint : NULL;
+ return $this;
+ }
+
+
+ /**
+ * @return string|NULL
+ */
+ public function getTypeHint()
+ {
+ return $this->typeHint;
+ }
+
+
+ /**
+ * @param bool
+ * @return self
+ */
+ public function setOptional($state = TRUE)
+ {
+ $this->optional = (bool) $state;
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isOptional()
+ {
+ return $this->optional;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setDefaultValue($val)
+ {
+ $this->defaultValue = $val;
+ return $this;
+ }
+
+
+ /**
+ * @return mixed
+ */
+ public function getDefaultValue()
+ {
+ return $this->defaultValue;
+ }
+
+}
diff --git a/vendor/nette/php-generator/src/PhpGenerator/PhpFile.php b/vendor/nette/php-generator/src/PhpGenerator/PhpFile.php
new file mode 100755
index 0000000..088161f
--- /dev/null
+++ b/vendor/nette/php-generator/src/PhpGenerator/PhpFile.php
@@ -0,0 +1,127 @@
+documents;
+ }
+
+
+ /**
+ * @param string[]
+ * @return self
+ */
+ public function setDocuments(array $documents)
+ {
+ $this->documents = $documents;
+ return $this;
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function addDocument($document)
+ {
+ $this->documents[] = $document;
+ return $this;
+ }
+
+
+ /**
+ * @param string
+ * @return ClassType
+ */
+ public function addClass($name)
+ {
+ return $this
+ ->addNamespace(Helpers::extractNamespace($name))
+ ->addClass(Helpers::extractShortName($name));
+ }
+
+
+ /**
+ * @param string
+ * @return ClassType
+ */
+ public function addInterface($name)
+ {
+ return $this
+ ->addNamespace(Helpers::extractNamespace($name))
+ ->addInterface(Helpers::extractShortName($name));
+ }
+
+
+ /**
+ * @param string
+ * @return ClassType
+ */
+ public function addTrait($name)
+ {
+ return $this
+ ->addNamespace(Helpers::extractNamespace($name))
+ ->addTrait(Helpers::extractShortName($name));
+ }
+
+
+ /**
+ * @param string NULL means global namespace
+ * @return PhpNamespace
+ */
+ public function addNamespace($name)
+ {
+ if (!isset($this->namespaces[$name])) {
+ $this->namespaces[$name] = new PhpNamespace($name);
+ }
+ return $this->namespaces[$name];
+ }
+
+
+ /**
+ * @return string PHP code
+ */
+ public function __toString()
+ {
+ foreach ($this->namespaces as $namespace) {
+ $namespace->setBracketedSyntax(isset($this->namespaces[NULL]));
+ }
+
+ return Strings::normalize(
+ "documents ? "\n" . str_replace("\n", "\n * ", "/**\n" . implode("\n", $this->documents)) . "\n */\n\n" : '')
+ . implode("\n\n", $this->namespaces)
+ ) . "\n";
+ }
+
+}
diff --git a/vendor/nette/php-generator/src/PhpGenerator/PhpLiteral.php b/vendor/nette/php-generator/src/PhpGenerator/PhpLiteral.php
new file mode 100755
index 0000000..be8a246
--- /dev/null
+++ b/vendor/nette/php-generator/src/PhpGenerator/PhpLiteral.php
@@ -0,0 +1,34 @@
+value = (string) $value;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->value;
+ }
+
+}
diff --git a/vendor/nette/php-generator/src/PhpGenerator/PhpNamespace.php b/vendor/nette/php-generator/src/PhpGenerator/PhpNamespace.php
new file mode 100755
index 0000000..db3d379
--- /dev/null
+++ b/vendor/nette/php-generator/src/PhpGenerator/PhpNamespace.php
@@ -0,0 +1,233 @@
+setName($name);
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function setName($name)
+ {
+ $this->name = (string) $name;
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function getBracketedSyntax()
+ {
+ return $this->bracketedSyntax;
+ }
+
+
+ /**
+ * @param bool
+ * @return self
+ * @internal
+ */
+ public function setBracketedSyntax($state = TRUE)
+ {
+ $this->bracketedSyntax = (bool) $state;
+ return $this;
+ }
+
+
+ /**
+ * @return string[]
+ */
+ public function getUses()
+ {
+ return $this->uses;
+ }
+
+
+ /**
+ * @param string
+ * @param string
+ * @param string
+ * @throws InvalidStateException
+ * @return self
+ */
+ public function addUse($name, $alias = NULL, &$aliasOut = NULL)
+ {
+ $name = ltrim($name, '\\');
+ if ($alias === NULL && $this->name === Helpers::extractNamespace($name)) {
+ $alias = Helpers::extractShortName($name);
+ }
+ if ($alias === NULL) {
+ $path = explode('\\', $name);
+ $counter = NULL;
+ do {
+ if (empty($path)) {
+ $counter++;
+ } else {
+ $alias = array_pop($path) . $alias;
+ }
+ } while (isset($this->uses[$alias . $counter]) && $this->uses[$alias . $counter] !== $name);
+ $alias .= $counter;
+
+ } elseif (isset($this->uses[$alias]) && $this->uses[$alias] !== $name) {
+ throw new InvalidStateException(
+ "Alias '$alias' used already for '{$this->uses[$alias]}', cannot use for '{$name}'."
+ );
+ }
+
+ $aliasOut = $alias;
+ $this->uses[$alias] = $name;
+ return $this;
+ }
+
+
+ /**
+ * @param string
+ * @return string
+ */
+ public function unresolveName($name)
+ {
+ $name = ltrim($name, '\\');
+ $res = NULL;
+ $lower = strtolower($name);
+ foreach ($this->uses as $alias => $for) {
+ if (Strings::startsWith($lower . '\\', strtolower($for) . '\\')) {
+ $short = $alias . substr($name, strlen($for));
+ if (!isset($res) || strlen($res) > strlen($short)) {
+ $res = $short;
+ }
+ }
+ }
+
+ if (!$res && Strings::startsWith($lower, strtolower($this->name) . '\\')) {
+ return substr($name, strlen($this->name) + 1);
+ } else {
+ return $res ?: '\\' . $name;
+ }
+ }
+
+
+ /**
+ * @return ClassType[]
+ */
+ public function getClasses()
+ {
+ return $this->classes;
+ }
+
+
+ /**
+ * @param string
+ * @return ClassType
+ */
+ public function addClass($name)
+ {
+ if (!isset($this->classes[$name])) {
+ $this->addUse($this->name . '\\' . $name);
+ $this->classes[$name] = new ClassType($name, $this);
+ }
+ return $this->classes[$name];
+ }
+
+
+ /**
+ * @param string
+ * @return ClassType
+ */
+ public function addInterface($name)
+ {
+ return $this->addClass($name)->setType(ClassType::TYPE_INTERFACE);
+ }
+
+
+ /**
+ * @param string
+ * @return ClassType
+ */
+ public function addTrait($name)
+ {
+ return $this->addClass($name)->setType(ClassType::TYPE_TRAIT);
+ }
+
+
+ /**
+ * @return string PHP code
+ */
+ public function __toString()
+ {
+ $uses = array();
+ asort($this->uses);
+ foreach ($this->uses as $alias => $name) {
+ $useNamespace = Helpers::extractNamespace($name);
+
+ if ($this->name !== $useNamespace) {
+ if ($alias === $name || substr($name, -(strlen($alias) + 1)) === '\\' . $alias) {
+ $uses[] = "use {$name};";
+ } else {
+ $uses[] = "use {$name} as {$alias};";
+ }
+ }
+ }
+
+ $body = ($uses ? implode("\n", $uses) . "\n\n" : '')
+ . implode("\n", $this->classes);
+
+ if ($this->bracketedSyntax) {
+ return 'namespace' . ($this->name ? ' ' . $this->name : '') . " {\n\n"
+ . Strings::indent($body)
+ . "\n}\n";
+
+ } else {
+ return ($this->name ? "namespace {$this->name};\n\n" : '')
+ . $body;
+ }
+ }
+
+}
diff --git a/vendor/nette/php-generator/src/PhpGenerator/Property.php b/vendor/nette/php-generator/src/PhpGenerator/Property.php
new file mode 100755
index 0000000..ff2592b
--- /dev/null
+++ b/vendor/nette/php-generator/src/PhpGenerator/Property.php
@@ -0,0 +1,162 @@
+name = $from->getName();
+ $defaults = $from->getDeclaringClass()->getDefaultProperties();
+ $prop->value = isset($defaults[$prop->name]) ? $defaults[$prop->name] : NULL;
+ $prop->static = $from->isStatic();
+ $prop->visibility = $from->isPrivate() ? 'private' : ($from->isProtected() ? 'protected' : 'public');
+ $prop->documents = $from->getDocComment() ? array(preg_replace('#^\s*\* ?#m', '', trim($from->getDocComment(), "/* \r\n\t"))) : array();
+ return $prop;
+ }
+
+
+ /**
+ * @param string without $
+ * @return self
+ */
+ public function setName($name)
+ {
+ $this->name = (string) $name;
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+
+ /**
+ * @return self
+ */
+ public function setValue($val)
+ {
+ $this->value = $val;
+ return $this;
+ }
+
+
+ /**
+ * @return mixed
+ */
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+
+ /**
+ * @param bool
+ * @return self
+ */
+ public function setStatic($state = TRUE)
+ {
+ $this->static = (bool) $state;
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isStatic()
+ {
+ return $this->static;
+ }
+
+
+ /**
+ * @param string public|protected|private
+ * @return self
+ */
+ public function setVisibility($val)
+ {
+ if (!in_array($val, array('public', 'protected', 'private'), TRUE)) {
+ throw new Nette\InvalidArgumentException('Argument must be public|protected|private.');
+ }
+ $this->visibility = (string) $val;
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getVisibility()
+ {
+ return $this->visibility;
+ }
+
+
+ /**
+ * @param string[]
+ * @return self
+ */
+ public function setDocuments(array $s)
+ {
+ $this->documents = $s;
+ return $this;
+ }
+
+
+ /**
+ * @return string[]
+ */
+ public function getDocuments()
+ {
+ return $this->documents;
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function addDocument($s)
+ {
+ $this->documents[] = (string) $s;
+ return $this;
+ }
+
+}
diff --git a/vendor/nette/reflection/composer.json b/vendor/nette/reflection/composer.json
new file mode 100755
index 0000000..339b07a
--- /dev/null
+++ b/vendor/nette/reflection/composer.json
@@ -0,0 +1,33 @@
+{
+ "name": "nette/reflection",
+ "description": "Nette PHP Reflection Component",
+ "homepage": "http://nette.org",
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.1",
+ "ext-tokenizer": "*",
+ "nette/caching": "~2.2",
+ "nette/utils": "~2.2"
+ },
+ "require-dev": {
+ "nette/di": "~2.3",
+ "nette/tester": "~1.4"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/reflection/license.md b/vendor/nette/reflection/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/reflection/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/reflection/src/Bridges/ReflectionDI/ReflectionExtension.php b/vendor/nette/reflection/src/Bridges/ReflectionDI/ReflectionExtension.php
new file mode 100755
index 0000000..f9e6067
--- /dev/null
+++ b/vendor/nette/reflection/src/Bridges/ReflectionDI/ReflectionExtension.php
@@ -0,0 +1,35 @@
+debugMode = $debugMode;
+ }
+
+
+ public function afterCompile(Nette\PhpGenerator\ClassType $class)
+ {
+ $class->getMethod('initialize')
+ ->addBody('Nette\Reflection\AnnotationsParser::setCacheStorage($this->getByType("Nette\Caching\IStorage"));')
+ ->addBody('Nette\Reflection\AnnotationsParser::$autoRefresh = ?;', array($this->debugMode));
+ }
+
+}
diff --git a/vendor/nette/reflection/src/Reflection/Annotation.php b/vendor/nette/reflection/src/Reflection/Annotation.php
new file mode 100755
index 0000000..03bb1cf
--- /dev/null
+++ b/vendor/nette/reflection/src/Reflection/Annotation.php
@@ -0,0 +1,36 @@
+ $v) {
+ $this->$k = $v;
+ }
+ }
+
+
+ /**
+ * Returns default annotation.
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->value;
+ }
+
+}
diff --git a/vendor/nette/reflection/src/Reflection/AnnotationsParser.php b/vendor/nette/reflection/src/Reflection/AnnotationsParser.php
new file mode 100755
index 0000000..e9d5d08
--- /dev/null
+++ b/vendor/nette/reflection/src/Reflection/AnnotationsParser.php
@@ -0,0 +1,410 @@
+getName();
+ $member = 'class';
+ $file = $r->getFileName();
+
+ } elseif ($r instanceof \ReflectionMethod) {
+ $type = $r->getDeclaringClass()->getName();
+ $member = $r->getName();
+ $file = $r->getFileName();
+
+ } elseif ($r instanceof \ReflectionFunction) {
+ $type = NULL;
+ $member = $r->getName();
+ $file = $r->getFileName();
+
+ } else {
+ $type = $r->getDeclaringClass()->getName();
+ $member = '$' . $r->getName();
+ $file = $r->getDeclaringClass()->getFileName();
+ }
+
+ if (!self::$useReflection) { // auto-expire cache
+ if ($file && isset(self::$timestamps[$file]) && self::$timestamps[$file] !== filemtime($file)) {
+ unset(self::$cache[$type]);
+ }
+ unset(self::$timestamps[$file]);
+ }
+
+ if (isset(self::$cache[$type][$member])) { // is value cached?
+ return self::$cache[$type][$member];
+ }
+
+ if (self::$useReflection === NULL) { // detects whether is reflection available
+ self::$useReflection = (bool) ClassType::from(__CLASS__)->getDocComment();
+ }
+
+ if (self::$useReflection) {
+ $annotations = self::parseComment($r->getDocComment());
+
+ } else {
+ $outerCache = self::getCache();
+
+ if (self::$cache === NULL) {
+ self::$cache = (array) $outerCache->load('list');
+ self::$timestamps = isset(self::$cache['*']) ? self::$cache['*'] : array();
+ }
+
+ if (!isset(self::$cache[$type]) && $file) {
+ self::$cache['*'][$file] = filemtime($file);
+ foreach (static::parsePhp(file_get_contents($file)) as $class => $info) {
+ foreach ($info as $prop => $comment) {
+ if ($prop !== 'use') {
+ self::$cache[$class][$prop] = self::parseComment($comment);
+ }
+ }
+ }
+ $outerCache->save('list', self::$cache);
+ }
+
+ if (isset(self::$cache[$type][$member])) {
+ $annotations = self::$cache[$type][$member];
+ } else {
+ $annotations = array();
+ }
+ }
+
+ if ($r instanceof \ReflectionMethod && !$r->isPrivate()
+ && (!$r->isConstructor() || !empty($annotations['inheritdoc'][0]))
+ ) {
+ try {
+ $inherited = self::getAll(new \ReflectionMethod(get_parent_class($type), $member));
+ } catch (\ReflectionException $e) {
+ try {
+ $inherited = self::getAll($r->getPrototype());
+ } catch (\ReflectionException $e) {
+ $inherited = array();
+ }
+ }
+ $annotations += array_intersect_key($inherited, array_flip(self::$inherited));
+ }
+
+ return self::$cache[$type][$member] = $annotations;
+ }
+
+
+ /**
+ * Expands class name into FQN.
+ * @param string
+ * @return string fully qualified class name
+ * @throws Nette\InvalidArgumentException
+ */
+ public static function expandClassName($name, \ReflectionClass $reflector)
+ {
+ if (empty($name)) {
+ throw new Nette\InvalidArgumentException('Class name must not be empty.');
+
+ } elseif ($name === 'self') {
+ return $reflector->getName();
+
+ } elseif ($name[0] === '\\') { // already fully qualified
+ return ltrim($name, '\\');
+ }
+
+ $filename = $reflector->getFileName();
+ $parsed = static::getCache()->load($filename, function (& $dp) use ($filename) {
+ if (AnnotationsParser::$autoRefresh) {
+ $dp[Nette\Caching\Cache::FILES] = $filename;
+ }
+ return AnnotationsParser::parsePhp(file_get_contents($filename));
+ });
+ $uses = array_change_key_case((array) $tmp = & $parsed[$reflector->getName()]['use']);
+ $parts = explode('\\', $name, 2);
+ $parts[0] = strtolower($parts[0]);
+ if (isset($uses[$parts[0]])) {
+ $parts[0] = $uses[$parts[0]];
+ return implode('\\', $parts);
+
+ } elseif ($reflector->inNamespace()) {
+ return $reflector->getNamespaceName() . '\\' . $name;
+
+ } else {
+ return $name;
+ }
+ }
+
+
+ /**
+ * Parses phpDoc comment.
+ * @param string
+ * @return array
+ */
+ private static function parseComment($comment)
+ {
+ static $tokens = array('true' => TRUE, 'false' => FALSE, 'null' => NULL, '' => TRUE);
+
+ $res = array();
+ $comment = preg_replace('#^\s*\*\s?#ms', '', trim($comment, '/*'));
+ $parts = preg_split('#^\s*(?=@'.self::RE_IDENTIFIER.')#m', $comment, 2);
+
+ $description = trim($parts[0]);
+ if ($description !== '') {
+ $res['description'] = array($description);
+ }
+
+ $matches = Strings::matchAll(
+ isset($parts[1]) ? $parts[1] : '',
+ '~
+ (?<=\s|^)@('.self::RE_IDENTIFIER.')[ \t]* ## annotation
+ (
+ \((?>'.self::RE_STRING.'|[^\'")@]+)+\)| ## (value)
+ [^(@\r\n][^@\r\n]*|) ## value
+ ~xi'
+ );
+
+ foreach ($matches as $match) {
+ list(, $name, $value) = $match;
+
+ if (substr($value, 0, 1) === '(') {
+ $items = array();
+ $key = '';
+ $val = TRUE;
+ $value[0] = ',';
+ while ($m = Strings::match(
+ $value,
+ '#\s*,\s*(?>(' . self::RE_IDENTIFIER . ')\s*=\s*)?(' . self::RE_STRING . '|[^\'"),\s][^\'"),]*)#A')
+ ) {
+ $value = substr($value, strlen($m[0]));
+ list(, $key, $val) = $m;
+ $val = rtrim($val);
+ if ($val[0] === "'" || $val[0] === '"') {
+ $val = substr($val, 1, -1);
+
+ } elseif (is_numeric($val)) {
+ $val = 1 * $val;
+
+ } else {
+ $lval = strtolower($val);
+ $val = array_key_exists($lval, $tokens) ? $tokens[$lval] : $val;
+ }
+
+ if ($key === '') {
+ $items[] = $val;
+
+ } else {
+ $items[$key] = $val;
+ }
+ }
+
+ $value = count($items) < 2 && $key === '' ? $val : $items;
+
+ } else {
+ $value = trim($value);
+ if (is_numeric($value)) {
+ $value = 1 * $value;
+
+ } else {
+ $lval = strtolower($value);
+ $value = array_key_exists($lval, $tokens) ? $tokens[$lval] : $value;
+ }
+ }
+
+ $res[$name][] = is_array($value) ? Nette\Utils\ArrayHash::from($value) : $value;
+ }
+
+ return $res;
+ }
+
+
+ /**
+ * Parses PHP file.
+ * @param string
+ * @return array [class => [prop => comment (or 'use' => [alias => class])]
+ * @internal
+ */
+ public static function parsePhp($code)
+ {
+ if (Strings::match($code, '#//nette'.'loader=(\S*)#')) {
+ return;
+ }
+
+ $tokens = @token_get_all($code);
+ $namespace = $class = $classLevel = $level = $docComment = NULL;
+ $res = $uses = array();
+
+ while (list(, $token) = each($tokens)) {
+ switch (is_array($token) ? $token[0] : $token) {
+ case T_DOC_COMMENT:
+ $docComment = $token[1];
+ break;
+
+ case T_NAMESPACE:
+ $namespace = self::fetch($tokens, array(T_STRING, T_NS_SEPARATOR)) . '\\';
+ $uses = array();
+ break;
+
+ case T_CLASS:
+ case T_INTERFACE:
+ case PHP_VERSION_ID < 50400 ? -1 : T_TRAIT:
+ if ($name = self::fetch($tokens, T_STRING)) {
+ $class = $namespace . $name;
+ $classLevel = $level + 1;
+ if ($docComment) {
+ $res[$class]['class'] = $docComment;
+ }
+ if ($uses) {
+ $res[$class]['use'] = $uses;
+ }
+ }
+ break;
+
+ case T_FUNCTION:
+ self::fetch($tokens, '&');
+ if ($level === $classLevel && $docComment && ($name = self::fetch($tokens, T_STRING))) {
+ $res[$class][$name] = $docComment;
+ }
+ break;
+
+ case T_VAR:
+ case T_PUBLIC:
+ case T_PROTECTED:
+ self::fetch($tokens, T_STATIC);
+ if ($level === $classLevel && $docComment && ($name = self::fetch($tokens, T_VARIABLE))) {
+ $res[$class][$name] = $docComment;
+ }
+ break;
+
+ case T_USE:
+ while (!$class && ($name = self::fetch($tokens, array(T_STRING, T_NS_SEPARATOR)))) {
+ if (self::fetch($tokens, T_AS)) {
+ $uses[self::fetch($tokens, T_STRING)] = ltrim($name, '\\');
+ } else {
+ $tmp = explode('\\', $name);
+ $uses[end($tmp)] = $name;
+ }
+ if (!self::fetch($tokens, ',')) {
+ break;
+ }
+ }
+ break;
+
+ case T_CURLY_OPEN:
+ case T_DOLLAR_OPEN_CURLY_BRACES:
+ case '{':
+ $level++;
+ break;
+
+ case '}':
+ if ($level === $classLevel) {
+ $class = $classLevel = NULL;
+ }
+ $level--;
+ // break omitted
+ case ';':
+ $docComment = NULL;
+ }
+ }
+
+ return $res;
+ }
+
+
+ private static function fetch(& $tokens, $take)
+ {
+ $res = NULL;
+ while ($token = current($tokens)) {
+ list($token, $s) = is_array($token) ? $token : array($token, $token);
+ if (in_array($token, (array) $take, TRUE)) {
+ $res .= $s;
+ } elseif (!in_array($token, array(T_DOC_COMMENT, T_WHITESPACE, T_COMMENT), TRUE)) {
+ break;
+ }
+ next($tokens);
+ }
+ return $res;
+ }
+
+
+ /********************* backend ****************d*g**/
+
+
+ /**
+ * @return void
+ */
+ public static function setCacheStorage(Nette\Caching\IStorage $storage)
+ {
+ self::$cacheStorage = $storage;
+ }
+
+
+ /**
+ * @return Nette\Caching\IStorage
+ */
+ public static function getCacheStorage()
+ {
+ if (!self::$cacheStorage) {
+ self::$cacheStorage = new Nette\Caching\Storages\MemoryStorage();
+ }
+ return self::$cacheStorage;
+ }
+
+
+ /**
+ * @return Nette\Caching\Cache
+ */
+ private static function getCache()
+ {
+ return new Nette\Caching\Cache(static::getCacheStorage(), 'Nette.Reflection.Annotations');
+ }
+
+}
diff --git a/vendor/nette/reflection/src/Reflection/ClassType.php b/vendor/nette/reflection/src/Reflection/ClassType.php
new file mode 100755
index 0000000..0fe285d
--- /dev/null
+++ b/vendor/nette/reflection/src/Reflection/ClassType.php
@@ -0,0 +1,239 @@
+getName();
+ }
+
+
+ /**
+ * @param string
+ * @return bool
+ */
+ public function is($type)
+ {
+ return $this->isSubclassOf($type) || strcasecmp($this->getName(), ltrim($type, '\\')) === 0;
+ }
+
+
+ /********************* Reflection layer ****************d*g**/
+
+
+ /**
+ * @return Method|NULL
+ */
+ public function getConstructor()
+ {
+ return ($ref = parent::getConstructor()) ? Method::from($this->getName(), $ref->getName()) : NULL;
+ }
+
+
+ /**
+ * @return Extension|NULL
+ */
+ public function getExtension()
+ {
+ return ($name = $this->getExtensionName()) ? new Extension($name) : NULL;
+ }
+
+
+ /**
+ * @return self[]
+ */
+ public function getInterfaces()
+ {
+ $res = array();
+ foreach (parent::getInterfaceNames() as $val) {
+ $res[$val] = new static($val);
+ }
+ return $res;
+ }
+
+
+ /**
+ * @return Method
+ */
+ public function getMethod($name)
+ {
+ return new Method($this->getName(), $name);
+ }
+
+
+ /**
+ * @return Method[]
+ */
+ public function getMethods($filter = -1)
+ {
+ foreach ($res = parent::getMethods($filter) as $key => $val) {
+ $res[$key] = new Method($this->getName(), $val->getName());
+ }
+ return $res;
+ }
+
+
+ /**
+ * @return self|NULL
+ */
+ public function getParentClass()
+ {
+ return ($ref = parent::getParentClass()) ? new static($ref->getName()) : NULL;
+ }
+
+
+ /**
+ * @return Property[]
+ */
+ public function getProperties($filter = -1)
+ {
+ foreach ($res = parent::getProperties($filter) as $key => $val) {
+ $res[$key] = new Property($this->getName(), $val->getName());
+ }
+ return $res;
+ }
+
+
+ /**
+ * @return Property
+ */
+ public function getProperty($name)
+ {
+ return new Property($this->getName(), $name);
+ }
+
+
+ /********************* Nette\Annotations support ****************d*g**/
+
+
+ /**
+ * Has class specified annotation?
+ * @param string
+ * @return bool
+ */
+ public function hasAnnotation($name)
+ {
+ $res = AnnotationsParser::getAll($this);
+ return !empty($res[$name]);
+ }
+
+
+ /**
+ * Returns an annotation value.
+ * @param string
+ * @return IAnnotation
+ */
+ public function getAnnotation($name)
+ {
+ $res = AnnotationsParser::getAll($this);
+ return isset($res[$name]) ? end($res[$name]) : NULL;
+ }
+
+
+ /**
+ * Returns all annotations.
+ * @return IAnnotation[][]
+ */
+ public function getAnnotations()
+ {
+ return AnnotationsParser::getAll($this);
+ }
+
+
+ /**
+ * Returns value of annotation 'description'.
+ * @return string
+ */
+ public function getDescription()
+ {
+ return $this->getAnnotation('description');
+ }
+
+
+ /********************* Nette\Object behaviour ****************d*g**/
+
+
+ public function __call($name, $args)
+ {
+ return ObjectMixin::call($this, $name, $args);
+ }
+
+
+ public function &__get($name)
+ {
+ return ObjectMixin::get($this, $name);
+ }
+
+
+ public function __set($name, $value)
+ {
+ ObjectMixin::set($this, $name, $value);
+ }
+
+
+ public function __isset($name)
+ {
+ return ObjectMixin::has($this, $name);
+ }
+
+
+ public function __unset($name)
+ {
+ ObjectMixin::remove($this, $name);
+ }
+
+}
diff --git a/vendor/nette/reflection/src/Reflection/Extension.php b/vendor/nette/reflection/src/Reflection/Extension.php
new file mode 100755
index 0000000..fdd5f46
--- /dev/null
+++ b/vendor/nette/reflection/src/Reflection/Extension.php
@@ -0,0 +1,80 @@
+getName();
+ }
+
+
+ /********************* Reflection layer ****************d*g**/
+
+
+ public function getClasses()
+ {
+ $res = array();
+ foreach (parent::getClassNames() as $val) {
+ $res[$val] = new ClassType($val);
+ }
+ return $res;
+ }
+
+
+ public function getFunctions()
+ {
+ foreach ($res = parent::getFunctions() as $key => $val) {
+ $res[$key] = new GlobalFunction($key);
+ }
+ return $res;
+ }
+
+
+ /********************* Nette\Object behaviour ****************d*g**/
+
+
+ public function __call($name, $args)
+ {
+ return ObjectMixin::call($this, $name, $args);
+ }
+
+
+ public function &__get($name)
+ {
+ return ObjectMixin::get($this, $name);
+ }
+
+
+ public function __set($name, $value)
+ {
+ ObjectMixin::set($this, $name, $value);
+ }
+
+
+ public function __isset($name)
+ {
+ return ObjectMixin::has($this, $name);
+ }
+
+
+ public function __unset($name)
+ {
+ ObjectMixin::remove($this, $name);
+ }
+
+}
diff --git a/vendor/nette/reflection/src/Reflection/GlobalFunction.php b/vendor/nette/reflection/src/Reflection/GlobalFunction.php
new file mode 100755
index 0000000..56ee41b
--- /dev/null
+++ b/vendor/nette/reflection/src/Reflection/GlobalFunction.php
@@ -0,0 +1,174 @@
+value = $name);
+ }
+
+
+ /**
+ * @deprecated
+ */
+ public function toCallback()
+ {
+ return new Nette\Callback($this->value);
+ }
+
+
+ public function __toString()
+ {
+ return $this->getName() . '()';
+ }
+
+
+ public function getClosure()
+ {
+ return PHP_VERSION_ID < 50400
+ ? Nette\Utils\Callback::closure($this->value)
+ : parent::getClosure();
+ }
+
+
+ /********************* Reflection layer ****************d*g**/
+
+
+ /**
+ * @return Extension
+ */
+ public function getExtension()
+ {
+ return ($name = $this->getExtensionName()) ? new Extension($name) : NULL;
+ }
+
+
+ /**
+ * @return Parameter[]
+ */
+ public function getParameters()
+ {
+ foreach ($res = parent::getParameters() as $key => $val) {
+ $res[$key] = new Parameter($this->value, $val->getName());
+ }
+ return $res;
+ }
+
+
+ /********************* Nette\Annotations support ****************d*g**/
+
+
+ /**
+ * Has method specified annotation?
+ * @param string
+ * @return bool
+ */
+ public function hasAnnotation($name)
+ {
+ $res = AnnotationsParser::getAll($this);
+ return !empty($res[$name]);
+ }
+
+
+ /**
+ * Returns an annotation value.
+ * @param string
+ * @return IAnnotation
+ */
+ public function getAnnotation($name)
+ {
+ $res = AnnotationsParser::getAll($this);
+ return isset($res[$name]) ? end($res[$name]) : NULL;
+ }
+
+
+ /**
+ * Returns all annotations.
+ * @return IAnnotation[][]
+ */
+ public function getAnnotations()
+ {
+ return AnnotationsParser::getAll($this);
+ }
+
+
+ /**
+ * Returns value of annotation 'description'.
+ * @return string
+ */
+ public function getDescription()
+ {
+ return $this->getAnnotation('description');
+ }
+
+
+ /********************* Nette\Object behaviour ****************d*g**/
+
+
+ public function __call($name, $args)
+ {
+ return ObjectMixin::call($this, $name, $args);
+ }
+
+
+ public function &__get($name)
+ {
+ return ObjectMixin::get($this, $name);
+ }
+
+
+ public function __set($name, $value)
+ {
+ ObjectMixin::set($this, $name, $value);
+ }
+
+
+ public function __isset($name)
+ {
+ return ObjectMixin::has($this, $name);
+ }
+
+
+ public function __unset($name)
+ {
+ ObjectMixin::remove($this, $name);
+ }
+
+}
diff --git a/vendor/nette/reflection/src/Reflection/Helpers.php b/vendor/nette/reflection/src/Reflection/Helpers.php
new file mode 100755
index 0000000..9d88868
--- /dev/null
+++ b/vendor/nette/reflection/src/Reflection/Helpers.php
@@ -0,0 +1,31 @@
+= 50400) {
+ foreach ($prop->getDeclaringClass()->getTraits() as $trait) {
+ if ($trait->hasProperty($prop->getName())) {
+ return self::getDeclaringClass($trait->getProperty($prop->getName()));
+ }
+ }
+ }
+ return $prop->getDeclaringClass();
+ }
+
+}
diff --git a/vendor/nette/reflection/src/Reflection/IAnnotation.php b/vendor/nette/reflection/src/Reflection/IAnnotation.php
new file mode 100755
index 0000000..63fa97c
--- /dev/null
+++ b/vendor/nette/reflection/src/Reflection/IAnnotation.php
@@ -0,0 +1,19 @@
+getName(), $this->getName());
+ }
+
+
+ public function __toString()
+ {
+ return parent::getDeclaringClass()->getName() . '::' . $this->getName() . '()';
+ }
+
+
+ public function getClosure($object = NULL)
+ {
+ return PHP_VERSION_ID < 50400
+ ? Nette\Utils\Callback::closure($object ?: parent::getDeclaringClass()->getName(), $this->getName())
+ : parent::getClosure($object);
+ }
+
+
+ /********************* Reflection layer ****************d*g**/
+
+
+ /**
+ * @return ClassType
+ */
+ public function getDeclaringClass()
+ {
+ return new ClassType(parent::getDeclaringClass()->getName());
+ }
+
+
+ /**
+ * @return Method
+ */
+ public function getPrototype()
+ {
+ $prototype = parent::getPrototype();
+ return new self($prototype->getDeclaringClass()->getName(), $prototype->getName());
+ }
+
+
+ /**
+ * @return Extension
+ */
+ public function getExtension()
+ {
+ return ($name = $this->getExtensionName()) ? new Extension($name) : NULL;
+ }
+
+
+ /**
+ * @return Parameter[]
+ */
+ public function getParameters()
+ {
+ $me = array(parent::getDeclaringClass()->getName(), $this->getName());
+ foreach ($res = parent::getParameters() as $key => $val) {
+ $res[$key] = new Parameter($me, $val->getName());
+ }
+ return $res;
+ }
+
+
+ /********************* Nette\Annotations support ****************d*g**/
+
+
+ /**
+ * Has method specified annotation?
+ * @param string
+ * @return bool
+ */
+ public function hasAnnotation($name)
+ {
+ $res = AnnotationsParser::getAll($this);
+ return !empty($res[$name]);
+ }
+
+
+ /**
+ * Returns an annotation value.
+ * @param string
+ * @return IAnnotation
+ */
+ public function getAnnotation($name)
+ {
+ $res = AnnotationsParser::getAll($this);
+ return isset($res[$name]) ? end($res[$name]) : NULL;
+ }
+
+
+ /**
+ * Returns all annotations.
+ * @return IAnnotation[][]
+ */
+ public function getAnnotations()
+ {
+ return AnnotationsParser::getAll($this);
+ }
+
+
+ /**
+ * Returns value of annotation 'description'.
+ * @return string
+ */
+ public function getDescription()
+ {
+ return $this->getAnnotation('description');
+ }
+
+
+ /********************* Nette\Object behaviour ****************d*g**/
+
+
+ public function __call($name, $args)
+ {
+ return ObjectMixin::call($this, $name, $args);
+ }
+
+
+ public function &__get($name)
+ {
+ return ObjectMixin::get($this, $name);
+ }
+
+
+ public function __set($name, $value)
+ {
+ ObjectMixin::set($this, $name, $value);
+ }
+
+
+ public function __isset($name)
+ {
+ return ObjectMixin::has($this, $name);
+ }
+
+
+ public function __unset($name)
+ {
+ ObjectMixin::remove($this, $name);
+ }
+
+}
diff --git a/vendor/nette/reflection/src/Reflection/Parameter.php b/vendor/nette/reflection/src/Reflection/Parameter.php
new file mode 100755
index 0000000..ac0ffa9
--- /dev/null
+++ b/vendor/nette/reflection/src/Reflection/Parameter.php
@@ -0,0 +1,140 @@
+function = $function, $parameter);
+ }
+
+
+ /**
+ * @return ClassType
+ */
+ public function getClass()
+ {
+ return ($ref = parent::getClass()) ? new ClassType($ref->getName()) : NULL;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getClassName()
+ {
+ try {
+ return ($ref = parent::getClass()) ? $ref->getName() : NULL;
+ } catch (\ReflectionException $e) {
+ if (preg_match('#Class (.+) does not exist#', $e->getMessage(), $m)) {
+ return $m[1];
+ }
+ throw $e;
+ }
+ }
+
+
+ /**
+ * @return ClassType
+ */
+ public function getDeclaringClass()
+ {
+ return ($ref = parent::getDeclaringClass()) ? new ClassType($ref->getName()) : NULL;
+ }
+
+
+ /**
+ * @return Method|GlobalFunction
+ */
+ public function getDeclaringFunction()
+ {
+ return is_array($this->function)
+ ? new Method($this->function[0], $this->function[1])
+ : new GlobalFunction($this->function);
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isDefaultValueAvailable()
+ {
+ if (PHP_VERSION_ID === 50316) { // PHP bug #62988
+ try {
+ $this->getDefaultValue();
+ return TRUE;
+ } catch (\ReflectionException $e) {
+ return FALSE;
+ }
+ }
+ return parent::isDefaultValueAvailable();
+ }
+
+
+ public function __toString()
+ {
+ return '$' . parent::getName() . ' in ' . $this->getDeclaringFunction();
+ }
+
+
+ /********************* Nette\Object behaviour ****************d*g**/
+
+
+ public function __call($name, $args)
+ {
+ return ObjectMixin::call($this, $name, $args);
+ }
+
+
+ public function &__get($name)
+ {
+ return ObjectMixin::get($this, $name);
+ }
+
+
+ public function __set($name, $value)
+ {
+ ObjectMixin::set($this, $name, $value);
+ }
+
+
+ public function __isset($name)
+ {
+ return ObjectMixin::has($this, $name);
+ }
+
+
+ public function __unset($name)
+ {
+ ObjectMixin::remove($this, $name);
+ }
+
+}
diff --git a/vendor/nette/reflection/src/Reflection/Property.php b/vendor/nette/reflection/src/Reflection/Property.php
new file mode 100755
index 0000000..e098057
--- /dev/null
+++ b/vendor/nette/reflection/src/Reflection/Property.php
@@ -0,0 +1,130 @@
+getName() . '::$' . $this->getName();
+ }
+
+
+ /********************* Reflection layer ****************d*g**/
+
+
+ /**
+ * @return ClassType
+ */
+ public function getDeclaringClass()
+ {
+ return new ClassType(parent::getDeclaringClass()->getName());
+ }
+
+
+ /********************* Nette\Annotations support ****************d*g**/
+
+
+ /**
+ * Has property specified annotation?
+ * @param string
+ * @return bool
+ */
+ public function hasAnnotation($name)
+ {
+ $res = AnnotationsParser::getAll($this);
+ return !empty($res[$name]);
+ }
+
+
+ /**
+ * Returns an annotation value.
+ * @param string
+ * @return IAnnotation
+ */
+ public function getAnnotation($name)
+ {
+ $res = AnnotationsParser::getAll($this);
+ return isset($res[$name]) ? end($res[$name]) : NULL;
+ }
+
+
+ /**
+ * Returns all annotations.
+ * @return IAnnotation[][]
+ */
+ public function getAnnotations()
+ {
+ return AnnotationsParser::getAll($this);
+ }
+
+
+ /**
+ * Returns value of annotation 'description'.
+ * @return string
+ */
+ public function getDescription()
+ {
+ return $this->getAnnotation('description');
+ }
+
+
+ /********************* Nette\Object behaviour ****************d*g**/
+
+
+ public function __call($name, $args)
+ {
+ return ObjectMixin::call($this, $name, $args);
+ }
+
+
+ public function &__get($name)
+ {
+ return ObjectMixin::get($this, $name);
+ }
+
+
+ public function __set($name, $value)
+ {
+ ObjectMixin::set($this, $name, $value);
+ }
+
+
+ public function __isset($name)
+ {
+ return ObjectMixin::has($this, $name);
+ }
+
+
+ public function __unset($name)
+ {
+ ObjectMixin::remove($this, $name);
+ }
+
+}
diff --git a/vendor/nette/robot-loader/composer.json b/vendor/nette/robot-loader/composer.json
new file mode 100755
index 0000000..e1fa2e0
--- /dev/null
+++ b/vendor/nette/robot-loader/composer.json
@@ -0,0 +1,32 @@
+{
+ "name": "nette/robot-loader",
+ "description": "Nette RobotLoader: comfortable autoloading",
+ "homepage": "http://nette.org",
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.1",
+ "nette/caching": "~2.2",
+ "nette/finder": "~2.3",
+ "nette/utils": "~2.2"
+ },
+ "require-dev": {
+ "nette/tester": "~1.4"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/robot-loader/license.md b/vendor/nette/robot-loader/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/robot-loader/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php b/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php
new file mode 100755
index 0000000..9576633
--- /dev/null
+++ b/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php
@@ -0,0 +1,381 @@
+ [file, time, orig] or num-of-retry */
+ private $classes = array();
+
+ /** @var bool */
+ private $rebuilt = FALSE;
+
+ /** @var array of missing classes in this request */
+ private $missing = array();
+
+ /** @var Nette\Caching\IStorage */
+ private $cacheStorage;
+
+
+ public function __construct()
+ {
+ if (!extension_loaded('tokenizer')) {
+ throw new Nette\NotSupportedException('PHP extension Tokenizer is not loaded.');
+ }
+ }
+
+
+ /**
+ * Register autoloader.
+ * @param bool prepend autoloader?
+ * @return self
+ */
+ public function register($prepend = FALSE)
+ {
+ $this->classes = $this->getCache()->load($this->getKey(), array($this, 'rebuildCallback'));
+ spl_autoload_register(array($this, 'tryLoad'), TRUE, (bool) $prepend);
+ return $this;
+ }
+
+
+ /**
+ * Handles autoloading of classes, interfaces or traits.
+ * @param string
+ * @return void
+ */
+ public function tryLoad($type)
+ {
+ $type = $orig = ltrim($type, '\\'); // PHP namespace bug #49143
+ $type = strtolower($type);
+
+ $info = & $this->classes[$type];
+ if (isset($this->missing[$type]) || (is_int($info) && $info >= self::RETRY_LIMIT)) {
+ return;
+ }
+
+ if ($this->autoRebuild) {
+ if (!is_array($info) || !is_file($info['file'])) {
+ $info = is_int($info) ? $info + 1 : 0;
+ if ($this->rebuilt) {
+ $this->getCache()->save($this->getKey(), $this->classes);
+ } else {
+ $this->rebuild();
+ }
+ } elseif (!$this->rebuilt && filemtime($info['file']) !== $info['time']) {
+ $this->updateFile($info['file']);
+ if (!isset($this->classes[$type])) {
+ $this->classes[$type] = 0;
+ }
+ $this->getCache()->save($this->getKey(), $this->classes);
+ }
+ }
+
+ if (isset($this->classes[$type]['file'])) {
+ if ($this->classes[$type]['orig'] !== $orig) {
+ trigger_error("Case mismatch on class name '$orig', correct name is '{$this->classes[$type]['orig']}'.", E_USER_WARNING);
+ }
+ call_user_func(function ($file) { require $file; }, $this->classes[$type]['file']);
+ } else {
+ $this->missing[$type] = TRUE;
+ }
+ }
+
+
+ /**
+ * Add path or paths to list.
+ * @param string|string[] absolute path
+ * @return self
+ */
+ public function addDirectory($path)
+ {
+ $this->scanPaths = array_merge($this->scanPaths, (array) $path);
+ return $this;
+ }
+
+
+ /**
+ * @return array of class => filename
+ */
+ public function getIndexedClasses()
+ {
+ $res = array();
+ foreach ($this->classes as $info) {
+ if (is_array($info)) {
+ $res[$info['orig']] = $info['file'];
+ }
+ }
+ return $res;
+ }
+
+
+ /**
+ * Rebuilds class list cache.
+ * @return void
+ */
+ public function rebuild()
+ {
+ $this->rebuilt = TRUE; // prevents calling rebuild() or updateFile() in tryLoad()
+ $this->getCache()->save($this->getKey(), Nette\Utils\Callback::closure($this, 'rebuildCallback'));
+ }
+
+
+ /**
+ * @internal
+ */
+ public function rebuildCallback()
+ {
+ $files = $missing = array();
+ foreach ($this->classes as $class => $info) {
+ if (is_array($info)) {
+ $files[$info['file']]['time'] = $info['time'];
+ $files[$info['file']]['classes'][] = $info['orig'];
+ } else {
+ $missing[$class] = $info;
+ }
+ }
+
+ $this->classes = array();
+ foreach ($this->scanPaths as $path) {
+ foreach (is_file($path) ? array(new SplFileInfo($path)) : $this->createFileIterator($path) as $file) {
+ $file = $file->getPathname();
+ if (isset($files[$file]) && $files[$file]['time'] == filemtime($file)) {
+ $classes = $files[$file]['classes'];
+ } else {
+ $classes = $this->scanPhp(file_get_contents($file));
+ }
+ $files[$file] = array('classes' => array(), 'time' => filemtime($file));
+
+ foreach ($classes as $class) {
+ $info = & $this->classes[strtolower($class)];
+ if (isset($info['file'])) {
+ throw new Nette\InvalidStateException("Ambiguous class $class resolution; defined in {$info['file']} and in $file.");
+ }
+ $info = array('file' => $file, 'time' => filemtime($file), 'orig' => $class);
+ }
+ }
+ }
+ $this->classes += $missing;
+ return $this->classes;
+ }
+
+
+ /**
+ * Creates an iterator scaning directory for PHP files, subdirectories and 'netterobots.txt' files.
+ * @return \Iterator
+ * @throws Nette\IOException if path is not found
+ */
+ private function createFileIterator($dir)
+ {
+ if (!is_dir($dir)) {
+ throw new Nette\IOException("File or directory '$dir' not found.");
+ }
+
+ $ignoreDirs = is_array($this->ignoreDirs) ? $this->ignoreDirs : preg_split('#[,\s]+#', $this->ignoreDirs);
+ $disallow = array();
+ foreach ($ignoreDirs as $item) {
+ if ($item = realpath($item)) {
+ $disallow[$item] = TRUE;
+ }
+ }
+
+ $iterator = Nette\Utils\Finder::findFiles(is_array($this->acceptFiles) ? $this->acceptFiles : preg_split('#[,\s]+#', $this->acceptFiles))
+ ->filter(function (SplFileInfo $file) use (& $disallow) {
+ return !isset($disallow[$file->getPathname()]);
+ })
+ ->from($dir)
+ ->exclude($ignoreDirs)
+ ->filter($filter = function (SplFileInfo $dir) use (& $disallow) {
+ $path = $dir->getPathname();
+ if (is_file("$path/netterobots.txt")) {
+ foreach (file("$path/netterobots.txt") as $s) {
+ if (preg_match('#^(?:disallow\\s*:)?\\s*(\\S+)#i', $s, $matches)) {
+ $disallow[$path . str_replace('/', DIRECTORY_SEPARATOR, rtrim('/' . ltrim($matches[1], '/'), '/'))] = TRUE;
+ }
+ }
+ }
+ return !isset($disallow[$path]);
+ });
+
+ $filter(new SplFileInfo($dir));
+ return $iterator;
+ }
+
+
+ /**
+ * @return void
+ */
+ private function updateFile($file)
+ {
+ foreach ($this->classes as $class => $info) {
+ if (isset($info['file']) && $info['file'] === $file) {
+ unset($this->classes[$class]);
+ }
+ }
+
+ if (is_file($file)) {
+ foreach ($this->scanPhp(file_get_contents($file)) as $class) {
+ $info = & $this->classes[strtolower($class)];
+ if (isset($info['file']) && @filemtime($info['file']) !== $info['time']) { // intentionally ==, file may not exists
+ $this->updateFile($info['file']);
+ $info = & $this->classes[strtolower($class)];
+ }
+ if (isset($info['file'])) {
+ throw new Nette\InvalidStateException("Ambiguous class $class resolution; defined in {$info['file']} and in $file.");
+ }
+ $info = array('file' => $file, 'time' => filemtime($file), 'orig' => $class);
+ }
+ }
+ }
+
+
+ /**
+ * Searches classes, interfaces and traits in PHP file.
+ * @param string
+ * @return array
+ */
+ private function scanPhp($code)
+ {
+ $T_TRAIT = PHP_VERSION_ID < 50400 ? -1 : T_TRAIT;
+
+ $expected = FALSE;
+ $namespace = '';
+ $level = $minLevel = 0;
+ $classes = array();
+
+ if (preg_match('#//nette'.'loader=(\S*)#', $code, $matches)) {
+ foreach (explode(',', $matches[1]) as $name) {
+ $classes[] = $name;
+ }
+ return $classes;
+ }
+
+ foreach (@token_get_all($code) as $token) { // intentionally @
+ if (is_array($token)) {
+ switch ($token[0]) {
+ case T_COMMENT:
+ case T_DOC_COMMENT:
+ case T_WHITESPACE:
+ continue 2;
+
+ case T_NS_SEPARATOR:
+ case T_STRING:
+ if ($expected) {
+ $name .= $token[1];
+ }
+ continue 2;
+
+ case T_NAMESPACE:
+ case T_CLASS:
+ case T_INTERFACE:
+ case $T_TRAIT:
+ $expected = $token[0];
+ $name = '';
+ continue 2;
+ case T_CURLY_OPEN:
+ case T_DOLLAR_OPEN_CURLY_BRACES:
+ $level++;
+ }
+ }
+
+ if ($expected) {
+ switch ($expected) {
+ case T_CLASS:
+ case T_INTERFACE:
+ case $T_TRAIT:
+ if ($name && $level === $minLevel) {
+ $classes[] = $namespace . $name;
+ }
+ break;
+
+ case T_NAMESPACE:
+ $namespace = $name ? $name . '\\' : '';
+ $minLevel = $token === '{' ? 1 : 0;
+ }
+
+ $expected = NULL;
+ }
+
+ if ($token === '{') {
+ $level++;
+ } elseif ($token === '}') {
+ $level--;
+ }
+ }
+ return $classes;
+ }
+
+
+ /********************* backend ****************d*g**/
+
+
+ /**
+ * @return RobotLoader
+ */
+ public function setCacheStorage(Nette\Caching\IStorage $storage)
+ {
+ $this->cacheStorage = $storage;
+ return $this;
+ }
+
+
+ /**
+ * @return Nette\Caching\IStorage
+ */
+ public function getCacheStorage()
+ {
+ return $this->cacheStorage;
+ }
+
+
+ /**
+ * @return Nette\Caching\Cache
+ */
+ protected function getCache()
+ {
+ if (!$this->cacheStorage) {
+ trigger_error('Missing cache storage.', E_USER_WARNING);
+ $this->cacheStorage = new Nette\Caching\Storages\DevNullStorage;
+ }
+ return new Cache($this->cacheStorage, 'Nette.RobotLoader');
+ }
+
+
+ /**
+ * @return string
+ */
+ protected function getKey()
+ {
+ return array($this->ignoreDirs, $this->acceptFiles, $this->scanPaths);
+ }
+
+}
diff --git a/vendor/nette/safe-stream/composer.json b/vendor/nette/safe-stream/composer.json
new file mode 100755
index 0000000..fe29464
--- /dev/null
+++ b/vendor/nette/safe-stream/composer.json
@@ -0,0 +1,34 @@
+{
+ "name": "nette/safe-stream",
+ "description": "Nette SafeStream: Atomic Operations",
+ "homepage": "http://nette.org",
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.1"
+ },
+ "require-dev": {
+ "nette/tester": "~1.0"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "files": ["src/loader.php"]
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.3-dev"
+ }
+ }
+}
diff --git a/vendor/nette/safe-stream/license.md b/vendor/nette/safe-stream/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/safe-stream/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/safe-stream/src/SafeStream/SafeStream.php b/vendor/nette/safe-stream/src/SafeStream/SafeStream.php
new file mode 100755
index 0000000..d58dfc2
--- /dev/null
+++ b/vendor/nette/safe-stream/src/SafeStream/SafeStream.php
@@ -0,0 +1,298 @@
+
+ * file_put_contents('nette.safe://myfile.txt', $content);
+ *
+ * $content = file_get_contents('nette.safe://myfile.txt');
+ *
+ * unlink('nette.safe://myfile.txt');
+ *
+ * @internal
+ */
+class SafeStream
+{
+ /** Name of stream protocol - nette.safe:// */
+ const PROTOCOL = 'nette.safe';
+
+ /** @var resource orignal file handle */
+ private $handle;
+
+ /** @var resource temporary file handle */
+ private $tempHandle;
+
+ /** @var string orignal file path */
+ private $file;
+
+ /** @var string temporary file path */
+ private $tempFile;
+
+ /** @var bool */
+ private $deleteFile;
+
+ /** @var bool error detected? */
+ private $writeError = FALSE;
+
+
+ /**
+ * Registers protocol 'nette.safe://'.
+ * @return bool
+ */
+ public static function register()
+ {
+ @stream_wrapper_unregister('safe'); // old protocol
+ stream_wrapper_register('safe', __CLASS__);
+ @stream_wrapper_unregister(self::PROTOCOL); // intentionally @
+ return stream_wrapper_register(self::PROTOCOL, __CLASS__);
+ }
+
+
+ /**
+ * Opens file.
+ * @param string file name with stream protocol
+ * @param string mode - see fopen()
+ * @param int STREAM_USE_PATH, STREAM_REPORT_ERRORS
+ * @return bool TRUE on success or FALSE on failure
+ */
+ public function stream_open($path, $mode, $options)
+ {
+ $path = substr($path, strpos($path, ':') + 3); // trim protocol nette.safe://
+
+ $flag = trim($mode, 'crwax+'); // text | binary mode
+ $mode = trim($mode, 'tb'); // mode
+ $use_path = (bool) (STREAM_USE_PATH & $options); // use include_path?
+
+ // open file
+ if ($mode === 'r') { // provides only isolation
+ return $this->checkAndLock($this->tempHandle = fopen($path, 'r'.$flag, $use_path), LOCK_SH);
+
+ } elseif ($mode === 'r+') {
+ if (!$this->checkAndLock($this->handle = fopen($path, 'r'.$flag, $use_path), LOCK_EX)) {
+ return FALSE;
+ }
+
+ } elseif ($mode[0] === 'x') {
+ if (!$this->checkAndLock($this->handle = fopen($path, 'x'.$flag, $use_path), LOCK_EX)) {
+ return FALSE;
+ }
+ $this->deleteFile = TRUE;
+
+ } elseif ($mode[0] === 'w' || $mode[0] === 'a' || $mode[0] === 'c') {
+ if ($this->checkAndLock($this->handle = @fopen($path, 'x'.$flag, $use_path), LOCK_EX)) { // intentionally @
+ $this->deleteFile = TRUE;
+
+ } elseif (!$this->checkAndLock($this->handle = fopen($path, 'a+'.$flag, $use_path), LOCK_EX)) {
+ return FALSE;
+ }
+
+ } else {
+ trigger_error("Unknown mode $mode", E_USER_WARNING);
+ return FALSE;
+ }
+
+ // create temporary file in the same directory to provide atomicity
+ $tmp = '~~' . lcg_value() . '.tmp';
+ if (!$this->tempHandle = fopen($path . $tmp, (strpos($mode, '+') ? 'x+' : 'x').$flag, $use_path)) {
+ $this->clean();
+ return FALSE;
+ }
+ $this->tempFile = realpath($path . $tmp);
+ $this->file = substr($this->tempFile, 0, -strlen($tmp));
+
+ // copy to temporary file
+ if ($mode === 'r+' || $mode[0] === 'a' || $mode[0] === 'c') {
+ $stat = fstat($this->handle);
+ fseek($this->handle, 0);
+ if (stream_copy_to_stream($this->handle, $this->tempHandle) !== $stat['size']) {
+ $this->clean();
+ return FALSE;
+ }
+
+ if ($mode[0] === 'a') { // emulate append mode
+ fseek($this->tempHandle, 0, SEEK_END);
+ }
+ }
+
+ return TRUE;
+ }
+
+
+ /**
+ * Checks handle and locks file.
+ * @return bool
+ */
+ private function checkAndLock($handle, $lock)
+ {
+ if (!$handle) {
+ return FALSE;
+
+ } elseif (!flock($handle, $lock)) {
+ fclose($handle);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+
+ /**
+ * Error destructor.
+ */
+ private function clean()
+ {
+ flock($this->handle, LOCK_UN);
+ fclose($this->handle);
+ if ($this->deleteFile) {
+ unlink($this->file);
+ }
+ if ($this->tempHandle) {
+ fclose($this->tempHandle);
+ unlink($this->tempFile);
+ }
+ }
+
+
+ /**
+ * Closes file.
+ * @return void
+ */
+ public function stream_close()
+ {
+ if (!$this->tempFile) { // 'r' mode
+ flock($this->tempHandle, LOCK_UN);
+ fclose($this->tempHandle);
+ return;
+ }
+
+ flock($this->handle, LOCK_UN);
+ fclose($this->handle);
+ fclose($this->tempHandle);
+
+ if ($this->writeError || !rename($this->tempFile, $this->file)) { // try to rename temp file
+ unlink($this->tempFile); // otherwise delete temp file
+ if ($this->deleteFile) {
+ unlink($this->file);
+ }
+ }
+ }
+
+
+ /**
+ * Reads up to length bytes from the file.
+ * @param int length
+ * @return string
+ */
+ public function stream_read($length)
+ {
+ return fread($this->tempHandle, $length);
+ }
+
+
+ /**
+ * Writes the string to the file.
+ * @param string data to write
+ * @return int number of bytes that were successfully stored
+ */
+ public function stream_write($data)
+ {
+ $len = strlen($data);
+ $res = fwrite($this->tempHandle, $data, $len);
+
+ if ($res !== $len) { // disk full?
+ $this->writeError = TRUE;
+ }
+
+ return $res;
+ }
+
+
+ /**
+ * Truncates a file to a given length.
+ * @param int The size to truncate to.
+ * @return bool
+ */
+ public function stream_truncate($size)
+ {
+ return ftruncate($this->tempHandle, $size);
+ }
+
+
+ /**
+ * Returns the position of the file.
+ * @return int
+ */
+ public function stream_tell()
+ {
+ return ftell($this->tempHandle);
+ }
+
+
+ /**
+ * Returns TRUE if the file pointer is at end-of-file.
+ * @return bool
+ */
+ public function stream_eof()
+ {
+ return feof($this->tempHandle);
+ }
+
+
+ /**
+ * Sets the file position indicator for the file.
+ * @param int position
+ * @param int see fseek()
+ * @return int Return TRUE on success
+ */
+ public function stream_seek($offset, $whence)
+ {
+ return fseek($this->tempHandle, $offset, $whence) === 0; // ???
+ }
+
+
+ /**
+ * Gets information about a file referenced by $this->tempHandle.
+ * @return array
+ */
+ public function stream_stat()
+ {
+ return fstat($this->tempHandle);
+ }
+
+
+ /**
+ * Gets information about a file referenced by filename.
+ * @param string file name
+ * @param int STREAM_URL_STAT_LINK, STREAM_URL_STAT_QUIET
+ * @return array
+ */
+ public function url_stat($path, $flags)
+ {
+ // This is not thread safe
+ $path = substr($path, strpos($path, ':') + 3);
+ return ($flags & STREAM_URL_STAT_LINK) ? @lstat($path) : @stat($path); // intentionally @
+ }
+
+
+ /**
+ * Deletes a file.
+ * On Windows unlink is not allowed till file is opened
+ * @param string file name with stream protocol
+ * @return bool TRUE on success or FALSE on failure
+ */
+ public function unlink($path)
+ {
+ $path = substr($path, strpos($path, ':') + 3);
+ return unlink($path);
+ }
+
+}
diff --git a/vendor/nette/safe-stream/src/loader.php b/vendor/nette/safe-stream/src/loader.php
new file mode 100755
index 0000000..c5070f8
--- /dev/null
+++ b/vendor/nette/safe-stream/src/loader.php
@@ -0,0 +1,5 @@
+=5.3.1",
+ "nette/utils": "~2.2"
+ },
+ "require-dev": {
+ "nette/di": "~2.3",
+ "nette/http": "~2.3",
+ "nette/tester": "~1.4"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/security/license.md b/vendor/nette/security/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/security/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/security/src/Bridges/SecurityDI/SecurityExtension.php b/vendor/nette/security/src/Bridges/SecurityDI/SecurityExtension.php
new file mode 100755
index 0000000..afc27cb
--- /dev/null
+++ b/vendor/nette/security/src/Bridges/SecurityDI/SecurityExtension.php
@@ -0,0 +1,94 @@
+ TRUE,
+ 'users' => array(), // of [user => password] or [user => ['password' => password, 'roles' => [role]]]
+ 'roles' => array(), // of [role => parents]
+ 'resources' => array(), // of [resource => parents]
+ );
+
+ /** @var bool */
+ private $debugMode;
+
+
+ public function __construct($debugMode = FALSE)
+ {
+ $this->debugMode = $debugMode;
+ }
+
+
+ public function loadConfiguration()
+ {
+ $config = $this->validateConfig($this->defaults);
+ $container = $this->getContainerBuilder();
+
+ $container->addDefinition($this->prefix('userStorage'))
+ ->setClass('Nette\Security\IUserStorage')
+ ->setFactory('Nette\Http\UserStorage');
+
+ $user = $container->addDefinition($this->prefix('user'))
+ ->setClass('Nette\Security\User');
+
+ if ($this->debugMode && $config['debugger']) {
+ $user->addSetup('@Tracy\Bar::addPanel', array(
+ new Nette\DI\Statement('Nette\Bridges\SecurityTracy\UserPanel'),
+ ));
+ }
+
+ if ($config['users']) {
+ $usersList = $usersRoles = array();
+ foreach ($config['users'] as $username => $data) {
+ $data = is_array($data) ? $data : array('password' => $data);
+ $this->validateConfig(array('password' => NULL, 'roles' => NULL), $data, $this->prefix("security.users.$username"));
+ $usersList[$username] = $data['password'];
+ $usersRoles[$username] = isset($data['roles']) ? $data['roles'] : NULL;
+ }
+
+ $container->addDefinition($this->prefix('authenticator'))
+ ->setClass('Nette\Security\IAuthenticator')
+ ->setFactory('Nette\Security\SimpleAuthenticator', array($usersList, $usersRoles));
+
+ if ($this->name === 'security') {
+ $container->addAlias('nette.authenticator', $this->prefix('authenticator'));
+ }
+ }
+
+ if ($config['roles'] || $config['resources']) {
+ $authorizator = $container->addDefinition($this->prefix('authorizator'))
+ ->setClass('Nette\Security\IAuthorizator')
+ ->setFactory('Nette\Security\Permission');
+
+ foreach ($config['roles'] as $role => $parents) {
+ $authorizator->addSetup('addRole', array($role, $parents));
+ }
+ foreach ($config['resources'] as $resource => $parents) {
+ $authorizator->addSetup('addResource', array($resource, $parents));
+ }
+
+ if ($this->name === 'security') {
+ $container->addAlias('nette.authorizator', $this->prefix('authorizator'));
+ }
+ }
+
+ if ($this->name === 'security') {
+ $container->addAlias('user', $this->prefix('user'));
+ $container->addAlias('nette.userStorage', $this->prefix('userStorage'));
+ }
+ }
+
+}
diff --git a/vendor/nette/security/src/Bridges/SecurityTracy/UserPanel.php b/vendor/nette/security/src/Bridges/SecurityTracy/UserPanel.php
new file mode 100755
index 0000000..931156d
--- /dev/null
+++ b/vendor/nette/security/src/Bridges/SecurityTracy/UserPanel.php
@@ -0,0 +1,58 @@
+user = $user;
+ }
+
+
+ /**
+ * Renders tab.
+ * @return string
+ */
+ public function getTab()
+ {
+ if (headers_sent() && !session_id()) {
+ return;
+ }
+
+ ob_start();
+ $user = $this->user;
+ require __DIR__ . '/templates/UserPanel.tab.phtml';
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Renders panel.
+ * @return string
+ */
+ public function getPanel()
+ {
+ ob_start();
+ $user = $this->user;
+ require __DIR__ . '/templates/UserPanel.panel.phtml';
+ return ob_get_clean();
+ }
+
+}
diff --git a/vendor/nette/security/src/Bridges/SecurityTracy/templates/UserPanel.panel.phtml b/vendor/nette/security/src/Bridges/SecurityTracy/templates/UserPanel.panel.phtml
new file mode 100755
index 0000000..1e8244a
--- /dev/null
+++ b/vendor/nette/security/src/Bridges/SecurityTracy/templates/UserPanel.panel.phtml
@@ -0,0 +1,13 @@
+
+
+
isLoggedIn()): ?>Logged inUnlogged
+
+ getIdentity()): echo Dumper::toHtml($user->getIdentity(), array(Dumper::LIVE => TRUE)); else: ?>
no identity
+
diff --git a/vendor/nette/security/src/Bridges/SecurityTracy/templates/UserPanel.tab.phtml b/vendor/nette/security/src/Bridges/SecurityTracy/templates/UserPanel.tab.phtml
new file mode 100755
index 0000000..cbf9afc
--- /dev/null
+++ b/vendor/nette/security/src/Bridges/SecurityTracy/templates/UserPanel.tab.phtml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/vendor/nette/security/src/Security/AuthenticationException.php b/vendor/nette/security/src/Security/AuthenticationException.php
new file mode 100755
index 0000000..3cb18db
--- /dev/null
+++ b/vendor/nette/security/src/Security/AuthenticationException.php
@@ -0,0 +1,16 @@
+setId($id);
+ $this->setRoles((array) $roles);
+ $this->data = $data instanceof \Traversable ? iterator_to_array($data) : (array) $data;
+ }
+
+
+ /**
+ * Sets the ID of user.
+ * @param mixed
+ * @return self
+ */
+ public function setId($id)
+ {
+ $this->id = is_numeric($id) && !is_float($tmp = $id * 1) ? $tmp : $id;
+ return $this;
+ }
+
+
+ /**
+ * Returns the ID of user.
+ * @return mixed
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+
+ /**
+ * Sets a list of roles that the user is a member of.
+ * @param array
+ * @return self
+ */
+ public function setRoles(array $roles)
+ {
+ $this->roles = $roles;
+ return $this;
+ }
+
+
+ /**
+ * Returns a list of roles that the user is a member of.
+ * @return array
+ */
+ public function getRoles()
+ {
+ return $this->roles;
+ }
+
+
+ /**
+ * Returns a user data.
+ * @return array
+ */
+ public function getData()
+ {
+ return $this->data;
+ }
+
+
+ /**
+ * Sets user data value.
+ * @param string property name
+ * @param mixed property value
+ * @return void
+ */
+ public function __set($key, $value)
+ {
+ if (parent::__isset($key)) {
+ parent::__set($key, $value);
+
+ } else {
+ $this->data[$key] = $value;
+ }
+ }
+
+
+ /**
+ * Returns user data value.
+ * @param string property name
+ * @return mixed
+ */
+ public function &__get($key)
+ {
+ if (parent::__isset($key)) {
+ return parent::__get($key);
+
+ } else {
+ return $this->data[$key];
+ }
+ }
+
+
+ /**
+ * Is property defined?
+ * @param string property name
+ * @return bool
+ */
+ public function __isset($key)
+ {
+ return isset($this->data[$key]) || parent::__isset($key);
+ }
+
+
+ /**
+ * Removes property.
+ * @param string property name
+ * @return void
+ * @throws Nette\MemberAccessException
+ */
+ public function __unset($name)
+ {
+ Nette\Utils\ObjectMixin::remove($this, $name);
+ }
+
+}
diff --git a/vendor/nette/security/src/Security/Passwords.php b/vendor/nette/security/src/Security/Passwords.php
new file mode 100755
index 0000000..f1eb0d4
--- /dev/null
+++ b/vendor/nette/security/src/Security/Passwords.php
@@ -0,0 +1,73 @@
+= 5.3.7.
+ */
+class Passwords
+{
+ const BCRYPT_COST = 10;
+
+
+ /**
+ * Computes salted password hash.
+ * @param string
+ * @param array with cost (4-31), salt (22 chars)
+ * @return string 60 chars long
+ */
+ public static function hash($password, array $options = NULL)
+ {
+ $cost = isset($options['cost']) ? (int) $options['cost'] : self::BCRYPT_COST;
+ $salt = isset($options['salt']) ? (string) $options['salt'] : Nette\Utils\Random::generate(22, '0-9A-Za-z./');
+
+ if (PHP_VERSION_ID < 50307) {
+ throw new Nette\NotSupportedException(__METHOD__ . ' requires PHP >= 5.3.7.');
+ } elseif (($len = strlen($salt)) < 22) {
+ throw new Nette\InvalidArgumentException("Salt must be 22 characters long, $len given.");
+ } elseif ($cost < 4 || $cost > 31) {
+ throw new Nette\InvalidArgumentException("Cost must be in range 4-31, $cost given.");
+ }
+
+ $hash = crypt($password, '$2y$' . ($cost < 10 ? 0 : '') . $cost . '$' . $salt);
+ if (strlen($hash) < 60) {
+ throw new Nette\InvalidStateException('Hash returned by crypt is invalid.');
+ }
+ return $hash;
+ }
+
+
+ /**
+ * Verifies that a password matches a hash.
+ * @return bool
+ */
+ public static function verify($password, $hash)
+ {
+ return preg_match('#^\$2y\$(?P\d\d)\$(?P.{22})#', $hash, $m)
+ && $m['cost'] >= 4 && $m['cost'] <= 31
+ && self::hash($password, $m) === $hash;
+ }
+
+
+ /**
+ * Checks if the given hash matches the options.
+ * @param string
+ * @param array with cost (4-31)
+ * @return bool
+ */
+ public static function needsRehash($hash, array $options = NULL)
+ {
+ $cost = isset($options['cost']) ? (int) $options['cost'] : self::BCRYPT_COST;
+ return !preg_match('#^\$2y\$(?P\d\d)\$(?P.{22})#', $hash, $m)
+ || $m['cost'] < $cost;
+ }
+
+}
diff --git a/vendor/nette/security/src/Security/Permission.php b/vendor/nette/security/src/Security/Permission.php
new file mode 100755
index 0000000..d1db73a
--- /dev/null
+++ b/vendor/nette/security/src/Security/Permission.php
@@ -0,0 +1,805 @@
+ array(
+ 'allRoles' => array(
+ 'allPrivileges' => array(
+ 'type' => self::DENY,
+ 'assert' => NULL,
+ ),
+ 'byPrivilege' => array(),
+ ),
+ 'byRole' => array(),
+ ),
+ 'byResource' => array(),
+ );
+
+ /** @var mixed */
+ private $queriedRole, $queriedResource;
+
+
+ /********************* roles ****************d*g**/
+
+
+ /**
+ * Adds a Role to the list. The most recently added parent
+ * takes precedence over parents that were previously added.
+ * @param string
+ * @param string|array
+ * @throws Nette\InvalidArgumentException
+ * @throws Nette\InvalidStateException
+ * @return self
+ */
+ public function addRole($role, $parents = NULL)
+ {
+ $this->checkRole($role, FALSE);
+ if (isset($this->roles[$role])) {
+ throw new Nette\InvalidStateException("Role '$role' already exists in the list.");
+ }
+
+ $roleParents = array();
+
+ if ($parents !== NULL) {
+ if (!is_array($parents)) {
+ $parents = array($parents);
+ }
+
+ foreach ($parents as $parent) {
+ $this->checkRole($parent);
+ $roleParents[$parent] = TRUE;
+ $this->roles[$parent]['children'][$role] = TRUE;
+ }
+ }
+
+ $this->roles[$role] = array(
+ 'parents' => $roleParents,
+ 'children' => array(),
+ );
+
+ return $this;
+ }
+
+
+ /**
+ * Returns TRUE if the Role exists in the list.
+ * @param string
+ * @return bool
+ */
+ public function hasRole($role)
+ {
+ $this->checkRole($role, FALSE);
+ return isset($this->roles[$role]);
+ }
+
+
+ /**
+ * Checks whether Role is valid and exists in the list.
+ * @param string
+ * @param bool
+ * @throws Nette\InvalidStateException
+ * @return void
+ */
+ private function checkRole($role, $need = TRUE)
+ {
+ if (!is_string($role) || $role === '') {
+ throw new Nette\InvalidArgumentException('Role must be a non-empty string.');
+
+ } elseif ($need && !isset($this->roles[$role])) {
+ throw new Nette\InvalidStateException("Role '$role' does not exist.");
+ }
+ }
+
+
+ /**
+ * Returns all Roles.
+ * @return array
+ */
+ public function getRoles()
+ {
+ return array_keys($this->roles);
+ }
+
+
+ /**
+ * Returns existing Role's parents ordered by ascending priority.
+ * @param string
+ * @return array
+ */
+ public function getRoleParents($role)
+ {
+ $this->checkRole($role);
+ return array_keys($this->roles[$role]['parents']);
+ }
+
+
+ /**
+ * Returns TRUE if $role inherits from $inherit. If $onlyParents is TRUE,
+ * then $role must inherit directly from $inherit.
+ * @param string
+ * @param string
+ * @param bool
+ * @throws Nette\InvalidStateException
+ * @return bool
+ */
+ public function roleInheritsFrom($role, $inherit, $onlyParents = FALSE)
+ {
+ $this->checkRole($role);
+ $this->checkRole($inherit);
+
+ $inherits = isset($this->roles[$role]['parents'][$inherit]);
+
+ if ($inherits || $onlyParents) {
+ return $inherits;
+ }
+
+ foreach ($this->roles[$role]['parents'] as $parent => $foo) {
+ if ($this->roleInheritsFrom($parent, $inherit)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+
+ /**
+ * Removes the Role from the list.
+ *
+ * @param string
+ * @throws Nette\InvalidStateException
+ * @return self
+ */
+ public function removeRole($role)
+ {
+ $this->checkRole($role);
+
+ foreach ($this->roles[$role]['children'] as $child => $foo) {
+ unset($this->roles[$child]['parents'][$role]);
+ }
+
+ foreach ($this->roles[$role]['parents'] as $parent => $foo) {
+ unset($this->roles[$parent]['children'][$role]);
+ }
+
+ unset($this->roles[$role]);
+
+ foreach ($this->rules['allResources']['byRole'] as $roleCurrent => $rules) {
+ if ($role === $roleCurrent) {
+ unset($this->rules['allResources']['byRole'][$roleCurrent]);
+ }
+ }
+
+ foreach ($this->rules['byResource'] as $resourceCurrent => $visitor) {
+ if (isset($visitor['byRole'])) {
+ foreach ($visitor['byRole'] as $roleCurrent => $rules) {
+ if ($role === $roleCurrent) {
+ unset($this->rules['byResource'][$resourceCurrent]['byRole'][$roleCurrent]);
+ }
+ }
+ }
+ }
+
+ return $this;
+ }
+
+
+ /**
+ * Removes all Roles from the list.
+ *
+ * @return self
+ */
+ public function removeAllRoles()
+ {
+ $this->roles = array();
+
+ foreach ($this->rules['allResources']['byRole'] as $roleCurrent => $rules) {
+ unset($this->rules['allResources']['byRole'][$roleCurrent]);
+ }
+
+ foreach ($this->rules['byResource'] as $resourceCurrent => $visitor) {
+ foreach ($visitor['byRole'] as $roleCurrent => $rules) {
+ unset($this->rules['byResource'][$resourceCurrent]['byRole'][$roleCurrent]);
+ }
+ }
+
+ return $this;
+ }
+
+
+ /********************* resources ****************d*g**/
+
+
+ /**
+ * Adds a Resource having an identifier unique to the list.
+ *
+ * @param string
+ * @param string
+ * @throws Nette\InvalidArgumentException
+ * @throws Nette\InvalidStateException
+ * @return self
+ */
+ public function addResource($resource, $parent = NULL)
+ {
+ $this->checkResource($resource, FALSE);
+
+ if (isset($this->resources[$resource])) {
+ throw new Nette\InvalidStateException("Resource '$resource' already exists in the list.");
+ }
+
+ if ($parent !== NULL) {
+ $this->checkResource($parent);
+ $this->resources[$parent]['children'][$resource] = TRUE;
+ }
+
+ $this->resources[$resource] = array(
+ 'parent' => $parent,
+ 'children' => array(),
+ );
+
+ return $this;
+ }
+
+
+ /**
+ * Returns TRUE if the Resource exists in the list.
+ * @param string
+ * @return bool
+ */
+ public function hasResource($resource)
+ {
+ $this->checkResource($resource, FALSE);
+ return isset($this->resources[$resource]);
+ }
+
+
+ /**
+ * Checks whether Resource is valid and exists in the list.
+ * @param string
+ * @param bool
+ * @throws Nette\InvalidStateException
+ * @return void
+ */
+ private function checkResource($resource, $need = TRUE)
+ {
+ if (!is_string($resource) || $resource === '') {
+ throw new Nette\InvalidArgumentException('Resource must be a non-empty string.');
+
+ } elseif ($need && !isset($this->resources[$resource])) {
+ throw new Nette\InvalidStateException("Resource '$resource' does not exist.");
+ }
+ }
+
+
+ /**
+ * Returns all Resources.
+ * @return array
+ */
+ public function getResources()
+ {
+ return array_keys($this->resources);
+ }
+
+
+ /**
+ * Returns TRUE if $resource inherits from $inherit. If $onlyParents is TRUE,
+ * then $resource must inherit directly from $inherit.
+ *
+ * @param string
+ * @param string
+ * @param bool
+ * @throws Nette\InvalidStateException
+ * @return bool
+ */
+ public function resourceInheritsFrom($resource, $inherit, $onlyParent = FALSE)
+ {
+ $this->checkResource($resource);
+ $this->checkResource($inherit);
+
+ if ($this->resources[$resource]['parent'] === NULL) {
+ return FALSE;
+ }
+
+ $parent = $this->resources[$resource]['parent'];
+ if ($inherit === $parent) {
+ return TRUE;
+
+ } elseif ($onlyParent) {
+ return FALSE;
+ }
+
+ while ($this->resources[$parent]['parent'] !== NULL) {
+ $parent = $this->resources[$parent]['parent'];
+ if ($inherit === $parent) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+
+ /**
+ * Removes a Resource and all of its children.
+ *
+ * @param string
+ * @throws Nette\InvalidStateException
+ * @return self
+ */
+ public function removeResource($resource)
+ {
+ $this->checkResource($resource);
+
+ $parent = $this->resources[$resource]['parent'];
+ if ($parent !== NULL) {
+ unset($this->resources[$parent]['children'][$resource]);
+ }
+
+ $removed = array($resource);
+ foreach ($this->resources[$resource]['children'] as $child => $foo) {
+ $this->removeResource($child);
+ $removed[] = $child;
+ }
+
+ foreach ($removed as $resourceRemoved) {
+ foreach ($this->rules['byResource'] as $resourceCurrent => $rules) {
+ if ($resourceRemoved === $resourceCurrent) {
+ unset($this->rules['byResource'][$resourceCurrent]);
+ }
+ }
+ }
+
+ unset($this->resources[$resource]);
+ return $this;
+ }
+
+
+ /**
+ * Removes all Resources.
+ * @return self
+ */
+ public function removeAllResources()
+ {
+ foreach ($this->resources as $resource => $foo) {
+ foreach ($this->rules['byResource'] as $resourceCurrent => $rules) {
+ if ($resource === $resourceCurrent) {
+ unset($this->rules['byResource'][$resourceCurrent]);
+ }
+ }
+ }
+
+ $this->resources = array();
+ return $this;
+ }
+
+
+ /********************* defining rules ****************d*g**/
+
+
+ /**
+ * Allows one or more Roles access to [certain $privileges upon] the specified Resource(s).
+ * If $assertion is provided, then it must return TRUE in order for rule to apply.
+ *
+ * @param string|array|Permission::ALL roles
+ * @param string|array|Permission::ALL resources
+ * @param string|array|Permission::ALL privileges
+ * @param callable assertion
+ * @return self
+ */
+ public function allow($roles = self::ALL, $resources = self::ALL, $privileges = self::ALL, $assertion = NULL)
+ {
+ $this->setRule(TRUE, self::ALLOW, $roles, $resources, $privileges, $assertion);
+ return $this;
+ }
+
+
+ /**
+ * Denies one or more Roles access to [certain $privileges upon] the specified Resource(s).
+ * If $assertion is provided, then it must return TRUE in order for rule to apply.
+ *
+ * @param string|array|Permission::ALL roles
+ * @param string|array|Permission::ALL resources
+ * @param string|array|Permission::ALL privileges
+ * @param callable assertion
+ * @return self
+ */
+ public function deny($roles = self::ALL, $resources = self::ALL, $privileges = self::ALL, $assertion = NULL)
+ {
+ $this->setRule(TRUE, self::DENY, $roles, $resources, $privileges, $assertion);
+ return $this;
+ }
+
+
+ /**
+ * Removes "allow" permissions from the list in the context of the given Roles, Resources, and privileges.
+ *
+ * @param string|array|Permission::ALL roles
+ * @param string|array|Permission::ALL resources
+ * @param string|array|Permission::ALL privileges
+ * @return self
+ */
+ public function removeAllow($roles = self::ALL, $resources = self::ALL, $privileges = self::ALL)
+ {
+ $this->setRule(FALSE, self::ALLOW, $roles, $resources, $privileges);
+ return $this;
+ }
+
+
+ /**
+ * Removes "deny" restrictions from the list in the context of the given Roles, Resources, and privileges.
+ *
+ * @param string|array|Permission::ALL roles
+ * @param string|array|Permission::ALL resources
+ * @param string|array|Permission::ALL privileges
+ * @return self
+ */
+ public function removeDeny($roles = self::ALL, $resources = self::ALL, $privileges = self::ALL)
+ {
+ $this->setRule(FALSE, self::DENY, $roles, $resources, $privileges);
+ return $this;
+ }
+
+
+ /**
+ * Performs operations on Access Control List rules.
+ * @param bool operation add?
+ * @param bool type
+ * @param string|array|Permission::ALL roles
+ * @param string|array|Permission::ALL resources
+ * @param string|array|Permission::ALL privileges
+ * @param callable assertion
+ * @throws Nette\InvalidStateException
+ * @return self
+ */
+ protected function setRule($toAdd, $type, $roles, $resources, $privileges, $assertion = NULL)
+ {
+ // ensure that all specified Roles exist; normalize input to array of Roles or NULL
+ if ($roles === self::ALL) {
+ $roles = array(self::ALL);
+
+ } else {
+ if (!is_array($roles)) {
+ $roles = array($roles);
+ }
+
+ foreach ($roles as $role) {
+ $this->checkRole($role);
+ }
+ }
+
+ // ensure that all specified Resources exist; normalize input to array of Resources or NULL
+ if ($resources === self::ALL) {
+ $resources = array(self::ALL);
+
+ } else {
+ if (!is_array($resources)) {
+ $resources = array($resources);
+ }
+
+ foreach ($resources as $resource) {
+ $this->checkResource($resource);
+ }
+ }
+
+ // normalize privileges to array
+ if ($privileges === self::ALL) {
+ $privileges = array();
+
+ } elseif (!is_array($privileges)) {
+ $privileges = array($privileges);
+ }
+
+ if ($toAdd) { // add to the rules
+ foreach ($resources as $resource) {
+ foreach ($roles as $role) {
+ $rules = & $this->getRules($resource, $role, TRUE);
+ if (count($privileges) === 0) {
+ $rules['allPrivileges']['type'] = $type;
+ $rules['allPrivileges']['assert'] = $assertion;
+ if (!isset($rules['byPrivilege'])) {
+ $rules['byPrivilege'] = array();
+ }
+ } else {
+ foreach ($privileges as $privilege) {
+ $rules['byPrivilege'][$privilege]['type'] = $type;
+ $rules['byPrivilege'][$privilege]['assert'] = $assertion;
+ }
+ }
+ }
+ }
+
+ } else { // remove from the rules
+ foreach ($resources as $resource) {
+ foreach ($roles as $role) {
+ $rules = & $this->getRules($resource, $role);
+ if ($rules === NULL) {
+ continue;
+ }
+ if (count($privileges) === 0) {
+ if ($resource === self::ALL && $role === self::ALL) {
+ if ($type === $rules['allPrivileges']['type']) {
+ $rules = array(
+ 'allPrivileges' => array(
+ 'type' => self::DENY,
+ 'assert' => NULL,
+ ),
+ 'byPrivilege' => array(),
+ );
+ }
+ continue;
+ }
+ if ($type === $rules['allPrivileges']['type']) {
+ unset($rules['allPrivileges']);
+ }
+ } else {
+ foreach ($privileges as $privilege) {
+ if (isset($rules['byPrivilege'][$privilege]) &&
+ $type === $rules['byPrivilege'][$privilege]['type']
+ ) {
+ unset($rules['byPrivilege'][$privilege]);
+ }
+ }
+ }
+ }
+ }
+ }
+ return $this;
+ }
+
+
+ /********************* querying the ACL ****************d*g**/
+
+
+ /**
+ * Returns TRUE if and only if the Role has access to [certain $privileges upon] the Resource.
+ *
+ * This method checks Role inheritance using a depth-first traversal of the Role list.
+ * The highest priority parent (i.e., the parent most recently added) is checked first,
+ * and its respective parents are checked similarly before the lower-priority parents of
+ * the Role are checked.
+ *
+ * @param string|Permission::ALL|IRole role
+ * @param string|Permission::ALL|IResource resource
+ * @param string|Permission::ALL privilege
+ * @throws Nette\InvalidStateException
+ * @return bool
+ */
+ public function isAllowed($role = self::ALL, $resource = self::ALL, $privilege = self::ALL)
+ {
+ $this->queriedRole = $role;
+ if ($role !== self::ALL) {
+ if ($role instanceof IRole) {
+ $role = $role->getRoleId();
+ }
+ $this->checkRole($role);
+ }
+
+ $this->queriedResource = $resource;
+ if ($resource !== self::ALL) {
+ if ($resource instanceof IResource) {
+ $resource = $resource->getResourceId();
+ }
+ $this->checkResource($resource);
+ }
+
+ do {
+ // depth-first search on $role if it is not 'allRoles' pseudo-parent
+ if ($role !== NULL && NULL !== ($result = $this->searchRolePrivileges($privilege === self::ALL, $role, $resource, $privilege))) {
+ break;
+ }
+
+ if ($privilege === self::ALL) {
+ if ($rules = $this->getRules($resource, self::ALL)) { // look for rule on 'allRoles' psuedo-parent
+ foreach ($rules['byPrivilege'] as $privilege => $rule) {
+ if (self::DENY === ($result = $this->getRuleType($resource, NULL, $privilege))) {
+ break 2;
+ }
+ }
+ if (NULL !== ($result = $this->getRuleType($resource, NULL, NULL))) {
+ break;
+ }
+ }
+ } else {
+ if (NULL !== ($result = $this->getRuleType($resource, NULL, $privilege))) { // look for rule on 'allRoles' pseudo-parent
+ break;
+
+ } elseif (NULL !== ($result = $this->getRuleType($resource, NULL, NULL))) {
+ break;
+ }
+ }
+
+ $resource = $this->resources[$resource]['parent']; // try next Resource
+ } while (TRUE);
+
+ $this->queriedRole = $this->queriedResource = NULL;
+ return $result;
+ }
+
+
+ /**
+ * Returns real currently queried Role. Use by assertion.
+ * @return mixed
+ */
+ public function getQueriedRole()
+ {
+ return $this->queriedRole;
+ }
+
+
+ /**
+ * Returns real currently queried Resource. Use by assertion.
+ * @return mixed
+ */
+ public function getQueriedResource()
+ {
+ return $this->queriedResource;
+ }
+
+
+ /********************* internals ****************d*g**/
+
+
+ /**
+ * Performs a depth-first search of the Role DAG, starting at $role, in order to find a rule
+ * allowing/denying $role access to a/all $privilege upon $resource.
+ * @param bool all (true) or one?
+ * @param string
+ * @param string
+ * @param string only for one
+ * @return mixed NULL if no applicable rule is found, otherwise returns ALLOW or DENY
+ */
+ private function searchRolePrivileges($all, $role, $resource, $privilege)
+ {
+ $dfs = array(
+ 'visited' => array(),
+ 'stack' => array($role),
+ );
+
+ while (NULL !== ($role = array_pop($dfs['stack']))) {
+ if (isset($dfs['visited'][$role])) {
+ continue;
+ }
+ if ($all) {
+ if ($rules = $this->getRules($resource, $role)) {
+ foreach ($rules['byPrivilege'] as $privilege2 => $rule) {
+ if (self::DENY === $this->getRuleType($resource, $role, $privilege2)) {
+ return self::DENY;
+ }
+ }
+ if (NULL !== ($type = $this->getRuleType($resource, $role, NULL))) {
+ return $type;
+ }
+ }
+ } else {
+ if (NULL !== ($type = $this->getRuleType($resource, $role, $privilege))) {
+ return $type;
+
+ } elseif (NULL !== ($type = $this->getRuleType($resource, $role, NULL))) {
+ return $type;
+ }
+ }
+
+ $dfs['visited'][$role] = TRUE;
+ foreach ($this->roles[$role]['parents'] as $roleParent => $foo) {
+ $dfs['stack'][] = $roleParent;
+ }
+ }
+ return NULL;
+ }
+
+
+ /**
+ * Returns the rule type associated with the specified Resource, Role, and privilege.
+ * @param string|Permission::ALL
+ * @param string|Permission::ALL
+ * @param string|Permission::ALL
+ * @return mixed NULL if a rule does not exist or assertion fails, otherwise returns ALLOW or DENY
+ */
+ private function getRuleType($resource, $role, $privilege)
+ {
+ if (!$rules = $this->getRules($resource, $role)) {
+ return NULL;
+ }
+
+ if ($privilege === self::ALL) {
+ if (isset($rules['allPrivileges'])) {
+ $rule = $rules['allPrivileges'];
+ } else {
+ return NULL;
+ }
+ } elseif (!isset($rules['byPrivilege'][$privilege])) {
+ return NULL;
+
+ } else {
+ $rule = $rules['byPrivilege'][$privilege];
+ }
+
+ if ($rule['assert'] === NULL || Nette\Utils\Callback::invoke($rule['assert'], $this, $role, $resource, $privilege)) {
+ return $rule['type'];
+
+ } elseif ($resource !== self::ALL || $role !== self::ALL || $privilege !== self::ALL) {
+ return NULL;
+
+ } elseif (self::ALLOW === $rule['type']) {
+ return self::DENY;
+
+ } else {
+ return self::ALLOW;
+ }
+ }
+
+
+ /**
+ * Returns the rules associated with a Resource and a Role, or NULL if no such rules exist.
+ * If the $create parameter is TRUE, then a rule set is first created and then returned to the caller.
+ * @param string|Permission::ALL
+ * @param string|Permission::ALL
+ * @param bool
+ * @return array|NULL
+ */
+ private function & getRules($resource, $role, $create = FALSE)
+ {
+ $null = NULL;
+ if ($resource === self::ALL) {
+ $visitor = & $this->rules['allResources'];
+ } else {
+ if (!isset($this->rules['byResource'][$resource])) {
+ if (!$create) {
+ return $null;
+ }
+ $this->rules['byResource'][$resource] = array();
+ }
+ $visitor = & $this->rules['byResource'][$resource];
+ }
+
+ if ($role === self::ALL) {
+ if (!isset($visitor['allRoles'])) {
+ if (!$create) {
+ return $null;
+ }
+ $visitor['allRoles']['byPrivilege'] = array();
+ }
+ return $visitor['allRoles'];
+ }
+
+ if (!isset($visitor['byRole'][$role])) {
+ if (!$create) {
+ return $null;
+ }
+ $visitor['byRole'][$role]['byPrivilege'] = array();
+ }
+
+ return $visitor['byRole'][$role];
+ }
+
+}
diff --git a/vendor/nette/security/src/Security/SimpleAuthenticator.php b/vendor/nette/security/src/Security/SimpleAuthenticator.php
new file mode 100755
index 0000000..3b44ac3
--- /dev/null
+++ b/vendor/nette/security/src/Security/SimpleAuthenticator.php
@@ -0,0 +1,57 @@
+ password
+ * @param array list of pairs username => role[]
+ */
+ public function __construct(array $userlist, array $usersRoles = array())
+ {
+ $this->userlist = $userlist;
+ $this->usersRoles = $usersRoles;
+ }
+
+
+ /**
+ * Performs an authentication against e.g. database.
+ * and returns IIdentity on success or throws AuthenticationException
+ * @return IIdentity
+ * @throws AuthenticationException
+ */
+ public function authenticate(array $credentials)
+ {
+ list($username, $password) = $credentials;
+ foreach ($this->userlist as $name => $pass) {
+ if (strcasecmp($name, $username) === 0) {
+ if ((string) $pass === (string) $password) {
+ return new Identity($name, isset($this->usersRoles[$name]) ? $this->usersRoles[$name] : NULL);
+ } else {
+ throw new AuthenticationException('Invalid password.', self::INVALID_CREDENTIAL);
+ }
+ }
+ }
+ throw new AuthenticationException("User '$username' not found.", self::IDENTITY_NOT_FOUND);
+ }
+
+}
diff --git a/vendor/nette/security/src/Security/User.php b/vendor/nette/security/src/Security/User.php
new file mode 100755
index 0000000..77099c7
--- /dev/null
+++ b/vendor/nette/security/src/Security/User.php
@@ -0,0 +1,261 @@
+storage = $storage;
+ $this->authenticator = $authenticator;
+ $this->authorizator = $authorizator;
+ }
+
+
+ /**
+ * @return IUserStorage
+ */
+ public function getStorage()
+ {
+ return $this->storage;
+ }
+
+
+ /********************* Authentication ****************d*g**/
+
+
+ /**
+ * Conducts the authentication process. Parameters are optional.
+ * @param mixed optional parameter (e.g. username or IIdentity)
+ * @param mixed optional parameter (e.g. password)
+ * @return void
+ * @throws AuthenticationException if authentication was not successful
+ */
+ public function login($id = NULL, $password = NULL)
+ {
+ $this->logout(TRUE);
+ if (!$id instanceof IIdentity) {
+ $id = $this->getAuthenticator()->authenticate(func_get_args());
+ }
+ $this->storage->setIdentity($id);
+ $this->storage->setAuthenticated(TRUE);
+ $this->onLoggedIn($this);
+ }
+
+
+ /**
+ * Logs out the user from the current session.
+ * @param bool clear the identity from persistent storage?
+ * @return void
+ */
+ public function logout($clearIdentity = FALSE)
+ {
+ if ($this->isLoggedIn()) {
+ $this->onLoggedOut($this);
+ $this->storage->setAuthenticated(FALSE);
+ }
+ if ($clearIdentity) {
+ $this->storage->setIdentity(NULL);
+ }
+ }
+
+
+ /**
+ * Is this user authenticated?
+ * @return bool
+ */
+ public function isLoggedIn()
+ {
+ return $this->storage->isAuthenticated();
+ }
+
+
+ /**
+ * Returns current user identity, if any.
+ * @return IIdentity|NULL
+ */
+ public function getIdentity()
+ {
+ return $this->storage->getIdentity();
+ }
+
+
+ /**
+ * Returns current user ID, if any.
+ * @return mixed
+ */
+ public function getId()
+ {
+ $identity = $this->getIdentity();
+ return $identity ? $identity->getId() : NULL;
+ }
+
+
+ /**
+ * Sets authentication handler.
+ * @return self
+ */
+ public function setAuthenticator(IAuthenticator $handler)
+ {
+ $this->authenticator = $handler;
+ return $this;
+ }
+
+
+ /**
+ * Returns authentication handler.
+ * @return IAuthenticator
+ */
+ public function getAuthenticator($need = TRUE)
+ {
+ if ($need && !$this->authenticator) {
+ throw new Nette\InvalidStateException('Authenticator has not been set.');
+ }
+ return $this->authenticator;
+ }
+
+
+ /**
+ * Enables log out after inactivity.
+ * @param string|int|DateTime number of seconds or timestamp
+ * @param bool log out when the browser is closed?
+ * @param bool clear the identity from persistent storage?
+ * @return self
+ */
+ public function setExpiration($time, $whenBrowserIsClosed = TRUE, $clearIdentity = FALSE)
+ {
+ $flags = ($whenBrowserIsClosed ? IUserStorage::BROWSER_CLOSED : 0) | ($clearIdentity ? IUserStorage::CLEAR_IDENTITY : 0);
+ $this->storage->setExpiration($time, $flags);
+ return $this;
+ }
+
+
+ /**
+ * Why was user logged out?
+ * @return int
+ */
+ public function getLogoutReason()
+ {
+ return $this->storage->getLogoutReason();
+ }
+
+
+ /********************* Authorization ****************d*g**/
+
+
+ /**
+ * Returns a list of effective roles that a user has been granted.
+ * @return array
+ */
+ public function getRoles()
+ {
+ if (!$this->isLoggedIn()) {
+ return array($this->guestRole);
+ }
+
+ $identity = $this->getIdentity();
+ return $identity && $identity->getRoles() ? $identity->getRoles() : array($this->authenticatedRole);
+ }
+
+
+ /**
+ * Is a user in the specified effective role?
+ * @param string
+ * @return bool
+ */
+ public function isInRole($role)
+ {
+ return in_array($role, $this->getRoles(), TRUE);
+ }
+
+
+ /**
+ * Has a user effective access to the Resource?
+ * If $resource is NULL, then the query applies to all resources.
+ * @param string resource
+ * @param string privilege
+ * @return bool
+ */
+ public function isAllowed($resource = IAuthorizator::ALL, $privilege = IAuthorizator::ALL)
+ {
+ foreach ($this->getRoles() as $role) {
+ if ($this->getAuthorizator()->isAllowed($role, $resource, $privilege)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+
+ /**
+ * Sets authorization handler.
+ * @return self
+ */
+ public function setAuthorizator(IAuthorizator $handler)
+ {
+ $this->authorizator = $handler;
+ return $this;
+ }
+
+
+ /**
+ * Returns current authorization handler.
+ * @return IAuthorizator
+ */
+ public function getAuthorizator($need = TRUE)
+ {
+ if ($need && !$this->authorizator) {
+ throw new Nette\InvalidStateException('Authorizator has not been set.');
+ }
+ return $this->authorizator;
+ }
+
+}
diff --git a/vendor/nette/tester/composer.json b/vendor/nette/tester/composer.json
new file mode 100755
index 0000000..ae20c5d
--- /dev/null
+++ b/vendor/nette/tester/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "nette/tester",
+ "description": "An easy-to-use PHP unit testing framework.",
+ "homepage": "http://nette.org",
+ "keywords": ["testing", "unit", "nette"],
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "bin": ["src/tester"],
+ "extra": {
+ "branch-alias": { "dev-master": "1.5-dev" }
+ }
+}
diff --git a/vendor/nette/tester/license.md b/vendor/nette/tester/license.md
new file mode 100755
index 0000000..4bb4304
--- /dev/null
+++ b/vendor/nette/tester/license.md
@@ -0,0 +1,49 @@
+Licenses
+========
+
+Good news! You may use Nette Tester under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2013 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Tester" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/tester/src/CodeCoverage/Collector.php b/vendor/nette/tester/src/CodeCoverage/Collector.php
new file mode 100755
index 0000000..3847507
--- /dev/null
+++ b/vendor/nette/tester/src/CodeCoverage/Collector.php
@@ -0,0 +1,68 @@
+ $lines) {
+ if (!file_exists($filename)) {
+ continue;
+ }
+ foreach ($lines as $num => $val) {
+ if (empty($coverage[$filename][$num]) || $val > 0) {
+ $coverage[$filename][$num] = $val; // -1 => untested; -2 => dead code
+ }
+ }
+ }
+
+ ftruncate(self::$file, 0);
+ fwrite(self::$file, serialize($coverage));
+ fclose(self::$file);
+ }
+
+}
diff --git a/vendor/nette/tester/src/CodeCoverage/Generators/AbstractGenerator.php b/vendor/nette/tester/src/CodeCoverage/Generators/AbstractGenerator.php
new file mode 100755
index 0000000..f0cd292
--- /dev/null
+++ b/vendor/nette/tester/src/CodeCoverage/Generators/AbstractGenerator.php
@@ -0,0 +1,126 @@
+data = @unserialize(file_get_contents($file)); // @ is escalated to exception
+ if (!is_array($this->data)) {
+ throw new \Exception("Content of file '$file' is invalid.");
+ }
+
+ if (!$source) {
+ $source = key($this->data);
+ for ($i = 0; $i < strlen($source); $i++) {
+ foreach ($this->data as $s => $foo) {
+ if (!isset($s[$i]) || $source[$i] !== $s[$i]) {
+ $source = substr($source, 0, $i);
+ break 2;
+ }
+ }
+ }
+ $source = dirname($source . 'x');
+
+ } elseif (!file_exists($source)) {
+ throw new \Exception("File or directory '$source' is missing.");
+ }
+
+ $this->source = realpath($source);
+ }
+
+
+ public function render($file = NULL)
+ {
+ $handle = $file ? @fopen($file, 'w') : STDOUT; // @ is escalated to exception
+ if (!$handle) {
+ throw new \Exception("Unable to write to file '$file'.");
+ }
+
+ ob_start(function ($buffer) use ($handle) { fwrite($handle, $buffer); }, 4096);
+ try {
+ $this->renderSelf();
+ } catch (\Exception $e) {
+ }
+ ob_end_flush();
+ fclose($handle);
+
+ if (isset($e)) {
+ if ($file) {
+ unlink($file);
+ }
+ throw $e;
+ }
+ }
+
+
+ /**
+ * @return AcceptIterator
+ */
+ protected function getSourceIterator()
+ {
+ $iterator = is_dir($this->source)
+ ? new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->source))
+ : new \ArrayIterator(array(new \SplFileInfo($this->source)));
+
+ return new AcceptIterator($iterator, $this->acceptFiles);
+ }
+
+
+ abstract protected function renderSelf();
+
+}
+
+
+/** @internal */
+class AcceptIterator extends \FilterIterator
+{
+ private $acceptFiles;
+
+ public function __construct(\Iterator $iterator, array $acceptFiles)
+ {
+ parent::__construct($iterator);
+ $this->acceptFiles = $acceptFiles;
+ }
+
+
+ public function accept()
+ {
+ return substr($this->current()->getBasename(), 0, 1) !== '.' // . or .. or .gitignore
+ && in_array(pathinfo($this->current(), PATHINFO_EXTENSION), $this->acceptFiles, TRUE);
+ }
+
+}
diff --git a/vendor/nette/tester/src/CodeCoverage/Generators/CloverXMLGenerator.php b/vendor/nette/tester/src/CodeCoverage/Generators/CloverXMLGenerator.php
new file mode 100755
index 0000000..7b5ea4b
--- /dev/null
+++ b/vendor/nette/tester/src/CodeCoverage/Generators/CloverXMLGenerator.php
@@ -0,0 +1,217 @@
+ 'packages',
+ 'fileCount' => 'files',
+ 'linesOfCode' => 'loc',
+ 'linesOfNonCommentedCode' => 'ncloc',
+ 'classCount' => 'classes',
+ 'methodCount' => 'methods',
+ 'coveredMethodCount' => 'coveredmethods',
+ 'statementCount' => 'statements',
+ 'coveredStatementCount' => 'coveredstatements',
+ 'elementCount' => 'elements',
+ 'coveredElementCount' => 'coveredelements',
+ 'conditionalCount' => 'conditionals',
+ 'coveredConditionalCount' => 'coveredconditionals',
+ );
+
+
+ public function __construct($file, $source = NULL)
+ {
+ if (!extension_loaded('dom')) {
+ throw new \LogicException('CloverXML generator requires DOM extension to be loaded.');
+ }
+ parent::__construct($file, $source);
+ }
+
+
+ protected function renderSelf()
+ {
+ $time = time();
+ $parser = new PhpParser;
+
+ $doc = new DOMDocument;
+ $doc->formatOutput = TRUE;
+
+ $elCoverage = $doc->appendChild($doc->createElement('coverage'));
+ $elCoverage->setAttribute('generated', $time);
+
+ // TODO: @name
+ $elProject = $elCoverage->appendChild($doc->createElement('project'));
+ $elProject->setAttribute('timestamp', $time);
+ $elProjectMetrics = $elProject->appendChild($doc->createElement('metrics'));
+
+ $projectMetrics = (object) array(
+ 'packageCount' => 0,
+ 'fileCount' => 0,
+ 'linesOfCode' => 0,
+ 'linesOfNonCommentedCode' => 0,
+ 'classCount' => 0,
+ 'methodCount' => 0,
+ 'coveredMethodCount' => 0,
+ 'statementCount' => 0,
+ 'coveredStatementCount' => 0,
+ 'elementCount' => 0,
+ 'coveredElementCount' => 0,
+ 'conditionalCount' => 0,
+ 'coveredConditionalCount' => 0,
+ );
+
+ foreach ($this->getSourceIterator() as $file) {
+ $file = (string) $file;
+
+ $projectMetrics->fileCount++;
+
+ $coverageData = isset($this->data[$file]) ? $this->data[$file] : NULL;
+
+ // TODO: split to by namespace?
+ $elFile = $elProject->appendChild($doc->createElement('file'));
+ $elFile->setAttribute('name', $file);
+ $elFileMetrics = $elFile->appendChild($doc->createElement('metrics'));
+
+ $code = $parser->parse(file_get_contents($file));
+
+ $fileMetrics = (object) array(
+ 'linesOfCode' => $code->linesOfCode,
+ 'linesOfNonCommentedCode' => $code->linesOfCode - $code->linesOfComments,
+ 'classCount' => count($code->classes) + count($code->traits),
+ 'methodCount' => 0,
+ 'coveredMethodCount' => 0,
+ 'statementCount' => 0,
+ 'coveredStatementCount' => 0,
+ 'elementCount' => 0,
+ 'coveredElementCount' => 0,
+ 'conditionalCount' => 0,
+ 'coveredConditionalCount' => 0,
+ );
+
+ foreach (array_merge($code->classes, $code->traits) as $name => $info) { // TODO: interfaces?
+ $elClass = $elFile->appendChild($doc->createElement('class'));
+ if (($tmp = strrpos($name, '\\')) === FALSE) {
+ $elClass->setAttribute('name', $name);
+ } else {
+ $elClass->setAttribute('namespace', substr($name, 0, $tmp));
+ $elClass->setAttribute('name', substr($name, $tmp + 1));
+ }
+
+ $elClassMetrics = $elClass->appendChild($doc->createElement('metrics'));
+ $classMetrics = $this->calculateClassMetrics($info, $coverageData);
+ self::setMetricAttributes($elClassMetrics, $classMetrics);
+ self::appendMetrics($fileMetrics, $classMetrics);
+ }
+ self::setMetricAttributes($elFileMetrics, $fileMetrics);
+
+
+ foreach ((array) $coverageData as $line => $count) {
+ if ($count === self::CODE_DEAD) {
+ continue;
+ }
+
+ // Line type can be 'method' but Xdebug does not report such lines as executed.
+ $elLine = $elFile->appendChild($doc->createElement('line'));
+ $elLine->setAttribute('num', $line);
+ $elLine->setAttribute('type', 'stmt');
+ $elLine->setAttribute('count', max(0, $count));
+ }
+
+ self::appendMetrics($projectMetrics, $fileMetrics);
+ }
+
+ // TODO: What about reported (covered) lines outside of class/trait definition?
+ self::setMetricAttributes($elProjectMetrics, $projectMetrics);
+
+ echo $doc->saveXML();
+ }
+
+
+ /**
+ * @return \stdClass
+ */
+ private function calculateClassMetrics(\stdClass $info, array $coverageData = NULL)
+ {
+ $stats = (object) array(
+ 'methodCount' => count($info->methods),
+ 'coveredMethodCount' => 0,
+ 'statementCount' => 0,
+ 'coveredStatementCount' => 0,
+ 'conditionalCount' => 0,
+ 'coveredConditionalCount' => 0,
+ 'elementCount' => NULL,
+ 'coveredElementCount' => NULL,
+ );
+
+ foreach ($info->methods as $name => $methodInfo) {
+ list($lineCount, $coveredLineCount) = $this->analyzeMethod($methodInfo, $coverageData);
+
+ $stats->statementCount += $lineCount;
+
+ if ($coverageData !== NULL) {
+ $stats->coveredMethodCount += $lineCount === $coveredLineCount ? 1 : 0;
+ $stats->coveredStatementCount += $coveredLineCount;
+ }
+ }
+
+ $stats->elementCount = $stats->methodCount + $stats->statementCount;
+ $stats->coveredElementCount = $stats->coveredMethodCount + $stats->coveredStatementCount;
+
+ return $stats;
+ }
+
+
+ /**
+ * @return array
+ */
+ private static function analyzeMethod(\stdClass $info, array $coverageData = NULL)
+ {
+ $count = 0;
+ $coveredCount = 0;
+
+ if ($coverageData === NULL) { // Never loaded file
+ $count = max(1, $info->end - $info->start - 2);
+ } else {
+ for ($i = $info->start; $i <= $info->end; $i++) {
+ if (isset($coverageData[$i]) && $coverageData[$i] !== self::CODE_DEAD) {
+ $count++;
+ if ($coverageData[$i] > 0) {
+ $coveredCount++;
+ }
+ }
+ }
+ }
+
+ return array($count, $coveredCount);
+ }
+
+
+ private static function appendMetrics(\stdClass $summary, \stdClass $add)
+ {
+ foreach ($add as $name => $value) {
+ $summary->{$name} += $value;
+ }
+ }
+
+
+ private static function setMetricAttributes(DOMElement $element, \stdClass $metrics)
+ {
+ foreach ($metrics as $name => $value) {
+ $element->setAttribute(self::$metricAttributesMap[$name], $value);
+ }
+ }
+
+}
diff --git a/vendor/nette/tester/src/CodeCoverage/Generators/HtmlGenerator.php b/vendor/nette/tester/src/CodeCoverage/Generators/HtmlGenerator.php
new file mode 100755
index 0000000..7b407e5
--- /dev/null
+++ b/vendor/nette/tester/src/CodeCoverage/Generators/HtmlGenerator.php
@@ -0,0 +1,113 @@
+ 't', // tested
+ self::CODE_UNTESTED => 'u', // untested
+ self::CODE_DEAD => 'dead', // dead code
+ );
+
+
+ /**
+ * @param string path to coverage.dat file
+ * @param string path to source file/directory
+ * @param string
+ */
+ public function __construct($file, $source = NULL, $title = NULL)
+ {
+ parent::__construct($file, $source);
+ $this->title = $title;
+ }
+
+
+ protected function renderSelf()
+ {
+ $this->setupHighlight();
+ $this->parse();
+
+ $title = $this->title;
+ $classes = self::$classes;
+ $files = $this->files;
+ $totalSum = $this->totalSum;
+ $coveredSum = $this->coveredSum;
+
+ include __DIR__ . '/template.phtml';
+ }
+
+
+ private function setupHighlight()
+ {
+ ini_set('highlight.comment', '#999; font-style: italic');
+ ini_set('highlight.default', '#000');
+ ini_set('highlight.html', '#06B');
+ ini_set('highlight.keyword', '#D24; font-weight: bold');
+ ini_set('highlight.string', '#080');
+ }
+
+
+ private function parse()
+ {
+ if (count($this->files) > 0) {
+ return;
+ }
+
+ $this->files = array();
+ foreach ($this->getSourceIterator() as $entry) {
+ $entry = (string) $entry;
+
+ $coverage = $covered = $total = 0;
+ $loaded = isset($this->data[$entry]);
+ $lines = array();
+ if ($loaded) {
+ $lines = $this->data[$entry];
+ foreach ($lines as $flag) {
+ if ($flag >= self::CODE_UNTESTED) {
+ $total++;
+ }
+ if ($flag >= self::CODE_TESTED) {
+ $covered++;
+ }
+ }
+ $coverage = round($covered * 100 / $total);
+ $this->totalSum += $total;
+ $this->coveredSum += $covered;
+ }
+
+ $light = $total ? $total < 5 : count(file($entry)) < 50;
+ $this->files[] = (object) array(
+ 'name' => str_replace((is_dir($this->source) ? $this->source : dirname($this->source)) . DIRECTORY_SEPARATOR, '', $entry),
+ 'file' => $entry,
+ 'lines' => $lines,
+ 'coverage' => $coverage,
+ 'total' => $total,
+ 'class' => $light ? 'light' : ($loaded ? NULL : 'not-loaded'),
+ );
+ }
+ }
+
+}
diff --git a/vendor/nette/tester/src/CodeCoverage/Generators/template.phtml b/vendor/nette/tester/src/CodeCoverage/Generators/template.phtml
new file mode 100755
index 0000000..74bb51a
--- /dev/null
+++ b/vendor/nette/tester/src/CodeCoverage/Generators/template.phtml
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+ Code coverage
+
+
+
+
+
+ Code coverage %
+
+ $info): ?>
+
+
+ class ? " class='$info->class'" : '' ?>>
+ coverage ?> %
+
+ name ?>
+
+
+
+
+ ', highlight_file($info->file, TRUE));
+
+ end($source);
+ $numWidth = strlen((string) key($source));
+
+ unset($prevColor);
+ $tags = '';
+ foreach ($source as $n => $line) {
+ if (isset($info->lines[$n + 1]) && isset($classes[$info->lines[$n + 1]])) {
+ $color = $classes[$info->lines[$n + 1]];
+ } else {
+ $color = ''; // not executable
+ }
+ if (!isset($prevColor)) {
+ $prevColor = $color;
+ }
+ $line = sprintf("
%{$numWidth}s: ", $n + 1) . $line;
+ if ($prevColor !== $color || $n === count($source) - 1) {
+ echo '
', str_replace(' />', '>', $tags);
+ $openTags = array();
+ preg_match_all('#<([^>]+)#', $tags, $matches);
+ foreach ($matches[1] as $m) {
+ if ($m[0] === '/') {
+ array_pop($openTags);
+ } elseif (substr($m, -1) !== '/') {
+ $openTags[] = $m;
+ }
+ }
+ foreach (array_reverse($openTags) as $tag) {
+ echo '' . preg_replace('# .*#', '', $tag) . '>';
+ }
+ echo "
\n";
+ $tags = ($openTags ? '<' . implode('><', $openTags) . '>' : '');
+ $prevColor = $color;
+ }
+ $tags .= "$line
\n";
+ }
+ ?>
+
+
+
+
+
+
+
+
diff --git a/vendor/nette/tester/src/CodeCoverage/PhpParser.php b/vendor/nette/tester/src/CodeCoverage/PhpParser.php
new file mode 100755
index 0000000..5ac7c0d
--- /dev/null
+++ b/vendor/nette/tester/src/CodeCoverage/PhpParser.php
@@ -0,0 +1,183 @@
+ $functionInfo],
+ * classes: [className => $info],
+ * traits: [traitName => $info],
+ * interfaces: [interfaceName => $info],
+ * }
+ *
+ * where $functionInfo is:
+ * stdClass {
+ * start: int,
+ * end: int
+ * }
+ *
+ * and $info is:
+ * stdClass {
+ * start: int,
+ * end: int,
+ * methods: [methodName => $methodInfo]
+ * }
+ *
+ * where $methodInfo is:
+ * stdClass {
+ * start: int,
+ * end: int,
+ * visibility: public|protected|private
+ * }
+ */
+ public function parse($code)
+ {
+ $tokens = @token_get_all($code); // @ - source code can be written in newer PHP
+
+ $level = $classLevel = $functionLevel = NULL;
+ $namespace = '';
+ $line = 1;
+
+ $result = (object) array(
+ 'linesOfCode' => max(1, substr_count($code, "\n")),
+ 'linesOfComments' => 0,
+ 'functions' => array(),
+ 'classes' => array(),
+ 'traits' => array(),
+ 'interfaces' => array(),
+ );
+
+ $T_TRAIT = PHP_VERSION_ID < 50400 ? -1 : T_TRAIT;
+ while (list(, $token) = each($tokens)) {
+ if (is_array($token)) {
+ if (PHP_VERSION_ID < 50400 && $token[0] === T_STRING && strcasecmp($token[1], 'trait') === 0) {
+ $token[0] = $T_TRAIT;
+ }
+ $line = $token[2];
+ }
+
+ switch (is_array($token) ? $token[0] : $token) {
+ case T_NAMESPACE:
+ $namespace = ltrim(self::fetch($tokens, array(T_STRING, T_NS_SEPARATOR)) . '\\', '\\');
+ break;
+
+ case T_CLASS:
+ case T_INTERFACE:
+ case $T_TRAIT:
+ if ($name = self::fetch($tokens, T_STRING)) {
+ if ($token[0] === T_CLASS) {
+ $class = & $result->classes[$namespace . $name];
+ } elseif ($token[0] === T_INTERFACE) {
+ $class = & $result->interfaces[$namespace . $name];
+ } else {
+ $class = & $result->traits[$namespace . $name];
+ }
+
+ $classLevel = $level + 1;
+ $class = (object) array(
+ 'start' => $line,
+ 'end' => NULL,
+ 'methods' => array(),
+ );
+ }
+ break;
+
+ case T_PUBLIC:
+ case T_PROTECTED:
+ case T_PRIVATE:
+ $visibility = $token[1];
+ break;
+
+ case T_ABSTRACT:
+ $isAbstract = TRUE;
+ break;
+
+ case T_FUNCTION:
+ if (($name = self::fetch($tokens, T_STRING)) && !isset($isAbstract)) {
+ if (isset($class) && $level === $classLevel) {
+ $function = & $class->methods[$name];
+ $function = (object) array(
+ 'start' => $line,
+ 'end' => NULL,
+ 'visibility' => isset($visibility) ? $visibility : 'public',
+ );
+
+ } else {
+ $function = & $result->functions[$namespace . $name];
+ $function = (object) array(
+ 'start' => $line,
+ 'end' => NULL,
+ );
+ }
+ $functionLevel = $level + 1;
+ }
+ unset($visibility, $isAbstract);
+ break;
+
+ case T_CURLY_OPEN:
+ case T_DOLLAR_OPEN_CURLY_BRACES:
+ case '{':
+ $level++;
+ break;
+
+ case '}':
+ if (isset($function) && $level === $functionLevel) {
+ $function->end = $line;
+ unset($function);
+
+ } elseif (isset($class) && $level === $classLevel) {
+ $class->end = $line;
+ unset($class);
+ }
+ $level--;
+ break;
+
+ case T_COMMENT:
+ case T_DOC_COMMENT:
+ $result->linesOfComments += substr_count(trim($token[1]), "\n") + 1;
+ // break omitted
+
+ case T_WHITESPACE:
+ case T_CONSTANT_ENCAPSED_STRING:
+ $line += substr_count($token[1], "\n");
+ break;
+ }
+ }
+
+ return $result;
+ }
+
+
+ private static function fetch(& $tokens, $take)
+ {
+ $res = NULL;
+ while ($token = current($tokens)) {
+ list($token, $s) = is_array($token) ? $token : array($token, $token);
+ if (in_array($token, (array) $take, TRUE)) {
+ $res .= $s;
+ } elseif (!in_array($token, array(T_DOC_COMMENT, T_WHITESPACE, T_COMMENT), TRUE)) {
+ break;
+ }
+ next($tokens);
+ }
+ return $res;
+ }
+
+}
diff --git a/vendor/nette/tester/src/Framework/Assert.php b/vendor/nette/tester/src/Framework/Assert.php
new file mode 100755
index 0000000..7be630d
--- /dev/null
+++ b/vendor/nette/tester/src/Framework/Assert.php
@@ -0,0 +1,531 @@
+ '[^\r\n]+', // one or more of anything except the end of line characters
+ '%a\?%' => '[^\r\n]*', // zero or more of anything except the end of line characters
+ '%A%' => '.+', // one or more of anything including the end of line characters
+ '%A\?%' => '.*', // zero or more of anything including the end of line characters
+ '%s%' => '[\t ]+', // one or more white space characters except the end of line characters
+ '%s\?%' => '[\t ]*', // zero or more white space characters except the end of line characters
+ '%S%' => '\S+', // one or more of characters except the white space
+ '%S\?%' => '\S*', // zero or more of characters except the white space
+ '%c%' => '[^\r\n]', // a single character of any sort (except the end of line)
+ '%d%' => '[0-9]+', // one or more digits
+ '%d\?%' => '[0-9]*', // zero or more digits
+ '%i%' => '[+-]?[0-9]+', // signed integer value
+ '%f%' => '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?', // floating point number
+ '%h%' => '[0-9a-fA-F]+',// one or more HEX digits
+ '%ds%' => '[\\\\/]', // directory separator
+ '%(\[.+\][+*?{},\d]*)%' => '$1', // range
+ );
+
+ /** @var callable function (AssertException $exception) */
+ public static $onFailure;
+
+ /** @var int the count of assertions */
+ public static $counter = 0;
+
+
+ /**
+ * Checks assertion. Values must be exactly the same.
+ * @return void
+ */
+ public static function same($expected, $actual)
+ {
+ self::$counter++;
+ if ($actual !== $expected) {
+ self::fail('%1 should be %2', $actual, $expected);
+ }
+ }
+
+
+ /**
+ * Checks assertion. Values must not be exactly the same.
+ * @return void
+ */
+ public static function notSame($expected, $actual)
+ {
+ self::$counter++;
+ if ($actual === $expected) {
+ self::fail('%1 should not be %2', $actual, $expected);
+ }
+ }
+
+
+ /**
+ * Checks assertion. The identity of objects and the order of keys in the arrays are ignored.
+ * @return void
+ */
+ public static function equal($expected, $actual)
+ {
+ self::$counter++;
+ if (!self::isEqual($expected, $actual)) {
+ self::fail('%1 should be equal to %2', $actual, $expected);
+ }
+ }
+
+
+ /**
+ * Checks assertion. The identity of objects and the order of keys in the arrays are ignored.
+ * @return void
+ */
+ public static function notEqual($expected, $actual)
+ {
+ self::$counter++;
+ if (self::isEqual($expected, $actual)) {
+ self::fail('%1 should not be equal to %2', $actual, $expected);
+ }
+ }
+
+
+ /**
+ * Checks assertion. Values must contains expected needle.
+ * @return void
+ */
+ public static function contains($needle, $actual)
+ {
+ self::$counter++;
+ if (is_array($actual)) {
+ if (!in_array($needle, $actual, TRUE)) {
+ self::fail('%1 should contain %2', $actual, $needle);
+ }
+ } elseif (is_string($actual)) {
+ if ($needle !== '' && strpos($actual, $needle) === FALSE) {
+ self::fail('%1 should contain %2', $actual, $needle);
+ }
+ } else {
+ self::fail('%1 should be string or array', $actual);
+ }
+ }
+
+
+ /**
+ * Checks assertion. Values must not contains expected needle.
+ * @return void
+ */
+ public static function notContains($needle, $actual)
+ {
+ self::$counter++;
+ if (is_array($actual)) {
+ if (in_array($needle, $actual, TRUE)) {
+ self::fail('%1 should not contain %2', $actual, $needle);
+ }
+ } elseif (is_string($actual)) {
+ if ($needle === '' || strpos($actual, $needle) !== FALSE) {
+ self::fail('%1 should not contain %2', $actual, $needle);
+ }
+ } else {
+ self::fail('%1 should be string or array', $actual);
+ }
+ }
+
+
+ /**
+ * Checks TRUE assertion.
+ * @param mixed actual
+ * @return void
+ */
+ public static function true($actual)
+ {
+ self::$counter++;
+ if ($actual !== TRUE) {
+ self::fail('%1 should be TRUE', $actual);
+ }
+ }
+
+
+ /**
+ * Checks FALSE assertion.
+ * @param mixed actual
+ * @return void
+ */
+ public static function false($actual)
+ {
+ self::$counter++;
+ if ($actual !== FALSE) {
+ self::fail('%1 should be FALSE', $actual);
+ }
+ }
+
+
+ /**
+ * Checks NULL assertion.
+ * @param mixed actual
+ * @return void
+ */
+ public static function null($actual)
+ {
+ self::$counter++;
+ if ($actual !== NULL) {
+ self::fail('%1 should be NULL', $actual);
+ }
+ }
+
+
+ /**
+ * Checks Not a Number assertion.
+ * @param mixed actual
+ * @return void
+ */
+ public static function nan($actual)
+ {
+ self::$counter++;
+ if (!is_float($actual) || !is_nan($actual)) {
+ self::fail('%1 should be NAN', $actual);
+ }
+ }
+
+
+ /**
+ * Checks truthy assertion.
+ * @param mixed actual
+ * @return void
+ */
+ public static function truthy($actual)
+ {
+ self::$counter++;
+ if (!$actual) {
+ self::fail('%1 should be truthy', $actual);
+ }
+ }
+
+
+ /**
+ * Checks falsey (empty) assertion.
+ * @param mixed actual
+ * @return void
+ */
+ public static function falsey($actual)
+ {
+ self::$counter++;
+ if ($actual) {
+ self::fail('%1 should be falsey', $actual);
+ }
+ }
+
+
+ /**
+ * Checks if subject has expected count.
+ * @param int expected count
+ * @param mixed subject
+ * @return void
+ */
+ public static function count($count, $value)
+ {
+ self::$counter++;
+ if (!$value instanceof \Countable && !is_array($value)) {
+ self::fail('%1 should be array or countable object', $value);
+
+ } elseif (count($value) !== $count) {
+ self::fail('Count %1 should be %2', count($value), $count);
+ }
+ }
+
+
+ /**
+ * Checks assertion.
+ * @return void
+ */
+ public static function type($type, $value)
+ {
+ self::$counter++;
+ if (!is_object($type) && !is_string($type)) {
+ throw new \Exception('Type must be a object or a string.');
+
+ } elseif ($type === 'list') {
+ if (!is_array($value) || ($value && array_keys($value) !== range(0, count($value) - 1))) {
+ self::fail("%1 should be $type", $value);
+ }
+
+ } elseif (in_array($type, array('array', 'bool', 'callable', 'float',
+ 'int', 'integer', 'null', 'object', 'resource', 'scalar', 'string'), TRUE)
+ ) {
+ if (!call_user_func("is_$type", $value)) {
+ self::fail(gettype($value) . " should be $type");
+ }
+
+ } elseif (!$value instanceof $type) {
+ $actual = is_object($value) ? get_class($value) : gettype($value);
+ self::fail("$actual should be instance of $type");
+ }
+ }
+
+
+ /**
+ * Checks if the function throws exception.
+ * @param callable
+ * @param string class
+ * @param string message
+ * @param int code
+ * @return \Exception
+ */
+ public static function exception($function, $class, $message = NULL, $code = NULL)
+ {
+ self::$counter++;
+ $e = NULL;
+ try {
+ call_user_func($function);
+ } catch (\Throwable $e) {
+ } catch (\Exception $e) {
+ }
+ if ($e === NULL) {
+ self::fail("$class was expected, but none was thrown");
+
+ } elseif (!$e instanceof $class) {
+ self::fail("$class was expected but got " . get_class($e) . ($e->getMessage() ? " ({$e->getMessage()})" : ''));
+
+ } elseif ($message && !self::isMatching($message, $e->getMessage())) {
+ self::fail("$class with a message matching %2 was expected but got %1", $e->getMessage(), $message);
+
+ } elseif ($code !== NULL && $e->getCode() !== $code) {
+ self::fail("$class with a code %2 was expected but got %1", $e->getCode(), $code);
+ }
+ return $e;
+ }
+
+
+ /**
+ * Checks if the function throws exception, alias for exception().
+ * @return \Exception
+ */
+ public static function throws($function, $class, $message = NULL, $code = NULL)
+ {
+ return self::exception($function, $class, $message, $code);
+ }
+
+
+ /**
+ * Checks if the function generates PHP error or throws exception.
+ * @param callable
+ * @param int|string|array
+ * @param string message
+ * @return null|\Exception
+ */
+ public static function error($function, $expectedType, $expectedMessage = NULL)
+ {
+ if (is_string($expectedType) && !preg_match('#^E_[A-Z_]+\z#', $expectedType)) {
+ return static::exception($function, $expectedType, $expectedMessage);
+ }
+
+ self::$counter++;
+ $expected = is_array($expectedType) ? $expectedType : array(array($expectedType, $expectedMessage));
+ foreach ($expected as & $item) {
+ list($expectedType, $expectedMessage) = $item;
+ if (is_int($expectedType)) {
+ $item[2] = Helpers::errorTypeToString($expectedType);
+ } elseif (is_string($expectedType)) {
+ $item[0] = constant($item[2] = $expectedType);
+ } else {
+ throw new \Exception('Error type must be E_* constant.');
+ }
+ }
+
+ set_error_handler(function ($severity, $message, $file, $line) use (& $expected) {
+ if (($severity & error_reporting()) !== $severity) {
+ return;
+ }
+
+ $errorStr = Helpers::errorTypeToString($severity) . ($message ? " ($message)" : '');
+ list($expectedType, $expectedMessage, $expectedTypeStr) = array_shift($expected);
+ if ($expectedType === NULL) {
+ restore_error_handler();
+ Assert::fail("Generated more errors than expected: $errorStr was generated in file $file on line $line");
+
+ } elseif ($severity !== $expectedType) {
+ restore_error_handler();
+ Assert::fail("$expectedTypeStr was expected, but $errorStr was generated in file $file on line $line");
+
+ } elseif ($expectedMessage && !Assert::isMatching($expectedMessage, $message)) {
+ restore_error_handler();
+ Assert::fail("$expectedTypeStr with a message matching %2 was expected but got %1", $message, $expectedMessage);
+ }
+ });
+
+ reset($expected);
+ call_user_func($function);
+ restore_error_handler();
+
+ if ($expected) {
+ self::fail('Error was expected, but was not generated');
+ }
+ }
+
+
+ /**
+ * Compares result using regular expression or mask:
+ * %a% one or more of anything except the end of line characters
+ * %a?% zero or more of anything except the end of line characters
+ * %A% one or more of anything including the end of line characters
+ * %A?% zero or more of anything including the end of line characters
+ * %s% one or more white space characters except the end of line characters
+ * %s?% zero or more white space characters except the end of line characters
+ * %S% one or more of characters except the white space
+ * %S?% zero or more of characters except the white space
+ * %c% a single character of any sort (except the end of line)
+ * %d% one or more digits
+ * %d?% zero or more digits
+ * %i% signed integer value
+ * %f% floating point number
+ * %h% one or more HEX digits
+ * @param string mask|regexp; only delimiters ~ and # are supported for regexp
+ * @param string
+ * @return void
+ */
+ public static function match($pattern, $actual)
+ {
+ self::$counter++;
+ if (!is_string($pattern)) {
+ throw new \Exception('Pattern must be a string.');
+
+ } elseif (!is_scalar($actual) || !self::isMatching($pattern, $actual)) {
+ self::fail('%1 should match %2', $actual, rtrim($pattern));
+ }
+ }
+
+
+ /**
+ * Compares results using mask sorted in file.
+ * @return void
+ */
+ public static function matchFile($file, $actual)
+ {
+ self::$counter++;
+ $pattern = @file_get_contents($file); // @ is escalated to exception
+ if ($pattern === FALSE) {
+ throw new \Exception("Unable to read file '$file'.");
+
+ } elseif (!is_scalar($actual) || !self::isMatching($pattern, $actual)) {
+ self::fail('%1 should match %2', $actual, rtrim($pattern));
+ }
+ }
+
+
+ /**
+ * Failed assertion
+ * @return void
+ */
+ public static function fail($message, $actual = NULL, $expected = NULL)
+ {
+ $e = new AssertException($message, $expected, $actual);
+ if (self::$onFailure) {
+ call_user_func(self::$onFailure, $e);
+ } else {
+ throw $e;
+ }
+ }
+
+
+ public static function with($obj, \Closure $closure)
+ {
+ return $closure->bindTo($obj, $obj)->__invoke();
+ }
+
+
+ /********************* helpers ****************d*g**/
+
+
+ /**
+ * Compares using mask.
+ * @return bool
+ * @internal
+ */
+ public static function isMatching($pattern, $actual)
+ {
+ if (!is_string($pattern) && !is_scalar($actual)) {
+ throw new \Exception('Value and pattern must be strings.');
+ }
+
+ $old = ini_set('pcre.backtrack_limit', '10000000');
+
+ if (!preg_match('/^([~#]).+(\1)[imsxUu]*\z/s', $pattern)) {
+ $utf8 = preg_match('#\x80-\x{10FFFF}]#u', $pattern) ? 'u' : '';
+ $patterns = static::$patterns + array(
+ '[.\\\\+*?[^$(){|\x00\#]' => '\$0', // preg quoting
+ '[\t ]*\r?\n' => "[\\t ]*\n", // right trim
+ );
+ $pattern = '#^' . preg_replace_callback('#' . implode('|', array_keys($patterns)) . '#U' . $utf8, function ($m) use ($patterns) {
+ foreach ($patterns as $re => $replacement) {
+ $s = preg_replace("#^$re\\z#", str_replace('\\', '\\\\', $replacement), $m[0], 1, $count);
+ if ($count) {
+ return $s;
+ }
+ }
+ }, rtrim($pattern)) . '\s*$#sU' . $utf8;
+ $actual = str_replace("\r\n", "\n", $actual);
+ }
+
+ $res = preg_match($pattern, $actual);
+ ini_set('pcre.backtrack_limit', $old);
+ if ($res === FALSE || preg_last_error()) {
+ throw new \Exception('Error while executing regular expression. (PREG Error Code ' . preg_last_error() . ')');
+ }
+ return (bool) $res;
+ }
+
+
+ /**
+ * Compares two structures. Ignores the identity of objects and the order of keys in the arrays.
+ * @return bool
+ * @internal
+ */
+ public static function isEqual($expected, $actual, $level = 0, $objects = NULL)
+ {
+ if ($level > 10) {
+ throw new \Exception('Nesting level too deep or recursive dependency.');
+ }
+
+ if (is_float($expected) && is_float($actual) && is_finite($expected) && is_finite($actual)) {
+ $diff = abs($expected - $actual);
+ return ($diff < self::EPSILON) || ($diff / max(abs($expected), abs($actual)) < self::EPSILON);
+ }
+
+ if (is_object($expected) && is_object($actual) && get_class($expected) === get_class($actual)) {
+ $objects = $objects ? clone $objects : new \SplObjectStorage;
+ if (isset($objects[$expected])) {
+ return $objects[$expected] === $actual;
+ } elseif ($expected === $actual) {
+ return TRUE;
+ }
+ $objects[$expected] = $actual;
+ $objects[$actual] = $expected;
+ $expected = (array) $expected;
+ $actual = (array) $actual;
+ }
+
+ if (is_array($expected) && is_array($actual)) {
+ ksort($expected, SORT_STRING);
+ ksort($actual, SORT_STRING);
+ if (array_keys($expected) !== array_keys($actual)) {
+ return FALSE;
+ }
+
+ foreach ($expected as $value) {
+ if (!self::isEqual($value, current($actual), $level + 1, $objects)) {
+ return FALSE;
+ }
+ next($actual);
+ }
+ return TRUE;
+ }
+
+ return $expected === $actual;
+ }
+
+}
diff --git a/vendor/nette/tester/src/Framework/AssertException.php b/vendor/nette/tester/src/Framework/AssertException.php
new file mode 100755
index 0000000..9049f83
--- /dev/null
+++ b/vendor/nette/tester/src/Framework/AssertException.php
@@ -0,0 +1,42 @@
+expected = $expected;
+ $this->actual = $actual;
+ $this->setMessage($message);
+ }
+
+
+ public function setMessage($message)
+ {
+ $this->origMessage = $message;
+ $this->message = strtr($message, array(
+ '%1' => Dumper::toLine($this->actual),
+ '%2' => Dumper::toLine($this->expected),
+ ));
+ return $this;
+ }
+
+}
diff --git a/vendor/nette/tester/src/Framework/DataProvider.php b/vendor/nette/tester/src/Framework/DataProvider.php
new file mode 100755
index 0000000..dc015ee
--- /dev/null
+++ b/vendor/nette/tester/src/Framework/DataProvider.php
@@ -0,0 +1,98 @@
+ $value) {
+ if (!self::testQuery($key, $query)) {
+ unset($data[$key]);
+ }
+ }
+
+ if (!$data) {
+ throw new \Exception("No records in data-provider file '$file'" . ($query ? " for query '$query'" : '') . '.');
+ }
+ return $data;
+ }
+
+
+ public static function testQuery($input, $query)
+ {
+ static $replaces = array('' => '=', '=>' => '>=', '=<' => '<=');
+ $tokens = preg_split('#\s+#', $input);
+ preg_match_all('#\s*,?\s*(<=|=<|<|==|=|!=|<>|>=|=>|>)?\s*([^\s,]+)#A', $query, $queryParts, PREG_SET_ORDER);
+ foreach ($queryParts as $queryPart) {
+ list(, $operator, $operand) = $queryPart;
+ $operator = isset($replaces[$operator]) ? $replaces[$operator] : $operator;
+ $token = array_shift($tokens);
+ $res = preg_match('#^[0-9.]+\z#', $token)
+ ? version_compare($token, $operand, $operator)
+ : self::compare($token, $operator, $operand);
+ if (!$res) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+
+ private static function compare($l, $operator, $r)
+ {
+ switch ($operator) {
+ case '>':
+ return $l > $r;
+ case '=>':
+ case '>=':
+ return $l >= $r;
+ case '<':
+ return $l < $r;
+ case '=<':
+ case '<=':
+ return $l <= $r;
+ case '=':
+ case '==':
+ return $l == $r;
+ case '!':
+ case '!=':
+ case '<>':
+ return $l != $r;
+ }
+ throw new \InvalidArgumentException("Unknown operator $operator.");
+ }
+
+
+ /**
+ * @return [file, query, optional]
+ * @internal
+ */
+ public static function parseAnnotation($annotation, $file)
+ {
+ if (!preg_match('#^(\??)\s*([^,\s]+)\s*,?\s*(\S.*)?()#', $annotation, $m)) {
+ throw new \Exception("Invalid @dataProvider value '$annotation'.");
+ }
+ return array(dirname($file) . DIRECTORY_SEPARATOR . $m[2], $m[3], (bool) $m[1]);
+ }
+
+}
diff --git a/vendor/nette/tester/src/Framework/DomQuery.php b/vendor/nette/tester/src/Framework/DomQuery.php
new file mode 100755
index 0000000..7239b44
--- /dev/null
+++ b/vendor/nette/tester/src/Framework/DomQuery.php
@@ -0,0 +1,140 @@
+' . $html;
+ }
+
+ $html = preg_replace('#<(keygen|source|track|wbr)(?=\s|>)("[^"]*"|\'[^\']*\'|[^"\'>]+)*+(?#', '<$1$2 />', $html);
+
+ $dom = new \DOMDocument();
+ $old = libxml_use_internal_errors(TRUE);
+ libxml_clear_errors();
+ $dom->loadHTML($html);
+ $errors = libxml_get_errors();
+ libxml_use_internal_errors($old);
+
+ $re = '#Tag (article|aside|audio|bdi|canvas|data|datalist|figcaption|figure|footer|header|keygen|main|mark'
+ . '|meter|nav|output|progress|rb|rp|rt|rtc|ruby|section|source|template|time|track|video|wbr) invalid#';
+ foreach ($errors as $error) {
+ if (!preg_match($re, $error->message)) {
+ trigger_error(__METHOD__ . ": $error->message on line $error->line.", E_USER_WARNING);
+ }
+ }
+ return simplexml_import_dom($dom, __CLASS__);
+ }
+
+
+ /**
+ * @return DomQuery
+ */
+ public static function fromXml($xml)
+ {
+ return simplexml_load_string($xml, __CLASS__);
+ }
+
+
+ /**
+ * Returns array of descendants filtered by a selector.
+ * @return DomQuery[]
+ */
+ public function find($selector)
+ {
+ return $this->xpath(self::css2xpath($selector));
+ }
+
+
+ /**
+ * Check the current document against a selector.
+ * @return bool
+ */
+ public function has($selector)
+ {
+ return (bool) $this->find($selector);
+ }
+
+
+ /**
+ * Transforms CSS expression to XPath.
+ * @return string
+ */
+ public static function css2xpath($css)
+ {
+ $xpath = '//*';
+ preg_match_all('/
+ ([#.:]?)([a-z][a-z0-9_-]*)| # id, class, pseudoclass (1,2)
+ \[
+ ([a-z0-9_-]+)
+ (?:
+ ([~*^$]?)=(
+ "[^"]*"|
+ \'[^\']*\'|
+ [^\]]+
+ )
+ )?
+ \]| # [attr=val] (3,4,5)
+ \s*([>,+~])\s*| # > , + ~ (6)
+ (\s+)| # whitespace (7)
+ (\*) # * (8)
+ /ix', trim($css), $matches, PREG_SET_ORDER);
+ foreach ($matches as $m) {
+ if ($m[1] === '#') { // #ID
+ $xpath .= "[@id='$m[2]']";
+ } elseif ($m[1] === '.') { // .class
+ $xpath .= "[contains(concat(' ', normalize-space(@class), ' '), ' $m[2] ')]";
+ } elseif ($m[1] === ':') { // :pseudo-class
+ throw new \InvalidArgumentException('Not implemented.');
+ } elseif ($m[2]) { // tag
+ $xpath = rtrim($xpath, '*') . $m[2];
+ } elseif ($m[3]) { // [attribute]
+ $attr = '@' . strtolower($m[3]);
+ if (!isset($m[5])) {
+ $xpath .= "[$attr]";
+ continue;
+ }
+ $val = trim($m[5], '"\'');
+ if ($m[4] === '') {
+ $xpath .= "[$attr='$val']";
+ } elseif ($m[4] === '~') {
+ $xpath .= "[contains(concat(' ', normalize-space($attr), ' '), ' $val ')]";
+ } elseif ($m[4] === '*') {
+ $xpath .= "[contains($attr, '$val')]";
+ } elseif ($m[4] === '^') {
+ $xpath .= "[starts-with($attr, '$val')]";
+ } elseif ($m[4] === '$') {
+ $xpath .= "[substring($attr, string-length($attr)-0)='$val']";
+ }
+ } elseif ($m[6] === '>') {
+ $xpath .= '/*';
+ } elseif ($m[6] === ',') {
+ $xpath .= '|//*';
+ } elseif ($m[6] === '~') {
+ $xpath .= '/following-sibling::*';
+ } elseif ($m[6] === '+') {
+ throw new \InvalidArgumentException('Not implemented.');
+ } elseif ($m[7]) {
+ $xpath .= '//*';
+ }
+ }
+ return $xpath;
+ }
+
+}
diff --git a/vendor/nette/tester/src/Framework/Dumper.php b/vendor/nette/tester/src/Framework/Dumper.php
new file mode 100755
index 0000000..7ffc2c7
--- /dev/null
+++ b/vendor/nette/tester/src/Framework/Dumper.php
@@ -0,0 +1,358 @@
+ self::$maxLength) {
+ $var = substr($var, 0, self::$maxLength) . '...';
+ }
+ return (preg_match('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u', $var) || preg_last_error() ? '"' . strtr($var, $table) . '"' : "'$var'");
+
+ } elseif (is_array($var)) {
+ $out = '';
+ $counter = 0;
+ foreach ($var as $k => & $v) {
+ $out .= ($out === '' ? '' : ', ');
+ if (strlen($out) > self::$maxLength) {
+ $out .= '...';
+ break;
+ }
+ $out .= ($k === $counter ? '' : self::toLine($k) . ' => ')
+ . (is_array($v) ? 'array(...)' : self::toLine($v));
+ $counter = is_int($k) ? max($k + 1, $counter) : $counter;
+ }
+ return "array($out)";
+
+ } elseif ($var instanceof \Exception || $var instanceof \Throwable) {
+ return 'Exception ' . get_class($var) . ': ' . ($var->getCode() ? '#' . $var->getCode() . ' ' : '') . $var->getMessage();
+
+ } elseif (is_object($var)) {
+ return self::objectToLine($var);
+
+ } elseif (is_resource($var)) {
+ return 'resource(' . get_resource_type($var) . ')';
+
+ } else {
+ return 'unknown type';
+ }
+ }
+
+
+ /**
+ * Formats object to line.
+ * @param object
+ * @return string
+ */
+ private static function objectToLine($object)
+ {
+ $line = get_class($object);
+ if ($object instanceof \DateTime || $object instanceof \DateTimeInterface) {
+ $line .= '(' . $object->format('Y-m-d H:i:s O') . ')';
+ }
+
+ return $line . '(#' . substr(md5(spl_object_hash($object)), 0, 4) . ')';
+ }
+
+
+ /**
+ * Dumps variable in PHP format.
+ * @param mixed variable to dump
+ * @return string
+ */
+ public static function toPhp($var)
+ {
+ return self::_toPhp($var);
+ }
+
+
+ /**
+ * @return string
+ */
+ private static function _toPhp(&$var, & $list = array(), $level = 0, & $line = 1)
+ {
+ if (is_float($var)) {
+ $var = str_replace(',', '.', "$var");
+ return strpos($var, '.') === FALSE ? $var . '.0' : $var;
+
+ } elseif (is_bool($var)) {
+ return $var ? 'TRUE' : 'FALSE';
+
+ } elseif (is_string($var) && (preg_match('#[^\x09\x20-\x7E\xA0-\x{10FFFF}]#u', $var) || preg_last_error())) {
+ static $table;
+ if ($table === NULL) {
+ foreach (array_merge(range("\x00", "\x1F"), range("\x7F", "\xFF")) as $ch) {
+ $table[$ch] = '\x' . str_pad(dechex(ord($ch)), 2, '0', STR_PAD_LEFT);
+ }
+ $table['\\'] = '\\\\';
+ $table["\r"] = '\r';
+ $table["\n"] = '\n';
+ $table["\t"] = '\t';
+ $table['$'] = '\$';
+ $table['"'] = '\"';
+ }
+ return '"' . strtr($var, $table) . '"';
+
+ } elseif (is_array($var)) {
+ $space = str_repeat("\t", $level);
+
+ static $marker;
+ if ($marker === NULL) {
+ $marker = uniqid("\x00", TRUE);
+ }
+ if (empty($var)) {
+ $out = '';
+
+ } elseif ($level > self::$maxDepth || isset($var[$marker])) {
+ return '/* Nesting level too deep or recursive dependency */';
+
+ } else {
+ $out = "\n$space";
+ $outShort = '';
+ $var[$marker] = TRUE;
+ $oldLine = $line;
+ $line++;
+ $counter = 0;
+ foreach ($var as $k => &$v) {
+ if ($k !== $marker) {
+ $item = ($k === $counter ? '' : self::_toPhp($k, $list, $level + 1, $line) . ' => ') . self::_toPhp($v, $list, $level + 1, $line);
+ $counter = is_int($k) ? max($k + 1, $counter) : $counter;
+ $outShort .= ($outShort === '' ? '' : ', ') . $item;
+ $out .= "\t$item,\n$space";
+ $line++;
+ }
+ }
+ unset($var[$marker]);
+ if (strpos($outShort, "\n") === FALSE && strlen($outShort) < self::$maxLength) {
+ $line = $oldLine;
+ $out = $outShort;
+ }
+ }
+ return 'array(' . $out . ')';
+
+ } elseif (is_object($var)) {
+ $arr = (array) $var;
+ $space = str_repeat("\t", $level);
+ $class = get_class($var);
+ $used = & $list[spl_object_hash($var)];
+
+ if (empty($arr)) {
+ $out = '';
+
+ } elseif ($used) {
+ return "/* $class dumped on line $used */";
+
+ } elseif ($level > self::$maxDepth) {
+ return '/* Nesting level too deep */';
+
+ } else {
+ $out = "\n";
+ $used = $line;
+ $line++;
+ foreach ($arr as $k => &$v) {
+ if ($k[0] === "\x00") {
+ $k = substr($k, strrpos($k, "\x00") + 1);
+ }
+ $out .= "$space\t" . self::_toPhp($k, $list, $level + 1, $line) . ' => ' . self::_toPhp($v, $list, $level + 1, $line) . ",\n";
+ $line++;
+ }
+ $out .= $space;
+ }
+ return $class === 'stdClass'
+ ? "(object) array($out)"
+ : "$class::__set_state(array($out))";
+
+ } elseif (is_resource($var)) {
+ return '/* resource ' . get_resource_type($var) . ' */';
+
+ } else {
+ $res = var_export($var, TRUE);
+ $line += substr_count($res, "\n");
+ return $res;
+ }
+ }
+
+
+ /**
+ * @param \Exception|\Throwable
+ * @internal
+ */
+ public static function dumpException($e)
+ {
+ $trace = $e->getTrace();
+ array_splice($trace, 0, $e instanceof \ErrorException ? 1 : 0, array(array('file' => $e->getFile(), 'line' => $e->getLine())));
+
+ $testFile = NULL;
+ foreach (array_reverse($trace) as $item) {
+ if (isset($item['file'])) { // in case of shutdown handler, we want to skip inner-code blocks and debugging calls
+ $testFile = $item['file'];
+ break;
+ }
+ }
+
+ if ($e instanceof AssertException) {
+ $expected = $e->expected;
+ $actual = $e->actual;
+
+ if (is_object($expected) || is_array($expected) || (is_string($expected) && strlen($expected) > self::$maxLength)
+ || is_object($actual) || is_array($actual) || (is_string($actual) && strlen($actual) > self::$maxLength)
+ ) {
+ $args = isset($_SERVER['argv'][1])
+ ? '.[' . implode(' ', preg_replace(array('#^-*(.{1,20}).*#i', '#[^=a-z0-9. -]+#i'), array('$1', '-'), array_slice($_SERVER['argv'], 1))) . ']'
+ : '';
+ $stored[] = self::saveOutput($testFile, $expected, $args . '.expected');
+ $stored[] = self::saveOutput($testFile, $actual, $args . '.actual');
+ }
+
+ if ((is_string($actual) && is_string($expected))) {
+ for ($i = 0; $i < strlen($actual) && isset($expected[$i]) && $actual[$i] === $expected[$i]; $i++);
+ $i = max(0, min($i, max(strlen($actual), strlen($expected)) - self::$maxLength + 3));
+ for (; $i && $i < count($actual) && $actual[$i - 1] >= "\x80" && $actual[$i] >= "\x80" && $actual[$i] < "\xC0"; $i--);
+ if ($i) {
+ $expected = substr_replace($expected, '...', 0, $i);
+ $actual = substr_replace($actual, '...', 0, $i);
+ }
+ }
+
+ $message = 'Failed: ' . $e->origMessage;
+ if (((is_string($actual) && is_string($expected)) || (is_array($actual) && is_array($expected)))
+ && preg_match('#^(.*)(%\d)(.*)(%\d.*)\z#s', $message, $m)
+ ) {
+ if (($delta = strlen($m[1]) - strlen($m[3])) >= 3) {
+ $message = "$m[1]$m[2]\n" . str_repeat(' ', $delta - 3) . "...$m[3]$m[4]";
+ } else {
+ $message = "$m[1]$m[2]$m[3]\n" . str_repeat(' ', strlen($m[1]) - 4) . "... $m[4]";
+ }
+ }
+ $message = strtr($message, array(
+ '%1' => self::color('yellow') . self::toLine($actual) . self::color('white'),
+ '%2' => self::color('yellow') . self::toLine($expected) . self::color('white'),
+ ));
+ } else {
+ $message = ($e instanceof \ErrorException ? Helpers::errorTypeToString($e->getSeverity()) : get_class($e))
+ . ': ' . preg_replace('#[\x00-\x09\x0B-\x1F]+#', ' ', $e->getMessage());
+ }
+
+ $s = self::color('white', $message) . "\n\n"
+ . (isset($stored) ? 'diff ' . Helpers::escapeArg($stored[0]) . ' ' . Helpers::escapeArg($stored[1]) . "\n\n" : '');
+
+ foreach ($trace as $item) {
+ $item += array('file' => NULL, 'class' => NULL, 'type' => NULL, 'function' => NULL);
+ if ($e instanceof AssertException && $item['file'] === __DIR__ . DIRECTORY_SEPARATOR . 'Assert.php') {
+ continue;
+ }
+
+ $s .= 'in '
+ . ($item['file']
+ ? (
+ ($item['file'] === $testFile ? self::color('white') : '')
+ . implode(DIRECTORY_SEPARATOR, array_slice(explode(DIRECTORY_SEPARATOR, $item['file']), -self::$maxPathSegments))
+ . "($item[line])" . self::color('gray') . ' '
+ )
+ : '[internal function]'
+ )
+ . $item['class'] . $item['type']
+ . (isset($item['function']) ? $item['function'] . '()' : '')
+ . self::color() . "\n";
+ }
+
+ if ($e->getPrevious()) {
+ $s .= "\n(previous) " . static::dumpException($e->getPrevious());
+ }
+ return $s;
+ }
+
+
+ /**
+ * Dumps data to folder 'output'.
+ * @return string
+ * @internal
+ */
+ public static function saveOutput($testFile, $content, $suffix = '')
+ {
+ $path = self::$dumpDir . DIRECTORY_SEPARATOR . basename($testFile, '.phpt') . $suffix;
+ if (!preg_match('#/|\w:#A', self::$dumpDir)) {
+ $path = dirname($testFile) . DIRECTORY_SEPARATOR . $path;
+ }
+ @mkdir(dirname($path)); // @ - directory may already exist
+ file_put_contents($path, is_string($content) ? $content : self::toPhp($content));
+ return $path;
+ }
+
+
+ /**
+ * Applies color to string.
+ * @return string
+ */
+ public static function color($color = NULL, $s = NULL)
+ {
+ static $colors = array(
+ 'black' => '0;30', 'gray' => '1;30', 'silver' => '0;37', 'white' => '1;37',
+ 'navy' => '0;34', 'blue' => '1;34', 'green' => '0;32', 'lime' => '1;32',
+ 'teal' => '0;36', 'aqua' => '1;36', 'maroon' => '0;31', 'red' => '1;31',
+ 'purple' => '0;35', 'fuchsia' => '1;35', 'olive' => '0;33', 'yellow' => '1;33',
+ NULL => '0',
+ );
+ $c = explode('/', $color);
+ return "\033[" . $colors[$c[0]] . (empty($c[1]) ? '' : ';4' . substr($colors[$c[1]], -1))
+ . 'm' . $s . ($s === NULL ? '' : "\033[0m");
+ }
+
+
+ public static function removeColors($s)
+ {
+ return preg_replace('#\033\[[\d;]+m#', '', $s);
+ }
+
+}
diff --git a/vendor/nette/tester/src/Framework/Environment.php b/vendor/nette/tester/src/Framework/Environment.php
new file mode 100755
index 0000000..a814fca
--- /dev/null
+++ b/vendor/nette/tester/src/Framework/Environment.php
@@ -0,0 +1,186 @@
+getMessage()}\n";
+ exit($e instanceof AssertException ? Runner\Job::CODE_FAIL : Runner\Job::CODE_ERROR);
+ }
+
+
+ /**
+ * Skips this test.
+ * @return void
+ */
+ public static function skip($message = '')
+ {
+ self::$checkAssertions = FALSE;
+ echo "\nSkipped:\n$message\n";
+ die(Runner\Job::CODE_SKIP);
+ }
+
+
+ /**
+ * Locks the parallel tests.
+ * @param string
+ * @param string lock store directory
+ * @return void
+ */
+ public static function lock($name = '', $path = '')
+ {
+ static $locks;
+ $file = "$path/lock-" . md5($name);
+ if (!isset($locks[$file])) {
+ flock($locks[$file] = fopen($file, 'w'), LOCK_EX);
+ }
+ }
+
+
+ /**
+ * Returns current test annotations.
+ * @return array
+ */
+ public static function getTestAnnotations()
+ {
+ $trace = debug_backtrace();
+ $file = $trace[count($trace) - 1]['file'];
+ return Helpers::parseDocComment(file_get_contents($file)) + array('file' => $file);
+ }
+
+
+ /**
+ * Loads data according to the file annotation or specified by Tester\Runner\TestHandler::initiateDataProvider()
+ * @return array
+ */
+ public static function loadData()
+ {
+ if (isset($_SERVER['argv']) && ($tmp = preg_filter('#--dataprovider=(.*)#Ai', '$1', $_SERVER['argv']))) {
+ list($query, $file) = explode('|', reset($tmp), 2);
+
+ } else {
+ $annotations = self::getTestAnnotations();
+ if (!isset($annotations['dataprovider'])) {
+ throw new \Exception('Missing annotation @dataProvider.');
+ }
+ $provider = (array) $annotations['dataprovider'];
+ list($file, $query) = DataProvider::parseAnnotation($provider[0], $annotations['file']);
+ }
+ $data = DataProvider::load($file, $query);
+ return reset($data);
+ }
+
+}
diff --git a/vendor/nette/tester/src/Framework/FileMock.php b/vendor/nette/tester/src/Framework/FileMock.php
new file mode 100755
index 0000000..d32fb3c
--- /dev/null
+++ b/vendor/nette/tester/src/Framework/FileMock.php
@@ -0,0 +1,125 @@
+content = & self::$files[$path];
+ $this->pos = strpos($mode, 'a') === FALSE ? 0 : strlen($this->content);
+ return TRUE;
+ }
+
+
+ public function stream_read($len)
+ {
+ $res = substr($this->content, $this->pos, $len);
+ $this->pos += strlen($res);
+ return $res;
+ }
+
+
+ public function stream_write($data)
+ {
+ $this->content = substr($this->content, 0, $this->pos)
+ . str_repeat("\x00", max(0, $this->pos - strlen($this->content)))
+ . $data
+ . substr($this->content, $this->pos + strlen($data));
+ $this->pos += strlen($data);
+ return strlen($data);
+ }
+
+
+ public function stream_tell()
+ {
+ return $this->pos;
+ }
+
+
+ public function stream_eof()
+ {
+ return $this->pos >= strlen($this->content);
+ }
+
+
+ public function stream_seek($offset, $whence)
+ {
+ if ($whence === SEEK_CUR) {
+ $offset += $this->pos;
+ } elseif ($whence === SEEK_END) {
+ $offset += strlen($this->content);
+ }
+ if ($offset >= 0) {
+ $this->pos = $offset;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+
+ public function stream_truncate($size)
+ {
+ $this->content = (string) substr($this->content, 0, $size)
+ . str_repeat("\x00", max(0, $size - strlen($this->content)));
+ return TRUE;
+ }
+
+
+ public function stream_stat()
+ {
+ return array('mode' => 0100666, 'size' => strlen($this->content));
+ }
+
+
+ public function url_stat($path, $flags)
+ {
+ return isset(self::$files[$path])
+ ? array('mode' => 0100666, 'size' => strlen(self::$files[$path]))
+ : FALSE;
+ }
+
+
+ public function stream_lock($operation)
+ {
+ return FALSE;
+ }
+
+}
diff --git a/vendor/nette/tester/src/Framework/Helpers.php b/vendor/nette/tester/src/Framework/Helpers.php
new file mode 100755
index 0000000..0fd9875
--- /dev/null
+++ b/vendor/nette/tester/src/Framework/Helpers.php
@@ -0,0 +1,93 @@
+isDir()) {
+ rmdir($entry);
+ } else {
+ unlink($entry);
+ }
+ }
+ }
+
+
+ /**
+ * Parse phpDoc comment.
+ * @return array
+ * @internal
+ */
+ public static function parseDocComment($s)
+ {
+ $options = array();
+ if (!preg_match('#^/\*\*(.*?)\*/#ms', $s, $content)) {
+ return array();
+ }
+ if (preg_match('#^[ \t\*]*+([^\s@].*)#mi', $content[1], $matches)) {
+ $options[0] = trim($matches[1]);
+ }
+ preg_match_all('#^[ \t\*]*@(\w+)([^\w\r\n].*)?#mi', $content[1], $matches, PREG_SET_ORDER);
+ foreach ($matches as $match) {
+ $ref = & $options[strtolower($match[1])];
+ if (isset($ref)) {
+ $ref = (array) $ref;
+ $ref = & $ref[];
+ }
+ $ref = isset($match[2]) ? trim($match[2]) : '';
+ }
+ return $options;
+ }
+
+
+ /**
+ * @internal
+ */
+ public static function errorTypeToString($type)
+ {
+ $consts = get_defined_constants(TRUE);
+ foreach ($consts['Core'] as $name => $val) {
+ if ($type === $val && substr($name, 0, 2) === 'E_') {
+ return $name;
+ }
+ }
+ }
+
+
+ /**
+ * Escape a string to be used as a shell argument.
+ * @return string
+ */
+ public static function escapeArg($s)
+ {
+ if (preg_match('#^[a-z0-9._-]+\z#i', $s)) {
+ return $s;
+ }
+
+ return defined('PHP_WINDOWS_VERSION_BUILD')
+ ? '"' . str_replace('"', '""', $s) . '"'
+ : escapeshellarg($s);
+ }
+
+}
diff --git a/vendor/nette/tester/src/Framework/TestCase.php b/vendor/nette/tester/src/Framework/TestCase.php
new file mode 100755
index 0000000..09e2cf3
--- /dev/null
+++ b/vendor/nette/tester/src/Framework/TestCase.php
@@ -0,0 +1,181 @@
+getName();
+ }, $r->getMethods())));
+
+ if (substr($method, 0, 2) === '--') { // back compatibility
+ $method = NULL;
+ }
+
+ if ($method === NULL && isset($_SERVER['argv']) && ($tmp = preg_filter('#(--method=)?([\w-]+)$#Ai', '$2', $_SERVER['argv']))) {
+ $method = reset($tmp);
+ if ($method === self::LIST_METHODS) {
+ Environment::$checkAssertions = FALSE;
+ header('Content-Type: text/plain');
+ echo '[' . implode(',', $methods) . ']';
+ return;
+ }
+ }
+
+ if ($method === NULL) {
+ foreach ($methods as $method) {
+ $this->runMethod($method);
+ }
+ } elseif (in_array($method, $methods, TRUE)) {
+ $this->runMethod($method);
+ } else {
+ throw new TestCaseException("Method '$method' does not exist or it is not a testing method.");
+ }
+ }
+
+
+ /**
+ * Runs the test method.
+ * @return void
+ */
+ private function runMethod($method)
+ {
+ $method = new \ReflectionMethod($this, $method);
+ if (!$method->isPublic()) {
+ throw new TestCaseException("Method {$method->getName()} is not public. Make it public or rename it.");
+ }
+
+ $data = array();
+ $info = Helpers::parseDocComment($method->getDocComment()) + array('dataprovider' => NULL, 'throws' => NULL);
+
+ if ($info['throws'] === '') {
+ throw new TestCaseException("Missing class name in @throws annotation for {$method->getName()}().");
+ } elseif (is_array($info['throws'])) {
+ throw new TestCaseException("Annotation @throws for {$method->getName()}() can be specified only once.");
+ } else {
+ $throws = preg_split('#\s+#', $info['throws'], 2) + array(NULL, NULL);
+ }
+
+ $defaultParams = array();
+ foreach ($method->getParameters() as $param) {
+ $defaultParams[$param->getName()] = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : NULL;
+ }
+
+ foreach ((array) $info['dataprovider'] as $provider) {
+ $res = $this->getData($provider);
+ if (!is_array($res)) {
+ throw new TestCaseException("Data provider $provider() doesn't return array.");
+ }
+ foreach ($res as $set) {
+ $data[] = is_string(key($set)) ? array_merge($defaultParams, $set) : $set;
+ }
+ }
+
+ if (!$info['dataprovider']) {
+ if ($method->getNumberOfRequiredParameters()) {
+ throw new TestCaseException("Method {$method->getName()}() has arguments, but @dataProvider is missing.");
+ }
+ $data[] = array();
+ }
+
+ foreach ($data as $args) {
+ try {
+ if ($info['throws']) {
+ $tmp = $this;
+ $e = Assert::error(function () use ($tmp, $method, $args) {
+ $tmp->runTest($method->getName(), $args);
+ }, $throws[0], $throws[1]);
+ if ($e instanceof AssertException) {
+ throw $e;
+ }
+ } else {
+ $this->runTest($method->getName(), $args);
+ }
+ } catch (AssertException $e) {
+ throw $e->setMessage("$e->origMessage in {$method->getName()}" . (substr(Dumper::toLine($args), 5)));
+ }
+ }
+ }
+
+
+ /**
+ * Runs the single test.
+ * @return void
+ */
+ public function runTest($name, array $args = array())
+ {
+ $this->setUp();
+ try {
+ call_user_func_array(array($this, $name), $args);
+ } catch (\Exception $e) {
+ }
+ try {
+ $this->tearDown();
+ } catch (\Exception $tearDownEx) {
+ throw isset($e) ? $e : $tearDownEx;
+ }
+ if (isset($e)) {
+ throw $e;
+ }
+ }
+
+
+ /**
+ * @return array
+ */
+ protected function getData($provider)
+ {
+ if (strpos($provider, '.')) {
+ $rc = new \ReflectionClass($this);
+ list($file, $query) = DataProvider::parseAnnotation($provider, $rc->getFileName());
+ return DataProvider::load($file, $query);
+ } else {
+ return $this->$provider();
+ }
+ }
+
+
+ /**
+ * This method is called before a test is executed.
+ * @return void
+ */
+ protected function setUp()
+ {
+ }
+
+
+ /**
+ * This method is called after a test is executed.
+ * @return void
+ */
+ protected function tearDown()
+ {
+ }
+
+}
+
+
+class TestCaseException extends \Exception
+{
+}
diff --git a/vendor/nette/tester/src/Runner/CliTester.php b/vendor/nette/tester/src/Runner/CliTester.php
new file mode 100755
index 0000000..226892a
--- /dev/null
+++ b/vendor/nette/tester/src/Runner/CliTester.php
@@ -0,0 +1,278 @@
+loadOptions();
+
+ Environment::$debugMode = (bool) $this->options['--debug'];
+ if (isset($this->options['--colors'])) {
+ Environment::$useColors = (bool) $this->options['--colors'];
+ } elseif (in_array($this->options['-o'], array('tap', 'junit'))) {
+ Environment::$useColors = FALSE;
+ }
+
+ if ($cmd->isEmpty() || $this->options['--help']) {
+ $cmd->help();
+ return;
+ }
+
+ $this->createPhpInterpreter();
+
+ if ($this->options['--info']) {
+ $job = new Job(__DIR__ . '/info.php', $this->interpreter);
+ $job->run();
+ echo $job->getOutput();
+ return;
+ }
+
+ if ($this->options['--coverage']) {
+ $coverageFile = $this->prepareCodeCoverage();
+ }
+
+ $runner = $this->createRunner();
+
+ if ($this->options['-o'] !== NULL) {
+ ob_clean();
+ }
+ ob_end_flush();
+
+ if ($this->options['--watch']) {
+ $this->watch($runner);
+ return;
+ }
+
+ $result = $runner->run();
+
+ if (isset($coverageFile)) {
+ $this->finishCodeCoverage($coverageFile);
+ }
+
+ return $result ? 0 : 1;
+ }
+
+
+ /** @return CommandLine */
+ private function loadOptions()
+ {
+ echo <<<'XX'
+ _____ ___ ___ _____ ___ ___
+|_ _/ __)( __/_ _/ __)| _ )
+ |_| \___ /___) |_| \___ |_|_\ v1.5.0
+
+
+XX;
+
+ $cmd = new CommandLine(<< | ]...
+
+Options:
+ -p Specify PHP interpreter to run (default: php-cgi).
+ -c Look for php.ini file (or look in directory) .
+ -l | --log Write log to file .
+ -d ... Define INI entry 'key' with value 'val'.
+ -s Show information about skipped tests.
+ --stop-on-fail Stop execution upon the first failure.
+ -j Run jobs in parallel (default: 8).
+ -o Specify output format.
+ -w | --watch Watch directory.
+ -i | --info Show tests environment info and exit.
+ --setup Script for runner setup.
+ --colors [1|0] Enable or disable colors.
+ --coverage Generate code coverage report to file.
+ --coverage-src Path to source code.
+ -h | --help This help.
+
+XX
+ , array(
+ '-c' => array(CommandLine::REALPATH => TRUE),
+ '--watch' => array(CommandLine::REPEATABLE => TRUE, CommandLine::REALPATH => TRUE),
+ '--setup' => array(CommandLine::REALPATH => TRUE),
+ 'paths' => array(CommandLine::REPEATABLE => TRUE, CommandLine::VALUE => getcwd()),
+ '--debug' => array(),
+ '--coverage-src' => array(CommandLine::REALPATH => TRUE),
+ ));
+
+ if (isset($_SERVER['argv'])) {
+ if ($tmp = array_search('-log', $_SERVER['argv'])) {
+ $_SERVER['argv'][$tmp] = '--log';
+ }
+
+ if ($tmp = array_search('--tap', $_SERVER['argv'])) {
+ unset($_SERVER['argv'][$tmp]);
+ $_SERVER['argv'] = array_merge($_SERVER['argv'], array('-o', 'tap'));
+ }
+ }
+
+ $this->options = $cmd->parse();
+ return $cmd;
+ }
+
+
+ /** @return void */
+ private function createPhpInterpreter()
+ {
+ $args = '';
+ if ($this->options['-c']) {
+ $args .= ' -c ' . Helpers::escapeArg($this->options['-c']);
+ } elseif (!$this->options['--info']) {
+ echo "Note: No php.ini is used.\n";
+ }
+
+ foreach ($this->options['-d'] as $item) {
+ $args .= ' -d ' . Helpers::escapeArg($item);
+ }
+
+ // Is the executable Zend PHP or HHVM?
+ $proc = @proc_open( // @ is escalated to exception
+ $this->options['-p'] . ' --version',
+ array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w')),
+ $pipes,
+ NULL,
+ NULL,
+ array('bypass_shell' => TRUE)
+ );
+ if ($proc === FALSE) {
+ throw new \Exception('Cannot run PHP interpreter ' . $this->options['-p'] . '. Use -p option.');
+ }
+ $output = stream_get_contents($pipes[1]);
+ $error = stream_get_contents($pipes[2]);
+ if (proc_close($proc)) {
+ throw new \Exception("Unable to run '{$this->options['-p']}': " . preg_replace('#[\r\n ]+#', ' ', $error));
+ }
+
+ if (preg_match('#HipHop VM#', $output)) {
+ $this->interpreter = new HhvmPhpInterpreter($this->options['-p'], $args);
+ } else {
+ $this->interpreter = new ZendPhpInterpreter($this->options['-p'], $args);
+ }
+
+ if ($this->interpreter->getErrorOutput()) {
+ echo Dumper::color('red', 'PHP startup error: ' . $this->interpreter->getErrorOutput()) . "\n";
+ if ($this->interpreter->isCgi()) {
+ echo "(note that PHP CLI generates better error messages)\n";
+ }
+ }
+ }
+
+
+ /** @return Runner */
+ private function createRunner()
+ {
+ $runner = new Runner($this->interpreter);
+ $runner->paths = $this->options['paths'];
+ $runner->threadCount = max(1, (int) $this->options['-j']);
+ $runner->stopOnFail = $this->options['--stop-on-fail'];
+
+ if ($this->options['-o'] !== 'none') {
+ switch ($this->options['-o']) {
+ case 'tap':
+ $runner->outputHandlers[] = new Output\TapPrinter($runner);
+ break;
+ case 'junit':
+ $runner->outputHandlers[] = new Output\JUnitPrinter($runner);
+ break;
+ default:
+ $runner->outputHandlers[] = new Output\ConsolePrinter($runner, $this->options['-s']);
+ }
+ }
+
+ if ($this->options['--log']) {
+ echo "Log: {$this->options['--log']}\n";
+ $runner->outputHandlers[] = new Output\Logger($runner, $this->options['--log']);
+ }
+
+ if ($this->options['--setup']) {
+ call_user_func(function () use ($runner) {
+ require func_get_arg(0);
+ }, $this->options['--setup']);
+ }
+ return $runner;
+ }
+
+
+ /** @return string */
+ private function prepareCodeCoverage()
+ {
+ if (!$this->interpreter->hasXdebug()) {
+ throw new \Exception("Code coverage functionality requires Xdebug extension (used {$this->interpreter->getCommandLine()})");
+ }
+ file_put_contents($this->options['--coverage'], '');
+ $file = realpath($this->options['--coverage']);
+ putenv(Environment::COVERAGE . '=' . $file);
+ echo "Code coverage: {$file}\n";
+ if (preg_match('#\.(?:html?|xml)\z#', $file)) {
+ return $file;
+ }
+ }
+
+
+ /** @return void */
+ private function finishCodeCoverage($file)
+ {
+ if (!in_array($this->options['-o'], array('none', 'tap', 'junit'), TRUE)) {
+ echo "Generating code coverage report\n";
+ }
+ if (pathinfo($file, PATHINFO_EXTENSION) === 'xml') {
+ $generator = new CodeCoverage\Generators\CloverXMLGenerator($file, $this->options['--coverage-src']);
+ } else {
+ $generator = new CodeCoverage\Generators\HtmlGenerator($file, $this->options['--coverage-src']);
+ }
+ $generator->render($file);
+ }
+
+
+ /** @return void */
+ private function watch(Runner $runner)
+ {
+ $prev = array();
+ $counter = 0;
+ while (TRUE) {
+ $state = array();
+ foreach ($this->options['--watch'] as $directory) {
+ foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($directory)) as $file) {
+ if (substr($file->getExtension(), 0, 3) === 'php' && substr($file->getBasename(), 0, 1) !== '.') {
+ $state[(string) $file] = md5_file((string) $file);
+ }
+ }
+ }
+ if ($state !== $prev) {
+ $prev = $state;
+ $runner->run();
+ }
+ echo 'Watching ' . implode(', ', $this->options['--watch']) . ' ' . str_repeat('.', ++$counter % 5) . " \r";
+ sleep(2);
+ }
+ }
+
+}
diff --git a/vendor/nette/tester/src/Runner/CommandLine.php b/vendor/nette/tester/src/Runner/CommandLine.php
new file mode 100755
index 0000000..6f280aa
--- /dev/null
+++ b/vendor/nette/tester/src/Runner/CommandLine.php
@@ -0,0 +1,171 @@
+help = $help;
+ $this->options = $defaults;
+
+ preg_match_all('#^[ \t]+(--?\w.*?)(?: .*\(default: (.*)\)| |\r|$)#m', $help, $lines, PREG_SET_ORDER);
+ foreach ($lines as $line) {
+ preg_match_all('#(--?\w[\w-]*)(?:[= ](<.*?>|\[.*?]|\w+)(\.{0,3}))?[ ,|]*#A', $line[1], $m);
+ if (!count($m[0]) || count($m[0]) > 2 || implode('', $m[0]) !== $line[1]) {
+ throw new \InvalidArgumentException("Unable to parse '$line[1]'.");
+ }
+
+ $name = end($m[1]);
+ $opts = isset($this->options[$name]) ? $this->options[$name] : array();
+ $this->options[$name] = $opts + array(
+ self::ARGUMENT => (bool) end($m[2]),
+ self::OPTIONAL => isset($line[2]) || (substr(end($m[2]), 0, 1) === '[') || isset($opts[self::VALUE]),
+ self::REPEATABLE => (bool) end($m[3]),
+ self::ENUM => count($enums = explode('|', trim(end($m[2]), '<[]>'))) > 1 ? $enums : NULL,
+ self::VALUE => isset($line[2]) ? $line[2] : NULL,
+ );
+ if ($name !== $m[1][0]) {
+ $this->aliases[$m[1][0]] = $name;
+ }
+ }
+
+ foreach ($this->options as $name => $foo) {
+ if ($name[0] !== '-') {
+ $this->positional[] = $name;
+ }
+ }
+ }
+
+
+ public function parse(array $args = NULL)
+ {
+ if ($args === NULL) {
+ $args = isset($_SERVER['argv']) ? array_slice($_SERVER['argv'], 1) : array();
+ }
+ $params = array();
+ reset($this->positional);
+ $i = 0;
+ while ($i < count($args)) {
+ $arg = $args[$i++];
+ if ($arg[0] !== '-') {
+ if (!current($this->positional)) {
+ throw new \Exception("Unexpected parameter $arg.");
+ }
+ $name = current($this->positional);
+ $this->checkArg($this->options[$name], $arg);
+ if (empty($this->options[$name][self::REPEATABLE])) {
+ $params[$name] = $arg;
+ next($this->positional);
+ } else {
+ $params[$name][] = $arg;
+ }
+ continue;
+ }
+
+ list($name, $arg) = strpos($arg, '=') ? explode('=', $arg, 2) : array($arg, TRUE);
+
+ if (isset($this->aliases[$name])) {
+ $name = $this->aliases[$name];
+
+ } elseif (!isset($this->options[$name])) {
+ throw new \Exception("Unknown option $name.");
+ }
+
+ $opt = $this->options[$name];
+
+ if ($arg !== TRUE && empty($opt[self::ARGUMENT])) {
+ throw new \Exception("Option $name has not argument.");
+
+ } elseif ($arg === TRUE && !empty($opt[self::ARGUMENT])) {
+ if (isset($args[$i]) && $args[$i][0] !== '-') {
+ $arg = $args[$i++];
+ } elseif (empty($opt[self::OPTIONAL])) {
+ throw new \Exception("Option $name requires argument.");
+ }
+ }
+
+ if (!empty($opt[self::ENUM]) && !in_array($arg, $opt[self::ENUM], TRUE) && !($opt[self::OPTIONAL] && $arg === TRUE)) {
+ throw new \Exception("Value of option $name must be " . implode(', or ', $opt[self::ENUM]) . ".");
+ }
+ $this->checkArg($opt, $arg);
+
+ if (empty($opt[self::REPEATABLE])) {
+ $params[$name] = $arg;
+ } else {
+ $params[$name][] = $arg;
+ }
+ }
+
+ foreach ($this->options as $name => $opt) {
+ if (isset($params[$name])) {
+ continue;
+ } elseif (isset($opt[self::VALUE])) {
+ $params[$name] = $opt[self::VALUE];
+ } elseif ($name[0] !== '-' && empty($opt[self::OPTIONAL])) {
+ throw new \Exception("Missing required argument <$name>.");
+ } else {
+ $params[$name] = NULL;
+ }
+ if (!empty($opt[self::REPEATABLE])) {
+ $params[$name] = (array) $params[$name];
+ }
+ }
+ return $params;
+ }
+
+
+ public function help()
+ {
+ echo $this->help;
+ }
+
+
+ public function checkArg(array $opt, & $arg)
+ {
+ if (!empty($opt[self::REALPATH])) {
+ $path = realpath($arg);
+ if ($path === FALSE) {
+ throw new \Exception("File path '$arg' not found.");
+ }
+ $arg = $path;
+ }
+ }
+
+
+ public function isEmpty()
+ {
+ return !isset($_SERVER['argv']) || count($_SERVER['argv']) < 2;
+ }
+
+}
diff --git a/vendor/nette/tester/src/Runner/HhvmPhpInterpreter.php b/vendor/nette/tester/src/Runner/HhvmPhpInterpreter.php
new file mode 100755
index 0000000..bd44ccb
--- /dev/null
+++ b/vendor/nette/tester/src/Runner/HhvmPhpInterpreter.php
@@ -0,0 +1,106 @@
+path = Helpers::escapeArg($path);
+ $proc = proc_open(
+ "$this->path --php $args -r " . Helpers::escapeArg('echo HHVM_VERSION . "|" . PHP_VERSION;'),
+ array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w')),
+ $pipes,
+ NULL,
+ NULL,
+ array('bypass_shell' => TRUE)
+ );
+ $output = stream_get_contents($pipes[1]);
+ $this->error = trim(stream_get_contents($pipes[2]));
+
+ if (proc_close($proc)) {
+ throw new \Exception("Unable to run '$path': " . preg_replace('#[\r\n ]+#', ' ', $this->error));
+ } elseif (count($tmp = explode('|', $output)) !== 2) {
+ throw new \Exception("Unable to detect HHVM version (output: $output).");
+ }
+
+ list($this->version, $this->phpVersion) = $tmp;
+ if (version_compare($this->version, '3.3.0', '<')) {
+ throw new \Exception('HHVM below version 3.3.0 is not supported.');
+ }
+ $this->arguments = ' --php -d hhvm.log.always_log_unhandled_exceptions=false' . ($args ? " $args" : ''); // HHVM issue #3019
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getCommandLine()
+ {
+ return $this->path . $this->arguments;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getVersion()
+ {
+ return $this->phpVersion;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function hasXdebug()
+ {
+ return FALSE;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isCgi()
+ {
+ return FALSE;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getErrorOutput()
+ {
+ return $this->error;
+ }
+
+}
diff --git a/vendor/nette/tester/src/Runner/Job.php b/vendor/nette/tester/src/Runner/Job.php
new file mode 100755
index 0000000..37eb3d8
--- /dev/null
+++ b/vendor/nette/tester/src/Runner/Job.php
@@ -0,0 +1,217 @@
+file = (string) $testFile;
+ $this->interpreter = $interpreter;
+ $this->args = (array) $args;
+ }
+
+
+ /**
+ * Runs single test.
+ * @param int RUN_ASYNC | RUN_COLLECT_ERRORS
+ * @return void
+ */
+ public function run($flags = NULL)
+ {
+ putenv(Environment::RUNNER . '=1');
+ putenv(Environment::COLORS . '=' . (int) Environment::$useColors);
+ $this->proc = proc_open(
+ $this->interpreter->getCommandLine()
+ . ' -n -d register_argc_argv=on ' . \Tester\Helpers::escapeArg($this->file) . ' ' . implode(' ', $this->args),
+ array(
+ array('pipe', 'r'),
+ array('pipe', 'w'),
+ array('pipe', 'w'),
+ ),
+ $pipes,
+ dirname($this->file),
+ NULL,
+ array('bypass_shell' => TRUE)
+ );
+
+ list($stdin, $this->stdout, $stderr) = $pipes;
+ fclose($stdin);
+ if ($flags & self::RUN_COLLECT_ERRORS) {
+ $this->stderr = $stderr;
+ } else {
+ fclose($stderr);
+ }
+
+ if ($flags & self::RUN_ASYNC) {
+ stream_set_blocking($this->stdout, 0); // on Windows does not work with proc_open()
+ if ($this->stderr) {
+ stream_set_blocking($this->stderr, 0);
+ }
+ } else {
+ while ($this->isRunning()) {
+ usleep(self::RUN_USLEEP); // stream_select() doesn't work with proc_open()
+ }
+ }
+ }
+
+
+ /**
+ * Checks if the test is still running.
+ * @return bool
+ */
+ public function isRunning()
+ {
+ if (!is_resource($this->stdout)) {
+ return FALSE;
+ }
+ $this->output .= stream_get_contents($this->stdout);
+ if ($this->stderr) {
+ $this->errorOutput .= stream_get_contents($this->stderr);
+ }
+
+ $status = proc_get_status($this->proc);
+ if ($status['running']) {
+ return TRUE;
+ }
+
+ fclose($this->stdout);
+ if ($this->stderr) {
+ fclose($this->stderr);
+ }
+ $code = proc_close($this->proc);
+ $this->exitCode = $code === self::CODE_NONE ? $status['exitcode'] : $code;
+
+ if ($this->interpreter->isCgi() && count($tmp = explode("\r\n\r\n", $this->output, 2)) >= 2) {
+ list($headers, $this->output) = $tmp;
+ foreach (explode("\r\n", $headers) as $header) {
+ $a = strpos($header, ':');
+ if ($a !== FALSE) {
+ $this->headers[trim(substr($header, 0, $a))] = (string) trim(substr($header, $a + 1));
+ }
+ }
+ }
+ return FALSE;
+ }
+
+
+ /**
+ * Returns test file path.
+ * @return string
+ */
+ public function getFile()
+ {
+ return $this->file;
+ }
+
+
+ /**
+ * Returns script arguments.
+ * @return string[]
+ */
+ public function getArguments()
+ {
+ return $this->args;
+ }
+
+
+ /**
+ * Returns exit code.
+ * @return int
+ */
+ public function getExitCode()
+ {
+ return $this->exitCode;
+ }
+
+
+ /**
+ * Returns test output.
+ * @return string
+ */
+ public function getOutput()
+ {
+ return $this->output;
+ }
+
+
+ /**
+ * Returns test error output.
+ * @return string|NULL
+ */
+ public function getErrorOutput()
+ {
+ return $this->errorOutput;
+ }
+
+
+ /**
+ * Returns output headers.
+ * @return string[]
+ */
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+
+}
diff --git a/vendor/nette/tester/src/Runner/Output/ConsolePrinter.php b/vendor/nette/tester/src/Runner/Output/ConsolePrinter.php
new file mode 100755
index 0000000..639fba6
--- /dev/null
+++ b/vendor/nette/tester/src/Runner/Output/ConsolePrinter.php
@@ -0,0 +1,84 @@
+runner = $runner;
+ $this->displaySkipped = $displaySkipped;
+ }
+
+
+ public function begin()
+ {
+ $this->time = -microtime(TRUE);
+ echo 'PHP ' . $this->runner->getInterpreter()->getVersion()
+ . ' | ' . $this->runner->getInterpreter()->getCommandLine()
+ . " | {$this->runner->threadCount} thread" . ($this->runner->threadCount > 1 ? 's' : '') . "\n\n";
+ }
+
+
+ public function result($testName, $result, $message)
+ {
+ $outputs = array(
+ Runner::PASSED => '.',
+ Runner::SKIPPED => 's',
+ Runner::FAILED => Dumper::color('white/red', 'F'),
+ );
+ echo $outputs[$result];
+
+ $message = ' ' . str_replace("\n", "\n ", trim($message)) . "\n\n";
+ if ($result === Runner::FAILED) {
+ $this->buffer .= Dumper::color('red', "-- FAILED: $testName") . "\n$message";
+ } elseif ($result === Runner::SKIPPED && $this->displaySkipped) {
+ $this->buffer .= "-- Skipped: $testName\n$message";
+ }
+ }
+
+
+ public function end()
+ {
+ $jobCount = $this->runner->getJobCount();
+ $results = $this->runner->getResults();
+ $count = array_sum($results);
+ echo !$jobCount ? "No tests found\n" :
+ "\n\n" . $this->buffer . "\n"
+ . ($results[Runner::FAILED] ? Dumper::color('white/red') . 'FAILURES!' : Dumper::color('white/green') . 'OK')
+ . " ($jobCount test" . ($jobCount > 1 ? 's' : '') . ", "
+ . ($results[Runner::FAILED] ? $results[Runner::FAILED] . ' failure' . ($results[Runner::FAILED] > 1 ? 's' : '') . ', ' : '')
+ . ($results[Runner::SKIPPED] ? $results[Runner::SKIPPED] . ' skipped, ' : '')
+ . ($jobCount !== $count ? ($jobCount - $count) . ' not run, ' : '')
+ . sprintf('%0.1f', $this->time + microtime(TRUE)) . ' seconds)' . Dumper::color() . "\n";
+
+ $this->buffer = NULL;
+ }
+
+}
diff --git a/vendor/nette/tester/src/Runner/Output/JUnitPrinter.php b/vendor/nette/tester/src/Runner/Output/JUnitPrinter.php
new file mode 100755
index 0000000..53544ce
--- /dev/null
+++ b/vendor/nette/tester/src/Runner/Output/JUnitPrinter.php
@@ -0,0 +1,75 @@
+runner = $runner;
+ $this->file = fopen($file, 'w');
+ }
+
+
+ public function begin()
+ {
+ $this->startTime = microtime(TRUE);
+ fwrite($this->file, "\n\n");
+ }
+
+
+ public function result($testName, $result, $message)
+ {
+ $this->buffer .= "\t\tbuffer .= ">\n\t\t\t \n\t\t \n";
+ break;
+ case Runner::SKIPPED:
+ $this->buffer .= ">\n\t\t\t \n\t\t\n";
+ break;
+ case Runner::PASSED:
+ $this->buffer .= "/>\n";
+ break;
+ }
+ }
+
+
+ public function end()
+ {
+ $time = sprintf('%0.1f', microtime(TRUE) - $this->startTime);
+ $output = $this->buffer;
+ $results = $this->runner->getResults();
+ $this->buffer = "\t\n";
+ $this->buffer .= $output;
+ $this->buffer .= "\t ";
+
+ fwrite($this->file, $this->buffer . "\n \n");
+ }
+
+}
diff --git a/vendor/nette/tester/src/Runner/Output/Logger.php b/vendor/nette/tester/src/Runner/Output/Logger.php
new file mode 100755
index 0000000..8a8ff89
--- /dev/null
+++ b/vendor/nette/tester/src/Runner/Output/Logger.php
@@ -0,0 +1,68 @@
+runner = $runner;
+ $this->file = fopen($file, 'w');
+ }
+
+
+ public function begin()
+ {
+ fwrite($this->file, 'PHP ' . $this->runner->getInterpreter()->getVersion()
+ . ' | ' . $this->runner->getInterpreter()->getCommandLine()
+ . " | {$this->runner->threadCount} threads\n\n");
+ }
+
+
+ public function result($testName, $result, $message)
+ {
+ $message = ' ' . str_replace("\n", "\n ", Tester\Dumper::removeColors(trim($message)));
+ $outputs = array(
+ Runner::PASSED => "-- OK: $testName",
+ Runner::SKIPPED => "-- Skipped: $testName\n$message",
+ Runner::FAILED => "-- FAILED: $testName\n$message",
+ );
+ fwrite($this->file, $outputs[$result] . "\n\n");
+ }
+
+
+ public function end()
+ {
+ $jobCount = $this->runner->getJobCount();
+ $results = $this->runner->getResults();
+ $count = array_sum($results);
+ fwrite($this->file,
+ ($results[Runner::FAILED] ? 'FAILURES!' : 'OK')
+ . " ($jobCount tests"
+ . ($results[Runner::FAILED] ? ", {$results[Runner::FAILED]} failures" : '')
+ . ($results[Runner::SKIPPED] ? ", {$results[Runner::SKIPPED]} skipped" : '')
+ . ($jobCount !== $count ? ', ' . ($jobCount - $count) . ' not run' : '')
+ . ')'
+ );
+ }
+
+}
diff --git a/vendor/nette/tester/src/Runner/Output/TapPrinter.php b/vendor/nette/tester/src/Runner/Output/TapPrinter.php
new file mode 100755
index 0000000..6e2ef42
--- /dev/null
+++ b/vendor/nette/tester/src/Runner/Output/TapPrinter.php
@@ -0,0 +1,56 @@
+runner = $runner;
+ $this->file = fopen($file, 'w');
+ }
+
+
+ public function begin()
+ {
+ fwrite($this->file, "TAP version 13\n");
+ }
+
+
+ public function result($testName, $result, $message)
+ {
+ $message = str_replace("\n", "\n# ", trim($message));
+ $outputs = array(
+ Runner::PASSED => "ok $testName",
+ Runner::SKIPPED => "ok $testName #skip $message",
+ Runner::FAILED => "not ok $testName\n# $message",
+ );
+ fwrite($this->file, $outputs[$result] . "\n");
+ }
+
+
+ public function end()
+ {
+ fwrite($this->file, '1..' . array_sum($this->runner->getResults()));
+ }
+
+}
diff --git a/vendor/nette/tester/src/Runner/OutputHandler.php b/vendor/nette/tester/src/Runner/OutputHandler.php
new file mode 100755
index 0000000..abb49e4
--- /dev/null
+++ b/vendor/nette/tester/src/Runner/OutputHandler.php
@@ -0,0 +1,25 @@
+interpreter = $interpreter;
+ $this->testHandler = new TestHandler($this);
+ }
+
+
+ /**
+ * Runs all tests.
+ * @return bool
+ */
+ public function run()
+ {
+ $this->interrupted = FALSE;
+
+ foreach ($this->outputHandlers as $handler) {
+ $handler->begin();
+ }
+
+ $this->results = array(self::PASSED => 0, self::SKIPPED => 0, self::FAILED => 0);
+ $this->jobs = $running = array();
+ foreach ($this->paths as $path) {
+ $this->findTests($path);
+ }
+ $this->jobCount = count($this->jobs) + array_sum($this->results);
+
+ $this->installInterruptHandler();
+ while (($this->jobs || $running) && !$this->isInterrupted()) {
+ for ($i = count($running); $this->jobs && $i < $this->threadCount; $i++) {
+ $running[] = $job = array_shift($this->jobs);
+ $async = $this->threadCount > 1 && (count($running) + count($this->jobs) > 1);
+ $job->run($async ? $job::RUN_ASYNC : NULL);
+ }
+
+ if (count($running) > 1) {
+ usleep(Job::RUN_USLEEP); // stream_select() doesn't work with proc_open()
+ }
+
+ foreach ($running as $key => $job) {
+ if ($this->isInterrupted()) {
+ break 2;
+ }
+
+ if (!$job->isRunning()) {
+ $this->testHandler->assess($job);
+ unset($running[$key]);
+ }
+ }
+ }
+ $this->removeInterruptHandler();
+
+ foreach ($this->outputHandlers as $handler) {
+ $handler->end();
+ }
+ return !$this->results[self::FAILED];
+ }
+
+
+ /**
+ * @return void
+ */
+ private function findTests($path)
+ {
+ if (strpbrk($path, '*?') === FALSE && !file_exists($path)) {
+ throw new \InvalidArgumentException("File or directory '$path' not found.");
+ }
+
+ if (is_dir($path)) {
+ foreach (glob(str_replace('[', '[[]', $path) . '/*', GLOB_ONLYDIR) ?: array() as $dir) {
+ $this->findTests($dir);
+ }
+ $path .= '/*.' . self::TEST_FILE_EXTENSION;
+ }
+ foreach (glob(str_replace('[', '[[]', $path)) ?: array() as $file) {
+ if (is_file($file)) {
+ $this->testHandler->initiate(realpath($file));
+ }
+ }
+ }
+
+
+ /**
+ * Appends new job to queue.
+ * @return void
+ */
+ public function addJob(Job $job)
+ {
+ $this->jobs[] = $job;
+ }
+
+
+ /**
+ * Get count of jobs.
+ * @return int
+ */
+ public function getJobCount()
+ {
+ return $this->jobCount;
+ }
+
+
+ /**
+ * Writes to output handlers.
+ * @return void
+ */
+ public function writeResult($testName, $result, $message = NULL)
+ {
+ $this->results[$result]++;
+ foreach ($this->outputHandlers as $handler) {
+ $handler->result($testName, $result, $message);
+ }
+
+ if ($this->stopOnFail && $result === self::FAILED) {
+ $this->interrupted = TRUE;
+ }
+ }
+
+
+ /**
+ * @return PhpInterpreter
+ */
+ public function getInterpreter()
+ {
+ return $this->interpreter;
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getResults()
+ {
+ return $this->results;
+ }
+
+
+ /**
+ * @return void
+ */
+ private function installInterruptHandler()
+ {
+ if (extension_loaded('pcntl')) {
+ $interrupted = & $this->interrupted;
+ pcntl_signal(SIGINT, function () use (& $interrupted) {
+ pcntl_signal(SIGINT, SIG_DFL);
+ $interrupted = TRUE;
+ });
+ }
+ }
+
+
+ /**
+ * @return void
+ */
+ private function removeInterruptHandler()
+ {
+ if (extension_loaded('pcntl')) {
+ pcntl_signal(SIGINT, SIG_DFL);
+ }
+ }
+
+
+ /**
+ * @return bool
+ */
+ private function isInterrupted()
+ {
+ if (extension_loaded('pcntl')) {
+ pcntl_signal_dispatch();
+ }
+
+ return $this->interrupted;
+ }
+
+}
diff --git a/vendor/nette/tester/src/Runner/TestHandler.php b/vendor/nette/tester/src/Runner/TestHandler.php
new file mode 100755
index 0000000..1364e6a
--- /dev/null
+++ b/vendor/nette/tester/src/Runner/TestHandler.php
@@ -0,0 +1,220 @@
+runner = $runner;
+ }
+
+
+ /**
+ * @return void
+ */
+ public function initiate($file)
+ {
+ list($annotations, $testName) = $this->getAnnotations($file);
+ $php = clone $this->runner->getInterpreter();
+ $jobsArgs = array(array());
+
+ foreach (get_class_methods($this) as $method) {
+ if (!preg_match('#^initiate(.+)#', strtolower($method), $m) || !isset($annotations[$m[1]])) {
+ continue;
+ }
+ foreach ((array) $annotations[$m[1]] as $value) {
+ $res = $this->$method($value, $php, $file);
+ if ($res && is_int($res[0])) { // [Runner::*, message]
+ $this->runner->writeResult($testName, $res[0], $res[1]);
+ return;
+ } elseif ($res && $res[1]) { // [param name, values]
+ $tmp = array();
+ foreach ($res[1] as $val) {
+ foreach ($jobsArgs as $args) {
+ $args[] = Helpers::escapeArg("--$res[0]=$val");
+ $tmp[] = $args;
+ }
+ }
+ $jobsArgs = $tmp;
+ }
+ }
+ }
+
+ foreach ($jobsArgs as $args) {
+ $this->runner->addJob(new Job($file, $php, $args));
+ }
+ }
+
+
+ /**
+ * @return void
+ */
+ public function assess(Job $job)
+ {
+ list($annotations, $testName) = $this->getAnnotations($job->getFile());
+ $testName .= $job->getArguments()
+ ? ' [' . implode(' ', preg_replace(array('#["\'-]*(.+?)["\']?$#A', '#(.{30}).+#A'), array('$1', '$1...'), $job->getArguments())) . ']'
+ : '';
+ $annotations += array(
+ 'exitcode' => Job::CODE_OK,
+ 'httpcode' => self::HTTP_OK,
+ );
+
+ foreach (get_class_methods($this) as $method) {
+ if (!preg_match('#^assess(.+)#', strtolower($method), $m) || !isset($annotations[$m[1]])) {
+ continue;
+ }
+ foreach ((array) $annotations[$m[1]] as $arg) {
+ if ($res = $this->$method($job, $arg)) {
+ $this->runner->writeResult($testName, $res[0], $res[1]);
+ return;
+ }
+ }
+ }
+ $this->runner->writeResult($testName, Runner::PASSED);
+ }
+
+
+ private function initiateSkip($message)
+ {
+ return array(Runner::SKIPPED, $message);
+ }
+
+
+ private function initiatePhpVersion($version, PhpInterpreter $interpreter)
+ {
+ if (preg_match('#^(<=|<|==|=|!=|<>|>=|>)?\s*(.+)#', $version, $matches)
+ && version_compare($matches[2], $interpreter->getVersion(), $matches[1] ?: '>='))
+ {
+ return array(Runner::SKIPPED, "Requires PHP $version.");
+ }
+ }
+
+
+ private function initiatePhpIni($value, PhpInterpreter $interpreter)
+ {
+ $interpreter->arguments .= ' -d ' . Helpers::escapeArg($value);
+ }
+
+
+ private function initiateDataProvider($provider, PhpInterpreter $interpreter, $file)
+ {
+ try {
+ list($dataFile, $query, $optional) = Tester\DataProvider::parseAnnotation($provider, $file);
+ $data = Tester\DataProvider::load($dataFile, $query);
+ } catch (\Exception $e) {
+ return array(empty($optional) ? Runner::FAILED : Runner::SKIPPED, $e->getMessage());
+ }
+
+ $res = array();
+ foreach (array_keys($data) as $item) {
+ $res[] = "$item|$dataFile";
+ }
+ return array('dataprovider', $res);
+ }
+
+
+ private function initiateMultiple($count, PhpInterpreter $interpreter, $file)
+ {
+ return array('multiple', range(0, (int) $count - 1));
+ }
+
+
+ private function initiateTestCase($foo, PhpInterpreter $interpreter, $file)
+ {
+ $job = new Job($file, $interpreter, array(Helpers::escapeArg('--method=' . Tester\TestCase::LIST_METHODS)));
+ $job->run();
+
+ if (in_array($job->getExitCode(), array(Job::CODE_ERROR, Job::CODE_FAIL, Job::CODE_SKIP), TRUE)) {
+ return array($job->getExitCode() === Job::CODE_SKIP ? Runner::SKIPPED : Runner::FAILED, $job->getOutput());
+ }
+
+ if (!preg_match('#\[([^[]*)]#', strrchr($job->getOutput(), '['), $m)) {
+ return array(Runner::FAILED, "Cannot list TestCase methods in file '$file'. Do you call TestCase::run() in it?");
+ } elseif (!strlen($m[1])) {
+ return array(Runner::SKIPPED, "TestCase in file '$file' does not contain test methods.");
+ }
+
+ return array('method', explode(',', $m[1]));
+ }
+
+
+ private function assessExitCode(Job $job, $code)
+ {
+ $code = (int) $code;
+ if ($job->getExitCode() === Job::CODE_SKIP) {
+ $message = preg_match('#.*Skipped:\n(.*?)\z#s', $output = $job->getOutput(), $m)
+ ? $m[1]
+ : $output;
+ return array(Runner::SKIPPED, trim($message));
+
+ } elseif ($job->getExitCode() !== $code) {
+ $message = $job->getExitCode() !== Job::CODE_FAIL ? "Exited with error code {$job->getExitCode()} (expected $code)" : '';
+ return array(Runner::FAILED, trim($message . "\n" . $job->getOutput()));
+ }
+ }
+
+
+ private function assessHttpCode(Job $job, $code)
+ {
+ if (!$this->runner->getInterpreter()->isCgi()) {
+ return;
+ }
+ $headers = $job->getHeaders();
+ $actual = isset($headers['Status']) ? (int) $headers['Status'] : self::HTTP_OK;
+ $code = (int) $code;
+ if ($code && $code !== $actual) {
+ return array(Runner::FAILED, "Exited with HTTP code $actual (expected $code)");
+ }
+ }
+
+
+ private function assessOutputMatchFile(Job $job, $file)
+ {
+ $file = dirname($job->getFile()) . DIRECTORY_SEPARATOR . $file;
+ if (!is_file($file)) {
+ return array(Runner::FAILED, "Missing matching file '$file'.");
+ }
+ return $this->assessOutputMatch($job, file_get_contents($file));
+ }
+
+
+ private function assessOutputMatch(Job $job, $content)
+ {
+ if (!Tester\Assert::isMatching($content, $job->getOutput())) {
+ Dumper::saveOutput($job->getFile(), $job->getOutput(), '.actual');
+ Dumper::saveOutput($job->getFile(), $content, '.expected');
+ return array(Runner::FAILED, 'Failed: output should match ' . Dumper::toLine(rtrim($content)));
+ }
+ }
+
+
+ private function getAnnotations($file)
+ {
+ $annotations = Helpers::parseDocComment(file_get_contents($file));
+ $testName = (isset($annotations[0]) ? preg_replace('#^TEST:\s*#i', '', $annotations[0]) . ' | ' : '')
+ . implode(DIRECTORY_SEPARATOR, array_slice(explode(DIRECTORY_SEPARATOR, $file), -3));
+ return array($annotations, $testName);
+ }
+
+}
diff --git a/vendor/nette/tester/src/Runner/ZendPhpInterpreter.php b/vendor/nette/tester/src/Runner/ZendPhpInterpreter.php
new file mode 100755
index 0000000..dc010b0
--- /dev/null
+++ b/vendor/nette/tester/src/Runner/ZendPhpInterpreter.php
@@ -0,0 +1,108 @@
+path = \Tester\Helpers::escapeArg($path);
+ $proc = proc_open(
+ "$this->path -n $args -v", // -v must be the last
+ array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w')),
+ $pipes,
+ NULL,
+ NULL,
+ array('bypass_shell' => TRUE)
+ );
+ $output = stream_get_contents($pipes[1]);
+ $this->error = trim(stream_get_contents($pipes[2]));
+ if (proc_close($proc)) {
+ throw new \Exception("Unable to run '$path': " . preg_replace('#[\r\n ]+#', ' ', $this->error));
+ } elseif (!preg_match('#^PHP (\S+).*c(g|l)i#i', $output, $matches)) {
+ throw new \Exception("Unable to detect PHP version (output: $output).");
+ }
+
+ $this->version = $matches[1];
+ $this->cgi = strcasecmp($matches[2], 'g') === 0;
+ $this->arguments = $args;
+
+ $job = new Job(__DIR__ . '/info.php', $this, array('xdebug'));
+ $job->run();
+ $this->xdebug = !$job->getExitCode();
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getCommandLine()
+ {
+ return $this->path . $this->arguments;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getVersion()
+ {
+ return $this->version;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function hasXdebug()
+ {
+ return $this->xdebug;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isCgi()
+ {
+ return $this->cgi;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getErrorOutput()
+ {
+ return $this->error;
+ }
+
+}
diff --git a/vendor/nette/tester/src/Runner/info.php b/vendor/nette/tester/src/Runner/info.php
new file mode 100755
index 0000000..7344902
--- /dev/null
+++ b/vendor/nette/tester/src/Runner/info.php
@@ -0,0 +1,35 @@
+ defined('PHP_BINARY') ? PHP_BINARY : '(not available)',
+
+ 'PHP version' . ($isHhvm ? '; HHVM version' : '') => PHP_VERSION . ' (' . PHP_SAPI . ')' . ($isHhvm ? '; ' . HHVM_VERSION : ''),
+
+ 'Loaded php.ini files' => count($iniFiles) ? implode(', ', $iniFiles) : ($isHhvm ? '(unable to detect under HHVM)' : '(none)'),
+
+ 'Loaded extensions' => count($extensions) ? implode(', ', $extensions) : '(none)',
+);
+
+foreach ($values as $title => $value) {
+ echo "\033[1;32m$title\033[0m:\n$value\n\n";
+}
+
+echo "\n\n";
diff --git a/vendor/nette/tester/src/bootstrap.php b/vendor/nette/tester/src/bootstrap.php
new file mode 100755
index 0000000..51366b9
--- /dev/null
+++ b/vendor/nette/tester/src/bootstrap.php
@@ -0,0 +1,19 @@
+run());
diff --git a/vendor/nette/utils/composer.json b/vendor/nette/utils/composer.json
new file mode 100755
index 0000000..3c00f35
--- /dev/null
+++ b/vendor/nette/utils/composer.json
@@ -0,0 +1,35 @@
+{
+ "name": "nette/utils",
+ "description": "Nette Utility Classes",
+ "homepage": "http://nette.org",
+ "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "http://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "http://nette.org/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.1"
+ },
+ "require-dev": {
+ "nette/tester": "~1.0"
+ },
+ "suggest": {
+ "ext-iconv": "to use Strings::webalize() and toAscii()",
+ "ext-intl": "for script transliteration in Strings::webalize() and toAscii()",
+ "ext-mbstring": "to use Strings::lower() etc...",
+ "ext-gd": "to use Image"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "autoload": {
+ "classmap": ["src/"]
+ },
+ "minimum-stability": "dev"
+}
diff --git a/vendor/nette/utils/license.md b/vendor/nette/utils/license.md
new file mode 100755
index 0000000..af571d5
--- /dev/null
+++ b/vendor/nette/utils/license.md
@@ -0,0 +1,60 @@
+Licenses
+========
+
+Good news! You may use Nette Framework under the terms of either
+the New BSD License or the GNU General Public License (GPL) version 2 or 3.
+
+The BSD License is recommended for most projects. It is easy to understand and it
+places almost no restrictions on what you can do with the framework. If the GPL
+fits better to your project, you can use the framework under this license.
+
+You don't have to notify anyone which license you are using. You can freely
+use Nette Framework in commercial projects as long as the copyright header
+remains intact.
+
+Please be advised that the name "Nette Framework" is a protected trademark and its
+usage has some limitations. So please do not use word "Nette" in the name of your
+project or top-level domain, and choose a name that stands on its own merits.
+If your stuff is good, it will not take long to establish a reputation for yourselves.
+
+
+New BSD License
+---------------
+
+Copyright (c) 2004, 2014 David Grudl (http://davidgrudl.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of "Nette Framework" nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright owner or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused and on
+any theory of liability, whether in contract, strict liability, or tort
+(including negligence or otherwise) arising in any way out of the use of this
+software, even if advised of the possibility of such damage.
+
+
+GNU General Public License
+--------------------------
+
+GPL licenses are very very long, so instead of including them here we offer
+you URLs with full text:
+
+- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
+- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/vendor/nette/utils/src/Iterators/CachingIterator.php b/vendor/nette/utils/src/Iterators/CachingIterator.php
new file mode 100755
index 0000000..8cd65b8
--- /dev/null
+++ b/vendor/nette/utils/src/Iterators/CachingIterator.php
@@ -0,0 +1,243 @@
+getIterator();
+ } while ($iterator instanceof \IteratorAggregate);
+
+ } elseif ($iterator instanceof \Traversable) {
+ if (!$iterator instanceof \Iterator) {
+ $iterator = new \IteratorIterator($iterator);
+ }
+ } else {
+ throw new Nette\InvalidArgumentException(sprintf('Invalid argument passed to %s; array or Traversable expected, %s given.', __CLASS__, is_object($iterator) ? get_class($iterator) : gettype($iterator)));
+ }
+
+ parent::__construct($iterator, 0);
+ }
+
+
+ /**
+ * Is the current element the first one?
+ * @param int grid width
+ * @return bool
+ */
+ public function isFirst($width = NULL)
+ {
+ return $this->counter === 1 || ($width && $this->counter !== 0 && (($this->counter - 1) % $width) === 0);
+ }
+
+
+ /**
+ * Is the current element the last one?
+ * @param int grid width
+ * @return bool
+ */
+ public function isLast($width = NULL)
+ {
+ return !$this->hasNext() || ($width && ($this->counter % $width) === 0);
+ }
+
+
+ /**
+ * Is the iterator empty?
+ * @return bool
+ */
+ public function isEmpty()
+ {
+ return $this->counter === 0;
+ }
+
+
+ /**
+ * Is the counter odd?
+ * @return bool
+ */
+ public function isOdd()
+ {
+ return $this->counter % 2 === 1;
+ }
+
+
+ /**
+ * Is the counter even?
+ * @return bool
+ */
+ public function isEven()
+ {
+ return $this->counter % 2 === 0;
+ }
+
+
+ /**
+ * Returns the counter.
+ * @return int
+ */
+ public function getCounter()
+ {
+ return $this->counter;
+ }
+
+
+ /**
+ * Returns the count of elements.
+ * @return int
+ */
+ public function count()
+ {
+ $inner = $this->getInnerIterator();
+ if ($inner instanceof \Countable) {
+ return $inner->count();
+
+ } else {
+ throw new Nette\NotSupportedException('Iterator is not countable.');
+ }
+ }
+
+
+ /**
+ * Forwards to the next element.
+ * @return void
+ */
+ public function next()
+ {
+ parent::next();
+ if (parent::valid()) {
+ $this->counter++;
+ }
+ }
+
+
+ /**
+ * Rewinds the Iterator.
+ * @return void
+ */
+ public function rewind()
+ {
+ parent::rewind();
+ $this->counter = parent::valid() ? 1 : 0;
+ }
+
+
+ /**
+ * Returns the next key.
+ * @return mixed
+ */
+ public function getNextKey()
+ {
+ return $this->getInnerIterator()->key();
+ }
+
+
+ /**
+ * Returns the next element.
+ * @return mixed
+ */
+ public function getNextValue()
+ {
+ return $this->getInnerIterator()->current();
+ }
+
+
+ /********************* Nette\Object behaviour ****************d*g**/
+
+
+ /**
+ * Call to undefined method.
+ * @param string method name
+ * @param array arguments
+ * @return mixed
+ * @throws Nette\MemberAccessException
+ */
+ public function __call($name, $args)
+ {
+ return ObjectMixin::call($this, $name, $args);
+ }
+
+
+ /**
+ * Returns property value. Do not call directly.
+ * @param string property name
+ * @return mixed property value
+ * @throws Nette\MemberAccessException if the property is not defined.
+ */
+ public function &__get($name)
+ {
+ return ObjectMixin::get($this, $name);
+ }
+
+
+ /**
+ * Sets value of a property. Do not call directly.
+ * @param string property name
+ * @param mixed property value
+ * @return void
+ * @throws Nette\MemberAccessException if the property is not defined or is read-only
+ */
+ public function __set($name, $value)
+ {
+ ObjectMixin::set($this, $name, $value);
+ }
+
+
+ /**
+ * Is property defined?
+ * @param string property name
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ return ObjectMixin::has($this, $name);
+ }
+
+
+ /**
+ * Access to undeclared property.
+ * @param string property name
+ * @return void
+ * @throws Nette\MemberAccessException
+ */
+ public function __unset($name)
+ {
+ ObjectMixin::remove($this, $name);
+ }
+
+
+}
diff --git a/vendor/nette/utils/src/Iterators/Filter.php b/vendor/nette/utils/src/Iterators/Filter.php
new file mode 100755
index 0000000..ae19faf
--- /dev/null
+++ b/vendor/nette/utils/src/Iterators/Filter.php
@@ -0,0 +1,34 @@
+callback = Nette\Utils\Callback::check($callback);
+ }
+
+
+ public function accept()
+ {
+ return call_user_func($this->callback, $this->current(), $this->key(), $this);
+ }
+
+}
diff --git a/vendor/nette/utils/src/Iterators/Mapper.php b/vendor/nette/utils/src/Iterators/Mapper.php
new file mode 100755
index 0000000..14fd0c9
--- /dev/null
+++ b/vendor/nette/utils/src/Iterators/Mapper.php
@@ -0,0 +1,34 @@
+callback = Nette\Utils\Callback::check($callback);
+ }
+
+
+ public function current()
+ {
+ return call_user_func($this->callback, parent::current(), parent::key());
+ }
+
+}
diff --git a/vendor/nette/utils/src/Iterators/RecursiveFilter.php b/vendor/nette/utils/src/Iterators/RecursiveFilter.php
new file mode 100755
index 0000000..e108c9a
--- /dev/null
+++ b/vendor/nette/utils/src/Iterators/RecursiveFilter.php
@@ -0,0 +1,34 @@
+getInnerIterator()->hasChildren();
+ }
+
+
+ public function getChildren()
+ {
+ return new static($this->getInnerIterator()->getChildren(), $this->callback);
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/ArrayHash.php b/vendor/nette/utils/src/Utils/ArrayHash.php
new file mode 100755
index 0000000..9bcfe8d
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/ArrayHash.php
@@ -0,0 +1,100 @@
+ $value) {
+ if ($recursive && is_array($value)) {
+ $obj->$key = static::from($value, TRUE);
+ } else {
+ $obj->$key = $value;
+ }
+ }
+ return $obj;
+ }
+
+
+ /**
+ * Returns an iterator over all items.
+ * @return \RecursiveArrayIterator
+ */
+ public function getIterator()
+ {
+ return new \RecursiveArrayIterator($this);
+ }
+
+
+ /**
+ * Returns items count.
+ * @return int
+ */
+ public function count()
+ {
+ return count((array) $this);
+ }
+
+
+ /**
+ * Replaces or appends a item.
+ * @return void
+ */
+ public function offsetSet($key, $value)
+ {
+ if (!is_scalar($key)) { // prevents NULL
+ throw new Nette\InvalidArgumentException(sprintf('Key must be either a string or an integer, %s given.', gettype($key)));
+ }
+ $this->$key = $value;
+ }
+
+
+ /**
+ * Returns a item.
+ * @return mixed
+ */
+ public function offsetGet($key)
+ {
+ return $this->$key;
+ }
+
+
+ /**
+ * Determines whether a item exists.
+ * @return bool
+ */
+ public function offsetExists($key)
+ {
+ return isset($this->$key);
+ }
+
+
+ /**
+ * Removes the element from this list.
+ * @return void
+ */
+ public function offsetUnset($key)
+ {
+ unset($this->$key);
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/ArrayList.php b/vendor/nette/utils/src/Utils/ArrayList.php
new file mode 100755
index 0000000..f4989e2
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/ArrayList.php
@@ -0,0 +1,104 @@
+list);
+ }
+
+
+ /**
+ * Returns items count.
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->list);
+ }
+
+
+ /**
+ * Replaces or appends a item.
+ * @param int|NULL
+ * @param mixed
+ * @return void
+ * @throws Nette\OutOfRangeException
+ */
+ public function offsetSet($index, $value)
+ {
+ if ($index === NULL) {
+ $this->list[] = $value;
+
+ } elseif ($index < 0 || $index >= count($this->list)) {
+ throw new Nette\OutOfRangeException('Offset invalid or out of range');
+
+ } else {
+ $this->list[(int) $index] = $value;
+ }
+ }
+
+
+ /**
+ * Returns a item.
+ * @param int
+ * @return mixed
+ * @throws Nette\OutOfRangeException
+ */
+ public function offsetGet($index)
+ {
+ if ($index < 0 || $index >= count($this->list)) {
+ throw new Nette\OutOfRangeException('Offset invalid or out of range');
+ }
+ return $this->list[(int) $index];
+ }
+
+
+ /**
+ * Determines whether a item exists.
+ * @param int
+ * @return bool
+ */
+ public function offsetExists($index)
+ {
+ return $index >= 0 && $index < count($this->list);
+ }
+
+
+ /**
+ * Removes the element at the specified position in this list.
+ * @param int
+ * @return void
+ * @throws Nette\OutOfRangeException
+ */
+ public function offsetUnset($index)
+ {
+ if ($index < 0 || $index >= count($this->list)) {
+ throw new Nette\OutOfRangeException('Offset invalid or out of range');
+ }
+ array_splice($this->list, (int) $index, 1);
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/Arrays.php b/vendor/nette/utils/src/Utils/Arrays.php
new file mode 100755
index 0000000..6e847bf
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Arrays.php
@@ -0,0 +1,261 @@
+ $v) {
+ if (is_array($v) && is_array($arr2[$k])) {
+ $res[$k] = self::mergeTree($v, $arr2[$k]);
+ }
+ }
+ return $res;
+ }
+
+
+ /**
+ * Searches the array for a given key and returns the offset if successful.
+ * @return int|FALSE offset if it is found, FALSE otherwise
+ */
+ public static function searchKey($arr, $key)
+ {
+ $foo = array($key => NULL);
+ return array_search(key($foo), array_keys($arr), TRUE);
+ }
+
+
+ /**
+ * Inserts new array before item specified by key.
+ * @return void
+ */
+ public static function insertBefore(array & $arr, $key, array $inserted)
+ {
+ $offset = self::searchKey($arr, $key);
+ $arr = array_slice($arr, 0, $offset, TRUE) + $inserted + array_slice($arr, $offset, count($arr), TRUE);
+ }
+
+
+ /**
+ * Inserts new array after item specified by key.
+ * @return void
+ */
+ public static function insertAfter(array & $arr, $key, array $inserted)
+ {
+ $offset = self::searchKey($arr, $key);
+ $offset = $offset === FALSE ? count($arr) : $offset + 1;
+ $arr = array_slice($arr, 0, $offset, TRUE) + $inserted + array_slice($arr, $offset, count($arr), TRUE);
+ }
+
+
+ /**
+ * Renames key in array.
+ * @return void
+ */
+ public static function renameKey(array & $arr, $oldKey, $newKey)
+ {
+ $offset = self::searchKey($arr, $oldKey);
+ if ($offset !== FALSE) {
+ $keys = array_keys($arr);
+ $keys[$offset] = $newKey;
+ $arr = array_combine($keys, $arr);
+ }
+ }
+
+
+ /**
+ * Returns array entries that match the pattern.
+ * @return array
+ */
+ public static function grep(array $arr, $pattern, $flags = 0)
+ {
+ return Strings::pcre('preg_grep', array($pattern, $arr, $flags));
+ }
+
+
+ /**
+ * Returns flattened array.
+ * @return array
+ */
+ public static function flatten(array $arr, $preserveKeys = FALSE)
+ {
+ $res = array();
+ $cb = $preserveKeys
+ ? function ($v, $k) use (& $res) { $res[$k] = $v; }
+ : function ($v) use (& $res) { $res[] = $v; };
+ array_walk_recursive($arr, $cb);
+ return $res;
+ }
+
+
+ /**
+ * Finds whether a variable is a zero-based integer indexed array.
+ * @return bool
+ */
+ public static function isList($value)
+ {
+ return is_array($value) && (!$value || array_keys($value) === range(0, count($value) - 1));
+ }
+
+
+ /**
+ * Reformats table to associative tree. Path looks like 'field|field[]field->field=field'.
+ * @return array|\stdClass
+ */
+ public static function associate(array $arr, $path)
+ {
+ $parts = is_array($path)
+ ? $path
+ : preg_split('#(\[\]|->|=|\|)#', $path, NULL, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+
+ if (!$parts || $parts[0] === '=' || $parts[0] === '|' || $parts === array('->')) {
+ throw new Nette\InvalidArgumentException("Invalid path '$path'.");
+ }
+
+ $res = $parts[0] === '->' ? new \stdClass : array();
+
+ foreach ($arr as $rowOrig) {
+ $row = (array) $rowOrig;
+ $x = & $res;
+
+ for ($i = 0; $i < count($parts); $i++) {
+ $part = $parts[$i];
+ if ($part === '[]') {
+ $x = & $x[];
+
+ } elseif ($part === '=') {
+ if (isset($parts[++$i])) {
+ $x = $row[$parts[$i]];
+ $row = NULL;
+ }
+
+ } elseif ($part === '->') {
+ if (isset($parts[++$i])) {
+ $x = & $x->{$row[$parts[$i]]};
+ } else {
+ $row = is_object($rowOrig) ? $rowOrig : (object) $row;
+ }
+
+ } elseif ($part !== '|') {
+ $x = & $x[(string) $row[$part]];
+ }
+ }
+
+ if ($x === NULL) {
+ $x = $row;
+ }
+ }
+
+ return $res;
+ }
+
+
+ /**
+ * Normalizes to associative array.
+ * @return array
+ */
+ public static function normalize(array $arr, $filling = NULL)
+ {
+ $res = array();
+ foreach ($arr as $k => $v) {
+ $res[is_int($k) ? $v : $k] = is_int($k) ? $filling : $v;
+ }
+ return $res;
+ }
+
+
+ /**
+ * Picks element from the array by key and return its value.
+ * @param array
+ * @param string|int array key
+ * @param mixed
+ * @return mixed
+ * @throws Nette\InvalidArgumentException if item does not exist and default value is not provided
+ */
+ public static function pick(array & $arr, $key, $default = NULL)
+ {
+ if (array_key_exists($key, $arr)) {
+ $value = $arr[$key];
+ unset($arr[$key]);
+ return $value;
+
+ } elseif (func_num_args() < 3) {
+ throw new Nette\InvalidArgumentException("Missing item '$key'.");
+
+ } else {
+ return $default;
+ }
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/Callback.php b/vendor/nette/utils/src/Utils/Callback.php
new file mode 100755
index 0000000..79e0798
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Callback.php
@@ -0,0 +1,200 @@
+= 50400) {
+ if (is_string($callable) && function_exists($callable)) {
+ $r = new \ReflectionFunction($callable);
+ return $r->getClosure();
+
+ } elseif (is_array($callable) && method_exists($callable[0], $callable[1])) {
+ $r = new \ReflectionMethod($callable[0], $callable[1]);
+ return $r->getClosure($callable[0]);
+ }
+ }
+
+ self::check($callable);
+ $_callable_ = $callable;
+ return function () use ($_callable_) {
+ return call_user_func_array($_callable_, func_get_args());
+ };
+ }
+
+
+ /**
+ * Invokes callback.
+ * @return mixed
+ */
+ public static function invoke($callable)
+ {
+ self::check($callable);
+ return call_user_func_array($callable, array_slice(func_get_args(), 1));
+ }
+
+
+ /**
+ * Invokes callback with an array of parameters.
+ * @return mixed
+ */
+ public static function invokeArgs($callable, array $args = array())
+ {
+ self::check($callable);
+ return call_user_func_array($callable, $args);
+ }
+
+
+ /**
+ * Invokes internal PHP function with own error handler.
+ * @param string
+ * @return mixed
+ */
+ public static function invokeSafe($function, array $args, $onError)
+ {
+ $prev = set_error_handler(function ($severity, $message, $file, $line, $context = NULL, $stack = NULL) use ($onError, & $prev, $function) {
+ if ($file === '' && defined('HHVM_VERSION')) { // https://github.com/facebook/hhvm/issues/4625
+ $file = $stack[1]['file'];
+ }
+ if ($file === __FILE__ && $onError(str_replace("$function(): ", '', $message), $severity) !== FALSE) {
+ return;
+ } elseif ($prev) {
+ return call_user_func_array($prev, func_get_args());
+ }
+ return FALSE;
+ });
+
+ try {
+ $res = call_user_func_array($function, $args);
+ restore_error_handler();
+ return $res;
+
+ } catch (\Exception $e) {
+ restore_error_handler();
+ throw $e;
+ }
+ }
+
+
+ /**
+ * @return callable
+ */
+ public static function check($callable, $syntax = FALSE)
+ {
+ if (!is_callable($callable, $syntax)) {
+ throw new Nette\InvalidArgumentException($syntax
+ ? 'Given value is not a callable type.'
+ : sprintf("Callback '%s' is not callable.", self::toString($callable))
+ );
+ }
+ return $callable;
+ }
+
+
+ /**
+ * @return string
+ */
+ public static function toString($callable)
+ {
+ if ($callable instanceof \Closure) {
+ $inner = self::unwrap($callable);
+ return '{closure' . ($inner instanceof \Closure ? '}' : ' ' . self::toString($inner) . '}');
+ } elseif (is_string($callable) && $callable[0] === "\0") {
+ return '{lambda}';
+ } else {
+ is_callable($callable, TRUE, $textual);
+ return $textual;
+ }
+ }
+
+
+ /**
+ * @return \ReflectionMethod|\ReflectionFunction
+ */
+ public static function toReflection($callable)
+ {
+ if ($callable instanceof \Closure) {
+ $callable = self::unwrap($callable);
+ } elseif ($callable instanceof Nette\Callback) {
+ $callable = $callable->getNative();
+ }
+
+ $class = class_exists('Nette\Reflection\Method') ? 'Nette\Reflection\Method' : 'ReflectionMethod';
+ if (is_string($callable) && strpos($callable, '::')) {
+ return new $class($callable);
+ } elseif (is_array($callable)) {
+ return new $class($callable[0], $callable[1]);
+ } elseif (is_object($callable) && !$callable instanceof \Closure) {
+ return new $class($callable, '__invoke');
+ } else {
+ $class = class_exists('Nette\Reflection\GlobalFunction') ? 'Nette\Reflection\GlobalFunction' : 'ReflectionFunction';
+ return new $class($callable);
+ }
+ }
+
+
+ /**
+ * @return bool
+ */
+ public static function isStatic($callable)
+ {
+ return is_array($callable) ? is_string($callable[0]) : is_string($callable);
+ }
+
+
+ /**
+ * Unwraps closure created by self::closure()
+ * @internal
+ * @return callable
+ */
+ public static function unwrap(\Closure $closure)
+ {
+ $r = new \ReflectionFunction($closure);
+ if (substr($r->getName(), -1) === '}') {
+ $vars = $r->getStaticVariables();
+ return isset($vars['_callable_']) ? $vars['_callable_'] : $closure;
+
+ } elseif ($obj = $r->getClosureThis()) {
+ return array($obj, $r->getName());
+
+ } elseif ($class = $r->getClosureScopeClass()) {
+ return array($class->getName(), $r->getName());
+
+ } else {
+ return $r->getName();
+ }
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/DateTime.php b/vendor/nette/utils/src/Utils/DateTime.php
new file mode 100755
index 0000000..9cb7dab
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/DateTime.php
@@ -0,0 +1,125 @@
+format('Y-m-d H:i:s'), $time->getTimezone());
+
+ } elseif (is_numeric($time)) {
+ if ($time <= self::YEAR) {
+ $time += time();
+ }
+ $tmp = new static('@' . $time);
+ return $tmp->setTimeZone(new \DateTimeZone(date_default_timezone_get()));
+
+ } else { // textual or NULL
+ return new static($time);
+ }
+ }
+
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->format('Y-m-d H:i:s');
+ }
+
+
+ /**
+ * @param string
+ * @return self
+ */
+ public function modifyClone($modify = '')
+ {
+ $dolly = clone $this;
+ return $modify ? $dolly->modify($modify) : $dolly;
+ }
+
+
+ /**
+ * @param int
+ * @return self
+ */
+ public function setTimestamp($timestamp)
+ {
+ $zone = $this->getTimezone();
+ $this->__construct('@' . $timestamp);
+ return $this->setTimeZone($zone);
+ }
+
+
+ /**
+ * @return int|string
+ */
+ public function getTimestamp()
+ {
+ $ts = $this->format('U');
+ return is_float($tmp = $ts * 1) ? $ts : $tmp;
+ }
+
+
+ /**
+ * Returns new DateTime object formatted according to the specified format.
+ * @param string The format the $time parameter should be in
+ * @param string String representing the time
+ * @param string|\DateTimeZone desired timezone (default timezone is used if NULL is passed)
+ * @return self|FALSE
+ */
+ public static function createFromFormat($format, $time, $timezone = NULL)
+ {
+ if ($timezone === NULL) {
+ $timezone = new \DateTimeZone(date_default_timezone_get());
+
+ } elseif (is_string($timezone)) {
+ $timezone = new \DateTimeZone($timezone);
+
+ } elseif (!$timezone instanceof \DateTimeZone) {
+ throw new Nette\InvalidArgumentException('Invalid timezone given');
+ }
+
+ $date = parent::createFromFormat($format, $time, $timezone);
+ return $date ? static::from($date) : FALSE;
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/FileSystem.php b/vendor/nette/utils/src/Utils/FileSystem.php
new file mode 100755
index 0000000..672d637
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/FileSystem.php
@@ -0,0 +1,141 @@
+isDir()) {
+ static::createDir($dest . '/' . $iterator->getSubPathName());
+ } else {
+ static::copy($item, $dest . '/' . $iterator->getSubPathName());
+ }
+ }
+
+ } else {
+ static::createDir(dirname($dest));
+ if (@stream_copy_to_stream(fopen($source, 'r'), fopen($dest, 'w')) === FALSE) { // @ is escalated to exception
+ throw new Nette\IOException("Unable to copy file '$source' to '$dest'.");
+ }
+ }
+ }
+
+
+ /**
+ * Deletes a file or directory.
+ * @return void
+ * @throws Nette\IOException
+ */
+ public static function delete($path)
+ {
+ if (is_file($path) || is_link($path)) {
+ $func = DIRECTORY_SEPARATOR === '\\' && is_dir($path) ? 'rmdir' : 'unlink';
+ if (!@$func($path)) { // @ is escalated to exception
+ throw new Nette\IOException("Unable to delete '$path'.");
+ }
+
+ } elseif (is_dir($path)) {
+ foreach (new \FilesystemIterator($path) as $item) {
+ static::delete($item);
+ }
+ if (!@rmdir($path)) { // @ is escalated to exception
+ throw new Nette\IOException("Unable to delete directory '$path'.");
+ }
+ }
+ }
+
+
+ /**
+ * Renames a file or directory.
+ * @return void
+ * @throws Nette\IOException
+ * @throws Nette\InvalidStateException if the target file or directory already exist
+ */
+ public static function rename($name, $newName, $overwrite = TRUE)
+ {
+ if (!$overwrite && file_exists($newName)) {
+ throw new Nette\InvalidStateException("File or directory '$newName' already exists.");
+
+ } elseif (!file_exists($name)) {
+ throw new Nette\IOException("File or directory '$name' not found.");
+
+ } else {
+ static::createDir(dirname($newName));
+ static::delete($newName);
+ if (!@rename($name, $newName)) { // @ is escalated to exception
+ throw new Nette\IOException("Unable to rename file or directory '$name' to '$newName'.");
+ }
+ }
+ }
+
+
+ /**
+ * Writes a string to a file.
+ * @return void
+ * @throws Nette\IOException
+ */
+ public static function write($file, $content, $mode = 0666)
+ {
+ static::createDir(dirname($file));
+ if (@file_put_contents($file, $content) === FALSE) { // @ is escalated to exception
+ throw new Nette\IOException("Unable to write file '$file'.");
+ }
+ if ($mode !== NULL && !@chmod($file, $mode)) { // @ is escalated to exception
+ throw new Nette\IOException("Unable to chmod file '$file'.");
+ }
+ }
+
+
+ /**
+ * Is path absolute?
+ * @return bool
+ */
+ public static function isAbsolute($path)
+ {
+ return (bool) preg_match('#([a-z]:)?[/\\\\]|[a-z][a-z0-9+.-]*://#Ai', $path);
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/Html.php b/vendor/nette/utils/src/Utils/Html.php
new file mode 100755
index 0000000..3e0e94c
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Html.php
@@ -0,0 +1,594 @@
+
+ * $el = Html::el('a')->href($link)->setText('Nette');
+ * $el->class = 'myclass';
+ * echo $el;
+ *
+ * echo $el->startTag(), $el->endTag();
+ *
+ */
+class Html extends Nette\Object implements \ArrayAccess, \Countable, \IteratorAggregate, IHtmlString
+{
+ /** @var string element's name */
+ private $name;
+
+ /** @var bool is element empty? */
+ private $isEmpty;
+
+ /** @var array element's attributes */
+ public $attrs = array();
+
+ /** @var array of Html | string nodes */
+ protected $children = array();
+
+ /** @var bool use XHTML syntax? */
+ public static $xhtml = FALSE;
+
+ /** @var array empty (void) elements */
+ public static $emptyElements = array(
+ 'img' => 1, 'hr' => 1, 'br' => 1, 'input' => 1, 'meta' => 1, 'area' => 1, 'embed' => 1, 'keygen' => 1,
+ 'source' => 1, 'base' => 1, 'col' => 1, 'link' => 1, 'param' => 1, 'basefont' => 1, 'frame' => 1,
+ 'isindex' => 1, 'wbr' => 1, 'command' => 1, 'track' => 1,
+ );
+
+
+ /**
+ * Static factory.
+ * @param string element name (or NULL)
+ * @param array|string element's attributes or plain text content
+ * @return self
+ */
+ public static function el($name = NULL, $attrs = NULL)
+ {
+ $el = new static;
+ $parts = explode(' ', $name, 2);
+ $el->setName($parts[0]);
+
+ if (is_array($attrs)) {
+ $el->attrs = $attrs;
+
+ } elseif ($attrs !== NULL) {
+ $el->setText($attrs);
+ }
+
+ if (isset($parts[1])) {
+ foreach (Strings::matchAll($parts[1] . ' ', '#([a-z0-9:-]+)(?:=(["\'])?(.*?)(?(2)\\2|\s))?#i') as $m) {
+ $el->attrs[$m[1]] = isset($m[3]) ? $m[3] : TRUE;
+ }
+ }
+
+ return $el;
+ }
+
+
+ /**
+ * Changes element's name.
+ * @param string
+ * @param bool Is element empty?
+ * @return self
+ * @throws Nette\InvalidArgumentException
+ */
+ public function setName($name, $isEmpty = NULL)
+ {
+ if ($name !== NULL && !is_string($name)) {
+ throw new Nette\InvalidArgumentException(sprintf('Name must be string or NULL, %s given.', gettype($name)));
+ }
+
+ $this->name = $name;
+ $this->isEmpty = $isEmpty === NULL ? isset(static::$emptyElements[$name]) : (bool) $isEmpty;
+ return $this;
+ }
+
+
+ /**
+ * Returns element's name.
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+
+ /**
+ * Is element empty?
+ * @return bool
+ */
+ public function isEmpty()
+ {
+ return $this->isEmpty;
+ }
+
+
+ /**
+ * Sets multiple attributes.
+ * @param array
+ * @return self
+ */
+ public function addAttributes(array $attrs)
+ {
+ $this->attrs = array_merge($this->attrs, $attrs);
+ return $this;
+ }
+
+
+ /**
+ * Overloaded setter for element's attribute.
+ * @param string HTML attribute name
+ * @param mixed HTML attribute value
+ * @return void
+ */
+ public function __set($name, $value)
+ {
+ $this->attrs[$name] = $value;
+ }
+
+
+ /**
+ * Overloaded getter for element's attribute.
+ * @param string HTML attribute name
+ * @return mixed HTML attribute value
+ */
+ public function &__get($name)
+ {
+ return $this->attrs[$name];
+ }
+
+
+ /**
+ * Overloaded tester for element's attribute.
+ * @param string HTML attribute name
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ return isset($this->attrs[$name]);
+ }
+
+
+ /**
+ * Overloaded unsetter for element's attribute.
+ * @param string HTML attribute name
+ * @return void
+ */
+ public function __unset($name)
+ {
+ unset($this->attrs[$name]);
+ }
+
+
+ /**
+ * Overloaded setter for element's attribute.
+ * @param string HTML attribute name
+ * @param array (string) HTML attribute value or pair?
+ * @return self
+ */
+ public function __call($m, $args)
+ {
+ $p = substr($m, 0, 3);
+ if ($p === 'get' || $p === 'set' || $p === 'add') {
+ $m = substr($m, 3);
+ $m[0] = $m[0] | "\x20";
+ if ($p === 'get') {
+ return isset($this->attrs[$m]) ? $this->attrs[$m] : NULL;
+
+ } elseif ($p === 'add') {
+ $args[] = TRUE;
+ }
+ }
+
+ if (count($args) === 0) { // invalid
+
+ } elseif (count($args) === 1) { // set
+ $this->attrs[$m] = $args[0];
+
+ } elseif ((string) $args[0] === '') {
+ $tmp = & $this->attrs[$m]; // appending empty value? -> ignore, but ensure it exists
+
+ } elseif (!isset($this->attrs[$m]) || is_array($this->attrs[$m])) { // needs array
+ $this->attrs[$m][$args[0]] = $args[1];
+
+ } else {
+ $this->attrs[$m] = array($this->attrs[$m], $args[0] => $args[1]);
+ }
+
+ return $this;
+ }
+
+
+ /**
+ * Special setter for element's attribute.
+ * @param string path
+ * @param array query
+ * @return self
+ */
+ public function href($path, $query = NULL)
+ {
+ if ($query) {
+ $query = http_build_query($query, NULL, '&');
+ if ($query !== '') {
+ $path .= '?' . $query;
+ }
+ }
+ $this->attrs['href'] = $path;
+ return $this;
+ }
+
+
+ /**
+ * Setter for data-* attributes. Booleans are converted to 'true' resp. 'false'.
+ * @return self
+ */
+ public function data($name, $value = NULL)
+ {
+ if (func_num_args() === 1) {
+ $this->attrs['data'] = $name;
+ } else {
+ $this->attrs["data-$name"] = is_bool($value) ? json_encode($value) : $value;
+ }
+ return $this;
+ }
+
+
+ /**
+ * Sets element's HTML content.
+ * @param string raw HTML string
+ * @return self
+ * @throws Nette\InvalidArgumentException
+ */
+ public function setHtml($html)
+ {
+ if (is_array($html)) {
+ throw new Nette\InvalidArgumentException(sprintf('Textual content must be a scalar, %s given.', gettype($html)));
+ }
+ $this->removeChildren();
+ $this->children[] = (string) $html;
+ return $this;
+ }
+
+
+ /**
+ * Returns element's HTML content.
+ * @return string
+ */
+ public function getHtml()
+ {
+ $s = '';
+ foreach ($this->children as $child) {
+ if (is_object($child)) {
+ $s .= $child->render();
+ } else {
+ $s .= $child;
+ }
+ }
+ return $s;
+ }
+
+
+ /**
+ * Sets element's textual content.
+ * @param string
+ * @return self
+ * @throws Nette\InvalidArgumentException
+ */
+ public function setText($text)
+ {
+ if (!is_array($text) && !$text instanceof self) {
+ $text = htmlspecialchars((string) $text, ENT_NOQUOTES, 'UTF-8');
+ }
+ return $this->setHtml($text);
+ }
+
+
+ /**
+ * Returns element's textual content.
+ * @return string
+ */
+ public function getText()
+ {
+ return html_entity_decode(strip_tags($this->getHtml()), ENT_QUOTES, 'UTF-8');
+ }
+
+
+ /**
+ * Adds new element's child.
+ * @param Html|string Html node or raw HTML string
+ * @return self
+ */
+ public function add($child)
+ {
+ return $this->insert(NULL, $child);
+ }
+
+
+ /**
+ * Creates and adds a new Html child.
+ * @param string elements's name
+ * @param array|string element's attributes or raw HTML string
+ * @return self created element
+ */
+ public function create($name, $attrs = NULL)
+ {
+ $this->insert(NULL, $child = static::el($name, $attrs));
+ return $child;
+ }
+
+
+ /**
+ * Inserts child node.
+ * @param int|NULL position of NULL for appending
+ * @param Html|string Html node or raw HTML string
+ * @param bool
+ * @return self
+ * @throws Nette\InvalidArgumentException
+ */
+ public function insert($index, $child, $replace = FALSE)
+ {
+ if ($child instanceof self || is_scalar($child)) {
+ if ($index === NULL) { // append
+ $this->children[] = $child;
+
+ } else { // insert or replace
+ array_splice($this->children, (int) $index, $replace ? 1 : 0, array($child));
+ }
+
+ } else {
+ throw new Nette\InvalidArgumentException(sprintf('Child node must be scalar or Html object, %s given.', is_object($child) ? get_class($child) : gettype($child)));
+ }
+
+ return $this;
+ }
+
+
+ /**
+ * Inserts (replaces) child node (\ArrayAccess implementation).
+ * @param int|NULL position of NULL for appending
+ * @param Html|string Html node or raw HTML string
+ * @return void
+ */
+ public function offsetSet($index, $child)
+ {
+ $this->insert($index, $child, TRUE);
+ }
+
+
+ /**
+ * Returns child node (\ArrayAccess implementation).
+ * @param int
+ * @return self|string
+ */
+ public function offsetGet($index)
+ {
+ return $this->children[$index];
+ }
+
+
+ /**
+ * Exists child node? (\ArrayAccess implementation).
+ * @param int
+ * @return bool
+ */
+ public function offsetExists($index)
+ {
+ return isset($this->children[$index]);
+ }
+
+
+ /**
+ * Removes child node (\ArrayAccess implementation).
+ * @param int
+ * @return void
+ */
+ public function offsetUnset($index)
+ {
+ if (isset($this->children[$index])) {
+ array_splice($this->children, (int) $index, 1);
+ }
+ }
+
+
+ /**
+ * Returns children count.
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->children);
+ }
+
+
+ /**
+ * Removed all children.
+ * @return void
+ */
+ public function removeChildren()
+ {
+ $this->children = array();
+ }
+
+
+ /**
+ * Iterates over a elements.
+ * @return \ArrayIterator
+ */
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->children);
+ }
+
+
+ /**
+ * Returns all of children.
+ * @return array
+ */
+ public function getChildren()
+ {
+ return $this->children;
+ }
+
+
+ /**
+ * Renders element's start tag, content and end tag.
+ * @param int
+ * @return string
+ */
+ public function render($indent = NULL)
+ {
+ $s = $this->startTag();
+
+ if (!$this->isEmpty) {
+ // add content
+ if ($indent !== NULL) {
+ $indent++;
+ }
+ foreach ($this->children as $child) {
+ if (is_object($child)) {
+ $s .= $child->render($indent);
+ } else {
+ $s .= $child;
+ }
+ }
+
+ // add end tag
+ $s .= $this->endTag();
+ }
+
+ if ($indent !== NULL) {
+ return "\n" . str_repeat("\t", $indent - 1) . $s . "\n" . str_repeat("\t", max(0, $indent - 2));
+ }
+ return $s;
+ }
+
+
+ public function __toString()
+ {
+ return $this->render();
+ }
+
+
+ /**
+ * Returns element's start tag.
+ * @return string
+ */
+ public function startTag()
+ {
+ if ($this->name) {
+ return '<' . $this->name . $this->attributes() . (static::$xhtml && $this->isEmpty ? ' />' : '>');
+
+ } else {
+ return '';
+ }
+ }
+
+
+ /**
+ * Returns element's end tag.
+ * @return string
+ */
+ public function endTag()
+ {
+ return $this->name && !$this->isEmpty ? '' . $this->name . '>' : '';
+ }
+
+
+ /**
+ * Returns element's attributes.
+ * @return string
+ * @internal
+ */
+ public function attributes()
+ {
+ if (!is_array($this->attrs)) {
+ return '';
+ }
+
+ $s = '';
+ $attrs = $this->attrs;
+ if (isset($attrs['data']) && is_array($attrs['data'])) { // deprecated
+ foreach ($attrs['data'] as $key => $value) {
+ $attrs['data-' . $key] = $value;
+ }
+ unset($attrs['data']);
+ }
+
+ foreach ($attrs as $key => $value) {
+ if ($value === NULL || $value === FALSE) {
+ continue;
+
+ } elseif ($value === TRUE) {
+ if (static::$xhtml) {
+ $s .= ' ' . $key . '="' . $key . '"';
+ } else {
+ $s .= ' ' . $key;
+ }
+ continue;
+
+ } elseif (is_array($value)) {
+ if (strncmp($key, 'data-', 5) === 0) {
+ $value = Json::encode($value);
+
+ } else {
+ $tmp = NULL;
+ foreach ($value as $k => $v) {
+ if ($v != NULL) { // intentionally ==, skip NULLs & empty string
+ // composite 'style' vs. 'others'
+ $tmp[] = $v === TRUE ? $k : (is_string($k) ? $k . ':' . $v : $v);
+ }
+ }
+ if ($tmp === NULL) {
+ continue;
+ }
+
+ $value = implode($key === 'style' || !strncmp($key, 'on', 2) ? ';' : ' ', $tmp);
+ }
+
+ } elseif (is_float($value)) {
+ $value = rtrim(rtrim(number_format($value, 10, '.', ''), '0'), '.');
+
+ } else {
+ $value = (string) $value;
+ }
+
+ $q = strpos($value, '"') === FALSE ? '"' : "'";
+ $s .= ' ' . $key . '=' . $q
+ . str_replace(
+ array('&', $q, '<'),
+ array('&', $q === '"' ? '"' : ''', self::$xhtml ? '<' : '<'),
+ $value
+ )
+ . (strpos($value, '`') !== FALSE && strpbrk($value, ' <>"\'') === FALSE ? ' ' : '')
+ . $q;
+ }
+
+ $s = str_replace('@', '@', $s);
+ return $s;
+ }
+
+
+ /**
+ * Clones all children too.
+ */
+ public function __clone()
+ {
+ foreach ($this->children as $key => $value) {
+ if (is_object($value)) {
+ $this->children[$key] = clone $value;
+ }
+ }
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/IHtmlString.php b/vendor/nette/utils/src/Utils/IHtmlString.php
new file mode 100755
index 0000000..c49d212
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/IHtmlString.php
@@ -0,0 +1,19 @@
+
+ * $image = Image::fromFile('nette.jpg');
+ * $image->resize(150, 100);
+ * $image->sharpen();
+ * $image->send();
+ *
+ *
+ * @method void alphaBlending(bool $on)
+ * @method void antialias(bool $on)
+ * @method void arc($x, $y, $w, $h, $start, $end, $color)
+ * @method void char(int $font, $x, $y, string $char, $color)
+ * @method void charUp(int $font, $x, $y, string $char, $color)
+ * @method int colorAllocate($red, $green, $blue)
+ * @method int colorAllocateAlpha($red, $green, $blue, $alpha)
+ * @method int colorAt($x, $y)
+ * @method int colorClosest($red, $green, $blue)
+ * @method int colorClosestAlpha($red, $green, $blue, $alpha)
+ * @method int colorClosestHWB($red, $green, $blue)
+ * @method void colorDeallocate($color)
+ * @method int colorExact($red, $green, $blue)
+ * @method int colorExactAlpha($red, $green, $blue, $alpha)
+ * @method void colorMatch(Image $image2)
+ * @method int colorResolve($red, $green, $blue)
+ * @method int colorResolveAlpha($red, $green, $blue, $alpha)
+ * @method void colorSet($index, $red, $green, $blue)
+ * @method array colorsForIndex($index)
+ * @method int colorsTotal()
+ * @method int colorTransparent($color = NULL)
+ * @method void convolution(array $matrix, float $div, float $offset)
+ * @method void copy(Image $src, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH)
+ * @method void copyMerge(Image $src, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH, $opacity)
+ * @method void copyMergeGray(Image $src, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH, $opacity)
+ * @method void copyResampled(Image $src, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH)
+ * @method void copyResized(Image $src, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH)
+ * @method void dashedLine($x1, $y1, $x2, $y2, $color)
+ * @method void ellipse($cx, $cy, $w, $h, $color)
+ * @method void fill($x, $y, $color)
+ * @method void filledArc($cx, $cy, $w, $h, $s, $e, $color, $style)
+ * @method void filledEllipse($cx, $cy, $w, $h, $color)
+ * @method void filledPolygon(array $points, $numPoints, $color)
+ * @method void filledRectangle($x1, $y1, $x2, $y2, $color)
+ * @method void fillToBorder($x, $y, $border, $color)
+ * @method void filter($filtertype)
+ * @method array ftText($size, $angle, $x, $y, $col, string $fontFile, string $text, array $extrainfo = NULL)
+ * @method void gammaCorrect(float $inputgamma, float $outputgamma)
+ * @method int interlace($interlace = NULL)
+ * @method bool isTrueColor()
+ * @method void layerEffect($effect)
+ * @method void line($x1, $y1, $x2, $y2, $color)
+ * @method void paletteCopy(Image $source)
+ * @method void polygon(array $points, $numPoints, $color)
+ * @method array psText(string $text, $font, $size, $color, $backgroundColor, $x, $y, $space = NULL, $tightness = NULL, float $angle = NULL, $antialiasSteps = NULL)
+ * @method void rectangle($x1, $y1, $x2, $y2, $col)
+ * @method Image rotate(float $angle, $backgroundColor)
+ * @method void saveAlpha(bool $saveflag)
+ * @method void setBrush(Image $brush)
+ * @method void setPixel($x, $y, $color)
+ * @method void setStyle(array $style)
+ * @method void setThickness($thickness)
+ * @method void setTile(Image $tile)
+ * @method void string($font, $x, $y, string $s, $col)
+ * @method void stringUp($font, $x, $y, string $s, $col)
+ * @method void trueColorToPalette(bool $dither, $ncolors)
+ * @method array ttfText($size, $angle, $x, $y, $color, string $fontfile, string $text)
+ * @property-read int $width
+ * @property-read int $height
+ * @property-read resource $imageResource
+ */
+class Image extends Nette\Object
+{
+ /** {@link resize()} only shrinks images */
+ const SHRINK_ONLY = 1;
+
+ /** {@link resize()} will ignore aspect ratio */
+ const STRETCH = 2;
+
+ /** {@link resize()} fits in given area so its dimensions are less than or equal to the required dimensions */
+ const FIT = 0;
+
+ /** {@link resize()} fills given area so its dimensions are greater than or equal to the required dimensions */
+ const FILL = 4;
+
+ /** {@link resize()} fills given area exactly */
+ const EXACT = 8;
+
+ /** image types */
+ const JPEG = IMAGETYPE_JPEG,
+ PNG = IMAGETYPE_PNG,
+ GIF = IMAGETYPE_GIF;
+
+ const EMPTY_GIF = "GIF89a\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\x00\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;";
+
+ /** @deprecated */
+ const ENLARGE = 0;
+
+ /** @var resource */
+ private $image;
+
+
+ /**
+ * Returns RGB color.
+ * @param int red 0..255
+ * @param int green 0..255
+ * @param int blue 0..255
+ * @param int transparency 0..127
+ * @return array
+ */
+ public static function rgb($red, $green, $blue, $transparency = 0)
+ {
+ return array(
+ 'red' => max(0, min(255, (int) $red)),
+ 'green' => max(0, min(255, (int) $green)),
+ 'blue' => max(0, min(255, (int) $blue)),
+ 'alpha' => max(0, min(127, (int) $transparency)),
+ );
+ }
+
+
+ /**
+ * Opens image from file.
+ * @param string
+ * @param mixed detected image format
+ * @throws Nette\NotSupportedException if gd extension is not loaded
+ * @throws UnknownImageFileException if file not found or file type is not known
+ * @return self
+ */
+ public static function fromFile($file, & $format = NULL)
+ {
+ if (!extension_loaded('gd')) {
+ throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
+ }
+
+ static $funcs = array(
+ self::JPEG => 'imagecreatefromjpeg',
+ self::PNG => 'imagecreatefrompng',
+ self::GIF => 'imagecreatefromgif',
+ );
+ $info = @getimagesize($file); // @ - files smaller than 12 bytes causes read error
+ $format = $info[2];
+
+ if (!isset($funcs[$format])) {
+ throw new UnknownImageFileException(is_file($file) ? "Unknown type of file '$file'." : "File '$file' not found.");
+ }
+ return new static(Callback::invokeSafe($funcs[$format], array($file), function ($message) {
+ throw new ImageException($message);
+ }));
+ }
+
+
+ /**
+ * @deprecated
+ */
+ public static function getFormatFromString($s)
+ {
+ trigger_error(__METHOD__ . '() is deprecated; use finfo_buffer() instead.', E_USER_DEPRECATED);
+ $types = array('image/jpeg' => self::JPEG, 'image/gif' => self::GIF, 'image/png' => self::PNG);
+ $type = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $s);
+ return isset($types[$type]) ? $types[$type] : NULL;
+ }
+
+
+ /**
+ * Create a new image from the image stream in the string.
+ * @param string
+ * @param mixed detected image format
+ * @return self
+ * @throws ImageException
+ */
+ public static function fromString($s, & $format = NULL)
+ {
+ if (!extension_loaded('gd')) {
+ throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
+ }
+
+ if (func_num_args() > 1) {
+ $format = @static::getFormatFromString($s); // @ suppress trigger_error
+ }
+
+ return new static(Callback::invokeSafe('imagecreatefromstring', array($s), function ($message) {
+ throw new ImageException($message);
+ }));
+ }
+
+
+ /**
+ * Creates blank image.
+ * @param int
+ * @param int
+ * @param array
+ * @return self
+ */
+ public static function fromBlank($width, $height, $color = NULL)
+ {
+ if (!extension_loaded('gd')) {
+ throw new Nette\NotSupportedException('PHP extension GD is not loaded.');
+ }
+
+ $width = (int) $width;
+ $height = (int) $height;
+ if ($width < 1 || $height < 1) {
+ throw new Nette\InvalidArgumentException('Image width and height must be greater than zero.');
+ }
+
+ $image = imagecreatetruecolor($width, $height);
+ if (is_array($color)) {
+ $color += array('alpha' => 0);
+ $color = imagecolorallocatealpha($image, $color['red'], $color['green'], $color['blue'], $color['alpha']);
+ imagealphablending($image, FALSE);
+ imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, $color);
+ imagealphablending($image, TRUE);
+ }
+ return new static($image);
+ }
+
+
+ /**
+ * Wraps GD image.
+ * @param resource
+ */
+ public function __construct($image)
+ {
+ $this->setImageResource($image);
+ imagesavealpha($image, TRUE);
+ }
+
+
+ /**
+ * Returns image width.
+ * @return int
+ */
+ public function getWidth()
+ {
+ return imagesx($this->image);
+ }
+
+
+ /**
+ * Returns image height.
+ * @return int
+ */
+ public function getHeight()
+ {
+ return imagesy($this->image);
+ }
+
+
+ /**
+ * Sets image resource.
+ * @param resource
+ * @return self
+ */
+ protected function setImageResource($image)
+ {
+ if (!is_resource($image) || get_resource_type($image) !== 'gd') {
+ throw new Nette\InvalidArgumentException('Image is not valid.');
+ }
+ $this->image = $image;
+ return $this;
+ }
+
+
+ /**
+ * Returns image GD resource.
+ * @return resource
+ */
+ public function getImageResource()
+ {
+ return $this->image;
+ }
+
+
+ /**
+ * Resizes image.
+ * @param mixed width in pixels or percent
+ * @param mixed height in pixels or percent
+ * @param int flags
+ * @return self
+ */
+ public function resize($width, $height, $flags = self::FIT)
+ {
+ if ($flags & self::EXACT) {
+ return $this->resize($width, $height, self::FILL)->crop('50%', '50%', $width, $height);
+ }
+
+ list($newWidth, $newHeight) = static::calculateSize($this->getWidth(), $this->getHeight(), $width, $height, $flags);
+
+ if ($newWidth !== $this->getWidth() || $newHeight !== $this->getHeight()) { // resize
+ $newImage = static::fromBlank($newWidth, $newHeight, self::RGB(0, 0, 0, 127))->getImageResource();
+ imagecopyresampled(
+ $newImage, $this->image,
+ 0, 0, 0, 0,
+ $newWidth, $newHeight, $this->getWidth(), $this->getHeight()
+ );
+ $this->image = $newImage;
+ }
+
+ if ($width < 0 || $height < 0) { // flip is processed in two steps for better quality
+ $newImage = static::fromBlank($newWidth, $newHeight, self::RGB(0, 0, 0, 127))->getImageResource();
+ imagecopyresampled(
+ $newImage, $this->image,
+ 0, 0, $width < 0 ? $newWidth - 1 : 0, $height < 0 ? $newHeight - 1 : 0,
+ $newWidth, $newHeight, $width < 0 ? -$newWidth : $newWidth, $height < 0 ? -$newHeight : $newHeight
+ );
+ $this->image = $newImage;
+ }
+ return $this;
+ }
+
+
+ /**
+ * Calculates dimensions of resized image.
+ * @param mixed source width
+ * @param mixed source height
+ * @param mixed width in pixels or percent
+ * @param mixed height in pixels or percent
+ * @param int flags
+ * @return array
+ */
+ public static function calculateSize($srcWidth, $srcHeight, $newWidth, $newHeight, $flags = self::FIT)
+ {
+ if (substr($newWidth, -1) === '%') {
+ $newWidth = round($srcWidth / 100 * abs($newWidth));
+ $percents = TRUE;
+ } else {
+ $newWidth = (int) abs($newWidth);
+ }
+
+ if (substr($newHeight, -1) === '%') {
+ $newHeight = round($srcHeight / 100 * abs($newHeight));
+ $flags |= empty($percents) ? 0 : self::STRETCH;
+ } else {
+ $newHeight = (int) abs($newHeight);
+ }
+
+ if ($flags & self::STRETCH) { // non-proportional
+ if (empty($newWidth) || empty($newHeight)) {
+ throw new Nette\InvalidArgumentException('For stretching must be both width and height specified.');
+ }
+
+ if ($flags & self::SHRINK_ONLY) {
+ $newWidth = round($srcWidth * min(1, $newWidth / $srcWidth));
+ $newHeight = round($srcHeight * min(1, $newHeight / $srcHeight));
+ }
+
+ } else { // proportional
+ if (empty($newWidth) && empty($newHeight)) {
+ throw new Nette\InvalidArgumentException('At least width or height must be specified.');
+ }
+
+ $scale = array();
+ if ($newWidth > 0) { // fit width
+ $scale[] = $newWidth / $srcWidth;
+ }
+
+ if ($newHeight > 0) { // fit height
+ $scale[] = $newHeight / $srcHeight;
+ }
+
+ if ($flags & self::FILL) {
+ $scale = array(max($scale));
+ }
+
+ if ($flags & self::SHRINK_ONLY) {
+ $scale[] = 1;
+ }
+
+ $scale = min($scale);
+ $newWidth = round($srcWidth * $scale);
+ $newHeight = round($srcHeight * $scale);
+ }
+
+ return array(max((int) $newWidth, 1), max((int) $newHeight, 1));
+ }
+
+
+ /**
+ * Crops image.
+ * @param mixed x-offset in pixels or percent
+ * @param mixed y-offset in pixels or percent
+ * @param mixed width in pixels or percent
+ * @param mixed height in pixels or percent
+ * @return self
+ */
+ public function crop($left, $top, $width, $height)
+ {
+ list($left, $top, $width, $height) = static::calculateCutout($this->getWidth(), $this->getHeight(), $left, $top, $width, $height);
+ $newImage = static::fromBlank($width, $height, self::RGB(0, 0, 0, 127))->getImageResource();
+ imagecopy($newImage, $this->image, 0, 0, $left, $top, $width, $height);
+ $this->image = $newImage;
+ return $this;
+ }
+
+
+ /**
+ * Calculates dimensions of cutout in image.
+ * @param mixed source width
+ * @param mixed source height
+ * @param mixed x-offset in pixels or percent
+ * @param mixed y-offset in pixels or percent
+ * @param mixed width in pixels or percent
+ * @param mixed height in pixels or percent
+ * @return array
+ */
+ public static function calculateCutout($srcWidth, $srcHeight, $left, $top, $newWidth, $newHeight)
+ {
+ if (substr($newWidth, -1) === '%') {
+ $newWidth = round($srcWidth / 100 * $newWidth);
+ }
+ if (substr($newHeight, -1) === '%') {
+ $newHeight = round($srcHeight / 100 * $newHeight);
+ }
+ if (substr($left, -1) === '%') {
+ $left = round(($srcWidth - $newWidth) / 100 * $left);
+ }
+ if (substr($top, -1) === '%') {
+ $top = round(($srcHeight - $newHeight) / 100 * $top);
+ }
+ if ($left < 0) {
+ $newWidth += $left;
+ $left = 0;
+ }
+ if ($top < 0) {
+ $newHeight += $top;
+ $top = 0;
+ }
+ $newWidth = min((int) $newWidth, $srcWidth - $left);
+ $newHeight = min((int) $newHeight, $srcHeight - $top);
+ return array($left, $top, $newWidth, $newHeight);
+ }
+
+
+ /**
+ * Sharpen image.
+ * @return self
+ */
+ public function sharpen()
+ {
+ imageconvolution($this->image, array( // my magic numbers ;)
+ array(-1, -1, -1),
+ array(-1, 24, -1),
+ array(-1, -1, -1),
+ ), 16, 0);
+ return $this;
+ }
+
+
+ /**
+ * Puts another image into this image.
+ * @param Image
+ * @param mixed x-coordinate in pixels or percent
+ * @param mixed y-coordinate in pixels or percent
+ * @param int opacity 0..100
+ * @return self
+ */
+ public function place(Image $image, $left = 0, $top = 0, $opacity = 100)
+ {
+ $opacity = max(0, min(100, (int) $opacity));
+
+ if (substr($left, -1) === '%') {
+ $left = round(($this->getWidth() - $image->getWidth()) / 100 * $left);
+ }
+
+ if (substr($top, -1) === '%') {
+ $top = round(($this->getHeight() - $image->getHeight()) / 100 * $top);
+ }
+
+ if ($opacity === 100) {
+ imagecopy(
+ $this->image, $image->getImageResource(),
+ $left, $top, 0, 0, $image->getWidth(), $image->getHeight()
+ );
+
+ } elseif ($opacity != 0) {
+ $cutting = imagecreatetruecolor($image->getWidth(), $image->getHeight());
+ imagecopy(
+ $cutting, $this->image,
+ 0, 0, $left, $top, $image->getWidth(), $image->getHeight()
+ );
+ imagecopy(
+ $cutting, $image->getImageResource(),
+ 0, 0, 0, 0, $image->getWidth(), $image->getHeight()
+ );
+
+ imagecopymerge(
+ $this->image, $cutting,
+ $left, $top, 0, 0, $image->getWidth(), $image->getHeight(),
+ $opacity
+ );
+ }
+ return $this;
+ }
+
+
+ /**
+ * Saves image to the file.
+ * @param string filename
+ * @param int quality 0..100 (for JPEG and PNG)
+ * @param int optional image type
+ * @return bool TRUE on success or FALSE on failure.
+ */
+ public function save($file = NULL, $quality = NULL, $type = NULL)
+ {
+ if ($type === NULL) {
+ switch (strtolower($ext = pathinfo($file, PATHINFO_EXTENSION))) {
+ case 'jpg':
+ case 'jpeg':
+ $type = self::JPEG;
+ break;
+ case 'png':
+ $type = self::PNG;
+ break;
+ case 'gif':
+ $type = self::GIF;
+ break;
+ default:
+ throw new Nette\InvalidArgumentException("Unsupported file extension '$ext'.");
+ }
+ }
+
+ switch ($type) {
+ case self::JPEG:
+ $quality = $quality === NULL ? 85 : max(0, min(100, (int) $quality));
+ return imagejpeg($this->image, $file, $quality);
+
+ case self::PNG:
+ $quality = $quality === NULL ? 9 : max(0, min(9, (int) $quality));
+ return imagepng($this->image, $file, $quality);
+
+ case self::GIF:
+ return imagegif($this->image, $file);
+
+ default:
+ throw new Nette\InvalidArgumentException("Unsupported image type '$type'.");
+ }
+ }
+
+
+ /**
+ * Outputs image to string.
+ * @param int image type
+ * @param int quality 0..100 (for JPEG and PNG)
+ * @return string
+ */
+ public function toString($type = self::JPEG, $quality = NULL)
+ {
+ ob_start();
+ $this->save(NULL, $quality, $type);
+ return ob_get_clean();
+ }
+
+
+ /**
+ * Outputs image to string.
+ * @return string
+ */
+ public function __toString()
+ {
+ try {
+ return $this->toString();
+ } catch (\Exception $e) {
+ if (func_num_args()) {
+ throw $e;
+ }
+ trigger_error("Exception in " . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
+ }
+ }
+
+
+ /**
+ * Outputs image to browser.
+ * @param int image type
+ * @param int quality 0..100 (for JPEG and PNG)
+ * @return bool TRUE on success or FALSE on failure.
+ */
+ public function send($type = self::JPEG, $quality = NULL)
+ {
+ if (!in_array($type, array(self::JPEG, self::PNG, self::GIF), TRUE)) {
+ throw new Nette\InvalidArgumentException("Unsupported image type '$type'.");
+ }
+ header('Content-Type: ' . image_type_to_mime_type($type));
+ return $this->save(NULL, $quality, $type);
+ }
+
+
+ /**
+ * Call to undefined method.
+ *
+ * @param string method name
+ * @param array arguments
+ * @return mixed
+ * @throws Nette\MemberAccessException
+ */
+ public function __call($name, $args)
+ {
+ $function = 'image' . $name;
+ if (function_exists($function)) {
+ foreach ($args as $key => $value) {
+ if ($value instanceof self) {
+ $args[$key] = $value->getImageResource();
+
+ } elseif (is_array($value) && isset($value['red'])) { // rgb
+ $args[$key] = imagecolorallocatealpha(
+ $this->image,
+ $value['red'], $value['green'], $value['blue'], $value['alpha']
+ );
+ }
+ }
+ array_unshift($args, $this->image);
+
+ $res = call_user_func_array($function, $args);
+ return is_resource($res) && get_resource_type($res) === 'gd' ? $this->setImageResource($res) : $res;
+ }
+
+ return parent::__call($name, $args);
+ }
+
+
+ public function __clone()
+ {
+ ob_start();
+ imagegd2($this->image);
+ $this->setImageResource(imagecreatefromstring(ob_get_clean()));
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/Json.php b/vendor/nette/utils/src/Utils/Json.php
new file mode 100755
index 0000000..0e7c21a
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Json.php
@@ -0,0 +1,99 @@
+ 'The maximum stack depth has been exceeded',
+ JSON_ERROR_STATE_MISMATCH => 'Syntax error, malformed JSON',
+ JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
+ JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
+ 5 /*JSON_ERROR_UTF8*/ => 'Invalid UTF-8 sequence', // exists since 5.3.3, but is returned since 5.3.1
+ );
+
+
+ /**
+ * Static class - cannot be instantiated.
+ */
+ final public function __construct()
+ {
+ throw new Nette\StaticClassException;
+ }
+
+
+ /**
+ * Returns the JSON representation of a value.
+ * @param mixed
+ * @param int accepts Json::PRETTY
+ * @return string
+ */
+ public static function encode($value, $options = 0)
+ {
+ $flags = PHP_VERSION_ID >= 50400 ? (JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | ($options & self::PRETTY ? JSON_PRETTY_PRINT : 0)) : 0;
+
+ if (PHP_VERSION_ID < 50500) {
+ $json = Callback::invokeSafe('json_encode', array($value, $flags), function ($message) { // needed to receive 'recursion detected' error
+ throw new JsonException($message);
+ });
+ } else {
+ $json = json_encode($value, $flags);
+ }
+
+ if ($error = json_last_error()) {
+ $message = isset(static::$messages[$error]) ? static::$messages[$error]
+ : (PHP_VERSION_ID >= 50500 ? json_last_error_msg() : 'Unknown error');
+ throw new JsonException($message, $error);
+ }
+
+ $json = str_replace(array("\xe2\x80\xa8", "\xe2\x80\xa9"), array('\u2028', '\u2029'), $json);
+ return $json;
+ }
+
+
+ /**
+ * Decodes a JSON string.
+ * @param string
+ * @param int accepts Json::FORCE_ARRAY
+ * @return mixed
+ */
+ public static function decode($json, $options = 0)
+ {
+ $json = (string) $json;
+ if (!preg_match('##u', $json)) {
+ throw new JsonException('Invalid UTF-8 sequence', 5); // workaround for PHP < 5.3.3 & PECL JSON-C
+ }
+
+ $forceArray = (bool) ($options & self::FORCE_ARRAY);
+ if (!$forceArray && preg_match('#(?<=[^\\\\]")\\\\u0000(?:[^"\\\\]|\\\\.)*+"\s*+:#', $json)) { // workaround for json_decode fatal error when object key starts with \u0000
+ throw new JsonException(static::$messages[JSON_ERROR_CTRL_CHAR]);
+ }
+ $args = array($json, $forceArray, 512);
+ if (PHP_VERSION_ID >= 50400 && !(defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) { // not implemented in PECL JSON-C 1.3.2 for 64bit systems
+ $args[] = JSON_BIGINT_AS_STRING;
+ }
+ $value = call_user_func_array('json_decode', $args);
+
+ if ($value === NULL && $json !== '' && strcasecmp(trim($json, " \t\n\r"), 'null') !== 0) { // '' is not clearing json_last_error
+ $error = json_last_error();
+ throw new JsonException(isset(static::$messages[$error]) ? static::$messages[$error] : 'Unknown error', $error);
+ }
+ return $value;
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/Object.php b/vendor/nette/utils/src/Utils/Object.php
new file mode 100755
index 0000000..5f212d7
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Object.php
@@ -0,0 +1,162 @@
+
+ * $val = $obj->label; // equivalent to $val = $obj->getLabel();
+ * $obj->label = 'Nette'; // equivalent to $obj->setLabel('Nette');
+ *
+ * Property names are case-sensitive, and they are written in the camelCaps
+ * or PascalCaps.
+ *
+ * Event functionality is provided by declaration of property named 'on{Something}'
+ * Multiple handlers are allowed.
+ *
+ * public $onClick; // declaration in class
+ * $this->onClick[] = 'callback'; // attaching event handler
+ * if (!empty($this->onClick)) ... // are there any handlers?
+ * $this->onClick($sender, $arg); // raises the event with arguments
+ *
+ *
+ * Adding method to class (i.e. to all instances) works similar to JavaScript
+ * prototype property. The syntax for adding a new method is:
+ *
+ * MyClass::extensionMethod('newMethod', function (MyClass $obj, $arg, ...) { ... });
+ * $obj = new MyClass;
+ * $obj->newMethod($x);
+ *
+ *
+ * @property-read Nette\Reflection\ClassType|\ReflectionClass $reflection
+ */
+abstract class Object
+{
+
+ /**
+ * Access to reflection.
+ * @return Nette\Reflection\ClassType|\ReflectionClass
+ */
+ public static function getReflection()
+ {
+ $class = class_exists('Nette\Reflection\ClassType') ? 'Nette\Reflection\ClassType' : 'ReflectionClass';
+ return new $class(get_called_class());
+ }
+
+
+ /**
+ * Call to undefined method.
+ * @param string method name
+ * @param array arguments
+ * @return mixed
+ * @throws MemberAccessException
+ */
+ public function __call($name, $args)
+ {
+ return ObjectMixin::call($this, $name, $args);
+ }
+
+
+ /**
+ * Call to undefined static method.
+ * @param string method name (in lower case!)
+ * @param array arguments
+ * @return mixed
+ * @throws MemberAccessException
+ */
+ public static function __callStatic($name, $args)
+ {
+ return ObjectMixin::callStatic(get_called_class(), $name, $args);
+ }
+
+
+ /**
+ * Adding method to class.
+ * @param string method name
+ * @param callable
+ * @return mixed
+ */
+ public static function extensionMethod($name, $callback = NULL)
+ {
+ if (strpos($name, '::') === FALSE) {
+ $class = get_called_class();
+ } else {
+ list($class, $name) = explode('::', $name);
+ $rc = new \ReflectionClass($class);
+ $class = $rc->getName();
+ }
+ if ($callback === NULL) {
+ return ObjectMixin::getExtensionMethod($class, $name);
+ } else {
+ ObjectMixin::setExtensionMethod($class, $name, $callback);
+ }
+ }
+
+
+ /**
+ * Returns property value. Do not call directly.
+ * @param string property name
+ * @return mixed property value
+ * @throws MemberAccessException if the property is not defined.
+ */
+ public function &__get($name)
+ {
+ return ObjectMixin::get($this, $name);
+ }
+
+
+ /**
+ * Sets value of a property. Do not call directly.
+ * @param string property name
+ * @param mixed property value
+ * @return void
+ * @throws MemberAccessException if the property is not defined or is read-only
+ */
+ public function __set($name, $value)
+ {
+ ObjectMixin::set($this, $name, $value);
+ }
+
+
+ /**
+ * Is property defined?
+ * @param string property name
+ * @return bool
+ */
+ public function __isset($name)
+ {
+ return ObjectMixin::has($this, $name);
+ }
+
+
+ /**
+ * Access to undeclared property.
+ * @param string property name
+ * @return void
+ * @throws MemberAccessException
+ */
+ public function __unset($name)
+ {
+ ObjectMixin::remove($this, $name);
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/ObjectMixin.php b/vendor/nette/utils/src/Utils/ObjectMixin.php
new file mode 100755
index 0000000..16c4a17
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/ObjectMixin.php
@@ -0,0 +1,391 @@
+ 0 | bool | array) used by getMethods() */
+ private static $methods;
+
+ /** @var array (name => 'event' | TRUE) used by hasProperty() */
+ private static $props;
+
+ /** @var array (name => array(type => callback)) used by get|setExtensionMethod() */
+ private static $extMethods;
+
+
+ /**
+ * Static class - cannot be instantiated.
+ */
+ final public function __construct()
+ {
+ throw new Nette\StaticClassException;
+ }
+
+
+ /**
+ * __call() implementation.
+ * @param object
+ * @param string
+ * @param array
+ * @return mixed
+ * @throws MemberAccessException
+ */
+ public static function call($_this, $name, $args)
+ {
+ $class = get_class($_this);
+ $isProp = self::hasProperty($class, $name);
+
+ if ($name === '') {
+ throw new MemberAccessException("Call to class '$class' method without name.");
+
+ } elseif ($isProp && $_this->$name instanceof \Closure) { // closure in property
+ return call_user_func_array($_this->$name, $args);
+
+ } elseif ($isProp === 'event') { // calling event handlers
+ if (is_array($_this->$name) || $_this->$name instanceof \Traversable) {
+ foreach ($_this->$name as $handler) {
+ Callback::invokeArgs($handler, $args);
+ }
+ } elseif ($_this->$name !== NULL) {
+ throw new Nette\UnexpectedValueException("Property $class::$$name must be array or NULL, " . gettype($_this->$name) . ' given.');
+ }
+
+ } elseif (($methods = & self::getMethods($class)) && isset($methods[$name]) && is_array($methods[$name])) { // magic @methods
+ list($op, $rp, $type) = $methods[$name];
+ if (count($args) !== ($op === 'get' ? 0 : 1)) {
+ throw new Nette\InvalidArgumentException("$class::$name() expects " . ($op === 'get' ? 'no' : '1') . ' argument, ' . count($args) . ' given.');
+
+ } elseif ($type && $args && !self::checkType($args[0], $type)) {
+ throw new Nette\InvalidArgumentException("Argument passed to $class::$name() must be $type, " . gettype($args[0]) . ' given.');
+ }
+
+ if ($op === 'get') {
+ return $rp->getValue($_this);
+ } elseif ($op === 'set') {
+ $rp->setValue($_this, $args[0]);
+ } elseif ($op === 'add') {
+ $val = $rp->getValue($_this);
+ $val[] = $args[0];
+ $rp->setValue($_this, $val);
+ }
+ return $_this;
+
+ } elseif ($cb = self::getExtensionMethod($class, $name)) { // extension methods
+ array_unshift($args, $_this);
+ return Callback::invokeArgs($cb, $args);
+
+ } else {
+ if (method_exists($class, $name)) { // called parent::$name()
+ $class = 'parent';
+ }
+ throw new MemberAccessException("Call to undefined method $class::$name().");
+ }
+ }
+
+
+ /**
+ * __callStatic() implementation.
+ * @param string
+ * @param string
+ * @param array
+ * @return void
+ * @throws MemberAccessException
+ */
+ public static function callStatic($class, $method, $args)
+ {
+ throw new MemberAccessException("Call to undefined static method $class::$method().");
+ }
+
+
+ /**
+ * __get() implementation.
+ * @param object
+ * @param string property name
+ * @return mixed property value
+ * @throws MemberAccessException if the property is not defined.
+ */
+ public static function & get($_this, $name)
+ {
+ $class = get_class($_this);
+ $uname = ucfirst($name);
+ $methods = & self::getMethods($class);
+
+ if ($name === '') {
+ throw new MemberAccessException("Cannot read a class '$class' property without name.");
+
+ } elseif (isset($methods[$m = 'get' . $uname]) || isset($methods[$m = 'is' . $uname])) { // property getter
+ if ($methods[$m] === 0) {
+ $rm = new \ReflectionMethod($class, $m);
+ $methods[$m] = $rm->returnsReference();
+ }
+ if ($methods[$m] === TRUE) {
+ return $_this->$m();
+ } else {
+ $val = $_this->$m();
+ return $val;
+ }
+
+ } elseif (isset($methods[$name])) { // public method as closure getter
+ $val = Callback::closure($_this, $name);
+ return $val;
+
+ } else { // strict class
+ $type = isset($methods['set' . $uname]) ? 'a write-only' : 'an undeclared';
+ throw new MemberAccessException("Cannot read $type property $class::\$$name.");
+ }
+ }
+
+
+ /**
+ * __set() implementation.
+ * @param object
+ * @param string property name
+ * @param mixed property value
+ * @return void
+ * @throws MemberAccessException if the property is not defined or is read-only
+ */
+ public static function set($_this, $name, $value)
+ {
+ $class = get_class($_this);
+ $uname = ucfirst($name);
+ $methods = & self::getMethods($class);
+
+ if ($name === '') {
+ throw new MemberAccessException("Cannot write to a class '$class' property without name.");
+
+ } elseif (self::hasProperty($class, $name)) { // unsetted property
+ $_this->$name = $value;
+
+ } elseif (isset($methods[$m = 'set' . $uname])) { // property setter
+ $_this->$m($value);
+
+ } else { // strict class
+ $type = isset($methods['get' . $uname]) || isset($methods['is' . $uname])
+ ? 'a read-only' : 'an undeclared';
+ throw new MemberAccessException("Cannot write to $type property $class::\$$name.");
+ }
+ }
+
+
+ /**
+ * __unset() implementation.
+ * @param object
+ * @param string property name
+ * @return void
+ * @throws MemberAccessException
+ */
+ public static function remove($_this, $name)
+ {
+ $class = get_class($_this);
+ if (!self::hasProperty($class, $name)) { // strict class
+ throw new MemberAccessException("Cannot unset the property $class::\$$name.");
+ }
+ }
+
+
+ /**
+ * __isset() implementation.
+ * @param object
+ * @param string property name
+ * @return bool
+ */
+ public static function has($_this, $name)
+ {
+ $name = ucfirst($name);
+ $methods = & self::getMethods(get_class($_this));
+ return $name !== '' && (isset($methods['get' . $name]) || isset($methods['is' . $name]));
+ }
+
+
+ /**
+ * Checks if the public non-static property exists.
+ * @return mixed
+ */
+ private static function hasProperty($class, $name)
+ {
+ $prop = & self::$props[$class][$name];
+ if ($prop === NULL) {
+ $prop = FALSE;
+ try {
+ $rp = new \ReflectionProperty($class, $name);
+ if ($rp->isPublic() && !$rp->isStatic()) {
+ $prop = $name >= 'onA' && $name < 'on_' ? 'event' : TRUE;
+ }
+ } catch (\ReflectionException $e) {
+ }
+ }
+ return $prop;
+ }
+
+
+ /**
+ * Returns array of public (static, non-static and magic) methods.
+ * @return array
+ */
+ private static function & getMethods($class)
+ {
+ if (!isset(self::$methods[$class])) {
+ self::$methods[$class] = array_fill_keys(get_class_methods($class), 0) + self::getMagicMethods($class);
+ if ($parent = get_parent_class($class)) {
+ self::$methods[$class] += self::getMethods($parent);
+ }
+ }
+ return self::$methods[$class];
+ }
+
+
+ /**
+ * Returns array of magic methods defined by annotation @method.
+ * @return array
+ */
+ public static function getMagicMethods($class)
+ {
+ $rc = new \ReflectionClass($class);
+ preg_match_all('~^
+ [ \t*]* @method [ \t]+
+ (?: [^\s(]+ [ \t]+ )?
+ (set|get|is|add) ([A-Z]\w*) [ \t]*
+ (?: \( [ \t]* ([^)$\s]+) )?
+ ()~mx', $rc->getDocComment(), $matches, PREG_SET_ORDER);
+
+ $methods = array();
+ foreach ($matches as $m) {
+ list(, $op, $prop, $type) = $m;
+ $name = $op . $prop;
+ $prop = strtolower($prop[0]) . substr($prop, 1) . ($op === 'add' ? 's' : '');
+ if ($rc->hasProperty($prop) && ($rp = $rc->getProperty($prop)) && !$rp->isStatic()) {
+ $rp->setAccessible(TRUE);
+ if ($op === 'get' || $op === 'is') {
+ $type = NULL;
+ $op = 'get';
+ } elseif (!$type && preg_match('#@var[ \t]+(\S+)' . ($op === 'add' ? '\[\]#' : '#'), $rp->getDocComment(), $m)) {
+ $type = $m[1];
+ }
+ if ($rc->inNamespace() && preg_match('#^[A-Z]\w+(\[|\||\z)#', $type)) {
+ $type = $rc->getNamespaceName() . '\\' . $type;
+ }
+ $methods[$name] = array($op, $rp, $type);
+ }
+ }
+ return $methods;
+ }
+
+
+ /**
+ * Finds whether a variable is of expected type and do non-data-loss conversion.
+ * @return bool
+ * @internal
+ */
+ public static function checkType(& $val, $type)
+ {
+ if (strpos($type, '|') !== FALSE) {
+ $found = NULL;
+ foreach (explode('|', $type) as $type) {
+ $tmp = $val;
+ if (self::checkType($tmp, $type)) {
+ if ($val === $tmp) {
+ return TRUE;
+ }
+ $found[] = $tmp;
+ }
+ }
+ if ($found) {
+ $val = $found[0];
+ return TRUE;
+ }
+ return FALSE;
+
+ } elseif (substr($type, -2) === '[]') {
+ if (!is_array($val)) {
+ return FALSE;
+ }
+ $type = substr($type, 0, -2);
+ $res = array();
+ foreach ($val as $k => $v) {
+ if (!self::checkType($v, $type)) {
+ return FALSE;
+ }
+ $res[$k] = $v;
+ }
+ $val = $res;
+ return TRUE;
+ }
+
+ switch (strtolower($type)) {
+ case NULL:
+ case 'mixed':
+ return TRUE;
+ case 'bool':
+ case 'boolean':
+ return ($val === NULL || is_scalar($val)) && settype($val, 'bool');
+ case 'string':
+ return ($val === NULL || is_scalar($val) || (is_object($val) && method_exists($val, '__toString'))) && settype($val, 'string');
+ case 'int':
+ case 'integer':
+ return ($val === NULL || is_bool($val) || is_numeric($val)) && ((float) (int) $val === (float) $val) && settype($val, 'int');
+ case 'float':
+ return ($val === NULL || is_bool($val) || is_numeric($val)) && settype($val, 'float');
+ case 'scalar':
+ case 'array':
+ case 'object':
+ case 'callable':
+ case 'resource':
+ case 'null':
+ return call_user_func("is_$type", $val);
+ default:
+ return $val instanceof $type;
+ }
+ }
+
+
+ /**
+ * Adds a method to class.
+ * @param string
+ * @param string
+ * @param mixed callable
+ * @return void
+ */
+ public static function setExtensionMethod($class, $name, $callback)
+ {
+ $name = strtolower($name);
+ self::$extMethods[$name][$class] = Callback::check($callback);
+ self::$extMethods[$name][''] = NULL;
+ }
+
+
+ /**
+ * Returns extension method.
+ * @param string
+ * @param string
+ * @return mixed
+ */
+ public static function getExtensionMethod($class, $name)
+ {
+ $list = & self::$extMethods[strtolower($name)];
+ $cache = & $list[''][$class];
+ if (isset($cache)) {
+ return $cache;
+ }
+
+ foreach (array($class) + class_parents($class) + class_implements($class) as $cl) {
+ if (isset($list[$cl])) {
+ return $cache = $list[$cl];
+ }
+ }
+ return $cache = FALSE;
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/Paginator.php b/vendor/nette/utils/src/Utils/Paginator.php
new file mode 100755
index 0000000..f8caca2
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Paginator.php
@@ -0,0 +1,226 @@
+page = (int) $page;
+ return $this;
+ }
+
+
+ /**
+ * Returns current page number.
+ * @return int
+ */
+ public function getPage()
+ {
+ return $this->base + $this->getPageIndex();
+ }
+
+
+ /**
+ * Returns first page number.
+ * @return int
+ */
+ public function getFirstPage()
+ {
+ return $this->base;
+ }
+
+
+ /**
+ * Returns last page number.
+ * @return int|NULL
+ */
+ public function getLastPage()
+ {
+ return $this->itemCount === NULL ? NULL : $this->base + max(0, $this->getPageCount() - 1);
+ }
+
+
+ /**
+ * Sets first page (base) number.
+ * @param int
+ * @return self
+ */
+ public function setBase($base)
+ {
+ $this->base = (int) $base;
+ return $this;
+ }
+
+
+ /**
+ * Returns first page (base) number.
+ * @return int
+ */
+ public function getBase()
+ {
+ return $this->base;
+ }
+
+
+ /**
+ * Returns zero-based page number.
+ * @return int
+ */
+ protected function getPageIndex()
+ {
+ $index = max(0, $this->page - $this->base);
+ return $this->itemCount === NULL ? $index : min($index, max(0, $this->getPageCount() - 1));
+ }
+
+
+ /**
+ * Is the current page the first one?
+ * @return bool
+ */
+ public function isFirst()
+ {
+ return $this->getPageIndex() === 0;
+ }
+
+
+ /**
+ * Is the current page the last one?
+ * @return bool
+ */
+ public function isLast()
+ {
+ return $this->itemCount === NULL ? FALSE : $this->getPageIndex() >= $this->getPageCount() - 1;
+ }
+
+
+ /**
+ * Returns the total number of pages.
+ * @return int|NULL
+ */
+ public function getPageCount()
+ {
+ return $this->itemCount === NULL ? NULL : (int) ceil($this->itemCount / $this->itemsPerPage);
+ }
+
+
+ /**
+ * Sets the number of items to display on a single page.
+ * @param int
+ * @return self
+ */
+ public function setItemsPerPage($itemsPerPage)
+ {
+ $this->itemsPerPage = max(1, (int) $itemsPerPage);
+ return $this;
+ }
+
+
+ /**
+ * Returns the number of items to display on a single page.
+ * @return int
+ */
+ public function getItemsPerPage()
+ {
+ return $this->itemsPerPage;
+ }
+
+
+ /**
+ * Sets the total number of items.
+ * @param int (or NULL as infinity)
+ * @return self
+ */
+ public function setItemCount($itemCount)
+ {
+ $this->itemCount = ($itemCount === FALSE || $itemCount === NULL) ? NULL : max(0, (int) $itemCount);
+ return $this;
+ }
+
+
+ /**
+ * Returns the total number of items.
+ * @return int|NULL
+ */
+ public function getItemCount()
+ {
+ return $this->itemCount;
+ }
+
+
+ /**
+ * Returns the absolute index of the first item on current page.
+ * @return int
+ */
+ public function getOffset()
+ {
+ return $this->getPageIndex() * $this->itemsPerPage;
+ }
+
+
+ /**
+ * Returns the absolute index of the first item on current page in countdown paging.
+ * @return int|NULL
+ */
+ public function getCountdownOffset()
+ {
+ return $this->itemCount === NULL
+ ? NULL
+ : max(0, $this->itemCount - ($this->getPageIndex() + 1) * $this->itemsPerPage);
+ }
+
+
+ /**
+ * Returns the number of items on current page.
+ * @return int|NULL
+ */
+ public function getLength()
+ {
+ return $this->itemCount === NULL
+ ? $this->itemsPerPage
+ : min($this->itemsPerPage, $this->itemCount - $this->getPageIndex() * $this->itemsPerPage);
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/Random.php b/vendor/nette/utils/src/Utils/Random.php
new file mode 100755
index 0000000..13f9dea
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Random.php
@@ -0,0 +1,64 @@
+= 50400 || !defined('PHP_WINDOWS_VERSION_BUILD')) // slow in PHP 5.3 & Windows
+ ) {
+ $rand3 = openssl_random_pseudo_bytes($length);
+ }
+ if (empty($rand3) && function_exists('mcrypt_create_iv') && (PHP_VERSION_ID >= 50307 || !$windows)) { // PHP bug #52523
+ $rand3 = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
+ }
+ if (empty($rand3) && !$windows && @is_readable('/dev/urandom')) {
+ $rand3 = file_get_contents('/dev/urandom', FALSE, NULL, -1, $length);
+ }
+ if (empty($rand3)) {
+ static $cache;
+ $rand3 = $cache ?: $cache = md5(serialize($_SERVER), TRUE);
+ }
+
+ $s = '';
+ for ($i = 0; $i < $length; $i++) {
+ if ($i % 5 === 0) {
+ list($rand, $rand2) = explode(' ', microtime());
+ $rand += lcg_value();
+ }
+ $rand *= $chLen;
+ $s .= $charlist[($rand + $rand2 + ord($rand3[$i % strlen($rand3)])) % $chLen];
+ $rand -= (int) $rand;
+ }
+ return $s;
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/Strings.php b/vendor/nette/utils/src/Utils/Strings.php
new file mode 100755
index 0000000..c19002f
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Strings.php
@@ -0,0 +1,607 @@
+= 0xD800 && $code <= 0xDFFF) || $code > 0x10FFFF) {
+ throw new Nette\InvalidArgumentException('Code point must be in range 0x0 to 0xD7FF or 0xE000 to 0x10FFFF.');
+ }
+ return iconv('UTF-32BE', 'UTF-8//IGNORE', pack('N', $code));
+ }
+
+
+ /**
+ * Starts the $haystack string with the prefix $needle?
+ * @param string
+ * @param string
+ * @return bool
+ */
+ public static function startsWith($haystack, $needle)
+ {
+ return strncmp($haystack, $needle, strlen($needle)) === 0;
+ }
+
+
+ /**
+ * Ends the $haystack string with the suffix $needle?
+ * @param string
+ * @param string
+ * @return bool
+ */
+ public static function endsWith($haystack, $needle)
+ {
+ return strlen($needle) === 0 || substr($haystack, -strlen($needle)) === $needle;
+ }
+
+
+ /**
+ * Does $haystack contain $needle?
+ * @param string
+ * @param string
+ * @return bool
+ */
+ public static function contains($haystack, $needle)
+ {
+ return strpos($haystack, $needle) !== FALSE;
+ }
+
+
+ /**
+ * Returns a part of UTF-8 string.
+ * @param string
+ * @param int in characters (code points)
+ * @param int in characters (code points)
+ * @return string
+ */
+ public static function substring($s, $start, $length = NULL)
+ {
+ if (function_exists('mb_substr')) {
+ if ($length === NULL && PHP_VERSION_ID < 50408) {
+ $length = self::length($s);
+ }
+ return mb_substr($s, $start, $length, 'UTF-8'); // MB is much faster
+ } elseif ($length === NULL) {
+ $length = self::length($s);
+ } elseif ($start < 0 && $length < 0) {
+ $start += self::length($s); // unifies iconv_substr behavior with mb_substr
+ }
+ return iconv_substr($s, $start, $length, 'UTF-8');
+ }
+
+
+ /**
+ * Removes special controls characters and normalizes line endings and spaces.
+ * @param string UTF-8 encoding
+ * @return string
+ */
+ public static function normalize($s)
+ {
+ $s = self::normalizeNewLines($s);
+
+ // remove control characters; leave \t + \n
+ $s = preg_replace('#[\x00-\x08\x0B-\x1F\x7F-\x9F]+#u', '', $s);
+
+ // right trim
+ $s = preg_replace('#[\t ]+$#m', '', $s);
+
+ // leading and trailing blank lines
+ $s = trim($s, "\n");
+
+ return $s;
+ }
+
+
+ /**
+ * Standardize line endings to unix-like.
+ * @param string UTF-8 encoding or 8-bit
+ * @return string
+ */
+ public static function normalizeNewLines($s)
+ {
+ return str_replace(array("\r\n", "\r"), "\n", $s);
+ }
+
+
+ /**
+ * Converts to ASCII.
+ * @param string UTF-8 encoding
+ * @return string ASCII
+ */
+ public static function toAscii($s)
+ {
+ $s = preg_replace('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{2FF}\x{370}-\x{10FFFF}]#u', '', $s);
+ $s = strtr($s, '`\'"^~?', "\x01\x02\x03\x04\x05\x06");
+ $s = str_replace(
+ array("\xE2\x80\x9E", "\xE2\x80\x9C", "\xE2\x80\x9D", "\xE2\x80\x9A", "\xE2\x80\x98", "\xE2\x80\x99", "\xC2\xB0"),
+ array("\x03", "\x03", "\x03", "\x02", "\x02", "\x02", "\x04"), $s
+ );
+ if (class_exists('Transliterator') && $transliterator = \Transliterator::create('Any-Latin; Latin-ASCII')) {
+ $s = $transliterator->transliterate($s);
+ }
+ if (ICONV_IMPL === 'glibc') {
+ $s = str_replace(
+ array("\xC2\xBB", "\xC2\xAB", "\xE2\x80\xA6", "\xE2\x84\xA2", "\xC2\xA9", "\xC2\xAE"),
+ array('>>', '<<', '...', 'TM', '(c)', '(R)'), $s
+ );
+ $s = @iconv('UTF-8', 'WINDOWS-1250//TRANSLIT//IGNORE', $s); // intentionally @
+ $s = strtr($s, "\xa5\xa3\xbc\x8c\xa7\x8a\xaa\x8d\x8f\x8e\xaf\xb9\xb3\xbe\x9c\x9a\xba\x9d\x9f\x9e"
+ . "\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3"
+ . "\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
+ . "\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xfe"
+ . "\x96\xa0\x8b\x97\x9b\xa6\xad\xb7",
+ 'ALLSSSSTZZZallssstzzzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTsraaaalccceeeeiiddnnooooruuuuyt- <->|-.');
+ $s = preg_replace('#[^\x00-\x7F]++#', '', $s);
+ } else {
+ $s = @iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s); // intentionally @
+ }
+ $s = str_replace(array('`', "'", '"', '^', '~', '?'), '', $s);
+ return strtr($s, "\x01\x02\x03\x04\x05\x06", '`\'"^~?');
+ }
+
+
+ /**
+ * Converts to web safe characters [a-z0-9-] text.
+ * @param string UTF-8 encoding
+ * @param string allowed characters
+ * @param bool
+ * @return string
+ */
+ public static function webalize($s, $charlist = NULL, $lower = TRUE)
+ {
+ $s = self::toAscii($s);
+ if ($lower) {
+ $s = strtolower($s);
+ }
+ $s = preg_replace('#[^a-z0-9' . preg_quote($charlist, '#') . ']+#i', '-', $s);
+ $s = trim($s, '-');
+ return $s;
+ }
+
+
+ /**
+ * Truncates string to maximal length.
+ * @param string UTF-8 encoding
+ * @param int
+ * @param string UTF-8 encoding
+ * @return string
+ */
+ public static function truncate($s, $maxLen, $append = "\xE2\x80\xA6")
+ {
+ if (self::length($s) > $maxLen) {
+ $maxLen = $maxLen - self::length($append);
+ if ($maxLen < 1) {
+ return $append;
+
+ } elseif ($matches = self::match($s, '#^.{1,'.$maxLen.'}(?=[\s\x00-/:-@\[-`{-~])#us')) {
+ return $matches[0] . $append;
+
+ } else {
+ return self::substring($s, 0, $maxLen) . $append;
+ }
+ }
+ return $s;
+ }
+
+
+ /**
+ * Indents the content from the left.
+ * @param string UTF-8 encoding or 8-bit
+ * @param int
+ * @param string
+ * @return string
+ */
+ public static function indent($s, $level = 1, $chars = "\t")
+ {
+ if ($level > 0) {
+ $s = self::replace($s, '#(?:^|[\r\n]+)(?=[^\r\n])#', '$0' . str_repeat($chars, $level));
+ }
+ return $s;
+ }
+
+
+ /**
+ * Convert to lower case.
+ * @param string UTF-8 encoding
+ * @return string
+ */
+ public static function lower($s)
+ {
+ return mb_strtolower($s, 'UTF-8');
+ }
+
+
+ /**
+ * Convert first character to lower case.
+ * @param string UTF-8 encoding
+ * @return string
+ */
+ public static function firstLower($s)
+ {
+ return self::lower(self::substring($s, 0, 1)) . self::substring($s, 1);
+ }
+
+
+ /**
+ * Convert to upper case.
+ * @param string UTF-8 encoding
+ * @return string
+ */
+ public static function upper($s)
+ {
+ return mb_strtoupper($s, 'UTF-8');
+ }
+
+
+ /**
+ * Convert first character to upper case.
+ * @param string UTF-8 encoding
+ * @return string
+ */
+ public static function firstUpper($s)
+ {
+ return self::upper(self::substring($s, 0, 1)) . self::substring($s, 1);
+ }
+
+
+ /**
+ * Capitalize string.
+ * @param string UTF-8 encoding
+ * @return string
+ */
+ public static function capitalize($s)
+ {
+ return mb_convert_case($s, MB_CASE_TITLE, 'UTF-8');
+ }
+
+
+ /**
+ * Case-insensitive compares UTF-8 strings.
+ * @param string
+ * @param string
+ * @param int
+ * @return bool
+ */
+ public static function compare($left, $right, $len = NULL)
+ {
+ if ($len < 0) {
+ $left = self::substring($left, $len, -$len);
+ $right = self::substring($right, $len, -$len);
+ } elseif ($len !== NULL) {
+ $left = self::substring($left, 0, $len);
+ $right = self::substring($right, 0, $len);
+ }
+ return self::lower($left) === self::lower($right);
+ }
+
+
+ /**
+ * Finds the length of common prefix of strings.
+ * @param string|array
+ * @return string
+ */
+ public static function findPrefix($strings)
+ {
+ if (!is_array($strings)) {
+ $strings = func_get_args();
+ }
+ $first = array_shift($strings);
+ for ($i = 0; $i < strlen($first); $i++) {
+ foreach ($strings as $s) {
+ if (!isset($s[$i]) || $first[$i] !== $s[$i]) {
+ while ($i && $first[$i - 1] >= "\x80" && $first[$i] >= "\x80" && $first[$i] < "\xC0") {
+ $i--;
+ }
+ return substr($first, 0, $i);
+ }
+ }
+ }
+ return $first;
+ }
+
+
+ /**
+ * Returns number of characters (not bytes) in UTF-8 string.
+ * That is the number of Unicode code points which may differ from the number of graphemes.
+ * @param string
+ * @return int
+ */
+ public static function length($s)
+ {
+ return function_exists('mb_strlen') ? mb_strlen($s, 'UTF-8') : strlen(utf8_decode($s));
+ }
+
+
+ /**
+ * Strips whitespace.
+ * @param string UTF-8 encoding
+ * @param string
+ * @return string
+ */
+ public static function trim($s, $charlist = self::TRIM_CHARACTERS)
+ {
+ $charlist = preg_quote($charlist, '#');
+ return self::replace($s, '#^['.$charlist.']+|['.$charlist.']+\z#u', '');
+ }
+
+
+ /**
+ * Pad a string to a certain length with another string.
+ * @param string UTF-8 encoding
+ * @param int
+ * @param string
+ * @return string
+ */
+ public static function padLeft($s, $length, $pad = ' ')
+ {
+ $length = max(0, $length - self::length($s));
+ $padLen = self::length($pad);
+ return str_repeat($pad, $length / $padLen) . self::substring($pad, 0, $length % $padLen) . $s;
+ }
+
+
+ /**
+ * Pad a string to a certain length with another string.
+ * @param string UTF-8 encoding
+ * @param int
+ * @param string
+ * @return string
+ */
+ public static function padRight($s, $length, $pad = ' ')
+ {
+ $length = max(0, $length - self::length($s));
+ $padLen = self::length($pad);
+ return $s . str_repeat($pad, $length / $padLen) . self::substring($pad, 0, $length % $padLen);
+ }
+
+
+ /**
+ * Reverse string.
+ * @param string UTF-8 encoding
+ * @return string
+ */
+ public static function reverse($s)
+ {
+ return @iconv('UTF-32LE', 'UTF-8', strrev(@iconv('UTF-8', 'UTF-32BE', $s)));
+ }
+
+
+ /**
+ * Use Nette\Utils\Random::generate
+ * @deprecated
+ */
+ public static function random($length = 10, $charlist = '0-9a-z')
+ {
+ return Random::generate($length, $charlist);
+ }
+
+
+ /**
+ * Returns part of $haystack before $nth occurence of $needle.
+ * @param string
+ * @param string
+ * @param int negative value means searching from the end
+ * @return string|FALSE returns FALSE if the needle was not found
+ */
+ public static function before($haystack, $needle, $nth = 1)
+ {
+ $pos = self::pos($haystack, $needle, $nth);
+ return $pos === FALSE
+ ? FALSE
+ : substr($haystack, 0, $pos);
+ }
+
+
+ /**
+ * Returns part of $haystack after $nth occurence of $needle.
+ * @param string
+ * @param string
+ * @param int negative value means searching from the end
+ * @return string|FALSE returns FALSE if the needle was not found
+ */
+ public static function after($haystack, $needle, $nth = 1)
+ {
+ $pos = self::pos($haystack, $needle, $nth);
+ return $pos === FALSE
+ ? FALSE
+ : (string) substr($haystack, $pos + strlen($needle));
+ }
+
+
+ /**
+ * Returns position of $nth occurence of $needle in $haystack.
+ * @return int|FALSE offset in bytes or FALSE if the needle was not found
+ */
+ private static function pos($haystack, $needle, $nth = 1)
+ {
+ if (!$nth) {
+ return FALSE;
+ } elseif ($nth > 0) {
+ if (strlen($needle) === 0) {
+ return 0;
+ }
+ $pos = 0;
+ while (FALSE !== ($pos = strpos($haystack, $needle, $pos)) && --$nth) {
+ $pos++;
+ }
+ } else {
+ $len = strlen($haystack);
+ if (strlen($needle) === 0) {
+ return $len;
+ }
+ $pos = $len - 1;
+ while (FALSE !== ($pos = strrpos($haystack, $needle, $pos - $len)) && ++$nth) {
+ $pos--;
+ }
+ }
+ return $pos;
+ }
+
+
+ /**
+ * Splits string by a regular expression.
+ * @param string
+ * @param string
+ * @param int
+ * @return array
+ */
+ public static function split($subject, $pattern, $flags = 0)
+ {
+ return self::pcre('preg_split', array($pattern, $subject, -1, $flags | PREG_SPLIT_DELIM_CAPTURE));
+ }
+
+
+ /**
+ * Performs a regular expression match.
+ * @param string
+ * @param string
+ * @param int can be PREG_OFFSET_CAPTURE (returned in bytes)
+ * @param int offset in bytes
+ * @return mixed
+ */
+ public static function match($subject, $pattern, $flags = 0, $offset = 0)
+ {
+ if ($offset > strlen($subject)) {
+ return NULL;
+ }
+ return self::pcre('preg_match', array($pattern, $subject, & $m, $flags, $offset))
+ ? $m
+ : NULL;
+ }
+
+
+ /**
+ * Performs a global regular expression match.
+ * @param string
+ * @param string
+ * @param int can be PREG_OFFSET_CAPTURE (returned in bytes); PREG_SET_ORDER is default
+ * @param int offset in bytes
+ * @return array
+ */
+ public static function matchAll($subject, $pattern, $flags = 0, $offset = 0)
+ {
+ if ($offset > strlen($subject)) {
+ return array();
+ }
+ self::pcre('preg_match_all', array(
+ $pattern, $subject, & $m,
+ ($flags & PREG_PATTERN_ORDER) ? $flags : ($flags | PREG_SET_ORDER),
+ $offset,
+ ));
+ return $m;
+ }
+
+
+ /**
+ * Perform a regular expression search and replace.
+ * @param string
+ * @param string|array
+ * @param string|callable
+ * @param int
+ * @return string
+ */
+ public static function replace($subject, $pattern, $replacement = NULL, $limit = -1)
+ {
+ if (is_object($replacement) || is_array($replacement)) {
+ if ($replacement instanceof Nette\Callback) {
+ $replacement = $replacement->getNative();
+ }
+ if (!is_callable($replacement, FALSE, $textual)) {
+ throw new Nette\InvalidStateException("Callback '$textual' is not callable.");
+ }
+
+ return self::pcre('preg_replace_callback', array($pattern, $replacement, $subject, $limit));
+
+ } elseif ($replacement === NULL && is_array($pattern)) {
+ $replacement = array_values($pattern);
+ $pattern = array_keys($pattern);
+ }
+
+ return self::pcre('preg_replace', array($pattern, $replacement, $subject, $limit));
+ }
+
+
+ /** @internal */
+ public static function pcre($func, $args)
+ {
+ static $messages = array(
+ PREG_INTERNAL_ERROR => 'Internal error',
+ PREG_BACKTRACK_LIMIT_ERROR => 'Backtrack limit was exhausted',
+ PREG_RECURSION_LIMIT_ERROR => 'Recursion limit was exhausted',
+ PREG_BAD_UTF8_ERROR => 'Malformed UTF-8 data',
+ 5 => 'Offset didn\'t correspond to the begin of a valid UTF-8 code point', // PREG_BAD_UTF8_OFFSET_ERROR
+ );
+ $res = Callback::invokeSafe($func, $args, function ($message) use ($args) {
+ // compile-time error, not detectable by preg_last_error
+ throw new RegexpException($message . ' in pattern: ' . implode(' or ', (array) $args[0]));
+ });
+
+ if (($code = preg_last_error()) // run-time error, but preg_last_error & return code are liars
+ && ($res === NULL || !in_array($func, array('preg_filter', 'preg_replace_callback', 'preg_replace')))
+ ) {
+ throw new RegexpException((isset($messages[$code]) ? $messages[$code] : 'Unknown error')
+ . ' (pattern: ' . implode(' or ', (array) $args[0]) . ')', $code);
+ }
+ return $res;
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/Validators.php b/vendor/nette/utils/src/Utils/Validators.php
new file mode 100755
index 0000000..8a84d7d
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/Validators.php
@@ -0,0 +1,295 @@
+ 'is_bool',
+ 'boolean' => 'is_bool',
+ 'int' => 'is_int',
+ 'integer' => 'is_int',
+ 'float' => 'is_float',
+ 'number' => NULL, // is_int || is_float,
+ 'numeric' => array(__CLASS__, 'isNumeric'),
+ 'numericint' => array(__CLASS__, 'isNumericInt'),
+ 'string' => 'is_string',
+ 'unicode' => array(__CLASS__, 'isUnicode'),
+ 'array' => 'is_array',
+ 'list' => array('Nette\Utils\Arrays', 'isList'),
+ 'object' => 'is_object',
+ 'resource' => 'is_resource',
+ 'scalar' => 'is_scalar',
+ 'callable' => array(__CLASS__, 'isCallable'),
+ 'null' => 'is_null',
+ 'email' => array(__CLASS__, 'isEmail'),
+ 'url' => array(__CLASS__, 'isUrl'),
+ 'uri' => array(__CLASS__, 'isUri'),
+ 'none' => array(__CLASS__, 'isNone'),
+ 'type' => array(__CLASS__, 'isType'),
+ 'identifier' => array(__CLASS__, 'isPhpIdentifier'),
+ 'pattern' => NULL,
+ 'alnum' => 'ctype_alnum',
+ 'alpha' => 'ctype_alpha',
+ 'digit' => 'ctype_digit',
+ 'lower' => 'ctype_lower',
+ 'upper' => 'ctype_upper',
+ 'space' => 'ctype_space',
+ 'xdigit' => 'ctype_xdigit',
+ );
+
+ protected static $counters = array(
+ 'string' => 'strlen',
+ 'unicode' => array('Nette\Utils\Strings', 'length'),
+ 'array' => 'count',
+ 'list' => 'count',
+ 'alnum' => 'strlen',
+ 'alpha' => 'strlen',
+ 'digit' => 'strlen',
+ 'lower' => 'strlen',
+ 'space' => 'strlen',
+ 'upper' => 'strlen',
+ 'xdigit' => 'strlen',
+ );
+
+
+ /**
+ * Throws exception if a variable is of unexpected type.
+ * @param mixed
+ * @param string expected types separated by pipe
+ * @param string label
+ * @return void
+ */
+ public static function assert($value, $expected, $label = 'variable')
+ {
+ if (!static::is($value, $expected)) {
+ $expected = str_replace(array('|', ':'), array(' or ', ' in range '), $expected);
+ if (is_array($value)) {
+ $type = 'array(' . count($value) . ')';
+ } elseif (is_object($value)) {
+ $type = 'object ' . get_class($value);
+ } elseif (is_string($value) && strlen($value) < 40) {
+ $type = "string '$value'";
+ } else {
+ $type = gettype($value);
+ }
+ throw new AssertionException("The $label expects to be $expected, $type given.");
+ }
+ }
+
+
+ /**
+ * Throws exception if an array field is missing or of unexpected type.
+ * @param array
+ * @param string item
+ * @param string expected types separated by pipe
+ * @param string
+ * @return void
+ */
+ public static function assertField($arr, $field, $expected = NULL, $label = "item '%' in array")
+ {
+ self::assert($arr, 'array', 'first argument');
+ if (!array_key_exists($field, $arr)) {
+ throw new AssertionException('Missing ' . str_replace('%', $field, $label) . '.');
+
+ } elseif ($expected) {
+ static::assert($arr[$field], $expected, str_replace('%', $field, $label));
+ }
+ }
+
+
+ /**
+ * Finds whether a variable is of expected type.
+ * @param mixed
+ * @param string expected types separated by pipe with optional ranges
+ * @return bool
+ */
+ public static function is($value, $expected)
+ {
+ foreach (explode('|', $expected) as $item) {
+ list($type) = $item = explode(':', $item, 2);
+ if (isset(static::$validators[$type])) {
+ if (!call_user_func(static::$validators[$type], $value)) {
+ continue;
+ }
+ } elseif ($type === 'number') {
+ if (!is_int($value) && !is_float($value)) {
+ continue;
+ }
+ } elseif ($type === 'pattern') {
+ if (preg_match('|^' . (isset($item[1]) ? $item[1] : '') . '\z|', $value)) {
+ return TRUE;
+ }
+ continue;
+ } elseif (!$value instanceof $type) {
+ continue;
+ }
+
+ if (isset($item[1])) {
+ if (isset(static::$counters[$type])) {
+ $value = call_user_func(static::$counters[$type], $value);
+ }
+ $range = explode('..', $item[1]);
+ if (!isset($range[1])) {
+ $range[1] = $range[0];
+ }
+ if (($range[0] !== '' && $value < $range[0]) || ($range[1] !== '' && $value > $range[1])) {
+ continue;
+ }
+ }
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+
+ /**
+ * Finds whether a value is an integer.
+ * @return bool
+ */
+ public static function isNumericInt($value)
+ {
+ return is_int($value) || is_string($value) && preg_match('#^-?[0-9]+\z#', $value);
+ }
+
+
+ /**
+ * Finds whether a string is a floating point number in decimal base.
+ * @return bool
+ */
+ public static function isNumeric($value)
+ {
+ return is_float($value) || is_int($value) || is_string($value) && preg_match('#^-?[0-9]*[.]?[0-9]+\z#', $value);
+ }
+
+
+ /**
+ * Finds whether a value is a syntactically correct callback.
+ * @return bool
+ */
+ public static function isCallable($value)
+ {
+ return $value && is_callable($value, TRUE);
+ }
+
+
+ /**
+ * Finds whether a value is an UTF-8 encoded string.
+ * @param string
+ * @return bool
+ */
+ public static function isUnicode($value)
+ {
+ return is_string($value) && preg_match('##u', $value);
+ }
+
+
+ /**
+ * Finds whether a value is "falsy".
+ * @return bool
+ */
+ public static function isNone($value)
+ {
+ return $value == NULL; // intentionally ==
+ }
+
+
+ /**
+ * Finds whether a variable is a zero-based integer indexed array.
+ * @param array
+ * @return bool
+ */
+ public static function isList($value)
+ {
+ return Arrays::isList($value);
+ }
+
+
+ /**
+ * Is a value in specified range?
+ * @param mixed
+ * @param array min and max value pair
+ * @return bool
+ */
+ public static function isInRange($value, $range)
+ {
+ return (!isset($range[0]) || $range[0] === '' || $value >= $range[0])
+ && (!isset($range[1]) || $range[1] === '' || $value <= $range[1]);
+ }
+
+
+ /**
+ * Finds whether a string is a valid email address.
+ * @param string
+ * @return bool
+ */
+ public static function isEmail($value)
+ {
+ $atom = "[-a-z0-9!#$%&'*+/=?^_`{|}~]"; // RFC 5322 unquoted characters in local-part
+ $localPart = "(?:\"(?:[ !\\x23-\\x5B\\x5D-\\x7E]*|\\\\[ -~])+\"|$atom+(?:\\.$atom+)*)"; // quoted or unquoted
+ $alpha = "a-z\x80-\xFF"; // superset of IDN
+ $domain = "[0-9$alpha](?:[-0-9$alpha]{0,61}[0-9$alpha])?"; // RFC 1034 one domain component
+ $topDomain = "[$alpha](?:[-0-9$alpha]{0,17}[$alpha])?";
+ return (bool) preg_match("(^$localPart@(?:$domain\\.)+$topDomain\\z)i", $value);
+ }
+
+
+ /**
+ * Finds whether a string is a valid http(s) URL.
+ * @param string
+ * @return bool
+ */
+ public static function isUrl($value)
+ {
+ $alpha = "a-z\x80-\xFF";
+ $subDomain = "[-_0-9$alpha]";
+ $domain = "[0-9$alpha](?:[-0-9$alpha]{0,61}[0-9$alpha])?";
+ $topDomain = "[$alpha](?:[-0-9$alpha]{0,17}[$alpha])?";
+ $domainName = "(?:(?:$subDomain+\\.)*?$domain\\.)?$topDomain";
+ return (bool) preg_match("(^https?://(?:$domainName|\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|\[[0-9a-f:]{3,39}\])(:\\d{1,5})?(/\\S*)?\\z)i", $value);
+ }
+
+
+ /**
+ * Finds whether a string is a valid URI according to RFC 1738.
+ * @param string
+ * @return bool
+ */
+ public static function isUri($value)
+ {
+ return (bool) preg_match('#^[a-z\d+\.-]+:\S+\z#i', $value);
+ }
+
+
+ /**
+ * Checks whether the input is a class, interface or trait.
+ * @param string
+ * @return bool
+ */
+ public static function isType($type)
+ {
+ return class_exists($type) || interface_exists($type) || (PHP_VERSION_ID >= 50400 && trait_exists($type));
+ }
+
+
+ /**
+ * Checks whether the input is a valid PHP identifier.
+ * @return bool
+ */
+ public static function isPhpIdentifier($value)
+ {
+ return is_string($value) && preg_match('#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z#', $value);
+ }
+
+}
diff --git a/vendor/nette/utils/src/Utils/exceptions.php b/vendor/nette/utils/src/Utils/exceptions.php
new file mode 100755
index 0000000..7ff86bd
--- /dev/null
+++ b/vendor/nette/utils/src/Utils/exceptions.php
@@ -0,0 +1,158 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config;
+
+use Symfony\Component\Config\Resource\ResourceInterface;
+use Symfony\Component\Filesystem\Exception\IOException;
+use Symfony\Component\Filesystem\Filesystem;
+
+/**
+ * ConfigCache manages PHP cache files.
+ *
+ * When debug is enabled, it knows when to flush the cache
+ * thanks to an array of ResourceInterface instances.
+ *
+ * @author Fabien Potencier
+ */
+class ConfigCache implements ConfigCacheInterface
+{
+ private $debug;
+ private $file;
+
+ /**
+ * @param string $file The absolute cache path
+ * @param bool $debug Whether debugging is enabled or not
+ */
+ public function __construct($file, $debug)
+ {
+ $this->file = $file;
+ $this->debug = (bool) $debug;
+ }
+
+ /**
+ * Gets the cache file path.
+ *
+ * @return string The cache file path
+ *
+ * @deprecated since 2.7, to be removed in 3.0. Use getPath() instead.
+ */
+ public function __toString()
+ {
+ @trigger_error('ConfigCache::__toString() is deprecated since version 2.7 and will be removed in 3.0. Use the getPath() method instead.', E_USER_DEPRECATED);
+
+ return $this->file;
+ }
+
+ /**
+ * Gets the cache file path.
+ *
+ * @return string The cache file path
+ */
+ public function getPath()
+ {
+ return $this->file;
+ }
+
+ /**
+ * Checks if the cache is still fresh.
+ *
+ * This method always returns true when debug is off and the
+ * cache file exists.
+ *
+ * @return bool true if the cache is fresh, false otherwise
+ */
+ public function isFresh()
+ {
+ if (!is_file($this->file)) {
+ return false;
+ }
+
+ if (!$this->debug) {
+ return true;
+ }
+
+ $metadata = $this->getMetaFile();
+ if (!is_file($metadata)) {
+ return false;
+ }
+
+ $time = filemtime($this->file);
+ $meta = unserialize(file_get_contents($metadata));
+ foreach ($meta as $resource) {
+ if (!$resource->isFresh($time)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Writes cache.
+ *
+ * @param string $content The content to write in the cache
+ * @param ResourceInterface[] $metadata An array of ResourceInterface instances
+ *
+ * @throws \RuntimeException When cache file can't be written
+ */
+ public function write($content, array $metadata = null)
+ {
+ $mode = 0666;
+ $umask = umask();
+ $filesystem = new Filesystem();
+ $filesystem->dumpFile($this->file, $content, null);
+ try {
+ $filesystem->chmod($this->file, $mode, $umask);
+ } catch (IOException $e) {
+ // discard chmod failure (some filesystem may not support it)
+ }
+
+ if (null !== $metadata && true === $this->debug) {
+ $filesystem->dumpFile($this->getMetaFile(), serialize($metadata), null);
+ try {
+ $filesystem->chmod($this->getMetaFile(), $mode, $umask);
+ } catch (IOException $e) {
+ // discard chmod failure (some filesystem may not support it)
+ }
+ }
+ }
+
+ /**
+ * Gets the meta file path.
+ *
+ * @return string The meta file path
+ */
+ private function getMetaFile()
+ {
+ return $this->file.'.meta';
+ }
+}
diff --git a/vendor/symfony/config/ConfigCacheFactory.php b/vendor/symfony/config/ConfigCacheFactory.php
new file mode 100755
index 0000000..5a8f456
--- /dev/null
+++ b/vendor/symfony/config/ConfigCacheFactory.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config;
+
+/**
+ * Basic implementation for ConfigCacheFactoryInterface
+ * that will simply create an instance of ConfigCache.
+ *
+ * @author Matthias Pigulla
+ */
+class ConfigCacheFactory implements ConfigCacheFactoryInterface
+{
+ /**
+ * @var bool Debug flag passed to the ConfigCache
+ */
+ private $debug;
+
+ /**
+ * @param bool $debug The debug flag to pass to ConfigCache
+ */
+ public function __construct($debug)
+ {
+ $this->debug = $debug;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function cache($file, $callback)
+ {
+ if (!is_callable($callback)) {
+ throw new \InvalidArgumentException(sprintf('Invalid type for callback argument. Expected callable, but got "%s".', gettype($callback)));
+ }
+
+ $cache = new ConfigCache($file, $this->debug);
+ if (!$cache->isFresh()) {
+ call_user_func($callback, $cache);
+ }
+
+ return $cache;
+ }
+}
diff --git a/vendor/symfony/config/ConfigCacheFactoryInterface.php b/vendor/symfony/config/ConfigCacheFactoryInterface.php
new file mode 100755
index 0000000..bd614c4
--- /dev/null
+++ b/vendor/symfony/config/ConfigCacheFactoryInterface.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config;
+
+/**
+ * Interface for a ConfigCache factory. This factory creates
+ * an instance of ConfigCacheInterface and initializes the
+ * cache if necessary.
+ *
+ * @author Matthias Pigulla
+ */
+interface ConfigCacheFactoryInterface
+{
+ /**
+ * Creates a cache instance and (re-)initializes it if necessary.
+ *
+ * @param string $file The absolute cache file path
+ * @param callable $callable The callable to be executed when the cache needs to be filled (i. e. is not fresh). The cache will be passed as the only parameter to this callback
+ *
+ * @return ConfigCacheInterface $configCache The cache instance
+ */
+ public function cache($file, $callable);
+}
diff --git a/vendor/symfony/config/ConfigCacheInterface.php b/vendor/symfony/config/ConfigCacheInterface.php
new file mode 100755
index 0000000..e367ad1
--- /dev/null
+++ b/vendor/symfony/config/ConfigCacheInterface.php
@@ -0,0 +1,49 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config;
+
+use Symfony\Component\Config\Resource\ResourceInterface;
+
+/**
+ * Interface for ConfigCache.
+ *
+ * @author Matthias Pigulla
+ */
+interface ConfigCacheInterface
+{
+ /**
+ * Gets the cache file path.
+ *
+ * @return string The cache file path
+ */
+ public function getPath();
+
+ /**
+ * Checks if the cache is still fresh.
+ *
+ * This check should take the metadata passed to the write() method into consideration.
+ *
+ * @return bool Whether the cache is still fresh.
+ */
+ public function isFresh();
+
+ /**
+ * Writes the given content into the cache file. Metadata will be stored
+ * independently and can be used to check cache freshness at a later time.
+ *
+ * @param string $content The content to write into the cache
+ * @param ResourceInterface[]|null $metadata An array of ResourceInterface instances
+ *
+ * @throws \RuntimeException When the cache file cannot be written
+ */
+ public function write($content, array $metadata = null);
+}
diff --git a/vendor/symfony/config/Definition/ArrayNode.php b/vendor/symfony/config/Definition/ArrayNode.php
new file mode 100755
index 0000000..05ae1fd
--- /dev/null
+++ b/vendor/symfony/config/Definition/ArrayNode.php
@@ -0,0 +1,393 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
+use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
+use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
+
+/**
+ * Represents an Array node in the config tree.
+ *
+ * @author Johannes M. Schmitt
+ */
+class ArrayNode extends BaseNode implements PrototypeNodeInterface
+{
+ protected $xmlRemappings = array();
+ protected $children = array();
+ protected $allowFalse = false;
+ protected $allowNewKeys = true;
+ protected $addIfNotSet = false;
+ protected $performDeepMerging = true;
+ protected $ignoreExtraKeys = false;
+ protected $normalizeKeys = true;
+
+ public function setNormalizeKeys($normalizeKeys)
+ {
+ $this->normalizeKeys = (bool) $normalizeKeys;
+ }
+
+ /**
+ * Normalizes keys between the different configuration formats.
+ *
+ * Namely, you mostly have foo_bar in YAML while you have foo-bar in XML.
+ * After running this method, all keys are normalized to foo_bar.
+ *
+ * If you have a mixed key like foo-bar_moo, it will not be altered.
+ * The key will also not be altered if the target key already exists.
+ *
+ * @param mixed $value
+ *
+ * @return array The value with normalized keys
+ */
+ protected function preNormalize($value)
+ {
+ if (!$this->normalizeKeys || !is_array($value)) {
+ return $value;
+ }
+
+ foreach ($value as $k => $v) {
+ if (false !== strpos($k, '-') && false === strpos($k, '_') && !array_key_exists($normalizedKey = str_replace('-', '_', $k), $value)) {
+ $value[$normalizedKey] = $v;
+ unset($value[$k]);
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * Retrieves the children of this node.
+ *
+ * @return array The children
+ */
+ public function getChildren()
+ {
+ return $this->children;
+ }
+
+ /**
+ * Sets the xml remappings that should be performed.
+ *
+ * @param array $remappings an array of the form array(array(string, string))
+ */
+ public function setXmlRemappings(array $remappings)
+ {
+ $this->xmlRemappings = $remappings;
+ }
+
+ /**
+ * Gets the xml remappings that should be performed.
+ *
+ * @return array $remappings an array of the form array(array(string, string))
+ */
+ public function getXmlRemappings()
+ {
+ return $this->xmlRemappings;
+ }
+
+ /**
+ * Sets whether to add default values for this array if it has not been
+ * defined in any of the configuration files.
+ *
+ * @param bool $boolean
+ */
+ public function setAddIfNotSet($boolean)
+ {
+ $this->addIfNotSet = (bool) $boolean;
+ }
+
+ /**
+ * Sets whether false is allowed as value indicating that the array should be unset.
+ *
+ * @param bool $allow
+ */
+ public function setAllowFalse($allow)
+ {
+ $this->allowFalse = (bool) $allow;
+ }
+
+ /**
+ * Sets whether new keys can be defined in subsequent configurations.
+ *
+ * @param bool $allow
+ */
+ public function setAllowNewKeys($allow)
+ {
+ $this->allowNewKeys = (bool) $allow;
+ }
+
+ /**
+ * Sets if deep merging should occur.
+ *
+ * @param bool $boolean
+ */
+ public function setPerformDeepMerging($boolean)
+ {
+ $this->performDeepMerging = (bool) $boolean;
+ }
+
+ /**
+ * Whether extra keys should just be ignore without an exception.
+ *
+ * @param bool $boolean To allow extra keys
+ */
+ public function setIgnoreExtraKeys($boolean)
+ {
+ $this->ignoreExtraKeys = (bool) $boolean;
+ }
+
+ /**
+ * Sets the node Name.
+ *
+ * @param string $name The node's name
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * Checks if the node has a default value.
+ *
+ * @return bool
+ */
+ public function hasDefaultValue()
+ {
+ return $this->addIfNotSet;
+ }
+
+ /**
+ * Retrieves the default value.
+ *
+ * @return array The default value
+ *
+ * @throws \RuntimeException if the node has no default value
+ */
+ public function getDefaultValue()
+ {
+ if (!$this->hasDefaultValue()) {
+ throw new \RuntimeException(sprintf('The node at path "%s" has no default value.', $this->getPath()));
+ }
+
+ $defaults = array();
+ foreach ($this->children as $name => $child) {
+ if ($child->hasDefaultValue()) {
+ $defaults[$name] = $child->getDefaultValue();
+ }
+ }
+
+ return $defaults;
+ }
+
+ /**
+ * Adds a child node.
+ *
+ * @param NodeInterface $node The child node to add
+ *
+ * @throws \InvalidArgumentException when the child node has no name
+ * @throws \InvalidArgumentException when the child node's name is not unique
+ */
+ public function addChild(NodeInterface $node)
+ {
+ $name = $node->getName();
+ if (!strlen($name)) {
+ throw new \InvalidArgumentException('Child nodes must be named.');
+ }
+ if (isset($this->children[$name])) {
+ throw new \InvalidArgumentException(sprintf('A child node named "%s" already exists.', $name));
+ }
+
+ $this->children[$name] = $node;
+ }
+
+ /**
+ * Finalizes the value of this node.
+ *
+ * @param mixed $value
+ *
+ * @return mixed The finalised value
+ *
+ * @throws UnsetKeyException
+ * @throws InvalidConfigurationException if the node doesn't have enough children
+ */
+ protected function finalizeValue($value)
+ {
+ if (false === $value) {
+ $msg = sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value));
+ throw new UnsetKeyException($msg);
+ }
+
+ foreach ($this->children as $name => $child) {
+ if (!array_key_exists($name, $value)) {
+ if ($child->isRequired()) {
+ $msg = sprintf('The child node "%s" at path "%s" must be configured.', $name, $this->getPath());
+ $ex = new InvalidConfigurationException($msg);
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ }
+
+ if ($child->hasDefaultValue()) {
+ $value[$name] = $child->getDefaultValue();
+ }
+
+ continue;
+ }
+
+ try {
+ $value[$name] = $child->finalize($value[$name]);
+ } catch (UnsetKeyException $e) {
+ unset($value[$name]);
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * Validates the type of the value.
+ *
+ * @param mixed $value
+ *
+ * @throws InvalidTypeException
+ */
+ protected function validateType($value)
+ {
+ if (!is_array($value) && (!$this->allowFalse || false !== $value)) {
+ $ex = new InvalidTypeException(sprintf(
+ 'Invalid type for path "%s". Expected array, but got %s',
+ $this->getPath(),
+ gettype($value)
+ ));
+ if ($hint = $this->getInfo()) {
+ $ex->addHint($hint);
+ }
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ }
+ }
+
+ /**
+ * Normalizes the value.
+ *
+ * @param mixed $value The value to normalize
+ *
+ * @return mixed The normalized value
+ *
+ * @throws InvalidConfigurationException
+ */
+ protected function normalizeValue($value)
+ {
+ if (false === $value) {
+ return $value;
+ }
+
+ $value = $this->remapXml($value);
+
+ $normalized = array();
+ foreach ($value as $name => $val) {
+ if (isset($this->children[$name])) {
+ $normalized[$name] = $this->children[$name]->normalize($val);
+ unset($value[$name]);
+ }
+ }
+
+ // if extra fields are present, throw exception
+ if (count($value) && !$this->ignoreExtraKeys) {
+ $msg = sprintf('Unrecognized option%s "%s" under "%s"', 1 === count($value) ? '' : 's', implode(', ', array_keys($value)), $this->getPath());
+ $ex = new InvalidConfigurationException($msg);
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ }
+
+ return $normalized;
+ }
+
+ /**
+ * Remaps multiple singular values to a single plural value.
+ *
+ * @param array $value The source values
+ *
+ * @return array The remapped values
+ */
+ protected function remapXml($value)
+ {
+ foreach ($this->xmlRemappings as $transformation) {
+ list($singular, $plural) = $transformation;
+
+ if (!isset($value[$singular])) {
+ continue;
+ }
+
+ $value[$plural] = Processor::normalizeConfig($value, $singular, $plural);
+ unset($value[$singular]);
+ }
+
+ return $value;
+ }
+
+ /**
+ * Merges values together.
+ *
+ * @param mixed $leftSide The left side to merge.
+ * @param mixed $rightSide The right side to merge.
+ *
+ * @return mixed The merged values
+ *
+ * @throws InvalidConfigurationException
+ * @throws \RuntimeException
+ */
+ protected function mergeValues($leftSide, $rightSide)
+ {
+ if (false === $rightSide) {
+ // if this is still false after the last config has been merged the
+ // finalization pass will take care of removing this key entirely
+ return false;
+ }
+
+ if (false === $leftSide || !$this->performDeepMerging) {
+ return $rightSide;
+ }
+
+ foreach ($rightSide as $k => $v) {
+ // no conflict
+ if (!array_key_exists($k, $leftSide)) {
+ if (!$this->allowNewKeys) {
+ $ex = new InvalidConfigurationException(sprintf(
+ 'You are not allowed to define new elements for path "%s". '
+ .'Please define all elements for this path in one config file. '
+ .'If you are trying to overwrite an element, make sure you redefine it '
+ .'with the same name.',
+ $this->getPath()
+ ));
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ }
+
+ $leftSide[$k] = $v;
+ continue;
+ }
+
+ if (!isset($this->children[$k])) {
+ throw new \RuntimeException('merge() expects a normalized config array.');
+ }
+
+ $leftSide[$k] = $this->children[$k]->merge($leftSide[$k], $v);
+ }
+
+ return $leftSide;
+ }
+}
diff --git a/vendor/symfony/config/Definition/BaseNode.php b/vendor/symfony/config/Definition/BaseNode.php
new file mode 100755
index 0000000..fc3e012
--- /dev/null
+++ b/vendor/symfony/config/Definition/BaseNode.php
@@ -0,0 +1,356 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+use Symfony\Component\Config\Definition\Exception\Exception;
+use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException;
+use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
+use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
+
+/**
+ * The base node class.
+ *
+ * @author Johannes M. Schmitt
+ */
+abstract class BaseNode implements NodeInterface
+{
+ protected $name;
+ protected $parent;
+ protected $normalizationClosures = array();
+ protected $finalValidationClosures = array();
+ protected $allowOverwrite = true;
+ protected $required = false;
+ protected $equivalentValues = array();
+ protected $attributes = array();
+
+ /**
+ * Constructor.
+ *
+ * @param string $name The name of the node
+ * @param NodeInterface $parent The parent of this node
+ *
+ * @throws \InvalidArgumentException if the name contains a period.
+ */
+ public function __construct($name, NodeInterface $parent = null)
+ {
+ if (false !== strpos($name, '.')) {
+ throw new \InvalidArgumentException('The name must not contain ".".');
+ }
+
+ $this->name = $name;
+ $this->parent = $parent;
+ }
+
+ public function setAttribute($key, $value)
+ {
+ $this->attributes[$key] = $value;
+ }
+
+ public function getAttribute($key, $default = null)
+ {
+ return isset($this->attributes[$key]) ? $this->attributes[$key] : $default;
+ }
+
+ public function hasAttribute($key)
+ {
+ return isset($this->attributes[$key]);
+ }
+
+ public function getAttributes()
+ {
+ return $this->attributes;
+ }
+
+ public function setAttributes(array $attributes)
+ {
+ $this->attributes = $attributes;
+ }
+
+ public function removeAttribute($key)
+ {
+ unset($this->attributes[$key]);
+ }
+
+ /**
+ * Sets an info message.
+ *
+ * @param string $info
+ */
+ public function setInfo($info)
+ {
+ $this->setAttribute('info', $info);
+ }
+
+ /**
+ * Returns info message.
+ *
+ * @return string The info text
+ */
+ public function getInfo()
+ {
+ return $this->getAttribute('info');
+ }
+
+ /**
+ * Sets the example configuration for this node.
+ *
+ * @param string|array $example
+ */
+ public function setExample($example)
+ {
+ $this->setAttribute('example', $example);
+ }
+
+ /**
+ * Retrieves the example configuration for this node.
+ *
+ * @return string|array The example
+ */
+ public function getExample()
+ {
+ return $this->getAttribute('example');
+ }
+
+ /**
+ * Adds an equivalent value.
+ *
+ * @param mixed $originalValue
+ * @param mixed $equivalentValue
+ */
+ public function addEquivalentValue($originalValue, $equivalentValue)
+ {
+ $this->equivalentValues[] = array($originalValue, $equivalentValue);
+ }
+
+ /**
+ * Set this node as required.
+ *
+ * @param bool $boolean Required node
+ */
+ public function setRequired($boolean)
+ {
+ $this->required = (bool) $boolean;
+ }
+
+ /**
+ * Sets if this node can be overridden.
+ *
+ * @param bool $allow
+ */
+ public function setAllowOverwrite($allow)
+ {
+ $this->allowOverwrite = (bool) $allow;
+ }
+
+ /**
+ * Sets the closures used for normalization.
+ *
+ * @param \Closure[] $closures An array of Closures used for normalization
+ */
+ public function setNormalizationClosures(array $closures)
+ {
+ $this->normalizationClosures = $closures;
+ }
+
+ /**
+ * Sets the closures used for final validation.
+ *
+ * @param \Closure[] $closures An array of Closures used for final validation
+ */
+ public function setFinalValidationClosures(array $closures)
+ {
+ $this->finalValidationClosures = $closures;
+ }
+
+ /**
+ * Checks if this node is required.
+ *
+ * @return bool
+ */
+ public function isRequired()
+ {
+ return $this->required;
+ }
+
+ /**
+ * Returns the name of this node.
+ *
+ * @return string The Node's name.
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Retrieves the path of this node.
+ *
+ * @return string The Node's path
+ */
+ public function getPath()
+ {
+ $path = $this->name;
+
+ if (null !== $this->parent) {
+ $path = $this->parent->getPath().'.'.$path;
+ }
+
+ return $path;
+ }
+
+ /**
+ * Merges two values together.
+ *
+ * @param mixed $leftSide
+ * @param mixed $rightSide
+ *
+ * @return mixed The merged value
+ *
+ * @throws ForbiddenOverwriteException
+ */
+ final public function merge($leftSide, $rightSide)
+ {
+ if (!$this->allowOverwrite) {
+ throw new ForbiddenOverwriteException(sprintf(
+ 'Configuration path "%s" cannot be overwritten. You have to '
+ .'define all options for this path, and any of its sub-paths in '
+ .'one configuration section.',
+ $this->getPath()
+ ));
+ }
+
+ $this->validateType($leftSide);
+ $this->validateType($rightSide);
+
+ return $this->mergeValues($leftSide, $rightSide);
+ }
+
+ /**
+ * Normalizes a value, applying all normalization closures.
+ *
+ * @param mixed $value Value to normalize.
+ *
+ * @return mixed The normalized value.
+ */
+ final public function normalize($value)
+ {
+ $value = $this->preNormalize($value);
+
+ // run custom normalization closures
+ foreach ($this->normalizationClosures as $closure) {
+ $value = $closure($value);
+ }
+
+ // replace value with their equivalent
+ foreach ($this->equivalentValues as $data) {
+ if ($data[0] === $value) {
+ $value = $data[1];
+ }
+ }
+
+ // validate type
+ $this->validateType($value);
+
+ // normalize value
+ return $this->normalizeValue($value);
+ }
+
+ /**
+ * Normalizes the value before any other normalization is applied.
+ *
+ * @param $value
+ *
+ * @return $value The normalized array value
+ */
+ protected function preNormalize($value)
+ {
+ return $value;
+ }
+
+ /**
+ * Returns parent node for this node.
+ *
+ * @return NodeInterface|null
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+
+ /**
+ * Finalizes a value, applying all finalization closures.
+ *
+ * @param mixed $value The value to finalize
+ *
+ * @return mixed The finalized value
+ *
+ * @throws Exception
+ * @throws InvalidConfigurationException
+ */
+ final public function finalize($value)
+ {
+ $this->validateType($value);
+
+ $value = $this->finalizeValue($value);
+
+ // Perform validation on the final value if a closure has been set.
+ // The closure is also allowed to return another value.
+ foreach ($this->finalValidationClosures as $closure) {
+ try {
+ $value = $closure($value);
+ } catch (Exception $e) {
+ throw $e;
+ } catch (\Exception $e) {
+ throw new InvalidConfigurationException(sprintf('Invalid configuration for path "%s": %s', $this->getPath(), $e->getMessage()), $e->getCode(), $e);
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * Validates the type of a Node.
+ *
+ * @param mixed $value The value to validate
+ *
+ * @throws InvalidTypeException when the value is invalid
+ */
+ abstract protected function validateType($value);
+
+ /**
+ * Normalizes the value.
+ *
+ * @param mixed $value The value to normalize.
+ *
+ * @return mixed The normalized value
+ */
+ abstract protected function normalizeValue($value);
+
+ /**
+ * Merges two values together.
+ *
+ * @param mixed $leftSide
+ * @param mixed $rightSide
+ *
+ * @return mixed The merged value
+ */
+ abstract protected function mergeValues($leftSide, $rightSide);
+
+ /**
+ * Finalizes a value.
+ *
+ * @param mixed $value The value to finalize
+ *
+ * @return mixed The finalized value
+ */
+ abstract protected function finalizeValue($value);
+}
diff --git a/vendor/symfony/config/Definition/BooleanNode.php b/vendor/symfony/config/Definition/BooleanNode.php
new file mode 100755
index 0000000..08e1a77
--- /dev/null
+++ b/vendor/symfony/config/Definition/BooleanNode.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
+
+/**
+ * This node represents a Boolean value in the config tree.
+ *
+ * @author Johannes M. Schmitt
+ */
+class BooleanNode extends ScalarNode
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function validateType($value)
+ {
+ if (!is_bool($value)) {
+ $ex = new InvalidTypeException(sprintf(
+ 'Invalid type for path "%s". Expected boolean, but got %s.',
+ $this->getPath(),
+ gettype($value)
+ ));
+ if ($hint = $this->getInfo()) {
+ $ex->addHint($hint);
+ }
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function isValueEmpty($value)
+ {
+ // a boolean value cannot be empty
+ return false;
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php b/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php
new file mode 100755
index 0000000..c64b2ec
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php
@@ -0,0 +1,489 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+use Symfony\Component\Config\Definition\ArrayNode;
+use Symfony\Component\Config\Definition\PrototypedArrayNode;
+use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
+
+/**
+ * This class provides a fluent interface for defining an array node.
+ *
+ * @author Johannes M. Schmitt
+ */
+class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinitionInterface
+{
+ protected $performDeepMerging = true;
+ protected $ignoreExtraKeys = false;
+ protected $children = array();
+ protected $prototype;
+ protected $atLeastOne = false;
+ protected $allowNewKeys = true;
+ protected $key;
+ protected $removeKeyItem;
+ protected $addDefaults = false;
+ protected $addDefaultChildren = false;
+ protected $nodeBuilder;
+ protected $normalizeKeys = true;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct($name, NodeParentInterface $parent = null)
+ {
+ parent::__construct($name, $parent);
+
+ $this->nullEquivalent = array();
+ $this->trueEquivalent = array();
+ }
+
+ /**
+ * Sets a custom children builder.
+ *
+ * @param NodeBuilder $builder A custom NodeBuilder
+ */
+ public function setBuilder(NodeBuilder $builder)
+ {
+ $this->nodeBuilder = $builder;
+ }
+
+ /**
+ * Returns a builder to add children nodes.
+ *
+ * @return NodeBuilder
+ */
+ public function children()
+ {
+ return $this->getNodeBuilder();
+ }
+
+ /**
+ * Sets a prototype for child nodes.
+ *
+ * @param string $type the type of node
+ *
+ * @return NodeDefinition
+ */
+ public function prototype($type)
+ {
+ return $this->prototype = $this->getNodeBuilder()->node(null, $type)->setParent($this);
+ }
+
+ /**
+ * Adds the default value if the node is not set in the configuration.
+ *
+ * This method is applicable to concrete nodes only (not to prototype nodes).
+ * If this function has been called and the node is not set during the finalization
+ * phase, it's default value will be derived from its children default values.
+ *
+ * @return ArrayNodeDefinition
+ */
+ public function addDefaultsIfNotSet()
+ {
+ $this->addDefaults = true;
+
+ return $this;
+ }
+
+ /**
+ * Adds children with a default value when none are defined.
+ *
+ * @param int|string|array|null $children The number of children|The child name|The children names to be added
+ *
+ * This method is applicable to prototype nodes only.
+ *
+ * @return ArrayNodeDefinition
+ */
+ public function addDefaultChildrenIfNoneSet($children = null)
+ {
+ $this->addDefaultChildren = $children;
+
+ return $this;
+ }
+
+ /**
+ * Requires the node to have at least one element.
+ *
+ * This method is applicable to prototype nodes only.
+ *
+ * @return ArrayNodeDefinition
+ */
+ public function requiresAtLeastOneElement()
+ {
+ $this->atLeastOne = true;
+
+ return $this;
+ }
+
+ /**
+ * Disallows adding news keys in a subsequent configuration.
+ *
+ * If used all keys have to be defined in the same configuration file.
+ *
+ * @return ArrayNodeDefinition
+ */
+ public function disallowNewKeysInSubsequentConfigs()
+ {
+ $this->allowNewKeys = false;
+
+ return $this;
+ }
+
+ /**
+ * Sets a normalization rule for XML configurations.
+ *
+ * @param string $singular The key to remap
+ * @param string $plural The plural of the key for irregular plurals
+ *
+ * @return ArrayNodeDefinition
+ */
+ public function fixXmlConfig($singular, $plural = null)
+ {
+ $this->normalization()->remap($singular, $plural);
+
+ return $this;
+ }
+
+ /**
+ * Sets the attribute which value is to be used as key.
+ *
+ * This is useful when you have an indexed array that should be an
+ * associative array. You can select an item from within the array
+ * to be the key of the particular item. For example, if "id" is the
+ * "key", then:
+ *
+ * array(
+ * array('id' => 'my_name', 'foo' => 'bar'),
+ * );
+ *
+ * becomes
+ *
+ * array(
+ * 'my_name' => array('foo' => 'bar'),
+ * );
+ *
+ * If you'd like "'id' => 'my_name'" to still be present in the resulting
+ * array, then you can set the second argument of this method to false.
+ *
+ * This method is applicable to prototype nodes only.
+ *
+ * @param string $name The name of the key
+ * @param bool $removeKeyItem Whether or not the key item should be removed.
+ *
+ * @return ArrayNodeDefinition
+ */
+ public function useAttributeAsKey($name, $removeKeyItem = true)
+ {
+ $this->key = $name;
+ $this->removeKeyItem = $removeKeyItem;
+
+ return $this;
+ }
+
+ /**
+ * Sets whether the node can be unset.
+ *
+ * @param bool $allow
+ *
+ * @return ArrayNodeDefinition
+ */
+ public function canBeUnset($allow = true)
+ {
+ $this->merge()->allowUnset($allow);
+
+ return $this;
+ }
+
+ /**
+ * Adds an "enabled" boolean to enable the current section.
+ *
+ * By default, the section is disabled. If any configuration is specified then
+ * the node will be automatically enabled:
+ *
+ * enableableArrayNode: {enabled: true, ...} # The config is enabled & default values get overridden
+ * enableableArrayNode: ~ # The config is enabled & use the default values
+ * enableableArrayNode: true # The config is enabled & use the default values
+ * enableableArrayNode: {other: value, ...} # The config is enabled & default values get overridden
+ * enableableArrayNode: {enabled: false, ...} # The config is disabled
+ * enableableArrayNode: false # The config is disabled
+ *
+ * @return ArrayNodeDefinition
+ */
+ public function canBeEnabled()
+ {
+ $this
+ ->addDefaultsIfNotSet()
+ ->treatFalseLike(array('enabled' => false))
+ ->treatTrueLike(array('enabled' => true))
+ ->treatNullLike(array('enabled' => true))
+ ->beforeNormalization()
+ ->ifArray()
+ ->then(function ($v) {
+ $v['enabled'] = isset($v['enabled']) ? $v['enabled'] : true;
+
+ return $v;
+ })
+ ->end()
+ ->children()
+ ->booleanNode('enabled')
+ ->defaultFalse()
+ ;
+
+ return $this;
+ }
+
+ /**
+ * Adds an "enabled" boolean to enable the current section.
+ *
+ * By default, the section is enabled.
+ *
+ * @return ArrayNodeDefinition
+ */
+ public function canBeDisabled()
+ {
+ $this
+ ->addDefaultsIfNotSet()
+ ->treatFalseLike(array('enabled' => false))
+ ->treatTrueLike(array('enabled' => true))
+ ->treatNullLike(array('enabled' => true))
+ ->children()
+ ->booleanNode('enabled')
+ ->defaultTrue()
+ ;
+
+ return $this;
+ }
+
+ /**
+ * Disables the deep merging of the node.
+ *
+ * @return ArrayNodeDefinition
+ */
+ public function performNoDeepMerging()
+ {
+ $this->performDeepMerging = false;
+
+ return $this;
+ }
+
+ /**
+ * Allows extra config keys to be specified under an array without
+ * throwing an exception.
+ *
+ * Those config values are simply ignored and removed from the
+ * resulting array. This should be used only in special cases where
+ * you want to send an entire configuration array through a special
+ * tree that processes only part of the array.
+ *
+ * @return ArrayNodeDefinition
+ */
+ public function ignoreExtraKeys()
+ {
+ $this->ignoreExtraKeys = true;
+
+ return $this;
+ }
+
+ /**
+ * Sets key normalization.
+ *
+ * @param bool $bool Whether to enable key normalization
+ *
+ * @return ArrayNodeDefinition
+ */
+ public function normalizeKeys($bool)
+ {
+ $this->normalizeKeys = (bool) $bool;
+
+ return $this;
+ }
+
+ /**
+ * Appends a node definition.
+ *
+ * $node = new ArrayNodeDefinition()
+ * ->children()
+ * ->scalarNode('foo')->end()
+ * ->scalarNode('baz')->end()
+ * ->end()
+ * ->append($this->getBarNodeDefinition())
+ * ;
+ *
+ * @param NodeDefinition $node A NodeDefinition instance
+ *
+ * @return ArrayNodeDefinition This node
+ */
+ public function append(NodeDefinition $node)
+ {
+ $this->children[$node->name] = $node->setParent($this);
+
+ return $this;
+ }
+
+ /**
+ * Returns a node builder to be used to add children and prototype.
+ *
+ * @return NodeBuilder The node builder
+ */
+ protected function getNodeBuilder()
+ {
+ if (null === $this->nodeBuilder) {
+ $this->nodeBuilder = new NodeBuilder();
+ }
+
+ return $this->nodeBuilder->setParent($this);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createNode()
+ {
+ if (null === $this->prototype) {
+ $node = new ArrayNode($this->name, $this->parent);
+
+ $this->validateConcreteNode($node);
+
+ $node->setAddIfNotSet($this->addDefaults);
+
+ foreach ($this->children as $child) {
+ $child->parent = $node;
+ $node->addChild($child->getNode());
+ }
+ } else {
+ $node = new PrototypedArrayNode($this->name, $this->parent);
+
+ $this->validatePrototypeNode($node);
+
+ if (null !== $this->key) {
+ $node->setKeyAttribute($this->key, $this->removeKeyItem);
+ }
+
+ if (true === $this->atLeastOne) {
+ $node->setMinNumberOfElements(1);
+ }
+
+ if ($this->default) {
+ $node->setDefaultValue($this->defaultValue);
+ }
+
+ if (false !== $this->addDefaultChildren) {
+ $node->setAddChildrenIfNoneSet($this->addDefaultChildren);
+ if ($this->prototype instanceof static && null === $this->prototype->prototype) {
+ $this->prototype->addDefaultsIfNotSet();
+ }
+ }
+
+ $this->prototype->parent = $node;
+ $node->setPrototype($this->prototype->getNode());
+ }
+
+ $node->setAllowNewKeys($this->allowNewKeys);
+ $node->addEquivalentValue(null, $this->nullEquivalent);
+ $node->addEquivalentValue(true, $this->trueEquivalent);
+ $node->addEquivalentValue(false, $this->falseEquivalent);
+ $node->setPerformDeepMerging($this->performDeepMerging);
+ $node->setRequired($this->required);
+ $node->setIgnoreExtraKeys($this->ignoreExtraKeys);
+ $node->setNormalizeKeys($this->normalizeKeys);
+
+ if (null !== $this->normalization) {
+ $node->setNormalizationClosures($this->normalization->before);
+ $node->setXmlRemappings($this->normalization->remappings);
+ }
+
+ if (null !== $this->merge) {
+ $node->setAllowOverwrite($this->merge->allowOverwrite);
+ $node->setAllowFalse($this->merge->allowFalse);
+ }
+
+ if (null !== $this->validation) {
+ $node->setFinalValidationClosures($this->validation->rules);
+ }
+
+ return $node;
+ }
+
+ /**
+ * Validate the configuration of a concrete node.
+ *
+ * @param ArrayNode $node The related node
+ *
+ * @throws InvalidDefinitionException
+ */
+ protected function validateConcreteNode(ArrayNode $node)
+ {
+ $path = $node->getPath();
+
+ if (null !== $this->key) {
+ throw new InvalidDefinitionException(
+ sprintf('->useAttributeAsKey() is not applicable to concrete nodes at path "%s"', $path)
+ );
+ }
+
+ if (true === $this->atLeastOne) {
+ throw new InvalidDefinitionException(
+ sprintf('->requiresAtLeastOneElement() is not applicable to concrete nodes at path "%s"', $path)
+ );
+ }
+
+ if ($this->default) {
+ throw new InvalidDefinitionException(
+ sprintf('->defaultValue() is not applicable to concrete nodes at path "%s"', $path)
+ );
+ }
+
+ if (false !== $this->addDefaultChildren) {
+ throw new InvalidDefinitionException(
+ sprintf('->addDefaultChildrenIfNoneSet() is not applicable to concrete nodes at path "%s"', $path)
+ );
+ }
+ }
+
+ /**
+ * Validate the configuration of a prototype node.
+ *
+ * @param PrototypedArrayNode $node The related node
+ *
+ * @throws InvalidDefinitionException
+ */
+ protected function validatePrototypeNode(PrototypedArrayNode $node)
+ {
+ $path = $node->getPath();
+
+ if ($this->addDefaults) {
+ throw new InvalidDefinitionException(
+ sprintf('->addDefaultsIfNotSet() is not applicable to prototype nodes at path "%s"', $path)
+ );
+ }
+
+ if (false !== $this->addDefaultChildren) {
+ if ($this->default) {
+ throw new InvalidDefinitionException(
+ sprintf('A default value and default children might not be used together at path "%s"', $path)
+ );
+ }
+
+ if (null !== $this->key && (null === $this->addDefaultChildren || is_int($this->addDefaultChildren) && $this->addDefaultChildren > 0)) {
+ throw new InvalidDefinitionException(
+ sprintf('->addDefaultChildrenIfNoneSet() should set default children names as ->useAttributeAsKey() is used at path "%s"', $path)
+ );
+ }
+
+ if (null === $this->key && (is_string($this->addDefaultChildren) || is_array($this->addDefaultChildren))) {
+ throw new InvalidDefinitionException(
+ sprintf('->addDefaultChildrenIfNoneSet() might not set default children names as ->useAttributeAsKey() is not used at path "%s"', $path)
+ );
+ }
+ }
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php b/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php
new file mode 100755
index 0000000..db7ebc2
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php
@@ -0,0 +1,42 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+use Symfony\Component\Config\Definition\BooleanNode;
+
+/**
+ * This class provides a fluent interface for defining a node.
+ *
+ * @author Johannes M. Schmitt
+ */
+class BooleanNodeDefinition extends ScalarNodeDefinition
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct($name, NodeParentInterface $parent = null)
+ {
+ parent::__construct($name, $parent);
+
+ $this->nullEquivalent = true;
+ }
+
+ /**
+ * Instantiate a Node.
+ *
+ * @return BooleanNode The node
+ */
+ protected function instantiateNode()
+ {
+ return new BooleanNode($this->name, $this->parent);
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/EnumNodeDefinition.php b/vendor/symfony/config/Definition/Builder/EnumNodeDefinition.php
new file mode 100755
index 0000000..dc25fcb
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/EnumNodeDefinition.php
@@ -0,0 +1,58 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+use Symfony\Component\Config\Definition\EnumNode;
+
+/**
+ * Enum Node Definition.
+ *
+ * @author Johannes M. Schmitt
+ */
+class EnumNodeDefinition extends ScalarNodeDefinition
+{
+ private $values;
+
+ /**
+ * @param array $values
+ *
+ * @return EnumNodeDefinition|$this
+ */
+ public function values(array $values)
+ {
+ $values = array_unique($values);
+
+ if (count($values) <= 1) {
+ throw new \InvalidArgumentException('->values() must be called with at least two distinct values.');
+ }
+
+ $this->values = $values;
+
+ return $this;
+ }
+
+ /**
+ * Instantiate a Node.
+ *
+ * @return EnumNode The node
+ *
+ * @throws \RuntimeException
+ */
+ protected function instantiateNode()
+ {
+ if (null === $this->values) {
+ throw new \RuntimeException('You must call ->values() on enum nodes.');
+ }
+
+ return new EnumNode($this->name, $this->parent, $this->values);
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/ExprBuilder.php b/vendor/symfony/config/Definition/Builder/ExprBuilder.php
new file mode 100755
index 0000000..3d79b29
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/ExprBuilder.php
@@ -0,0 +1,238 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
+
+/**
+ * This class builds an if expression.
+ *
+ * @author Johannes M. Schmitt
+ * @author Christophe Coevoet
+ */
+class ExprBuilder
+{
+ protected $node;
+ public $ifPart;
+ public $thenPart;
+
+ /**
+ * Constructor.
+ *
+ * @param NodeDefinition $node The related node
+ */
+ public function __construct(NodeDefinition $node)
+ {
+ $this->node = $node;
+ }
+
+ /**
+ * Marks the expression as being always used.
+ *
+ * @param \Closure $then
+ *
+ * @return ExprBuilder
+ */
+ public function always(\Closure $then = null)
+ {
+ $this->ifPart = function ($v) { return true; };
+
+ if (null !== $then) {
+ $this->thenPart = $then;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Sets a closure to use as tests.
+ *
+ * The default one tests if the value is true.
+ *
+ * @param \Closure $closure
+ *
+ * @return ExprBuilder
+ */
+ public function ifTrue(\Closure $closure = null)
+ {
+ if (null === $closure) {
+ $closure = function ($v) { return true === $v; };
+ }
+
+ $this->ifPart = $closure;
+
+ return $this;
+ }
+
+ /**
+ * Tests if the value is a string.
+ *
+ * @return ExprBuilder
+ */
+ public function ifString()
+ {
+ $this->ifPart = function ($v) { return is_string($v); };
+
+ return $this;
+ }
+
+ /**
+ * Tests if the value is null.
+ *
+ * @return ExprBuilder
+ */
+ public function ifNull()
+ {
+ $this->ifPart = function ($v) { return null === $v; };
+
+ return $this;
+ }
+
+ /**
+ * Tests if the value is an array.
+ *
+ * @return ExprBuilder
+ */
+ public function ifArray()
+ {
+ $this->ifPart = function ($v) { return is_array($v); };
+
+ return $this;
+ }
+
+ /**
+ * Tests if the value is in an array.
+ *
+ * @param array $array
+ *
+ * @return ExprBuilder
+ */
+ public function ifInArray(array $array)
+ {
+ $this->ifPart = function ($v) use ($array) { return in_array($v, $array, true); };
+
+ return $this;
+ }
+
+ /**
+ * Tests if the value is not in an array.
+ *
+ * @param array $array
+ *
+ * @return ExprBuilder
+ */
+ public function ifNotInArray(array $array)
+ {
+ $this->ifPart = function ($v) use ($array) { return !in_array($v, $array, true); };
+
+ return $this;
+ }
+
+ /**
+ * Sets the closure to run if the test pass.
+ *
+ * @param \Closure $closure
+ *
+ * @return ExprBuilder
+ */
+ public function then(\Closure $closure)
+ {
+ $this->thenPart = $closure;
+
+ return $this;
+ }
+
+ /**
+ * Sets a closure returning an empty array.
+ *
+ * @return ExprBuilder
+ */
+ public function thenEmptyArray()
+ {
+ $this->thenPart = function ($v) { return array(); };
+
+ return $this;
+ }
+
+ /**
+ * Sets a closure marking the value as invalid at validation time.
+ *
+ * if you want to add the value of the node in your message just use a %s placeholder.
+ *
+ * @param string $message
+ *
+ * @return ExprBuilder
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function thenInvalid($message)
+ {
+ $this->thenPart = function ($v) use ($message) {throw new \InvalidArgumentException(sprintf($message, json_encode($v))); };
+
+ return $this;
+ }
+
+ /**
+ * Sets a closure unsetting this key of the array at validation time.
+ *
+ * @return ExprBuilder
+ *
+ * @throws UnsetKeyException
+ */
+ public function thenUnset()
+ {
+ $this->thenPart = function ($v) { throw new UnsetKeyException('Unsetting key'); };
+
+ return $this;
+ }
+
+ /**
+ * Returns the related node.
+ *
+ * @return NodeDefinition
+ *
+ * @throws \RuntimeException
+ */
+ public function end()
+ {
+ if (null === $this->ifPart) {
+ throw new \RuntimeException('You must specify an if part.');
+ }
+ if (null === $this->thenPart) {
+ throw new \RuntimeException('You must specify a then part.');
+ }
+
+ return $this->node;
+ }
+
+ /**
+ * Builds the expressions.
+ *
+ * @param ExprBuilder[] $expressions An array of ExprBuilder instances to build
+ *
+ * @return array
+ */
+ public static function buildExpressions(array $expressions)
+ {
+ foreach ($expressions as $k => $expr) {
+ if ($expr instanceof self) {
+ $if = $expr->ifPart;
+ $then = $expr->thenPart;
+ $expressions[$k] = function ($v) use ($if, $then) {
+ return $if($v) ? $then($v) : $v;
+ };
+ }
+ }
+
+ return $expressions;
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/FloatNodeDefinition.php b/vendor/symfony/config/Definition/Builder/FloatNodeDefinition.php
new file mode 100755
index 0000000..c0bed46
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/FloatNodeDefinition.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+use Symfony\Component\Config\Definition\FloatNode;
+
+/**
+ * This class provides a fluent interface for defining a float node.
+ *
+ * @author Jeanmonod David
+ */
+class FloatNodeDefinition extends NumericNodeDefinition
+{
+ /**
+ * Instantiates a Node.
+ *
+ * @return FloatNode The node
+ */
+ protected function instantiateNode()
+ {
+ return new FloatNode($this->name, $this->parent, $this->min, $this->max);
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/IntegerNodeDefinition.php b/vendor/symfony/config/Definition/Builder/IntegerNodeDefinition.php
new file mode 100755
index 0000000..f6c3c14
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/IntegerNodeDefinition.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+use Symfony\Component\Config\Definition\IntegerNode;
+
+/**
+ * This class provides a fluent interface for defining an integer node.
+ *
+ * @author Jeanmonod David
+ */
+class IntegerNodeDefinition extends NumericNodeDefinition
+{
+ /**
+ * Instantiates a Node.
+ *
+ * @return IntegerNode The node
+ */
+ protected function instantiateNode()
+ {
+ return new IntegerNode($this->name, $this->parent, $this->min, $this->max);
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/MergeBuilder.php b/vendor/symfony/config/Definition/Builder/MergeBuilder.php
new file mode 100755
index 0000000..f908a49
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/MergeBuilder.php
@@ -0,0 +1,72 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+/**
+ * This class builds merge conditions.
+ *
+ * @author Johannes M. Schmitt
+ */
+class MergeBuilder
+{
+ protected $node;
+ public $allowFalse = false;
+ public $allowOverwrite = true;
+
+ /**
+ * Constructor.
+ *
+ * @param NodeDefinition $node The related node
+ */
+ public function __construct(NodeDefinition $node)
+ {
+ $this->node = $node;
+ }
+
+ /**
+ * Sets whether the node can be unset.
+ *
+ * @param bool $allow
+ *
+ * @return MergeBuilder
+ */
+ public function allowUnset($allow = true)
+ {
+ $this->allowFalse = $allow;
+
+ return $this;
+ }
+
+ /**
+ * Sets whether the node can be overwritten.
+ *
+ * @param bool $deny Whether the overwriting is forbidden or not
+ *
+ * @return MergeBuilder
+ */
+ public function denyOverwrite($deny = true)
+ {
+ $this->allowOverwrite = !$deny;
+
+ return $this;
+ }
+
+ /**
+ * Returns the related node.
+ *
+ * @return NodeDefinition
+ */
+ public function end()
+ {
+ return $this->node;
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/NodeBuilder.php b/vendor/symfony/config/Definition/Builder/NodeBuilder.php
new file mode 100755
index 0000000..b2b6336
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/NodeBuilder.php
@@ -0,0 +1,245 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+/**
+ * This class provides a fluent interface for building a node.
+ *
+ * @author Johannes M. Schmitt
+ */
+class NodeBuilder implements NodeParentInterface
+{
+ protected $parent;
+ protected $nodeMapping;
+
+ /**
+ * Constructor.
+ */
+ public function __construct()
+ {
+ $this->nodeMapping = array(
+ 'variable' => __NAMESPACE__.'\\VariableNodeDefinition',
+ 'scalar' => __NAMESPACE__.'\\ScalarNodeDefinition',
+ 'boolean' => __NAMESPACE__.'\\BooleanNodeDefinition',
+ 'integer' => __NAMESPACE__.'\\IntegerNodeDefinition',
+ 'float' => __NAMESPACE__.'\\FloatNodeDefinition',
+ 'array' => __NAMESPACE__.'\\ArrayNodeDefinition',
+ 'enum' => __NAMESPACE__.'\\EnumNodeDefinition',
+ );
+ }
+
+ /**
+ * Set the parent node.
+ *
+ * @param ParentNodeDefinitionInterface $parent The parent node
+ *
+ * @return NodeBuilder This node builder
+ */
+ public function setParent(ParentNodeDefinitionInterface $parent = null)
+ {
+ $this->parent = $parent;
+
+ return $this;
+ }
+
+ /**
+ * Creates a child array node.
+ *
+ * @param string $name The name of the node
+ *
+ * @return ArrayNodeDefinition The child node
+ */
+ public function arrayNode($name)
+ {
+ return $this->node($name, 'array');
+ }
+
+ /**
+ * Creates a child scalar node.
+ *
+ * @param string $name the name of the node
+ *
+ * @return ScalarNodeDefinition The child node
+ */
+ public function scalarNode($name)
+ {
+ return $this->node($name, 'scalar');
+ }
+
+ /**
+ * Creates a child Boolean node.
+ *
+ * @param string $name The name of the node
+ *
+ * @return BooleanNodeDefinition The child node
+ */
+ public function booleanNode($name)
+ {
+ return $this->node($name, 'boolean');
+ }
+
+ /**
+ * Creates a child integer node.
+ *
+ * @param string $name the name of the node
+ *
+ * @return IntegerNodeDefinition The child node
+ */
+ public function integerNode($name)
+ {
+ return $this->node($name, 'integer');
+ }
+
+ /**
+ * Creates a child float node.
+ *
+ * @param string $name the name of the node
+ *
+ * @return FloatNodeDefinition The child node
+ */
+ public function floatNode($name)
+ {
+ return $this->node($name, 'float');
+ }
+
+ /**
+ * Creates a child EnumNode.
+ *
+ * @param string $name
+ *
+ * @return EnumNodeDefinition
+ */
+ public function enumNode($name)
+ {
+ return $this->node($name, 'enum');
+ }
+
+ /**
+ * Creates a child variable node.
+ *
+ * @param string $name The name of the node
+ *
+ * @return VariableNodeDefinition The builder of the child node
+ */
+ public function variableNode($name)
+ {
+ return $this->node($name, 'variable');
+ }
+
+ /**
+ * Returns the parent node.
+ *
+ * @return ParentNodeDefinitionInterface The parent node
+ */
+ public function end()
+ {
+ return $this->parent;
+ }
+
+ /**
+ * Creates a child node.
+ *
+ * @param string $name The name of the node
+ * @param string $type The type of the node
+ *
+ * @return NodeDefinition The child node
+ *
+ * @throws \RuntimeException When the node type is not registered
+ * @throws \RuntimeException When the node class is not found
+ */
+ public function node($name, $type)
+ {
+ $class = $this->getNodeClass($type);
+
+ $node = new $class($name);
+
+ $this->append($node);
+
+ return $node;
+ }
+
+ /**
+ * Appends a node definition.
+ *
+ * Usage:
+ *
+ * $node = new ArrayNodeDefinition('name')
+ * ->children()
+ * ->scalarNode('foo')->end()
+ * ->scalarNode('baz')->end()
+ * ->append($this->getBarNodeDefinition())
+ * ->end()
+ * ;
+ *
+ * @param NodeDefinition $node
+ *
+ * @return NodeBuilder This node builder
+ */
+ public function append(NodeDefinition $node)
+ {
+ if ($node instanceof ParentNodeDefinitionInterface) {
+ $builder = clone $this;
+ $builder->setParent(null);
+ $node->setBuilder($builder);
+ }
+
+ if (null !== $this->parent) {
+ $this->parent->append($node);
+ // Make this builder the node parent to allow for a fluid interface
+ $node->setParent($this);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Adds or overrides a node Type.
+ *
+ * @param string $type The name of the type
+ * @param string $class The fully qualified name the node definition class
+ *
+ * @return NodeBuilder This node builder
+ */
+ public function setNodeClass($type, $class)
+ {
+ $this->nodeMapping[strtolower($type)] = $class;
+
+ return $this;
+ }
+
+ /**
+ * Returns the class name of the node definition.
+ *
+ * @param string $type The node type
+ *
+ * @return string The node definition class name
+ *
+ * @throws \RuntimeException When the node type is not registered
+ * @throws \RuntimeException When the node class is not found
+ */
+ protected function getNodeClass($type)
+ {
+ $type = strtolower($type);
+
+ if (!isset($this->nodeMapping[$type])) {
+ throw new \RuntimeException(sprintf('The node type "%s" is not registered.', $type));
+ }
+
+ $class = $this->nodeMapping[$type];
+
+ if (!class_exists($class)) {
+ throw new \RuntimeException(sprintf('The node class "%s" does not exist.', $class));
+ }
+
+ return $class;
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/NodeDefinition.php b/vendor/symfony/config/Definition/Builder/NodeDefinition.php
new file mode 100755
index 0000000..f7f84bc
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/NodeDefinition.php
@@ -0,0 +1,343 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+use Symfony\Component\Config\Definition\NodeInterface;
+use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
+
+/**
+ * This class provides a fluent interface for defining a node.
+ *
+ * @author Johannes M. Schmitt
+ */
+abstract class NodeDefinition implements NodeParentInterface
+{
+ protected $name;
+ protected $normalization;
+ protected $validation;
+ protected $defaultValue;
+ protected $default = false;
+ protected $required = false;
+ protected $merge;
+ protected $allowEmptyValue = true;
+ protected $nullEquivalent;
+ protected $trueEquivalent = true;
+ protected $falseEquivalent = false;
+
+ /**
+ * @var NodeParentInterface|null
+ */
+ protected $parent;
+ protected $attributes = array();
+
+ /**
+ * Constructor.
+ *
+ * @param string $name The name of the node
+ * @param NodeParentInterface|null $parent The parent
+ */
+ public function __construct($name, NodeParentInterface $parent = null)
+ {
+ $this->parent = $parent;
+ $this->name = $name;
+ }
+
+ /**
+ * Sets the parent node.
+ *
+ * @param NodeParentInterface $parent The parent
+ *
+ * @return NodeDefinition|$this
+ */
+ public function setParent(NodeParentInterface $parent)
+ {
+ $this->parent = $parent;
+
+ return $this;
+ }
+
+ /**
+ * Sets info message.
+ *
+ * @param string $info The info text
+ *
+ * @return NodeDefinition|$this
+ */
+ public function info($info)
+ {
+ return $this->attribute('info', $info);
+ }
+
+ /**
+ * Sets example configuration.
+ *
+ * @param string|array $example
+ *
+ * @return NodeDefinition|$this
+ */
+ public function example($example)
+ {
+ return $this->attribute('example', $example);
+ }
+
+ /**
+ * Sets an attribute on the node.
+ *
+ * @param string $key
+ * @param mixed $value
+ *
+ * @return NodeDefinition|$this
+ */
+ public function attribute($key, $value)
+ {
+ $this->attributes[$key] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Returns the parent node.
+ *
+ * @return NodeParentInterface|null The builder of the parent node
+ */
+ public function end()
+ {
+ return $this->parent;
+ }
+
+ /**
+ * Creates the node.
+ *
+ * @param bool $forceRootNode Whether to force this node as the root node
+ *
+ * @return NodeInterface
+ */
+ public function getNode($forceRootNode = false)
+ {
+ if ($forceRootNode) {
+ $this->parent = null;
+ }
+
+ if (null !== $this->normalization) {
+ $this->normalization->before = ExprBuilder::buildExpressions($this->normalization->before);
+ }
+
+ if (null !== $this->validation) {
+ $this->validation->rules = ExprBuilder::buildExpressions($this->validation->rules);
+ }
+
+ $node = $this->createNode();
+ $node->setAttributes($this->attributes);
+
+ return $node;
+ }
+
+ /**
+ * Sets the default value.
+ *
+ * @param mixed $value The default value
+ *
+ * @return NodeDefinition|$this
+ */
+ public function defaultValue($value)
+ {
+ $this->default = true;
+ $this->defaultValue = $value;
+
+ return $this;
+ }
+
+ /**
+ * Sets the node as required.
+ *
+ * @return NodeDefinition|$this
+ */
+ public function isRequired()
+ {
+ $this->required = true;
+
+ return $this;
+ }
+
+ /**
+ * Sets the equivalent value used when the node contains null.
+ *
+ * @param mixed $value
+ *
+ * @return NodeDefinition|$this
+ */
+ public function treatNullLike($value)
+ {
+ $this->nullEquivalent = $value;
+
+ return $this;
+ }
+
+ /**
+ * Sets the equivalent value used when the node contains true.
+ *
+ * @param mixed $value
+ *
+ * @return NodeDefinition|$this
+ */
+ public function treatTrueLike($value)
+ {
+ $this->trueEquivalent = $value;
+
+ return $this;
+ }
+
+ /**
+ * Sets the equivalent value used when the node contains false.
+ *
+ * @param mixed $value
+ *
+ * @return NodeDefinition|$this
+ */
+ public function treatFalseLike($value)
+ {
+ $this->falseEquivalent = $value;
+
+ return $this;
+ }
+
+ /**
+ * Sets null as the default value.
+ *
+ * @return NodeDefinition|$this
+ */
+ public function defaultNull()
+ {
+ return $this->defaultValue(null);
+ }
+
+ /**
+ * Sets true as the default value.
+ *
+ * @return NodeDefinition|$this
+ */
+ public function defaultTrue()
+ {
+ return $this->defaultValue(true);
+ }
+
+ /**
+ * Sets false as the default value.
+ *
+ * @return NodeDefinition|$this
+ */
+ public function defaultFalse()
+ {
+ return $this->defaultValue(false);
+ }
+
+ /**
+ * Sets an expression to run before the normalization.
+ *
+ * @return ExprBuilder
+ */
+ public function beforeNormalization()
+ {
+ return $this->normalization()->before();
+ }
+
+ /**
+ * Denies the node value being empty.
+ *
+ * @return NodeDefinition|$this
+ */
+ public function cannotBeEmpty()
+ {
+ $this->allowEmptyValue = false;
+
+ return $this;
+ }
+
+ /**
+ * Sets an expression to run for the validation.
+ *
+ * The expression receives the value of the node and must return it. It can
+ * modify it.
+ * An exception should be thrown when the node is not valid.
+ *
+ * @return ExprBuilder
+ */
+ public function validate()
+ {
+ return $this->validation()->rule();
+ }
+
+ /**
+ * Sets whether the node can be overwritten.
+ *
+ * @param bool $deny Whether the overwriting is forbidden or not
+ *
+ * @return NodeDefinition|$this
+ */
+ public function cannotBeOverwritten($deny = true)
+ {
+ $this->merge()->denyOverwrite($deny);
+
+ return $this;
+ }
+
+ /**
+ * Gets the builder for validation rules.
+ *
+ * @return ValidationBuilder
+ */
+ protected function validation()
+ {
+ if (null === $this->validation) {
+ $this->validation = new ValidationBuilder($this);
+ }
+
+ return $this->validation;
+ }
+
+ /**
+ * Gets the builder for merging rules.
+ *
+ * @return MergeBuilder
+ */
+ protected function merge()
+ {
+ if (null === $this->merge) {
+ $this->merge = new MergeBuilder($this);
+ }
+
+ return $this->merge;
+ }
+
+ /**
+ * Gets the builder for normalization rules.
+ *
+ * @return NormalizationBuilder
+ */
+ protected function normalization()
+ {
+ if (null === $this->normalization) {
+ $this->normalization = new NormalizationBuilder($this);
+ }
+
+ return $this->normalization;
+ }
+
+ /**
+ * Instantiate and configure the node according to this definition.
+ *
+ * @return NodeInterface $node The node instance
+ *
+ * @throws InvalidDefinitionException When the definition is invalid
+ */
+ abstract protected function createNode();
+}
diff --git a/vendor/symfony/config/Definition/Builder/NodeParentInterface.php b/vendor/symfony/config/Definition/Builder/NodeParentInterface.php
new file mode 100755
index 0000000..305e993
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/NodeParentInterface.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+/**
+ * An interface that must be implemented by all node parents.
+ *
+ * @author Victor Berchet
+ */
+interface NodeParentInterface
+{
+}
diff --git a/vendor/symfony/config/Definition/Builder/NormalizationBuilder.php b/vendor/symfony/config/Definition/Builder/NormalizationBuilder.php
new file mode 100755
index 0000000..748c9f2
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/NormalizationBuilder.php
@@ -0,0 +1,67 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+/**
+ * This class builds normalization conditions.
+ *
+ * @author Johannes M. Schmitt
+ */
+class NormalizationBuilder
+{
+ protected $node;
+ public $before = array();
+ public $remappings = array();
+
+ /**
+ * Constructor.
+ *
+ * @param NodeDefinition $node The related node
+ */
+ public function __construct(NodeDefinition $node)
+ {
+ $this->node = $node;
+ }
+
+ /**
+ * Registers a key to remap to its plural form.
+ *
+ * @param string $key The key to remap
+ * @param string $plural The plural of the key in case of irregular plural
+ *
+ * @return NormalizationBuilder
+ */
+ public function remap($key, $plural = null)
+ {
+ $this->remappings[] = array($key, null === $plural ? $key.'s' : $plural);
+
+ return $this;
+ }
+
+ /**
+ * Registers a closure to run before the normalization or an expression builder to build it if null is provided.
+ *
+ * @param \Closure $closure
+ *
+ * @return ExprBuilder|NormalizationBuilder
+ */
+ public function before(\Closure $closure = null)
+ {
+ if (null !== $closure) {
+ $this->before[] = $closure;
+
+ return $this;
+ }
+
+ return $this->before[] = new ExprBuilder($this->node);
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/NumericNodeDefinition.php b/vendor/symfony/config/Definition/Builder/NumericNodeDefinition.php
new file mode 100755
index 0000000..ddd716d
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/NumericNodeDefinition.php
@@ -0,0 +1,61 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+/**
+ * Abstract class that contains common code of integer and float node definitions.
+ *
+ * @author David Jeanmonod
+ */
+abstract class NumericNodeDefinition extends ScalarNodeDefinition
+{
+ protected $min;
+ protected $max;
+
+ /**
+ * Ensures that the value is smaller than the given reference.
+ *
+ * @param mixed $max
+ *
+ * @return NumericNodeDefinition
+ *
+ * @throws \InvalidArgumentException when the constraint is inconsistent
+ */
+ public function max($max)
+ {
+ if (isset($this->min) && $this->min > $max) {
+ throw new \InvalidArgumentException(sprintf('You cannot define a max(%s) as you already have a min(%s)', $max, $this->min));
+ }
+ $this->max = $max;
+
+ return $this;
+ }
+
+ /**
+ * Ensures that the value is bigger than the given reference.
+ *
+ * @param mixed $min
+ *
+ * @return NumericNodeDefinition
+ *
+ * @throws \InvalidArgumentException when the constraint is inconsistent
+ */
+ public function min($min)
+ {
+ if (isset($this->max) && $this->max < $min) {
+ throw new \InvalidArgumentException(sprintf('You cannot define a min(%s) as you already have a max(%s)', $min, $this->max));
+ }
+ $this->min = $min;
+
+ return $this;
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/ParentNodeDefinitionInterface.php b/vendor/symfony/config/Definition/Builder/ParentNodeDefinitionInterface.php
new file mode 100755
index 0000000..575495b
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/ParentNodeDefinitionInterface.php
@@ -0,0 +1,26 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+/**
+ * An interface that must be implemented by nodes which can have children.
+ *
+ * @author Victor Berchet
+ */
+interface ParentNodeDefinitionInterface
+{
+ public function children();
+
+ public function append(NodeDefinition $node);
+
+ public function setBuilder(NodeBuilder $builder);
+}
diff --git a/vendor/symfony/config/Definition/Builder/ScalarNodeDefinition.php b/vendor/symfony/config/Definition/Builder/ScalarNodeDefinition.php
new file mode 100755
index 0000000..6170555
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/ScalarNodeDefinition.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+use Symfony\Component\Config\Definition\ScalarNode;
+
+/**
+ * This class provides a fluent interface for defining a node.
+ *
+ * @author Johannes M. Schmitt
+ */
+class ScalarNodeDefinition extends VariableNodeDefinition
+{
+ /**
+ * Instantiate a Node.
+ *
+ * @return ScalarNode The node
+ */
+ protected function instantiateNode()
+ {
+ return new ScalarNode($this->name, $this->parent);
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/TreeBuilder.php b/vendor/symfony/config/Definition/Builder/TreeBuilder.php
new file mode 100755
index 0000000..5d02848
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/TreeBuilder.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+use Symfony\Component\Config\Definition\NodeInterface;
+
+/**
+ * This is the entry class for building a config tree.
+ *
+ * @author Johannes M. Schmitt
+ */
+class TreeBuilder implements NodeParentInterface
+{
+ protected $tree;
+ protected $root;
+ protected $builder;
+
+ /**
+ * Creates the root node.
+ *
+ * @param string $name The name of the root node
+ * @param string $type The type of the root node
+ * @param NodeBuilder $builder A custom node builder instance
+ *
+ * @return ArrayNodeDefinition|NodeDefinition The root node (as an ArrayNodeDefinition when the type is 'array')
+ *
+ * @throws \RuntimeException When the node type is not supported
+ */
+ public function root($name, $type = 'array', NodeBuilder $builder = null)
+ {
+ $builder = $builder ?: new NodeBuilder();
+
+ return $this->root = $builder->node($name, $type)->setParent($this);
+ }
+
+ /**
+ * Builds the tree.
+ *
+ * @return NodeInterface
+ *
+ * @throws \RuntimeException
+ */
+ public function buildTree()
+ {
+ if (null === $this->root) {
+ throw new \RuntimeException('The configuration tree has no root node.');
+ }
+ if (null !== $this->tree) {
+ return $this->tree;
+ }
+
+ return $this->tree = $this->root->getNode(true);
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/ValidationBuilder.php b/vendor/symfony/config/Definition/Builder/ValidationBuilder.php
new file mode 100755
index 0000000..e885823
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/ValidationBuilder.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+/**
+ * This class builds validation conditions.
+ *
+ * @author Christophe Coevoet
+ */
+class ValidationBuilder
+{
+ protected $node;
+ public $rules = array();
+
+ /**
+ * Constructor.
+ *
+ * @param NodeDefinition $node The related node
+ */
+ public function __construct(NodeDefinition $node)
+ {
+ $this->node = $node;
+ }
+
+ /**
+ * Registers a closure to run as normalization or an expression builder to build it if null is provided.
+ *
+ * @param \Closure $closure
+ *
+ * @return ExprBuilder|ValidationBuilder
+ */
+ public function rule(\Closure $closure = null)
+ {
+ if (null !== $closure) {
+ $this->rules[] = $closure;
+
+ return $this;
+ }
+
+ return $this->rules[] = new ExprBuilder($this->node);
+ }
+}
diff --git a/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php b/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php
new file mode 100755
index 0000000..a46b7ea
--- /dev/null
+++ b/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php
@@ -0,0 +1,64 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Builder;
+
+use Symfony\Component\Config\Definition\VariableNode;
+
+/**
+ * This class provides a fluent interface for defining a node.
+ *
+ * @author Johannes M. Schmitt
+ */
+class VariableNodeDefinition extends NodeDefinition
+{
+ /**
+ * Instantiate a Node.
+ *
+ * @return VariableNode The node
+ */
+ protected function instantiateNode()
+ {
+ return new VariableNode($this->name, $this->parent);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function createNode()
+ {
+ $node = $this->instantiateNode();
+
+ if (null !== $this->normalization) {
+ $node->setNormalizationClosures($this->normalization->before);
+ }
+
+ if (null !== $this->merge) {
+ $node->setAllowOverwrite($this->merge->allowOverwrite);
+ }
+
+ if (true === $this->default) {
+ $node->setDefaultValue($this->defaultValue);
+ }
+
+ $node->setAllowEmptyValue($this->allowEmptyValue);
+ $node->addEquivalentValue(null, $this->nullEquivalent);
+ $node->addEquivalentValue(true, $this->trueEquivalent);
+ $node->addEquivalentValue(false, $this->falseEquivalent);
+ $node->setRequired($this->required);
+
+ if (null !== $this->validation) {
+ $node->setFinalValidationClosures($this->validation->rules);
+ }
+
+ return $node;
+ }
+}
diff --git a/vendor/symfony/config/Definition/ConfigurationInterface.php b/vendor/symfony/config/Definition/ConfigurationInterface.php
new file mode 100755
index 0000000..d6456ed
--- /dev/null
+++ b/vendor/symfony/config/Definition/ConfigurationInterface.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+/**
+ * Configuration interface.
+ *
+ * @author Victor Berchet
+ */
+interface ConfigurationInterface
+{
+ /**
+ * Generates the configuration tree builder.
+ *
+ * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
+ */
+ public function getConfigTreeBuilder();
+}
diff --git a/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php b/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php
new file mode 100755
index 0000000..c3b2fcd
--- /dev/null
+++ b/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php
@@ -0,0 +1,300 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Dumper;
+
+use Symfony\Component\Config\Definition\ConfigurationInterface;
+use Symfony\Component\Config\Definition\NodeInterface;
+use Symfony\Component\Config\Definition\ArrayNode;
+use Symfony\Component\Config\Definition\EnumNode;
+use Symfony\Component\Config\Definition\PrototypedArrayNode;
+
+/**
+ * Dumps a XML reference configuration for the given configuration/node instance.
+ *
+ * @author Wouter J
+ */
+class XmlReferenceDumper
+{
+ private $reference;
+
+ public function dump(ConfigurationInterface $configuration, $namespace = null)
+ {
+ return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree(), $namespace);
+ }
+
+ public function dumpNode(NodeInterface $node, $namespace = null)
+ {
+ $this->reference = '';
+ $this->writeNode($node, 0, true, $namespace);
+ $ref = $this->reference;
+ $this->reference = null;
+
+ return $ref;
+ }
+
+ /**
+ * @param NodeInterface $node
+ * @param int $depth
+ * @param bool $root If the node is the root node
+ * @param string $namespace The namespace of the node
+ */
+ private function writeNode(NodeInterface $node, $depth = 0, $root = false, $namespace = null)
+ {
+ $rootName = ($root ? 'config' : $node->getName());
+ $rootNamespace = ($namespace ?: ($root ? 'http://example.org/schema/dic/'.$node->getName() : null));
+
+ // xml remapping
+ if ($node->getParent()) {
+ $remapping = array_filter($node->getParent()->getXmlRemappings(), function ($mapping) use ($rootName) {
+ return $rootName === $mapping[1];
+ });
+
+ if (count($remapping)) {
+ list($singular) = current($remapping);
+ $rootName = $singular;
+ }
+ }
+ $rootName = str_replace('_', '-', $rootName);
+
+ $rootAttributes = array();
+ $rootAttributeComments = array();
+ $rootChildren = array();
+ $rootComments = array();
+
+ if ($node instanceof ArrayNode) {
+ $children = $node->getChildren();
+
+ // comments about the root node
+ if ($rootInfo = $node->getInfo()) {
+ $rootComments[] = $rootInfo;
+ }
+
+ if ($rootNamespace) {
+ $rootComments[] = 'Namespace: '.$rootNamespace;
+ }
+
+ // render prototyped nodes
+ if ($node instanceof PrototypedArrayNode) {
+ array_unshift($rootComments, 'prototype');
+
+ if ($key = $node->getKeyAttribute()) {
+ $rootAttributes[$key] = str_replace('-', ' ', $rootName).' '.$key;
+ }
+
+ $prototype = $node->getPrototype();
+
+ if ($prototype instanceof ArrayNode) {
+ $children = $prototype->getChildren();
+ } else {
+ if ($prototype->hasDefaultValue()) {
+ $prototypeValue = $prototype->getDefaultValue();
+ } else {
+ switch (get_class($prototype)) {
+ case 'Symfony\Component\Config\Definition\ScalarNode':
+ $prototypeValue = 'scalar value';
+ break;
+
+ case 'Symfony\Component\Config\Definition\FloatNode':
+ case 'Symfony\Component\Config\Definition\IntegerNode':
+ $prototypeValue = 'numeric value';
+ break;
+
+ case 'Symfony\Component\Config\Definition\BooleanNode':
+ $prototypeValue = 'true|false';
+ break;
+
+ case 'Symfony\Component\Config\Definition\EnumNode':
+ $prototypeValue = implode('|', array_map('json_encode', $prototype->getValues()));
+ break;
+
+ default:
+ $prototypeValue = 'value';
+ }
+ }
+ }
+ }
+
+ // get attributes and elements
+ foreach ($children as $child) {
+ if (!$child instanceof ArrayNode) {
+ // get attributes
+
+ // metadata
+ $name = str_replace('_', '-', $child->getName());
+ $value = '%%%%not_defined%%%%'; // use a string which isn't used in the normal world
+
+ // comments
+ $comments = array();
+ if ($info = $child->getInfo()) {
+ $comments[] = $info;
+ }
+
+ if ($example = $child->getExample()) {
+ $comments[] = 'Example: '.$example;
+ }
+
+ if ($child->isRequired()) {
+ $comments[] = 'Required';
+ }
+
+ if ($child instanceof EnumNode) {
+ $comments[] = 'One of '.implode('; ', array_map('json_encode', $child->getValues()));
+ }
+
+ if (count($comments)) {
+ $rootAttributeComments[$name] = implode(";\n", $comments);
+ }
+
+ // default values
+ if ($child->hasDefaultValue()) {
+ $value = $child->getDefaultValue();
+ }
+
+ // append attribute
+ $rootAttributes[$name] = $value;
+ } else {
+ // get elements
+ $rootChildren[] = $child;
+ }
+ }
+ }
+
+ // render comments
+
+ // root node comment
+ if (count($rootComments)) {
+ foreach ($rootComments as $comment) {
+ $this->writeLine('', $depth);
+ }
+ }
+
+ // attribute comments
+ if (count($rootAttributeComments)) {
+ foreach ($rootAttributeComments as $attrName => $comment) {
+ $commentDepth = $depth + 4 + strlen($attrName) + 2;
+ $commentLines = explode("\n", $comment);
+ $multiline = (count($commentLines) > 1);
+ $comment = implode(PHP_EOL.str_repeat(' ', $commentDepth), $commentLines);
+
+ if ($multiline) {
+ $this->writeLine('', $depth);
+ } else {
+ $this->writeLine('', $depth);
+ }
+ }
+ }
+
+ // render start tag + attributes
+ $rootIsVariablePrototype = isset($prototypeValue);
+ $rootIsEmptyTag = (0 === count($rootChildren) && !$rootIsVariablePrototype);
+ $rootOpenTag = '<'.$rootName;
+ if (1 >= ($attributesCount = count($rootAttributes))) {
+ if (1 === $attributesCount) {
+ $rootOpenTag .= sprintf(' %s="%s"', current(array_keys($rootAttributes)), $this->writeValue(current($rootAttributes)));
+ }
+
+ $rootOpenTag .= $rootIsEmptyTag ? ' />' : '>';
+
+ if ($rootIsVariablePrototype) {
+ $rootOpenTag .= $prototypeValue.''.$rootName.'>';
+ }
+
+ $this->writeLine($rootOpenTag, $depth);
+ } else {
+ $this->writeLine($rootOpenTag, $depth);
+
+ $i = 1;
+
+ foreach ($rootAttributes as $attrName => $attrValue) {
+ $attr = sprintf('%s="%s"', $attrName, $this->writeValue($attrValue));
+
+ $this->writeLine($attr, $depth + 4);
+
+ if ($attributesCount === $i++) {
+ $this->writeLine($rootIsEmptyTag ? '/>' : '>', $depth);
+
+ if ($rootIsVariablePrototype) {
+ $rootOpenTag .= $prototypeValue.''.$rootName.'>';
+ }
+ }
+ }
+ }
+
+ // render children tags
+ foreach ($rootChildren as $child) {
+ $this->writeLine('');
+ $this->writeNode($child, $depth + 4);
+ }
+
+ // render end tag
+ if (!$rootIsEmptyTag && !$rootIsVariablePrototype) {
+ $this->writeLine('');
+
+ $rootEndTag = ''.$rootName.'>';
+ $this->writeLine($rootEndTag, $depth);
+ }
+ }
+
+ /**
+ * Outputs a single config reference line.
+ *
+ * @param string $text
+ * @param int $indent
+ */
+ private function writeLine($text, $indent = 0)
+ {
+ $indent = strlen($text) + $indent;
+ $format = '%'.$indent.'s';
+
+ $this->reference .= sprintf($format, $text).PHP_EOL;
+ }
+
+ /**
+ * Renders the string conversion of the value.
+ *
+ * @param mixed $value
+ *
+ * @return string
+ */
+ private function writeValue($value)
+ {
+ if ('%%%%not_defined%%%%' === $value) {
+ return '';
+ }
+
+ if (is_string($value) || is_numeric($value)) {
+ return $value;
+ }
+
+ if (false === $value) {
+ return 'false';
+ }
+
+ if (true === $value) {
+ return 'true';
+ }
+
+ if (null === $value) {
+ return 'null';
+ }
+
+ if (empty($value)) {
+ return '';
+ }
+
+ if (is_array($value)) {
+ return implode(',', $value);
+ }
+ }
+}
diff --git a/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php b/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php
new file mode 100755
index 0000000..83587fb
--- /dev/null
+++ b/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php
@@ -0,0 +1,198 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Dumper;
+
+use Symfony\Component\Config\Definition\ConfigurationInterface;
+use Symfony\Component\Config\Definition\NodeInterface;
+use Symfony\Component\Config\Definition\ArrayNode;
+use Symfony\Component\Config\Definition\EnumNode;
+use Symfony\Component\Config\Definition\PrototypedArrayNode;
+use Symfony\Component\Yaml\Inline;
+
+/**
+ * Dumps a Yaml reference configuration for the given configuration/node instance.
+ *
+ * @author Kevin Bond
+ */
+class YamlReferenceDumper
+{
+ private $reference;
+
+ public function dump(ConfigurationInterface $configuration)
+ {
+ return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree());
+ }
+
+ public function dumpNode(NodeInterface $node)
+ {
+ $this->reference = '';
+ $this->writeNode($node);
+ $ref = $this->reference;
+ $this->reference = null;
+
+ return $ref;
+ }
+
+ /**
+ * @param NodeInterface $node
+ * @param int $depth
+ */
+ private function writeNode(NodeInterface $node, $depth = 0)
+ {
+ $comments = array();
+ $default = '';
+ $defaultArray = null;
+ $children = null;
+ $example = $node->getExample();
+
+ // defaults
+ if ($node instanceof ArrayNode) {
+ $children = $node->getChildren();
+
+ if ($node instanceof PrototypedArrayNode) {
+ $prototype = $node->getPrototype();
+
+ if ($prototype instanceof ArrayNode) {
+ $children = $prototype->getChildren();
+ }
+
+ // check for attribute as key
+ if ($key = $node->getKeyAttribute()) {
+ $keyNodeClass = 'Symfony\Component\Config\Definition\\'.($prototype instanceof ArrayNode ? 'ArrayNode' : 'ScalarNode');
+ $keyNode = new $keyNodeClass($key, $node);
+ $keyNode->setInfo('Prototype');
+
+ // add children
+ foreach ($children as $childNode) {
+ $keyNode->addChild($childNode);
+ }
+ $children = array($key => $keyNode);
+ }
+ }
+
+ if (!$children) {
+ if ($node->hasDefaultValue() && count($defaultArray = $node->getDefaultValue())) {
+ $default = '';
+ } elseif (!is_array($example)) {
+ $default = '[]';
+ }
+ }
+ } elseif ($node instanceof EnumNode) {
+ $comments[] = 'One of '.implode('; ', array_map('json_encode', $node->getValues()));
+ $default = '~';
+ } else {
+ $default = '~';
+
+ if ($node->hasDefaultValue()) {
+ $default = $node->getDefaultValue();
+
+ if (is_array($default)) {
+ if (count($defaultArray = $node->getDefaultValue())) {
+ $default = '';
+ } elseif (!is_array($example)) {
+ $default = '[]';
+ }
+ } else {
+ $default = Inline::dump($default);
+ }
+ }
+ }
+
+ // required?
+ if ($node->isRequired()) {
+ $comments[] = 'Required';
+ }
+
+ // example
+ if ($example && !is_array($example)) {
+ $comments[] = 'Example: '.$example;
+ }
+
+ $default = (string) $default != '' ? ' '.$default : '';
+ $comments = count($comments) ? '# '.implode(', ', $comments) : '';
+
+ $text = rtrim(sprintf('%-20s %s %s', $node->getName().':', $default, $comments), ' ');
+
+ if ($info = $node->getInfo()) {
+ $this->writeLine('');
+ // indenting multi-line info
+ $info = str_replace("\n", sprintf("\n%".($depth * 4).'s# ', ' '), $info);
+ $this->writeLine('# '.$info, $depth * 4);
+ }
+
+ $this->writeLine($text, $depth * 4);
+
+ // output defaults
+ if ($defaultArray) {
+ $this->writeLine('');
+
+ $message = count($defaultArray) > 1 ? 'Defaults' : 'Default';
+
+ $this->writeLine('# '.$message.':', $depth * 4 + 4);
+
+ $this->writeArray($defaultArray, $depth + 1);
+ }
+
+ if (is_array($example)) {
+ $this->writeLine('');
+
+ $message = count($example) > 1 ? 'Examples' : 'Example';
+
+ $this->writeLine('# '.$message.':', $depth * 4 + 4);
+
+ $this->writeArray($example, $depth + 1);
+ }
+
+ if ($children) {
+ foreach ($children as $childNode) {
+ $this->writeNode($childNode, $depth + 1);
+ }
+ }
+ }
+
+ /**
+ * Outputs a single config reference line.
+ *
+ * @param string $text
+ * @param int $indent
+ */
+ private function writeLine($text, $indent = 0)
+ {
+ $indent = strlen($text) + $indent;
+ $format = '%'.$indent.'s';
+
+ $this->reference .= sprintf($format, $text)."\n";
+ }
+
+ private function writeArray(array $array, $depth)
+ {
+ $isIndexed = array_values($array) === $array;
+
+ foreach ($array as $key => $value) {
+ if (is_array($value)) {
+ $val = '';
+ } else {
+ $val = $value;
+ }
+
+ if ($isIndexed) {
+ $this->writeLine('- '.$val, $depth * 4);
+ } else {
+ $this->writeLine(sprintf('%-20s %s', $key.':', $val), $depth * 4);
+ }
+
+ if (is_array($value)) {
+ $this->writeArray($value, $depth + 1);
+ }
+ }
+ }
+}
diff --git a/vendor/symfony/config/Definition/EnumNode.php b/vendor/symfony/config/Definition/EnumNode.php
new file mode 100755
index 0000000..224871a
--- /dev/null
+++ b/vendor/symfony/config/Definition/EnumNode.php
@@ -0,0 +1,58 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
+
+/**
+ * Node which only allows a finite set of values.
+ *
+ * @author Johannes M. Schmitt
+ */
+class EnumNode extends ScalarNode
+{
+ private $values;
+
+ public function __construct($name, NodeInterface $parent = null, array $values = array())
+ {
+ $values = array_unique($values);
+ if (count($values) <= 1) {
+ throw new \InvalidArgumentException('$values must contain at least two distinct elements.');
+ }
+
+ parent::__construct($name, $parent);
+ $this->values = $values;
+ }
+
+ public function getValues()
+ {
+ return $this->values;
+ }
+
+ protected function finalizeValue($value)
+ {
+ $value = parent::finalizeValue($value);
+
+ if (!in_array($value, $this->values, true)) {
+ $ex = new InvalidConfigurationException(sprintf(
+ 'The value %s is not allowed for path "%s". Permissible values: %s',
+ json_encode($value),
+ $this->getPath(),
+ implode(', ', array_map('json_encode', $this->values))));
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ }
+
+ return $value;
+ }
+}
diff --git a/vendor/symfony/config/Definition/Exception/DuplicateKeyException.php b/vendor/symfony/config/Definition/Exception/DuplicateKeyException.php
new file mode 100755
index 0000000..48dd932
--- /dev/null
+++ b/vendor/symfony/config/Definition/Exception/DuplicateKeyException.php
@@ -0,0 +1,22 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Exception;
+
+/**
+ * This exception is thrown whenever the key of an array is not unique. This can
+ * only be the case if the configuration is coming from an XML file.
+ *
+ * @author Johannes M. Schmitt
+ */
+class DuplicateKeyException extends InvalidConfigurationException
+{
+}
diff --git a/vendor/symfony/config/Definition/Exception/Exception.php b/vendor/symfony/config/Definition/Exception/Exception.php
new file mode 100755
index 0000000..8933a49
--- /dev/null
+++ b/vendor/symfony/config/Definition/Exception/Exception.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Exception;
+
+/**
+ * Base exception for all configuration exceptions.
+ *
+ * @author Johannes M. Schmitt
+ */
+class Exception extends \RuntimeException
+{
+}
diff --git a/vendor/symfony/config/Definition/Exception/ForbiddenOverwriteException.php b/vendor/symfony/config/Definition/Exception/ForbiddenOverwriteException.php
new file mode 100755
index 0000000..726c07f
--- /dev/null
+++ b/vendor/symfony/config/Definition/Exception/ForbiddenOverwriteException.php
@@ -0,0 +1,22 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Exception;
+
+/**
+ * This exception is thrown when a configuration path is overwritten from a
+ * subsequent configuration file, but the entry node specifically forbids this.
+ *
+ * @author Johannes M. Schmitt
+ */
+class ForbiddenOverwriteException extends InvalidConfigurationException
+{
+}
diff --git a/vendor/symfony/config/Definition/Exception/InvalidConfigurationException.php b/vendor/symfony/config/Definition/Exception/InvalidConfigurationException.php
new file mode 100755
index 0000000..3dbc57b
--- /dev/null
+++ b/vendor/symfony/config/Definition/Exception/InvalidConfigurationException.php
@@ -0,0 +1,49 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Exception;
+
+/**
+ * A very general exception which can be thrown whenever non of the more specific
+ * exceptions is suitable.
+ *
+ * @author Johannes M. Schmitt
+ */
+class InvalidConfigurationException extends Exception
+{
+ private $path;
+ private $containsHints = false;
+
+ public function setPath($path)
+ {
+ $this->path = $path;
+ }
+
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ /**
+ * Adds extra information that is suffixed to the original exception message.
+ *
+ * @param string $hint
+ */
+ public function addHint($hint)
+ {
+ if (!$this->containsHints) {
+ $this->message .= "\nHint: ".$hint;
+ $this->containsHints = true;
+ } else {
+ $this->message .= ', '.$hint;
+ }
+ }
+}
diff --git a/vendor/symfony/config/Definition/Exception/InvalidDefinitionException.php b/vendor/symfony/config/Definition/Exception/InvalidDefinitionException.php
new file mode 100755
index 0000000..98310da
--- /dev/null
+++ b/vendor/symfony/config/Definition/Exception/InvalidDefinitionException.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Exception;
+
+/**
+ * Thrown when an error is detected in a node Definition.
+ *
+ * @author Victor Berchet
+ */
+class InvalidDefinitionException extends Exception
+{
+}
diff --git a/vendor/symfony/config/Definition/Exception/InvalidTypeException.php b/vendor/symfony/config/Definition/Exception/InvalidTypeException.php
new file mode 100755
index 0000000..d7ca8c9
--- /dev/null
+++ b/vendor/symfony/config/Definition/Exception/InvalidTypeException.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Exception;
+
+/**
+ * This exception is thrown if an invalid type is encountered.
+ *
+ * @author Johannes M. Schmitt
+ */
+class InvalidTypeException extends InvalidConfigurationException
+{
+}
diff --git a/vendor/symfony/config/Definition/Exception/UnsetKeyException.php b/vendor/symfony/config/Definition/Exception/UnsetKeyException.php
new file mode 100755
index 0000000..863181a
--- /dev/null
+++ b/vendor/symfony/config/Definition/Exception/UnsetKeyException.php
@@ -0,0 +1,22 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition\Exception;
+
+/**
+ * This exception is usually not encountered by the end-user, but only used
+ * internally to signal the parent scope to unset a key.
+ *
+ * @author Johannes M. Schmitt
+ */
+class UnsetKeyException extends Exception
+{
+}
diff --git a/vendor/symfony/config/Definition/FloatNode.php b/vendor/symfony/config/Definition/FloatNode.php
new file mode 100755
index 0000000..5e1af17
--- /dev/null
+++ b/vendor/symfony/config/Definition/FloatNode.php
@@ -0,0 +1,43 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
+
+/**
+ * This node represents a float value in the config tree.
+ *
+ * @author Jeanmonod David
+ */
+class FloatNode extends NumericNode
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function validateType($value)
+ {
+ // Integers are also accepted, we just cast them
+ if (is_int($value)) {
+ $value = (float) $value;
+ }
+
+ if (!is_float($value)) {
+ $ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected float, but got %s.', $this->getPath(), gettype($value)));
+ if ($hint = $this->getInfo()) {
+ $ex->addHint($hint);
+ }
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ }
+ }
+}
diff --git a/vendor/symfony/config/Definition/IntegerNode.php b/vendor/symfony/config/Definition/IntegerNode.php
new file mode 100755
index 0000000..ba23070
--- /dev/null
+++ b/vendor/symfony/config/Definition/IntegerNode.php
@@ -0,0 +1,38 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
+
+/**
+ * This node represents an integer value in the config tree.
+ *
+ * @author Jeanmonod David
+ */
+class IntegerNode extends NumericNode
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function validateType($value)
+ {
+ if (!is_int($value)) {
+ $ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected int, but got %s.', $this->getPath(), gettype($value)));
+ if ($hint = $this->getInfo()) {
+ $ex->addHint($hint);
+ }
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ }
+ }
+}
diff --git a/vendor/symfony/config/Definition/NodeInterface.php b/vendor/symfony/config/Definition/NodeInterface.php
new file mode 100755
index 0000000..b9bddc4
--- /dev/null
+++ b/vendor/symfony/config/Definition/NodeInterface.php
@@ -0,0 +1,88 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+/**
+ * Common Interface among all nodes.
+ *
+ * In most cases, it is better to inherit from BaseNode instead of implementing
+ * this interface yourself.
+ *
+ * @author Johannes M. Schmitt
+ */
+interface NodeInterface
+{
+ /**
+ * Returns the name of the node.
+ *
+ * @return string The name of the node
+ */
+ public function getName();
+
+ /**
+ * Returns the path of the node.
+ *
+ * @return string The node path
+ */
+ public function getPath();
+
+ /**
+ * Returns true when the node is required.
+ *
+ * @return bool If the node is required
+ */
+ public function isRequired();
+
+ /**
+ * Returns true when the node has a default value.
+ *
+ * @return bool If the node has a default value
+ */
+ public function hasDefaultValue();
+
+ /**
+ * Returns the default value of the node.
+ *
+ * @return mixed The default value
+ *
+ * @throws \RuntimeException if the node has no default value
+ */
+ public function getDefaultValue();
+
+ /**
+ * Normalizes the supplied value.
+ *
+ * @param mixed $value The value to normalize
+ *
+ * @return mixed The normalized value
+ */
+ public function normalize($value);
+
+ /**
+ * Merges two values together.
+ *
+ * @param mixed $leftSide
+ * @param mixed $rightSide
+ *
+ * @return mixed The merged values
+ */
+ public function merge($leftSide, $rightSide);
+
+ /**
+ * Finalizes a value.
+ *
+ * @param mixed $value The value to finalize
+ *
+ * @return mixed The finalized value
+ */
+ public function finalize($value);
+}
diff --git a/vendor/symfony/config/Definition/NumericNode.php b/vendor/symfony/config/Definition/NumericNode.php
new file mode 100755
index 0000000..439935e
--- /dev/null
+++ b/vendor/symfony/config/Definition/NumericNode.php
@@ -0,0 +1,64 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
+
+/**
+ * This node represents a numeric value in the config tree.
+ *
+ * @author David Jeanmonod
+ */
+class NumericNode extends ScalarNode
+{
+ protected $min;
+ protected $max;
+
+ public function __construct($name, NodeInterface $parent = null, $min = null, $max = null)
+ {
+ parent::__construct($name, $parent);
+ $this->min = $min;
+ $this->max = $max;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function finalizeValue($value)
+ {
+ $value = parent::finalizeValue($value);
+
+ $errorMsg = null;
+ if (isset($this->min) && $value < $this->min) {
+ $errorMsg = sprintf('The value %s is too small for path "%s". Should be greater than or equal to %s', $value, $this->getPath(), $this->min);
+ }
+ if (isset($this->max) && $value > $this->max) {
+ $errorMsg = sprintf('The value %s is too big for path "%s". Should be less than or equal to %s', $value, $this->getPath(), $this->max);
+ }
+ if (isset($errorMsg)) {
+ $ex = new InvalidConfigurationException($errorMsg);
+ $ex->setPath($this->getPath());
+ throw $ex;
+ }
+
+ return $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function isValueEmpty($value)
+ {
+ // a numeric value cannot be empty
+ return false;
+ }
+}
diff --git a/vendor/symfony/config/Definition/Processor.php b/vendor/symfony/config/Definition/Processor.php
new file mode 100755
index 0000000..025e693
--- /dev/null
+++ b/vendor/symfony/config/Definition/Processor.php
@@ -0,0 +1,97 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+/**
+ * This class is the entry point for config normalization/merging/finalization.
+ *
+ * @author Johannes M. Schmitt
+ */
+class Processor
+{
+ /**
+ * Processes an array of configurations.
+ *
+ * @param NodeInterface $configTree The node tree describing the configuration
+ * @param array $configs An array of configuration items to process
+ *
+ * @return array The processed configuration
+ */
+ public function process(NodeInterface $configTree, array $configs)
+ {
+ $currentConfig = array();
+ foreach ($configs as $config) {
+ $config = $configTree->normalize($config);
+ $currentConfig = $configTree->merge($currentConfig, $config);
+ }
+
+ return $configTree->finalize($currentConfig);
+ }
+
+ /**
+ * Processes an array of configurations.
+ *
+ * @param ConfigurationInterface $configuration The configuration class
+ * @param array $configs An array of configuration items to process
+ *
+ * @return array The processed configuration
+ */
+ public function processConfiguration(ConfigurationInterface $configuration, array $configs)
+ {
+ return $this->process($configuration->getConfigTreeBuilder()->buildTree(), $configs);
+ }
+
+ /**
+ * Normalizes a configuration entry.
+ *
+ * This method returns a normalize configuration array for a given key
+ * to remove the differences due to the original format (YAML and XML mainly).
+ *
+ * Here is an example.
+ *
+ * The configuration in XML:
+ *
+ * twig.extension.foo
+ * twig.extension.bar
+ *
+ * And the same configuration in YAML:
+ *
+ * extensions: ['twig.extension.foo', 'twig.extension.bar']
+ *
+ * @param array $config A config array
+ * @param string $key The key to normalize
+ * @param string $plural The plural form of the key if it is irregular
+ *
+ * @return array
+ */
+ public static function normalizeConfig($config, $key, $plural = null)
+ {
+ if (null === $plural) {
+ $plural = $key.'s';
+ }
+
+ if (isset($config[$plural])) {
+ return $config[$plural];
+ }
+
+ if (isset($config[$key])) {
+ if (is_string($config[$key]) || !is_int(key($config[$key]))) {
+ // only one
+ return array($config[$key]);
+ }
+
+ return $config[$key];
+ }
+
+ return array();
+ }
+}
diff --git a/vendor/symfony/config/Definition/PrototypeNodeInterface.php b/vendor/symfony/config/Definition/PrototypeNodeInterface.php
new file mode 100755
index 0000000..8bbb84d
--- /dev/null
+++ b/vendor/symfony/config/Definition/PrototypeNodeInterface.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+/**
+ * This interface must be implemented by nodes which can be used as prototypes.
+ *
+ * @author Johannes M. Schmitt
+ */
+interface PrototypeNodeInterface extends NodeInterface
+{
+ /**
+ * Sets the name of the node.
+ *
+ * @param string $name The name of the node
+ */
+ public function setName($name);
+}
diff --git a/vendor/symfony/config/Definition/PrototypedArrayNode.php b/vendor/symfony/config/Definition/PrototypedArrayNode.php
new file mode 100755
index 0000000..931b467
--- /dev/null
+++ b/vendor/symfony/config/Definition/PrototypedArrayNode.php
@@ -0,0 +1,331 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
+use Symfony\Component\Config\Definition\Exception\DuplicateKeyException;
+use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
+use Symfony\Component\Config\Definition\Exception\Exception;
+
+/**
+ * Represents a prototyped Array node in the config tree.
+ *
+ * @author Johannes M. Schmitt
+ */
+class PrototypedArrayNode extends ArrayNode
+{
+ protected $prototype;
+ protected $keyAttribute;
+ protected $removeKeyAttribute = false;
+ protected $minNumberOfElements = 0;
+ protected $defaultValue = array();
+ protected $defaultChildren;
+
+ /**
+ * Sets the minimum number of elements that a prototype based node must
+ * contain. By default this is zero, meaning no elements.
+ *
+ * @param int $number
+ */
+ public function setMinNumberOfElements($number)
+ {
+ $this->minNumberOfElements = $number;
+ }
+
+ /**
+ * Sets the attribute which value is to be used as key.
+ *
+ * This is useful when you have an indexed array that should be an
+ * associative array. You can select an item from within the array
+ * to be the key of the particular item. For example, if "id" is the
+ * "key", then:
+ *
+ * array(
+ * array('id' => 'my_name', 'foo' => 'bar'),
+ * );
+ *
+ * becomes
+ *
+ * array(
+ * 'my_name' => array('foo' => 'bar'),
+ * );
+ *
+ * If you'd like "'id' => 'my_name'" to still be present in the resulting
+ * array, then you can set the second argument of this method to false.
+ *
+ * @param string $attribute The name of the attribute which value is to be used as a key
+ * @param bool $remove Whether or not to remove the key
+ */
+ public function setKeyAttribute($attribute, $remove = true)
+ {
+ $this->keyAttribute = $attribute;
+ $this->removeKeyAttribute = $remove;
+ }
+
+ /**
+ * Retrieves the name of the attribute which value should be used as key.
+ *
+ * @return string The name of the attribute
+ */
+ public function getKeyAttribute()
+ {
+ return $this->keyAttribute;
+ }
+
+ /**
+ * Sets the default value of this node.
+ *
+ * @param string $value
+ *
+ * @throws \InvalidArgumentException if the default value is not an array
+ */
+ public function setDefaultValue($value)
+ {
+ if (!is_array($value)) {
+ throw new \InvalidArgumentException($this->getPath().': the default value of an array node has to be an array.');
+ }
+
+ $this->defaultValue = $value;
+ }
+
+ /**
+ * Checks if the node has a default value.
+ *
+ * @return bool
+ */
+ public function hasDefaultValue()
+ {
+ return true;
+ }
+
+ /**
+ * Adds default children when none are set.
+ *
+ * @param int|string|array|null $children The number of children|The child name|The children names to be added
+ */
+ public function setAddChildrenIfNoneSet($children = array('defaults'))
+ {
+ if (null === $children) {
+ $this->defaultChildren = array('defaults');
+ } else {
+ $this->defaultChildren = is_int($children) && $children > 0 ? range(1, $children) : (array) $children;
+ }
+ }
+
+ /**
+ * Retrieves the default value.
+ *
+ * The default value could be either explicited or derived from the prototype
+ * default value.
+ *
+ * @return array The default value
+ */
+ public function getDefaultValue()
+ {
+ if (null !== $this->defaultChildren) {
+ $default = $this->prototype->hasDefaultValue() ? $this->prototype->getDefaultValue() : array();
+ $defaults = array();
+ foreach (array_values($this->defaultChildren) as $i => $name) {
+ $defaults[null === $this->keyAttribute ? $i : $name] = $default;
+ }
+
+ return $defaults;
+ }
+
+ return $this->defaultValue;
+ }
+
+ /**
+ * Sets the node prototype.
+ *
+ * @param PrototypeNodeInterface $node
+ */
+ public function setPrototype(PrototypeNodeInterface $node)
+ {
+ $this->prototype = $node;
+ }
+
+ /**
+ * Retrieves the prototype.
+ *
+ * @return PrototypeNodeInterface The prototype
+ */
+ public function getPrototype()
+ {
+ return $this->prototype;
+ }
+
+ /**
+ * Disable adding concrete children for prototyped nodes.
+ *
+ * @param NodeInterface $node The child node to add
+ *
+ * @throws Exception
+ */
+ public function addChild(NodeInterface $node)
+ {
+ throw new Exception('A prototyped array node can not have concrete children.');
+ }
+
+ /**
+ * Finalizes the value of this node.
+ *
+ * @param mixed $value
+ *
+ * @return mixed The finalized value
+ *
+ * @throws UnsetKeyException
+ * @throws InvalidConfigurationException if the node doesn't have enough children
+ */
+ protected function finalizeValue($value)
+ {
+ if (false === $value) {
+ $msg = sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value));
+ throw new UnsetKeyException($msg);
+ }
+
+ foreach ($value as $k => $v) {
+ $this->prototype->setName($k);
+ try {
+ $value[$k] = $this->prototype->finalize($v);
+ } catch (UnsetKeyException $e) {
+ unset($value[$k]);
+ }
+ }
+
+ if (count($value) < $this->minNumberOfElements) {
+ $msg = sprintf('The path "%s" should have at least %d element(s) defined.', $this->getPath(), $this->minNumberOfElements);
+ $ex = new InvalidConfigurationException($msg);
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ }
+
+ return $value;
+ }
+
+ /**
+ * Normalizes the value.
+ *
+ * @param mixed $value The value to normalize
+ *
+ * @return mixed The normalized value
+ *
+ * @throws InvalidConfigurationException
+ * @throws DuplicateKeyException
+ */
+ protected function normalizeValue($value)
+ {
+ if (false === $value) {
+ return $value;
+ }
+
+ $value = $this->remapXml($value);
+
+ $isAssoc = array_keys($value) !== range(0, count($value) - 1);
+ $normalized = array();
+ foreach ($value as $k => $v) {
+ if (null !== $this->keyAttribute && is_array($v)) {
+ if (!isset($v[$this->keyAttribute]) && is_int($k) && !$isAssoc) {
+ $msg = sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath());
+ $ex = new InvalidConfigurationException($msg);
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ } elseif (isset($v[$this->keyAttribute])) {
+ $k = $v[$this->keyAttribute];
+
+ // remove the key attribute when required
+ if ($this->removeKeyAttribute) {
+ unset($v[$this->keyAttribute]);
+ }
+
+ // if only "value" is left
+ if (1 == count($v) && isset($v['value'])) {
+ $v = $v['value'];
+ }
+ }
+
+ if (array_key_exists($k, $normalized)) {
+ $msg = sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath());
+ $ex = new DuplicateKeyException($msg);
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ }
+ }
+
+ $this->prototype->setName($k);
+ if (null !== $this->keyAttribute || $isAssoc) {
+ $normalized[$k] = $this->prototype->normalize($v);
+ } else {
+ $normalized[] = $this->prototype->normalize($v);
+ }
+ }
+
+ return $normalized;
+ }
+
+ /**
+ * Merges values together.
+ *
+ * @param mixed $leftSide The left side to merge.
+ * @param mixed $rightSide The right side to merge.
+ *
+ * @return mixed The merged values
+ *
+ * @throws InvalidConfigurationException
+ * @throws \RuntimeException
+ */
+ protected function mergeValues($leftSide, $rightSide)
+ {
+ if (false === $rightSide) {
+ // if this is still false after the last config has been merged the
+ // finalization pass will take care of removing this key entirely
+ return false;
+ }
+
+ if (false === $leftSide || !$this->performDeepMerging) {
+ return $rightSide;
+ }
+
+ foreach ($rightSide as $k => $v) {
+ // prototype, and key is irrelevant, so simply append the element
+ if (null === $this->keyAttribute) {
+ $leftSide[] = $v;
+ continue;
+ }
+
+ // no conflict
+ if (!array_key_exists($k, $leftSide)) {
+ if (!$this->allowNewKeys) {
+ $ex = new InvalidConfigurationException(sprintf(
+ 'You are not allowed to define new elements for path "%s". '.
+ 'Please define all elements for this path in one config file.',
+ $this->getPath()
+ ));
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ }
+
+ $leftSide[$k] = $v;
+ continue;
+ }
+
+ $this->prototype->setName($k);
+ $leftSide[$k] = $this->prototype->merge($leftSide[$k], $v);
+ }
+
+ return $leftSide;
+ }
+}
diff --git a/vendor/symfony/config/Definition/ReferenceDumper.php b/vendor/symfony/config/Definition/ReferenceDumper.php
new file mode 100755
index 0000000..09526cf
--- /dev/null
+++ b/vendor/symfony/config/Definition/ReferenceDumper.php
@@ -0,0 +1,24 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+@trigger_error('The '.__NAMESPACE__.'\ReferenceDumper class is deprecated since version 2.4 and will be removed in 3.0. Use the Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper class instead.', E_USER_DEPRECATED);
+
+use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;
+
+/**
+ * @deprecated since version 2.4, to be removed in 3.0.
+ * Use {@link \Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper} instead.
+ */
+class ReferenceDumper extends YamlReferenceDumper
+{
+}
diff --git a/vendor/symfony/config/Definition/ScalarNode.php b/vendor/symfony/config/Definition/ScalarNode.php
new file mode 100755
index 0000000..6b3fd0b
--- /dev/null
+++ b/vendor/symfony/config/Definition/ScalarNode.php
@@ -0,0 +1,57 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
+
+/**
+ * This node represents a scalar value in the config tree.
+ *
+ * The following values are considered scalars:
+ * * booleans
+ * * strings
+ * * null
+ * * integers
+ * * floats
+ *
+ * @author Johannes M. Schmitt
+ */
+class ScalarNode extends VariableNode
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function validateType($value)
+ {
+ if (!is_scalar($value) && null !== $value) {
+ $ex = new InvalidTypeException(sprintf(
+ 'Invalid type for path "%s". Expected scalar, but got %s.',
+ $this->getPath(),
+ gettype($value)
+ ));
+ if ($hint = $this->getInfo()) {
+ $ex->addHint($hint);
+ }
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function isValueEmpty($value)
+ {
+ return null === $value || '' === $value;
+ }
+}
diff --git a/vendor/symfony/config/Definition/VariableNode.php b/vendor/symfony/config/Definition/VariableNode.php
new file mode 100755
index 0000000..e2c0677
--- /dev/null
+++ b/vendor/symfony/config/Definition/VariableNode.php
@@ -0,0 +1,135 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Definition;
+
+use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
+
+/**
+ * This node represents a value of variable type in the config tree.
+ *
+ * This node is intended for values of arbitrary type.
+ * Any PHP type is accepted as a value.
+ *
+ * @author Jeremy Mikola
+ */
+class VariableNode extends BaseNode implements PrototypeNodeInterface
+{
+ protected $defaultValueSet = false;
+ protected $defaultValue;
+ protected $allowEmptyValue = true;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setDefaultValue($value)
+ {
+ $this->defaultValueSet = true;
+ $this->defaultValue = $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasDefaultValue()
+ {
+ return $this->defaultValueSet;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDefaultValue()
+ {
+ $v = $this->defaultValue;
+
+ return $v instanceof \Closure ? $v() : $v;
+ }
+
+ /**
+ * Sets if this node is allowed to have an empty value.
+ *
+ * @param bool $boolean True if this entity will accept empty values.
+ */
+ public function setAllowEmptyValue($boolean)
+ {
+ $this->allowEmptyValue = (bool) $boolean;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function validateType($value)
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function finalizeValue($value)
+ {
+ if (!$this->allowEmptyValue && $this->isValueEmpty($value)) {
+ $ex = new InvalidConfigurationException(sprintf(
+ 'The path "%s" cannot contain an empty value, but got %s.',
+ $this->getPath(),
+ json_encode($value)
+ ));
+ if ($hint = $this->getInfo()) {
+ $ex->addHint($hint);
+ }
+ $ex->setPath($this->getPath());
+
+ throw $ex;
+ }
+
+ return $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function normalizeValue($value)
+ {
+ return $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function mergeValues($leftSide, $rightSide)
+ {
+ return $rightSide;
+ }
+
+ /**
+ * Evaluates if the given value is to be treated as empty.
+ *
+ * By default, PHP's empty() function is used to test for emptiness. This
+ * method may be overridden by subtypes to better match their understanding
+ * of empty data.
+ *
+ * @param mixed $value
+ *
+ * @return bool
+ */
+ protected function isValueEmpty($value)
+ {
+ return empty($value);
+ }
+}
diff --git a/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php b/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php
new file mode 100755
index 0000000..6a3b01c
--- /dev/null
+++ b/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Exception;
+
+/**
+ * Exception class for when a circular reference is detected when importing resources.
+ *
+ * @author Fabien Potencier
+ */
+class FileLoaderImportCircularReferenceException extends FileLoaderLoadException
+{
+ public function __construct(array $resources, $code = null, $previous = null)
+ {
+ $message = sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]);
+
+ \Exception::__construct($message, $code, $previous);
+ }
+}
diff --git a/vendor/symfony/config/Exception/FileLoaderLoadException.php b/vendor/symfony/config/Exception/FileLoaderLoadException.php
new file mode 100755
index 0000000..6af3dd0
--- /dev/null
+++ b/vendor/symfony/config/Exception/FileLoaderLoadException.php
@@ -0,0 +1,101 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Exception;
+
+/**
+ * Exception class for when a resource cannot be loaded or imported.
+ *
+ * @author Ryan Weaver
+ */
+class FileLoaderLoadException extends \Exception
+{
+ /**
+ * @param string $resource The resource that could not be imported
+ * @param string $sourceResource The original resource importing the new resource
+ * @param int $code The error code
+ * @param \Exception $previous A previous exception
+ */
+ public function __construct($resource, $sourceResource = null, $code = null, $previous = null)
+ {
+ $message = '';
+ if ($previous) {
+ // Include the previous exception, to help the user see what might be the underlying cause
+
+ // Trim the trailing period of the previous message. We only want 1 period remove so no rtrim...
+ if ('.' === substr($previous->getMessage(), -1)) {
+ $trimmedMessage = substr($previous->getMessage(), 0, -1);
+ $message .= sprintf('%s', $trimmedMessage).' in ';
+ } else {
+ $message .= sprintf('%s', $previous->getMessage()).' in ';
+ }
+ $message .= $resource.' ';
+
+ // show tweaked trace to complete the human readable sentence
+ if (null === $sourceResource) {
+ $message .= sprintf('(which is loaded in resource "%s")', $this->varToString($resource));
+ } else {
+ $message .= sprintf('(which is being imported from "%s")', $this->varToString($sourceResource));
+ }
+ $message .= '.';
+
+ // if there's no previous message, present it the default way
+ } elseif (null === $sourceResource) {
+ $message .= sprintf('Cannot load resource "%s".', $this->varToString($resource));
+ } else {
+ $message .= sprintf('Cannot import resource "%s" from "%s".', $this->varToString($resource), $this->varToString($sourceResource));
+ }
+
+ // Is the resource located inside a bundle?
+ if ('@' === $resource[0]) {
+ $parts = explode(DIRECTORY_SEPARATOR, $resource);
+ $bundle = substr($parts[0], 1);
+ $message .= sprintf(' Make sure the "%s" bundle is correctly registered and loaded in the application kernel class.', $bundle);
+ $message .= sprintf(' If the bundle is registered, make sure the bundle path "%s" is not empty.', $resource);
+ }
+
+ parent::__construct($message, $code, $previous);
+ }
+
+ protected function varToString($var)
+ {
+ if (is_object($var)) {
+ return sprintf('Object(%s)', get_class($var));
+ }
+
+ if (is_array($var)) {
+ $a = array();
+ foreach ($var as $k => $v) {
+ $a[] = sprintf('%s => %s', $k, $this->varToString($v));
+ }
+
+ return sprintf('Array(%s)', implode(', ', $a));
+ }
+
+ if (is_resource($var)) {
+ return sprintf('Resource(%s)', get_resource_type($var));
+ }
+
+ if (null === $var) {
+ return 'null';
+ }
+
+ if (false === $var) {
+ return 'false';
+ }
+
+ if (true === $var) {
+ return 'true';
+ }
+
+ return (string) $var;
+ }
+}
diff --git a/vendor/symfony/config/FileLocator.php b/vendor/symfony/config/FileLocator.php
new file mode 100755
index 0000000..c6600c7
--- /dev/null
+++ b/vendor/symfony/config/FileLocator.php
@@ -0,0 +1,96 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config;
+
+/**
+ * FileLocator uses an array of pre-defined paths to find files.
+ *
+ * @author Fabien Potencier
+ */
+class FileLocator implements FileLocatorInterface
+{
+ protected $paths;
+
+ /**
+ * Constructor.
+ *
+ * @param string|array $paths A path or an array of paths where to look for resources
+ */
+ public function __construct($paths = array())
+ {
+ $this->paths = (array) $paths;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function locate($name, $currentPath = null, $first = true)
+ {
+ if ('' == $name) {
+ throw new \InvalidArgumentException('An empty file name is not valid to be located.');
+ }
+
+ if ($this->isAbsolutePath($name)) {
+ if (!file_exists($name)) {
+ throw new \InvalidArgumentException(sprintf('The file "%s" does not exist.', $name));
+ }
+
+ return $name;
+ }
+
+ $paths = $this->paths;
+
+ if (null !== $currentPath) {
+ array_unshift($paths, $currentPath);
+ }
+
+ $paths = array_unique($paths);
+ $filepaths = array();
+
+ foreach ($paths as $path) {
+ if (file_exists($file = $path.DIRECTORY_SEPARATOR.$name)) {
+ if (true === $first) {
+ return $file;
+ }
+ $filepaths[] = $file;
+ }
+ }
+
+ if (!$filepaths) {
+ throw new \InvalidArgumentException(sprintf('The file "%s" does not exist (in: %s).', $name, implode(', ', $paths)));
+ }
+
+ return $filepaths;
+ }
+
+ /**
+ * Returns whether the file path is an absolute path.
+ *
+ * @param string $file A file path
+ *
+ * @return bool
+ */
+ private function isAbsolutePath($file)
+ {
+ if ($file[0] === '/' || $file[0] === '\\'
+ || (strlen($file) > 3 && ctype_alpha($file[0])
+ && $file[1] === ':'
+ && ($file[2] === '\\' || $file[2] === '/')
+ )
+ || null !== parse_url($file, PHP_URL_SCHEME)
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/vendor/symfony/config/FileLocatorInterface.php b/vendor/symfony/config/FileLocatorInterface.php
new file mode 100755
index 0000000..6605798
--- /dev/null
+++ b/vendor/symfony/config/FileLocatorInterface.php
@@ -0,0 +1,31 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config;
+
+/**
+ * @author Fabien Potencier
+ */
+interface FileLocatorInterface
+{
+ /**
+ * Returns a full path for a given file name.
+ *
+ * @param string $name The file name to locate
+ * @param string|null $currentPath The current path
+ * @param bool $first Whether to return the first occurrence or an array of filenames
+ *
+ * @return string|array The full path to the file or an array of file paths
+ *
+ * @throws \InvalidArgumentException When file is not found
+ */
+ public function locate($name, $currentPath = null, $first = true);
+}
diff --git a/vendor/symfony/config/LICENSE b/vendor/symfony/config/LICENSE
new file mode 100755
index 0000000..43028bc
--- /dev/null
+++ b/vendor/symfony/config/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2015 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/symfony/config/Loader/DelegatingLoader.php b/vendor/symfony/config/Loader/DelegatingLoader.php
new file mode 100755
index 0000000..3097878
--- /dev/null
+++ b/vendor/symfony/config/Loader/DelegatingLoader.php
@@ -0,0 +1,55 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Loader;
+
+use Symfony\Component\Config\Exception\FileLoaderLoadException;
+
+/**
+ * DelegatingLoader delegates loading to other loaders using a loader resolver.
+ *
+ * This loader acts as an array of LoaderInterface objects - each having
+ * a chance to load a given resource (handled by the resolver)
+ *
+ * @author Fabien Potencier
+ */
+class DelegatingLoader extends Loader
+{
+ /**
+ * Constructor.
+ *
+ * @param LoaderResolverInterface $resolver A LoaderResolverInterface instance
+ */
+ public function __construct(LoaderResolverInterface $resolver)
+ {
+ $this->resolver = $resolver;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function load($resource, $type = null)
+ {
+ if (false === $loader = $this->resolver->resolve($resource, $type)) {
+ throw new FileLoaderLoadException($resource);
+ }
+
+ return $loader->load($resource, $type);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supports($resource, $type = null)
+ {
+ return false !== $this->resolver->resolve($resource, $type);
+ }
+}
diff --git a/vendor/symfony/config/Loader/FileLoader.php b/vendor/symfony/config/Loader/FileLoader.php
new file mode 100755
index 0000000..88ec070
--- /dev/null
+++ b/vendor/symfony/config/Loader/FileLoader.php
@@ -0,0 +1,134 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Loader;
+
+use Symfony\Component\Config\FileLocatorInterface;
+use Symfony\Component\Config\Exception\FileLoaderLoadException;
+use Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException;
+
+/**
+ * FileLoader is the abstract class used by all built-in loaders that are file based.
+ *
+ * @author Fabien Potencier
+ */
+abstract class FileLoader extends Loader
+{
+ /**
+ * @var array
+ */
+ protected static $loading = array();
+
+ /**
+ * @var FileLocatorInterface
+ */
+ protected $locator;
+
+ private $currentDir;
+
+ /**
+ * Constructor.
+ *
+ * @param FileLocatorInterface $locator A FileLocatorInterface instance
+ */
+ public function __construct(FileLocatorInterface $locator)
+ {
+ $this->locator = $locator;
+ }
+
+ /**
+ * Sets the current directory.
+ *
+ * @param string $dir
+ */
+ public function setCurrentDir($dir)
+ {
+ $this->currentDir = $dir;
+ }
+
+ /**
+ * Returns the file locator used by this loader.
+ *
+ * @return FileLocatorInterface
+ */
+ public function getLocator()
+ {
+ return $this->locator;
+ }
+
+ /**
+ * Imports a resource.
+ *
+ * @param mixed $resource A Resource
+ * @param string|null $type The resource type or null if unknown
+ * @param bool $ignoreErrors Whether to ignore import errors or not
+ * @param string|null $sourceResource The original resource importing the new resource
+ *
+ * @return mixed
+ *
+ * @throws FileLoaderLoadException
+ * @throws FileLoaderImportCircularReferenceException
+ */
+ public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null)
+ {
+ try {
+ $loader = $this->resolve($resource, $type);
+
+ if ($loader instanceof self && null !== $this->currentDir) {
+ // we fallback to the current locator to keep BC
+ // as some some loaders do not call the parent __construct()
+ // @deprecated should be removed in 3.0
+ $locator = $loader->getLocator();
+ if (null === $locator) {
+ @trigger_error('Not calling the parent constructor in '.get_class($loader).' which extends '.__CLASS__.' is deprecated since version 2.7 and will not be supported anymore in 3.0.', E_USER_DEPRECATED);
+ $locator = $this->locator;
+ }
+
+ $resource = $locator->locate($resource, $this->currentDir, false);
+ }
+
+ $resources = is_array($resource) ? $resource : array($resource);
+ for ($i = 0; $i < $resourcesCount = count($resources); ++$i) {
+ if (isset(self::$loading[$resources[$i]])) {
+ if ($i == $resourcesCount - 1) {
+ throw new FileLoaderImportCircularReferenceException(array_keys(self::$loading));
+ }
+ } else {
+ $resource = $resources[$i];
+ break;
+ }
+ }
+ self::$loading[$resource] = true;
+
+ try {
+ $ret = $loader->load($resource, $type);
+ } catch (\Exception $e) {
+ unset(self::$loading[$resource]);
+ throw $e;
+ }
+
+ unset(self::$loading[$resource]);
+
+ return $ret;
+ } catch (FileLoaderImportCircularReferenceException $e) {
+ throw $e;
+ } catch (\Exception $e) {
+ if (!$ignoreErrors) {
+ // prevent embedded imports from nesting multiple exceptions
+ if ($e instanceof FileLoaderLoadException) {
+ throw $e;
+ }
+
+ throw new FileLoaderLoadException($resource, $sourceResource, null, $e);
+ }
+ }
+ }
+}
diff --git a/vendor/symfony/config/Loader/Loader.php b/vendor/symfony/config/Loader/Loader.php
new file mode 100755
index 0000000..de4e127
--- /dev/null
+++ b/vendor/symfony/config/Loader/Loader.php
@@ -0,0 +1,78 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Loader;
+
+use Symfony\Component\Config\Exception\FileLoaderLoadException;
+
+/**
+ * Loader is the abstract class used by all built-in loaders.
+ *
+ * @author Fabien Potencier
+ */
+abstract class Loader implements LoaderInterface
+{
+ protected $resolver;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getResolver()
+ {
+ return $this->resolver;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setResolver(LoaderResolverInterface $resolver)
+ {
+ $this->resolver = $resolver;
+ }
+
+ /**
+ * Imports a resource.
+ *
+ * @param mixed $resource A resource
+ * @param string|null $type The resource type or null if unknown
+ *
+ * @return mixed
+ */
+ public function import($resource, $type = null)
+ {
+ return $this->resolve($resource, $type)->load($resource, $type);
+ }
+
+ /**
+ * Finds a loader able to load an imported resource.
+ *
+ * @param mixed $resource A resource
+ * @param string|null $type The resource type or null if unknown
+ *
+ * @return LoaderInterface A LoaderInterface instance
+ *
+ * @throws FileLoaderLoadException If no loader is found
+ */
+ public function resolve($resource, $type = null)
+ {
+ if ($this->supports($resource, $type)) {
+ return $this;
+ }
+
+ $loader = null === $this->resolver ? false : $this->resolver->resolve($resource, $type);
+
+ if (false === $loader) {
+ throw new FileLoaderLoadException($resource);
+ }
+
+ return $loader;
+ }
+}
diff --git a/vendor/symfony/config/Loader/LoaderInterface.php b/vendor/symfony/config/Loader/LoaderInterface.php
new file mode 100755
index 0000000..dd0a85a
--- /dev/null
+++ b/vendor/symfony/config/Loader/LoaderInterface.php
@@ -0,0 +1,54 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Loader;
+
+/**
+ * LoaderInterface is the interface implemented by all loader classes.
+ *
+ * @author Fabien Potencier
+ */
+interface LoaderInterface
+{
+ /**
+ * Loads a resource.
+ *
+ * @param mixed $resource The resource
+ * @param string|null $type The resource type or null if unknown
+ *
+ * @throws \Exception If something went wrong
+ */
+ public function load($resource, $type = null);
+
+ /**
+ * Returns whether this class supports the given resource.
+ *
+ * @param mixed $resource A resource
+ * @param string|null $type The resource type or null if unknown
+ *
+ * @return bool True if this class supports the given resource, false otherwise
+ */
+ public function supports($resource, $type = null);
+
+ /**
+ * Gets the loader resolver.
+ *
+ * @return LoaderResolverInterface A LoaderResolverInterface instance
+ */
+ public function getResolver();
+
+ /**
+ * Sets the loader resolver.
+ *
+ * @param LoaderResolverInterface $resolver A LoaderResolverInterface instance
+ */
+ public function setResolver(LoaderResolverInterface $resolver);
+}
diff --git a/vendor/symfony/config/Loader/LoaderResolver.php b/vendor/symfony/config/Loader/LoaderResolver.php
new file mode 100755
index 0000000..dc6846d
--- /dev/null
+++ b/vendor/symfony/config/Loader/LoaderResolver.php
@@ -0,0 +1,75 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Loader;
+
+/**
+ * LoaderResolver selects a loader for a given resource.
+ *
+ * A resource can be anything (e.g. a full path to a config file or a Closure).
+ * Each loader determines whether it can load a resource and how.
+ *
+ * @author Fabien Potencier
+ */
+class LoaderResolver implements LoaderResolverInterface
+{
+ /**
+ * @var LoaderInterface[] An array of LoaderInterface objects
+ */
+ private $loaders = array();
+
+ /**
+ * Constructor.
+ *
+ * @param LoaderInterface[] $loaders An array of loaders
+ */
+ public function __construct(array $loaders = array())
+ {
+ foreach ($loaders as $loader) {
+ $this->addLoader($loader);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function resolve($resource, $type = null)
+ {
+ foreach ($this->loaders as $loader) {
+ if ($loader->supports($resource, $type)) {
+ return $loader;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Adds a loader.
+ *
+ * @param LoaderInterface $loader A LoaderInterface instance
+ */
+ public function addLoader(LoaderInterface $loader)
+ {
+ $this->loaders[] = $loader;
+ $loader->setResolver($this);
+ }
+
+ /**
+ * Returns the registered loaders.
+ *
+ * @return LoaderInterface[] An array of LoaderInterface instances
+ */
+ public function getLoaders()
+ {
+ return $this->loaders;
+ }
+}
diff --git a/vendor/symfony/config/Loader/LoaderResolverInterface.php b/vendor/symfony/config/Loader/LoaderResolverInterface.php
new file mode 100755
index 0000000..40f1a1a
--- /dev/null
+++ b/vendor/symfony/config/Loader/LoaderResolverInterface.php
@@ -0,0 +1,30 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Loader;
+
+/**
+ * LoaderResolverInterface selects a loader for a given resource.
+ *
+ * @author Fabien Potencier
+ */
+interface LoaderResolverInterface
+{
+ /**
+ * Returns a loader able to load the resource.
+ *
+ * @param mixed $resource A resource
+ * @param string|null $type The resource type or null if unknown
+ *
+ * @return LoaderInterface|false The loader or false if none is able to load the resource
+ */
+ public function resolve($resource, $type = null);
+}
diff --git a/vendor/symfony/config/README.md b/vendor/symfony/config/README.md
new file mode 100755
index 0000000..690d7d7
--- /dev/null
+++ b/vendor/symfony/config/README.md
@@ -0,0 +1,17 @@
+Config Component
+================
+
+Config provides the infrastructure for loading configurations from different
+data sources and optionally monitoring these data sources for changes. There
+are additional tools for validating, normalizing and handling of defaults that
+can optionally be used to convert from different formats to arrays.
+
+Resources
+---------
+
+You can run the unit tests with the following command:
+
+ $ cd path/to/Symfony/Component/Config/
+ $ composer install
+ $ phpunit
+
diff --git a/vendor/symfony/config/Resource/DirectoryResource.php b/vendor/symfony/config/Resource/DirectoryResource.php
new file mode 100755
index 0000000..515fb5c
--- /dev/null
+++ b/vendor/symfony/config/Resource/DirectoryResource.php
@@ -0,0 +1,99 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Resource;
+
+/**
+ * DirectoryResource represents a resources stored in a subdirectory tree.
+ *
+ * @author Fabien Potencier
+ */
+class DirectoryResource implements ResourceInterface, \Serializable
+{
+ private $resource;
+ private $pattern;
+
+ /**
+ * Constructor.
+ *
+ * @param string $resource The file path to the resource
+ * @param string|null $pattern A pattern to restrict monitored files
+ */
+ public function __construct($resource, $pattern = null)
+ {
+ $this->resource = $resource;
+ $this->pattern = $pattern;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ return (string) $this->resource;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getResource()
+ {
+ return $this->resource;
+ }
+
+ /**
+ * Returns the pattern to restrict monitored files.
+ *
+ * @return string|null
+ */
+ public function getPattern()
+ {
+ return $this->pattern;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isFresh($timestamp)
+ {
+ if (!is_dir($this->resource)) {
+ return false;
+ }
+
+ $newestMTime = filemtime($this->resource);
+ foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->resource), \RecursiveIteratorIterator::SELF_FIRST) as $file) {
+ // if regex filtering is enabled only check matching files
+ if ($this->pattern && $file->isFile() && !preg_match($this->pattern, $file->getBasename())) {
+ continue;
+ }
+
+ // always monitor directories for changes, except the .. entries
+ // (otherwise deleted files wouldn't get detected)
+ if ($file->isDir() && '/..' === substr($file, -3)) {
+ continue;
+ }
+
+ $newestMTime = max($file->getMTime(), $newestMTime);
+ }
+
+ return $newestMTime < $timestamp;
+ }
+
+ public function serialize()
+ {
+ return serialize(array($this->resource, $this->pattern));
+ }
+
+ public function unserialize($serialized)
+ {
+ list($this->resource, $this->pattern) = unserialize($serialized);
+ }
+}
diff --git a/vendor/symfony/config/Resource/FileResource.php b/vendor/symfony/config/Resource/FileResource.php
new file mode 100755
index 0000000..4c00ae4
--- /dev/null
+++ b/vendor/symfony/config/Resource/FileResource.php
@@ -0,0 +1,75 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Resource;
+
+/**
+ * FileResource represents a resource stored on the filesystem.
+ *
+ * The resource can be a file or a directory.
+ *
+ * @author Fabien Potencier
+ */
+class FileResource implements ResourceInterface, \Serializable
+{
+ /**
+ * @var string|false
+ */
+ private $resource;
+
+ /**
+ * Constructor.
+ *
+ * @param string $resource The file path to the resource
+ */
+ public function __construct($resource)
+ {
+ $this->resource = realpath($resource);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ return (string) $this->resource;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getResource()
+ {
+ return $this->resource;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isFresh($timestamp)
+ {
+ if (false === $this->resource || !file_exists($this->resource)) {
+ return false;
+ }
+
+ return filemtime($this->resource) <= $timestamp;
+ }
+
+ public function serialize()
+ {
+ return serialize($this->resource);
+ }
+
+ public function unserialize($serialized)
+ {
+ $this->resource = unserialize($serialized);
+ }
+}
diff --git a/vendor/symfony/config/Resource/ResourceInterface.php b/vendor/symfony/config/Resource/ResourceInterface.php
new file mode 100755
index 0000000..db03d12
--- /dev/null
+++ b/vendor/symfony/config/Resource/ResourceInterface.php
@@ -0,0 +1,43 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Resource;
+
+/**
+ * ResourceInterface is the interface that must be implemented by all Resource classes.
+ *
+ * @author Fabien Potencier
+ */
+interface ResourceInterface
+{
+ /**
+ * Returns a string representation of the Resource.
+ *
+ * @return string A string representation of the Resource
+ */
+ public function __toString();
+
+ /**
+ * Returns true if the resource has not been updated since the given timestamp.
+ *
+ * @param int $timestamp The last time the resource was loaded
+ *
+ * @return bool True if the resource has not been updated, false otherwise
+ */
+ public function isFresh($timestamp);
+
+ /**
+ * Returns the tied resource.
+ *
+ * @return mixed The resource
+ */
+ public function getResource();
+}
diff --git a/vendor/symfony/config/Tests/ConfigCacheFactoryTest.php b/vendor/symfony/config/Tests/ConfigCacheFactoryTest.php
new file mode 100755
index 0000000..291243d
--- /dev/null
+++ b/vendor/symfony/config/Tests/ConfigCacheFactoryTest.php
@@ -0,0 +1,28 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests;
+
+use Symfony\Component\Config\ConfigCacheFactory;
+
+class ConfigCacheFactoryTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Invalid type for callback argument. Expected callable, but got "object".
+ */
+ public function testCachWithInvalidCallback()
+ {
+ $cacheFactory = new ConfigCacheFactory(true);
+
+ $cacheFactory->cache('file', new \stdClass());
+ }
+}
diff --git a/vendor/symfony/config/Tests/ConfigCacheTest.php b/vendor/symfony/config/Tests/ConfigCacheTest.php
new file mode 100755
index 0000000..f3f2a44
--- /dev/null
+++ b/vendor/symfony/config/Tests/ConfigCacheTest.php
@@ -0,0 +1,138 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests;
+
+use Symfony\Component\Config\ConfigCache;
+use Symfony\Component\Config\Resource\FileResource;
+
+class ConfigCacheTest extends \PHPUnit_Framework_TestCase
+{
+ private $resourceFile = null;
+
+ private $cacheFile = null;
+
+ private $metaFile = null;
+
+ protected function setUp()
+ {
+ $this->resourceFile = tempnam(sys_get_temp_dir(), '_resource');
+ $this->cacheFile = tempnam(sys_get_temp_dir(), 'config_');
+ $this->metaFile = $this->cacheFile.'.meta';
+
+ $this->makeCacheFresh();
+ $this->generateMetaFile();
+ }
+
+ protected function tearDown()
+ {
+ $files = array($this->cacheFile, $this->metaFile, $this->resourceFile);
+
+ foreach ($files as $file) {
+ if (file_exists($file)) {
+ unlink($file);
+ }
+ }
+ }
+
+ public function testGetPath()
+ {
+ $cache = new ConfigCache($this->cacheFile, true);
+
+ $this->assertSame($this->cacheFile, $cache->getPath());
+ }
+
+ public function testCacheIsNotFreshIfFileDoesNotExist()
+ {
+ unlink($this->cacheFile);
+
+ $cache = new ConfigCache($this->cacheFile, false);
+
+ $this->assertFalse($cache->isFresh());
+ }
+
+ public function testCacheIsAlwaysFreshIfFileExistsWithDebugDisabled()
+ {
+ $this->makeCacheStale();
+
+ $cache = new ConfigCache($this->cacheFile, false);
+
+ $this->assertTrue($cache->isFresh());
+ }
+
+ public function testCacheIsNotFreshWithoutMetaFile()
+ {
+ unlink($this->metaFile);
+
+ $cache = new ConfigCache($this->cacheFile, true);
+
+ $this->assertFalse($cache->isFresh());
+ }
+
+ public function testCacheIsFreshIfResourceIsFresh()
+ {
+ $cache = new ConfigCache($this->cacheFile, true);
+
+ $this->assertTrue($cache->isFresh());
+ }
+
+ public function testCacheIsNotFreshIfOneOfTheResourcesIsNotFresh()
+ {
+ $this->makeCacheStale();
+
+ $cache = new ConfigCache($this->cacheFile, true);
+
+ $this->assertFalse($cache->isFresh());
+ }
+
+ public function testWriteDumpsFile()
+ {
+ unlink($this->cacheFile);
+ unlink($this->metaFile);
+
+ $cache = new ConfigCache($this->cacheFile, false);
+ $cache->write('FOOBAR');
+
+ $this->assertFileExists($this->cacheFile, 'Cache file is created');
+ $this->assertSame('FOOBAR', file_get_contents($this->cacheFile));
+ $this->assertFileNotExists($this->metaFile, 'Meta file is not created');
+ }
+
+ public function testWriteDumpsMetaFileWithDebugEnabled()
+ {
+ unlink($this->cacheFile);
+ unlink($this->metaFile);
+
+ $metadata = array(new FileResource($this->resourceFile));
+
+ $cache = new ConfigCache($this->cacheFile, true);
+ $cache->write('FOOBAR', $metadata);
+
+ $this->assertFileExists($this->cacheFile, 'Cache file is created');
+ $this->assertFileExists($this->metaFile, 'Meta file is created');
+ $this->assertSame(serialize($metadata), file_get_contents($this->metaFile));
+ }
+
+ private function makeCacheFresh()
+ {
+ touch($this->resourceFile, filemtime($this->cacheFile) - 3600);
+ }
+
+ private function makeCacheStale()
+ {
+ touch($this->cacheFile, filemtime($this->resourceFile) - 3600);
+ }
+
+ private function generateMetaFile()
+ {
+ file_put_contents($this->metaFile, serialize(array(new FileResource($this->resourceFile))));
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/ArrayNodeTest.php b/vendor/symfony/config/Tests/Definition/ArrayNodeTest.php
new file mode 100755
index 0000000..291c2fd
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/ArrayNodeTest.php
@@ -0,0 +1,160 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition;
+
+use Symfony\Component\Config\Definition\ArrayNode;
+use Symfony\Component\Config\Definition\ScalarNode;
+
+class ArrayNodeTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidTypeException
+ */
+ public function testNormalizeThrowsExceptionWhenFalseIsNotAllowed()
+ {
+ $node = new ArrayNode('root');
+ $node->normalize(false);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ * @expectedExceptionMessage Unrecognized option "foo" under "root"
+ */
+ public function testExceptionThrownOnUnrecognizedChild()
+ {
+ $node = new ArrayNode('root');
+ $node->normalize(array('foo' => 'bar'));
+ }
+
+ /**
+ * Tests that no exception is thrown for an unrecognized child if the
+ * ignoreExtraKeys option is set to true.
+ *
+ * Related to testExceptionThrownOnUnrecognizedChild
+ */
+ public function testIgnoreExtraKeysNoException()
+ {
+ $node = new ArrayNode('roo');
+ $node->setIgnoreExtraKeys(true);
+
+ $node->normalize(array('foo' => 'bar'));
+ $this->assertTrue(true, 'No exception was thrown when setIgnoreExtraKeys is true');
+ }
+
+ /**
+ * @dataProvider getPreNormalizationTests
+ */
+ public function testPreNormalize($denormalized, $normalized)
+ {
+ $node = new ArrayNode('foo');
+
+ $r = new \ReflectionMethod($node, 'preNormalize');
+ $r->setAccessible(true);
+
+ $this->assertSame($normalized, $r->invoke($node, $denormalized));
+ }
+
+ public function getPreNormalizationTests()
+ {
+ return array(
+ array(
+ array('foo-bar' => 'foo'),
+ array('foo_bar' => 'foo'),
+ ),
+ array(
+ array('foo-bar_moo' => 'foo'),
+ array('foo-bar_moo' => 'foo'),
+ ),
+ array(
+ array('foo-bar' => null, 'foo_bar' => 'foo'),
+ array('foo-bar' => null, 'foo_bar' => 'foo'),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider getZeroNamedNodeExamplesData
+ */
+ public function testNodeNameCanBeZero($denormalized, $normalized)
+ {
+ $zeroNode = new ArrayNode(0);
+ $zeroNode->addChild(new ScalarNode('name'));
+ $fiveNode = new ArrayNode(5);
+ $fiveNode->addChild(new ScalarNode(0));
+ $fiveNode->addChild(new ScalarNode('new_key'));
+ $rootNode = new ArrayNode('root');
+ $rootNode->addChild($zeroNode);
+ $rootNode->addChild($fiveNode);
+ $rootNode->addChild(new ScalarNode('string_key'));
+ $r = new \ReflectionMethod($rootNode, 'normalizeValue');
+ $r->setAccessible(true);
+
+ $this->assertSame($normalized, $r->invoke($rootNode, $denormalized));
+ }
+
+ public function getZeroNamedNodeExamplesData()
+ {
+ return array(
+ array(
+ array(
+ 0 => array(
+ 'name' => 'something',
+ ),
+ 5 => array(
+ 0 => 'this won\'t work too',
+ 'new_key' => 'some other value',
+ ),
+ 'string_key' => 'just value',
+ ),
+ array(
+ 0 => array(
+ 'name' => 'something',
+ ),
+ 5 => array(
+ 0 => 'this won\'t work too',
+ 'new_key' => 'some other value',
+ ),
+ 'string_key' => 'just value',
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider getPreNormalizedNormalizedOrderedData
+ */
+ public function testChildrenOrderIsMaintainedOnNormalizeValue($prenormalized, $normalized)
+ {
+ $scalar1 = new ScalarNode('1');
+ $scalar2 = new ScalarNode('2');
+ $scalar3 = new ScalarNode('3');
+ $node = new ArrayNode('foo');
+ $node->addChild($scalar1);
+ $node->addChild($scalar3);
+ $node->addChild($scalar2);
+
+ $r = new \ReflectionMethod($node, 'normalizeValue');
+ $r->setAccessible(true);
+
+ $this->assertSame($normalized, $r->invoke($node, $prenormalized));
+ }
+
+ public function getPreNormalizedNormalizedOrderedData()
+ {
+ return array(
+ array(
+ array('2' => 'two', '1' => 'one', '3' => 'three'),
+ array('2' => 'two', '1' => 'one', '3' => 'three'),
+ ),
+ );
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/BooleanNodeTest.php b/vendor/symfony/config/Tests/Definition/BooleanNodeTest.php
new file mode 100755
index 0000000..b0cb079
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/BooleanNodeTest.php
@@ -0,0 +1,73 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition;
+
+use Symfony\Component\Config\Definition\BooleanNode;
+
+class BooleanNodeTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getValidValues
+ */
+ public function testNormalize($value)
+ {
+ $node = new BooleanNode('test');
+ $this->assertSame($value, $node->normalize($value));
+ }
+
+ /**
+ * @dataProvider getValidValues
+ *
+ * @param bool $value
+ */
+ public function testValidNonEmptyValues($value)
+ {
+ $node = new BooleanNode('test');
+ $node->setAllowEmptyValue(false);
+
+ $this->assertSame($value, $node->finalize($value));
+ }
+
+ public function getValidValues()
+ {
+ return array(
+ array(false),
+ array(true),
+ );
+ }
+
+ /**
+ * @dataProvider getInvalidValues
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidTypeException
+ */
+ public function testNormalizeThrowsExceptionOnInvalidValues($value)
+ {
+ $node = new BooleanNode('test');
+ $node->normalize($value);
+ }
+
+ public function getInvalidValues()
+ {
+ return array(
+ array(null),
+ array(''),
+ array('foo'),
+ array(0),
+ array(1),
+ array(0.0),
+ array(0.1),
+ array(array()),
+ array(array('foo' => 'bar')),
+ array(new \stdClass()),
+ );
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php b/vendor/symfony/config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php
new file mode 100755
index 0000000..e75ed34
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php
@@ -0,0 +1,207 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition\Builder;
+
+use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
+use Symfony\Component\Config\Definition\Processor;
+use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition;
+use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
+
+class ArrayNodeDefinitionTest extends \PHPUnit_Framework_TestCase
+{
+ public function testAppendingSomeNode()
+ {
+ $parent = new ArrayNodeDefinition('root');
+ $child = new ScalarNodeDefinition('child');
+
+ $parent
+ ->children()
+ ->scalarNode('foo')->end()
+ ->scalarNode('bar')->end()
+ ->end()
+ ->append($child);
+
+ $this->assertCount(3, $this->getField($parent, 'children'));
+ $this->assertTrue(in_array($child, $this->getField($parent, 'children')));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidDefinitionException
+ * @dataProvider providePrototypeNodeSpecificCalls
+ */
+ public function testPrototypeNodeSpecificOption($method, $args)
+ {
+ $node = new ArrayNodeDefinition('root');
+
+ call_user_func_array(array($node, $method), $args);
+
+ $node->getNode();
+ }
+
+ public function providePrototypeNodeSpecificCalls()
+ {
+ return array(
+ array('defaultValue', array(array())),
+ array('addDefaultChildrenIfNoneSet', array()),
+ array('requiresAtLeastOneElement', array()),
+ array('useAttributeAsKey', array('foo')),
+ );
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidDefinitionException
+ */
+ public function testConcreteNodeSpecificOption()
+ {
+ $node = new ArrayNodeDefinition('root');
+ $node
+ ->addDefaultsIfNotSet()
+ ->prototype('array')
+ ;
+ $node->getNode();
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidDefinitionException
+ */
+ public function testPrototypeNodesCantHaveADefaultValueWhenUsingDefaultChildren()
+ {
+ $node = new ArrayNodeDefinition('root');
+ $node
+ ->defaultValue(array())
+ ->addDefaultChildrenIfNoneSet('foo')
+ ->prototype('array')
+ ;
+ $node->getNode();
+ }
+
+ public function testPrototypedArrayNodeDefaultWhenUsingDefaultChildren()
+ {
+ $node = new ArrayNodeDefinition('root');
+ $node
+ ->addDefaultChildrenIfNoneSet()
+ ->prototype('array')
+ ;
+ $tree = $node->getNode();
+ $this->assertEquals(array(array()), $tree->getDefaultValue());
+ }
+
+ /**
+ * @dataProvider providePrototypedArrayNodeDefaults
+ */
+ public function testPrototypedArrayNodeDefault($args, $shouldThrowWhenUsingAttrAsKey, $shouldThrowWhenNotUsingAttrAsKey, $defaults)
+ {
+ $node = new ArrayNodeDefinition('root');
+ $node
+ ->addDefaultChildrenIfNoneSet($args)
+ ->prototype('array')
+ ;
+
+ try {
+ $tree = $node->getNode();
+ $this->assertFalse($shouldThrowWhenNotUsingAttrAsKey);
+ $this->assertEquals($defaults, $tree->getDefaultValue());
+ } catch (InvalidDefinitionException $e) {
+ $this->assertTrue($shouldThrowWhenNotUsingAttrAsKey);
+ }
+
+ $node = new ArrayNodeDefinition('root');
+ $node
+ ->useAttributeAsKey('attr')
+ ->addDefaultChildrenIfNoneSet($args)
+ ->prototype('array')
+ ;
+
+ try {
+ $tree = $node->getNode();
+ $this->assertFalse($shouldThrowWhenUsingAttrAsKey);
+ $this->assertEquals($defaults, $tree->getDefaultValue());
+ } catch (InvalidDefinitionException $e) {
+ $this->assertTrue($shouldThrowWhenUsingAttrAsKey);
+ }
+ }
+
+ public function providePrototypedArrayNodeDefaults()
+ {
+ return array(
+ array(null, true, false, array(array())),
+ array(2, true, false, array(array(), array())),
+ array('2', false, true, array('2' => array())),
+ array('foo', false, true, array('foo' => array())),
+ array(array('foo'), false, true, array('foo' => array())),
+ array(array('foo', 'bar'), false, true, array('foo' => array(), 'bar' => array())),
+ );
+ }
+
+ public function testNestedPrototypedArrayNodes()
+ {
+ $node = new ArrayNodeDefinition('root');
+ $node
+ ->addDefaultChildrenIfNoneSet()
+ ->prototype('array')
+ ->prototype('array')
+ ;
+ $node->getNode();
+ }
+
+ public function testEnabledNodeDefaults()
+ {
+ $node = new ArrayNodeDefinition('root');
+ $node
+ ->canBeEnabled()
+ ->children()
+ ->scalarNode('foo')->defaultValue('bar')->end()
+ ;
+
+ $this->assertEquals(array('enabled' => false, 'foo' => 'bar'), $node->getNode()->getDefaultValue());
+ }
+
+ /**
+ * @dataProvider getEnableableNodeFixtures
+ */
+ public function testTrueEnableEnabledNode($expected, $config, $message)
+ {
+ $processor = new Processor();
+ $node = new ArrayNodeDefinition('root');
+ $node
+ ->canBeEnabled()
+ ->children()
+ ->scalarNode('foo')->defaultValue('bar')->end()
+ ;
+
+ $this->assertEquals(
+ $expected,
+ $processor->process($node->getNode(), $config),
+ $message
+ );
+ }
+
+ public function getEnableableNodeFixtures()
+ {
+ return array(
+ array(array('enabled' => true, 'foo' => 'bar'), array(true), 'true enables an enableable node'),
+ array(array('enabled' => true, 'foo' => 'bar'), array(null), 'null enables an enableable node'),
+ array(array('enabled' => true, 'foo' => 'bar'), array(array('enabled' => true)), 'An enableable node can be enabled'),
+ array(array('enabled' => true, 'foo' => 'baz'), array(array('foo' => 'baz')), 'any configuration enables an enableable node'),
+ array(array('enabled' => false, 'foo' => 'baz'), array(array('foo' => 'baz', 'enabled' => false)), 'An enableable node can be disabled'),
+ array(array('enabled' => false, 'foo' => 'bar'), array(false), 'false disables an enableable node'),
+ );
+ }
+
+ protected function getField($object, $field)
+ {
+ $reflection = new \ReflectionProperty($object, $field);
+ $reflection->setAccessible(true);
+
+ return $reflection->getValue($object);
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/Builder/EnumNodeDefinitionTest.php b/vendor/symfony/config/Tests/Definition/Builder/EnumNodeDefinitionTest.php
new file mode 100755
index 0000000..69f7fcf
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/Builder/EnumNodeDefinitionTest.php
@@ -0,0 +1,46 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition\Builder;
+
+use Symfony\Component\Config\Definition\Builder\EnumNodeDefinition;
+
+class EnumNodeDefinitionTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage ->values() must be called with at least two distinct values.
+ */
+ public function testNoDistinctValues()
+ {
+ $def = new EnumNodeDefinition('foo');
+ $def->values(array('foo', 'foo'));
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ * @expectedExceptionMessage You must call ->values() on enum nodes.
+ */
+ public function testNoValuesPassed()
+ {
+ $def = new EnumNodeDefinition('foo');
+ $def->getNode();
+ }
+
+ public function testGetNode()
+ {
+ $def = new EnumNodeDefinition('foo');
+ $def->values(array('foo', 'bar'));
+
+ $node = $def->getNode();
+ $this->assertEquals(array('foo', 'bar'), $node->getValues());
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/Builder/ExprBuilderTest.php b/vendor/symfony/config/Tests/Definition/Builder/ExprBuilderTest.php
new file mode 100755
index 0000000..147bf13
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/Builder/ExprBuilderTest.php
@@ -0,0 +1,215 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition\Builder;
+
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+
+class ExprBuilderTest extends \PHPUnit_Framework_TestCase
+{
+ public function testAlwaysExpression()
+ {
+ $test = $this->getTestBuilder()
+ ->always($this->returnClosure('new_value'))
+ ->end();
+
+ $this->assertFinalizedValueIs('new_value', $test);
+ }
+
+ public function testIfTrueExpression()
+ {
+ $test = $this->getTestBuilder()
+ ->ifTrue()
+ ->then($this->returnClosure('new_value'))
+ ->end();
+ $this->assertFinalizedValueIs('new_value', $test, array('key' => true));
+
+ $test = $this->getTestBuilder()
+ ->ifTrue(function ($v) { return true; })
+ ->then($this->returnClosure('new_value'))
+ ->end();
+ $this->assertFinalizedValueIs('new_value', $test);
+
+ $test = $this->getTestBuilder()
+ ->ifTrue(function ($v) { return false; })
+ ->then($this->returnClosure('new_value'))
+ ->end();
+ $this->assertFinalizedValueIs('value', $test);
+ }
+
+ public function testIfStringExpression()
+ {
+ $test = $this->getTestBuilder()
+ ->ifString()
+ ->then($this->returnClosure('new_value'))
+ ->end();
+ $this->assertFinalizedValueIs('new_value', $test);
+
+ $test = $this->getTestBuilder()
+ ->ifString()
+ ->then($this->returnClosure('new_value'))
+ ->end();
+ $this->assertFinalizedValueIs(45, $test, array('key' => 45));
+ }
+
+ public function testIfNullExpression()
+ {
+ $test = $this->getTestBuilder()
+ ->ifNull()
+ ->then($this->returnClosure('new_value'))
+ ->end();
+ $this->assertFinalizedValueIs('new_value', $test, array('key' => null));
+
+ $test = $this->getTestBuilder()
+ ->ifNull()
+ ->then($this->returnClosure('new_value'))
+ ->end();
+ $this->assertFinalizedValueIs('value', $test);
+ }
+
+ public function testIfArrayExpression()
+ {
+ $test = $this->getTestBuilder()
+ ->ifArray()
+ ->then($this->returnClosure('new_value'))
+ ->end();
+ $this->assertFinalizedValueIs('new_value', $test, array('key' => array()));
+
+ $test = $this->getTestBuilder()
+ ->ifArray()
+ ->then($this->returnClosure('new_value'))
+ ->end();
+ $this->assertFinalizedValueIs('value', $test);
+ }
+
+ public function testIfInArrayExpression()
+ {
+ $test = $this->getTestBuilder()
+ ->ifInArray(array('foo', 'bar', 'value'))
+ ->then($this->returnClosure('new_value'))
+ ->end();
+ $this->assertFinalizedValueIs('new_value', $test);
+
+ $test = $this->getTestBuilder()
+ ->ifInArray(array('foo', 'bar'))
+ ->then($this->returnClosure('new_value'))
+ ->end();
+ $this->assertFinalizedValueIs('value', $test);
+ }
+
+ public function testIfNotInArrayExpression()
+ {
+ $test = $this->getTestBuilder()
+ ->ifNotInArray(array('foo', 'bar'))
+ ->then($this->returnClosure('new_value'))
+ ->end();
+ $this->assertFinalizedValueIs('new_value', $test);
+
+ $test = $this->getTestBuilder()
+ ->ifNotInArray(array('foo', 'bar', 'value_from_config'))
+ ->then($this->returnClosure('new_value'))
+ ->end();
+ $this->assertFinalizedValueIs('new_value', $test);
+ }
+
+ public function testThenEmptyArrayExpression()
+ {
+ $test = $this->getTestBuilder()
+ ->ifString()
+ ->thenEmptyArray()
+ ->end();
+ $this->assertFinalizedValueIs(array(), $test);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ */
+ public function testThenInvalid()
+ {
+ $test = $this->getTestBuilder()
+ ->ifString()
+ ->thenInvalid('Invalid value')
+ ->end();
+ $this->finalizeTestBuilder($test);
+ }
+
+ public function testThenUnsetExpression()
+ {
+ $test = $this->getTestBuilder()
+ ->ifString()
+ ->thenUnset()
+ ->end();
+ $this->assertEquals(array(), $this->finalizeTestBuilder($test));
+ }
+
+ /**
+ * Create a test treebuilder with a variable node, and init the validation.
+ *
+ * @return TreeBuilder
+ */
+ protected function getTestBuilder()
+ {
+ $builder = new TreeBuilder();
+
+ return $builder
+ ->root('test')
+ ->children()
+ ->variableNode('key')
+ ->validate()
+ ;
+ }
+
+ /**
+ * Close the validation process and finalize with the given config.
+ *
+ * @param TreeBuilder $testBuilder The tree builder to finalize
+ * @param array $config The config you want to use for the finalization, if nothing provided
+ * a simple array('key'=>'value') will be used
+ *
+ * @return array The finalized config values
+ */
+ protected function finalizeTestBuilder($testBuilder, $config = null)
+ {
+ return $testBuilder
+ ->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ->finalize(null === $config ? array('key' => 'value') : $config)
+ ;
+ }
+
+ /**
+ * Return a closure that will return the given value.
+ *
+ * @param mixed $val The value that the closure must return
+ *
+ * @return \Closure
+ */
+ protected function returnClosure($val)
+ {
+ return function ($v) use ($val) {
+ return $val;
+ };
+ }
+
+ /**
+ * Assert that the given test builder, will return the given value.
+ *
+ * @param mixed $value The value to test
+ * @param TreeBuilder $treeBuilder The tree builder to finalize
+ * @param mixed $config The config values that new to be finalized
+ */
+ protected function assertFinalizedValueIs($value, $treeBuilder, $config = null)
+ {
+ $this->assertEquals(array('key' => $value), $this->finalizeTestBuilder($treeBuilder, $config));
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/Builder/NodeBuilderTest.php b/vendor/symfony/config/Tests/Definition/Builder/NodeBuilderTest.php
new file mode 100755
index 0000000..22c399c
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/Builder/NodeBuilderTest.php
@@ -0,0 +1,94 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition\Builder;
+
+use Symfony\Component\Config\Definition\Builder\NodeBuilder as BaseNodeBuilder;
+use Symfony\Component\Config\Definition\Builder\VariableNodeDefinition as BaseVariableNodeDefinition;
+
+class NodeBuilderTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @expectedException \RuntimeException
+ */
+ public function testThrowsAnExceptionWhenTryingToCreateANonRegisteredNodeType()
+ {
+ $builder = new BaseNodeBuilder();
+ $builder->node('', 'foobar');
+ }
+
+ /**
+ * @expectedException \RuntimeException
+ */
+ public function testThrowsAnExceptionWhenTheNodeClassIsNotFound()
+ {
+ $builder = new BaseNodeBuilder();
+ $builder
+ ->setNodeClass('noclasstype', '\\foo\\bar\\noclass')
+ ->node('', 'noclasstype');
+ }
+
+ public function testAddingANewNodeType()
+ {
+ $class = __NAMESPACE__.'\\SomeNodeDefinition';
+
+ $builder = new BaseNodeBuilder();
+ $node = $builder
+ ->setNodeClass('newtype', $class)
+ ->node('', 'newtype');
+
+ $this->assertInstanceOf($class, $node);
+ }
+
+ public function testOverridingAnExistingNodeType()
+ {
+ $class = __NAMESPACE__.'\\SomeNodeDefinition';
+
+ $builder = new BaseNodeBuilder();
+ $node = $builder
+ ->setNodeClass('variable', $class)
+ ->node('', 'variable');
+
+ $this->assertInstanceOf($class, $node);
+ }
+
+ public function testNodeTypesAreNotCaseSensitive()
+ {
+ $builder = new BaseNodeBuilder();
+
+ $node1 = $builder->node('', 'VaRiAbLe');
+ $node2 = $builder->node('', 'variable');
+
+ $this->assertInstanceOf(get_class($node1), $node2);
+
+ $builder->setNodeClass('CuStOm', __NAMESPACE__.'\\SomeNodeDefinition');
+
+ $node1 = $builder->node('', 'CUSTOM');
+ $node2 = $builder->node('', 'custom');
+
+ $this->assertInstanceOf(get_class($node1), $node2);
+ }
+
+ public function testNumericNodeCreation()
+ {
+ $builder = new BaseNodeBuilder();
+
+ $node = $builder->integerNode('foo')->min(3)->max(5);
+ $this->assertInstanceOf('Symfony\Component\Config\Definition\Builder\IntegerNodeDefinition', $node);
+
+ $node = $builder->floatNode('bar')->min(3.0)->max(5.0);
+ $this->assertInstanceOf('Symfony\Component\Config\Definition\Builder\FloatNodeDefinition', $node);
+ }
+}
+
+class SomeNodeDefinition extends BaseVariableNodeDefinition
+{
+}
diff --git a/vendor/symfony/config/Tests/Definition/Builder/NumericNodeDefinitionTest.php b/vendor/symfony/config/Tests/Definition/Builder/NumericNodeDefinitionTest.php
new file mode 100755
index 0000000..cf0813a
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/Builder/NumericNodeDefinitionTest.php
@@ -0,0 +1,93 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition\Builder;
+
+use Symfony\Component\Config\Definition\Builder\IntegerNodeDefinition as NumericNodeDefinition;
+use Symfony\Component\Config\Definition\Builder\IntegerNodeDefinition;
+use Symfony\Component\Config\Definition\Builder\FloatNodeDefinition;
+
+class NumericNodeDefinitionTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage You cannot define a min(4) as you already have a max(3)
+ */
+ public function testIncoherentMinAssertion()
+ {
+ $def = new NumericNodeDefinition('foo');
+ $def->max(3)->min(4);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage You cannot define a max(2) as you already have a min(3)
+ */
+ public function testIncoherentMaxAssertion()
+ {
+ $node = new NumericNodeDefinition('foo');
+ $node->min(3)->max(2);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ * @expectedExceptionMessage The value 4 is too small for path "foo". Should be greater than or equal to 5
+ */
+ public function testIntegerMinAssertion()
+ {
+ $def = new IntegerNodeDefinition('foo');
+ $def->min(5)->getNode()->finalize(4);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ * @expectedExceptionMessage The value 4 is too big for path "foo". Should be less than or equal to 3
+ */
+ public function testIntegerMaxAssertion()
+ {
+ $def = new IntegerNodeDefinition('foo');
+ $def->max(3)->getNode()->finalize(4);
+ }
+
+ public function testIntegerValidMinMaxAssertion()
+ {
+ $def = new IntegerNodeDefinition('foo');
+ $node = $def->min(3)->max(7)->getNode();
+ $this->assertEquals(4, $node->finalize(4));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ * @expectedExceptionMessage The value 400 is too small for path "foo". Should be greater than or equal to 500
+ */
+ public function testFloatMinAssertion()
+ {
+ $def = new FloatNodeDefinition('foo');
+ $def->min(5E2)->getNode()->finalize(4e2);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ * @expectedExceptionMessage The value 4.3 is too big for path "foo". Should be less than or equal to 0.3
+ */
+ public function testFloatMaxAssertion()
+ {
+ $def = new FloatNodeDefinition('foo');
+ $def->max(0.3)->getNode()->finalize(4.3);
+ }
+
+ public function testFloatValidMinMaxAssertion()
+ {
+ $def = new FloatNodeDefinition('foo');
+ $node = $def->min(3.0)->max(7e2)->getNode();
+ $this->assertEquals(4.5, $node->finalize(4.5));
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/Builder/TreeBuilderTest.php b/vendor/symfony/config/Tests/Definition/Builder/TreeBuilderTest.php
new file mode 100755
index 0000000..00e27c6
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/Builder/TreeBuilderTest.php
@@ -0,0 +1,126 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition\Builder;
+
+use Symfony\Component\Config\Tests\Definition\Builder\NodeBuilder as CustomNodeBuilder;
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+
+require __DIR__.'/../../Fixtures/Builder/NodeBuilder.php';
+require __DIR__.'/../../Fixtures/Builder/BarNodeDefinition.php';
+require __DIR__.'/../../Fixtures/Builder/VariableNodeDefinition.php';
+
+class TreeBuilderTest extends \PHPUnit_Framework_TestCase
+{
+ public function testUsingACustomNodeBuilder()
+ {
+ $builder = new TreeBuilder();
+ $root = $builder->root('custom', 'array', new CustomNodeBuilder());
+
+ $nodeBuilder = $root->children();
+
+ $this->assertInstanceOf('Symfony\Component\Config\Tests\Definition\Builder\NodeBuilder', $nodeBuilder);
+
+ $nodeBuilder = $nodeBuilder->arrayNode('deeper')->children();
+
+ $this->assertInstanceOf('Symfony\Component\Config\Tests\Definition\Builder\NodeBuilder', $nodeBuilder);
+ }
+
+ public function testOverrideABuiltInNodeType()
+ {
+ $builder = new TreeBuilder();
+ $root = $builder->root('override', 'array', new CustomNodeBuilder());
+
+ $definition = $root->children()->variableNode('variable');
+
+ $this->assertInstanceOf('Symfony\Component\Config\Tests\Definition\Builder\VariableNodeDefinition', $definition);
+ }
+
+ public function testAddANodeType()
+ {
+ $builder = new TreeBuilder();
+ $root = $builder->root('override', 'array', new CustomNodeBuilder());
+
+ $definition = $root->children()->barNode('variable');
+
+ $this->assertInstanceOf('Symfony\Component\Config\Tests\Definition\Builder\BarNodeDefinition', $definition);
+ }
+
+ public function testCreateABuiltInNodeTypeWithACustomNodeBuilder()
+ {
+ $builder = new TreeBuilder();
+ $root = $builder->root('builtin', 'array', new CustomNodeBuilder());
+
+ $definition = $root->children()->booleanNode('boolean');
+
+ $this->assertInstanceOf('Symfony\Component\Config\Definition\Builder\BooleanNodeDefinition', $definition);
+ }
+
+ public function testPrototypedArrayNodeUseTheCustomNodeBuilder()
+ {
+ $builder = new TreeBuilder();
+ $root = $builder->root('override', 'array', new CustomNodeBuilder());
+
+ $root->prototype('bar')->end();
+ }
+
+ public function testAnExtendedNodeBuilderGetsPropagatedToTheChildren()
+ {
+ $builder = new TreeBuilder();
+
+ $builder->root('propagation')
+ ->children()
+ ->setNodeClass('extended', 'Symfony\Component\Config\Tests\Definition\Builder\VariableNodeDefinition')
+ ->node('foo', 'extended')->end()
+ ->arrayNode('child')
+ ->children()
+ ->node('foo', 'extended')
+ ->end()
+ ->end()
+ ->end()
+ ->end();
+ }
+
+ public function testDefinitionInfoGetsTransferredToNode()
+ {
+ $builder = new TreeBuilder();
+
+ $builder->root('test')->info('root info')
+ ->children()
+ ->node('child', 'variable')->info('child info')->defaultValue('default')
+ ->end()
+ ->end();
+
+ $tree = $builder->buildTree();
+ $children = $tree->getChildren();
+
+ $this->assertEquals('root info', $tree->getInfo());
+ $this->assertEquals('child info', $children['child']->getInfo());
+ }
+
+ public function testDefinitionExampleGetsTransferredToNode()
+ {
+ $builder = new TreeBuilder();
+
+ $builder->root('test')
+ ->example(array('key' => 'value'))
+ ->children()
+ ->node('child', 'variable')->info('child info')->defaultValue('default')->example('example')
+ ->end()
+ ->end();
+
+ $tree = $builder->buildTree();
+ $children = $tree->getChildren();
+
+ $this->assertTrue(is_array($tree->getExample()));
+ $this->assertEquals('example', $children['child']->getExample());
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/Dumper/XmlReferenceDumperTest.php b/vendor/symfony/config/Tests/Definition/Dumper/XmlReferenceDumperTest.php
new file mode 100755
index 0000000..699751d
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/Dumper/XmlReferenceDumperTest.php
@@ -0,0 +1,81 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition\Dumper;
+
+use Symfony\Component\Config\Definition\Dumper\XmlReferenceDumper;
+use Symfony\Component\Config\Tests\Fixtures\Configuration\ExampleConfiguration;
+
+class XmlReferenceDumperTest extends \PHPUnit_Framework_TestCase
+{
+ public function testDumper()
+ {
+ $configuration = new ExampleConfiguration();
+
+ $dumper = new XmlReferenceDumper();
+ $this->assertEquals($this->getConfigurationAsString(), $dumper->dump($configuration));
+ }
+
+ public function testNamespaceDumper()
+ {
+ $configuration = new ExampleConfiguration();
+
+ $dumper = new XmlReferenceDumper();
+ $this->assertEquals(str_replace('http://example.org/schema/dic/acme_root', 'http://symfony.com/schema/dic/symfony', $this->getConfigurationAsString()), $dumper->dump($configuration, 'http://symfony.com/schema/dic/symfony'));
+ }
+
+ private function getConfigurationAsString()
+ {
+ return str_replace("\n", PHP_EOL, <<
+
+
+
+
+
+
+
+
+
+ scalar value
+
+
+
+
+
+
+EOL
+ );
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/Dumper/YamlReferenceDumperTest.php b/vendor/symfony/config/Tests/Definition/Dumper/YamlReferenceDumperTest.php
new file mode 100755
index 0000000..4775235
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/Dumper/YamlReferenceDumperTest.php
@@ -0,0 +1,67 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition\Dumper;
+
+use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;
+use Symfony\Component\Config\Tests\Fixtures\Configuration\ExampleConfiguration;
+
+class YamlReferenceDumperTest extends \PHPUnit_Framework_TestCase
+{
+ public function testDumper()
+ {
+ $configuration = new ExampleConfiguration();
+
+ $dumper = new YamlReferenceDumper();
+
+ $this->markTestIncomplete('The Yaml Dumper currently does not support prototyped arrays');
+ $this->assertEquals($this->getConfigurationAsString(), $dumper->dump($configuration));
+ }
+
+ private function getConfigurationAsString()
+ {
+ return <<
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition;
+
+use Symfony\Component\Config\Definition\EnumNode;
+
+class EnumNodeTest extends \PHPUnit_Framework_TestCase
+{
+ public function testFinalizeValue()
+ {
+ $node = new EnumNode('foo', null, array('foo', 'bar'));
+ $this->assertSame('foo', $node->finalize('foo'));
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testConstructionWithOneValue()
+ {
+ new EnumNode('foo', null, array('foo', 'foo'));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ * @expectedExceptionMessage The value "foobar" is not allowed for path "foo". Permissible values: "foo", "bar"
+ */
+ public function testFinalizeWithInvalidValue()
+ {
+ $node = new EnumNode('foo', null, array('foo', 'bar'));
+ $node->finalize('foobar');
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/FinalizationTest.php b/vendor/symfony/config/Tests/Definition/FinalizationTest.php
new file mode 100755
index 0000000..19fc347
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/FinalizationTest.php
@@ -0,0 +1,73 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition;
+
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+use Symfony\Component\Config\Definition\Processor;
+use Symfony\Component\Config\Definition\NodeInterface;
+
+class FinalizationTest extends \PHPUnit_Framework_TestCase
+{
+ public function testUnsetKeyWithDeepHierarchy()
+ {
+ $tb = new TreeBuilder();
+ $tree = $tb
+ ->root('config', 'array')
+ ->children()
+ ->node('level1', 'array')
+ ->canBeUnset()
+ ->children()
+ ->node('level2', 'array')
+ ->canBeUnset()
+ ->children()
+ ->node('somevalue', 'scalar')->end()
+ ->node('anothervalue', 'scalar')->end()
+ ->end()
+ ->end()
+ ->node('level1_scalar', 'scalar')->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ $a = array(
+ 'level1' => array(
+ 'level2' => array(
+ 'somevalue' => 'foo',
+ 'anothervalue' => 'bar',
+ ),
+ 'level1_scalar' => 'foo',
+ ),
+ );
+
+ $b = array(
+ 'level1' => array(
+ 'level2' => false,
+ ),
+ );
+
+ $this->assertEquals(array(
+ 'level1' => array(
+ 'level1_scalar' => 'foo',
+ ),
+ ), $this->process($tree, array($a, $b)));
+ }
+
+ protected function process(NodeInterface $tree, array $configs)
+ {
+ $processor = new Processor();
+
+ return $processor->process($tree, $configs);
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/FloatNodeTest.php b/vendor/symfony/config/Tests/Definition/FloatNodeTest.php
new file mode 100755
index 0000000..84afd6c
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/FloatNodeTest.php
@@ -0,0 +1,77 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition;
+
+use Symfony\Component\Config\Definition\FloatNode;
+
+class FloatNodeTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getValidValues
+ */
+ public function testNormalize($value)
+ {
+ $node = new FloatNode('test');
+ $this->assertSame($value, $node->normalize($value));
+ }
+
+ /**
+ * @dataProvider getValidValues
+ *
+ * @param int $value
+ */
+ public function testValidNonEmptyValues($value)
+ {
+ $node = new FloatNode('test');
+ $node->setAllowEmptyValue(false);
+
+ $this->assertSame($value, $node->finalize($value));
+ }
+
+ public function getValidValues()
+ {
+ return array(
+ array(1798.0),
+ array(-678.987),
+ array(12.56E45),
+ array(0.0),
+ // Integer are accepted too, they will be cast
+ array(17),
+ array(-10),
+ array(0),
+ );
+ }
+
+ /**
+ * @dataProvider getInvalidValues
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidTypeException
+ */
+ public function testNormalizeThrowsExceptionOnInvalidValues($value)
+ {
+ $node = new FloatNode('test');
+ $node->normalize($value);
+ }
+
+ public function getInvalidValues()
+ {
+ return array(
+ array(null),
+ array(''),
+ array('foo'),
+ array(true),
+ array(false),
+ array(array()),
+ array(array('foo' => 'bar')),
+ array(new \stdClass()),
+ );
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/IntegerNodeTest.php b/vendor/symfony/config/Tests/Definition/IntegerNodeTest.php
new file mode 100755
index 0000000..58d2148
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/IntegerNodeTest.php
@@ -0,0 +1,74 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition;
+
+use Symfony\Component\Config\Definition\IntegerNode;
+
+class IntegerNodeTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getValidValues
+ */
+ public function testNormalize($value)
+ {
+ $node = new IntegerNode('test');
+ $this->assertSame($value, $node->normalize($value));
+ }
+
+ /**
+ * @dataProvider getValidValues
+ *
+ * @param int $value
+ */
+ public function testValidNonEmptyValues($value)
+ {
+ $node = new IntegerNode('test');
+ $node->setAllowEmptyValue(false);
+
+ $this->assertSame($value, $node->finalize($value));
+ }
+
+ public function getValidValues()
+ {
+ return array(
+ array(1798),
+ array(-678),
+ array(0),
+ );
+ }
+
+ /**
+ * @dataProvider getInvalidValues
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidTypeException
+ */
+ public function testNormalizeThrowsExceptionOnInvalidValues($value)
+ {
+ $node = new IntegerNode('test');
+ $node->normalize($value);
+ }
+
+ public function getInvalidValues()
+ {
+ return array(
+ array(null),
+ array(''),
+ array('foo'),
+ array(true),
+ array(false),
+ array(0.0),
+ array(0.1),
+ array(array()),
+ array(array('foo' => 'bar')),
+ array(new \stdClass()),
+ );
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/MergeTest.php b/vendor/symfony/config/Tests/Definition/MergeTest.php
new file mode 100755
index 0000000..08ddc32
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/MergeTest.php
@@ -0,0 +1,195 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition;
+
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+
+class MergeTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException
+ */
+ public function testForbiddenOverwrite()
+ {
+ $tb = new TreeBuilder();
+ $tree = $tb
+ ->root('root', 'array')
+ ->children()
+ ->node('foo', 'scalar')
+ ->cannotBeOverwritten()
+ ->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ $a = array(
+ 'foo' => 'bar',
+ );
+
+ $b = array(
+ 'foo' => 'moo',
+ );
+
+ $tree->merge($a, $b);
+ }
+
+ public function testUnsetKey()
+ {
+ $tb = new TreeBuilder();
+ $tree = $tb
+ ->root('root', 'array')
+ ->children()
+ ->node('foo', 'scalar')->end()
+ ->node('bar', 'scalar')->end()
+ ->node('unsettable', 'array')
+ ->canBeUnset()
+ ->children()
+ ->node('foo', 'scalar')->end()
+ ->node('bar', 'scalar')->end()
+ ->end()
+ ->end()
+ ->node('unsetted', 'array')
+ ->canBeUnset()
+ ->prototype('scalar')->end()
+ ->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ $a = array(
+ 'foo' => 'bar',
+ 'unsettable' => array(
+ 'foo' => 'a',
+ 'bar' => 'b',
+ ),
+ 'unsetted' => false,
+ );
+
+ $b = array(
+ 'foo' => 'moo',
+ 'bar' => 'b',
+ 'unsettable' => false,
+ 'unsetted' => array('a', 'b'),
+ );
+
+ $this->assertEquals(array(
+ 'foo' => 'moo',
+ 'bar' => 'b',
+ 'unsettable' => false,
+ 'unsetted' => array('a', 'b'),
+ ), $tree->merge($a, $b));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ */
+ public function testDoesNotAllowNewKeysInSubsequentConfigs()
+ {
+ $tb = new TreeBuilder();
+ $tree = $tb
+ ->root('config', 'array')
+ ->children()
+ ->node('test', 'array')
+ ->disallowNewKeysInSubsequentConfigs()
+ ->useAttributeAsKey('key')
+ ->prototype('array')
+ ->children()
+ ->node('value', 'scalar')->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->buildTree();
+
+ $a = array(
+ 'test' => array(
+ 'a' => array('value' => 'foo'),
+ ),
+ );
+
+ $b = array(
+ 'test' => array(
+ 'b' => array('value' => 'foo'),
+ ),
+ );
+
+ $tree->merge($a, $b);
+ }
+
+ public function testPerformsNoDeepMerging()
+ {
+ $tb = new TreeBuilder();
+
+ $tree = $tb
+ ->root('config', 'array')
+ ->children()
+ ->node('no_deep_merging', 'array')
+ ->performNoDeepMerging()
+ ->children()
+ ->node('foo', 'scalar')->end()
+ ->node('bar', 'scalar')->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ $a = array(
+ 'no_deep_merging' => array(
+ 'foo' => 'a',
+ 'bar' => 'b',
+ ),
+ );
+
+ $b = array(
+ 'no_deep_merging' => array(
+ 'c' => 'd',
+ ),
+ );
+
+ $this->assertEquals(array(
+ 'no_deep_merging' => array(
+ 'c' => 'd',
+ ),
+ ), $tree->merge($a, $b));
+ }
+
+ public function testPrototypeWithoutAKeyAttribute()
+ {
+ $tb = new TreeBuilder();
+
+ $tree = $tb
+ ->root('config', 'array')
+ ->children()
+ ->arrayNode('append_elements')
+ ->prototype('scalar')->end()
+ ->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ $a = array(
+ 'append_elements' => array('a', 'b'),
+ );
+
+ $b = array(
+ 'append_elements' => array('c', 'd'),
+ );
+
+ $this->assertEquals(array('append_elements' => array('a', 'b', 'c', 'd')), $tree->merge($a, $b));
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/NormalizationTest.php b/vendor/symfony/config/Tests/Definition/NormalizationTest.php
new file mode 100755
index 0000000..a896f96
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/NormalizationTest.php
@@ -0,0 +1,229 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition;
+
+use Symfony\Component\Config\Definition\NodeInterface;
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+
+class NormalizationTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getEncoderTests
+ */
+ public function testNormalizeEncoders($denormalized)
+ {
+ $tb = new TreeBuilder();
+ $tree = $tb
+ ->root('root_name', 'array')
+ ->fixXmlConfig('encoder')
+ ->children()
+ ->node('encoders', 'array')
+ ->useAttributeAsKey('class')
+ ->prototype('array')
+ ->beforeNormalization()->ifString()->then(function ($v) { return array('algorithm' => $v); })->end()
+ ->children()
+ ->node('algorithm', 'scalar')->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ $normalized = array(
+ 'encoders' => array(
+ 'foo' => array('algorithm' => 'plaintext'),
+ ),
+ );
+
+ $this->assertNormalized($tree, $denormalized, $normalized);
+ }
+
+ public function getEncoderTests()
+ {
+ $configs = array();
+
+ // XML
+ $configs[] = array(
+ 'encoder' => array(
+ array('class' => 'foo', 'algorithm' => 'plaintext'),
+ ),
+ );
+
+ // XML when only one element of this type
+ $configs[] = array(
+ 'encoder' => array('class' => 'foo', 'algorithm' => 'plaintext'),
+ );
+
+ // YAML/PHP
+ $configs[] = array(
+ 'encoders' => array(
+ array('class' => 'foo', 'algorithm' => 'plaintext'),
+ ),
+ );
+
+ // YAML/PHP
+ $configs[] = array(
+ 'encoders' => array(
+ 'foo' => 'plaintext',
+ ),
+ );
+
+ // YAML/PHP
+ $configs[] = array(
+ 'encoders' => array(
+ 'foo' => array('algorithm' => 'plaintext'),
+ ),
+ );
+
+ return array_map(function ($v) {
+ return array($v);
+ }, $configs);
+ }
+
+ /**
+ * @dataProvider getAnonymousKeysTests
+ */
+ public function testAnonymousKeysArray($denormalized)
+ {
+ $tb = new TreeBuilder();
+ $tree = $tb
+ ->root('root', 'array')
+ ->children()
+ ->node('logout', 'array')
+ ->fixXmlConfig('handler')
+ ->children()
+ ->node('handlers', 'array')
+ ->prototype('scalar')->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ $normalized = array('logout' => array('handlers' => array('a', 'b', 'c')));
+
+ $this->assertNormalized($tree, $denormalized, $normalized);
+ }
+
+ public function getAnonymousKeysTests()
+ {
+ $configs = array();
+
+ $configs[] = array(
+ 'logout' => array(
+ 'handlers' => array('a', 'b', 'c'),
+ ),
+ );
+
+ $configs[] = array(
+ 'logout' => array(
+ 'handler' => array('a', 'b', 'c'),
+ ),
+ );
+
+ return array_map(function ($v) { return array($v); }, $configs);
+ }
+
+ /**
+ * @dataProvider getNumericKeysTests
+ */
+ public function testNumericKeysAsAttributes($denormalized)
+ {
+ $normalized = array(
+ 'thing' => array(42 => array('foo', 'bar'), 1337 => array('baz', 'qux')),
+ );
+
+ $this->assertNormalized($this->getNumericKeysTestTree(), $denormalized, $normalized);
+ }
+
+ public function getNumericKeysTests()
+ {
+ $configs = array();
+
+ $configs[] = array(
+ 'thing' => array(
+ 42 => array('foo', 'bar'), 1337 => array('baz', 'qux'),
+ ),
+ );
+
+ $configs[] = array(
+ 'thing' => array(
+ array('foo', 'bar', 'id' => 42), array('baz', 'qux', 'id' => 1337),
+ ),
+ );
+
+ return array_map(function ($v) { return array($v); }, $configs);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ * @expectedExceptionMessage The attribute "id" must be set for path "root.thing".
+ */
+ public function testNonAssociativeArrayThrowsExceptionIfAttributeNotSet()
+ {
+ $denormalized = array(
+ 'thing' => array(
+ array('foo', 'bar'), array('baz', 'qux'),
+ ),
+ );
+
+ $this->assertNormalized($this->getNumericKeysTestTree(), $denormalized, array());
+ }
+
+ public function testAssociativeArrayPreserveKeys()
+ {
+ $tb = new TreeBuilder();
+ $tree = $tb
+ ->root('root', 'array')
+ ->prototype('array')
+ ->children()
+ ->node('foo', 'scalar')->end()
+ ->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ $data = array('first' => array('foo' => 'bar'));
+
+ $this->assertNormalized($tree, $data, $data);
+ }
+
+ public static function assertNormalized(NodeInterface $tree, $denormalized, $normalized)
+ {
+ self::assertSame($normalized, $tree->normalize($denormalized));
+ }
+
+ private function getNumericKeysTestTree()
+ {
+ $tb = new TreeBuilder();
+ $tree = $tb
+ ->root('root', 'array')
+ ->children()
+ ->node('thing', 'array')
+ ->useAttributeAsKey('id')
+ ->prototype('array')
+ ->prototype('scalar')->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ->buildTree()
+ ;
+
+ return $tree;
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/PrototypedArrayNodeTest.php b/vendor/symfony/config/Tests/Definition/PrototypedArrayNodeTest.php
new file mode 100755
index 0000000..c343fcf
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/PrototypedArrayNodeTest.php
@@ -0,0 +1,180 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition;
+
+use Symfony\Component\Config\Definition\PrototypedArrayNode;
+use Symfony\Component\Config\Definition\ArrayNode;
+use Symfony\Component\Config\Definition\ScalarNode;
+
+class PrototypedArrayNodeTest extends \PHPUnit_Framework_TestCase
+{
+ public function testGetDefaultValueReturnsAnEmptyArrayForPrototypes()
+ {
+ $node = new PrototypedArrayNode('root');
+ $prototype = new ArrayNode(null, $node);
+ $node->setPrototype($prototype);
+ $this->assertEmpty($node->getDefaultValue());
+ }
+
+ public function testGetDefaultValueReturnsDefaultValueForPrototypes()
+ {
+ $node = new PrototypedArrayNode('root');
+ $prototype = new ArrayNode(null, $node);
+ $node->setPrototype($prototype);
+ $node->setDefaultValue(array('test'));
+ $this->assertEquals(array('test'), $node->getDefaultValue());
+ }
+
+ // a remapped key (e.g. "mapping" -> "mappings") should be unset after being used
+ public function testRemappedKeysAreUnset()
+ {
+ $node = new ArrayNode('root');
+ $mappingsNode = new PrototypedArrayNode('mappings');
+ $node->addChild($mappingsNode);
+
+ // each item under mappings is just a scalar
+ $prototype = new ScalarNode(null, $mappingsNode);
+ $mappingsNode->setPrototype($prototype);
+
+ $remappings = array();
+ $remappings[] = array('mapping', 'mappings');
+ $node->setXmlRemappings($remappings);
+
+ $normalized = $node->normalize(array('mapping' => array('foo', 'bar')));
+ $this->assertEquals(array('mappings' => array('foo', 'bar')), $normalized);
+ }
+
+ /**
+ * Tests that when a key attribute is mapped, that key is removed from the array.
+ *
+ *
+ *
+ *
+ *
+ *
+ * The above should finally be mapped to an array that looks like this
+ * (because "id" is the key attribute).
+ *
+ * array(
+ * 'things' => array(
+ * 'option1' => 'foo',
+ * 'option2' => 'bar',
+ * )
+ * )
+ */
+ public function testMappedAttributeKeyIsRemoved()
+ {
+ $node = new PrototypedArrayNode('root');
+ $node->setKeyAttribute('id', true);
+
+ // each item under the root is an array, with one scalar item
+ $prototype = new ArrayNode(null, $node);
+ $prototype->addChild(new ScalarNode('foo'));
+ $node->setPrototype($prototype);
+
+ $children = array();
+ $children[] = array('id' => 'item_name', 'foo' => 'bar');
+ $normalized = $node->normalize($children);
+
+ $expected = array();
+ $expected['item_name'] = array('foo' => 'bar');
+ $this->assertEquals($expected, $normalized);
+ }
+
+ /**
+ * Tests the opposite of the testMappedAttributeKeyIsRemoved because
+ * the removal can be toggled with an option.
+ */
+ public function testMappedAttributeKeyNotRemoved()
+ {
+ $node = new PrototypedArrayNode('root');
+ $node->setKeyAttribute('id', false);
+
+ // each item under the root is an array, with two scalar items
+ $prototype = new ArrayNode(null, $node);
+ $prototype->addChild(new ScalarNode('foo'));
+ $prototype->addChild(new ScalarNode('id')); // the key attribute will remain
+ $node->setPrototype($prototype);
+
+ $children = array();
+ $children[] = array('id' => 'item_name', 'foo' => 'bar');
+ $normalized = $node->normalize($children);
+
+ $expected = array();
+ $expected['item_name'] = array('id' => 'item_name', 'foo' => 'bar');
+ $this->assertEquals($expected, $normalized);
+ }
+
+ public function testAddDefaultChildren()
+ {
+ $node = $this->getPrototypeNodeWithDefaultChildren();
+ $node->setAddChildrenIfNoneSet();
+ $this->assertTrue($node->hasDefaultValue());
+ $this->assertEquals(array(array('foo' => 'bar')), $node->getDefaultValue());
+
+ $node = $this->getPrototypeNodeWithDefaultChildren();
+ $node->setKeyAttribute('foobar');
+ $node->setAddChildrenIfNoneSet();
+ $this->assertTrue($node->hasDefaultValue());
+ $this->assertEquals(array('defaults' => array('foo' => 'bar')), $node->getDefaultValue());
+
+ $node = $this->getPrototypeNodeWithDefaultChildren();
+ $node->setKeyAttribute('foobar');
+ $node->setAddChildrenIfNoneSet('defaultkey');
+ $this->assertTrue($node->hasDefaultValue());
+ $this->assertEquals(array('defaultkey' => array('foo' => 'bar')), $node->getDefaultValue());
+
+ $node = $this->getPrototypeNodeWithDefaultChildren();
+ $node->setKeyAttribute('foobar');
+ $node->setAddChildrenIfNoneSet(array('defaultkey'));
+ $this->assertTrue($node->hasDefaultValue());
+ $this->assertEquals(array('defaultkey' => array('foo' => 'bar')), $node->getDefaultValue());
+
+ $node = $this->getPrototypeNodeWithDefaultChildren();
+ $node->setKeyAttribute('foobar');
+ $node->setAddChildrenIfNoneSet(array('dk1', 'dk2'));
+ $this->assertTrue($node->hasDefaultValue());
+ $this->assertEquals(array('dk1' => array('foo' => 'bar'), 'dk2' => array('foo' => 'bar')), $node->getDefaultValue());
+
+ $node = $this->getPrototypeNodeWithDefaultChildren();
+ $node->setAddChildrenIfNoneSet(array(5, 6));
+ $this->assertTrue($node->hasDefaultValue());
+ $this->assertEquals(array(0 => array('foo' => 'bar'), 1 => array('foo' => 'bar')), $node->getDefaultValue());
+
+ $node = $this->getPrototypeNodeWithDefaultChildren();
+ $node->setAddChildrenIfNoneSet(2);
+ $this->assertTrue($node->hasDefaultValue());
+ $this->assertEquals(array(array('foo' => 'bar'), array('foo' => 'bar')), $node->getDefaultValue());
+ }
+
+ public function testDefaultChildrenWinsOverDefaultValue()
+ {
+ $node = $this->getPrototypeNodeWithDefaultChildren();
+ $node->setAddChildrenIfNoneSet();
+ $node->setDefaultValue(array('bar' => 'foo'));
+ $this->assertTrue($node->hasDefaultValue());
+ $this->assertEquals(array(array('foo' => 'bar')), $node->getDefaultValue());
+ }
+
+ protected function getPrototypeNodeWithDefaultChildren()
+ {
+ $node = new PrototypedArrayNode('root');
+ $prototype = new ArrayNode(null, $node);
+ $child = new ScalarNode('foo');
+ $child->setDefaultValue('bar');
+ $prototype->addChild($child);
+ $prototype->setAddIfNotSet(true);
+ $node->setPrototype($prototype);
+
+ return $node;
+ }
+}
diff --git a/vendor/symfony/config/Tests/Definition/ScalarNodeTest.php b/vendor/symfony/config/Tests/Definition/ScalarNodeTest.php
new file mode 100755
index 0000000..86c1803
--- /dev/null
+++ b/vendor/symfony/config/Tests/Definition/ScalarNodeTest.php
@@ -0,0 +1,126 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition;
+
+use Symfony\Component\Config\Definition\ScalarNode;
+
+class ScalarNodeTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getValidValues
+ */
+ public function testNormalize($value)
+ {
+ $node = new ScalarNode('test');
+ $this->assertSame($value, $node->normalize($value));
+ }
+
+ public function getValidValues()
+ {
+ return array(
+ array(false),
+ array(true),
+ array(null),
+ array(''),
+ array('foo'),
+ array(0),
+ array(1),
+ array(0.0),
+ array(0.1),
+ );
+ }
+
+ /**
+ * @dataProvider getInvalidValues
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidTypeException
+ */
+ public function testNormalizeThrowsExceptionOnInvalidValues($value)
+ {
+ $node = new ScalarNode('test');
+ $node->normalize($value);
+ }
+
+ public function getInvalidValues()
+ {
+ return array(
+ array(array()),
+ array(array('foo' => 'bar')),
+ array(new \stdClass()),
+ );
+ }
+
+ public function testNormalizeThrowsExceptionWithoutHint()
+ {
+ $node = new ScalarNode('test');
+
+ $this->setExpectedException('Symfony\Component\Config\Definition\Exception\InvalidTypeException', 'Invalid type for path "test". Expected scalar, but got array.');
+
+ $node->normalize(array());
+ }
+
+ public function testNormalizeThrowsExceptionWithErrorMessage()
+ {
+ $node = new ScalarNode('test');
+ $node->setInfo('"the test value"');
+
+ $this->setExpectedException('Symfony\Component\Config\Definition\Exception\InvalidTypeException', "Invalid type for path \"test\". Expected scalar, but got array.\nHint: \"the test value\"");
+
+ $node->normalize(array());
+ }
+
+ /**
+ * @dataProvider getValidNonEmptyValues
+ *
+ * @param mixed $value
+ */
+ public function testValidNonEmptyValues($value)
+ {
+ $node = new ScalarNode('test');
+ $node->setAllowEmptyValue(false);
+
+ $this->assertSame($value, $node->finalize($value));
+ }
+
+ public function getValidNonEmptyValues()
+ {
+ return array(
+ array(false),
+ array(true),
+ array('foo'),
+ array(0),
+ array(1),
+ array(0.0),
+ array(0.1),
+ );
+ }
+
+ /**
+ * @dataProvider getEmptyValues
+ * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
+ *
+ * @param mixed $value
+ */
+ public function testNotAllowedEmptyValuesThrowException($value)
+ {
+ $node = new ScalarNode('test');
+ $node->setAllowEmptyValue(false);
+ $node->finalize($value);
+ }
+
+ public function getEmptyValues()
+ {
+ return array(
+ array(null),
+ array(''),
+ );
+ }
+}
diff --git a/vendor/symfony/config/Tests/Exception/FileLoaderLoadExceptionTest.php b/vendor/symfony/config/Tests/Exception/FileLoaderLoadExceptionTest.php
new file mode 100755
index 0000000..c3d050c
--- /dev/null
+++ b/vendor/symfony/config/Tests/Exception/FileLoaderLoadExceptionTest.php
@@ -0,0 +1,85 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Exception;
+
+use Symfony\Component\Config\Exception\FileLoaderLoadException;
+
+class FileLoaderLoadExceptionTest extends \PHPUnit_Framework_TestCase
+{
+ public function testMessageCannotLoadResource()
+ {
+ $exception = new FileLoaderLoadException('resource', null);
+ $this->assertEquals('Cannot load resource "resource".', $exception->getMessage());
+ }
+
+ public function testMessageCannotImportResourceFromSource()
+ {
+ $exception = new FileLoaderLoadException('resource', 'sourceResource');
+ $this->assertEquals('Cannot import resource "resource" from "sourceResource".', $exception->getMessage());
+ }
+
+ public function testMessageCannotImportBundleResource()
+ {
+ $exception = new FileLoaderLoadException('@resource', 'sourceResource');
+ $this->assertEquals(
+ 'Cannot import resource "@resource" from "sourceResource". '.
+ 'Make sure the "resource" bundle is correctly registered and loaded in the application kernel class. '.
+ 'If the bundle is registered, make sure the bundle path "@resource" is not empty.',
+ $exception->getMessage()
+ );
+ }
+
+ public function testMessageHasPreviousErrorWithDotAndUnableToLoad()
+ {
+ $exception = new FileLoaderLoadException(
+ 'resource',
+ null,
+ null,
+ new \Exception('There was a previous error with an ending dot.')
+ );
+ $this->assertEquals(
+ 'There was a previous error with an ending dot in resource (which is loaded in resource "resource").',
+ $exception->getMessage()
+ );
+ }
+
+ public function testMessageHasPreviousErrorWithoutDotAndUnableToLoad()
+ {
+ $exception = new FileLoaderLoadException(
+ 'resource',
+ null,
+ null,
+ new \Exception('There was a previous error with no ending dot')
+ );
+ $this->assertEquals(
+ 'There was a previous error with no ending dot in resource (which is loaded in resource "resource").',
+ $exception->getMessage()
+ );
+ }
+
+ public function testMessageHasPreviousErrorAndUnableToLoadBundle()
+ {
+ $exception = new FileLoaderLoadException(
+ '@resource',
+ null,
+ null,
+ new \Exception('There was a previous error with an ending dot.')
+ );
+ $this->assertEquals(
+ 'There was a previous error with an ending dot in @resource '.
+ '(which is loaded in resource "@resource"). '.
+ 'Make sure the "resource" bundle is correctly registered and loaded in the application kernel class. '.
+ 'If the bundle is registered, make sure the bundle path "@resource" is not empty.',
+ $exception->getMessage()
+ );
+ }
+}
diff --git a/vendor/symfony/config/Tests/FileLocatorTest.php b/vendor/symfony/config/Tests/FileLocatorTest.php
new file mode 100755
index 0000000..d479f25
--- /dev/null
+++ b/vendor/symfony/config/Tests/FileLocatorTest.php
@@ -0,0 +1,119 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests;
+
+use Symfony\Component\Config\FileLocator;
+
+class FileLocatorTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider getIsAbsolutePathTests
+ */
+ public function testIsAbsolutePath($path)
+ {
+ $loader = new FileLocator(array());
+ $r = new \ReflectionObject($loader);
+ $m = $r->getMethod('isAbsolutePath');
+ $m->setAccessible(true);
+
+ $this->assertTrue($m->invoke($loader, $path), '->isAbsolutePath() returns true for an absolute path');
+ }
+
+ public function getIsAbsolutePathTests()
+ {
+ return array(
+ array('/foo.xml'),
+ array('c:\\\\foo.xml'),
+ array('c:/foo.xml'),
+ array('\\server\\foo.xml'),
+ array('https://server/foo.xml'),
+ array('phar://server/foo.xml'),
+ );
+ }
+
+ public function testLocate()
+ {
+ $loader = new FileLocator(__DIR__.'/Fixtures');
+
+ $this->assertEquals(
+ __DIR__.DIRECTORY_SEPARATOR.'FileLocatorTest.php',
+ $loader->locate('FileLocatorTest.php', __DIR__),
+ '->locate() returns the absolute filename if the file exists in the given path'
+ );
+
+ $this->assertEquals(
+ __DIR__.'/Fixtures'.DIRECTORY_SEPARATOR.'foo.xml',
+ $loader->locate('foo.xml', __DIR__),
+ '->locate() returns the absolute filename if the file exists in one of the paths given in the constructor'
+ );
+
+ $this->assertEquals(
+ __DIR__.'/Fixtures'.DIRECTORY_SEPARATOR.'foo.xml',
+ $loader->locate(__DIR__.'/Fixtures'.DIRECTORY_SEPARATOR.'foo.xml', __DIR__),
+ '->locate() returns the absolute filename if the file exists in one of the paths given in the constructor'
+ );
+
+ $loader = new FileLocator(array(__DIR__.'/Fixtures', __DIR__.'/Fixtures/Again'));
+
+ $this->assertEquals(
+ array(__DIR__.'/Fixtures'.DIRECTORY_SEPARATOR.'foo.xml', __DIR__.'/Fixtures/Again'.DIRECTORY_SEPARATOR.'foo.xml'),
+ $loader->locate('foo.xml', __DIR__, false),
+ '->locate() returns an array of absolute filenames'
+ );
+
+ $this->assertEquals(
+ array(__DIR__.'/Fixtures'.DIRECTORY_SEPARATOR.'foo.xml', __DIR__.'/Fixtures/Again'.DIRECTORY_SEPARATOR.'foo.xml'),
+ $loader->locate('foo.xml', __DIR__.'/Fixtures', false),
+ '->locate() returns an array of absolute filenames'
+ );
+
+ $loader = new FileLocator(__DIR__.'/Fixtures/Again');
+
+ $this->assertEquals(
+ array(__DIR__.'/Fixtures'.DIRECTORY_SEPARATOR.'foo.xml', __DIR__.'/Fixtures/Again'.DIRECTORY_SEPARATOR.'foo.xml'),
+ $loader->locate('foo.xml', __DIR__.'/Fixtures', false),
+ '->locate() returns an array of absolute filenames'
+ );
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage The file "foobar.xml" does not exist
+ */
+ public function testLocateThrowsAnExceptionIfTheFileDoesNotExists()
+ {
+ $loader = new FileLocator(array(__DIR__.'/Fixtures'));
+
+ $loader->locate('foobar.xml', __DIR__);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testLocateThrowsAnExceptionIfTheFileDoesNotExistsInAbsolutePath()
+ {
+ $loader = new FileLocator(array(__DIR__.'/Fixtures'));
+
+ $loader->locate(__DIR__.'/Fixtures/foobar.xml', __DIR__);
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage An empty file name is not valid to be located.
+ */
+ public function testLocateEmpty()
+ {
+ $loader = new FileLocator(array(__DIR__.'/Fixtures'));
+
+ $loader->locate(null, __DIR__);
+ }
+}
diff --git a/vendor/symfony/config/Tests/Fixtures/Again/foo.xml b/vendor/symfony/config/Tests/Fixtures/Again/foo.xml
new file mode 100755
index 0000000..e69de29
diff --git a/vendor/symfony/config/Tests/Fixtures/Builder/BarNodeDefinition.php b/vendor/symfony/config/Tests/Fixtures/Builder/BarNodeDefinition.php
new file mode 100755
index 0000000..47701c1
--- /dev/null
+++ b/vendor/symfony/config/Tests/Fixtures/Builder/BarNodeDefinition.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition\Builder;
+
+use Symfony\Component\Config\Definition\Builder\NodeDefinition;
+
+class BarNodeDefinition extends NodeDefinition
+{
+ protected function createNode()
+ {
+ }
+}
diff --git a/vendor/symfony/config/Tests/Fixtures/Builder/NodeBuilder.php b/vendor/symfony/config/Tests/Fixtures/Builder/NodeBuilder.php
new file mode 100755
index 0000000..aa59863
--- /dev/null
+++ b/vendor/symfony/config/Tests/Fixtures/Builder/NodeBuilder.php
@@ -0,0 +1,34 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition\Builder;
+
+use Symfony\Component\Config\Definition\Builder\NodeBuilder as BaseNodeBuilder;
+
+class NodeBuilder extends BaseNodeBuilder
+{
+ public function barNode($name)
+ {
+ return $this->node($name, 'bar');
+ }
+
+ protected function getNodeClass($type)
+ {
+ switch ($type) {
+ case 'variable':
+ return __NAMESPACE__.'\\'.ucfirst($type).'NodeDefinition';
+ case 'bar':
+ return __NAMESPACE__.'\\'.ucfirst($type).'NodeDefinition';
+ default:
+ return parent::getNodeClass($type);
+ }
+ }
+}
diff --git a/vendor/symfony/config/Tests/Fixtures/Builder/VariableNodeDefinition.php b/vendor/symfony/config/Tests/Fixtures/Builder/VariableNodeDefinition.php
new file mode 100755
index 0000000..1017880
--- /dev/null
+++ b/vendor/symfony/config/Tests/Fixtures/Builder/VariableNodeDefinition.php
@@ -0,0 +1,18 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Definition\Builder;
+
+use Symfony\Component\Config\Definition\Builder\VariableNodeDefinition as BaseVariableNodeDefinition;
+
+class VariableNodeDefinition extends BaseVariableNodeDefinition
+{
+}
diff --git a/vendor/symfony/config/Tests/Fixtures/Configuration/ExampleConfiguration.php b/vendor/symfony/config/Tests/Fixtures/Configuration/ExampleConfiguration.php
new file mode 100755
index 0000000..df43e8b
--- /dev/null
+++ b/vendor/symfony/config/Tests/Fixtures/Configuration/ExampleConfiguration.php
@@ -0,0 +1,71 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Fixtures\Configuration;
+
+use Symfony\Component\Config\Definition\Builder\TreeBuilder;
+use Symfony\Component\Config\Definition\ConfigurationInterface;
+
+class ExampleConfiguration implements ConfigurationInterface
+{
+ public function getConfigTreeBuilder()
+ {
+ $treeBuilder = new TreeBuilder();
+ $rootNode = $treeBuilder->root('acme_root');
+
+ $rootNode
+ ->fixXmlConfig('parameter')
+ ->fixXmlConfig('connection')
+ ->children()
+ ->booleanNode('boolean')->defaultTrue()->end()
+ ->scalarNode('scalar_empty')->end()
+ ->scalarNode('scalar_null')->defaultNull()->end()
+ ->scalarNode('scalar_true')->defaultTrue()->end()
+ ->scalarNode('scalar_false')->defaultFalse()->end()
+ ->scalarNode('scalar_default')->defaultValue('default')->end()
+ ->scalarNode('scalar_array_empty')->defaultValue(array())->end()
+ ->scalarNode('scalar_array_defaults')->defaultValue(array('elem1', 'elem2'))->end()
+ ->scalarNode('scalar_required')->isRequired()->end()
+ ->enumNode('enum')->values(array('this', 'that'))->end()
+ ->arrayNode('array')
+ ->info('some info')
+ ->canBeUnset()
+ ->children()
+ ->scalarNode('child1')->end()
+ ->scalarNode('child2')->end()
+ ->scalarNode('child3')
+ ->info(
+ "this is a long\n".
+ "multi-line info text\n".
+ 'which should be indented'
+ )
+ ->example('example setting')
+ ->end()
+ ->end()
+ ->end()
+ ->arrayNode('parameters')
+ ->useAttributeAsKey('name')
+ ->prototype('scalar')->end()
+ ->end()
+ ->arrayNode('connections')
+ ->prototype('array')
+ ->children()
+ ->scalarNode('user')->end()
+ ->scalarNode('pass')->end()
+ ->end()
+ ->end()
+ ->end()
+ ->end()
+ ;
+
+ return $treeBuilder;
+ }
+}
diff --git a/vendor/symfony/config/Tests/Fixtures/Util/document_type.xml b/vendor/symfony/config/Tests/Fixtures/Util/document_type.xml
new file mode 100755
index 0000000..4c25228
--- /dev/null
+++ b/vendor/symfony/config/Tests/Fixtures/Util/document_type.xml
@@ -0,0 +1,3 @@
+
+]>
+
diff --git a/vendor/symfony/config/Tests/Fixtures/Util/invalid.xml b/vendor/symfony/config/Tests/Fixtures/Util/invalid.xml
new file mode 100755
index 0000000..a07af9f
--- /dev/null
+++ b/vendor/symfony/config/Tests/Fixtures/Util/invalid.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/vendor/symfony/config/Tests/Fixtures/Util/invalid_schema.xml b/vendor/symfony/config/Tests/Fixtures/Util/invalid_schema.xml
new file mode 100755
index 0000000..e2725a2
--- /dev/null
+++ b/vendor/symfony/config/Tests/Fixtures/Util/invalid_schema.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/vendor/symfony/config/Tests/Fixtures/Util/schema.xsd b/vendor/symfony/config/Tests/Fixtures/Util/schema.xsd
new file mode 100755
index 0000000..e56820f
--- /dev/null
+++ b/vendor/symfony/config/Tests/Fixtures/Util/schema.xsd
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/vendor/symfony/config/Tests/Fixtures/Util/valid.xml b/vendor/symfony/config/Tests/Fixtures/Util/valid.xml
new file mode 100755
index 0000000..a96bb38
--- /dev/null
+++ b/vendor/symfony/config/Tests/Fixtures/Util/valid.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/vendor/symfony/config/Tests/Fixtures/foo.xml b/vendor/symfony/config/Tests/Fixtures/foo.xml
new file mode 100755
index 0000000..e69de29
diff --git a/vendor/symfony/config/Tests/Loader/DelegatingLoaderTest.php b/vendor/symfony/config/Tests/Loader/DelegatingLoaderTest.php
new file mode 100755
index 0000000..7641e24
--- /dev/null
+++ b/vendor/symfony/config/Tests/Loader/DelegatingLoaderTest.php
@@ -0,0 +1,83 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Loader;
+
+use Symfony\Component\Config\Loader\LoaderResolver;
+use Symfony\Component\Config\Loader\DelegatingLoader;
+
+class DelegatingLoaderTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @covers Symfony\Component\Config\Loader\DelegatingLoader::__construct
+ */
+ public function testConstructor()
+ {
+ $loader = new DelegatingLoader($resolver = new LoaderResolver());
+ $this->assertTrue(true, '__construct() takes a loader resolver as its first argument');
+ }
+
+ /**
+ * @covers Symfony\Component\Config\Loader\DelegatingLoader::getResolver
+ * @covers Symfony\Component\Config\Loader\DelegatingLoader::setResolver
+ */
+ public function testGetSetResolver()
+ {
+ $resolver = new LoaderResolver();
+ $loader = new DelegatingLoader($resolver);
+ $this->assertSame($resolver, $loader->getResolver(), '->getResolver() gets the resolver loader');
+ $loader->setResolver($resolver = new LoaderResolver());
+ $this->assertSame($resolver, $loader->getResolver(), '->setResolver() sets the resolver loader');
+ }
+
+ /**
+ * @covers Symfony\Component\Config\Loader\DelegatingLoader::supports
+ */
+ public function testSupports()
+ {
+ $loader1 = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface');
+ $loader1->expects($this->once())->method('supports')->will($this->returnValue(true));
+ $loader = new DelegatingLoader(new LoaderResolver(array($loader1)));
+ $this->assertTrue($loader->supports('foo.xml'), '->supports() returns true if the resource is loadable');
+
+ $loader1 = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface');
+ $loader1->expects($this->once())->method('supports')->will($this->returnValue(false));
+ $loader = new DelegatingLoader(new LoaderResolver(array($loader1)));
+ $this->assertFalse($loader->supports('foo.foo'), '->supports() returns false if the resource is not loadable');
+ }
+
+ /**
+ * @covers Symfony\Component\Config\Loader\DelegatingLoader::load
+ */
+ public function testLoad()
+ {
+ $loader = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface');
+ $loader->expects($this->once())->method('supports')->will($this->returnValue(true));
+ $loader->expects($this->once())->method('load');
+ $resolver = new LoaderResolver(array($loader));
+ $loader = new DelegatingLoader($resolver);
+
+ $loader->load('foo');
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Exception\FileLoaderLoadException
+ */
+ public function testLoadThrowsAnExceptionIfTheResourceCannotBeLoaded()
+ {
+ $loader = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface');
+ $loader->expects($this->once())->method('supports')->will($this->returnValue(false));
+ $resolver = new LoaderResolver(array($loader));
+ $loader = new DelegatingLoader($resolver);
+
+ $loader->load('foo');
+ }
+}
diff --git a/vendor/symfony/config/Tests/Loader/FileLoaderTest.php b/vendor/symfony/config/Tests/Loader/FileLoaderTest.php
new file mode 100755
index 0000000..1442e94
--- /dev/null
+++ b/vendor/symfony/config/Tests/Loader/FileLoaderTest.php
@@ -0,0 +1,106 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Loader;
+
+use Symfony\Component\Config\Loader\FileLoader;
+use Symfony\Component\Config\Loader\LoaderResolver;
+
+class FileLoaderTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @covers Symfony\Component\Config\Loader\FileLoader
+ */
+ public function testImportWithFileLocatorDelegation()
+ {
+ $locatorMock = $this->getMock('Symfony\Component\Config\FileLocatorInterface');
+
+ $locatorMockForAdditionalLoader = $this->getMock('Symfony\Component\Config\FileLocatorInterface');
+ $locatorMockForAdditionalLoader->expects($this->any())->method('locate')->will($this->onConsecutiveCalls(
+ array('path/to/file1'), // Default
+ array('path/to/file1', 'path/to/file2'), // First is imported
+ array('path/to/file1', 'path/to/file2'), // Second is imported
+ array('path/to/file1'), // Exception
+ array('path/to/file1', 'path/to/file2') // Exception
+ ));
+
+ $fileLoader = new TestFileLoader($locatorMock);
+ $fileLoader->setSupports(false);
+ $fileLoader->setCurrentDir('.');
+
+ $additionalLoader = new TestFileLoader($locatorMockForAdditionalLoader);
+ $additionalLoader->setCurrentDir('.');
+
+ $fileLoader->setResolver($loaderResolver = new LoaderResolver(array($fileLoader, $additionalLoader)));
+
+ // Default case
+ $this->assertSame('path/to/file1', $fileLoader->import('my_resource'));
+
+ // Check first file is imported if not already loading
+ $this->assertSame('path/to/file1', $fileLoader->import('my_resource'));
+
+ // Check second file is imported if first is already loading
+ $fileLoader->addLoading('path/to/file1');
+ $this->assertSame('path/to/file2', $fileLoader->import('my_resource'));
+
+ // Check exception throws if first (and only available) file is already loading
+ try {
+ $fileLoader->import('my_resource');
+ $this->fail('->import() throws a FileLoaderImportCircularReferenceException if the resource is already loading');
+ } catch (\Exception $e) {
+ $this->assertInstanceOf('Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException', $e, '->import() throws a FileLoaderImportCircularReferenceException if the resource is already loading');
+ }
+
+ // Check exception throws if all files are already loading
+ try {
+ $fileLoader->addLoading('path/to/file2');
+ $fileLoader->import('my_resource');
+ $this->fail('->import() throws a FileLoaderImportCircularReferenceException if the resource is already loading');
+ } catch (\Exception $e) {
+ $this->assertInstanceOf('Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException', $e, '->import() throws a FileLoaderImportCircularReferenceException if the resource is already loading');
+ }
+ }
+}
+
+class TestFileLoader extends FileLoader
+{
+ private $supports = true;
+
+ public function load($resource, $type = null)
+ {
+ return $resource;
+ }
+
+ public function supports($resource, $type = null)
+ {
+ return $this->supports;
+ }
+
+ public function addLoading($resource)
+ {
+ self::$loading[$resource] = true;
+ }
+
+ public function removeLoading($resource)
+ {
+ unset(self::$loading[$resource]);
+ }
+
+ public function clearLoading()
+ {
+ self::$loading = array();
+ }
+
+ public function setSupports($supports)
+ {
+ $this->supports = $supports;
+ }
+}
diff --git a/vendor/symfony/config/Tests/Loader/LoaderResolverTest.php b/vendor/symfony/config/Tests/Loader/LoaderResolverTest.php
new file mode 100755
index 0000000..8ee276b
--- /dev/null
+++ b/vendor/symfony/config/Tests/Loader/LoaderResolverTest.php
@@ -0,0 +1,56 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Loader;
+
+use Symfony\Component\Config\Loader\LoaderResolver;
+
+class LoaderResolverTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @covers Symfony\Component\Config\Loader\LoaderResolver::__construct
+ */
+ public function testConstructor()
+ {
+ $resolver = new LoaderResolver(array(
+ $loader = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface'),
+ ));
+
+ $this->assertEquals(array($loader), $resolver->getLoaders(), '__construct() takes an array of loaders as its first argument');
+ }
+
+ /**
+ * @covers Symfony\Component\Config\Loader\LoaderResolver::resolve
+ */
+ public function testResolve()
+ {
+ $loader = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface');
+ $resolver = new LoaderResolver(array($loader));
+ $this->assertFalse($resolver->resolve('foo.foo'), '->resolve() returns false if no loader is able to load the resource');
+
+ $loader = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface');
+ $loader->expects($this->once())->method('supports')->will($this->returnValue(true));
+ $resolver = new LoaderResolver(array($loader));
+ $this->assertEquals($loader, $resolver->resolve(function () {}), '->resolve() returns the loader for the given resource');
+ }
+
+ /**
+ * @covers Symfony\Component\Config\Loader\LoaderResolver::getLoaders
+ * @covers Symfony\Component\Config\Loader\LoaderResolver::addLoader
+ */
+ public function testLoaders()
+ {
+ $resolver = new LoaderResolver();
+ $resolver->addLoader($loader = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface'));
+
+ $this->assertEquals(array($loader), $resolver->getLoaders(), 'addLoader() adds a loader');
+ }
+}
diff --git a/vendor/symfony/config/Tests/Loader/LoaderTest.php b/vendor/symfony/config/Tests/Loader/LoaderTest.php
new file mode 100755
index 0000000..e938a4b
--- /dev/null
+++ b/vendor/symfony/config/Tests/Loader/LoaderTest.php
@@ -0,0 +1,117 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Loader;
+
+use Symfony\Component\Config\Loader\Loader;
+
+class LoaderTest extends \PHPUnit_Framework_TestCase
+{
+ public function testGetSetResolver()
+ {
+ $resolver = $this->getMock('Symfony\Component\Config\Loader\LoaderResolverInterface');
+
+ $loader = new ProjectLoader1();
+ $loader->setResolver($resolver);
+
+ $this->assertSame($resolver, $loader->getResolver(), '->setResolver() sets the resolver loader');
+ }
+
+ public function testResolve()
+ {
+ $resolvedLoader = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface');
+
+ $resolver = $this->getMock('Symfony\Component\Config\Loader\LoaderResolverInterface');
+ $resolver->expects($this->once())
+ ->method('resolve')
+ ->with('foo.xml')
+ ->will($this->returnValue($resolvedLoader));
+
+ $loader = new ProjectLoader1();
+ $loader->setResolver($resolver);
+
+ $this->assertSame($loader, $loader->resolve('foo.foo'), '->resolve() finds a loader');
+ $this->assertSame($resolvedLoader, $loader->resolve('foo.xml'), '->resolve() finds a loader');
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Config\Exception\FileLoaderLoadException
+ */
+ public function testResolveWhenResolverCannotFindLoader()
+ {
+ $resolver = $this->getMock('Symfony\Component\Config\Loader\LoaderResolverInterface');
+ $resolver->expects($this->once())
+ ->method('resolve')
+ ->with('FOOBAR')
+ ->will($this->returnValue(false));
+
+ $loader = new ProjectLoader1();
+ $loader->setResolver($resolver);
+
+ $loader->resolve('FOOBAR');
+ }
+
+ public function testImport()
+ {
+ $resolvedLoader = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface');
+ $resolvedLoader->expects($this->once())
+ ->method('load')
+ ->with('foo')
+ ->will($this->returnValue('yes'));
+
+ $resolver = $this->getMock('Symfony\Component\Config\Loader\LoaderResolverInterface');
+ $resolver->expects($this->once())
+ ->method('resolve')
+ ->with('foo')
+ ->will($this->returnValue($resolvedLoader));
+
+ $loader = new ProjectLoader1();
+ $loader->setResolver($resolver);
+
+ $this->assertEquals('yes', $loader->import('foo'));
+ }
+
+ public function testImportWithType()
+ {
+ $resolvedLoader = $this->getMock('Symfony\Component\Config\Loader\LoaderInterface');
+ $resolvedLoader->expects($this->once())
+ ->method('load')
+ ->with('foo', 'bar')
+ ->will($this->returnValue('yes'));
+
+ $resolver = $this->getMock('Symfony\Component\Config\Loader\LoaderResolverInterface');
+ $resolver->expects($this->once())
+ ->method('resolve')
+ ->with('foo', 'bar')
+ ->will($this->returnValue($resolvedLoader));
+
+ $loader = new ProjectLoader1();
+ $loader->setResolver($resolver);
+
+ $this->assertEquals('yes', $loader->import('foo', 'bar'));
+ }
+}
+
+class ProjectLoader1 extends Loader
+{
+ public function load($resource, $type = null)
+ {
+ }
+
+ public function supports($resource, $type = null)
+ {
+ return is_string($resource) && 'foo' === pathinfo($resource, PATHINFO_EXTENSION);
+ }
+
+ public function getType()
+ {
+ }
+}
diff --git a/vendor/symfony/config/Tests/Resource/DirectoryResourceTest.php b/vendor/symfony/config/Tests/Resource/DirectoryResourceTest.php
new file mode 100755
index 0000000..226e280
--- /dev/null
+++ b/vendor/symfony/config/Tests/Resource/DirectoryResourceTest.php
@@ -0,0 +1,152 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Resource;
+
+use Symfony\Component\Config\Resource\DirectoryResource;
+
+class DirectoryResourceTest extends \PHPUnit_Framework_TestCase
+{
+ protected $directory;
+
+ protected function setUp()
+ {
+ $this->directory = sys_get_temp_dir().'/symfonyDirectoryIterator';
+ if (!file_exists($this->directory)) {
+ mkdir($this->directory);
+ }
+ touch($this->directory.'/tmp.xml');
+ }
+
+ protected function tearDown()
+ {
+ if (!is_dir($this->directory)) {
+ return;
+ }
+ $this->removeDirectory($this->directory);
+ }
+
+ protected function removeDirectory($directory)
+ {
+ $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($directory), \RecursiveIteratorIterator::CHILD_FIRST);
+ foreach ($iterator as $path) {
+ if (preg_match('#[/\\\\]\.\.?$#', $path->__toString())) {
+ continue;
+ }
+ if ($path->isDir()) {
+ rmdir($path->__toString());
+ } else {
+ unlink($path->__toString());
+ }
+ }
+ rmdir($directory);
+ }
+
+ public function testGetResource()
+ {
+ $resource = new DirectoryResource($this->directory);
+ $this->assertSame($this->directory, $resource->getResource(), '->getResource() returns the path to the resource');
+ $this->assertSame($this->directory, (string) $resource, '->__toString() returns the path to the resource');
+ }
+
+ public function testGetPattern()
+ {
+ $resource = new DirectoryResource('foo', 'bar');
+ $this->assertEquals('bar', $resource->getPattern());
+ }
+
+ public function testIsFresh()
+ {
+ $resource = new DirectoryResource($this->directory);
+ $this->assertTrue($resource->isFresh(time() + 10), '->isFresh() returns true if the resource has not changed');
+ $this->assertFalse($resource->isFresh(time() - 86400), '->isFresh() returns false if the resource has been updated');
+
+ $resource = new DirectoryResource('/____foo/foobar'.mt_rand(1, 999999));
+ $this->assertFalse($resource->isFresh(time()), '->isFresh() returns false if the resource does not exist');
+ }
+
+ public function testIsFreshUpdateFile()
+ {
+ $resource = new DirectoryResource($this->directory);
+ touch($this->directory.'/tmp.xml', time() + 20);
+ $this->assertFalse($resource->isFresh(time() + 10), '->isFresh() returns false if an existing file is modified');
+ }
+
+ public function testIsFreshNewFile()
+ {
+ $resource = new DirectoryResource($this->directory);
+ touch($this->directory.'/new.xml', time() + 20);
+ $this->assertFalse($resource->isFresh(time() + 10), '->isFresh() returns false if a new file is added');
+ }
+
+ public function testIsFreshDeleteFile()
+ {
+ $resource = new DirectoryResource($this->directory);
+ unlink($this->directory.'/tmp.xml');
+ $this->assertFalse($resource->isFresh(time()), '->isFresh() returns false if an existing file is removed');
+ }
+
+ public function testIsFreshDeleteDirectory()
+ {
+ $resource = new DirectoryResource($this->directory);
+ $this->removeDirectory($this->directory);
+ $this->assertFalse($resource->isFresh(time()), '->isFresh() returns false if the whole resource is removed');
+ }
+
+ public function testIsFreshCreateFileInSubdirectory()
+ {
+ $subdirectory = $this->directory.'/subdirectory';
+ mkdir($subdirectory);
+
+ $resource = new DirectoryResource($this->directory);
+ $this->assertTrue($resource->isFresh(time() + 10), '->isFresh() returns true if an unmodified subdirectory exists');
+
+ touch($subdirectory.'/newfile.xml', time() + 20);
+ $this->assertFalse($resource->isFresh(time() + 10), '->isFresh() returns false if a new file in a subdirectory is added');
+ }
+
+ public function testIsFreshModifySubdirectory()
+ {
+ $resource = new DirectoryResource($this->directory);
+
+ $subdirectory = $this->directory.'/subdirectory';
+ mkdir($subdirectory);
+ touch($subdirectory, time() + 20);
+
+ $this->assertFalse($resource->isFresh(time() + 10), '->isFresh() returns false if a subdirectory is modified (e.g. a file gets deleted)');
+ }
+
+ public function testFilterRegexListNoMatch()
+ {
+ $resource = new DirectoryResource($this->directory, '/\.(foo|xml)$/');
+
+ touch($this->directory.'/new.bar', time() + 20);
+ $this->assertTrue($resource->isFresh(time() + 10), '->isFresh() returns true if a new file not matching the filter regex is created');
+ }
+
+ public function testFilterRegexListMatch()
+ {
+ $resource = new DirectoryResource($this->directory, '/\.(foo|xml)$/');
+
+ touch($this->directory.'/new.xml', time() + 20);
+ $this->assertFalse($resource->isFresh(time() + 10), '->isFresh() returns false if an new file matching the filter regex is created ');
+ }
+
+ public function testSerializeUnserialize()
+ {
+ $resource = new DirectoryResource($this->directory, '/\.(foo|xml)$/');
+
+ $unserialized = unserialize(serialize($resource));
+
+ $this->assertSame($this->directory, $resource->getResource());
+ $this->assertSame('/\.(foo|xml)$/', $resource->getPattern());
+ }
+}
diff --git a/vendor/symfony/config/Tests/Resource/FileResourceTest.php b/vendor/symfony/config/Tests/Resource/FileResourceTest.php
new file mode 100755
index 0000000..db85cf7
--- /dev/null
+++ b/vendor/symfony/config/Tests/Resource/FileResourceTest.php
@@ -0,0 +1,61 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Resource;
+
+use Symfony\Component\Config\Resource\FileResource;
+
+class FileResourceTest extends \PHPUnit_Framework_TestCase
+{
+ protected $resource;
+ protected $file;
+ protected $time;
+
+ protected function setUp()
+ {
+ $this->file = realpath(sys_get_temp_dir()).'/tmp.xml';
+ $this->time = time();
+ touch($this->file, $this->time);
+ $this->resource = new FileResource($this->file);
+ }
+
+ protected function tearDown()
+ {
+ unlink($this->file);
+ }
+
+ public function testGetResource()
+ {
+ $this->assertSame(realpath($this->file), $this->resource->getResource(), '->getResource() returns the path to the resource');
+ }
+
+ public function testToString()
+ {
+ $this->assertSame(realpath($this->file), (string) $this->resource);
+ }
+
+ public function testIsFresh()
+ {
+ $this->assertTrue($this->resource->isFresh($this->time), '->isFresh() returns true if the resource has not changed in same second');
+ $this->assertTrue($this->resource->isFresh($this->time + 10), '->isFresh() returns true if the resource has not changed');
+ $this->assertFalse($this->resource->isFresh($this->time - 86400), '->isFresh() returns false if the resource has been updated');
+
+ $resource = new FileResource('/____foo/foobar'.mt_rand(1, 999999));
+ $this->assertFalse($resource->isFresh($this->time), '->isFresh() returns false if the resource does not exist');
+ }
+
+ public function testSerializeUnserialize()
+ {
+ $unserialized = unserialize(serialize($this->resource));
+
+ $this->assertSame(realpath($this->file), $this->resource->getResource());
+ }
+}
diff --git a/vendor/symfony/config/Tests/Util/XmlUtilsTest.php b/vendor/symfony/config/Tests/Util/XmlUtilsTest.php
new file mode 100755
index 0000000..f9d3d14
--- /dev/null
+++ b/vendor/symfony/config/Tests/Util/XmlUtilsTest.php
@@ -0,0 +1,197 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Tests\Loader;
+
+use Symfony\Component\Config\Util\XmlUtils;
+
+class XmlUtilsTest extends \PHPUnit_Framework_TestCase
+{
+ public function testLoadFile()
+ {
+ $fixtures = __DIR__.'/../Fixtures/Util/';
+
+ try {
+ XmlUtils::loadFile($fixtures.'invalid.xml');
+ $this->fail();
+ } catch (\InvalidArgumentException $e) {
+ $this->assertContains('ERROR 77', $e->getMessage());
+ }
+
+ try {
+ XmlUtils::loadFile($fixtures.'document_type.xml');
+ $this->fail();
+ } catch (\InvalidArgumentException $e) {
+ $this->assertContains('Document types are not allowed', $e->getMessage());
+ }
+
+ try {
+ XmlUtils::loadFile($fixtures.'invalid_schema.xml', $fixtures.'schema.xsd');
+ $this->fail();
+ } catch (\InvalidArgumentException $e) {
+ $this->assertContains('ERROR 1845', $e->getMessage());
+ }
+
+ try {
+ XmlUtils::loadFile($fixtures.'invalid_schema.xml', 'invalid_callback_or_file');
+ $this->fail();
+ } catch (\InvalidArgumentException $e) {
+ $this->assertContains('XSD file or callable', $e->getMessage());
+ }
+
+ $mock = $this->getMock(__NAMESPACE__.'\Validator');
+ $mock->expects($this->exactly(2))->method('validate')->will($this->onConsecutiveCalls(false, true));
+
+ try {
+ XmlUtils::loadFile($fixtures.'valid.xml', array($mock, 'validate'));
+ $this->fail();
+ } catch (\InvalidArgumentException $e) {
+ $this->assertContains('is not valid', $e->getMessage());
+ }
+
+ $this->assertInstanceOf('DOMDocument', XmlUtils::loadFile($fixtures.'valid.xml', array($mock, 'validate')));
+ $this->assertSame(array(), libxml_get_errors());
+ }
+
+ public function testLoadFileWithInternalErrorsEnabled()
+ {
+ libxml_use_internal_errors(true);
+
+ $this->assertSame(array(), libxml_get_errors());
+ $this->assertInstanceOf('DOMDocument', XmlUtils::loadFile(__DIR__.'/../Fixtures/Util/invalid_schema.xml'));
+ $this->assertSame(array(), libxml_get_errors());
+ }
+
+ /**
+ * @dataProvider getDataForConvertDomToArray
+ */
+ public function testConvertDomToArray($expected, $xml, $root = false, $checkPrefix = true)
+ {
+ $dom = new \DOMDocument();
+ $dom->loadXML($root ? $xml : ''.$xml.' ');
+
+ $this->assertSame($expected, XmlUtils::convertDomElementToArray($dom->documentElement, $checkPrefix));
+ }
+
+ public function getDataForConvertDomToArray()
+ {
+ return array(
+ array(null, ''),
+ array('bar', 'bar'),
+ array(array('bar' => 'foobar'), ' ', true),
+ array(array('foo' => null), ' '),
+ array(array('foo' => 'bar'), 'bar '),
+ array(array('foo' => array('foo' => 'bar')), ' '),
+ array(array('foo' => array('foo' => 0)), '0 '),
+ array(array('foo' => array('foo' => 'bar')), 'bar '),
+ array(array('foo' => array('foo' => 'bar', 'value' => 'text')), 'text '),
+ array(array('foo' => array('attr' => 'bar', 'foo' => 'text')), 'text '),
+ array(array('foo' => array('bar', 'text')), 'bar text '),
+ array(array('foo' => array(array('foo' => 'bar'), array('foo' => 'text'))), ' '),
+ array(array('foo' => array('foo' => array('bar', 'text'))), 'text '),
+ array(array('foo' => 'bar'), 'bar '),
+ array(array('foo' => 'text'), 'text '),
+ array(array('foo' => array('bar' => 'bar', 'value' => 'text')), 'text ', false, false),
+ array(array('attr' => 1, 'b' => 'hello'), 'hello 2 ', true),
+ );
+ }
+
+ /**
+ * @dataProvider getDataForPhpize
+ */
+ public function testPhpize($expected, $value)
+ {
+ $this->assertSame($expected, XmlUtils::phpize($value));
+ }
+
+ public function getDataForPhpize()
+ {
+ return array(
+ array('', ''),
+ array(null, 'null'),
+ array(true, 'true'),
+ array(false, 'false'),
+ array(null, 'Null'),
+ array(true, 'True'),
+ array(false, 'False'),
+ array(0, '0'),
+ array(1, '1'),
+ array(-1, '-1'),
+ array(0777, '0777'),
+ array(255, '0xFF'),
+ array(100.0, '1e2'),
+ array(-120.0, '-1.2E2'),
+ array(-10100.1, '-10100.1'),
+ array('-10,100.1', '-10,100.1'),
+ array('1234 5678 9101 1121 3141', '1234 5678 9101 1121 3141'),
+ array('1,2,3,4', '1,2,3,4'),
+ array('11,22,33,44', '11,22,33,44'),
+ array('11,222,333,4', '11,222,333,4'),
+ array('1,222,333,444', '1,222,333,444'),
+ array('11,222,333,444', '11,222,333,444'),
+ array('111,222,333,444', '111,222,333,444'),
+ array('1111,2222,3333,4444,5555', '1111,2222,3333,4444,5555'),
+ array('foo', 'foo'),
+ array(6, '0b0110'),
+ );
+ }
+
+ public function testLoadEmptyXmlFile()
+ {
+ $file = __DIR__.'/../Fixtures/foo.xml';
+ $this->setExpectedException('InvalidArgumentException', 'File '.$file.' does not contain valid XML, it is empty.');
+ XmlUtils::loadFile($file);
+ }
+
+ // test for issue https://github.com/symfony/symfony/issues/9731
+ public function testLoadWrongEmptyXMLWithErrorHandler()
+ {
+ $originalDisableEntities = libxml_disable_entity_loader(false);
+ $errorReporting = error_reporting(-1);
+
+ set_error_handler(function ($errno, $errstr) {
+ throw new \Exception($errstr, $errno);
+ });
+
+ $file = __DIR__.'/../Fixtures/foo.xml';
+ try {
+ try {
+ XmlUtils::loadFile($file);
+ $this->fail('An exception should have been raised');
+ } catch (\InvalidArgumentException $e) {
+ $this->assertEquals(sprintf('File %s does not contain valid XML, it is empty.', $file), $e->getMessage());
+ }
+ } catch (\Exception $e) {
+ restore_error_handler();
+ error_reporting($errorReporting);
+
+ throw $e;
+ }
+
+ restore_error_handler();
+ error_reporting($errorReporting);
+
+ $disableEntities = libxml_disable_entity_loader(true);
+ libxml_disable_entity_loader($disableEntities);
+
+ libxml_disable_entity_loader($originalDisableEntities);
+
+ $this->assertFalse($disableEntities);
+
+ // should not throw an exception
+ XmlUtils::loadFile(__DIR__.'/../Fixtures/Util/valid.xml', __DIR__.'/../Fixtures/Util/schema.xsd');
+ }
+}
+
+interface Validator
+{
+ public function validate();
+}
diff --git a/vendor/symfony/config/Util/XmlUtils.php b/vendor/symfony/config/Util/XmlUtils.php
new file mode 100755
index 0000000..d8d4eaa
--- /dev/null
+++ b/vendor/symfony/config/Util/XmlUtils.php
@@ -0,0 +1,238 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Config\Util;
+
+/**
+ * XMLUtils is a bunch of utility methods to XML operations.
+ *
+ * This class contains static methods only and is not meant to be instantiated.
+ *
+ * @author Fabien Potencier
+ * @author Martin Hasoň
+ */
+class XmlUtils
+{
+ /**
+ * This class should not be instantiated.
+ */
+ private function __construct()
+ {
+ }
+
+ /**
+ * Loads an XML file.
+ *
+ * @param string $file An XML file path
+ * @param string|callable|null $schemaOrCallable An XSD schema file path, a callable, or null to disable validation
+ *
+ * @return \DOMDocument
+ *
+ * @throws \InvalidArgumentException When loading of XML file returns error
+ */
+ public static function loadFile($file, $schemaOrCallable = null)
+ {
+ $content = @file_get_contents($file);
+ if ('' === trim($content)) {
+ throw new \InvalidArgumentException(sprintf('File %s does not contain valid XML, it is empty.', $file));
+ }
+
+ $internalErrors = libxml_use_internal_errors(true);
+ $disableEntities = libxml_disable_entity_loader(true);
+ libxml_clear_errors();
+
+ $dom = new \DOMDocument();
+ $dom->validateOnParse = true;
+ if (!$dom->loadXML($content, LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
+ libxml_disable_entity_loader($disableEntities);
+
+ throw new \InvalidArgumentException(implode("\n", static::getXmlErrors($internalErrors)));
+ }
+
+ $dom->normalizeDocument();
+
+ libxml_use_internal_errors($internalErrors);
+ libxml_disable_entity_loader($disableEntities);
+
+ foreach ($dom->childNodes as $child) {
+ if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
+ throw new \InvalidArgumentException('Document types are not allowed.');
+ }
+ }
+
+ if (null !== $schemaOrCallable) {
+ $internalErrors = libxml_use_internal_errors(true);
+ libxml_clear_errors();
+
+ $e = null;
+ if (is_callable($schemaOrCallable)) {
+ try {
+ $valid = call_user_func($schemaOrCallable, $dom, $internalErrors);
+ } catch (\Exception $e) {
+ $valid = false;
+ }
+ } elseif (!is_array($schemaOrCallable) && is_file((string) $schemaOrCallable)) {
+ $schemaSource = file_get_contents((string) $schemaOrCallable);
+ $valid = @$dom->schemaValidateSource($schemaSource);
+ } else {
+ libxml_use_internal_errors($internalErrors);
+
+ throw new \InvalidArgumentException('The schemaOrCallable argument has to be a valid path to XSD file or callable.');
+ }
+
+ if (!$valid) {
+ $messages = static::getXmlErrors($internalErrors);
+ if (empty($messages)) {
+ $messages = array(sprintf('The XML file "%s" is not valid.', $file));
+ }
+ throw new \InvalidArgumentException(implode("\n", $messages), 0, $e);
+ }
+ }
+
+ libxml_clear_errors();
+ libxml_use_internal_errors($internalErrors);
+
+ return $dom;
+ }
+
+ /**
+ * Converts a \DomElement object to a PHP array.
+ *
+ * The following rules applies during the conversion:
+ *
+ * * Each tag is converted to a key value or an array
+ * if there is more than one "value"
+ *
+ * * The content of a tag is set under a "value" key (bar )
+ * if the tag also has some nested tags
+ *
+ * * The attributes are converted to keys ( )
+ *
+ * * The nested-tags are converted to keys (bar )
+ *
+ * @param \DomElement $element A \DomElement instance
+ * @param bool $checkPrefix Check prefix in an element or an attribute name
+ *
+ * @return array A PHP array
+ */
+ public static function convertDomElementToArray(\DomElement $element, $checkPrefix = true)
+ {
+ $prefix = (string) $element->prefix;
+ $empty = true;
+ $config = array();
+ foreach ($element->attributes as $name => $node) {
+ if ($checkPrefix && !in_array((string) $node->prefix, array('', $prefix), true)) {
+ continue;
+ }
+ $config[$name] = static::phpize($node->value);
+ $empty = false;
+ }
+
+ $nodeValue = false;
+ foreach ($element->childNodes as $node) {
+ if ($node instanceof \DOMText) {
+ if ('' !== trim($node->nodeValue)) {
+ $nodeValue = trim($node->nodeValue);
+ $empty = false;
+ }
+ } elseif ($checkPrefix && $prefix != (string) $node->prefix) {
+ continue;
+ } elseif (!$node instanceof \DOMComment) {
+ $value = static::convertDomElementToArray($node, $checkPrefix);
+
+ $key = $node->localName;
+ if (isset($config[$key])) {
+ if (!is_array($config[$key]) || !is_int(key($config[$key]))) {
+ $config[$key] = array($config[$key]);
+ }
+ $config[$key][] = $value;
+ } else {
+ $config[$key] = $value;
+ }
+
+ $empty = false;
+ }
+ }
+
+ if (false !== $nodeValue) {
+ $value = static::phpize($nodeValue);
+ if (count($config)) {
+ $config['value'] = $value;
+ } else {
+ $config = $value;
+ }
+ }
+
+ return !$empty ? $config : null;
+ }
+
+ /**
+ * Converts an xml value to a PHP type.
+ *
+ * @param mixed $value
+ *
+ * @return mixed
+ */
+ public static function phpize($value)
+ {
+ $value = (string) $value;
+ $lowercaseValue = strtolower($value);
+
+ switch (true) {
+ case 'null' === $lowercaseValue:
+ return;
+ case ctype_digit($value):
+ $raw = $value;
+ $cast = (int) $value;
+
+ return '0' == $value[0] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw);
+ case isset($value[1]) && '-' === $value[0] && ctype_digit(substr($value, 1)):
+ $raw = $value;
+ $cast = (int) $value;
+
+ return '0' == $value[1] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw);
+ case 'true' === $lowercaseValue:
+ return true;
+ case 'false' === $lowercaseValue:
+ return false;
+ case isset($value[1]) && '0b' == $value[0].$value[1]:
+ return bindec($value);
+ case is_numeric($value):
+ return '0x' === $value[0].$value[1] ? hexdec($value) : (float) $value;
+ case preg_match('/^0x[0-9a-f]++$/i', $value):
+ return hexdec($value);
+ case preg_match('/^(-|\+)?[0-9]+(\.[0-9]+)?$/', $value):
+ return (float) $value;
+ default:
+ return $value;
+ }
+ }
+
+ protected static function getXmlErrors($internalErrors)
+ {
+ $errors = array();
+ foreach (libxml_get_errors() as $error) {
+ $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
+ LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
+ $error->code,
+ trim($error->message),
+ $error->file ?: 'n/a',
+ $error->line,
+ $error->column
+ );
+ }
+
+ libxml_clear_errors();
+ libxml_use_internal_errors($internalErrors);
+
+ return $errors;
+ }
+}
diff --git a/vendor/symfony/config/composer.json b/vendor/symfony/config/composer.json
new file mode 100755
index 0000000..a14d935
--- /dev/null
+++ b/vendor/symfony/config/composer.json
@@ -0,0 +1,34 @@
+{
+ "name": "symfony/config",
+ "type": "library",
+ "description": "Symfony Config Component",
+ "keywords": [],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.9",
+ "symfony/filesystem": "~2.3"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "~2.7"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Component\\Config\\": "" }
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.7-dev"
+ }
+ }
+}
diff --git a/vendor/symfony/config/phpunit.xml.dist b/vendor/symfony/config/phpunit.xml.dist
new file mode 100755
index 0000000..3fe6fd8
--- /dev/null
+++ b/vendor/symfony/config/phpunit.xml.dist
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+ ./Tests/
+
+
+
+
+
+ ./
+
+ ./Resources
+ ./Tests
+ ./vendor
+
+
+
+
diff --git a/vendor/symfony/filesystem/.gitignore b/vendor/symfony/filesystem/.gitignore
new file mode 100755
index 0000000..c49a5d8
--- /dev/null
+++ b/vendor/symfony/filesystem/.gitignore
@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml
diff --git a/vendor/symfony/filesystem/CHANGELOG.md b/vendor/symfony/filesystem/CHANGELOG.md
new file mode 100755
index 0000000..a4c0479
--- /dev/null
+++ b/vendor/symfony/filesystem/CHANGELOG.md
@@ -0,0 +1,28 @@
+CHANGELOG
+=========
+
+2.6.0
+-----
+
+ * added LockHandler
+
+2.3.12
+------
+
+ * deprecated dumpFile() file mode argument.
+
+2.3.0
+-----
+
+ * added the dumpFile() method to atomically write files
+
+2.2.0
+-----
+
+ * added a delete option for the mirror() method
+
+2.1.0
+-----
+
+ * 24eb396 : BC Break : mkdir() function now throws exception in case of failure instead of returning Boolean value
+ * created the component
diff --git a/vendor/symfony/filesystem/Exception/ExceptionInterface.php b/vendor/symfony/filesystem/Exception/ExceptionInterface.php
new file mode 100755
index 0000000..c212e66
--- /dev/null
+++ b/vendor/symfony/filesystem/Exception/ExceptionInterface.php
@@ -0,0 +1,23 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Filesystem\Exception;
+
+/**
+ * Exception interface for all exceptions thrown by the component.
+ *
+ * @author Romain Neutron
+ *
+ * @api
+ */
+interface ExceptionInterface
+{
+}
diff --git a/vendor/symfony/filesystem/Exception/FileNotFoundException.php b/vendor/symfony/filesystem/Exception/FileNotFoundException.php
new file mode 100755
index 0000000..bcc8fe8
--- /dev/null
+++ b/vendor/symfony/filesystem/Exception/FileNotFoundException.php
@@ -0,0 +1,34 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Filesystem\Exception;
+
+/**
+ * Exception class thrown when a file couldn't be found.
+ *
+ * @author Fabien Potencier
+ * @author Christian Gärtner
+ */
+class FileNotFoundException extends IOException
+{
+ public function __construct($message = null, $code = 0, \Exception $previous = null, $path = null)
+ {
+ if (null === $message) {
+ if (null === $path) {
+ $message = 'File could not be found.';
+ } else {
+ $message = sprintf('File "%s" could not be found.', $path);
+ }
+ }
+
+ parent::__construct($message, $code, $previous, $path);
+ }
+}
diff --git a/vendor/symfony/filesystem/Exception/IOException.php b/vendor/symfony/filesystem/Exception/IOException.php
new file mode 100755
index 0000000..f68a820
--- /dev/null
+++ b/vendor/symfony/filesystem/Exception/IOException.php
@@ -0,0 +1,41 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Filesystem\Exception;
+
+/**
+ * Exception class thrown when a filesystem operation failure happens.
+ *
+ * @author Romain Neutron
+ * @author Christian Gärtner
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+class IOException extends \RuntimeException implements IOExceptionInterface
+{
+ private $path;
+
+ public function __construct($message, $code = 0, \Exception $previous = null, $path = null)
+ {
+ $this->path = $path;
+
+ parent::__construct($message, $code, $previous);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+}
diff --git a/vendor/symfony/filesystem/Exception/IOExceptionInterface.php b/vendor/symfony/filesystem/Exception/IOExceptionInterface.php
new file mode 100755
index 0000000..3535058
--- /dev/null
+++ b/vendor/symfony/filesystem/Exception/IOExceptionInterface.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Filesystem\Exception;
+
+/**
+ * IOException interface for file and input/output stream related exceptions thrown by the component.
+ *
+ * @author Christian Gärtner
+ */
+interface IOExceptionInterface extends ExceptionInterface
+{
+ /**
+ * Returns the associated path for the exception.
+ *
+ * @return string The path.
+ */
+ public function getPath();
+}
diff --git a/vendor/symfony/filesystem/Filesystem.php b/vendor/symfony/filesystem/Filesystem.php
new file mode 100755
index 0000000..1bb7db3
--- /dev/null
+++ b/vendor/symfony/filesystem/Filesystem.php
@@ -0,0 +1,499 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Filesystem;
+
+use Symfony\Component\Filesystem\Exception\IOException;
+use Symfony\Component\Filesystem\Exception\FileNotFoundException;
+
+/**
+ * Provides basic utility to manipulate the file system.
+ *
+ * @author Fabien Potencier
+ */
+class Filesystem
+{
+ /**
+ * Copies a file.
+ *
+ * This method only copies the file if the origin file is newer than the target file.
+ *
+ * By default, if the target already exists, it is not overridden.
+ *
+ * @param string $originFile The original filename
+ * @param string $targetFile The target filename
+ * @param bool $override Whether to override an existing file or not
+ *
+ * @throws FileNotFoundException When originFile doesn't exist
+ * @throws IOException When copy fails
+ */
+ public function copy($originFile, $targetFile, $override = false)
+ {
+ if (stream_is_local($originFile) && !is_file($originFile)) {
+ throw new FileNotFoundException(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile);
+ }
+
+ $this->mkdir(dirname($targetFile));
+
+ $doCopy = true;
+ if (!$override && null === parse_url($originFile, PHP_URL_HOST) && is_file($targetFile)) {
+ $doCopy = filemtime($originFile) > filemtime($targetFile);
+ }
+
+ if ($doCopy) {
+ // https://bugs.php.net/bug.php?id=64634
+ if (false === $source = @fopen($originFile, 'r')) {
+ throw new IOException(sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading.', $originFile, $targetFile), 0, null, $originFile);
+ }
+
+ // Stream context created to allow files overwrite when using FTP stream wrapper - disabled by default
+ if (false === $target = @fopen($targetFile, 'w', null, stream_context_create(array('ftp' => array('overwrite' => true))))) {
+ throw new IOException(sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing.', $originFile, $targetFile), 0, null, $originFile);
+ }
+
+ $bytesCopied = stream_copy_to_stream($source, $target);
+ fclose($source);
+ fclose($target);
+ unset($source, $target);
+
+ if (!is_file($targetFile)) {
+ throw new IOException(sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile);
+ }
+
+ // Like `cp`, preserve executable permission bits
+ @chmod($targetFile, fileperms($targetFile) | (fileperms($originFile) & 0111));
+
+ if (stream_is_local($originFile) && $bytesCopied !== ($bytesOrigin = filesize($originFile))) {
+ throw new IOException(sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile);
+ }
+ }
+ }
+
+ /**
+ * Creates a directory recursively.
+ *
+ * @param string|array|\Traversable $dirs The directory path
+ * @param int $mode The directory mode
+ *
+ * @throws IOException On any directory creation failure
+ */
+ public function mkdir($dirs, $mode = 0777)
+ {
+ foreach ($this->toIterator($dirs) as $dir) {
+ if (is_dir($dir)) {
+ continue;
+ }
+
+ if (true !== @mkdir($dir, $mode, true)) {
+ $error = error_get_last();
+ if (!is_dir($dir)) {
+ // The directory was not created by a concurrent process. Let's throw an exception with a developer friendly error message if we have one
+ if ($error) {
+ throw new IOException(sprintf('Failed to create "%s": %s.', $dir, $error['message']), 0, null, $dir);
+ }
+ throw new IOException(sprintf('Failed to create "%s"', $dir), 0, null, $dir);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks the existence of files or directories.
+ *
+ * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to check
+ *
+ * @return bool true if the file exists, false otherwise
+ */
+ public function exists($files)
+ {
+ foreach ($this->toIterator($files) as $file) {
+ if (!file_exists($file)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Sets access and modification time of file.
+ *
+ * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to create
+ * @param int $time The touch time as a Unix timestamp
+ * @param int $atime The access time as a Unix timestamp
+ *
+ * @throws IOException When touch fails
+ */
+ public function touch($files, $time = null, $atime = null)
+ {
+ foreach ($this->toIterator($files) as $file) {
+ $touch = $time ? @touch($file, $time, $atime) : @touch($file);
+ if (true !== $touch) {
+ throw new IOException(sprintf('Failed to touch "%s".', $file), 0, null, $file);
+ }
+ }
+ }
+
+ /**
+ * Removes files or directories.
+ *
+ * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to remove
+ *
+ * @throws IOException When removal fails
+ */
+ public function remove($files)
+ {
+ $files = iterator_to_array($this->toIterator($files));
+ $files = array_reverse($files);
+ foreach ($files as $file) {
+ if (!file_exists($file) && !is_link($file)) {
+ continue;
+ }
+
+ if (is_dir($file) && !is_link($file)) {
+ $this->remove(new \FilesystemIterator($file));
+
+ if (true !== @rmdir($file)) {
+ throw new IOException(sprintf('Failed to remove directory "%s".', $file), 0, null, $file);
+ }
+ } else {
+ // https://bugs.php.net/bug.php?id=52176
+ if ('\\' === DIRECTORY_SEPARATOR && is_dir($file)) {
+ if (true !== @rmdir($file)) {
+ throw new IOException(sprintf('Failed to remove file "%s".', $file), 0, null, $file);
+ }
+ } else {
+ if (true !== @unlink($file)) {
+ throw new IOException(sprintf('Failed to remove file "%s".', $file), 0, null, $file);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Change mode for an array of files or directories.
+ *
+ * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change mode
+ * @param int $mode The new mode (octal)
+ * @param int $umask The mode mask (octal)
+ * @param bool $recursive Whether change the mod recursively or not
+ *
+ * @throws IOException When the change fail
+ */
+ public function chmod($files, $mode, $umask = 0000, $recursive = false)
+ {
+ foreach ($this->toIterator($files) as $file) {
+ if ($recursive && is_dir($file) && !is_link($file)) {
+ $this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
+ }
+ if (true !== @chmod($file, $mode & ~$umask)) {
+ throw new IOException(sprintf('Failed to chmod file "%s".', $file), 0, null, $file);
+ }
+ }
+ }
+
+ /**
+ * Change the owner of an array of files or directories.
+ *
+ * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change owner
+ * @param string $user The new owner user name
+ * @param bool $recursive Whether change the owner recursively or not
+ *
+ * @throws IOException When the change fail
+ */
+ public function chown($files, $user, $recursive = false)
+ {
+ foreach ($this->toIterator($files) as $file) {
+ if ($recursive && is_dir($file) && !is_link($file)) {
+ $this->chown(new \FilesystemIterator($file), $user, true);
+ }
+ if (is_link($file) && function_exists('lchown')) {
+ if (true !== @lchown($file, $user)) {
+ throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
+ }
+ } else {
+ if (true !== @chown($file, $user)) {
+ throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
+ }
+ }
+ }
+ }
+
+ /**
+ * Change the group of an array of files or directories.
+ *
+ * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change group
+ * @param string $group The group name
+ * @param bool $recursive Whether change the group recursively or not
+ *
+ * @throws IOException When the change fail
+ */
+ public function chgrp($files, $group, $recursive = false)
+ {
+ foreach ($this->toIterator($files) as $file) {
+ if ($recursive && is_dir($file) && !is_link($file)) {
+ $this->chgrp(new \FilesystemIterator($file), $group, true);
+ }
+ if (is_link($file) && function_exists('lchgrp')) {
+ if (true !== @lchgrp($file, $group) || (defined('HHVM_VERSION') && !posix_getgrnam($group))) {
+ throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
+ }
+ } else {
+ if (true !== @chgrp($file, $group)) {
+ throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
+ }
+ }
+ }
+ }
+
+ /**
+ * Renames a file or a directory.
+ *
+ * @param string $origin The origin filename or directory
+ * @param string $target The new filename or directory
+ * @param bool $overwrite Whether to overwrite the target if it already exists
+ *
+ * @throws IOException When target file or directory already exists
+ * @throws IOException When origin cannot be renamed
+ */
+ public function rename($origin, $target, $overwrite = false)
+ {
+ // we check that target does not exist
+ if (!$overwrite && is_readable($target)) {
+ throw new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target);
+ }
+
+ if (true !== @rename($origin, $target)) {
+ throw new IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target), 0, null, $target);
+ }
+ }
+
+ /**
+ * Creates a symbolic link or copy a directory.
+ *
+ * @param string $originDir The origin directory path
+ * @param string $targetDir The symbolic link name
+ * @param bool $copyOnWindows Whether to copy files if on Windows
+ *
+ * @throws IOException When symlink fails
+ */
+ public function symlink($originDir, $targetDir, $copyOnWindows = false)
+ {
+ if ('\\' === DIRECTORY_SEPARATOR && $copyOnWindows) {
+ $this->mirror($originDir, $targetDir);
+
+ return;
+ }
+
+ $this->mkdir(dirname($targetDir));
+
+ $ok = false;
+ if (is_link($targetDir)) {
+ if (readlink($targetDir) != $originDir) {
+ $this->remove($targetDir);
+ } else {
+ $ok = true;
+ }
+ }
+
+ if (!$ok && true !== @symlink($originDir, $targetDir)) {
+ $report = error_get_last();
+ if (is_array($report)) {
+ if ('\\' === DIRECTORY_SEPARATOR && false !== strpos($report['message'], 'error code(1314)')) {
+ throw new IOException('Unable to create symlink due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', 0, null, $targetDir);
+ }
+ }
+ throw new IOException(sprintf('Failed to create symbolic link from "%s" to "%s".', $originDir, $targetDir), 0, null, $targetDir);
+ }
+ }
+
+ /**
+ * Given an existing path, convert it to a path relative to a given starting path.
+ *
+ * @param string $endPath Absolute path of target
+ * @param string $startPath Absolute path where traversal begins
+ *
+ * @return string Path of target relative to starting path
+ */
+ public function makePathRelative($endPath, $startPath)
+ {
+ // Normalize separators on Windows
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $endPath = str_replace('\\', '/', $endPath);
+ $startPath = str_replace('\\', '/', $startPath);
+ }
+
+ // Split the paths into arrays
+ $startPathArr = explode('/', trim($startPath, '/'));
+ $endPathArr = explode('/', trim($endPath, '/'));
+
+ // Find for which directory the common path stops
+ $index = 0;
+ while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) {
+ ++$index;
+ }
+
+ // Determine how deep the start path is relative to the common path (ie, "web/bundles" = 2 levels)
+ $depth = count($startPathArr) - $index;
+
+ // Repeated "../" for each level need to reach the common path
+ $traverser = str_repeat('../', $depth);
+
+ $endPathRemainder = implode('/', array_slice($endPathArr, $index));
+
+ // Construct $endPath from traversing to the common path, then to the remaining $endPath
+ $relativePath = $traverser.('' !== $endPathRemainder ? $endPathRemainder.'/' : '');
+
+ return '' === $relativePath ? './' : $relativePath;
+ }
+
+ /**
+ * Mirrors a directory to another.
+ *
+ * @param string $originDir The origin directory
+ * @param string $targetDir The target directory
+ * @param \Traversable $iterator A Traversable instance
+ * @param array $options An array of boolean options
+ * Valid options are:
+ * - $options['override'] Whether to override an existing file on copy or not (see copy())
+ * - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink())
+ * - $options['delete'] Whether to delete files that are not in the source directory (defaults to false)
+ *
+ * @throws IOException When file type is unknown
+ */
+ public function mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array())
+ {
+ $targetDir = rtrim($targetDir, '/\\');
+ $originDir = rtrim($originDir, '/\\');
+
+ // Iterate in destination folder to remove obsolete entries
+ if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
+ $deleteIterator = $iterator;
+ if (null === $deleteIterator) {
+ $flags = \FilesystemIterator::SKIP_DOTS;
+ $deleteIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($targetDir, $flags), \RecursiveIteratorIterator::CHILD_FIRST);
+ }
+ foreach ($deleteIterator as $file) {
+ $origin = str_replace($targetDir, $originDir, $file->getPathname());
+ if (!$this->exists($origin)) {
+ $this->remove($file);
+ }
+ }
+ }
+
+ $copyOnWindows = false;
+ if (isset($options['copy_on_windows'])) {
+ $copyOnWindows = $options['copy_on_windows'];
+ }
+
+ if (null === $iterator) {
+ $flags = $copyOnWindows ? \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS : \FilesystemIterator::SKIP_DOTS;
+ $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST);
+ }
+
+ if ($this->exists($originDir)) {
+ $this->mkdir($targetDir);
+ }
+
+ foreach ($iterator as $file) {
+ $target = str_replace($originDir, $targetDir, $file->getPathname());
+
+ if ($copyOnWindows) {
+ if (is_link($file) || is_file($file)) {
+ $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
+ } elseif (is_dir($file)) {
+ $this->mkdir($target);
+ } else {
+ throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
+ }
+ } else {
+ if (is_link($file)) {
+ $this->symlink($file->getRealPath(), $target);
+ } elseif (is_dir($file)) {
+ $this->mkdir($target);
+ } elseif (is_file($file)) {
+ $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
+ } else {
+ throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns whether the file path is an absolute path.
+ *
+ * @param string $file A file path
+ *
+ * @return bool
+ */
+ public function isAbsolutePath($file)
+ {
+ return (strspn($file, '/\\', 0, 1)
+ || (strlen($file) > 3 && ctype_alpha($file[0])
+ && substr($file, 1, 1) === ':'
+ && (strspn($file, '/\\', 2, 1))
+ )
+ || null !== parse_url($file, PHP_URL_SCHEME)
+ );
+ }
+
+ /**
+ * Atomically dumps content into a file.
+ *
+ * @param string $filename The file to be written to.
+ * @param string $content The data to write into the file.
+ * @param null|int $mode The file mode (octal). If null, file permissions are not modified
+ * Deprecated since version 2.3.12, to be removed in 3.0.
+ *
+ * @throws IOException If the file cannot be written to.
+ */
+ public function dumpFile($filename, $content, $mode = 0666)
+ {
+ $dir = dirname($filename);
+
+ if (!is_dir($dir)) {
+ $this->mkdir($dir);
+ } elseif (!is_writable($dir)) {
+ throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir);
+ }
+
+ $tmpFile = tempnam($dir, basename($filename));
+
+ if (false === @file_put_contents($tmpFile, $content)) {
+ throw new IOException(sprintf('Failed to write file "%s".', $filename), 0, null, $filename);
+ }
+
+ $this->rename($tmpFile, $filename, true);
+ if (null !== $mode) {
+ if (func_num_args() > 2) {
+ @trigger_error('Support for modifying file permissions is deprecated since version 2.3.12 and will be removed in 3.0.', E_USER_DEPRECATED);
+ }
+
+ $this->chmod($filename, $mode);
+ }
+ }
+
+ /**
+ * @param mixed $files
+ *
+ * @return \Traversable
+ */
+ private function toIterator($files)
+ {
+ if (!$files instanceof \Traversable) {
+ $files = new \ArrayObject(is_array($files) ? $files : array($files));
+ }
+
+ return $files;
+ }
+}
diff --git a/vendor/symfony/filesystem/LICENSE b/vendor/symfony/filesystem/LICENSE
new file mode 100755
index 0000000..43028bc
--- /dev/null
+++ b/vendor/symfony/filesystem/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2015 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/symfony/filesystem/LockHandler.php b/vendor/symfony/filesystem/LockHandler.php
new file mode 100755
index 0000000..fa2575f
--- /dev/null
+++ b/vendor/symfony/filesystem/LockHandler.php
@@ -0,0 +1,114 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Filesystem;
+
+use Symfony\Component\Filesystem\Exception\IOException;
+
+/**
+ * LockHandler class provides a simple abstraction to lock anything by means of
+ * a file lock.
+ *
+ * A locked file is created based on the lock name when calling lock(). Other
+ * lock handlers will not be able to lock the same name until it is released
+ * (explicitly by calling release() or implicitly when the instance holding the
+ * lock is destroyed).
+ *
+ * @author Grégoire Pineau
+ * @author Romain Neutron
+ * @author Nicolas Grekas
+ */
+class LockHandler
+{
+ private $file;
+ private $handle;
+
+ /**
+ * @param string $name The lock name
+ * @param string|null $lockPath The directory to store the lock. Default values will use temporary directory
+ *
+ * @throws IOException If the lock directory could not be created or is not writable
+ */
+ public function __construct($name, $lockPath = null)
+ {
+ $lockPath = $lockPath ?: sys_get_temp_dir();
+
+ if (!is_dir($lockPath)) {
+ $fs = new Filesystem();
+ $fs->mkdir($lockPath);
+ }
+
+ if (!is_writable($lockPath)) {
+ throw new IOException(sprintf('The directory "%s" is not writable.', $lockPath), 0, null, $lockPath);
+ }
+
+ $this->file = sprintf('%s/sf.%s.%s.lock', $lockPath, preg_replace('/[^a-z0-9\._-]+/i', '-', $name), hash('sha256', $name));
+ }
+
+ /**
+ * Lock the resource.
+ *
+ * @param bool $blocking wait until the lock is released
+ *
+ * @return bool Returns true if the lock was acquired, false otherwise
+ *
+ * @throws IOException If the lock file could not be created or opened
+ */
+ public function lock($blocking = false)
+ {
+ if ($this->handle) {
+ return true;
+ }
+
+ // Silence both userland and native PHP error handlers
+ $errorLevel = error_reporting(0);
+ set_error_handler('var_dump', 0);
+
+ if (!$this->handle = fopen($this->file, 'r')) {
+ if ($this->handle = fopen($this->file, 'x')) {
+ chmod($this->file, 0444);
+ } elseif (!$this->handle = fopen($this->file, 'r')) {
+ usleep(100); // Give some time for chmod() to complete
+ $this->handle = fopen($this->file, 'r');
+ }
+ }
+ restore_error_handler();
+ error_reporting($errorLevel);
+
+ if (!$this->handle) {
+ $error = error_get_last();
+ throw new IOException($error['message'], 0, null, $this->file);
+ }
+
+ // On Windows, even if PHP doc says the contrary, LOCK_NB works, see
+ // https://bugs.php.net/54129
+ if (!flock($this->handle, LOCK_EX | ($blocking ? 0 : LOCK_NB))) {
+ fclose($this->handle);
+ $this->handle = null;
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Release the resource.
+ */
+ public function release()
+ {
+ if ($this->handle) {
+ flock($this->handle, LOCK_UN | LOCK_NB);
+ fclose($this->handle);
+ $this->handle = null;
+ }
+ }
+}
diff --git a/vendor/symfony/filesystem/README.md b/vendor/symfony/filesystem/README.md
new file mode 100755
index 0000000..df09f93
--- /dev/null
+++ b/vendor/symfony/filesystem/README.md
@@ -0,0 +1,47 @@
+Filesystem Component
+====================
+
+Filesystem provides basic utility to manipulate the file system:
+
+```php
+copy($originFile, $targetFile, $override = false);
+
+$filesystem->mkdir($dirs, $mode = 0777);
+
+$filesystem->touch($files, $time = null, $atime = null);
+
+$filesystem->remove($files);
+
+$filesystem->exists($files);
+
+$filesystem->chmod($files, $mode, $umask = 0000, $recursive = false);
+
+$filesystem->chown($files, $user, $recursive = false);
+
+$filesystem->chgrp($files, $group, $recursive = false);
+
+$filesystem->rename($origin, $target);
+
+$filesystem->symlink($originDir, $targetDir, $copyOnWindows = false);
+
+$filesystem->makePathRelative($endPath, $startPath);
+
+$filesystem->mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array());
+
+$filesystem->isAbsolutePath($file);
+```
+
+Resources
+---------
+
+You can run the unit tests with the following command:
+
+ $ cd path/to/Symfony/Component/Filesystem/
+ $ composer install
+ $ phpunit
diff --git a/vendor/symfony/filesystem/Tests/ExceptionTest.php b/vendor/symfony/filesystem/Tests/ExceptionTest.php
new file mode 100755
index 0000000..53bd8db
--- /dev/null
+++ b/vendor/symfony/filesystem/Tests/ExceptionTest.php
@@ -0,0 +1,46 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Filesystem\Tests;
+
+use Symfony\Component\Filesystem\Exception\IOException;
+use Symfony\Component\Filesystem\Exception\FileNotFoundException;
+
+/**
+ * Test class for Filesystem.
+ */
+class ExceptionTest extends \PHPUnit_Framework_TestCase
+{
+ public function testGetPath()
+ {
+ $e = new IOException('', 0, null, '/foo');
+ $this->assertEquals('/foo', $e->getPath(), 'The pass should be returned.');
+ }
+
+ public function testGeneratedMessage()
+ {
+ $e = new FileNotFoundException(null, 0, null, '/foo');
+ $this->assertEquals('/foo', $e->getPath());
+ $this->assertEquals('File "/foo" could not be found.', $e->getMessage(), 'A message should be generated.');
+ }
+
+ public function testGeneratedMessageWithoutPath()
+ {
+ $e = new FileNotFoundException();
+ $this->assertEquals('File could not be found.', $e->getMessage(), 'A message should be generated.');
+ }
+
+ public function testCustomMessage()
+ {
+ $e = new FileNotFoundException('bar', 0, null, '/foo');
+ $this->assertEquals('bar', $e->getMessage(), 'A custom message should be possible still.');
+ }
+}
diff --git a/vendor/symfony/filesystem/Tests/FilesystemTest.php b/vendor/symfony/filesystem/Tests/FilesystemTest.php
new file mode 100755
index 0000000..760000c
--- /dev/null
+++ b/vendor/symfony/filesystem/Tests/FilesystemTest.php
@@ -0,0 +1,1015 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Filesystem\Tests;
+
+/**
+ * Test class for Filesystem.
+ */
+class FilesystemTest extends FilesystemTestCase
+{
+ public function testCopyCreatesNewFile()
+ {
+ $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
+ $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
+
+ file_put_contents($sourceFilePath, 'SOURCE FILE');
+
+ $this->filesystem->copy($sourceFilePath, $targetFilePath);
+
+ $this->assertFileExists($targetFilePath);
+ $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Filesystem\Exception\IOException
+ */
+ public function testCopyFails()
+ {
+ $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
+ $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
+
+ $this->filesystem->copy($sourceFilePath, $targetFilePath);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Filesystem\Exception\IOException
+ */
+ public function testCopyUnreadableFileFails()
+ {
+ // skip test on Windows; PHP can't easily set file as unreadable on Windows
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('This test cannot run on Windows.');
+ }
+
+ $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
+ $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
+
+ file_put_contents($sourceFilePath, 'SOURCE FILE');
+
+ // make sure target cannot be read
+ $this->filesystem->chmod($sourceFilePath, 0222);
+
+ $this->filesystem->copy($sourceFilePath, $targetFilePath);
+ }
+
+ public function testCopyOverridesExistingFileIfModified()
+ {
+ $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
+ $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
+
+ file_put_contents($sourceFilePath, 'SOURCE FILE');
+ file_put_contents($targetFilePath, 'TARGET FILE');
+ touch($targetFilePath, time() - 1000);
+
+ $this->filesystem->copy($sourceFilePath, $targetFilePath);
+
+ $this->assertFileExists($targetFilePath);
+ $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
+ }
+
+ public function testCopyDoesNotOverrideExistingFileByDefault()
+ {
+ $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
+ $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
+
+ file_put_contents($sourceFilePath, 'SOURCE FILE');
+ file_put_contents($targetFilePath, 'TARGET FILE');
+
+ // make sure both files have the same modification time
+ $modificationTime = time() - 1000;
+ touch($sourceFilePath, $modificationTime);
+ touch($targetFilePath, $modificationTime);
+
+ $this->filesystem->copy($sourceFilePath, $targetFilePath);
+
+ $this->assertFileExists($targetFilePath);
+ $this->assertEquals('TARGET FILE', file_get_contents($targetFilePath));
+ }
+
+ public function testCopyOverridesExistingFileIfForced()
+ {
+ $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
+ $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
+
+ file_put_contents($sourceFilePath, 'SOURCE FILE');
+ file_put_contents($targetFilePath, 'TARGET FILE');
+
+ // make sure both files have the same modification time
+ $modificationTime = time() - 1000;
+ touch($sourceFilePath, $modificationTime);
+ touch($targetFilePath, $modificationTime);
+
+ $this->filesystem->copy($sourceFilePath, $targetFilePath, true);
+
+ $this->assertFileExists($targetFilePath);
+ $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Filesystem\Exception\IOException
+ */
+ public function testCopyWithOverrideWithReadOnlyTargetFails()
+ {
+ // skip test on Windows; PHP can't easily set file as unwritable on Windows
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('This test cannot run on Windows.');
+ }
+
+ $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
+ $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
+
+ file_put_contents($sourceFilePath, 'SOURCE FILE');
+ file_put_contents($targetFilePath, 'TARGET FILE');
+
+ // make sure both files have the same modification time
+ $modificationTime = time() - 1000;
+ touch($sourceFilePath, $modificationTime);
+ touch($targetFilePath, $modificationTime);
+
+ // make sure target is read-only
+ $this->filesystem->chmod($targetFilePath, 0444);
+
+ $this->filesystem->copy($sourceFilePath, $targetFilePath, true);
+ }
+
+ public function testCopyCreatesTargetDirectoryIfItDoesNotExist()
+ {
+ $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
+ $targetFileDirectory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
+ $targetFilePath = $targetFileDirectory.DIRECTORY_SEPARATOR.'copy_target_file';
+
+ file_put_contents($sourceFilePath, 'SOURCE FILE');
+
+ $this->filesystem->copy($sourceFilePath, $targetFilePath);
+
+ $this->assertTrue(is_dir($targetFileDirectory));
+ $this->assertFileExists($targetFilePath);
+ $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
+ }
+
+ public function testCopyForOriginUrlsAndExistingLocalFileDefaultsToNotCopy()
+ {
+ $sourceFilePath = 'http://symfony.com/images/common/logo/logo_symfony_header.png';
+ $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
+
+ file_put_contents($targetFilePath, 'TARGET FILE');
+
+ $this->filesystem->copy($sourceFilePath, $targetFilePath, false);
+
+ $this->assertFileExists($targetFilePath);
+ $this->assertEquals(file_get_contents($sourceFilePath), file_get_contents($targetFilePath));
+ }
+
+ public function testMkdirCreatesDirectoriesRecursively()
+ {
+ $directory = $this->workspace
+ .DIRECTORY_SEPARATOR.'directory'
+ .DIRECTORY_SEPARATOR.'sub_directory';
+
+ $this->filesystem->mkdir($directory);
+
+ $this->assertTrue(is_dir($directory));
+ }
+
+ public function testMkdirCreatesDirectoriesFromArray()
+ {
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR;
+ $directories = array(
+ $basePath.'1', $basePath.'2', $basePath.'3',
+ );
+
+ $this->filesystem->mkdir($directories);
+
+ $this->assertTrue(is_dir($basePath.'1'));
+ $this->assertTrue(is_dir($basePath.'2'));
+ $this->assertTrue(is_dir($basePath.'3'));
+ }
+
+ public function testMkdirCreatesDirectoriesFromTraversableObject()
+ {
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR;
+ $directories = new \ArrayObject(array(
+ $basePath.'1', $basePath.'2', $basePath.'3',
+ ));
+
+ $this->filesystem->mkdir($directories);
+
+ $this->assertTrue(is_dir($basePath.'1'));
+ $this->assertTrue(is_dir($basePath.'2'));
+ $this->assertTrue(is_dir($basePath.'3'));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Filesystem\Exception\IOException
+ */
+ public function testMkdirCreatesDirectoriesFails()
+ {
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR;
+ $dir = $basePath.'2';
+
+ file_put_contents($dir, '');
+
+ $this->filesystem->mkdir($dir);
+ }
+
+ public function testTouchCreatesEmptyFile()
+ {
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'1';
+
+ $this->filesystem->touch($file);
+
+ $this->assertFileExists($file);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Filesystem\Exception\IOException
+ */
+ public function testTouchFails()
+ {
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'1'.DIRECTORY_SEPARATOR.'2';
+
+ $this->filesystem->touch($file);
+ }
+
+ public function testTouchCreatesEmptyFilesFromArray()
+ {
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR;
+ $files = array(
+ $basePath.'1', $basePath.'2', $basePath.'3',
+ );
+
+ $this->filesystem->touch($files);
+
+ $this->assertFileExists($basePath.'1');
+ $this->assertFileExists($basePath.'2');
+ $this->assertFileExists($basePath.'3');
+ }
+
+ public function testTouchCreatesEmptyFilesFromTraversableObject()
+ {
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR;
+ $files = new \ArrayObject(array(
+ $basePath.'1', $basePath.'2', $basePath.'3',
+ ));
+
+ $this->filesystem->touch($files);
+
+ $this->assertFileExists($basePath.'1');
+ $this->assertFileExists($basePath.'2');
+ $this->assertFileExists($basePath.'3');
+ }
+
+ public function testRemoveCleansFilesAndDirectoriesIteratively()
+ {
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
+
+ mkdir($basePath);
+ mkdir($basePath.'dir');
+ touch($basePath.'file');
+
+ $this->filesystem->remove($basePath);
+
+ $this->assertTrue(!is_dir($basePath));
+ }
+
+ public function testRemoveCleansArrayOfFilesAndDirectories()
+ {
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR;
+
+ mkdir($basePath.'dir');
+ touch($basePath.'file');
+
+ $files = array(
+ $basePath.'dir', $basePath.'file',
+ );
+
+ $this->filesystem->remove($files);
+
+ $this->assertTrue(!is_dir($basePath.'dir'));
+ $this->assertTrue(!is_file($basePath.'file'));
+ }
+
+ public function testRemoveCleansTraversableObjectOfFilesAndDirectories()
+ {
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR;
+
+ mkdir($basePath.'dir');
+ touch($basePath.'file');
+
+ $files = new \ArrayObject(array(
+ $basePath.'dir', $basePath.'file',
+ ));
+
+ $this->filesystem->remove($files);
+
+ $this->assertTrue(!is_dir($basePath.'dir'));
+ $this->assertTrue(!is_file($basePath.'file'));
+ }
+
+ public function testRemoveIgnoresNonExistingFiles()
+ {
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR;
+
+ mkdir($basePath.'dir');
+
+ $files = array(
+ $basePath.'dir', $basePath.'file',
+ );
+
+ $this->filesystem->remove($files);
+
+ $this->assertTrue(!is_dir($basePath.'dir'));
+ }
+
+ public function testRemoveCleansInvalidLinks()
+ {
+ $this->markAsSkippedIfSymlinkIsMissing();
+
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
+
+ mkdir($basePath);
+ mkdir($basePath.'dir');
+ // create symlink to nonexistent file
+ @symlink($basePath.'file', $basePath.'link');
+
+ $this->filesystem->remove($basePath);
+
+ $this->assertTrue(!is_dir($basePath));
+ }
+
+ public function testFilesExists()
+ {
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
+
+ mkdir($basePath);
+ touch($basePath.'file1');
+ mkdir($basePath.'folder');
+
+ $this->assertTrue($this->filesystem->exists($basePath.'file1'));
+ $this->assertTrue($this->filesystem->exists($basePath.'folder'));
+ }
+
+ public function testFilesExistsTraversableObjectOfFilesAndDirectories()
+ {
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR;
+
+ mkdir($basePath.'dir');
+ touch($basePath.'file');
+
+ $files = new \ArrayObject(array(
+ $basePath.'dir', $basePath.'file',
+ ));
+
+ $this->assertTrue($this->filesystem->exists($files));
+ }
+
+ public function testFilesNotExistsTraversableObjectOfFilesAndDirectories()
+ {
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR;
+
+ mkdir($basePath.'dir');
+ touch($basePath.'file');
+ touch($basePath.'file2');
+
+ $files = new \ArrayObject(array(
+ $basePath.'dir', $basePath.'file', $basePath.'file2',
+ ));
+
+ unlink($basePath.'file');
+
+ $this->assertFalse($this->filesystem->exists($files));
+ }
+
+ public function testInvalidFileNotExists()
+ {
+ $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
+
+ $this->assertFalse($this->filesystem->exists($basePath.time()));
+ }
+
+ public function testChmodChangesFileMode()
+ {
+ $this->markAsSkippedIfChmodIsMissing();
+
+ $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
+ mkdir($dir);
+ $file = $dir.DIRECTORY_SEPARATOR.'file';
+ touch($file);
+
+ $this->filesystem->chmod($file, 0400);
+ $this->filesystem->chmod($dir, 0753);
+
+ $this->assertFilePermissions(753, $dir);
+ $this->assertFilePermissions(400, $file);
+ }
+
+ public function testChmodWrongMod()
+ {
+ $this->markAsSkippedIfChmodIsMissing();
+
+ $dir = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ touch($dir);
+
+ $this->filesystem->chmod($dir, 'Wrongmode');
+ }
+
+ public function testChmodRecursive()
+ {
+ $this->markAsSkippedIfChmodIsMissing();
+
+ $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
+ mkdir($dir);
+ $file = $dir.DIRECTORY_SEPARATOR.'file';
+ touch($file);
+
+ $this->filesystem->chmod($file, 0400, 0000, true);
+ $this->filesystem->chmod($dir, 0753, 0000, true);
+
+ $this->assertFilePermissions(753, $dir);
+ $this->assertFilePermissions(753, $file);
+ }
+
+ public function testChmodAppliesUmask()
+ {
+ $this->markAsSkippedIfChmodIsMissing();
+
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ touch($file);
+
+ $this->filesystem->chmod($file, 0770, 0022);
+ $this->assertFilePermissions(750, $file);
+ }
+
+ public function testChmodChangesModeOfArrayOfFiles()
+ {
+ $this->markAsSkippedIfChmodIsMissing();
+
+ $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ $files = array($directory, $file);
+
+ mkdir($directory);
+ touch($file);
+
+ $this->filesystem->chmod($files, 0753);
+
+ $this->assertFilePermissions(753, $file);
+ $this->assertFilePermissions(753, $directory);
+ }
+
+ public function testChmodChangesModeOfTraversableFileObject()
+ {
+ $this->markAsSkippedIfChmodIsMissing();
+
+ $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ $files = new \ArrayObject(array($directory, $file));
+
+ mkdir($directory);
+ touch($file);
+
+ $this->filesystem->chmod($files, 0753);
+
+ $this->assertFilePermissions(753, $file);
+ $this->assertFilePermissions(753, $directory);
+ }
+
+ public function testChown()
+ {
+ $this->markAsSkippedIfPosixIsMissing();
+
+ $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
+ mkdir($dir);
+
+ $this->filesystem->chown($dir, $this->getFileOwner($dir));
+ }
+
+ public function testChownRecursive()
+ {
+ $this->markAsSkippedIfPosixIsMissing();
+
+ $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
+ mkdir($dir);
+ $file = $dir.DIRECTORY_SEPARATOR.'file';
+ touch($file);
+
+ $this->filesystem->chown($dir, $this->getFileOwner($dir), true);
+ }
+
+ public function testChownSymlink()
+ {
+ $this->markAsSkippedIfSymlinkIsMissing();
+
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
+
+ touch($file);
+
+ $this->filesystem->symlink($file, $link);
+
+ $this->filesystem->chown($link, $this->getFileOwner($link));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Filesystem\Exception\IOException
+ */
+ public function testChownSymlinkFails()
+ {
+ $this->markAsSkippedIfSymlinkIsMissing();
+
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
+
+ touch($file);
+
+ $this->filesystem->symlink($file, $link);
+
+ $this->filesystem->chown($link, 'user'.time().mt_rand(1000, 9999));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Filesystem\Exception\IOException
+ */
+ public function testChownFail()
+ {
+ $this->markAsSkippedIfPosixIsMissing();
+
+ $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
+ mkdir($dir);
+
+ $this->filesystem->chown($dir, 'user'.time().mt_rand(1000, 9999));
+ }
+
+ public function testChgrp()
+ {
+ $this->markAsSkippedIfPosixIsMissing();
+
+ $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
+ mkdir($dir);
+
+ $this->filesystem->chgrp($dir, $this->getFileGroup($dir));
+ }
+
+ public function testChgrpRecursive()
+ {
+ $this->markAsSkippedIfPosixIsMissing();
+
+ $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
+ mkdir($dir);
+ $file = $dir.DIRECTORY_SEPARATOR.'file';
+ touch($file);
+
+ $this->filesystem->chgrp($dir, $this->getFileGroup($dir), true);
+ }
+
+ public function testChgrpSymlink()
+ {
+ $this->markAsSkippedIfSymlinkIsMissing();
+
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
+
+ touch($file);
+
+ $this->filesystem->symlink($file, $link);
+
+ $this->filesystem->chgrp($link, $this->getFileGroup($link));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Filesystem\Exception\IOException
+ */
+ public function testChgrpSymlinkFails()
+ {
+ $this->markAsSkippedIfSymlinkIsMissing();
+
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
+
+ touch($file);
+
+ $this->filesystem->symlink($file, $link);
+
+ $this->filesystem->chgrp($link, 'user'.time().mt_rand(1000, 9999));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Filesystem\Exception\IOException
+ */
+ public function testChgrpFail()
+ {
+ $this->markAsSkippedIfPosixIsMissing();
+
+ $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
+ mkdir($dir);
+
+ $this->filesystem->chgrp($dir, 'user'.time().mt_rand(1000, 9999));
+ }
+
+ public function testRename()
+ {
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
+ touch($file);
+
+ $this->filesystem->rename($file, $newPath);
+
+ $this->assertFileNotExists($file);
+ $this->assertFileExists($newPath);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Filesystem\Exception\IOException
+ */
+ public function testRenameThrowsExceptionIfTargetAlreadyExists()
+ {
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
+
+ touch($file);
+ touch($newPath);
+
+ $this->filesystem->rename($file, $newPath);
+ }
+
+ public function testRenameOverwritesTheTargetIfItAlreadyExists()
+ {
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
+
+ touch($file);
+ touch($newPath);
+
+ $this->filesystem->rename($file, $newPath, true);
+
+ $this->assertFileNotExists($file);
+ $this->assertFileExists($newPath);
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Filesystem\Exception\IOException
+ */
+ public function testRenameThrowsExceptionOnError()
+ {
+ $file = $this->workspace.DIRECTORY_SEPARATOR.uniqid('fs_test_', true);
+ $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
+
+ $this->filesystem->rename($file, $newPath);
+ }
+
+ public function testSymlink()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('Windows does not support creating "broken" symlinks');
+ }
+
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
+
+ // $file does not exists right now: creating "broken" links is a wanted feature
+ $this->filesystem->symlink($file, $link);
+
+ $this->assertTrue(is_link($link));
+
+ // Create the linked file AFTER creating the link
+ touch($file);
+
+ $this->assertEquals($file, readlink($link));
+ }
+
+ /**
+ * @depends testSymlink
+ */
+ public function testRemoveSymlink()
+ {
+ $this->markAsSkippedIfSymlinkIsMissing();
+
+ $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
+
+ $this->filesystem->remove($link);
+
+ $this->assertTrue(!is_link($link));
+ }
+
+ public function testSymlinkIsOverwrittenIfPointsToDifferentTarget()
+ {
+ $this->markAsSkippedIfSymlinkIsMissing();
+
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
+
+ touch($file);
+ symlink($this->workspace, $link);
+
+ $this->filesystem->symlink($file, $link);
+
+ $this->assertTrue(is_link($link));
+ $this->assertEquals($file, readlink($link));
+ }
+
+ public function testSymlinkIsNotOverwrittenIfAlreadyCreated()
+ {
+ $this->markAsSkippedIfSymlinkIsMissing();
+
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
+
+ touch($file);
+ symlink($file, $link);
+
+ $this->filesystem->symlink($file, $link);
+
+ $this->assertTrue(is_link($link));
+ $this->assertEquals($file, readlink($link));
+ }
+
+ public function testSymlinkCreatesTargetDirectoryIfItDoesNotExist()
+ {
+ $this->markAsSkippedIfSymlinkIsMissing();
+
+ $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
+ $link1 = $this->workspace.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'link';
+ $link2 = $this->workspace.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'subdir'.DIRECTORY_SEPARATOR.'link';
+
+ touch($file);
+
+ $this->filesystem->symlink($file, $link1);
+ $this->filesystem->symlink($file, $link2);
+
+ $this->assertTrue(is_link($link1));
+ $this->assertEquals($file, readlink($link1));
+ $this->assertTrue(is_link($link2));
+ $this->assertEquals($file, readlink($link2));
+ }
+
+ /**
+ * @dataProvider providePathsForMakePathRelative
+ */
+ public function testMakePathRelative($endPath, $startPath, $expectedPath)
+ {
+ $path = $this->filesystem->makePathRelative($endPath, $startPath);
+
+ $this->assertEquals($expectedPath, $path);
+ }
+
+ /**
+ * @return array
+ */
+ public function providePathsForMakePathRelative()
+ {
+ $paths = array(
+ array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component', '../'),
+ array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component/', '../'),
+ array('/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component', '../'),
+ array('/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component/', '../'),
+ array('var/lib/symfony/', 'var/lib/symfony/src/Symfony/Component', '../../../'),
+ array('/usr/lib/symfony/', '/var/lib/symfony/src/Symfony/Component', '../../../../../../usr/lib/symfony/'),
+ array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/', 'src/Symfony/'),
+ array('/aa/bb', '/aa/bb', './'),
+ array('/aa/bb', '/aa/bb/', './'),
+ array('/aa/bb/', '/aa/bb', './'),
+ array('/aa/bb/', '/aa/bb/', './'),
+ array('/aa/bb/cc', '/aa/bb/cc/dd', '../'),
+ array('/aa/bb/cc', '/aa/bb/cc/dd/', '../'),
+ array('/aa/bb/cc/', '/aa/bb/cc/dd', '../'),
+ array('/aa/bb/cc/', '/aa/bb/cc/dd/', '../'),
+ array('/aa/bb/cc', '/aa', 'bb/cc/'),
+ array('/aa/bb/cc', '/aa/', 'bb/cc/'),
+ array('/aa/bb/cc/', '/aa', 'bb/cc/'),
+ array('/aa/bb/cc/', '/aa/', 'bb/cc/'),
+ array('/a/aab/bb', '/a/aa', '../aab/bb/'),
+ array('/a/aab/bb', '/a/aa/', '../aab/bb/'),
+ array('/a/aab/bb/', '/a/aa', '../aab/bb/'),
+ array('/a/aab/bb/', '/a/aa/', '../aab/bb/'),
+ );
+
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $paths[] = array('c:\var\lib/symfony/src/Symfony/', 'c:/var/lib/symfony/', 'src/Symfony/');
+ }
+
+ return $paths;
+ }
+
+ public function testMirrorCopiesFilesAndDirectoriesRecursively()
+ {
+ $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
+ $directory = $sourcePath.'directory'.DIRECTORY_SEPARATOR;
+ $file1 = $directory.'file1';
+ $file2 = $sourcePath.'file2';
+
+ mkdir($sourcePath);
+ mkdir($directory);
+ file_put_contents($file1, 'FILE1');
+ file_put_contents($file2, 'FILE2');
+
+ $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
+
+ $this->filesystem->mirror($sourcePath, $targetPath);
+
+ $this->assertTrue(is_dir($targetPath));
+ $this->assertTrue(is_dir($targetPath.'directory'));
+ $this->assertFileEquals($file1, $targetPath.'directory'.DIRECTORY_SEPARATOR.'file1');
+ $this->assertFileEquals($file2, $targetPath.'file2');
+
+ $this->filesystem->remove($file1);
+
+ $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => false));
+ $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
+
+ $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
+ $this->assertFalse($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
+
+ file_put_contents($file1, 'FILE1');
+
+ $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
+ $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
+
+ $this->filesystem->remove($directory);
+ $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
+ $this->assertFalse($this->filesystem->exists($targetPath.'directory'));
+ $this->assertFalse($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
+ }
+
+ public function testMirrorCreatesEmptyDirectory()
+ {
+ $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
+
+ mkdir($sourcePath);
+
+ $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
+
+ $this->filesystem->mirror($sourcePath, $targetPath);
+
+ $this->assertTrue(is_dir($targetPath));
+
+ $this->filesystem->remove($sourcePath);
+ }
+
+ public function testMirrorCopiesLinks()
+ {
+ $this->markAsSkippedIfSymlinkIsMissing();
+
+ $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
+
+ mkdir($sourcePath);
+ file_put_contents($sourcePath.'file1', 'FILE1');
+ symlink($sourcePath.'file1', $sourcePath.'link1');
+
+ $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
+
+ $this->filesystem->mirror($sourcePath, $targetPath);
+
+ $this->assertTrue(is_dir($targetPath));
+ $this->assertFileEquals($sourcePath.'file1', $targetPath.DIRECTORY_SEPARATOR.'link1');
+ $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
+ }
+
+ public function testMirrorCopiesLinkedDirectoryContents()
+ {
+ $this->markAsSkippedIfSymlinkIsMissing();
+
+ $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
+
+ mkdir($sourcePath.'nested/', 0777, true);
+ file_put_contents($sourcePath.'/nested/file1.txt', 'FILE1');
+ // Note: We symlink directory, not file
+ symlink($sourcePath.'nested', $sourcePath.'link1');
+
+ $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
+
+ $this->filesystem->mirror($sourcePath, $targetPath);
+
+ $this->assertTrue(is_dir($targetPath));
+ $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.DIRECTORY_SEPARATOR.'link1/file1.txt');
+ $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
+ }
+
+ public function testMirrorCopiesRelativeLinkedContents()
+ {
+ $this->markAsSkippedIfSymlinkIsMissing();
+
+ $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
+ $oldPath = getcwd();
+
+ mkdir($sourcePath.'nested/', 0777, true);
+ file_put_contents($sourcePath.'/nested/file1.txt', 'FILE1');
+ // Note: Create relative symlink
+ chdir($sourcePath);
+ symlink('nested', 'link1');
+
+ chdir($oldPath);
+
+ $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
+
+ $this->filesystem->mirror($sourcePath, $targetPath);
+
+ $this->assertTrue(is_dir($targetPath));
+ $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.DIRECTORY_SEPARATOR.'link1/file1.txt');
+ $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
+ $this->assertEquals($sourcePath.'nested', readlink($targetPath.DIRECTORY_SEPARATOR.'link1'));
+ }
+
+ /**
+ * @dataProvider providePathsForIsAbsolutePath
+ */
+ public function testIsAbsolutePath($path, $expectedResult)
+ {
+ $result = $this->filesystem->isAbsolutePath($path);
+
+ $this->assertEquals($expectedResult, $result);
+ }
+
+ /**
+ * @return array
+ */
+ public function providePathsForIsAbsolutePath()
+ {
+ return array(
+ array('/var/lib', true),
+ array('c:\\\\var\\lib', true),
+ array('\\var\\lib', true),
+ array('var/lib', false),
+ array('../var/lib', false),
+ array('', false),
+ array(null, false),
+ );
+ }
+
+ public function testDumpFile()
+ {
+ $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
+
+ $this->filesystem->dumpFile($filename, 'bar');
+
+ $this->assertFileExists($filename);
+ $this->assertSame('bar', file_get_contents($filename));
+ }
+
+ /**
+ * @group legacy
+ */
+ public function testDumpFileAndSetPermissions()
+ {
+ $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
+
+ $this->filesystem->dumpFile($filename, 'bar', 0753);
+
+ $this->assertFileExists($filename);
+ $this->assertSame('bar', file_get_contents($filename));
+
+ // skip mode check on Windows
+ if ('\\' !== DIRECTORY_SEPARATOR) {
+ $this->assertFilePermissions(753, $filename);
+ }
+ }
+
+ public function testDumpFileWithNullMode()
+ {
+ $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
+
+ $this->filesystem->dumpFile($filename, 'bar', null);
+
+ $this->assertFileExists($filename);
+ $this->assertSame('bar', file_get_contents($filename));
+
+ // skip mode check on Windows
+ if ('\\' !== DIRECTORY_SEPARATOR) {
+ $this->assertFilePermissions(600, $filename);
+ }
+ }
+
+ public function testDumpFileOverwritesAnExistingFile()
+ {
+ $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo.txt';
+ file_put_contents($filename, 'FOO BAR');
+
+ $this->filesystem->dumpFile($filename, 'bar');
+
+ $this->assertFileExists($filename);
+ $this->assertSame('bar', file_get_contents($filename));
+ }
+
+ public function testCopyShouldKeepExecutionPermission()
+ {
+ $this->markAsSkippedIfChmodIsMissing();
+
+ $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
+ $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
+
+ file_put_contents($sourceFilePath, 'SOURCE FILE');
+ chmod($sourceFilePath, 0745);
+
+ $this->filesystem->copy($sourceFilePath, $targetFilePath);
+
+ $this->assertFilePermissions(767, $targetFilePath);
+ }
+}
diff --git a/vendor/symfony/filesystem/Tests/FilesystemTestCase.php b/vendor/symfony/filesystem/Tests/FilesystemTestCase.php
new file mode 100755
index 0000000..0ef9c8d
--- /dev/null
+++ b/vendor/symfony/filesystem/Tests/FilesystemTestCase.php
@@ -0,0 +1,119 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Filesystem\Tests;
+
+use Symfony\Component\Filesystem\Filesystem;
+
+class FilesystemTestCase extends \PHPUnit_Framework_TestCase
+{
+ private $umask;
+
+ /**
+ * @var \Symfony\Component\Filesystem\Filesystem
+ */
+ protected $filesystem = null;
+
+ /**
+ * @var string
+ */
+ protected $workspace = null;
+
+ private static $symlinkOnWindows = null;
+
+ public static function setUpBeforeClass()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR && null === self::$symlinkOnWindows) {
+ $target = tempnam(sys_get_temp_dir(), 'sl');
+ $link = sys_get_temp_dir().'/sl'.microtime(true).mt_rand();
+ if (self::$symlinkOnWindows = @symlink($target, $link)) {
+ unlink($link);
+ }
+ unlink($target);
+ }
+ }
+
+ protected function setUp()
+ {
+ $this->umask = umask(0);
+ $this->workspace = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.time().mt_rand(0, 1000);
+ mkdir($this->workspace, 0777, true);
+ $this->workspace = realpath($this->workspace);
+ $this->filesystem = new Filesystem();
+ }
+
+ protected function tearDown()
+ {
+ $this->filesystem->remove($this->workspace);
+ umask($this->umask);
+ }
+
+ /**
+ * @param int $expectedFilePerms expected file permissions as three digits (i.e. 755)
+ * @param string $filePath
+ */
+ protected function assertFilePermissions($expectedFilePerms, $filePath)
+ {
+ $actualFilePerms = (int) substr(sprintf('%o', fileperms($filePath)), -3);
+ $this->assertEquals(
+ $expectedFilePerms,
+ $actualFilePerms,
+ sprintf('File permissions for %s must be %s. Actual %s', $filePath, $expectedFilePerms, $actualFilePerms)
+ );
+ }
+
+ protected function getFileOwner($filepath)
+ {
+ $this->markAsSkippedIfPosixIsMissing();
+
+ $infos = stat($filepath);
+ if ($datas = posix_getpwuid($infos['uid'])) {
+ return $datas['name'];
+ }
+ }
+
+ protected function getFileGroup($filepath)
+ {
+ $this->markAsSkippedIfPosixIsMissing();
+
+ $infos = stat($filepath);
+ if ($datas = posix_getgrgid($infos['gid'])) {
+ return $datas['name'];
+ }
+
+ $this->markTestSkipped('Unable to retrieve file group name');
+ }
+
+ protected function markAsSkippedIfSymlinkIsMissing()
+ {
+ if (!function_exists('symlink')) {
+ $this->markTestSkipped('symlink is not supported');
+ }
+
+ if ('\\' === DIRECTORY_SEPARATOR && false === self::$symlinkOnWindows) {
+ $this->markTestSkipped('symlink requires "Create symbolic links" privilege on windows');
+ }
+ }
+
+ protected function markAsSkippedIfChmodIsMissing()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR) {
+ $this->markTestSkipped('chmod is not supported on windows');
+ }
+ }
+
+ protected function markAsSkippedIfPosixIsMissing()
+ {
+ if ('\\' === DIRECTORY_SEPARATOR || !function_exists('posix_isatty')) {
+ $this->markTestSkipped('Posix is not supported');
+ }
+ }
+}
diff --git a/vendor/symfony/filesystem/Tests/LockHandlerTest.php b/vendor/symfony/filesystem/Tests/LockHandlerTest.php
new file mode 100755
index 0000000..f229ffd
--- /dev/null
+++ b/vendor/symfony/filesystem/Tests/LockHandlerTest.php
@@ -0,0 +1,91 @@
+markTestSkipped('This test will fail if run under superuser');
+ }
+ new LockHandler('lock', '/a/b/c/d/e');
+ }
+
+ /**
+ * @expectedException Symfony\Component\Filesystem\Exception\IOException
+ * @expectedExceptionMessage The directory "/" is not writable.
+ */
+ public function testConstructWhenRepositoryIsNotWriteable()
+ {
+ if (!getenv('USER') || 'root' === getenv('USER')) {
+ $this->markTestSkipped('This test will fail if run under superuser');
+ }
+ new LockHandler('lock', '/');
+ }
+
+ public function testConstructSanitizeName()
+ {
+ $lock = new LockHandler('');
+
+ $file = sprintf('%s/sf.-php-echo-hello-word-.4b3d9d0d27ddef3a78a64685dda3a963e478659a9e5240feaf7b4173a8f28d5f.lock', sys_get_temp_dir());
+ // ensure the file does not exist before the lock
+ @unlink($file);
+
+ $lock->lock();
+
+ $this->assertFileExists($file);
+
+ $lock->release();
+ }
+
+ public function testLockRelease()
+ {
+ $name = 'symfony-test-filesystem.lock';
+
+ $l1 = new LockHandler($name);
+ $l2 = new LockHandler($name);
+
+ $this->assertTrue($l1->lock());
+ $this->assertFalse($l2->lock());
+
+ $l1->release();
+
+ $this->assertTrue($l2->lock());
+ $l2->release();
+ }
+
+ public function testLockTwice()
+ {
+ $name = 'symfony-test-filesystem.lock';
+
+ $lockHandler = new LockHandler($name);
+
+ $this->assertTrue($lockHandler->lock());
+ $this->assertTrue($lockHandler->lock());
+
+ $lockHandler->release();
+ }
+
+ public function testLockIsReleased()
+ {
+ $name = 'symfony-test-filesystem.lock';
+
+ $l1 = new LockHandler($name);
+ $l2 = new LockHandler($name);
+
+ $this->assertTrue($l1->lock());
+ $this->assertFalse($l2->lock());
+
+ $l1 = null;
+
+ $this->assertTrue($l2->lock());
+ $l2->release();
+ }
+}
diff --git a/vendor/symfony/filesystem/composer.json b/vendor/symfony/filesystem/composer.json
new file mode 100755
index 0000000..820d9f1
--- /dev/null
+++ b/vendor/symfony/filesystem/composer.json
@@ -0,0 +1,33 @@
+{
+ "name": "symfony/filesystem",
+ "type": "library",
+ "description": "Symfony Filesystem Component",
+ "keywords": [],
+ "homepage": "https://symfony.com",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "~2.7"
+ },
+ "autoload": {
+ "psr-4": { "Symfony\\Component\\Filesystem\\": "" }
+ },
+ "minimum-stability": "dev",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.7-dev"
+ }
+ }
+}
diff --git a/vendor/symfony/filesystem/phpunit.xml.dist b/vendor/symfony/filesystem/phpunit.xml.dist
new file mode 100755
index 0000000..7c6ba7a
--- /dev/null
+++ b/vendor/symfony/filesystem/phpunit.xml.dist
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+ ./Tests/
+
+
+
+
+
+ ./
+
+ ./Tests
+
+
+
+
diff --git a/vendor/symfony/translation/.gitignore b/vendor/symfony/translation/.gitignore
new file mode 100755
index 0000000..c49a5d8
--- /dev/null
+++ b/vendor/symfony/translation/.gitignore
@@ -0,0 +1,3 @@
+vendor/
+composer.lock
+phpunit.xml
diff --git a/vendor/symfony/translation/CHANGELOG.md b/vendor/symfony/translation/CHANGELOG.md
new file mode 100755
index 0000000..157752c
--- /dev/null
+++ b/vendor/symfony/translation/CHANGELOG.md
@@ -0,0 +1,47 @@
+CHANGELOG
+=========
+
+2.7.0
+-----
+
+ * added DataCollectorTranslator for collecting the translated messages.
+
+2.6.0
+-----
+
+ * added possibility to cache catalogues
+ * added TranslatorBagInterface
+ * added LoggingTranslator
+ * added Translator::getMessages() for retrieving the message catalogue as an array
+
+2.5.0
+-----
+
+ * added relative file path template to the file dumpers
+ * added optional backup to the file dumpers
+ * changed IcuResFileDumper to extend FileDumper
+
+2.3.0
+-----
+
+ * added classes to make operations on catalogues (like making a diff or a merge on 2 catalogues)
+ * added Translator::getFallbackLocales()
+ * deprecated Translator::setFallbackLocale() in favor of the new Translator::setFallbackLocales() method
+
+2.2.0
+-----
+
+ * QtTranslationsLoader class renamed to QtFileLoader. QtTranslationsLoader is deprecated and will be removed in 2.3.
+ * [BC BREAK] uniformized the exception thrown by the load() method when an error occurs. The load() method now
+ throws Symfony\Component\Translation\Exception\NotFoundResourceException when a resource cannot be found
+ and Symfony\Component\Translation\Exception\InvalidResourceException when a resource is invalid.
+ * changed the exception class thrown by some load() methods from \RuntimeException to \InvalidArgumentException
+ (IcuDatFileLoader, IcuResFileLoader and QtFileLoader)
+
+2.1.0
+-----
+
+ * added support for more than one fallback locale
+ * added support for extracting translation messages from templates (Twig and PHP)
+ * added dumpers for translation catalogs
+ * added support for QT, gettext, and ResourceBundles
diff --git a/vendor/symfony/translation/Catalogue/AbstractOperation.php b/vendor/symfony/translation/Catalogue/AbstractOperation.php
new file mode 100755
index 0000000..062056b
--- /dev/null
+++ b/vendor/symfony/translation/Catalogue/AbstractOperation.php
@@ -0,0 +1,146 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Catalogue;
+
+use Symfony\Component\Translation\MessageCatalogue;
+use Symfony\Component\Translation\MessageCatalogueInterface;
+
+/**
+ * Base catalogues binary operation class.
+ *
+ * @author Jean-François Simon
+ */
+abstract class AbstractOperation implements OperationInterface
+{
+ /**
+ * @var MessageCatalogueInterface
+ */
+ protected $source;
+
+ /**
+ * @var MessageCatalogueInterface
+ */
+ protected $target;
+
+ /**
+ * @var MessageCatalogue
+ */
+ protected $result;
+
+ /**
+ * @var null|array
+ */
+ private $domains;
+
+ /**
+ * @var array
+ */
+ protected $messages;
+
+ /**
+ * @param MessageCatalogueInterface $source
+ * @param MessageCatalogueInterface $target
+ *
+ * @throws \LogicException
+ */
+ public function __construct(MessageCatalogueInterface $source, MessageCatalogueInterface $target)
+ {
+ if ($source->getLocale() !== $target->getLocale()) {
+ throw new \LogicException('Operated catalogues must belong to the same locale.');
+ }
+
+ $this->source = $source;
+ $this->target = $target;
+ $this->result = new MessageCatalogue($source->getLocale());
+ $this->domains = null;
+ $this->messages = array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDomains()
+ {
+ if (null === $this->domains) {
+ $this->domains = array_values(array_unique(array_merge($this->source->getDomains(), $this->target->getDomains())));
+ }
+
+ return $this->domains;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMessages($domain)
+ {
+ if (!in_array($domain, $this->getDomains())) {
+ throw new \InvalidArgumentException(sprintf('Invalid domain: %s.', $domain));
+ }
+
+ if (!isset($this->messages[$domain]['all'])) {
+ $this->processDomain($domain);
+ }
+
+ return $this->messages[$domain]['all'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getNewMessages($domain)
+ {
+ if (!in_array($domain, $this->getDomains())) {
+ throw new \InvalidArgumentException(sprintf('Invalid domain: %s.', $domain));
+ }
+
+ if (!isset($this->messages[$domain]['new'])) {
+ $this->processDomain($domain);
+ }
+
+ return $this->messages[$domain]['new'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getObsoleteMessages($domain)
+ {
+ if (!in_array($domain, $this->getDomains())) {
+ throw new \InvalidArgumentException(sprintf('Invalid domain: %s.', $domain));
+ }
+
+ if (!isset($this->messages[$domain]['obsolete'])) {
+ $this->processDomain($domain);
+ }
+
+ return $this->messages[$domain]['obsolete'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getResult()
+ {
+ foreach ($this->getDomains() as $domain) {
+ if (!isset($this->messages[$domain])) {
+ $this->processDomain($domain);
+ }
+ }
+
+ return $this->result;
+ }
+
+ /**
+ * @param string $domain
+ */
+ abstract protected function processDomain($domain);
+}
diff --git a/vendor/symfony/translation/Catalogue/DiffOperation.php b/vendor/symfony/translation/Catalogue/DiffOperation.php
new file mode 100755
index 0000000..2d1994e
--- /dev/null
+++ b/vendor/symfony/translation/Catalogue/DiffOperation.php
@@ -0,0 +1,55 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Catalogue;
+
+/**
+ * Diff operation between two catalogues.
+ *
+ * @author Jean-François Simon
+ */
+class DiffOperation extends AbstractOperation
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function processDomain($domain)
+ {
+ $this->messages[$domain] = array(
+ 'all' => array(),
+ 'new' => array(),
+ 'obsolete' => array(),
+ );
+
+ foreach ($this->source->all($domain) as $id => $message) {
+ if ($this->target->has($id, $domain)) {
+ $this->messages[$domain]['all'][$id] = $message;
+ $this->result->add(array($id => $message), $domain);
+ if (null !== $keyMetadata = $this->source->getMetadata($id, $domain)) {
+ $this->result->setMetadata($id, $keyMetadata, $domain);
+ }
+ } else {
+ $this->messages[$domain]['obsolete'][$id] = $message;
+ }
+ }
+
+ foreach ($this->target->all($domain) as $id => $message) {
+ if (!$this->source->has($id, $domain)) {
+ $this->messages[$domain]['all'][$id] = $message;
+ $this->messages[$domain]['new'][$id] = $message;
+ $this->result->add(array($id => $message), $domain);
+ if (null !== $keyMetadata = $this->target->getMetadata($id, $domain)) {
+ $this->result->setMetadata($id, $keyMetadata, $domain);
+ }
+ }
+ }
+ }
+}
diff --git a/vendor/symfony/translation/Catalogue/MergeOperation.php b/vendor/symfony/translation/Catalogue/MergeOperation.php
new file mode 100755
index 0000000..562ca0e
--- /dev/null
+++ b/vendor/symfony/translation/Catalogue/MergeOperation.php
@@ -0,0 +1,51 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Catalogue;
+
+/**
+ * Merge operation between two catalogues.
+ *
+ * @author Jean-François Simon
+ */
+class MergeOperation extends AbstractOperation
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function processDomain($domain)
+ {
+ $this->messages[$domain] = array(
+ 'all' => array(),
+ 'new' => array(),
+ 'obsolete' => array(),
+ );
+
+ foreach ($this->source->all($domain) as $id => $message) {
+ $this->messages[$domain]['all'][$id] = $message;
+ $this->result->add(array($id => $message), $domain);
+ if (null !== $keyMetadata = $this->source->getMetadata($id, $domain)) {
+ $this->result->setMetadata($id, $keyMetadata, $domain);
+ }
+ }
+
+ foreach ($this->target->all($domain) as $id => $message) {
+ if (!$this->source->has($id, $domain)) {
+ $this->messages[$domain]['all'][$id] = $message;
+ $this->messages[$domain]['new'][$id] = $message;
+ $this->result->add(array($id => $message), $domain);
+ if (null !== $keyMetadata = $this->target->getMetadata($id, $domain)) {
+ $this->result->setMetadata($id, $keyMetadata, $domain);
+ }
+ }
+ }
+ }
+}
diff --git a/vendor/symfony/translation/Catalogue/OperationInterface.php b/vendor/symfony/translation/Catalogue/OperationInterface.php
new file mode 100755
index 0000000..d72378a
--- /dev/null
+++ b/vendor/symfony/translation/Catalogue/OperationInterface.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Catalogue;
+
+use Symfony\Component\Translation\MessageCatalogueInterface;
+
+/**
+ * Represents an operation on catalogue(s).
+ *
+ * @author Jean-François Simon
+ */
+interface OperationInterface
+{
+ /**
+ * Returns domains affected by operation.
+ *
+ * @return array
+ */
+ public function getDomains();
+
+ /**
+ * Returns all valid messages after operation.
+ *
+ * @param string $domain
+ *
+ * @return array
+ */
+ public function getMessages($domain);
+
+ /**
+ * Returns new messages after operation.
+ *
+ * @param string $domain
+ *
+ * @return array
+ */
+ public function getNewMessages($domain);
+
+ /**
+ * Returns obsolete messages after operation.
+ *
+ * @param string $domain
+ *
+ * @return array
+ */
+ public function getObsoleteMessages($domain);
+
+ /**
+ * Returns resulting catalogue.
+ *
+ * @return MessageCatalogueInterface
+ */
+ public function getResult();
+}
diff --git a/vendor/symfony/translation/DataCollector/TranslationDataCollector.php b/vendor/symfony/translation/DataCollector/TranslationDataCollector.php
new file mode 100755
index 0000000..c3c140f
--- /dev/null
+++ b/vendor/symfony/translation/DataCollector/TranslationDataCollector.php
@@ -0,0 +1,145 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\DataCollector;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\DataCollector\DataCollector;
+use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface;
+use Symfony\Component\Translation\DataCollectorTranslator;
+
+/**
+ * @author Abdellatif Ait boudad
+ */
+class TranslationDataCollector extends DataCollector implements LateDataCollectorInterface
+{
+ /**
+ * @var DataCollectorTranslator
+ */
+ private $translator;
+
+ /**
+ * @param DataCollectorTranslator $translator
+ */
+ public function __construct(DataCollectorTranslator $translator)
+ {
+ $this->translator = $translator;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function lateCollect()
+ {
+ $messages = $this->sanitizeCollectedMessages($this->translator->getCollectedMessages());
+
+ $this->data = $this->computeCount($messages);
+ $this->data['messages'] = $messages;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function collect(Request $request, Response $response, \Exception $exception = null)
+ {
+ }
+
+ /**
+ * @return array
+ */
+ public function getMessages()
+ {
+ return isset($this->data['messages']) ? $this->data['messages'] : array();
+ }
+
+ /**
+ * @return int
+ */
+ public function getCountMissings()
+ {
+ return isset($this->data[DataCollectorTranslator::MESSAGE_MISSING]) ? $this->data[DataCollectorTranslator::MESSAGE_MISSING] : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getCountFallbacks()
+ {
+ return isset($this->data[DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK]) ? $this->data[DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK] : 0;
+ }
+
+ /**
+ * @return int
+ */
+ public function getCountDefines()
+ {
+ return isset($this->data[DataCollectorTranslator::MESSAGE_DEFINED]) ? $this->data[DataCollectorTranslator::MESSAGE_DEFINED] : 0;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'translation';
+ }
+
+ private function sanitizeCollectedMessages($messages)
+ {
+ $result = array();
+ foreach ($messages as $key => $message) {
+ $messageId = $message['locale'].$message['domain'].$message['id'];
+
+ if (!isset($result[$messageId])) {
+ $message['count'] = 1;
+ $messages[$key]['translation'] = $this->sanitizeString($message['translation']);
+ $result[$messageId] = $message;
+ } else {
+ ++$result[$messageId]['count'];
+ }
+
+ unset($messages[$key]);
+ }
+
+ return $result;
+ }
+
+ private function computeCount($messages)
+ {
+ $count = array(
+ DataCollectorTranslator::MESSAGE_DEFINED => 0,
+ DataCollectorTranslator::MESSAGE_MISSING => 0,
+ DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK => 0,
+ );
+
+ foreach ($messages as $message) {
+ ++$count[$message['state']];
+ }
+
+ return $count;
+ }
+
+ private function sanitizeString($string, $length = 80)
+ {
+ $string = trim(preg_replace('/\s+/', ' ', $string));
+
+ if (function_exists('mb_strlen') && false !== $encoding = mb_detect_encoding($string)) {
+ if (mb_strlen($string, $encoding) > $length) {
+ return mb_substr($string, 0, $length - 3, $encoding).'...';
+ }
+ } elseif (strlen($string) > $length) {
+ return substr($string, 0, $length - 3).'...';
+ }
+
+ return $string;
+ }
+}
diff --git a/vendor/symfony/translation/DataCollectorTranslator.php b/vendor/symfony/translation/DataCollectorTranslator.php
new file mode 100755
index 0000000..813a857
--- /dev/null
+++ b/vendor/symfony/translation/DataCollectorTranslator.php
@@ -0,0 +1,152 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation;
+
+/**
+ * @author Abdellatif Ait boudad
+ */
+class DataCollectorTranslator implements TranslatorInterface, TranslatorBagInterface
+{
+ const MESSAGE_DEFINED = 0;
+ const MESSAGE_MISSING = 1;
+ const MESSAGE_EQUALS_FALLBACK = 2;
+
+ /**
+ * @var TranslatorInterface|TranslatorBagInterface
+ */
+ private $translator;
+
+ /**
+ * @var array
+ */
+ private $messages = array();
+
+ /**
+ * @param TranslatorInterface $translator The translator must implement TranslatorBagInterface
+ */
+ public function __construct(TranslatorInterface $translator)
+ {
+ if (!$translator instanceof TranslatorBagInterface) {
+ throw new \InvalidArgumentException(sprintf('The Translator "%s" must implement TranslatorInterface and TranslatorBagInterface.', get_class($translator)));
+ }
+
+ $this->translator = $translator;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function trans($id, array $parameters = array(), $domain = null, $locale = null)
+ {
+ $trans = $this->translator->trans($id, $parameters, $domain, $locale);
+ $this->collectMessage($locale, $domain, $id, $trans);
+
+ return $trans;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
+ {
+ $trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
+ $this->collectMessage($locale, $domain, $id, $trans);
+
+ return $trans;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @api
+ */
+ public function setLocale($locale)
+ {
+ $this->translator->setLocale($locale);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @api
+ */
+ public function getLocale()
+ {
+ return $this->translator->getLocale();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCatalogue($locale = null)
+ {
+ return $this->translator->getCatalogue($locale);
+ }
+
+ /**
+ * Passes through all unknown calls onto the translator object.
+ */
+ public function __call($method, $args)
+ {
+ return call_user_func_array(array($this->translator, $method), $args);
+ }
+
+ /**
+ * @return array
+ */
+ public function getCollectedMessages()
+ {
+ return $this->messages;
+ }
+
+ /**
+ * @param string|null $locale
+ * @param string|null $domain
+ * @param string $id
+ * @param string $trans
+ */
+ private function collectMessage($locale, $domain, $id, $translation)
+ {
+ if (null === $domain) {
+ $domain = 'messages';
+ }
+
+ $id = (string) $id;
+ $catalogue = $this->translator->getCatalogue($locale);
+ $locale = $catalogue->getLocale();
+ if ($catalogue->defines($id, $domain)) {
+ $state = self::MESSAGE_DEFINED;
+ } elseif ($catalogue->has($id, $domain)) {
+ $state = self::MESSAGE_EQUALS_FALLBACK;
+
+ $fallbackCatalogue = $catalogue->getFallBackCatalogue();
+ while ($fallbackCatalogue) {
+ if ($fallbackCatalogue->defines($id, $domain)) {
+ $locale = $fallbackCatalogue->getLocale();
+ break;
+ }
+
+ $fallbackCatalogue = $fallbackCatalogue->getFallBackCatalogue();
+ }
+ } else {
+ $state = self::MESSAGE_MISSING;
+ }
+
+ $this->messages[] = array(
+ 'locale' => $locale,
+ 'domain' => $domain,
+ 'id' => $id,
+ 'translation' => $translation,
+ 'state' => $state,
+ );
+ }
+}
diff --git a/vendor/symfony/translation/Dumper/CsvFileDumper.php b/vendor/symfony/translation/Dumper/CsvFileDumper.php
new file mode 100755
index 0000000..08005b0
--- /dev/null
+++ b/vendor/symfony/translation/Dumper/CsvFileDumper.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * CsvFileDumper generates a csv formatted string representation of a message catalogue.
+ *
+ * @author Stealth35
+ */
+class CsvFileDumper extends FileDumper
+{
+ private $delimiter = ';';
+ private $enclosure = '"';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(MessageCatalogue $messages, $domain = 'messages')
+ {
+ $handle = fopen('php://memory', 'rb+');
+
+ foreach ($messages->all($domain) as $source => $target) {
+ fputcsv($handle, array($source, $target), $this->delimiter, $this->enclosure);
+ }
+
+ rewind($handle);
+ $output = stream_get_contents($handle);
+ fclose($handle);
+
+ return $output;
+ }
+
+ /**
+ * Sets the delimiter and escape character for CSV.
+ *
+ * @param string $delimiter delimiter character
+ * @param string $enclosure enclosure character
+ */
+ public function setCsvControl($delimiter = ';', $enclosure = '"')
+ {
+ $this->delimiter = $delimiter;
+ $this->enclosure = $enclosure;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtension()
+ {
+ return 'csv';
+ }
+}
diff --git a/vendor/symfony/translation/Dumper/DumperInterface.php b/vendor/symfony/translation/Dumper/DumperInterface.php
new file mode 100755
index 0000000..cebc65e
--- /dev/null
+++ b/vendor/symfony/translation/Dumper/DumperInterface.php
@@ -0,0 +1,31 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * DumperInterface is the interface implemented by all translation dumpers.
+ * There is no common option.
+ *
+ * @author Michel Salib
+ */
+interface DumperInterface
+{
+ /**
+ * Dumps the message catalogue.
+ *
+ * @param MessageCatalogue $messages The message catalogue
+ * @param array $options Options that are used by the dumper
+ */
+ public function dump(MessageCatalogue $messages, $options = array());
+}
diff --git a/vendor/symfony/translation/Dumper/FileDumper.php b/vendor/symfony/translation/Dumper/FileDumper.php
new file mode 100755
index 0000000..f2f17d6
--- /dev/null
+++ b/vendor/symfony/translation/Dumper/FileDumper.php
@@ -0,0 +1,122 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * FileDumper is an implementation of DumperInterface that dump a message catalogue to file(s).
+ * Performs backup of already existing files.
+ *
+ * Options:
+ * - path (mandatory): the directory where the files should be saved
+ *
+ * @author Michel Salib
+ */
+abstract class FileDumper implements DumperInterface
+{
+ /**
+ * A template for the relative paths to files.
+ *
+ * @var string
+ */
+ protected $relativePathTemplate = '%domain%.%locale%.%extension%';
+
+ /**
+ * Make file backup before the dump.
+ *
+ * @var bool
+ */
+ private $backup = true;
+
+ /**
+ * Sets the template for the relative paths to files.
+ *
+ * @param string $relativePathTemplate A template for the relative paths to files
+ */
+ public function setRelativePathTemplate($relativePathTemplate)
+ {
+ $this->relativePathTemplate = $relativePathTemplate;
+ }
+
+ /**
+ * Sets backup flag.
+ *
+ * @param bool
+ */
+ public function setBackup($backup)
+ {
+ $this->backup = $backup;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dump(MessageCatalogue $messages, $options = array())
+ {
+ if (!array_key_exists('path', $options)) {
+ throw new \InvalidArgumentException('The file dumper needs a path option.');
+ }
+
+ // save a file for each domain
+ foreach ($messages->getDomains() as $domain) {
+ // backup
+ $fullpath = $options['path'].'/'.$this->getRelativePath($domain, $messages->getLocale());
+ if (file_exists($fullpath)) {
+ if ($this->backup) {
+ copy($fullpath, $fullpath.'~');
+ }
+ } else {
+ $directory = dirname($fullpath);
+ if (!file_exists($directory) && !@mkdir($directory, 0777, true)) {
+ throw new \RuntimeException(sprintf('Unable to create directory "%s".', $directory));
+ }
+ }
+ // save file
+ file_put_contents($fullpath, $this->format($messages, $domain));
+ }
+ }
+
+ /**
+ * Transforms a domain of a message catalogue to its string representation.
+ *
+ * @param MessageCatalogue $messages
+ * @param string $domain
+ *
+ * @return string representation
+ */
+ abstract protected function format(MessageCatalogue $messages, $domain);
+
+ /**
+ * Gets the file extension of the dumper.
+ *
+ * @return string file extension
+ */
+ abstract protected function getExtension();
+
+ /**
+ * Gets the relative file path using the template.
+ *
+ * @param string $domain The domain
+ * @param string $locale The locale
+ *
+ * @return string The relative file path
+ */
+ private function getRelativePath($domain, $locale)
+ {
+ return strtr($this->relativePathTemplate, array(
+ '%domain%' => $domain,
+ '%locale%' => $locale,
+ '%extension%' => $this->getExtension(),
+ ));
+ }
+}
diff --git a/vendor/symfony/translation/Dumper/IcuResFileDumper.php b/vendor/symfony/translation/Dumper/IcuResFileDumper.php
new file mode 100755
index 0000000..0a2ed9f
--- /dev/null
+++ b/vendor/symfony/translation/Dumper/IcuResFileDumper.php
@@ -0,0 +1,112 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * IcuResDumper generates an ICU ResourceBundle formatted string representation of a message catalogue.
+ *
+ * @author Stealth35
+ */
+class IcuResFileDumper extends FileDumper
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected $relativePathTemplate = '%domain%/%locale%.%extension%';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function format(MessageCatalogue $messages, $domain = 'messages')
+ {
+ $data = $indexes = $resources = '';
+
+ foreach ($messages->all($domain) as $source => $target) {
+ $indexes .= pack('v', strlen($data) + 28);
+ $data .= $source."\0";
+ }
+
+ $data .= $this->writePadding($data);
+
+ $keyTop = $this->getPosition($data);
+
+ foreach ($messages->all($domain) as $source => $target) {
+ $resources .= pack('V', $this->getPosition($data));
+
+ $data .= pack('V', strlen($target))
+ .mb_convert_encoding($target."\0", 'UTF-16LE', 'UTF-8')
+ .$this->writePadding($data)
+ ;
+ }
+
+ $resOffset = $this->getPosition($data);
+
+ $data .= pack('v', count($messages))
+ .$indexes
+ .$this->writePadding($data)
+ .$resources
+ ;
+
+ $bundleTop = $this->getPosition($data);
+
+ $root = pack('V7',
+ $resOffset + (2 << 28), // Resource Offset + Resource Type
+ 6, // Index length
+ $keyTop, // Index keys top
+ $bundleTop, // Index resources top
+ $bundleTop, // Index bundle top
+ count($messages), // Index max table length
+ 0 // Index attributes
+ );
+
+ $header = pack('vC2v4C12@32',
+ 32, // Header size
+ 0xDA, 0x27, // Magic number 1 and 2
+ 20, 0, 0, 2, // Rest of the header, ..., Size of a char
+ 0x52, 0x65, 0x73, 0x42, // Data format identifier
+ 1, 2, 0, 0, // Data version
+ 1, 4, 0, 0 // Unicode version
+ );
+
+ $output = $header
+ .$root
+ .$data;
+
+ return $output;
+ }
+
+ private function writePadding($data)
+ {
+ $padding = strlen($data) % 4;
+
+ if ($padding) {
+ return str_repeat("\xAA", 4 - $padding);
+ }
+ }
+
+ private function getPosition($data)
+ {
+ $position = (strlen($data) + 28) / 4;
+
+ return $position;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtension()
+ {
+ return 'res';
+ }
+}
diff --git a/vendor/symfony/translation/Dumper/IniFileDumper.php b/vendor/symfony/translation/Dumper/IniFileDumper.php
new file mode 100755
index 0000000..45df389
--- /dev/null
+++ b/vendor/symfony/translation/Dumper/IniFileDumper.php
@@ -0,0 +1,45 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * IniFileDumper generates an ini formatted string representation of a message catalogue.
+ *
+ * @author Stealth35
+ */
+class IniFileDumper extends FileDumper
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function format(MessageCatalogue $messages, $domain = 'messages')
+ {
+ $output = '';
+
+ foreach ($messages->all($domain) as $source => $target) {
+ $escapeTarget = str_replace('"', '\"', $target);
+ $output .= $source.'="'.$escapeTarget."\"\n";
+ }
+
+ return $output;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtension()
+ {
+ return 'ini';
+ }
+}
diff --git a/vendor/symfony/translation/Dumper/JsonFileDumper.php b/vendor/symfony/translation/Dumper/JsonFileDumper.php
new file mode 100755
index 0000000..7ad3518
--- /dev/null
+++ b/vendor/symfony/translation/Dumper/JsonFileDumper.php
@@ -0,0 +1,38 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * JsonFileDumper generates an json formatted string representation of a message catalogue.
+ *
+ * @author singles
+ */
+class JsonFileDumper extends FileDumper
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function format(MessageCatalogue $messages, $domain = 'messages')
+ {
+ return json_encode($messages->all($domain), defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtension()
+ {
+ return 'json';
+ }
+}
diff --git a/vendor/symfony/translation/Dumper/MoFileDumper.php b/vendor/symfony/translation/Dumper/MoFileDumper.php
new file mode 100755
index 0000000..f8dc6ac
--- /dev/null
+++ b/vendor/symfony/translation/Dumper/MoFileDumper.php
@@ -0,0 +1,82 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+use Symfony\Component\Translation\Loader\MoFileLoader;
+
+/**
+ * MoFileDumper generates a gettext formatted string representation of a message catalogue.
+ *
+ * @author Stealth35
+ */
+class MoFileDumper extends FileDumper
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function format(MessageCatalogue $messages, $domain = 'messages')
+ {
+ $output = $sources = $targets = $sourceOffsets = $targetOffsets = '';
+ $offsets = array();
+ $size = 0;
+
+ foreach ($messages->all($domain) as $source => $target) {
+ $offsets[] = array_map('strlen', array($sources, $source, $targets, $target));
+ $sources .= "\0".$source;
+ $targets .= "\0".$target;
+ ++$size;
+ }
+
+ $header = array(
+ 'magicNumber' => MoFileLoader::MO_LITTLE_ENDIAN_MAGIC,
+ 'formatRevision' => 0,
+ 'count' => $size,
+ 'offsetId' => MoFileLoader::MO_HEADER_SIZE,
+ 'offsetTranslated' => MoFileLoader::MO_HEADER_SIZE + (8 * $size),
+ 'sizeHashes' => 0,
+ 'offsetHashes' => MoFileLoader::MO_HEADER_SIZE + (16 * $size),
+ );
+
+ $sourcesSize = strlen($sources);
+ $sourcesStart = $header['offsetHashes'] + 1;
+
+ foreach ($offsets as $offset) {
+ $sourceOffsets .= $this->writeLong($offset[1])
+ .$this->writeLong($offset[0] + $sourcesStart);
+ $targetOffsets .= $this->writeLong($offset[3])
+ .$this->writeLong($offset[2] + $sourcesStart + $sourcesSize);
+ }
+
+ $output = implode(array_map(array($this, 'writeLong'), $header))
+ .$sourceOffsets
+ .$targetOffsets
+ .$sources
+ .$targets
+ ;
+
+ return $output;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtension()
+ {
+ return 'mo';
+ }
+
+ private function writeLong($str)
+ {
+ return pack('V*', $str);
+ }
+}
diff --git a/vendor/symfony/translation/Dumper/PhpFileDumper.php b/vendor/symfony/translation/Dumper/PhpFileDumper.php
new file mode 100755
index 0000000..b354c12
--- /dev/null
+++ b/vendor/symfony/translation/Dumper/PhpFileDumper.php
@@ -0,0 +1,40 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * PhpFileDumper generates PHP files from a message catalogue.
+ *
+ * @author Michel Salib
+ */
+class PhpFileDumper extends FileDumper
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function format(MessageCatalogue $messages, $domain)
+ {
+ $output = "all($domain), true).";\n";
+
+ return $output;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtension()
+ {
+ return 'php';
+ }
+}
diff --git a/vendor/symfony/translation/Dumper/PoFileDumper.php b/vendor/symfony/translation/Dumper/PoFileDumper.php
new file mode 100755
index 0000000..983064b
--- /dev/null
+++ b/vendor/symfony/translation/Dumper/PoFileDumper.php
@@ -0,0 +1,61 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * PoFileDumper generates a gettext formatted string representation of a message catalogue.
+ *
+ * @author Stealth35
+ */
+class PoFileDumper extends FileDumper
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function format(MessageCatalogue $messages, $domain = 'messages')
+ {
+ $output = 'msgid ""'."\n";
+ $output .= 'msgstr ""'."\n";
+ $output .= '"Content-Type: text/plain; charset=UTF-8\n"'."\n";
+ $output .= '"Content-Transfer-Encoding: 8bit\n"'."\n";
+ $output .= '"Language: '.$messages->getLocale().'\n"'."\n";
+ $output .= "\n";
+
+ $newLine = false;
+ foreach ($messages->all($domain) as $source => $target) {
+ if ($newLine) {
+ $output .= "\n";
+ } else {
+ $newLine = true;
+ }
+ $output .= sprintf('msgid "%s"'."\n", $this->escape($source));
+ $output .= sprintf('msgstr "%s"', $this->escape($target));
+ }
+
+ return $output;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtension()
+ {
+ return 'po';
+ }
+
+ private function escape($str)
+ {
+ return addcslashes($str, "\0..\37\42\134");
+ }
+}
diff --git a/vendor/symfony/translation/Dumper/QtFileDumper.php b/vendor/symfony/translation/Dumper/QtFileDumper.php
new file mode 100755
index 0000000..42aa093
--- /dev/null
+++ b/vendor/symfony/translation/Dumper/QtFileDumper.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * QtFileDumper generates ts files from a message catalogue.
+ *
+ * @author Benjamin Eberlei
+ */
+class QtFileDumper extends FileDumper
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function format(MessageCatalogue $messages, $domain)
+ {
+ $dom = new \DOMDocument('1.0', 'utf-8');
+ $dom->formatOutput = true;
+ $ts = $dom->appendChild($dom->createElement('TS'));
+ $context = $ts->appendChild($dom->createElement('context'));
+ $context->appendChild($dom->createElement('name', $domain));
+
+ foreach ($messages->all($domain) as $source => $target) {
+ $message = $context->appendChild($dom->createElement('message'));
+ $message->appendChild($dom->createElement('source', $source));
+ $message->appendChild($dom->createElement('translation', $target));
+ }
+
+ return $dom->saveXML();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtension()
+ {
+ return 'ts';
+ }
+}
diff --git a/vendor/symfony/translation/Dumper/XliffFileDumper.php b/vendor/symfony/translation/Dumper/XliffFileDumper.php
new file mode 100755
index 0000000..58d1973
--- /dev/null
+++ b/vendor/symfony/translation/Dumper/XliffFileDumper.php
@@ -0,0 +1,109 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * XliffFileDumper generates xliff files from a message catalogue.
+ *
+ * @author Michel Salib
+ */
+class XliffFileDumper extends FileDumper
+{
+ /**
+ * @var string
+ */
+ private $defaultLocale;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dump(MessageCatalogue $messages, $options = array())
+ {
+ if (array_key_exists('default_locale', $options)) {
+ $this->defaultLocale = $options['default_locale'];
+ } else {
+ $this->defaultLocale = \Locale::getDefault();
+ }
+
+ parent::dump($messages, $options);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function format(MessageCatalogue $messages, $domain)
+ {
+ $dom = new \DOMDocument('1.0', 'utf-8');
+ $dom->formatOutput = true;
+
+ $xliff = $dom->appendChild($dom->createElement('xliff'));
+ $xliff->setAttribute('version', '1.2');
+ $xliff->setAttribute('xmlns', 'urn:oasis:names:tc:xliff:document:1.2');
+
+ $xliffFile = $xliff->appendChild($dom->createElement('file'));
+ $xliffFile->setAttribute('source-language', str_replace('_', '-', $this->defaultLocale));
+ $xliffFile->setAttribute('target-language', str_replace('_', '-', $messages->getLocale()));
+ $xliffFile->setAttribute('datatype', 'plaintext');
+ $xliffFile->setAttribute('original', 'file.ext');
+
+ $xliffBody = $xliffFile->appendChild($dom->createElement('body'));
+ foreach ($messages->all($domain) as $source => $target) {
+ $translation = $dom->createElement('trans-unit');
+
+ $translation->setAttribute('id', md5($source));
+ $translation->setAttribute('resname', $source);
+
+ $s = $translation->appendChild($dom->createElement('source'));
+ $s->appendChild($dom->createTextNode($source));
+
+ // Does the target contain characters requiring a CDATA section?
+ $text = 1 === preg_match('/[&<>]/', $target) ? $dom->createCDATASection($target) : $dom->createTextNode($target);
+
+ $t = $translation->appendChild($dom->createElement('target'));
+ $t->appendChild($text);
+
+ $metadata = $messages->getMetadata($source, $domain);
+ if (null !== $metadata && array_key_exists('notes', $metadata) && is_array($metadata['notes'])) {
+ foreach ($metadata['notes'] as $note) {
+ if (!isset($note['content'])) {
+ continue;
+ }
+
+ $n = $translation->appendChild($dom->createElement('note'));
+ $n->appendChild($dom->createTextNode($note['content']));
+
+ if (isset($note['priority'])) {
+ $n->setAttribute('priority', $note['priority']);
+ }
+
+ if (isset($note['from'])) {
+ $n->setAttribute('from', $note['from']);
+ }
+ }
+ }
+
+ $xliffBody->appendChild($translation);
+ }
+
+ return $dom->saveXML();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtension()
+ {
+ return 'xlf';
+ }
+}
diff --git a/vendor/symfony/translation/Dumper/YamlFileDumper.php b/vendor/symfony/translation/Dumper/YamlFileDumper.php
new file mode 100755
index 0000000..870fb98
--- /dev/null
+++ b/vendor/symfony/translation/Dumper/YamlFileDumper.php
@@ -0,0 +1,43 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Dumper;
+
+use Symfony\Component\Translation\MessageCatalogue;
+use Symfony\Component\Yaml\Yaml;
+
+/**
+ * YamlFileDumper generates yaml files from a message catalogue.
+ *
+ * @author Michel Salib
+ */
+class YamlFileDumper extends FileDumper
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function format(MessageCatalogue $messages, $domain)
+ {
+ if (!class_exists('Symfony\Component\Yaml\Yaml')) {
+ throw new \LogicException('Dumping translations in the YAML format requires the Symfony Yaml component.');
+ }
+
+ return Yaml::dump($messages->all($domain));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getExtension()
+ {
+ return 'yml';
+ }
+}
diff --git a/vendor/symfony/translation/Exception/ExceptionInterface.php b/vendor/symfony/translation/Exception/ExceptionInterface.php
new file mode 100755
index 0000000..7757e66
--- /dev/null
+++ b/vendor/symfony/translation/Exception/ExceptionInterface.php
@@ -0,0 +1,23 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Exception;
+
+/**
+ * Exception interface for all exceptions thrown by the component.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+interface ExceptionInterface
+{
+}
diff --git a/vendor/symfony/translation/Exception/InvalidResourceException.php b/vendor/symfony/translation/Exception/InvalidResourceException.php
new file mode 100755
index 0000000..6413f1a
--- /dev/null
+++ b/vendor/symfony/translation/Exception/InvalidResourceException.php
@@ -0,0 +1,23 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Exception;
+
+/**
+ * Thrown when a resource cannot be loaded.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+class InvalidResourceException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/translation/Exception/NotFoundResourceException.php b/vendor/symfony/translation/Exception/NotFoundResourceException.php
new file mode 100755
index 0000000..7826e5c
--- /dev/null
+++ b/vendor/symfony/translation/Exception/NotFoundResourceException.php
@@ -0,0 +1,23 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Exception;
+
+/**
+ * Thrown when a resource does not exist.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+class NotFoundResourceException extends \InvalidArgumentException implements ExceptionInterface
+{
+}
diff --git a/vendor/symfony/translation/Extractor/AbstractFileExtractor.php b/vendor/symfony/translation/Extractor/AbstractFileExtractor.php
new file mode 100755
index 0000000..196bc33
--- /dev/null
+++ b/vendor/symfony/translation/Extractor/AbstractFileExtractor.php
@@ -0,0 +1,83 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Extractor;
+
+/**
+ * Base class used by classes that extract translation messages from files.
+ *
+ * @author Marcos D. Sánchez
+ */
+abstract class AbstractFileExtractor
+{
+ /**
+ * @param string|array $resource files, a file or a directory
+ *
+ * @return array
+ */
+ protected function extractFiles($resource)
+ {
+ if (is_array($resource) || $resource instanceof \Traversable) {
+ $files = array();
+ foreach ($resource as $file) {
+ if ($this->canBeExtracted($file)) {
+ $files[] = $this->toSplFileInfo($file);
+ }
+ }
+ } elseif (is_file($resource)) {
+ $files = $this->canBeExtracted($resource) ? array($this->toSplFileInfo($resource)) : array();
+ } else {
+ $files = $this->extractFromDirectory($resource);
+ }
+
+ return $files;
+ }
+
+ /**
+ * @param string $file
+ *
+ * @return \SplFileInfo
+ */
+ private function toSplFileInfo($file)
+ {
+ return ($file instanceof \SplFileInfo) ? $file : new \SplFileInfo($file);
+ }
+
+ /**
+ * @param string $file
+ *
+ * @throws \InvalidArgumentException
+ *
+ * @return bool
+ */
+ protected function isFile($file)
+ {
+ if (!is_file($file)) {
+ throw new \InvalidArgumentException(sprintf('The "%s" file does not exist.', $file));
+ }
+
+ return true;
+ }
+
+ /**
+ * @param string $file
+ *
+ * @return bool
+ */
+ abstract protected function canBeExtracted($file);
+
+ /**
+ * @param string|array $resource files, a file or a directory
+ *
+ * @return array files to be extracted
+ */
+ abstract protected function extractFromDirectory($resource);
+}
diff --git a/vendor/symfony/translation/Extractor/ChainExtractor.php b/vendor/symfony/translation/Extractor/ChainExtractor.php
new file mode 100755
index 0000000..50e3c84
--- /dev/null
+++ b/vendor/symfony/translation/Extractor/ChainExtractor.php
@@ -0,0 +1,60 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Extractor;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * ChainExtractor extracts translation messages from template files.
+ *
+ * @author Michel Salib
+ */
+class ChainExtractor implements ExtractorInterface
+{
+ /**
+ * The extractors.
+ *
+ * @var ExtractorInterface[]
+ */
+ private $extractors = array();
+
+ /**
+ * Adds a loader to the translation extractor.
+ *
+ * @param string $format The format of the loader
+ * @param ExtractorInterface $extractor The loader
+ */
+ public function addExtractor($format, ExtractorInterface $extractor)
+ {
+ $this->extractors[$format] = $extractor;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPrefix($prefix)
+ {
+ foreach ($this->extractors as $extractor) {
+ $extractor->setPrefix($prefix);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function extract($directory, MessageCatalogue $catalogue)
+ {
+ foreach ($this->extractors as $extractor) {
+ $extractor->extract($directory, $catalogue);
+ }
+ }
+}
diff --git a/vendor/symfony/translation/Extractor/ExtractorInterface.php b/vendor/symfony/translation/Extractor/ExtractorInterface.php
new file mode 100755
index 0000000..438f80b
--- /dev/null
+++ b/vendor/symfony/translation/Extractor/ExtractorInterface.php
@@ -0,0 +1,38 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Extractor;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * Extracts translation messages from a directory or files to the catalogue.
+ * New found messages are injected to the catalogue using the prefix.
+ *
+ * @author Michel Salib
+ */
+interface ExtractorInterface
+{
+ /**
+ * Extracts translation messages from files, a file or a directory to the catalogue.
+ *
+ * @param string|array $resource files, a file or a directory
+ * @param MessageCatalogue $catalogue The catalogue
+ */
+ public function extract($resource, MessageCatalogue $catalogue);
+
+ /**
+ * Sets the prefix that should be used for new found messages.
+ *
+ * @param string $prefix The prefix
+ */
+ public function setPrefix($prefix);
+}
diff --git a/vendor/symfony/translation/IdentityTranslator.php b/vendor/symfony/translation/IdentityTranslator.php
new file mode 100755
index 0000000..9c9212e
--- /dev/null
+++ b/vendor/symfony/translation/IdentityTranslator.php
@@ -0,0 +1,77 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation;
+
+/**
+ * IdentityTranslator does not translate anything.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+class IdentityTranslator implements TranslatorInterface
+{
+ private $selector;
+ private $locale;
+
+ /**
+ * Constructor.
+ *
+ * @param MessageSelector|null $selector The message selector for pluralization
+ *
+ * @api
+ */
+ public function __construct(MessageSelector $selector = null)
+ {
+ $this->selector = $selector ?: new MessageSelector();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @api
+ */
+ public function setLocale($locale)
+ {
+ $this->locale = $locale;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @api
+ */
+ public function getLocale()
+ {
+ return $this->locale ?: \Locale::getDefault();
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @api
+ */
+ public function trans($id, array $parameters = array(), $domain = null, $locale = null)
+ {
+ return strtr((string) $id, $parameters);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @api
+ */
+ public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null)
+ {
+ return strtr($this->selector->choose((string) $id, (int) $number, $locale ?: $this->getLocale()), $parameters);
+ }
+}
diff --git a/vendor/symfony/translation/Interval.php b/vendor/symfony/translation/Interval.php
new file mode 100755
index 0000000..2a51156
--- /dev/null
+++ b/vendor/symfony/translation/Interval.php
@@ -0,0 +1,107 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation;
+
+/**
+ * Tests if a given number belongs to a given math interval.
+ *
+ * An interval can represent a finite set of numbers:
+ *
+ * {1,2,3,4}
+ *
+ * An interval can represent numbers between two numbers:
+ *
+ * [1, +Inf]
+ * ]-1,2[
+ *
+ * The left delimiter can be [ (inclusive) or ] (exclusive).
+ * The right delimiter can be [ (exclusive) or ] (inclusive).
+ * Beside numbers, you can use -Inf and +Inf for the infinite.
+ *
+ * @author Fabien Potencier
+ *
+ * @see http://en.wikipedia.org/wiki/Interval_%28mathematics%29#The_ISO_notation
+ */
+class Interval
+{
+ /**
+ * Tests if the given number is in the math interval.
+ *
+ * @param int $number A number
+ * @param string $interval An interval
+ *
+ * @return bool
+ *
+ * @throws \InvalidArgumentException
+ */
+ public static function test($number, $interval)
+ {
+ $interval = trim($interval);
+
+ if (!preg_match('/^'.self::getIntervalRegexp().'$/x', $interval, $matches)) {
+ throw new \InvalidArgumentException(sprintf('"%s" is not a valid interval.', $interval));
+ }
+
+ if ($matches[1]) {
+ foreach (explode(',', $matches[2]) as $n) {
+ if ($number == $n) {
+ return true;
+ }
+ }
+ } else {
+ $leftNumber = self::convertNumber($matches['left']);
+ $rightNumber = self::convertNumber($matches['right']);
+
+ return
+ ('[' === $matches['left_delimiter'] ? $number >= $leftNumber : $number > $leftNumber)
+ && (']' === $matches['right_delimiter'] ? $number <= $rightNumber : $number < $rightNumber)
+ ;
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns a Regexp that matches valid intervals.
+ *
+ * @return string A Regexp (without the delimiters)
+ */
+ public static function getIntervalRegexp()
+ {
+ return <<[\[\]])
+ \s*
+ (?P-Inf|\-?\d+(\.\d+)?)
+ \s*,\s*
+ (?P\+?Inf|\-?\d+(\.\d+)?)
+ \s*
+ (?P[\[\]])
+EOF;
+ }
+
+ private static function convertNumber($number)
+ {
+ if ('-Inf' === $number) {
+ return log(0);
+ } elseif ('+Inf' === $number || 'Inf' === $number) {
+ return -log(0);
+ }
+
+ return (float) $number;
+ }
+}
diff --git a/vendor/symfony/translation/LICENSE b/vendor/symfony/translation/LICENSE
new file mode 100755
index 0000000..43028bc
--- /dev/null
+++ b/vendor/symfony/translation/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2004-2015 Fabien Potencier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/symfony/translation/Loader/ArrayLoader.php b/vendor/symfony/translation/Loader/ArrayLoader.php
new file mode 100755
index 0000000..68ba81d
--- /dev/null
+++ b/vendor/symfony/translation/Loader/ArrayLoader.php
@@ -0,0 +1,70 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\MessageCatalogue;
+
+/**
+ * ArrayLoader loads translations from a PHP array.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+class ArrayLoader implements LoaderInterface
+{
+ /**
+ * {@inheritdoc}
+ *
+ * @api
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ $this->flatten($resource);
+ $catalogue = new MessageCatalogue($locale);
+ $catalogue->add($resource, $domain);
+
+ return $catalogue;
+ }
+
+ /**
+ * Flattens an nested array of translations.
+ *
+ * The scheme used is:
+ * 'key' => array('key2' => array('key3' => 'value'))
+ * Becomes:
+ * 'key.key2.key3' => 'value'
+ *
+ * This function takes an array by reference and will modify it
+ *
+ * @param array &$messages The array that will be flattened
+ * @param array $subnode Current subnode being parsed, used internally for recursive calls
+ * @param string $path Current path being parsed, used internally for recursive calls
+ */
+ private function flatten(array &$messages, array $subnode = null, $path = null)
+ {
+ if (null === $subnode) {
+ $subnode = &$messages;
+ }
+ foreach ($subnode as $key => $value) {
+ if (is_array($value)) {
+ $nodePath = $path ? $path.'.'.$key : $key;
+ $this->flatten($messages, $value, $nodePath);
+ if (null === $path) {
+ unset($messages[$key]);
+ }
+ } elseif (null !== $path) {
+ $messages[$path.'.'.$key] = $value;
+ }
+ }
+ }
+}
diff --git a/vendor/symfony/translation/Loader/CsvFileLoader.php b/vendor/symfony/translation/Loader/CsvFileLoader.php
new file mode 100755
index 0000000..fc92760
--- /dev/null
+++ b/vendor/symfony/translation/Loader/CsvFileLoader.php
@@ -0,0 +1,95 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Config\Resource\FileResource;
+
+/**
+ * CsvFileLoader loads translations from CSV files.
+ *
+ * @author Saša Stamenković
+ *
+ * @api
+ */
+class CsvFileLoader extends ArrayLoader
+{
+ private $delimiter = ';';
+ private $enclosure = '"';
+ private $escape = '\\';
+
+ /**
+ * {@inheritdoc}
+ *
+ * @api
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ $messages = array();
+
+ try {
+ $file = new \SplFileObject($resource, 'rb');
+ } catch (\RuntimeException $e) {
+ throw new NotFoundResourceException(sprintf('Error opening file "%s".', $resource), 0, $e);
+ }
+
+ $file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY);
+ $file->setCsvControl($this->delimiter, $this->enclosure, $this->escape);
+
+ foreach ($file as $data) {
+ if (substr($data[0], 0, 1) === '#') {
+ continue;
+ }
+
+ if (!isset($data[1])) {
+ continue;
+ }
+
+ if (count($data) == 2) {
+ $messages[$data[0]] = $data[1];
+ } else {
+ continue;
+ }
+ }
+
+ $catalogue = parent::load($messages, $locale, $domain);
+
+ if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
+ $catalogue->addResource(new FileResource($resource));
+ }
+
+ return $catalogue;
+ }
+
+ /**
+ * Sets the delimiter, enclosure, and escape character for CSV.
+ *
+ * @param string $delimiter delimiter character
+ * @param string $enclosure enclosure character
+ * @param string $escape escape character
+ */
+ public function setCsvControl($delimiter = ';', $enclosure = '"', $escape = '\\')
+ {
+ $this->delimiter = $delimiter;
+ $this->enclosure = $enclosure;
+ $this->escape = $escape;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/IcuDatFileLoader.php b/vendor/symfony/translation/Loader/IcuDatFileLoader.php
new file mode 100755
index 0000000..71ba90a
--- /dev/null
+++ b/vendor/symfony/translation/Loader/IcuDatFileLoader.php
@@ -0,0 +1,62 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\MessageCatalogue;
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Config\Resource\FileResource;
+
+/**
+ * IcuResFileLoader loads translations from a resource bundle.
+ *
+ * @author stealth35
+ */
+class IcuDatFileLoader extends IcuResFileLoader
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource.'.dat')) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource.'.dat')) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ try {
+ $rb = new \ResourceBundle($locale, $resource);
+ } catch (\Exception $e) {
+ // HHVM compatibility: constructor throws on invalid resource
+ $rb = null;
+ }
+
+ if (!$rb) {
+ throw new InvalidResourceException(sprintf('Cannot load resource "%s"', $resource));
+ } elseif (intl_is_failure($rb->getErrorCode())) {
+ throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());
+ }
+
+ $messages = $this->flatten($rb);
+ $catalogue = new MessageCatalogue($locale);
+ $catalogue->add($messages, $domain);
+
+ if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
+ $catalogue->addResource(new FileResource($resource.'.dat'));
+ }
+
+ return $catalogue;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/IcuResFileLoader.php b/vendor/symfony/translation/Loader/IcuResFileLoader.php
new file mode 100755
index 0000000..2f8037f
--- /dev/null
+++ b/vendor/symfony/translation/Loader/IcuResFileLoader.php
@@ -0,0 +1,92 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\MessageCatalogue;
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Config\Resource\DirectoryResource;
+
+/**
+ * IcuResFileLoader loads translations from a resource bundle.
+ *
+ * @author stealth35
+ */
+class IcuResFileLoader implements LoaderInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!is_dir($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ try {
+ $rb = new \ResourceBundle($locale, $resource);
+ } catch (\Exception $e) {
+ // HHVM compatibility: constructor throws on invalid resource
+ $rb = null;
+ }
+
+ if (!$rb) {
+ throw new InvalidResourceException(sprintf('Cannot load resource "%s"', $resource));
+ } elseif (intl_is_failure($rb->getErrorCode())) {
+ throw new InvalidResourceException($rb->getErrorMessage(), $rb->getErrorCode());
+ }
+
+ $messages = $this->flatten($rb);
+ $catalogue = new MessageCatalogue($locale);
+ $catalogue->add($messages, $domain);
+
+ if (class_exists('Symfony\Component\Config\Resource\DirectoryResource')) {
+ $catalogue->addResource(new DirectoryResource($resource));
+ }
+
+ return $catalogue;
+ }
+
+ /**
+ * Flattens an ResourceBundle.
+ *
+ * The scheme used is:
+ * key { key2 { key3 { "value" } } }
+ * Becomes:
+ * 'key.key2.key3' => 'value'
+ *
+ * This function takes an array by reference and will modify it
+ *
+ * @param \ResourceBundle $rb the ResourceBundle that will be flattened
+ * @param array $messages used internally for recursive calls
+ * @param string $path current path being parsed, used internally for recursive calls
+ *
+ * @return array the flattened ResourceBundle
+ */
+ protected function flatten(\ResourceBundle $rb, array &$messages = array(), $path = null)
+ {
+ foreach ($rb as $key => $value) {
+ $nodePath = $path ? $path.'.'.$key : $key;
+ if ($value instanceof \ResourceBundle) {
+ $this->flatten($value, $messages, $nodePath);
+ } else {
+ $messages[$nodePath] = $value;
+ }
+ }
+
+ return $messages;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/IniFileLoader.php b/vendor/symfony/translation/Loader/IniFileLoader.php
new file mode 100755
index 0000000..1b3a7b1
--- /dev/null
+++ b/vendor/symfony/translation/Loader/IniFileLoader.php
@@ -0,0 +1,48 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Config\Resource\FileResource;
+
+/**
+ * IniFileLoader loads translations from an ini file.
+ *
+ * @author stealth35
+ */
+class IniFileLoader extends ArrayLoader
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ $messages = parse_ini_file($resource, true);
+
+ $catalogue = parent::load($messages, $locale, $domain);
+
+ if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
+ $catalogue->addResource(new FileResource($resource));
+ }
+
+ return $catalogue;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/JsonFileLoader.php b/vendor/symfony/translation/Loader/JsonFileLoader.php
new file mode 100755
index 0000000..81717f3
--- /dev/null
+++ b/vendor/symfony/translation/Loader/JsonFileLoader.php
@@ -0,0 +1,81 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Config\Resource\FileResource;
+
+/**
+ * JsonFileLoader loads translations from an json file.
+ *
+ * @author singles
+ */
+class JsonFileLoader extends ArrayLoader
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ $messages = array();
+ if ($data = file_get_contents($resource)) {
+ $messages = json_decode($data, true);
+
+ if (0 < $errorCode = json_last_error()) {
+ throw new InvalidResourceException(sprintf('Error parsing JSON - %s', $this->getJSONErrorMessage($errorCode)));
+ }
+ }
+
+ if (null === $messages) {
+ $messages = array();
+ }
+
+ $catalogue = parent::load($messages, $locale, $domain);
+ $catalogue->addResource(new FileResource($resource));
+
+ return $catalogue;
+ }
+
+ /**
+ * Translates JSON_ERROR_* constant into meaningful message.
+ *
+ * @param int $errorCode Error code returned by json_last_error() call
+ *
+ * @return string Message string
+ */
+ private function getJSONErrorMessage($errorCode)
+ {
+ switch ($errorCode) {
+ case JSON_ERROR_DEPTH:
+ return 'Maximum stack depth exceeded';
+ case JSON_ERROR_STATE_MISMATCH:
+ return 'Underflow or the modes mismatch';
+ case JSON_ERROR_CTRL_CHAR:
+ return 'Unexpected control character found';
+ case JSON_ERROR_SYNTAX:
+ return 'Syntax error, malformed JSON';
+ case JSON_ERROR_UTF8:
+ return 'Malformed UTF-8 characters, possibly incorrectly encoded';
+ default:
+ return 'Unknown error';
+ }
+ }
+}
diff --git a/vendor/symfony/translation/Loader/LoaderInterface.php b/vendor/symfony/translation/Loader/LoaderInterface.php
new file mode 100755
index 0000000..0b28e14
--- /dev/null
+++ b/vendor/symfony/translation/Loader/LoaderInterface.php
@@ -0,0 +1,42 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\MessageCatalogue;
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+
+/**
+ * LoaderInterface is the interface implemented by all translation loaders.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+interface LoaderInterface
+{
+ /**
+ * Loads a locale.
+ *
+ * @param mixed $resource A resource
+ * @param string $locale A locale
+ * @param string $domain The domain
+ *
+ * @return MessageCatalogue A MessageCatalogue instance
+ *
+ * @api
+ *
+ * @throws NotFoundResourceException when the resource cannot be found
+ * @throws InvalidResourceException when the resource cannot be loaded
+ */
+ public function load($resource, $locale, $domain = 'messages');
+}
diff --git a/vendor/symfony/translation/Loader/MoFileLoader.php b/vendor/symfony/translation/Loader/MoFileLoader.php
new file mode 100755
index 0000000..746fd52
--- /dev/null
+++ b/vendor/symfony/translation/Loader/MoFileLoader.php
@@ -0,0 +1,191 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Config\Resource\FileResource;
+
+/**
+ * @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)
+ */
+class MoFileLoader extends ArrayLoader
+{
+ /**
+ * Magic used for validating the format of a MO file as well as
+ * detecting if the machine used to create that file was little endian.
+ *
+ * @var float
+ */
+ const MO_LITTLE_ENDIAN_MAGIC = 0x950412de;
+
+ /**
+ * Magic used for validating the format of a MO file as well as
+ * detecting if the machine used to create that file was big endian.
+ *
+ * @var float
+ */
+ const MO_BIG_ENDIAN_MAGIC = 0xde120495;
+
+ /**
+ * The size of the header of a MO file in bytes.
+ *
+ * @var int Number of bytes.
+ */
+ const MO_HEADER_SIZE = 28;
+
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ $messages = $this->parse($resource);
+
+ // empty file
+ if (null === $messages) {
+ $messages = array();
+ }
+
+ // not an array
+ if (!is_array($messages)) {
+ throw new InvalidResourceException(sprintf('The file "%s" must contain a valid mo file.', $resource));
+ }
+
+ $catalogue = parent::load($messages, $locale, $domain);
+
+ if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
+ $catalogue->addResource(new FileResource($resource));
+ }
+
+ return $catalogue;
+ }
+
+ /**
+ * Parses machine object (MO) format, independent of the machine's endian it
+ * was created on. Both 32bit and 64bit systems are supported.
+ *
+ * @param resource $resource
+ *
+ * @return array
+ *
+ * @throws InvalidResourceException If stream content has an invalid format.
+ */
+ private function parse($resource)
+ {
+ $stream = fopen($resource, 'r');
+
+ $stat = fstat($stream);
+
+ if ($stat['size'] < self::MO_HEADER_SIZE) {
+ throw new InvalidResourceException('MO stream content has an invalid format.');
+ }
+ $magic = unpack('V1', fread($stream, 4));
+ $magic = hexdec(substr(dechex(current($magic)), -8));
+
+ if ($magic == self::MO_LITTLE_ENDIAN_MAGIC) {
+ $isBigEndian = false;
+ } elseif ($magic == self::MO_BIG_ENDIAN_MAGIC) {
+ $isBigEndian = true;
+ } else {
+ throw new InvalidResourceException('MO stream content has an invalid format.');
+ }
+
+ // formatRevision
+ $this->readLong($stream, $isBigEndian);
+ $count = $this->readLong($stream, $isBigEndian);
+ $offsetId = $this->readLong($stream, $isBigEndian);
+ $offsetTranslated = $this->readLong($stream, $isBigEndian);
+ // sizeHashes
+ $this->readLong($stream, $isBigEndian);
+ // offsetHashes
+ $this->readLong($stream, $isBigEndian);
+
+ $messages = array();
+
+ for ($i = 0; $i < $count; ++$i) {
+ $singularId = $pluralId = null;
+ $translated = null;
+
+ fseek($stream, $offsetId + $i * 8);
+
+ $length = $this->readLong($stream, $isBigEndian);
+ $offset = $this->readLong($stream, $isBigEndian);
+
+ if ($length < 1) {
+ continue;
+ }
+
+ fseek($stream, $offset);
+ $singularId = fread($stream, $length);
+
+ if (strpos($singularId, "\000") !== false) {
+ list($singularId, $pluralId) = explode("\000", $singularId);
+ }
+
+ fseek($stream, $offsetTranslated + $i * 8);
+ $length = $this->readLong($stream, $isBigEndian);
+ $offset = $this->readLong($stream, $isBigEndian);
+
+ if ($length < 1) {
+ continue;
+ }
+
+ fseek($stream, $offset);
+ $translated = fread($stream, $length);
+
+ if (strpos($translated, "\000") !== false) {
+ $translated = explode("\000", $translated);
+ }
+
+ $ids = array('singular' => $singularId, 'plural' => $pluralId);
+ $item = compact('ids', 'translated');
+
+ if (is_array($item['translated'])) {
+ $messages[$item['ids']['singular']] = stripcslashes($item['translated'][0]);
+ if (isset($item['ids']['plural'])) {
+ $plurals = array();
+ foreach ($item['translated'] as $plural => $translated) {
+ $plurals[] = sprintf('{%d} %s', $plural, $translated);
+ }
+ $messages[$item['ids']['plural']] = stripcslashes(implode('|', $plurals));
+ }
+ } elseif (!empty($item['ids']['singular'])) {
+ $messages[$item['ids']['singular']] = stripcslashes($item['translated']);
+ }
+ }
+
+ fclose($stream);
+
+ return array_filter($messages);
+ }
+
+ /**
+ * Reads an unsigned long from stream respecting endianess.
+ *
+ * @param resource $stream
+ * @param bool $isBigEndian
+ *
+ * @return int
+ */
+ private function readLong($stream, $isBigEndian)
+ {
+ $result = unpack($isBigEndian ? 'N1' : 'V1', fread($stream, 4));
+ $result = current($result);
+
+ return (int) substr($result, -8);
+ }
+}
diff --git a/vendor/symfony/translation/Loader/PhpFileLoader.php b/vendor/symfony/translation/Loader/PhpFileLoader.php
new file mode 100755
index 0000000..9ce2e7d
--- /dev/null
+++ b/vendor/symfony/translation/Loader/PhpFileLoader.php
@@ -0,0 +1,52 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Config\Resource\FileResource;
+
+/**
+ * PhpFileLoader loads translations from PHP files returning an array of translations.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+class PhpFileLoader extends ArrayLoader
+{
+ /**
+ * {@inheritdoc}
+ *
+ * @api
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ $messages = require $resource;
+
+ $catalogue = parent::load($messages, $locale, $domain);
+
+ if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
+ $catalogue->addResource(new FileResource($resource));
+ }
+
+ return $catalogue;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/PoFileLoader.php b/vendor/symfony/translation/Loader/PoFileLoader.php
new file mode 100755
index 0000000..b5d12e9
--- /dev/null
+++ b/vendor/symfony/translation/Loader/PoFileLoader.php
@@ -0,0 +1,180 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Config\Resource\FileResource;
+
+/**
+ * @copyright Copyright (c) 2010, Union of RAD http://union-of-rad.org (http://lithify.me/)
+ * @copyright Copyright (c) 2012, Clemens Tolboom
+ */
+class PoFileLoader extends ArrayLoader
+{
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ $messages = $this->parse($resource);
+
+ // empty file
+ if (null === $messages) {
+ $messages = array();
+ }
+
+ // not an array
+ if (!is_array($messages)) {
+ throw new InvalidResourceException(sprintf('The file "%s" must contain a valid po file.', $resource));
+ }
+
+ $catalogue = parent::load($messages, $locale, $domain);
+
+ if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
+ $catalogue->addResource(new FileResource($resource));
+ }
+
+ return $catalogue;
+ }
+
+ /**
+ * Parses portable object (PO) format.
+ *
+ * From http://www.gnu.org/software/gettext/manual/gettext.html#PO-Files
+ * we should be able to parse files having:
+ *
+ * white-space
+ * # translator-comments
+ * #. extracted-comments
+ * #: reference...
+ * #, flag...
+ * #| msgid previous-untranslated-string
+ * msgid untranslated-string
+ * msgstr translated-string
+ *
+ * extra or different lines are:
+ *
+ * #| msgctxt previous-context
+ * #| msgid previous-untranslated-string
+ * msgctxt context
+ *
+ * #| msgid previous-untranslated-string-singular
+ * #| msgid_plural previous-untranslated-string-plural
+ * msgid untranslated-string-singular
+ * msgid_plural untranslated-string-plural
+ * msgstr[0] translated-string-case-0
+ * ...
+ * msgstr[N] translated-string-case-n
+ *
+ * The definition states:
+ * - white-space and comments are optional.
+ * - msgid "" that an empty singleline defines a header.
+ *
+ * This parser sacrifices some features of the reference implementation the
+ * differences to that implementation are as follows.
+ * - No support for comments spanning multiple lines.
+ * - Translator and extracted comments are treated as being the same type.
+ * - Message IDs are allowed to have other encodings as just US-ASCII.
+ *
+ * Items with an empty id are ignored.
+ *
+ * @param resource $resource
+ *
+ * @return array
+ */
+ private function parse($resource)
+ {
+ $stream = fopen($resource, 'r');
+
+ $defaults = array(
+ 'ids' => array(),
+ 'translated' => null,
+ );
+
+ $messages = array();
+ $item = $defaults;
+
+ while ($line = fgets($stream)) {
+ $line = trim($line);
+
+ if ($line === '') {
+ // Whitespace indicated current item is done
+ $this->addMessage($messages, $item);
+ $item = $defaults;
+ } elseif (substr($line, 0, 7) === 'msgid "') {
+ // We start a new msg so save previous
+ // TODO: this fails when comments or contexts are added
+ $this->addMessage($messages, $item);
+ $item = $defaults;
+ $item['ids']['singular'] = substr($line, 7, -1);
+ } elseif (substr($line, 0, 8) === 'msgstr "') {
+ $item['translated'] = substr($line, 8, -1);
+ } elseif ($line[0] === '"') {
+ $continues = isset($item['translated']) ? 'translated' : 'ids';
+
+ if (is_array($item[$continues])) {
+ end($item[$continues]);
+ $item[$continues][key($item[$continues])] .= substr($line, 1, -1);
+ } else {
+ $item[$continues] .= substr($line, 1, -1);
+ }
+ } elseif (substr($line, 0, 14) === 'msgid_plural "') {
+ $item['ids']['plural'] = substr($line, 14, -1);
+ } elseif (substr($line, 0, 7) === 'msgstr[') {
+ $size = strpos($line, ']');
+ $item['translated'][(int) substr($line, 7, 1)] = substr($line, $size + 3, -1);
+ }
+ }
+ // save last item
+ $this->addMessage($messages, $item);
+ fclose($stream);
+
+ return $messages;
+ }
+
+ /**
+ * Save a translation item to the messages.
+ *
+ * A .po file could contain by error missing plural indexes. We need to
+ * fix these before saving them.
+ *
+ * @param array $messages
+ * @param array $item
+ */
+ private function addMessage(array &$messages, array $item)
+ {
+ if (is_array($item['translated'])) {
+ $messages[stripcslashes($item['ids']['singular'])] = stripcslashes($item['translated'][0]);
+ if (isset($item['ids']['plural'])) {
+ $plurals = $item['translated'];
+ // PO are by definition indexed so sort by index.
+ ksort($plurals);
+ // Make sure every index is filled.
+ end($plurals);
+ $count = key($plurals);
+ // Fill missing spots with '-'.
+ $empties = array_fill(0, $count + 1, '-');
+ $plurals += $empties;
+ ksort($plurals);
+ $messages[stripcslashes($item['ids']['plural'])] = stripcslashes(implode('|', $plurals));
+ }
+ } elseif (!empty($item['ids']['singular'])) {
+ $messages[stripcslashes($item['ids']['singular'])] = stripcslashes($item['translated']);
+ }
+ }
+}
diff --git a/vendor/symfony/translation/Loader/QtFileLoader.php b/vendor/symfony/translation/Loader/QtFileLoader.php
new file mode 100755
index 0000000..6dd0696
--- /dev/null
+++ b/vendor/symfony/translation/Loader/QtFileLoader.php
@@ -0,0 +1,81 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Config\Util\XmlUtils;
+use Symfony\Component\Translation\MessageCatalogue;
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Config\Resource\FileResource;
+
+/**
+ * QtFileLoader loads translations from QT Translations XML files.
+ *
+ * @author Benjamin Eberlei
+ *
+ * @api
+ */
+class QtFileLoader implements LoaderInterface
+{
+ /**
+ * {@inheritdoc}
+ *
+ * @api
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ try {
+ $dom = XmlUtils::loadFile($resource);
+ } catch (\InvalidArgumentException $e) {
+ throw new InvalidResourceException(sprintf('Unable to load "%s".', $resource), $e->getCode(), $e);
+ }
+
+ $internalErrors = libxml_use_internal_errors(true);
+ libxml_clear_errors();
+
+ $xpath = new \DOMXPath($dom);
+ $nodes = $xpath->evaluate('//TS/context/name[text()="'.$domain.'"]');
+
+ $catalogue = new MessageCatalogue($locale);
+ if ($nodes->length == 1) {
+ $translations = $nodes->item(0)->nextSibling->parentNode->parentNode->getElementsByTagName('message');
+ foreach ($translations as $translation) {
+ $translationValue = (string) $translation->getElementsByTagName('translation')->item(0)->nodeValue;
+
+ if (!empty($translationValue)) {
+ $catalogue->set(
+ (string) $translation->getElementsByTagName('source')->item(0)->nodeValue,
+ $translationValue,
+ $domain
+ );
+ }
+ $translation = $translation->nextSibling;
+ }
+
+ if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
+ $catalogue->addResource(new FileResource($resource));
+ }
+ }
+
+ libxml_use_internal_errors($internalErrors);
+
+ return $catalogue;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/XliffFileLoader.php b/vendor/symfony/translation/Loader/XliffFileLoader.php
new file mode 100755
index 0000000..109f35b
--- /dev/null
+++ b/vendor/symfony/translation/Loader/XliffFileLoader.php
@@ -0,0 +1,188 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Config\Util\XmlUtils;
+use Symfony\Component\Translation\MessageCatalogue;
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Config\Resource\FileResource;
+
+/**
+ * XliffFileLoader loads translations from XLIFF files.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+class XliffFileLoader implements LoaderInterface
+{
+ /**
+ * {@inheritdoc}
+ *
+ * @api
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ list($xml, $encoding) = $this->parseFile($resource);
+ $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2');
+
+ $catalogue = new MessageCatalogue($locale);
+ foreach ($xml->xpath('//xliff:trans-unit') as $translation) {
+ $attributes = $translation->attributes();
+
+ if (!(isset($attributes['resname']) || isset($translation->source))) {
+ continue;
+ }
+
+ $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source;
+ // If the xlf file has another encoding specified, try to convert it because
+ // simple_xml will always return utf-8 encoded values
+ $target = $this->utf8ToCharset((string) (isset($translation->target) ? $translation->target : $source), $encoding);
+
+ $catalogue->set((string) $source, $target, $domain);
+
+ if (isset($translation->note)) {
+ $notes = array();
+ foreach ($translation->note as $xmlNote) {
+ $noteAttributes = $xmlNote->attributes();
+ $note = array('content' => $this->utf8ToCharset((string) $xmlNote, $encoding));
+ if (isset($noteAttributes['priority'])) {
+ $note['priority'] = (int) $noteAttributes['priority'];
+ }
+
+ if (isset($noteAttributes['from'])) {
+ $note['from'] = (string) $noteAttributes['from'];
+ }
+
+ $notes[] = $note;
+ }
+
+ $catalogue->setMetadata((string) $source, array('notes' => $notes), $domain);
+ }
+ }
+
+ if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
+ $catalogue->addResource(new FileResource($resource));
+ }
+
+ return $catalogue;
+ }
+
+ /**
+ * Convert a UTF8 string to the specified encoding.
+ *
+ * @param string $content String to decode
+ * @param string $encoding Target encoding
+ *
+ * @return string
+ */
+ private function utf8ToCharset($content, $encoding = null)
+ {
+ if ('UTF-8' !== $encoding && !empty($encoding)) {
+ if (function_exists('mb_convert_encoding')) {
+ return mb_convert_encoding($content, $encoding, 'UTF-8');
+ }
+
+ if (function_exists('iconv')) {
+ return iconv('UTF-8', $encoding, $content);
+ }
+
+ throw new \RuntimeException('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).');
+ }
+
+ return $content;
+ }
+
+ /**
+ * Validates and parses the given file into a SimpleXMLElement.
+ *
+ * @param string $file
+ *
+ * @throws \RuntimeException
+ *
+ * @return \SimpleXMLElement
+ *
+ * @throws InvalidResourceException
+ */
+ private function parseFile($file)
+ {
+ try {
+ $dom = XmlUtils::loadFile($file);
+ } catch (\InvalidArgumentException $e) {
+ throw new InvalidResourceException(sprintf('Unable to load "%s": %s', $file, $e->getMessage()), $e->getCode(), $e);
+ }
+
+ $internalErrors = libxml_use_internal_errors(true);
+
+ $location = str_replace('\\', '/', __DIR__).'/schema/dic/xliff-core/xml.xsd';
+ $parts = explode('/', $location);
+ if (0 === stripos($location, 'phar://')) {
+ $tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
+ if ($tmpfile) {
+ copy($location, $tmpfile);
+ $parts = explode('/', str_replace('\\', '/', $tmpfile));
+ }
+ }
+ $drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
+ $location = 'file:///'.$drive.implode('/', array_map('rawurlencode', $parts));
+
+ $source = file_get_contents(__DIR__.'/schema/dic/xliff-core/xliff-core-1.2-strict.xsd');
+ $source = str_replace('http://www.w3.org/2001/xml.xsd', $location, $source);
+
+ if (!@$dom->schemaValidateSource($source)) {
+ throw new InvalidResourceException(sprintf('Invalid resource provided: "%s"; Errors: %s', $file, implode("\n", $this->getXmlErrors($internalErrors))));
+ }
+
+ $dom->normalizeDocument();
+
+ libxml_clear_errors();
+ libxml_use_internal_errors($internalErrors);
+
+ return array(simplexml_import_dom($dom), strtoupper($dom->encoding));
+ }
+
+ /**
+ * Returns the XML errors of the internal XML parser.
+ *
+ * @param bool $internalErrors
+ *
+ * @return array An array of errors
+ */
+ private function getXmlErrors($internalErrors)
+ {
+ $errors = array();
+ foreach (libxml_get_errors() as $error) {
+ $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
+ LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
+ $error->code,
+ trim($error->message),
+ $error->file ?: 'n/a',
+ $error->line,
+ $error->column
+ );
+ }
+
+ libxml_clear_errors();
+ libxml_use_internal_errors($internalErrors);
+
+ return $errors;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/YamlFileLoader.php b/vendor/symfony/translation/Loader/YamlFileLoader.php
new file mode 100755
index 0000000..fb0946c
--- /dev/null
+++ b/vendor/symfony/translation/Loader/YamlFileLoader.php
@@ -0,0 +1,78 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Loader;
+
+use Symfony\Component\Translation\Exception\InvalidResourceException;
+use Symfony\Component\Translation\Exception\NotFoundResourceException;
+use Symfony\Component\Config\Resource\FileResource;
+use Symfony\Component\Yaml\Parser as YamlParser;
+use Symfony\Component\Yaml\Exception\ParseException;
+
+/**
+ * YamlFileLoader loads translations from Yaml files.
+ *
+ * @author Fabien Potencier
+ *
+ * @api
+ */
+class YamlFileLoader extends ArrayLoader
+{
+ private $yamlParser;
+
+ /**
+ * {@inheritdoc}
+ *
+ * @api
+ */
+ public function load($resource, $locale, $domain = 'messages')
+ {
+ if (!stream_is_local($resource)) {
+ throw new InvalidResourceException(sprintf('This is not a local file "%s".', $resource));
+ }
+
+ if (!file_exists($resource)) {
+ throw new NotFoundResourceException(sprintf('File "%s" not found.', $resource));
+ }
+
+ if (!class_exists('Symfony\Component\Yaml\Parser')) {
+ throw new \LogicException('Loading translations from the YAML format requires the Symfony Yaml component.');
+ }
+
+ if (null === $this->yamlParser) {
+ $this->yamlParser = new YamlParser();
+ }
+
+ try {
+ $messages = $this->yamlParser->parse(file_get_contents($resource));
+ } catch (ParseException $e) {
+ throw new InvalidResourceException(sprintf('Error parsing YAML, invalid file "%s"', $resource), 0, $e);
+ }
+
+ // empty file
+ if (null === $messages) {
+ $messages = array();
+ }
+
+ // not an array
+ if (!is_array($messages)) {
+ throw new InvalidResourceException(sprintf('The file "%s" must contain a YAML array.', $resource));
+ }
+
+ $catalogue = parent::load($messages, $locale, $domain);
+
+ if (class_exists('Symfony\Component\Config\Resource\FileResource')) {
+ $catalogue->addResource(new FileResource($resource));
+ }
+
+ return $catalogue;
+ }
+}
diff --git a/vendor/symfony/translation/Loader/schema/dic/xliff-core/xliff-core-1.2-strict.xsd b/vendor/symfony/translation/Loader/schema/dic/xliff-core/xliff-core-1.2-strict.xsd
new file mode 100755
index 0000000..3ce2a8e
--- /dev/null
+++ b/vendor/symfony/translation/Loader/schema/dic/xliff-core/xliff-core-1.2-strict.xsd
@@ -0,0 +1,2223 @@
+
+
+
+