From c97b1d6c03ef9898c857cac0d42a37cb8307742d Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 1 Apr 2017 01:24:10 +0200 Subject: [PATCH 01/16] Add executable composer.phar in util --- util/composer.phar | Bin 0 -> 1836198 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 util/composer.phar diff --git a/util/composer.phar b/util/composer.phar new file mode 100755 index 0000000000000000000000000000000000000000..357793176e3b45854af3c8e201bcd3e1b169bbef GIT binary patch literal 1836198 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�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

$mnv-0$YUbqgGDaOzTUDD38=z@cC%`18B+x@ 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

xt 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

?Cr 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%0Dv4v$_Ri3Ddr6(2h;L#Tr`H^?|FB%*es z57*fE@XPY~1~?nrL&{c6-R;c`5txS--y#DDJ)z=Py-ufxBjaz-WVgu&>W6DHGgZ85 zT=d?zxGyrW2<`x?Ol}?kMgo~dKxKV3yr!J9NVX;fL%VQk;1MJlb%%1CutO39-v;gb zy#dh|&*R-(MEl!C%$}|4@p`!!?Np+}@OT(96aHg=A8s@n&(YJ?JqA+DZ8 z2V2p4=_LAXr?fdA6<;2fi!2L1M~Ca>>P~@Xc63-PA0AYS zXnqr5OFN~lGFmC_7faPew2Eg@v5p^6WqW;ZkD8iUuL1iq;TIJS4o}KEFSe`E_Q4)P zrz_D$5tyxS>=mUcbgHnozOz3cZLaUHzaZ?&(E*^8XQ-H97aeaG=@GTJj{g^`J4mB~ zZWInE$huISM=#4&TlILSQk;+0%R3b!$X5Aae}0C@i5h?oAgEU=3KSwW6UdGTiV(qS z=(NEl+AOZ`0Tza*#9cIn7XvlHkIpwD0_W$OcM!|6G}4bfnH59Q4ZxW=B)zv&D3&V4 z%K6p~D1$X{h++#mdxnd4`IFMcmj$Hq0S$ukEhOvdGuOEqyejKIc1ytkmW4aU4U+$K@p^RA`9Vumk?e!CAG2oa<7ud1sdhg)xKWIC$uo5_D3MX| z`_aO7XbPgFaD`)rjgOQGB0o#VX^0tIIBc91I4af~93&hx<4V~k$g#*up$-Z?lb8l@ z2g7!Or5;le`QR!I8+GLSGn;kWP$7koX@A&W@59dt-|;w>F{~J;Rg76;Cn1tk)Tw+* zIWr@%CBW{7ydg7l9ZYYe2EvrnNIFx=sO0>X)Ny$)4h+PS<9xpbgbft{Ck3VZMz<85 zk1;bJUp}|aakyB>rK;QVTa*(o22m0Sg66YmnJyd6(+-J^e4yooJPZbPn&)#lWNxr$ zk0EvGmMBwz=a>p9dxF}$B*vQtdl%WN-55j_rhwhJoTn3`Z`$u$U5adl=%lMS92V(e zu4?q}i6|6^u8t8+%3opZ2HGfVjKFZSJ@C)KHQNK4HTm=N&7Jc3xdeuQE|7mrp4O&!0CrQ zFUC_owF_3NWp~1fhVRjhK!tD}am`Hb3N5_h!2`GQ4xIupab#Rk?wsb?>uTU8674{kNkuU2jN~{lTQ4z~4l7i$0GJWe<)5oy zCqN2)++e%%nG|y4;R-X2+zTKl)R=}!u9`yif z%~+ue={8>8=){lZ7Bl1e%8Z<^$hr6r^VZub%i!UVG&=QBx@Z+|*BjDO>9E(E)*Yzv z%P+rhiXkAHf1ckgZtawcb2AY>KSb@OtSf8L@{jpweeZC4J$f8%?!4Hk;_m|fTa2VE zg4j&qXRprsduRR9;==1cmgm3BVI!4+X|EUB&9!LMc!w0895&d2UCt!{LW{JU&u0HH zL`nj%BQymlTb5zkU&AC+9ByBWUTvxyqujb$K%Y&Y=GI>C$$ApL2v7%{0ADAkA59;I{8mW=(?+qXWX|m_|_?UGhpi9`lZETGIhL8r&~iE2T-c@zb8W zw$k20t4VpR4Iy4O%BQ`L<{VF(>U^5+8P_Cc2JsR^Mv8^#Z1@Q8*2tUnnYucsPYm^K zk16fTa|@0@evZzl{*MIPw(5qEApIDf$z-!rE~Q`$N&B9TlmS6xCsGvQ_4*9Q$>-kS z^Fi67Y0G;JE1s4k+~^thBI&T4Pho^K>RQ|tPQa#V7zlSJ2|kC@mOmh)Zj(G&axiUX z=J!0MBu16e!Fr`qgtrI|8K2#~29dID=F8m-i$4;H97+w5$jdqZpl}t4Nl!IKInsNV zM2q7>wCL%o>rM_*A@6XzE$Au6VX{=ZKY?WOmAz4lr~z&8@!%E;Fr+s0Ol`;F5tghz<;@bztRQVy1_X|NHyB4E$H6SS%sf^JFnhXlof|Dm2PlCW$2FPlVw*A zTG%EURFS#>dv4fcf~G)Mw&>RtGLTiY+0#$}PP=@zaPArTC~OU1DK~D`ggNh;Js1@K zecR|%dp<}9ZL0Qvy*C0Kc&opy)4zOmo8O_wzudpat#76BulH{g8)4r(xDUoOo5fzV zJ_k%XOBc!0Hn`8KU@o}dOcVn&3<|p~*at{goKgw%%-Hg-?!q(HBwE9K03sJ7+p_F? zhp{5*n?T`QN5gQ#y?N6bXv`yD#y}3k^K)#8RVwG_*h^h~rjIO3*kO~bSbPF3OsXhHUH|-xdm0PHanZAMGXcDe;x&{8k`7`s1S!zy zYJ=W;IOPY%0hWrzxj2$PE~lm&*SAJ4%9? z2x@RV1Zrxw2D_N0%T7i%w}~@{-i(ZK2hYCf;PAY71ezdmyM3@%#RHtUbPs5Ybj5q{ zf=aCV52(Zw?*WXJU!$j%)zrJB3)w6tSa*2P2S1_|`_l3=xnKEQy{war7LMCv`cv-k z_`_e~&-SV)2$3EuxL3r(XYpq*sNl1p;0r4FOHdNGzs%$yI%6Q|q0Ua{hYflJ3cDV8 zSQ8+YWi$36Q5g@h5PHu*HF^f2?H&@b@epc)_e=_+Gu}g@ISP`<7eqY)U_>#Ei1%0} zQSj7fZaaiQ5aM@~7V*jPm#pA(eP*jWDJy7s$kIoV1Q*%V;frrI4|MUB9S)_j=fxLB z^roU%;sl*Op{(@-2vQbyBOY~oKLPxets`Dx&tZ^tpNl>JHTQqlf>{A+PvLX z;~Q{$aCb_IRa16;#%@1gKN2xZtRoKrpGtbqStok?cC3P~7O? zW_=N=CdjH4#OQ!s(13z~huC4Hz@Y--rG@Xk&^vFf0>UKEx{)7ytV_Zr)mCY$p<2h%x+hg0}K$9-G)01Q{ z&|&>JzhhxDcjXvbQTk-7%9XwXoKXW8p7|hWaQ(W68qZeMQfM$_o|y{3pgk<%HYGC8 zq%Wodt%eyD4po^=sYS{V)k@;VO_`eGn@p<=omg(0jw4L$(jF$kdW`eHBM6v{ewy;y zff<4l6F^p;I8>C~z!tHR7;Lc-12Ln_XONDQov&LJ29cqm+2V1OPeIEWUYCrYSLSC7 zpZj1wnMIS6fP-7?SR}~f^NdoAb0;!anZ=SPgR5$okrJzTtYbT#0U%D&*K&oeC89^I zgygW~Q%T|qq%PcPmwiqq9UH@Z;y5-wBn!XVQfVVdo3HxJGD^}kkLff`(NjY)nXuy0 zi-k(ow;E!67n3KHCtG9SCX>?oyK3LcA(mrO807yQD>_YUO=JGttJfUf^woR}DvHIu zkDI*OUpvrjU-JndP9Zsl1-w_N^!B!kvjp$?qV$yU^fh(X_eq5`jseX)X+S{LBG&MH zC0NbkIAQidCQDXNo`;bz(pC$EM$t$?^jry{#)$EllX-q|2mRh?qZ(Bw>e4$Nssqb|FB zf|4GmFs;c$6iln{Sy&3HVC85&zBwXr7M|HWZMHw;((nfqkm8MNIv@ucwD2haDk~%T zkJF@&lbVwWj(B&IfmCU!i<4OicvUj5fV4QTOpLjCfir)+9wJ7|^;j~+``CK=v~bzl z+QgAZZ$LWJcWEAB^tT?bP^c@UoPKo8O0XCO$LdmS(5B8QQDxw7C4|^Gv>jZiuNKc2UOz{4B(wv{ar*h9 zHEMjm_*^c0Zgl$Bjn9qGNMUw){kh-y+@C|j&b3zvZhn5&d^Gptqq*mllAC_R6Fc{u za{+`c64-VJ$9&l-Et4ZBZIKVLT%docQToeG(igy^pg;4;5Se{iy(`)PuCmdo>Msf4 zJebOFoage79~K|YerZ!9_|H~BTQnO|T*?Ym-Nmf>ED(C^$1#3qTWH~luUvCKc#1F* zY!u{ke~_M~3weA%phJPeXOEE3{J9{BWp32Nd1*Q@Wx5Bn84?IYIGgNu{Or|gETG;Y zkSw_@CAr%?0OFYvFw3vGrx(&qO>T}Fn4d;nUIk zTLhGgn7+&@8Ej(ZjK?Zem)P+8HjKS3ruJ;?s$aQ6kHf&_&|o=E}njMmZNcSrkWrY(V)ec z@^@s^pFbPEe)I^J;ypqp)<=)rli4rcWU>6mttd9Y&T>h16VKOZ&jwQC`PvNTMNVTXm^`@B!{9wB6s6woI{01 zPrmRfw8qO2-9C<^Hb2FlEzhrh!P@jah!rdzXPYz;auk#$+|Fc#bg&&j1dL@KJ^93a zW8O;$VN{ozo-8I2(xK}nXrF+ku~*8;Uo)cAp7~CfA>^2=)qKZc1{`;&7@?$>jrs6W zI6(V?gz7wC9g#Y5Oeo#@Yof#gGWcQ`HAFwVgQx(`ib)JcmX=Z`nGvr#4?Qx*m;jf3 zJfAZ@-ME2F_jk5=MVvqD$4kYiV`eTfjfhr0>$?y5bUmLq)mfG7^m!S(3wCCdTn zgb0mTY!cfs%6ux)iEHwZh_LVkvrr@iPT_!($ki)K^^t~z!UU0T2m<=%7D+0Q`=rrD zcmo9^D(Q%x_RicG@qQnNn_$m^-fQ(+5R`=DnRp@)@`_?15h&S+E;w=_qGQI<$KGu; zL{c2wj|=p#+IJE$i4^iIw3#)$*pM2cCJ{CWJEKl^chQ{t%iE9;vqoWUr^GWtTJw;| zN_2@0F{X6FVz-Mo>zyU!{6W5+bsCC8#xg%EoiJu?ob>tUhrei(&+^cpADtod{g3oz zjoySeAIwkb;sBqwEf7|awgQ!!@-obOy&jLjqKUJZ0;+ljXaX&gc~h}2W=wHIvX-@ z-jSLKc18HFD?+M*=ipNw2$))QMu_Bp#nUR#A#OEsj7kg(kUL?NJP)?va~U1)1#r-u z<4km@ETnJbeq>$SJj!68Jkf^n``7D7&p+F5m}*4FIco^|y&Q*0T)&;|4IHh=PtTMY zB1irRCLWF~o_#+1{2YHtqRJBLb&TDuy}^q?@3x=ev z;pbPsKKmt_2jzaGM+yC$lCGQr40ifz@;FD(zHbo_>6qAC*rA^y14| z#SxzeD!WZG(jozbdc$?V0zUZ0;hGe|jj%*P z40=L(OOS4UOA?|usih6CCDe$uWXxa+8f2uPgwIEEXR8aEM6D-MU;~K_p3>Q3EC-Hh z&_EjV$yzrP9>$??b3YzaL9a9Dx%otSqKv^4m=K;DWGpbAD9^FB_m~o9+~7fPbcQXR z5Uw{1&oW|J3U<>Bb*#6?Rphy&+LZBfT5T#JC|tb^bx^%6-?nmQEms&aZ?&Qct3P4R z6OS4XERVEVpg$rHE2m_0wO82P4ox^sKVx+ax|pbCKdQdvb)2B9q9V*fyb}1y%>^h% z&#|6qtN)R5%nCDUewjbU8T(XA-8Jf^hM1E7CHwWCXV2LhP`yj=VbhJA#@@6rv{w%c zK{9;oXuxjc6}kckME}n-zV2ok(`6=CVEYHh`y%EoW85LJfC8HH<-`9xw88VZ&RO`Ky>eBASNZ!mJfPr; ziNQSxd&krX@kfuHeKCtYhq`q|t2T7g=(hW}xZSR$uPSU$Td$HxZytQ`J#{i{_@7Am zM4K5Klvo8cPF*~_wn-AxM4i1xrr$%yST~KkJe{GoBe?*D6u_z2*P!i#pC{cGQ%Q+2 zi?cG>2-E82x9Tk&x;}axrW=YaFg||8yq7JD&e&lS7mdIy4|RRKFcRl=ZYh|dx~miT z7L&7uW(Cg{;+_N)tRWNt6hKK%+^jiA6PkuKWDal6`9_~iIhy9d)9EIF$4zKJIobIj zk|H~WZHXm_y}q7zzlJFdbN??fB#nLC+MjYs7JUE?l)$D;Sup<(uL-Gqa}Nm^lObO# zmoiv@)v*|Yq+Tp7^8Z+Fk%UjEUInW<a1;&pS|w(XTLuG{0sj3^;bmwz^#dmxX@|nsKVnZ zTX1GFr!Bsgz+f3=G{ZDjJ2gfrGn?<0voqP-Vq-Ils$v6`SxO~|w=tRkY`B7T9ZDMj zS!xkejfuQG!E*vnRUY_j(o&zqGoAs(pMe$S8-4+#}8YDy(>wT#~fy+Kx=#+w#K^D8V=@hR(~-;zmh0FwE{ z)+=TNd-Qa(RU@INF`8!;7EN@s?InK`{+fF%S|>{fPMVJOhi%npHUHP1DGPPNfvqGHvNK$ zka&jRki@em63(fEl^CT&_=26h(}!&hk&=@3^_{grq`1T#Oo%tkt(op<>>;v~@S6+o zjRv~Oi#}fHw~kkagCt>b%PYi$IlvsarW>O6sl&!lwh-QD^OMa<_Sbzjf8A&E*L^mB z-DhLhG>T~$_8Yhx$p)ks8XIt_b?Ce&`Ew74gR{Nf8~P8)%z`NP%Ez0lUiTvs8|o#L zXNQB{B^LIx!|T3&rL_Pb%^9V@vDz6K4M~j4ncxp^9O8=Wf2KUAo6ZrC)5aZ7I5gqT zSA-CN?m-_HQVlzY6wj>v?%?S3ToGl*_S$b1wlzY9A5QR|82c#hTiD(1VOr$L> z)*7@R-D3YXzjfwxtbiyQh*%Y9dw+3W;=u6)IK!VrY_%;Q>xyjq4uLkj7;X zAq1SQejCEb~N_ib2Vb+B#B+I=_u^VPuCOZ4A&Vw0U?>b4rG$P z-n()1b;T4boy#;QT)4(e?lJEFe%yc8emv?7A76r%@o!_{f`!WB+A zD?vpmV;^<}hH2$2jDG7zVcZS}k2}4~M&~h-_YPVP)&Mhh0psk!p|Y{|5*YRRqd2tN z0no!g3u*W#+MZZia2$_=PnE^Aj!soTnVjiip^#zh!ecIDqsKu(`h<9Zq|3izlhBkO zD@#nFDcM{bBzA(CH7#yfDMT1U(tx*V3Byb^$jf{t+=cJWbDFzvI=u^5bTRk%N5mD5 zkthbJBA6j~j9`U$5xklOZIoAwxqpJ)ofVnA+N4&-LaEK_l{vtAaq%&(%)z9h8NeLE4wUCH7Jz%M67VTOwg)gR_j-@rWJ9_g%r#vtMWxJ zn8z>^l=yW%7BF!&?Ryc&J}^Upi>^FHpwhT%$({3DXjXdxhA_(=ctF1{JfpXW?e+4( zo%C*P7F9}jOTYxmwrCyPyt>5ZB2>Y zNF!OZb#eP9pW|zG!5)Qm9x#~lSSdTSIOW}NEs}3$5w46OGYJJ@G7UH%K)Wm7*?(mB z5GJt}dTPK;GZE651JjIngO5OwcTAfMG|Hr`2nulX1jrkw^PSD;8M2cu{j|isllUA6 z0H7-_cLliGaP~|H5uwFPPnK9CNo#9$ z*-X6Y^z(a1RFeB9n)w_7J;v>)2gen|-sc;&oxM$w&y&HrAa&?$oZt?*S1^}!xAahg z|6^Mj@U|j611lB&MZmvo6wwIVTYYkW{GMB6r>q{pkScSFx%{i8g`ZzPLI5&6HOx6& zjGb2Yx(km|XywLVY4UmGo|(f#jzb1_#E@VvQZ_LiV<|^8qjte7z@&PZpM+Ji=7|`z@;deY#q!i_1$3%ePRaMz^bUnCWM# zH*uc$jG&^M?L*uvf?*rN+?m3#Ok2B?)5#D}Rtb%e;1y$*Se82tsL)sDsOFV9lhHv*K1p)O6|H>t#5s5E|tp1wWHta zovm_tslHlySFhBIb=2K`UtTKS)ob<5qnFKE{l(JLR=vMdx%s(KU%6YZZk@inc(MPf zcC&n1U%eil-1N6Y#&v( z>g8Ig+g!S~3GY z=wH`Ay}K*il%5{FD>sgd*!`@X9$aj_`&2{S{kP>Om3n#O^qtnNEtkqmm$AAhtM8Uu zo&L+_<_2JOmXAAV`?&P9bUgg+xKrM`tSxVzE;To6t6ST(rA~W)sa!7C`Wv-Qr+xCN zRJqvdkILQp{zd)tr;|^+$E`ZPQ1tyXL0jplN*dsN%n_?rI;@4l|y__m7RA%$DN#)ZqZ57l~k zt5y5CSO(s$o6%1gllRS)=G*Ga>&@1?t>2Drng{iFyBo)#dt-U`MYX=W+FWXOk85D7 z`qpl_xO-6j&<7p+gOioz9@A&Le2j7b3FF?NajkdjrP{l#)$)txX?g3kTmx?&9hdi; zpUOu^tL0H^8}B=Ke{9~5ibpTYwSqT}H5tdB%EzarqqiG|$5uh(T7BvC(@DK~aQR~A zQ@z{YE!Un7Pgb6mPnT;S>o@&(<(0b?;@?Jb8P~F3{wDmng}R+~P~=eNqr&yC9Q^~%Z8(~a8ks8GJSUTVETJIkk|ch#+(-Piq*Izcfr%UyI`W)V(IgGj1DHPt7S1~`S z?B3Dw&$~zOFprCv18+;ci_PY5$JLFKlcm$!#>>uDrMpqBEtT&s-fkRT)^+W~zrRt~p)630`oWblKT>TYX#Ks}@I{ zlWuPnIDTk+I{B@(wA?AzuMaEB>r0Je$cC5KPixiYVQJ;G(5zjTPLIo%F^+o6{GSmq$<0 zhwbLO>)Od`=df9OGPvmUf%EQYfA#cb>&4ThR;{z!?3_ZjFBdQ`w;P?Ue`9=0N5>=P z@6%#^wN@*Y@NTv6u8s-UKdsdJyWqigX=|%nuI(0%>RXsg&CU^IGdPcA^SknP6Ecm~ zjnns#MKzhj*Hy^+B7X1TclQ!9v|Ky+?WnW$7SH~DRC`)DT^T`^j{41bs%EPz&*-TwC8(&$O;_~#zpeXQKn?;0!D zyVc{n;>8Nqmf}BF8!N?62bIy`N%gwF-#vYawd`r5Q+sk$@2}LCK&Nhf=cHQRf}D6- z{&e}<#n$D=qvNgaN$qs6{I2xzpkBT`-YVZ<-af&c-a6@?tX7s!%cUFi`^Dw*9jzdJbUzu$jxcMLiK=DUwr&-eFM?)vqW z&ZkOe_x;7n$zcDuRN4Pj-)z1(`T$u}I9c5&lsaXsrFW&1rJs*3HZNCB!CTFxe)qHn zc%7{-Wa6jOo8`CY*XDlZ=ez0(=2h+K-QK5-TC3Y1)ZaB%4vMs@mo`sVw(7qv*H2EX z<&*02=}Kdz^!D_4_qU6;yYEgvE&W_*lRmOE0v(Dw#nM)-Q{FAV>uerjO%PpW={M+| zv%||lyH6SnuAj^m530GDnbu&?<3ohVmP1A?PH3QDyL;6`u@nRE0(+D{Ju&y$=8(&r zOt1Hi!Flucrte!1P+ylo9~uV3X_H@IYNz1f5_Vwj^y7Ae3c+!msd&PVN= z*7=AdY-WI;k21o>79T$EU-!?t4;RfP#@Zu5BGrs6dyV`+s5$K_pbr#;;Pw`<7t1uD zPHGwC3Bze-TnoqB{h4R6NfDf6i8P{c+XkE`s!}!M}#Bca&?Zg|k(Q&DO)5 zUm4rb?;_rv1EmL=Iwsv ze{kmN7VgC1HRwV;?tyB2O6@JYhV+Dxzv^`mO-H?hqYj&#=+tm+W~NH{87^?C6ZeLD zhl)bP=3+m3oWeOaqrhnGOx)lpN0Nv@!AM`VML^?C2s8*e)U|=2rE1 zy9Qs4<>0odm$+uC zQi%@AGduf-dpkuu+bI?HYMVQy7tsdll@6-W-p>9GZla2+2N5->pmvI=w-xOd%Y|(~ zUfK&uH$afLTzuo939rmhX<7+-*SuFOLt0JWwcV<$7cT` zT18V4469N#s%)?C?NL)R>os6sCj6qp!Qn}H=f!q4+CJFZgo8EOC<3$fjlH5Yg-+qx zuATk)Xmfpk{RLrHjt&5&JVV6Fr$PkTDj)36&k#9L1JD5k^-4v7!nghsf$WH&2>r&5UKU`qSzO-(EV{-pHhhcb zwkNmYuN(X1Sdvf1C1A2U;9me1>=!`hnU4xb8!(JeH_W{5B~q$sM4in$$UbS@QDy}r z2V%*gZEQl*Ci`CNeXFy!hA}L^D3%H*ifI0kPa`R!gMM8c{zaf-%3YeD;`z&S)+a~?@TUv(DI+)yU*sAQlIBf4t>&@au zEt}FdA7+~9kf@%lJC%@42)jqkVRV*N06%VjhUbJB{MvOBYoUHR#v1J%GmamunN5qwzDs2B2xn^XAHya=pL>XM4^W8A^g`JKl3Z7&m9HL<5R<8er3WKH6fkOjwnN&9 zFRe4>?&OKi4CT+b*kr@oup9Sc+t>{IOR-|5(kul20A?)n3EI=@FwOMLr2Air)dVd* zB>A)xKa1l3ClxERYy_la> z;qHORh5KuK#JLxa&gP*N(}DFWU9cJefp^*{yk@m-dvtC+XXo_30AIND*}@9D4acqk zmh}FHJQK>}PE?>7!a|hmXy>Nifhb34mfY7O<}Z9{uvvGY<p2Um!XNe{w@i&s@A z4>4;Ir!@%dhwGztj6AJgNGTPpVr+zWOgMWIIGow?cH!9{Quj+J3G+D&;sB={aXIit z?}9fJY$a4qv}w~nChNgYF zRKK<&D5{i@k>Ps~K|6z6FbWt;8G~>DpfuC1=6g)~^=@-toEgb0bMrG8CoblBKZu}0 zf|Qp?*OefL)e+cf>ZtJt(fJEPAQcW}Q0|@>qFQy&m*F3=g{MKj1kbqEf^V8H*w`JqhRuDUvrZ!g)(lqy%JU zZmZX$;}UQjhEtS;azVsKxz+E$$|mW2pB7nF$^D^oJNg5|bq&}4mq?~v^v6}Nw|LPQ ze2E&gaV0Z45Sc(xOQ{%b3|Ne&h(q=;L@CWd=0zKg0k!hII#a zgCY}eTG+X1nh-u77IXyXov|x~16j1&u;06UCt-WD*k8V((_A`yiDGWiqqX^LlZw+f zM>BVgCKJbHWC%cmGpODB1Dp{g7oLfrhr}0F>tR)fjGw_)Gj} zR-9GFtnZ!>aiftd3>u$4n)Q=+s8QE57RQZJO5N`{9aUD@Oy$3|K4SPbTM&Gx}b79hMETpe!ds0EP>R zlL$O{JlltkHT?S)HHtS2F`La9D)aZ8 z&zPQ{bLa{M2*r!Jx-=ddJE6Myf1?c>8-8}!>wH9bLFepj|3XB~*_kIj9HLCzp@ft_ z?rW`u8?8h#zyW1KcCqN6*|W^k0F?lxOi){Nb;n>D^scz%7(fW8;A6?t0W+mD0dCUS zooQgnrbQO5Ac%&&PHP%KSVyR+VASd~L1-{-ZPe}z$5uzt$GAvruy9L79}kfmgRx-{ zyNJTr!{Ra#!dnzXT8wSH>;{o?9LJx6NeL+E{>gVlGB3*x*X{V)av z@h1e|CAvWGxsU{8Sv7EX=WA>y!$>U9? zpMZ_n&~tD3euMK&SbSBVH61ej8Mk(mej3mRtjxy)=V zM+!j<+1oDeH~hZnq6uWG<*OAD3bV(94CK5JRR44&9WQ)f&jfC7*Z0j~K%`*9yZi&g zIL64#eS#iyE}cH-L&69)>NR0RNPfVq*X*Gqn>9pEhBiYzv%@NkWArkF_;k+6r*=;0 zSDv>dEw+Pxj{h=c1&el_H zI_+m zRq^2AHg#itZ8Sv)0j5eId;{yUtk5A?cxERD8N0;TS^R@Ac#2kSZE@u5uP(EWn}t*J z1D~570u?*@0r0VGz_GX5{V!gAg%}KC1}eDIgwm^7`>}@5Bcjr!;#wA?#fX%+ogwGD z9R%bZWJH|kDqL^ucQwu>~OC=l}|WEy~pADLz=yy1+RI8QiZjW8TVTc_huV#D?d$Tl4TZ)nOiI5TQUcV zy;N0aTQos^TWaO!jFP^QwDKgQP}~F(+)~Y(Wkx8?Y*}X5{3bL(s1lhwhXFA`Y~R}W zhm_h4N;$hgb?)V5DTvEvp)tC#u{`Qq42+id#y0_$X{g-0K(${6KHghy3`7={Je`T) zZAfy^M2@jNSfc*ii@)KPWINKd!JSF-0NkSubq8caj&bPpfYm!N4sO8H_knGyj-iM@ z6Q&0(zJqM6<5OpPxW<*BkW**d6wpvF^ep%gY4Ui!g((4&X`bO|@PUW(d`jqn-$5V- zvS2c(e&B`>FbQEX8PL>T32DK}3(qexxs^-R6;hlO3AnzDx({UMvj{;3qU|0)<1UO4 zZd?MV$S)*(qMW#aTZ6%n9-3iW!?B2IZ7r!X@V2cF+FJ?k4cF8KeZI`|5xe=wBf;7lD_*MP zTV2fr^o-ZpOsTZLs?RxMgT^yBHQIiUohevRS$Yy#<3TCY1*1yEir{Q&=b~}>F0D|q z!4|Ek;4Iy4_S*^o#R@r$VBYSCRilR%^=zy~nfon9nfN;VHq1*HK-WE-iov-(oN7Zh z9=cb}>-P=L7GtlxK-9z0yEJqg{ma`!CZgkf%dKE}dDoJyF0#-}4lLPj75WP~{DeGl z8~$9~HT>tC&lb>*UkV7{z_I;y9;P(RFcMFAPsrFsK3FrH3^&|ULie`3VNU@P4(2pq zGVlpN(FI&q)cD=v!6M7qlO|?QpT-fdxGE+~*dO2SX5y(gkF0OC>;gz^whO%sPZ=(e zVKTe!<}K~hDi$=?treYsVT%#6=&AXn;EZb-P3kCeiXaahJ;44lrE+JMHrPMVl7u#U z3$&cqjeyK{`e}D&#B+#LQPPyzunep5C2K+N!ZHD+vOvuTZR-7P!mT`%Fggbar-Zvv z2*Edc@?6t|{60s^TqCm^bzpu=6}_ipih^h+P6Nz)hf4-krIC!LLpsF4BTjG%tkURx zuSTb7Bz+`2=1iSZJfD@!#G2EysHW^kKZu#LnbaEh_hZs0X+#T{Gyz)a6c)=M4bOlq zPBgML&V$IftXT&5o>j`1U}mkP63vmtOgRA!x0~{~DGt}r{4wKQD3Nu{E&p&G=d-&D za-+^+rM&ROTu4vZDk72{9P85Hd+Q}5_ppT|jEzxmu=tQU$Tdzaae1)Kt#_8yrHf;a%)z;LeAmCj1pI$P6hjIA{lh zI3(tzQ3S0hZT(2*n37hFn4kfw=JWRVV1lI#CYY8hab3dq<;pCCbQ#iF9M_OZyEAhX zlx#I_5Py$Q<@c>~jhMl;2y~f2d~T*UWhA~`t7&r5#|nIfxdjQKIt%2xJ`_BNhkp10 z|Bv*-6C8ELCHVK~#eP-cR4Kb3-E9#euX_^`9nHR6#H|qi%@v$5PPIe7VWZn1cOD_0 zFRafkMo49cgWb3=7OCrSYyo-lX$8YI7nmr6#wBG9^l{A%Bf7vR)*Jz2jUi9DK`Bk- z;s{IP;{Qk7n>8zne{G`oe2TjFyf32&9nlxeB7%U7-gGdDGN?>4eEPH8L*~w`%*y(A z_lc7cyJ~MlW%#j%XFcm#f5C^tvA(?o<2L?^UwV3Q*e{vLm$+X2ar*DgK;V$G?0>vI z>(cj+4w`{3`G0@x^56G1hrudU1}zUA`myo9J~p6jH2&A?OVE!2jA)m^XdswKhQiPc zw7SM0FeIDhy0Bt9zb%`^U>}AB}5k6s>Tl-B0S}nHZcUfuK7#dW*Ezxl-Y9SK=?aV3qEK zC=M6!ImmW%cSiyd{+QTZV%d0{2r7?nVV@AvB#GSNeV@+ZaS$dZt=xja0LsFh-nZ+H zRHhyB_04Y0K2w2*2?bmxkJ$Pka%)|bCcWTBUF0L!Hp4dfJO8##my=0YxZUeR5uOVj zuH4DGU5@e?ik@X@(!|3E0QMUClN0&rpek!(9~c+i=0-7p+h;G0=`ki)4CIP=-R?%k z3Pl9o4B!2lAMoYP^0!kN^IW>>9Ht1zMmef6DOwWGSuV#>Dld-Q>vfI0!?m`=2oZ^Re10@8@w_U>Ssu47)|q7<1Pb(eRO4K5Coup!Yybz~kgODQBsrVEFlG!~}ZK5)MU zT1QEHMM=eD$Xt~wMzoTYANY}q)tg?UB{L5Jdp)~HbGM_aK2B1Fc5G#97w}tma}Spx zKV5sTj}4EKAO4k2a_w+<&O6>Pkpw?F66Mm$X3UJezvshwol?U@OiW%z-OeRwYq@n~ zy01oiEnQt-_p^we+ES_oJwIuztTbiepM*9*^2I^-Ld(Z|B_8ukUb64uS@ytlP!-<@=MRgu~-#NE@ zp11Ri2qW7fg85!qdlHit=Xgiag*`5u!RKXjDX$7UVy`Tbf=KCL=)H*6a;cl)@HD?vLfbAex+)KG+2UyZa_AR+F?Oxr$N z=XS9+C3Rng&+9eZY-rx{o;O8!V$_mY`$SgUYMo0YW1K6)^=8}VZ@QhPzU7H$*3%EO zf)prYZ030#VlmM?m-AD(vHQzTJ?+}OIt%q?u1zkMydJc{ALsRBuasrR)5~L;rf}G3 z^DgUToY2PSWs6*Ds+r_)s#5-T4c&I-&voENsi-x=dRN(GAdmzevSDU7l(+colVZto ztMl}_a9h@KQLCksGuuBi0STz!XxT-a$GWuD-Sb1`pYl=Mk@>6&7t%jf!4;K?opwAu zDDHp$&v$zU^Gg11&3<7JK~vc#eqj~gjN~6p<4}NUY_z|bMv;QS3OV*m)98p2ti87t zCkc}tz&MB}64r9(64fof^4|=KDqy)=sFSpC_Pgo3I|7)#FP87iYx=j>kPn+WZZCK_3wbkr->p}^Kk`R-v!jE@cv*Mh zqHC{H_;v(i zmFgX1fi=*}R-_TBHTO>{Jx{llf^F0>Fk-en%Nz0#P~k4zl@}4mWHVcl{VJiZoqNA* zj!mo`qf^#sneJZ{CcE$3=Y4q~9XV3_C7 zKB&PC&CBs&SJWd~npKORvqp#>`7>Qk0n5&f&pAQP@w3~~Chau*s9(4{Eg*Al3N^(D z+$eEebl`8Iz}L>Z%iUVcyQSlFxC!AXz8s;AIWMcnb1rx$FpmqDzSiQ_q9jDlEw^5& zTaQSRZO1o!zdrT5drz|C>2jq;Y0O6Du8>uY)mQRN z^0l%rI0O0F@P69eI+UHuG~FvIvNs1_8zgJrP)fJMP=Ac`#3HYYxN8~uIx=xB#g5xO z5cb5#+hfcRhg#&6o!mF2T5jrxj=>nBZckmP%Yk6=$>3YwGaib$5*@ASdr#Qohk9?Q z%8J&)TR@(+1A^i6)okS0ItS;qZ;Jpkd57qEy!R{e%8Fdhmx-NleQ_wLeFP(t%A3r` zo++p6!QSTU3w>D)sIgXd$_8PTRXUyp-3X_YJ3qxZzCCRPU)zPe5}x!U@3!cM?gv%3 zt=U__fQv3DxTWHf8obwIanYu7_x7-}&<*171%`V2Q&HCw%}XYEFT&M??^qggfrQC3 zeV0ppS6S-RpxZT!uHj4RnPqvVIQ#sc?XH)#*X|XD3a@gAE-O#mk)v9wF?7dQAIs>x85~YszR0d zIr8yKaw~I-@a9yh>c}@P2>kK{C&j0MeUHiABi)uSm$22BkI>tJ0VLw<=UeE#7zIb_ zP6z{Z+_m9U(dYF;zFxrp)9Z(Py@3Cx*AH&M_Y3%cdi{{E7x4Gj@85Yw7gXGV}MzfcX1+cl5fcL9NCYjss|?xldqe_@^#uM%%EkY-A-5&!H!7g zcu+vDRvjxy_df4g{G#fF!0E@7T}0ElVsN?FImY) zz7~X)S8i5~J+JQe<2)kLuwRWi40p;-#JWwDex(|ZZoZG$bn?PmP0L2IJv1q!sJ=j- zcfq)fWVa)h1|_5Cp0=Xss!z^t9XtvITd%JM>&vGTby!z=nes5?%Z4F6Owz3>V|SSR z0R}6qVMf%uXLSA^yMMY61XS|rW*H{5lvrAv0y5>iJ>&Q1 z$vqpyZZUi37BE!6u^qm;KI69LcEPkhBLzWkgoSMUi=K%J|LhY1S7&wL$LGEYoV~s2 z(lO1dh#8+)xo3|lal0n0185TGU$1E1qttNGQ&)`y1P!UNm@B2@Db`5uRCo!)V?)+` zC3j@QUg>dbZLiKMyE8}SvbzsvU)Q$f+TJ{@>GeaVq}DIsT3%ZWnFj3=$jA6mS=@q( z)0kwT&fho2C64dJra>cO9{cvmm5Foh#Hm}9-kFw*v!0*gIHxR`8-!`$-W{^op1^_v zCQRkNb3r>#9vZwItOxCskYpUzdj_tUWc{-bk#0~`>iYk_Wj*+ftiBF4Ab1q>*YSl& z0T}a+>IlEWIDYLMK2n9>Lm!g%@($Ct_+C0F5KfA}SR4>W^`hkJy!zAbGu+q>oehBGgo{-iM*B-c+>G66mc!mk=_4IlV zKp(oJl|S!jRLRYLoa(9w1N#vJKw||S7Afo;1@>AM@>v%xO8dlH9BI}IYeJ009Sui* z2V5Mm`moUuA=7YnVD%LY;*e2#&oVS=?ByR$Uz9mr{LG6i5`im30>bgbDeN&AKZY}J z->xd)RS9-Z1S$`~PbIZi@2?!p{HuC6%0-2175eI+IZ}n_g8qJICOy#<{Q(0#*5FO^ zuXhP`yp?sK@+bm=f(LZZp^_jPbNg_)lH0N{#ZyTIplpok=z7PeQc47eN-xM2=t17n#q+uJp?<-C-s@yiy zr1+5TWMwy>co^b0xKzVZcYyfEk5$mC52aQph*G!r6Ljg`y=TU7#l^iM9-nZf5IIk7y^D4Vx{}V$4F(8~ z*4ls>!1coDq3Z8yixho4;kJ~e0(ismcT64OF?>T9KhvGp6Y#I{omaZ!Wk(*f74F$z zcY}2;^mBdLaiu>5015&Qiu?qGzOq`L6Nk9KqgX$rP902i7NthTCNN!4-0&Av)5%E* zsg-}aI<&=immSmA$<3S*2c@R^Ou|~7?k*E?`Q;F5;V7k4jrD6CBOqoSj9Y7MVGxd5IjaxX_R69v<_}%BI`kc zNwaexTxOFp?6Zlh%5FuNKPo=Gbv&Rujk-TgKm0WfY zQCOdod?y$kk;O5VtFjlHPgH{3o{rL?I+eP|kv{R@7*8eZ;<^9?fKVekS-y^ zthKd>2efdS>(*Q2!tF|BS1;cyBZUtKZLXt}vAP5q0m+%y6LUT+wRR1kG4QKfdb7@tH-E(7e9D-V0 z^-U|Lhw6_F10GxRt|FcoDcRECyhM&4u}&(zqvop4 zg)jIBOsW1}AF(m>9XbMwn@h^inKbfBrC&7<&Jtu%CJt+bwIfND?*_4P=A^oC2bLuq zcAq9AMO&7X%vmXx0&&)`F;??OVc zB(z&JV|CC&QgYFr^z*4Gmt!}|*rr|ML7u7rcaP|FN-jFTMlNwKqrqx*vXw$)IH5N$ zN0=Nd;V>37yIj$`&|=c#M&2>-c*~TrCjy9)*X%58)W>cO!JEC0&-fVoU4(=iyj)*a zX$%U8q7sQ6ZU?mXxhmMl@LMLXFk7we*F!oh%ebRXPhh zc8l1;2*XIbw0HJLn^mcOFRt=*oTCekZ;Hi34;jA&gT0gXO}NyLe*(i{gyp+Q+~3Fl zdQ(b#i=jaStNVkM{0OK2WGn%zg9m&RK8+>M{n}7gKN(5~4CN1@Gy>z9%TLQ;x$3la zxcD>Tl_j}6eF7*jMAa4e!zr*yFsiM7l*a9QJr4}$g+D2_i+mVL5oSX#$;?f!;+^`A zaDPDN90alYs5{*9nw|O%ng6t{;NOn=D}?d4!~Rc?8qE0b5Br~v8iI_!RTPn5mlOrR z>aEMs7q8Lk!t>*jO$RZNX44p*V7p>Z2g!Qef~Twa#83%hA8U3+s;k?B)GxUL&}SKKG8 zCFrtl%u@|dQm`AYh@wxpN*!19YG>%Aa!{V4u+o$C-e6)iFVr#z3ftzT9?L~=+MyxJ zRkNoL+YM`cRusXQjCsP0$Pbou=TE&UxP41*i5{l=9hKD>u{+e}H#*n7LINm1{#bha zT6u)K38hC>d8*WX!`OC;!6--~Ac}>%K44FHoC<{QP|VrwjG#Iz@hdzJ9+@ zkFOl(=i1MUF7O^D3saAr`0l(|WI9+|x~g?dFE88rg(98tS#C~?jkg%hk`FeGH+BMp z-d#I=V&U4%is32Y?&U(I@j(xEn0Z02kY6+qv^ZtCP~?u$u7I?Q8&nh8{*E$Yxq78oB!JK4th51o0Y^D~e!}w{EGi88c<( zB?0QEeJQdq>=~zQ%-lfU@^324mi4TfXBm{z}uk^gA(jW@`I{*%pr z{>L_dS8(O0&EL9TY`)}Csp8Esgq!N$?Eib<{K3hn-WMFa?a^o6HP?z+R zj}LWnIwnbMSRvPLr8P$JR46ou`i?}$Ff6rR??Qb?%Ll zGUlf@f))6iBVRfKU);IhelS2L%_X7jNmrO}yr(zXQw4GVkFea=r-Zi(sRsVmTha=2 zh4keskk44`>jLy-+xjeEz3MLjdgbp=g6=54dtM>*Lf&JqKRAcI5L2pKjeS^9`O4=X zT56rH2@%@sJS{VSvbO4Ss*qwMhUsSLEPvXDs$q8~#2DEb_&=dDQJnvX*$7q7X11+? z+|phhF3~Q9&oKSko(#?J*=gkr>k+lbHA0W0;M!JSw3tun+p~QOZaa7q9U7jaT@)?4bOQJ;lGz4!&_-AUjBZu*X*F?*L%e-|XtUS$!*T zz6zW83p@w>dorANZsE_{bj5mm#(;15 zy9ubGQ+4UY+m9m)#6#Yr`|f%bk*~jNSr87{{}Ec)-TO)CJX?XR|U6!-D!ZT0Y&~jN{yfkSpRpnO#vk+1u_K@ zNHV|w;6}bblyHP9#}72!R|JFnV+dnoqw=0mLkMGk^%OrxEpH^Z*J(=dumoRM^f!{h zx5WDo#ve+>vfEO~&bSxeC34apBeZ=zC>wxh{3EUM7pgjzH*fTrGhj1=Cws&_5y+hJ zgDm3r5;m_95N3UD&iB2MOtQ;#qMS8QGmb2Xvb`nCl z)A9ysW8UPsGQB%jy4zByI>`2slJR}ur9#f{nNdaOc4d+9ElQf|< zlRlHD^tn463SHMWdS7zkzq9_<0Lr}QD{$|>u-*S9O7sGY{^$#~Z#10fPg%q5|3hD( zkLo-84!+>=gDZR{s8-hKX}`wE6Id>lFk2b_ygpJKx^SHpZ-88 zzoZdBd`mc!kjzJsb4EgHf#kVOhJ@tfr| z$|uId6=uUzk8^miZf$X%o;qdNuSDAEc4KRgm;M)`2Mb%U(LH6dM`65NCKNIXU4jZibR) z5*$l_LbaUY^myv6r*w=k<9Q?%cU4&F#x{oe&ZD)!c7q>;^mm`&LJ9bV^?c=(Tk9(9 zuUCB8;i^FU+$u09SGAZqd@TR$6Ci8&q-qL$`3~m4e8LWVf|B$9@WHg)K9q7ieaUK( zSMSCj)7pRO6A(yc3tjkDQ;&Y|34wQk!ab18yz)CB`+L9e&V%CX7Bu;&E8$%#`#?vQ z^SpF-=dNdsLs+pn6+|Ooofk54zlea7-f*`4oYHC_+fK6TmSU@kU8gN@GCRZYb~kKC2S^Gm z7jqqKx$N}tfbSwH%4yDw^P{`3^4d_FK~;|;-7u{thfRb%*qSxg)4f09{y7#%lNKhP zjUNuXWQZLAm+r>I`~0?k;@V}?X`Gp#l6~cIqy5Bz-8GUjNwc?Il(M^GN!aje@j|$; z>qE**oeFho8%S4~$Rk&|wYN9L+0MY?Ke$w;e0?<1oT7AK;9hn zLdOujdMomN+X!_G47QDV%>9)0dya00qx=p>0T~DXPR98ll_EM+h>g!+Z{dNClMHa0 z-&jpRgLzsw?*I`8$TlBj9H0mRW$5K_uE3Rm%kpBYdIJ&??vMP}>l;xCm^>VzekUq@ zyD=}q_@`IfeSiJU_aZ5{GXTDz2!48mgbe>@2UYsUeZ{iZviX;lWrW*DUSAr*syhJ@ zl2ysItslHZ-gL%Va-keKkR6Oq;tN`$G;<*(=~VAaEK^!3a=O?C=cso24b{VLK{$3G z0l{6Vs-11(ov&%os<#KmwR4tdEICy30}vj~3ok)zvo{=hFEUQ?W1W$ZePc+8X7a0p9(Wf=7 zh_{6nimP3qsBKI$NI_4>svH_OBui{bP-K^eU6-O}o{*yXviotx??WxpiHoW<==S zHw>(U=d=Ayp8@ilMuWH8zqL7OCvw-Edy&4lZwvdi+V!g8#kZ9YJuZ$4Y%>l=^u?O} z;^%$=`(7UG+e14!xt=Mf#+g_QN~hG3jekPsq8*$neXLzdd^IvfC38;q7CJ~zAA1$Y zKUy76ERRVX&jan}(y3mN47zj2p!oo5-AC)^TKB8ejeOL)9b6PfeAIKT7uVtHYKxqk zHy(4EZ~g4_$BAGCe}&tTavXKR%;u-+-){liA8>8a`sWQ-k2(^fp*hbXUwVAU%8W}r z3~b~NnJzvoYGdb-)yHZ3Qp;_sFj3u!^GGl?QFL)YzjH zR~XN!UU$Rc0TzVYXC7D7z}MKU4#LLXT7JZq*eV{G?KWb%?VZgJ*`78k-8rOowgXnU z8RahWboQ;n>327`r*+gVW+qX?m=G65OS0_l>!y7kh37r-pXKT^iNN*Ib>16R|6Voz zA+Z3)?&AWTJ-1CWdZozAY;(h_L2q^EZ$|USeUYDb{)y2FG1y0QtC8uCXmFo_cRXmG z;NI3{Bp;4uCOoc{rru8LjfE^Q;M`u__^xqG(v>3KrQ_pjt;M)^?B?Ue7~A%=4V(RS zSx~3P%RNdbX|Xk(^Rc&}m!Pd{@?NsWt)q|>y9TWm=EY3cv$Y5y&jnoK^Fi{Yt2zi3 z-G(0EG9_KD&D2a}v&%F$Ut&21`+s^?Q!BfXb}OQjKp=JFn!~+npb#IrEl42u(Rs%lWgz2%LJCAFq^`m}ZblOVm&14un{XhZP#(4AgzO!>zmuJkAKf_ya}A5rf&pc~AK`}Os&=0yee^n3fNH3Hg> zLGAU6p?fhGKQ?|Cx<4Mt*Dv}sbpQHDe#Ni(O0Rh(qn|DNPgBA<(-zMM9Qw-r^Quxf z&%FC86P8A)=XZ5o%CykswuA5OOW&Th!VWLR4w&ELRpt=y z+2j+6(bCH7JSJQ42I^L!NOD=yv5&9?x3=CJH*T$-Hb-jIle?y^rnA8*BP}iScu~{6 ze1nO(B^o2!)Y>ydNIuho@HTz6+cuP`4r>rMh?M&=BeqAgx%6o8bXN9Jy?pX(!UaGH z?#GHK@>vr7fpfD3;_FitbkEpo1WljZ=mAxWQ03g6&cA;E(7~arCF0~S`yzka`4{>C zm%mZ^zZ*af&2WwGQ^}k*NZ0PNcGn%C^`7#bwZNNe{7w^H?rs9^-e;3Qs_re`?s=5S z9WBJ%r&2z2pyx_Y)W}oYAoDy}rF8hbAg7&t6_!#hvA@!) zndOSmyovn)*W2K*lT6bhcE&)XF28V#LB+}5eYA12M-Gc!rFK85HrB~pGgc2DNVM$? zf&ODC(WX2ZpfLh0mX#D?++wHqV1K>(Y=u)D6ueKnAtL|+zi#wWKqfro78l$fV07+i zMO0JlnhR)&F#E%L(@9(hUF`I}oP-hrX)m~X+rd2a&_%^;4Vyk2{$qQrq7d^M8QD?` zuC}Xoxtj}hRUhpQ;!y2M$A4~_Wb)+J1EvW^Ue5Tp5`(+2&8=?Sm_Zu{Py};vFMt%KV=e}wpZ>{_J zt92h3y;|sbkx)zncP@6=#Wl|S^V-LKbj({BE0b7C#y>qKm^Qpv1zNs-oOF#k%?qzq8SuF&5<5N~^QoZwDiL!z7opdJX?1H8 zRI=k(#UVF%>;<94sl(huV>Qcia6bv=;!W#iWSVl2wEDO%@X(Ba93qa-^eBbr`9cCA ztGXS|*REQ`yS-M3 zXR_H5+laKf+vTP-)_N;T`x73CsB=lhWRoJyzH6%snq|xGh}y)ax1vi2G_OY*dC?Xf z>(eH&t$ej+)t%`0E*bI%cYO|etCCd3@?}U69a%RbW8)#sZD*7O0hG-lc_u52!Kc*Q zJ|4m;_K9iB7lD88b!I*56!R2pW?kY)!*%wl{oOOsZqESHSLstL~ zMfTg1Y9~k(-K@IEnbiR8sF^2G6u+*NYdJ7SV8TF%>hQ`Hx7sQSp6s$ZT}%vLcg!^P zQ}d+HfjSnKTHc6$ej$)1ik|7bBEvl{*>(G@P7SUguE@T#sW%PHC+a2YwR)#|(<)+f=5Lv6}R>^8Ln&bUf>HI))1hOi_l%1K7F8M@L8^hR3sLD7oH zQi&sUGCR;IpVAxhHc8mSAhvBQmi=j_pc}{Ka>~CfTNa)+vh1U`F{o_Puzaoo<>>~Z6wi_w$b^>k#2%<4s%+Qr;8 zIBPn4-kGRLOD^(YR(Oy-V`5sQ6q>Au7?=5z8@Ep=u$A-kcrXv34|hBd&pO^sX6`@e zlQwV6KDfE)S8uLOXg?HsK^_9i|O*d&REE<@pj|939K-=QqoG9YXPSl zxfnSmkhV3;iQ_Roc3u}v`!1ux!KHoDmty63yoqNxJ==ub~4Z7;3Y=WQF(UFAQul0bYD zTPbI=7eU0QTnfqo0|>npR<(kClaoiOQmd&ty?WXk)swhqrBX|W*I86xxffqCRo~fA z!Eu$=Lol!H zckm$Axx5f3yT5SU4LLQ-m`L2tdT70~2BjIRvUkSyh+Bgj#@egh?+6h)e+5e`TBfoe)03FhU=JarfRS z@z3II1cL{cRbvsz3Kh07nnn=m4DIzV`= z#QbzM7b4?81_!+_G(C2LXJ}}?@pnD96VnLv`uyX0wScTix!jLzpYRD*p4YeY9qsCs zm*q|6ZD%yWWoaut=}s=F&PYxLYK#^=5=GPV%wlXU@Y2J?+Yt%!dkE!hltr^1>zS6C zJRGy_$xUXEICKi=W5ur+wqw=PYA~Hf$IlN^wDVTZ*JoqcGFt17I~|30O&gzYS4bT{ z1gTYQc01jvuDG}J(#!!p0MCIH?I1CBKA~)n_b5lVy=ghq!Hzc;v`Xw!T^q1x%xgRI zEZq|A(Ev|Oz1%S2e!|6>!S831WeT>RC})U52X|?AWj=uxd!EQ8^fl(8J~F7Q5%#|2 ziC4t2teA&wnvYBH$dPbmr#e*vH%e)UK87|651Mz9c2DTVMJA*|guV^6VCs`}-_`XA zS66|(rw_P$ogPB|U~C_wGCw2FR}*>EOpT8vbGVF96FGGTnnC+|(rNlROjT{c6jt*# z9j+Z=jQlFUJgBrZDpDu-sGBzG&D!m}gK#xmA0mEPNu78rCp(~?rCvjvYu;~MqF=3H zrah_~M5+be_8ghEMpFFdDR5D@3jHk|?UR?xXVJ5Ua)TJisEK#p8aR^hYn%NI*h^ zYq>;QI-a+}v}$wJ$Eq0CPwLpK>+zqeE8ew>{>orjAHsh&HbR zJqSirOLzngrQ3Te$eWPETOY|w0OM6#c5}o6ZKRkm9v?~=(^ll7&y-ohPY;kS%}=iJ zjC~wR-A46eFCo-q3YE}B75eOSu=H>Gdv6;dtLG-8kf2=o~yVI8EN=m98P<9v1v9s-i1XWN=V`9XPJZ%FE#@5vGEuN!NdCEm+Sd45~Mwhmk@atWVImw&lI264MZM-)YG_tOvlA?Tl*X}w*G!GR)OKNr3 zIz`DUhoLx!Ut#@oVKh^Ap*%HqoKj&Gw9Ke`?U7|}cs(h1lAnytre7IjpQ1%wU1d$@ zl%+$I?ZiLN(LN0_I@}S`8m0Qrr1V{;^heP1Gbw!&qy4Gb8u^J%<{ebsH0KdbL_J&F zc*Rp=P8nyh|AkEHXCWs*W&RvY2_o#vmNNXKjY4av<~k$D3D$G3U)|UQRAPrV9@p2V zK?c&j^1&Dj#}32nE{P~$o^|5=&V>D3(&x$){}#}#zw@rASjZW#ZWH@ehTZ7s(dXjot;%f38&j(Ta+%?C1O~`*{hU zF3r9@$*7)1r8 zsO~=Pt5V$|44ZlRi1Wt{-$ZD^h~)ZuBhJ$1csff$XbKWKKIG)S+*j1b4TyN4svvp{ zhj>$#5dPaVKhtPa`!uS7Kp}b+fyV4z-z)ZU?k^0EV_P5#zXcpd_ENSiZ>ek)YY?xpahzHy}^@2sc~r zQ&mELDaHOyOZ2UVjC_?y{tc})M%yC zqc*pPjd;h#$_CPeI2BF~{aZPrw5MDaQebyw`g6aVYaKcp#npNiY(X|o0eT2)i!Rf3 zC;+NuxSF^jP1dBG3~z*@ain#(fxb^CgoZK%3zJ)xdAbYmKNO@>r5GkW(5;7I&QE1s zvfjflwPGul6DH2<>42V98wK5!DVQaX7PpUyahnax_4gyv$kk0T1|~6xxPun_T&H)I zbZNvQ&@?~v)RWcG3fI(>2dYa(d%Zdxe+j$fPp0P%9NGI{pz!`(4B|DE;1_h6cPi(f z%#ozOH3WYP>V5~tY`z9?5CLtW@$efH1$bmf#0Hg|7qu|C@27OdyC?KINuOE=s!4KYj%)U^mUrcH!&wdfI&vg*82ZE#wJ-lk} z_%f)OT`D9Y;S>uA0`_+;G=3bnF4TiSrC^4Bok-{N_hw9xaTas@ zp1!`ct#suj$q%OaD`E0<_LE%u3@{!!?TRl ze2miZ*sc_Qby#zInt}SKs{&mGT1P+{PfmoraXjK~$jn4sUlc^Z&1S~Na@)Sag?pK#b)WTAm>WK$-Xm#spY9W#*Jq4kpW#ifE>9ly+QIBxja~th z4V214oLvgzF4s{`HF_6h;>m6gb;fRUx=0w4aQD}mo7?@GIdBkZ+}72OIg;mgYa7b? zirY+3Y3X)d^2HVjAM+|_k~&*xZI_&(l0w#opIhpVFbQLG96?P@^fvcB^Jy>-{0L;p z=TEf6J1=R7y3jsjoja;w9ve!l&MY@R_Ar6rz4hxSxt(7}i`jd3@fqQ_)|i0CEa)@l zh8oU4sWKPuj|*FbP#}v5?D={!epE8`zAYgnnb$>9kE79W*j)tPvvR@GEl2NX_O<<` z)AzPeKXeX(4=Mk+9=-3681fSbyt-xljus5b42NoAXVq9h}=#nu63iL1}aXF?!(w_Vuh zR(LYUb*e@%_5p7fW4|DFk3FY>Z$?JPxOrl$9*@SHz6p;T=p_xUD4i;(nQR>3Gt|xei*d@Fo4R+Ok;w8S;?f>Q_&OZsT{mDxJmHtxw z-|!MIUiC+dGI$Bxs6rC@82%4D#XAY$Q@>y5C!NwXY%8`2l?j&NrfdBP^lHsor4%+q z3N4+j>T)*qq$cMK8fm)mJf-u|4rbp(*qgf~|zus8dYl{U8^=%Bfx-A|>92~0uHoze9P(#Fq}+F8NIkP~c=J|E!yO5Gn@ zvx}kghZbal9AMsnGIzIIB_4v>7q04*VHl-n!(A=okZ7*Guv)eMFL7_ups2QWYxnsT zyKe(f0c}!BAxK^Is00KBq!NGqof?^uk-2m4Jm-DycfUrSoyUwY(2%v}nsbb2ut@W~ z)$1kL-h*DDiu&?+%++Srw(BwOW+#c*c{s2s#-bW^EO69U4_ebiRHAkVa+(OfTbJwB zOk6bHxCp53BZ4=cWKf>a6K;}(_OLsQAu#LIEt_MfZyC$Ez}mVIBj~)N7wl73{{Y|b z18SaEJL(h3uWO}Usz*A{Zz>Ilh-%^5+l`h3Z1-R76i6Pty;`X_o1`k{^NFO1hRY6` z_xr^?So80N{`mc)^l>hHV`Pz6?`_K37=l30V@J>q!6I*I}u6zHS2!-0ObOJpo zwNPJ?t-NhIfwBkGz=*CP`Zn<%fjp_5-Cj-^sMb-IJk~Jl*D+$~w9pc%vElA=Sqg_~ zOI$Pppqduu>emYr5(Kl#Ye;`_rA`GEsbOT#s<@+)-^{mhI#XwLCG1Gl_77aP@;Cf) z=Q9C%=b{x=kt3?QlIf4jA{}0S2giU{Cd@tUT_yc?M19 zPsY;@zdKAKM;wXE^?4jdcD;!!uxr%&3#rdY%a)apSi+t?I}wG}{>iNATj&hH;R5og zeegudDY&|PX3-ek2r-6}V<;D3>1UpiaOPrY7z3?^ec-^MGdBz+K6}*qcec>CE#s}d z2lwzNKH^V%#-AO-AoGPyWBk*mf&TxtY1H45!?0;29~%3&E$ZjG=chXSgD?R?FKC#m8c93 z0&}KhlC^kTE)at_aCTZ;o8T}9qNjhPm%W6{M;zeTV^|zDfoo}+$FfO~s zZ)qqt5q2ynWMfzEB)HIR$4L6rJoxy&B)$=a)J0c!OQS}s%XXil(^DPnL$jl#2?QLn zoh~MJqth|bmpzLQz`jEl1l=ba3v2UCKhLYaorhB!!YXjG*i}1I((zoRi;yo@IHCb` z43&d>f;RH0E--N!HVmEa%atHLFCCD%kjq$KqJh`1J*dv5o)l=)!%r_PGlj2KQtusc z)L!@Z{Tg_}5Me8iJFK$r?sh90{Y3Nh07i!=Y26RKg_P5+Vq%)AoI2^p!6v8jY;NOm zA^=28M`x@aGTxl9$86wAD!cy49?1C{1bHih8CX1gZxJKh8$)3W8D8$Gw5g-?xbe)W z>7OvfU(y(2Nq!n|{t-oye>-C^;yh;;de?AWev*RqpN<%xcgeSp62Sf50P^2#9Poq+ zy)G{1ziu2~pAfi@pG5P&KjANVY%jyshhK}6U@SqEu{Dj7VS&rc+G)d#jCFPpY{M8q z1R&noru0}y2b4FQz$n+5J+7q*Gax4@-?oYfhMQi|8pekkTLA|2Otn_W1d*4V?(Jrc zv=(&!pYtJFnc?$*8M`o?#61e3VG5Y;oz@GgLfG+Z(D+DM8|mxH=LA^U~!2cnq${=#QRru?^&qA@mZltSL3`A+@( zwF&;+2=UMCegT6vICBK!;74pBf4YZ8`MYTc$NaiUu(r*IDwDkXEH6^C;rJl*xeC?G z2K=RU^tr~vFfn;kA^u=YMKYToRrXW;TYr7x|Ktg>59IzEPWm$FzNU&#P>a8j`!8at zYA2tMsejuf0BiYk#38UP_FmwbEga#QpBDLVYdm0H9&a?>FYEi?LIG4z{2xEsZ5+Zc z?&mYZ6aQyV@DH2BZ&^i zq9T0+@Byt58B=^rUU7indf^0PT5-V>PxI;N$lzRe$4QK09=ULt*4+KnUe{(GN75a4 zA6+m`{*Yeq-8v09R!3uJBL53y?6GKV*! z@|l*Yv-lZnGpT@ajYv)>*_!l%2f&yyer^&H>%3h++ZoY~KvL!aV%i*Nt@Av5&fa5m z7X0h4TtntbGX(@JzH0d7`3m-euFr-Z6S!;A_g$k+;Wd1|@*|M&qo4E-BLOJt%;t69 zr4kMF2a|urVQOz8$xBW1x(NEP@@N_yh$8hOXMn#y2dnU_$(evV6Ana=j(G@j4LFGc zs-F6l-vfY+22QsB`k8zmQQnsRgD`@3eGb534*xBZjfTgb3m$jj60F@hg@1o31AyU| zL)udPesT{&D12syA9@J@9R@FxfwD*#!-KGZ86N5`d4M|suE@xt8wQWpZ`(RNHiadF zCu^sd4nH-X-?vyI$^{Z^Owb~@Psn?EKf(K_0^TLY!vdb@`OCct9cyNKT}cM_q?CX8 z<>kDG02$?bZ|-gB|M6RbQ`z-xa(>0OeGtH<;TUHdTZt2oqh$&C9#-;oUHYFaOL=aP z$WXK3t#~)&e~k(K$2Mg-7|w8}uxqQ_4yje0Z&GmC*9`)u{c7W-)5*W{UA^6J>k{D0 zY)~A;=CFbUIhs1Hu+(UH3f-~Bd5Vvxy>;GE?B4Ef8bv>GEC%T3Z5(Ul*juPuriQXs z$f@cRU2qe_#Hy*0z%adm#f>0^>*aiQa5E7LU$oT>H2{(WW*|0q!J-6)RnZ5>`}%?8 z(pGjMeBuCzdOs2UY?#eV<2*k(Z14zMu7*mM{lk%AkW&*!Lm z*Y0*ESy4&QrF1q9rTXw>x4WU0C&juM>(w8Uf_|+Xeyb$@)7%PxF|Za9pGglaV^qIW z^!?3tV^rAVYtk{o|8%4Nh~W7t(zyO|Gk;0jgfaRn(HJyDugFeF*g0{)IrxY)hOPeN zL3r$40>GK==W%-V&)fZLw}&>$w=><3sXxH4X4V1I6JLUHmB^ zjv!`B7b)mcMVT5s|@D@ivobH68S z)Cgqfc-%JkuOmRtk($eNOB62BID>5_bIWQvUv^={jvi!C?6c^V!=hgW60_SCZ9aG7 zZRN|Qy7y00M478+Y9@3!s3%}HBQ>;NjOOg)@yRf#wC7O~M29iIk}4GQeZ1;VCLVMW zCUgDfu*u2{nWP=J!+*&QWrKVH0Ke;VS|*&U_DrKsmYOv}|uZCe!bFtM7c?Pdx88gZ;O2GJfo%pl4?WuF%mykKyJ9G8wu1#|CjE@p?YmGG`2ngBELMP8pL3fEL2Ca;v!j zRWC*O*q(tGD&O^u+OmP88JooQ*HtNO_Ym5*nsSJpO|OW1VK(h0-Kw}`c*+(H0&0ow z;&c!R#q)G<@yH$?B@<}R&d=wK*-pLEF-{MABN^<%zJ{YWc11a>NEBoxbCyd=;2L&@ z8WST1TeXhX85c+e0Uh;R>ll#hFZgLy(A(G?-J;2#hkbC#u+a=qj|^3mp!k0CynBe$ zJd@(sm(WYu5^6w@h9&9hi6n8Ci~}~5b+?BE*KJL)j<=fja21bqookwBT<*uhZ4BMC z9muZH3moy>=(36cZ+9*y?p~RVxNM>k!?0s;4K8_9%+D>UVy~J+j@1+c|*Zi>v_0CGuVu@JV&^qVYWp}fr&PS!OcboyvQ>fif#uX z3y`xjQ0vVFeeM&mo;QaKw0v^-+=y3hsn;kac$wqeMS>vRQ+YuYND66bLFY(g)Kr;GLF8Xk%^3hLs^|COwHkFt7gfZF)rS=NKai-e# zYB9Mq?`Gp;BsP?30`4ItTsi>Y!rebM_MVO6d78X}6Y5A-E@@Gn*VlVRfuO*wYc4%j zc|5^3$4NKo0zANxxl{aJ>CO6dE5RhZ(0zKeui;Em*CC3ilQuwcaZ?popZZC-AF_z+ z4>3vXZ|EhX)VW1k0<<%ZI#H-_mLayqJ{MU$oI~NT4OPH9pSG4Ple+b^y+wl zcu;~GYnjc7twR~E<<+&<5@#^Y+B-!_FNsa?C!TsjIH`RuiR%g|2hZ}f!t-bc<(X_R zdMr|H;`A!8B7~!~Q;9KMvpm2By0qj5kLGCmp%OSD51MNsfEmeJ% zDK9S*GLksKDLmCLPVKJSB=@2^abW@g>il?V*tKOh@}eRKFwB4;v9Bx`65LNPA7;TA zaj%~q-Z9dQLPpE+K#~rQr^tL?0an-EseMFv}eAOK)6{p5SlGIORQV4?OawFyw@cyxzF$3jc2FRK z`UU8OFmn!E9FX@3o@ndc8GzKypAY!o`V_GJ-T=_xn~?bYFTIJchmWrZ3mEG_O9F#4 zzz0GPewqO;&=%-$`SII7e*d>OUJnwX0}p;6D8@h#hrQ;x&=eU{7TSK_`a{UOK?FSp z>BoflmllKePJ4&IijPV0T7!ns-+`ttj0f`BgLs)+pd2us6h#3~S#1N{*T(GvKUY0` zoXMrxyr~C}@BG8pBCjuQoNHx1!RhwJDgsKwpSr#O((L_IBO=how|>{SH9&_1Mku{6MIaa*@yB8Abq-|lIWEA{;kl8%%&6;#Aj>l#2A*~TT1{2Xd z8)6WJwsMDZ=wK74`}(@?8Xp2N2V%?KL9nm@2S*$S>3LxOI05A&n%Y2$k?IZ{yu9UT~0yj3S!f zQwtpOdn>Nu8^a=i^X^rEQdK*#TD&UK6F?P~@<4S%U?;I*B>bJMc2$gVox&%oz705Znxy+Z1Tv)%Je z1t>D+G9&ac6>*=kSN5L{IY@i_-3rKxvJK= zurYTA^|USZdiIsAhliCs;?L9{@^uT2+AG%e~pk%9StuK>_5$I zK2*cs|MyR&7U#Wt(4Ps+kfr)N_$y=la!)G`#{<|W_)y9gs*X6A%h?#XWxoU>t5!10 zAJA_Ya}ajuX*eXmznZ=;weXO7#1Fjad+{^@gaVWK4>XlJpI$L>oB?D?gZOZE{qor5 z|Mivq7p^T(ZxAT924K$v2;8Kj#(tz6u@MdRL8Y4ejO>jEYbmp1}ENACI=(i|r;oAD)NHA-%!uVw=QtD3g`Ufv;e~Mit@o*1d95K(a9U z*znsdTKwt?(ZfE~K`ni_LgGTPmkaIw7-T%k+!aO7Lc9m9PPGmo8+M;*ovsHmd>=xH z^mcy?$U(-a8f4K8dDvNQz1XZe7qbxTD{>_s3NM5xBE#KCU`Og)2hM`~Cfio@9?ZPZ zf>-DpcTN#b4y#)_!$M&lH)}ByLeml=X7BVM`e8-+aTkYWcX9)b*LTV=uQZ76^uh8u zb@z3Qqpq&hqz_AL8mevhHfHQnP4r zf8PfGiH!P>E$4`5+wM43HV*ub*~0}&%lQ=mrRq(NV5!!j)3~~>*XUz*2M-o!5h&~H z#ti7IPFhSn*`#yaV_mSjtg-`%i_uy?vHbb&Tp+GV*=zUd;@Z1agk0IiFzniTXqyn` z*;6$i#=fK!2=J_o>oWJ?NqJ_s$Wje=S=|U`URe%*RW|m)_jk8eBOA)|Jiq3SGSU;f z)#)k+59c}rIq_(1r918-8H}_v|IluFBs;Rn9e4J9S)cE*mH@_M z&%lt{B1FhLqpSdYpRCE=J||`4tOn6<2Gcs%sw!l=0Yp;^a0x>fK17dRN*K&3?MVT=NgM39Gqf_vkOSj{5$u^&b|$KQ4M8dW2fxb9Bu> zpv~WZ7HhgeKzdQ&F-_NWmv#K84d$|5q57|r&AL#o z8|p=%W7+YpL8_mh1ZmI8tvPHHoo0Y|b8*F|1gT1fn6q9on9dUn>eJ~?-3-OW;s_`i z0CD1WIx?ID_OZR-I#D())g)UHR2y(m&0U7{4+CcABz!0?+@&kV-7Q$+GUMhO5UT;x zG{}0FI_8}@(0Sr!B62&QR*g(w^q{G>X#>t&$d{RUnvS634(hXifHIrkrKT)+7_5%% zJju2ZALOZjYm5G)q=t!}%^8?=lIvo9x(=sXQwB37Yq!ll7!d4Y0fnfnpIz^bQ9qqI z|9IDEec)%1QF2qXT}=NOf>C#T9v-)De*~M9Cp^sK4kSxWI#C)&$}4ok@e-26Y1)lxm+w6>!#r+5H$>C&5vGyPpaTz{g8p_LW10GkPwE{x@j}=A$Vd_1J6?t!6e>TL(yjQpIkjy{9G3%^N=m)+NLWzPVL(6?}LG%@+&??WDo$b zIf9_^bu|9SiF})1-sJl4Qh8f|tFcSmg_6=Tul15_jKO-1`9(mIT%9+#^z>rqKVgXm zC*i9?d{>8G9z#yH1jhfLU;E1=_CI;)FICasUi<&_rN6@D|MuEHRH5o0U;3}*C&C%9 zW`7gYeM|_ylTuko<5IUeWi{vBj(~H^4LhvQ*t8FJtL&_-X03FsaI{M}q@HuhuO(!@ z55T@qJkfr1$>8kxLqeW1><+}CD@g#=lQjF95}U{PWK#c{zzJ0A_DqMyRp*+C;U3j+ zC*Rk*SV)nf1K!mNlp^b~EcKq=pxa3G6BY0`P&j~lX6D7yf#OF7CX)bMcoc5w`ZMe+)44i4y>bYvWv6$KVlq03>n~?S&xjqvFDYpK?o}F(j}_K{bX0?oE1->#6~=76 z@&WzN%HYoHQ%|V4d{aFOdW1{k6!G`+Gmono$$>EY^U@5;&tLGV-zQr?(Nh&+@fSe+ z$e;;#F;Uxl0#dj55$j(;@o$7UI0KBm3W}vuL~k0-gZ=bVTJpAirT$ycvcP|_x2WIR zyMUh?Tvrnirvi2cw6Knl+M8U>4ajX^I;kxnVtjmz$sEAD(ajfq4|v(Xh*@Umvwwy# zvwHaYg&;}#d&%?-P;EXceRH!9*AT@03fA~H??f*6jj9Mr*(WN3qH(t1UdfJv>K;5h zIE-h$T?W5VdlK))`D6@x8ti@Xg^u;3Zp8zj7k7sieA0bYmn;Z37BzSJCif6OOBjMt zT*7g%emk@;He(U&aVI49r%O%>d~Q9a@pgK28W+ek*avtPP7!6&162f7MEbB34I|7R z%o?em)A%}5J?QOOxDq(^)VJ7rAB$~#fpob|DvnBX-3}W+_D;~K+$m$?Oj7qC_p*PZ z#0Wy^@}%fww7MZBdv`s7bw!k>L?NTjra=Vd7=Z`KQaZKd^c5&N@UyfGBK~mF&g(MA zz&a-+nNOYl5bQ9W&4&N1{+HI^M(S_`@n-}LwJ&B4)PEL@Fln4 z5PFx9qIbkI3<=!DC9D3a{BN z0vTuq_HFXwAsoG$J>e41K*YYaqv?XH4Qmb1YhL8#tkmnyQ6)6FaP7RfF7dcYhTwz^ z2w=jKaxtS#-_qJTQC(JWAwsiJ;Fss$8!oB2P}y@ZBr4R*Sy??qDL_{MvM$?sTkdJ% zw5=5V2Imw5z+@!!s2u}_d4SIca?4AG2`nX^L1#l!!5c!KckoM?;iZ63&&1Bm3uy?S zyM|rm#~`@>D)9gO&97_VZxR!H&XVcNXJ&b2Zhu?zKTT|}eB>=*Nn=-bPKS2ug` z*1Sd+IV141{bXPl>OV$5!9hIc4M*GbO6BIyt&0JDx&Sng9|kxEMpQq37))rstr!ca zYDM)o?;nU|y!m(HG!St>`32i)y^{bf3=NI5j8c`ZMwkJE^oLGJ?vB4{cexF)TP#On z1#RYv7M5xSGg%j1mr0nm7%l4&=)xR7IRYdjIzp(}G;zprw~*|9ho+n1aJCyumPqgN zoCWrZS~Z)eu>rH4CNJ^yqKl?3?)Zz3&))61OU2uz-)U+|+k3+q(OE+r{Y>_&2kVo! zG)^uMYqY0kU%K`NpZM%^pH(DACywA!x0|js!aBILAgg7bBSfr5M6lVO;9zt2(+3Lj zXAXQTTMBslRciY=mT|_emisH^>>rP!CMSz7E#bbhHW)Xo(qQU?#l9I?q^+As7@zt` zlxGN3Cg~POV9y$dgBM95mv;jjOk9a4&*caRr+@8?f7$N7$Ig7)^~(ICLH>_ajnAF# z&qlb%d#n2rqx`p(^c9cB?0;z%{lDGne&Liprr2?5H9mfM% zH__B*^3igK2j7of{`|6j-N2Fm%?|#{2A%_E>jTmOy)A&j{`<>bZ z0?6uqtzB%HD1a8il+k;f#Wirw1WDi7yK6B#PC!!6G94I|RWsxe$$+WlO0pv%XLW1C zI%IBHdl|t8{d@~kFml5EbDB{vy>6a|=y(;RhBc1ohqZ#cvGY?3?F|{LlWxTICj>)K z*#_oRJYjp{%Js?Su{*tZOU=f+=4;5Hd`y72P>+VOLF4IU0XDgHGrHY$>7_eB4Ehlq z1v(V8eR%0XM?pr8f2s4myC35r&Dt6vIoYeQNbXoq35|G+s6D~#xyL}F!;xQG@rpuZH8J4)7Yy!gZ6=x zr0Yia_w%t1(8<_PSJS9!7{PMQR$`o2yTX}g{sWz1zxEQKrQ|bA>0!H*7>=XSkBwu; zpI*UZoRzB`Jr^bMWvPC9l|T1|uPZg^&%f<5ug&51+G&gr)ALVxJSKPJqH`~AXBah} zd=fLdmBY2?u7w!pPuCp+8!s&69|_Pr7$E{FgbFL(8gR8ATOci}?1yoJHw=i`gh=@H z&$rk2UF+v7gI)QxZ7Cn`g9VXMvlQ^>FPk(JcEo$5Hok0u-(M;MLdN*xv<9LVj?YbbY~FGczVQc0CpE;Li2U941H{mJhqkY8@Tm zz@g+~_-^&c8ToW2f_@N9dB*C6J8lt)5w$Z+y)D?EZEcfei80?+<7pH;9N!kn!)q!% zKH7|-nUDNDJsF6A;P5f&w}B!(6c}IEtThNGpY_PFPEk5&1h0kea3Z3sQ*sJPQ?&dr zO+z}`Tamu|!zs@r!-jQ zkSh51j{pF4@-I}4&z_?AnRe0Jg8xqY+$L9HNW>5L1*mC=cb~%MtMAMY=q1LUAQ!Pu z=PwWe3<%^l6|2|(`A#!=PYj}RH9zm8NY$ssj10y*0vF$;X{d$aZp4yWqUTwp#FYkNX5c$9H^1i=1m>vD^ zU*7juhrC|iuf4&4X$=N4L+&A+i`?uWOboJsPV~_3sPNRW^N2_$o|xLM@cr#2)rstU zH<%u7vBuVSi1yuo%*UZaknK^x|H*g6w#!st@Gc(DxyD z(gp_^3Ilg+nqVD(EKrr?VeL@{_mFrMpy&2lh;}C%#D>#Nw8tI5vax8vu=7cl0&_X- z)&h?_53Ahju1?QyA_5w9*-hGZyr}B3VV<)|YMW(K^pm1Kr%<=E<7(5ait>3&_KD(> zkLvok-S_m4XQi$Ol~EFgx*5rqqG{~1?5}ysUpIDHY@Ky)>Fp?8iWI<_-q?~KN1SR?Hj70-dwOlur;75Nt6U_^%r-+LFODo4(|I*32node{fcy zyha)}JIFuuVwV>#Dg)D7>@&|Ff{YIal?P)61N?(8)D%yDy>bV(L6wCgAxy4*i`|Cp z6JlgfhRQ&fnX-x}!CslTNn5R69|>7dZ}?WO?3Ny9tcn%lo*<}FY{RGj5Mf|6#i_J? zaBB{7lCl1}?rN{HjvzhU6Cvoc;}d~-XXor|tM&|sRZF|~XPi7R3?Jmp@)$sVvt__2 z(mr$6-k^Y|yPf3Hvod0tDpBTp?0!3)6Jk=sn@!v)Alh&<3+hpyJ>Bi}7)j<{yZYC3 zo9u4L?ZL*Plxw{N+ARC9R;<_;5Bhi?z(X^|QA6ue{DdPkM9}EgQj*sPaau)( zf!;^qZS2_cvbC2dq|itpp4;z?Q=Af*wuh>c9HOhXyI8Q!8phU$_iSJorxnH9x(z1x z2Rq-)UEYA`GB!9l{`X_hq4|r8(i8+j-=^cg&t&@JZtzYR8b5b~f9mO7emUs8K+vCv zKUmBI3K0+(JXoZww=C!&Jd=ff zP0Zhn!0(8HzuTcdqnm;SrsZJT3YL#?x(eXupB|foZ}Tsppga8c)%-id?-kv25Z?CH zuU7(ek3F8SpJCDumHnU?f)%|n*Sj1s4?-2fKJ{(LpT9=!aDe$kXfg!a{(S#{>zC$U zXA|xH3ovqsc!HZrBU60U`Un16fMLP+vGPFPsT5t=Q}}pdp;tcL%^~-18AXKynk?z!0rt}d_IeE0~I|W+PpoRp9Jvq;5 zA;{}hr{R}PvBW;0+8~d{%r@diTH9UV>uWElhQ5pIb%{2YoZS=PM8e!{HXTocU-F$~ zAJg)5$9I+<(Gp{nYhQ8e6Kx7t=))nwfx#Zm0h*#x3_TPb8GqK!w4pC`lG4E$;TaaRP+|QN_|u?+vSv!G-LysNyTh~{ajwb zx88tRDWiGN@ey+1t2!W6JZ(9hC>6#k7ZDGTWB>5YMi*Tn;koc5siMM-YPd>P%9L|TO?5#$26l+~JhhUv&2pP)sJ z)(Pwq7z&P}GJI^o!I$!P6o>>Ow{az~0PoGn1b$utv?eIIjH6`OCyKu_4A*vE#tx8| z+BO9G%6QVDj1WUWBEEihw((WnQBxZ1p$L?2=qr*QYLO)YDPV1$#^=^vK!KR2$p zm%(=Wg8lp5VUA;(->m09xEqCW|^@rhp@`Sa0{ZXVFKR*U7UF1)f{?k?b;mY5e z11#?Uc; zMH2_-E4{B;j^uZ6w)I!fTE=XER0e3ar+{h30YO8ZZha%rp_*OR zL2?4k_X=*1WH#z>95yh42p?4!BC=^Zm#wjI)5Ji!1Cq6Uc;Gf@;_{$xBF@tV-#{!M40oQK zgh!FG1y4W$0cCf+(&zQWidRU$fh5BAX>0Lm7bSQ6DQ_Covou85($Bai6hFMlVv}Jv z^G@U5*48X7+YkdpsiEF}6SL%nq%s;yjB9#lw96KUp>K)Gd_y1ZAN?m$c#$jEU$mj9 z4aSrruWE zm;2-Mo4ELwlIZIi58)Xu7+Chp>ty|Xk$;Vq{-ZUX_ENBardU!z9^#=#qO<<=(k`Zh zB(m|WZTw1BhG}!8r0l7t87R-Wf;{*XR^j?BIT&tH0-!G#X%Ka-7RUe;uHvqCR=1;y z=+1*)ONR-FMqG9u%LnRU!j^hbmN1l^JJ1cG?HZWwrEk+T*rW@*0cjV=j@L&xKZF|x z0~JQbEl0UV9&o^Eqi*MHLr7f9AUF-M5ysH$bel?#gy;J$u|HR70YScXOyNn$a8C(4 zUjelaAHUYM(^KH(|h)( zm-TPRhnJoU4hG+m4;)i!y*wQrhqG9oYk$O5f?Ja7(VOi6qUX%)Io6w9r7BGxLd5ZM z(tzqsl=>V4dqmgp1!;gV)}$(|>gpX^RuejQv*Fgap*Id^qsvms2mj_mYn%J|^ztO0 z&)5MAxmHtzB0X}+S;K>iMINOVMZ^XjA=v@OADQ=bC7=T6-p1Kv>~l~o0%heAC81FQ zd5`X9xja&$zZY`TN7^k+Xh^aXSbs&u;6J3%6v@d>-9v+spTqK3B?0SnGFlK)~zBZ+)#4pA$cIjO~_g z?-;jD*GHVLG2G6 zw(rT^{Sl{YfP~jL2%3t*=#nYEsM|-%I=zi-s8LNB0Mh^Pb$-&WxDRcE&A@mF1knuo zt3NT?&R>Och`?`;)T65mVXTGqRaDgmi+J6DG?_&`d>6_=BAL+7M}_Vhwmir`bTmN2 zm9Zn};9yV1kQXTZEe~4u&+w)JeI0*y#NN1EcFdKCz7?hW^9btOH~;#*FzWpB%|KU! z7EYkbp*$sI&YC@^9;z0qZ(I=HHSj0DnP{*q2qb1*I?+f>rfx**80;#y&wjFQ8u$ zTx1A+H9}SLEd1 zj=Vn@T}%Oxv=+*!GCnv!5i{~HIvVIQ86(iXi`SFAK>Tlw)p7G3@I}nwA(;PhCdlPK z$znLexC>(?Z@qZLG5Ob@`di_EuPdj^wP4{=poR zCr|SCa@PYu4><=bD3KfL65KF5)Zn;3b5weY#PANHG!Abx2EW0swSzH*L0q;`xX4*z zLSz*L1h0)X-$CEk+-}Q|*&yd$yGQpMw_uQAD3(UKI*Uh!IP#7yX@Ycn8f|*p`b-Hg zJcB%JUQi)#m*vBo9}ZsLtN^w>HCA&{*%0BIs1~njbvJ_XNY--!TOPMrv+dS0?~>&=Q8Q45`-M+)EjSCFkq7xrH1iUB+>x&mFQ%9ShOR(;XY!YBe##nJ!Cm z#_TdE83ja4qN@xmchB#$EeE74Z8*xuZD3tkRi4d}J#94bL$rQD*foORF2dD;LlCyf zQy6}PVZB7KG@A46%FTi&>-~9}38Hgz(4-mQ?jharih;P6T*#_1PU*!^P!FX<4@K(v zD6nQPZ3JhtZA41jnp{wF3W0~mFuSi}NK~m7tI$rpfD%o4Z->2(3bkW&SM|_6_fnqZ z^k$bd_Xf%F?Y|bmc2v&M?XQFRbG!OaZE7KTIacw{ycq3gZ|H?uE~AI|&#kgExuXoR!r1)^zY&E`R`3Kk!{ z@i|-l^|4w1V#RoOqJ;$Jj`W*b^uj{RSUMpoh&kgcUdK1%L!0`?g#+G_Qu?RPvZTK| z%XtHxWl+D!O+B8TYIB1mE%bcy@T&s*!-3BWhmxNQfyL`m*LGy&pKU%_w@lB7;x2Qy zorcUi-;^@&3vzo&LC5p4J2=ELC)NId9_EAS5Vuo{I*R0n8JSqiypM?ekkm?JM>XwR7q_e z9)q$h#eB*F(Hr3IWodr2Av_ep&BFvCUiI~kCQm6H8fhM<%4`COr zFP^y?ET+5JBQrF682G_4Hi&>V?XLt^ZvnyR`461O=Vn4=qCK1=UP~h!l=$FHvZqJg zZ}lt5_06VDCvcdj&auw+WIen}RAuQaW!?^Zx6!PS+~^6lLvi7{KTwFVf!-SmqVfZn zNa^)ZuWHL5Z*FuuX3>%`T)v=f0fbm9gbyzLQ7&?H<&!V(oIT?T|9 zOa2T16vy%(0l{WyCivxHn#xie`YhV(}b94bMG>!&Ho_kZE zokzbEWW+Q}g^t!%zDBV9lFi(aQteK0Jm=SY?pp&LZZjT2pC(9*Pl!y_aJ_)F#nZj9 z->T0{G0BukLc|_xYlv?-do#=KdQmckQLhm8D=m~86;d_r%?8`vjWuYLA#YgST#A+Z zyzDNSto!+L?w*r{ZajY>ZHPvgFCY!0y}`+ub9N&jUMD8Jww*RP#AYiuiM$@VO$emw zt-3GtRJle<$itmmlwt)=1EU7_@NQa}n6O5)3`J=%Set+*eN>U)XHwNO)Wwpcz{N7h z^&8!Y1zy&51})nAw7u--D2}Q%ljTkqN+2N%iz`lxAPeUxkdy86cXCNA{qxjsYB9|-amOnDE)QK@H^q>UubZQT5!oG$mU`>? zW7@jRy{ZsuI3G?70V|C})tM07bs*Sl?)eHxbJv}&C#@eLd$YA9|2Qs{eR*uRZhV8d zZDYP#+Q~o5Qe#T$hEWWJ4H>60)SbEV-Np0s0UP!d4_J!1U)@8>NFm9Oq;T_|aM@Ai zIOrKqfCRp+s`wmeAV05bBek?PAx;ajI?pUfDXvMfHRy4ByGS;AhXev1UpRH7>oy4b zvu^xr2(dMneV;(n3Pj?=Uo8C>{+l+{A9wHd>*%xlY)lzGJqkWO-8@G;ySo`Z6YBXOp%76Mj|kU)r#}E%N`?oN^b~aNnURU&7;H=vHf+ z2prU}v)4D}>^s^HltLfKP#f-}m;3OQ#Cc)ffN%{SgLz%Pe18zmr(cYg5StFda}}V= zZ}%@`fbw%;r|bHetl_8tKk|E~1+>-@^HARqI5WMDL_ZCd!PoI4ndSK-#SdC))|a>7 zvvdG#&I3FkEF%5wjr}lz(D^$df@O2?fWTP;ECX{#Kg034D^|?pssw zmb%tfdjpFf7^@Zm6v#zk#XNo62V~;zwKyTp5Ry`r{=RdjyK+U3Nq4@cS0_R3vOW(= zq(KtV@oMr=)=@X`;a|`PypbWDA+))}dl7a=f|(vKr*KA)S(kMjM2WVCjle(08H#@( zqb`_#&5o}2cor+)7B=8u7UdLY+F(v^`dX@hUPGqxz=bKM*cr1dYtYU&RT@Fy*9C{D z%g$S3(4Mk>vhT*qitpeJB2K37g;=k|4tji2TxHx2s5NZ@-ARUfk0C9d#7m{+e zcjvLg%DvE|I=G@Ycl@4#61W?S-kFLgm!44{)$EAeio}CkS#97tnlQ<+h9oq#TQcoB zR-|^?ibugSsWG%09|k6c4`tDoESW+umrOr49wfmY40Rr)-QJEHd{3V;7S#JmRVi1< zI`@|2MoLJ|@9gKMn(Rp0A5wSWSZ~`#J9CEKUWzX?V0L0ld0yD##z}OairQ?K1(Mqu z@EKSg^p#kt1X4uNI>30N->BK7>Ev?5pkPvNc*zivESsjUzMX8Q|Y7B0z`FW?&#Y&t%$e-BqGZ0EQyhd@3Cytf?Ddd$utrMQrZLdd!Cqq~-AMn&}n)5t1QwT}+DO$#Bb-ctzV z)zp!$vKk+=cE8Xbee|!_z7WDb#&7L__*5dQtL24vb{kbQ7?}mDF7+V-|#p z=%TL$3$NBn`UKV%5dDH@c|U5V$NJ~JBh|yhna0g>Ci3gdFrm(N%DAkJNU{0h?c--!Q(l9{!ZFN!qT3x(!ZLZ3w-@U5pYd?9{ESo2Ut>>w_g*&0&efjS7<7}3J29PAkFDDS~d(I!wfv=`rG$Rh-H{p?g8`$ zA=#6Cbjkr}l%YAn(eFPW5(xhBRs(%Lcwv6JZ0KnGS67Yv+hzZ^SN)Q(mA|fH zpZ*(Y48y-G-|RO7SNJEuThjjVAnvF%U-`V%LV}+R#c?;;kY!`h1k9XrPA_S=8Qt2J z3;pOl6v}qb5i{)VLN_&hrA%~R7=KX7z-9;q+J2Q zBC-p8F*Cl2t)_=TVOB7Z3%yOHmNq~0czw4?=|LtuOH3`9PxsrfF6uo``=->pFI>)rm|KZwKA^*z+@_W45tEo{c zxa(+j9?PQU+FKbrW)uzCF4tT_PKLNQm-AjKSC_>uA*zrQ(LCQ0QM}smC1QALu-QuT zz60~(1)9X>uHJ2Z$PmV(e0O#Je4SNn?CJc*DKG$cxmTzIvpQ<|-pwxO8=4-t( zSzYfymJ>N6RI%tC^8lyaq?_}~ISC{7fYyLckEOdxhDFI1wy@d{zBDJ>!aD3rG_Lr= z<}mF3k}~_b_P#qv-j8#?TX+Au=GLz@_fuweV%R>mE1J=3;TD{0`Fs^c{KY)P2UWe7!i4T<1AQb|wKJ(d%hFl(r{y4~e`Cz@DJ zd_dI$M7r=ax%+&3J7{^{(2T)Cj;U56X3DIrMZk_iM%n9Ck{XBLHe4x6;^es@ym-5a zX0sjj?r^>~KHsdIlE0JN^0u*oaK17?IJInDkQ@%s+%0S{DPvJjN5o^h?e=PbMXQPc z)ff+L7`SicLyv8#XAMlOm_;x$&yLd)W_56v(~k1UaX|(5PQ4Zp5Gg%K`97muCOJ}X zUACvq?SS4MAajUJ(2L?^6Xf8`oI|~A2cRXdG@gEFK(|6?PqD6a1X&10sML@;xb16` z0V>L48_-I7S8#1X#KC!++VP^*Vdi5biLc&AT3xN0n>U$MrO}(THBvlmFKC)6S}(s3 zwvqc%8Q@s|=_LGm+V~CP>pLSpMXpb(?dj&BEs)**mghp zz&t!|BCi#oBUN~3?7XJaNNSNbtRSZgh0CP+>_d1ginV)5=8q-dCKA^H`>6C_qkgAe z*A5L76D`)}^QO`1XAiq{3ClwFb+)v2yA5Jd-s;e$oQ>s;V{i_BGFrg0HQJr7E41r* z-K>^U2?K^(LsWc|^kmju{M?>FtvVSg5zN&J3wEt{%8;jJbqk&oW=rxt&a5BNu`Vdi zsC~#Pu43#$VEd!uRWNa~z2MLDtE9emKssm`1{_!X;%rJMgxt8X(P`?ocnwm%^KBu$gOu&-LJB&|nY)6a z{4I458f>Q*jI4NF^rp6W#v+^F^li{JOTH`mpT+%W-OhI)Cb44OcD^;*p3Tkw6tt*# z%KCCFP}1104Xj0!hZn6KZZY{-Zg|&m-yH3n)yq3nlMPQ+RmP0tA)Hb$3sw7^KAW|< zlFjo`Z82@H?`ICn<351IZpA=Afj>iuJ7$-4+CIACveUBL@pg1_0Y#Ndvz!x%F7t9m z=70ouqwT0afRELNmib-vNY#%svQI%S#(~ho*yy1+Sx%1colAS zo9Q#HS$fOBhpp$=nv*2djo-;jsC5njv1{)82b&>^**?nS68Fy|;H>ZiuG`{5#6sf>) z=q#`=M;kYYMYWf>>?70nX3Eh=a3y2VreW{{e4bYn$#(n*VwtM1Ix zb_Xf)6p1QTn9Rb#p%UN?4#I`suSPg~A%)7>m-Wu*O91Q4390Y(#hP(yrZFz=3BqDD zV9WC%F^P_m*_X)>N~dS;%y}R=9K6TNg#k>+Ymf;{i1b`@VGIo}$F#ul3?St%wK$aGf|Y(hTzPga zz-LT1!3C2FhLx zM!ap>Tn47bqMNswKH)g@G3P3Z4Ha+3-pAC7vma(AGaCxu`7vYY$l6VG`?hCDl&VSK zFFD3W<|MrK4v(3tSGL;Nk~$re9e-b0sRI4+gYIxk^nh_XBpF@g({#vu$}2A26|v)G zziszB9got`%D1YNm9k`p4Lpl8w?)mCbo&g1lT^w>nqZIR$Ieq3fEjUS8cdYahxWrV zB%|at#DPqd<)mCg+YwooOc{I{htBG8PNQk1=PH#|<2;2t$>`;$KLgwwNSlDo^wJ=c#s^Q2p1Qs?6K+#=u z>wPuU=oD=G$@?w!oQWgM)35_WahUn+6$+RVU>snF7uboWQ|h}yl~^h5YS%z2G&EN{ zEt|@MNbCNtNZCsrhy0Ap-~@$zgFJyD`6;vcl|1tua|UOjw_EGgHbV}WYM2a}zPt~! z^al3$?J~-gwt`AJT>?#7Ur>NjRF-?3#5p?C0Hbsy1xeSk>;l|a{(!}RAKp>Nbz73% zX{AP()4B(rUjfNQmjHFLnLxn4J5 z)9~W_+G|1^Ec$fTtXk1|pF8q9jP2G#&U=p}xR*N`h!~ix9@uhX+RX(c^971*Ev6_P z$O83BU%XrAWs-R}XrfJCCr8DGN+3duKR~l}A5R`oAoXb&dI(;vFp2T${sEDV8{ke1 z^u~b3)B=~3p}wv5XF8Kxb#;N4v^}U7<@U&nLlOAEoR+mmh|BMc6)ps#kei72x}RKn;3qB`6EIBUk8hDGSLeOr+)rt)AD? zw7hf+Rk^Xti?MIBDJABdT!jNyc0ev<=Z6pfG>TCdB%b(4dXY5I-Fz)$O+Y!_RI6c|B;#*rJQc;)gALop8fz zG~QaDNOrdXmDA}cTsGv{EeI??x)!u;}D!>)j zCi#UxEwWfI1}guUC8~@9jJuCh{5uZsQ?&l`k^kg;Uq32F*|<7r{l(1^0wZ~S=|xfjpvF6bJhKxVsKQS1ZvxuV~7mzwHDow_&IX?@yU zvXnyvdhH01C`ILvDS8yf8cwZe$31vmp_9O?MeDp!Hed$bZIf!e&ibyYXSoncaEu$FDcnVuCn;)8?e_P8q=2`0W-&8HEy}2^28?>vm zSyIn_h+{8*J$LfH)?FVx&`+Ejs9G++T3WuWEMKa`2CBr@x<;Qc+k|tQ|3UQrTy9RF z9u*=# zFIpW0PT!Kws}}SESRFi*zgU`IF9AgUG%U@_uRYIOmI&m40hQ~MVER(8&@c506fd2* z!VgMet;F*_xAAl%0k^ks*XJwm>+KT2E{ioAYuNED7(L|jwC7`&wfhiHX9cze*ggM4w(D=<(}DX#0VB7E|GUJ?rL zG0m{2FVhMqs{4QlOakUd$ltnN`^~-L?ZAu6h%EP`&r})Vx;O3+)xmbXPS4=H?+3H@ zELlY%HbE2Tkm$WyD3?%0v&RWh(xK27_fn<~a&*JJgag7|YVUxpQXL9c_p76=Bpw$W zA!h-|`9<%@)2Eq7l)zmJhvv64Fx<2+g6TJ=z)vS`Kw`fim;s*lJTTL|NY}1`_dtfC zf>&gao&o3m*;9e3sqn@|l_=d)_-wETXa6cM&lU@{D)?t;S>gO25TEU*Y3GeH51Yx8 zi+vS8+1Rfx&qwGQ*l&AZAR8Fht`FGjK5W4nlU*-y_s%~1t^h`uizJx08-OV;=UGu7 z$;@v<3BAYL_*X}|H;lsm=%lSXEq4UJo)7R^VM{^nC9(#2U?~?Tuu%-2N|MJAl*(IB z{7Je@1l+xb&$5;)Lvj@HV7b<(9@b5FmtDp#UPSxmrqt0Rq9dBwv9#i zIdy|NTpFYYxjvDm5PqJ{a5|GrOx|^@$hASAO$>)^pn;}_+s(L^FOZUit(9m=4g>_& zj`vV(K?N7pVn>&!NLwNIeWb20_gO7!kODP-bQiqTipG-zD%_te1?r#w`A1m(u&#d` z?*F#F^WC#n-F()n@TqAjkvrm-3>|*8lm8qCs!Gp65qwlWCq-|%Km0|+1tPEi%0T$2 zPx*K8;mbOk0OM>4=!NHE$Y3$-bZ;knz}!GxD&YzX#Vf1eZyJFg9!r19<6|M0=sRJ< zQ!|Kw7~xg8!jdd1`g`m?-Hr4XkX`5BDKh?M3Cd&*rJ$6?+WKQh*A}jbQnXCse^A@}92HH;a z4%(G>Gr#Xr4t4Hlib?gIFI2=S-ETWGPuhj;Plv(wBNn3CSP}yTeKjv1Yt-`|U}9J^ zNDAJOrKPI3ZwL290hkOg=Y9wnyp}irrv`K3u@=K9Rx4H z`8nnwGGUcll6PqLFm&Qr9+~oovTUU~+NWI)gdOH_*Q#L0TXkTM6Uc3f$0di(_!6S_ zLi4)4nbm%@_cCgjWqAp!xF>CKZ;!6g>j;&YQ!{y%OWq+W^+GdE&?;DQB{f$yvV8UHJ_N26VvxfG?y?t;>ecq9YXw*Kotukp&8uh$|!UaY@uurbZ7|$no zwm@h*q*U`Itbu{ZtxwA%a##U~TOemp7Q-E%f%owxntli8KOKv^-)v`KYGA?*vDSBh zR;O0Cs6f_1YLm7x#0z6P+XNqCXcU~?{;1u~Q9n*08?#Fg0Sg1OMzuVi0q6peJEFz% z9br|dz>wA1bI7a2)d)do+#2-4X}N+ub$@ldI3y2ood6^S)ZJq?CuhZV*BY)YhRHDP zysffs<_E7KDDBwrn*zF2!H#mY2vM?dVxrsuB?!~VyGvP7?0_6WCM;*MgDvT(<@2%h z?sY6|9!sNQ4A`Yz987u-_;>0U+yy8}uN7_k0MYcc#5n1e1S@h0J}d}c)0FKcu&F6) z4iU1Sf!eKtl);Sii)&Vw>q5xI3$PWjA;&am_&56zkbMqURfk}chpI0ui$`e8>y-wm zaVZv0{W1xiC0!$`g&knoy&ZkVB*b0X;Na4OPomzJ2H&B>6-+s0SMKlNWMUi0l0Qnl z;icKB;|Nvvut``SNrFFb4v!S+6Rod%yr)o#(PnxH0@L>7Lkw$J5YyR%#mSqshmP$a zP3pWW28@sBXUHjWjpRQa`@WS4Mw0ho{g*=F??V9ohhz-N9DD148(YYA`PIj2(0?!l zp0Id)PBGupkYJ3-zxfc}O92}G!Y6JICX~**;{R>)hW3{yUUUDM`u4Fwzqhqu>wu`N zr)dGeC~E$)C;s@@Z=cQQOckCCcoNk4fBkHJC>M~gN4X!%h4Cne5vdYNJoWc{3V+~m@?B)RRVYg%NYC3)=6<`pk2lh!+P<*-OIuzK$uhGlCR|z_q6l|| zys{mnTTHWaXqGO&-yYq`KyCgOUfU2(M~7-+Jkza4md`}OWtpkQ)Kf)F_63Yvw74;u zsPNV|M)<3cam*kqcVHf@k09rF9A=H9sZ~xKS1r)M77k-!+@XSyAJaBv z=Yp+AktWC4iumEm>?G9FMbV@iMAz<>N}LT>aCh+xiJ5cOVK_U8i#Bu)E;!rna4--& zuuM-RbkU6_FGt?!48e?2mG2sQ1>CxwBvyrw_+bu1fy+uCr6^E&n5%p9@Q~6IB%Xlj zzgVvn0p`W=#^r-8i=Z*Bb;h3I0<&yLU4=BVS%-c=Syyr@dluT zo!X|)l28l1ajVX<2(kkXf0z(ENI!B%-a6unZq=n=S6JfAv3 zGxGC|m9<;lkRwxH@sXUi{Tc`=GDL=Pj59u%M%dSv99#k9;()9!XE1W$>r5Ivf@h0W zDx%TM3wlHrom%=2 zX6*6lus(tjvI)5k1QbxlF1E%co&kDHo;hv{=7%P)Xeoc(N*rr8Pg9SZDXf@093Ww& z1MecNknCJNhZ~SY^WnT0!z{Dxt%X}HaIZ3G^f>I*JwmVyPAf-M5Qy`sUILfg6Ei+< zi9laoLNKE|jK>iHQXG3DAU)Q~K`juIz0H9kr?z(&Fep!tt+vJTPOjV|1e#`oD{kZY zYz8MipxVbGZrH^hT#Q5s88=;roJXIZj(b&_c~euR)=g2Sb1=#6gYb0GyJ6%}dNWjx z%q=vfx^UEzRG5WWg;)BnK04Y7-TNLQ?qSr7uu`$hKdoK6+K7AL_>K^Th8I*+e@JVPh`cUD0i%&b~(r7uh>Z zE%>jn*a1fH#FGB@L6Zse%eKv$dTjUETr+2CJvUXdWY*oE$^{|3n{@~2j-QGFkP`fF z0ABxT=Yfr$GxEat0C}B+{e-&^8Q_v`^w7u zQ%9M47ttag9p%1`ZSX@|k%*VIqh{gm##qxTBJU>&P=ROI?;j<1(rc7lF0M8@7u?XT zVACA-Bz5-o+uKh&hA>YB+tlx@{Z*#GS=rhYwqqV2y#*tJNA+ zq(UPdw3;B1)$NBCZLl7~D@q#R*C2d8QS==H9ToetG2u0G`<08~M{&YIg`4H-+sT4C zss(`U`?g*JMN(ORgJJ;0(FgGv=+!=iv3xZ|(;T$3ek2_Tt1w*D*d~wNg;Q68DBiU@ zCYIF-6cPA_36Gx4EHd56^mM&P%!a7>)`D!s)eZo+36)u+x!cZYtd${fHQly!ow){( zPGlCLkQ3e(JoAF1nh!KXA6;$jr%YJH3x-z_^{mW^Rh|oMyC0#ph5pxS3EY+f0$hTv zYfJfNf8RsOyO=l=pydlcpUN^-jSU<{T^f?^R=Xh+ASz9C5k9|_7Nh zYZgMsV1XPyspTh?+uHWT+S_oHNoJv`WK(;;Tp*v_oNxHf&kT$2B&3jt=3D~o3LOpu z^s2Bx-WBEr+2>$}6}_BX-$zcooY{~m2Fnj%&D{%Ra4vynm~sTPYd`R~{a#Qi&`ZJM z=){3=y9F!YaJ}QvUp-z(Fq8xyhwnW@-SW-#e2SlGpOOGMKVtTMv$*_tmh|a!{o`MW zIG-}GSFae*iSJ&9cNy61K!`5)MF#f$d-8!w|J_@H{G0dWZ*K|mZ{Cx?y(I|$m-pmf znAIBOeguLAUs|OSX7hS^J6{x;<1C0Q8awyMH)rg2H|%V+pqg3mG->J-LHG7y~J1*sdt>;ZtK~Q3QFzlE?8~ron<$N zdYw!gV_VVMExD0IJ*j~&3@2pVGZkVGCNuXb-+ku&ebMiNuIzia+V+fHj$qq5ggrI_G4TQT zR$+q&5{wIfB1s^x!34~SL$IkDTMfd1=3xUiZ1%k7`}}gx$b&}Bz_cp5BUjxP(T*5Bd=Ev?J)e+cYLHVSVP#0u8`sa;rI(}bD{%Vf+WM@CjE$JrV@*cKs zSH%$?0#S{61l;a+>w0S~N+I+n@h!+@mWu}%$HFt5iFPECj_o?Q_nf*_Zh~ayYRuNo z#9X1Jk1B()J^Api_c;fTg|WY8Fw$8ZM9*~A<8|er1##NMpjiQ4i7g`Yb|#g@amg%s zG^)5dwjxHJ*{&Mt03c1iX7m|-1U`)ID(+v*zjjzBugTn7Ud8Gk&`v`A{<$Ii28#O} z;H`f%!22kt|NP&-?j_h$f3@wt729g9m&ujfz?4R^Q*{=a?XRtD05$wo9?~~m1N8B7 z=*t!Pt55f_)PEVYfra>bhPt|X@2q{4yc!hS`U)b9YQ?+{+FM7bjVgIg=dL|80&gD_-4LwChy?Os5XSW$gq0|k1-i^vq0Msh_~nOyVD1e%Jp)A% zcZ#ucrZ0QT-?BO0rj+1cdS(hfhm_B*BwA+e4CGCCio&g(PnYJW#H>Gf*T7mjtXKD_s5M$>t-Ox z08A16qdTu?8C$N}z`#8-ufYMb5e5=y7P|)+ObXvwM<;>S&{G$lsI`g#K)75WR9$07 zZ5t?yJ)aXd4XtEfXt_Ue=g(D?&m6_0x_neN?d+aSP-Ea_(4VKjYX!mBMq@H;b-semwG_&Yo7XP;J~;N-ED{~ndz&-`-81J@>8*YU0OW?{Om$uK(;?W`D0ei z#t<_I(ts4$G{W6&QfFNcJCt%;T@siPaA(9IgInVp&Gebcue=$qOoWnAHL!a~gnIq$=+%Rt3FptE#Xx_z((2%tekGx8d?)N|LhCt@ai#Tz;NT*@M@3gT0XA{czkj zT;SffXZ7)?{*w{x%o7NqpJ?9iC4Tu^9N^V{*JwSZEl>G1P&8pA#XUC% z2w~?&jen`HAqYfzy0O=g*oQyW*PviIDAXH;{$sCrdZ<5#W<37wH#|jP@C#trO+yst z8&&uRX{7lUgl2zix-ahv@;fQ^PfF~42U>!&Jx7-%FKrn>2v|g!*k^g9iPQ3WVonzX z5W4`>Dp11FdMBS`3=jq9r7#mTr=Rp8@Op;m7AffegiV#DLOCwU{=TVToh5P&tAy5o ziHs6ZDA^+H*#}CNFVuc5kr7C_mria_#+kvFX?OEjhFj=*A6u8>LAu1k)r*$WEV=jL zyn}Q9XdH|5up2WBINc&5@Gd1c=4qwS{fgYgL&cr%!bvwUV<+}ri5AE3`WTm$D5P7~ zwOp}URR^(Tfes#ad)&W!z&Y#=I||}$Fg#npP<0CX zRSqgU2-BOX3bOQK2qI09Z%eK^dBE6yzkjedzrkCWo`vf$g#CS(-V;0dw1Oe~`&Ig> zImNQAiPg6=TN!@d;nhRUg}uAA%yzZ8t{&K$^a;++!vX9bs5}4x!lHGfLjY3>nR342 zuXU7VAf?b7PSFw&7UcnlyzORt$QP?i)n5X|Cy%HE3nlY7fx_qzHgXq(*JT8ZvgmgQ zF+vJ&+)4JSUh_%P;eJ(Do9YfRiU8n(=p?pZoXaDCFyu7U%5v&uHPyHBK_yJtx>S@? zi1jtI(re@h(G@8biw^+xcb$#~16}-$yE#NCH;`Hc7`>tGXmP=|Pfc}A71a$i42b!(_= z<8~0QL<7EVbZOZ+zIrX-}eoI&V>A>;VRknYvvfn!PP(LS?2J_*2u9Eaog8tg0 z`ej3k-v8IDEa0Lq9~wf4Gs_(?T0^-nBC!1@uWXKYTi|x}_?F83RHy%K-T&P)`glUf)2R5jLicN(s~TIU7Dn4WUB|T!mXd>d z1PH@TU!)`Au!)?Uj#VF4p`I)9il6awm#%c<&TMA>hELgSDqB!n-&awLZj>s80YccP zyU3r+7InFYMG9*gk569n(F4}Cf3Ca8f1n22y!^J%2W6bISde8dKSJ$B0Qr@ z{rA9`H_`YTW$S>eBHTvr@!yb-ZM^4Wr@jq2*-yu;%fJDOR<~L$?@u-h`5))3;x5_xf|eIe z#8U0rpLQq4H40(ywg3}g>2S6l7q5a`%z2K0LhF}c!>lv`#3L0rcljN;J`#OakqYEe zVFiodss%8DnwC+MwYJz>Bn!&DzmqkL05?E?f_odb%bC((0z4cmDZLwJf74 z8ms*;Bar^K3UlJqku#h>Yh4qN1<75`395lTfWWED%RxH%Q+E(N$#neVSU|_5FOFyU zb{0G{EFeWgip?_*XRKQe5fZtda;Nuk6-SSXXf65X3Z48b%ejD}ex)xy2e0}GBUKaA zk1t6#_nDM2$}^RJEZ<_L9!-nnOmOS`YTgPF6Hqi1IR>#2Z$R3Vg9yG4WZWB&7SfVn z*!ukc`@mHa=&zd$Ea~DY)o|hRxwUC>6$fO+a9_9DaEV{y3%sSr5VJwo6E8bNXz+BMMWKLAl} za0|~y2+mC*uksFrG0u?k)vCT!=rU+eVX@Od4Y@o^%+3?;$1|}iHK`|BEs^iN(D62# zXk2=HTnw27dGV&95PUDp590z3L9`TM1_AHIp;8}>rjfSAocOEdnku(zQ+Flcka>aK zw|n}`1H@1j*UtUQ)fi_2IlA0K{AGP;3i8wYBWRG0clf>me>$AC^I-&|j=IsQhsjiu zw}!~~>I~sN-}Oa6?4*E1`TNrRn*fTIUnRW0<6a{Hb`u}>)aI7nKCL~^oSs*L{F%%U zZ>ip1Ul=6&cF&PNeN?^<{o&fl`_%#W6|w>&fn$|~#livRufJ|rNhe+;2l(S6pbDXU zSjdn5d~ZY2ju_s!My1V$d_%GuC0l9wAwF$(mC&=;W$p%px#trdD7 zkEUYNUZx`G&gX;f=ot4EU}eK}Ot^dhbe!m0F+8jt$4nXx&KTFzhjRAUL=H7@$^R@`ddsYwANEtOux3)-)neq_P!YsNeBH*{l~gh9azlr9{-s7B=6GD)V+5qS4*J=3(}?pm5!eBa&+8 zs7>Vfn3KUAmx~zebVbgegv6CsfqlE^rO(B?mU+nRMUPIZEXAAhc+{9dkmG#g_tC~; z55!O%O~iGjbk2kkLT7Dp_H-a15UFrXcs{STrWm)x-P{6T z>3lAU>j*IJrEu2ii;4I(wdjQkp#8T+>T5M9gld@W(AI3=&7tJ!xaJz}f}d=>OF+~I z$?ru9Wy?A^=#eMs__1}AWDh`|(nl62FmB=mo9~D%MH`~LqKJpH?wToB7CeNNh5&gO zYx`zMyS;aIVI~bhdB)bAnd1R-n0w7BQU~odsPSO{Du9T@ha&&;3gg|u$1*2gt3Gs0`q$y=D8MdHYw%q2+uvniE z;_#3TN9bbG$xuMwlI@0|lhVZvr+f&vNC|dN^&9G-?^0HQNWkm7r_9m6g{QH)sOu0E z08DFm4@)H%h#*+a6v>cam5GaTe6m7kS-6LEA zYjUXjC*Q<3_uEw?Poi20WA5&GImkyAnSx}e7C}>84IEddHSBjd46(zda;(u^mpKqJ zX1h!b@7VOG;{F^0S@OM?@;=^u)A{^2%lg~u{zT4)Ap=UU>{v|<8z z{?$r^vnb2pZx?=as0|wOkYunSLmp~D_QB6#4_|Nh59g;3D?bcqo=m41f^wgO))Xiu z>61_bBjM*`z`_69OMJdUXbt_}yu{}#MBr@jU%$kEvr}~5)*!`cxUA;dp>Af0VDueWf)MB#* zfhVm}(H_J{XimD-LaQa)%q))D0bd~rranWc%>@flPn2M`wr&7sh55iXR3=g$qf#Gs|yW(NM;VUP0(6B+cWyE>_(9z4;&Tkx zgvC<3?o(2gysfah5LPPu@2WPlhH}}2PXTGz9*R*8msI-EyqszU#vQwb+#~nLJrhlq8{!q5We?}I}~ruc`s7e!YlzWZ!se9)eOI`Pva@h7q3-#+e; zg##b=;a4tZ zj(>a%Z@Zf!ufqC3suE;by~G?mU~Zw^?pJMp)^< zcBfrF z1?6hMwO5E(u9n^XWL%K5SoRY4U?4a>>Cqu#(Sq~C)yQ@RA<##~P9eVRdJnC0v-S#l znXo4)Jdb)Kul7zTXQIyw^!5f*QesA~o~ALjZ5+Kbxfr6lKJ&J~OqF}R?E%rjE2EwV z6bJx z^H_Mv(M0D-7mkWGUrH={_s+g?_uiwrv{!N#Ywr=#TJ}dWWVHQMgVy~LI8$I>kHzm= z6K}2LA3787*u7sV+U_^BY*2s_T>K+_Z342e4lWVWPT-Wp} zyzci)7nq5oiJcnAV}f&cM8*r+8O!pF6ykJGqm6KcB$BM-x9f4$00#)Si+A-Yl^gj+-KV-tq+<)PLhMhC0!=bZ?w_+{g!^#%kX^i51p);yhQBSE ze_b+n&yRLne0F+ICO(Y|y%xdf8%3hA=gkOYMZZ`^ftCBCr2ENcfV{!imiA;a(|91m zvUs>&vM=*N$oa@XZ6-nxH{k9AhWe(|HX$L2q2A|!qjEK|+_X7hU=<`RPWtU*DTP0S zTuprr%|87`(C3Xlu7|J#^J=v@V3xm0JKoOp$-X!b_2FUz|5LD~eO-wQ=10R;E#066Z)JB^;Z21nanC=4PH<^w3UEv0kFNMgeq4Wnzn2?J zdyV{@g%ZGl85Zw(b18#?I-ShIl8R=Txwn$0ymqeI zXgQE8wci_u_L|>1N=WXcuHsORWbTS+soQwnlOWR`>!|lwBv@kr!s|0unr}}I375`A0X&}zp|Kt2Z1zzEVoBvF++?!9A`5_ICbAF{ z+)iwm8wh%0FUJfG05CDX+?IPtq}NVBnvf38iPq&qSwU+wLW!lR40aBOy5UygElJQT z9XZ?uZy;|F__90;n{jA#$70Af?hFTZ%6BIx&JE`LXC>Zq-1kd9QZuM%ow~b5EMWwF zD%zWXN}gQZDo{>Sj=Ue>7lFD%9WD6pbB_2Y0Ug)f76asM*2nc=X`p#j?gNc=(O_fqBYOb1JDoAuSwYO}O%Qn?6^No_r|Gto(ADWG!h+j-bYn%?GHQF=WFh3sB0YV# zxHHpoInqTCD7H94$O5|=tmQmo{(7otfDo-joj}k&#vMLmI1rNb$5w3^Act++SP`pI z!Dqe*M1bAphQH{PN9E@i@c?kOO>L%g8k<5yZM^MpB&vkJxCmqkpQx>u-1b_bLgtkg zi#LJm&$^Jz$0#=g$(Z$uhdCj$is9)Ip>iVHE?G~>5vY*~pAr-?PPuyL9ORyjM$l0D zeYq{*O-j!|^Rspq8aSxn8o6U_&wjT=ql;oWTNUexYbq}eTL@mm{#XYqiC^EF(Elg= zA7cjo-u(j+{rjc-Z;QD207)HPeF~R#N|}iDmW0%cn!LATQRzd&ju7<#YRVtPlmloo zKBdBM)g^CzL8kg3kCAa$kcKPBgdzLjtMy!k`gZbGAfuaTB@j*kaE3eaz2ghBzcz>L z*v%974DDW6bKh3?=K&EG>#KRrq47n6HdKkBoo4;$A6-?dxr|?P=tkzmpPsBEK!@oI9KRUL58|^_6&9)Q8+VKU@ z4HPZTYR3%*4{~DT#4_U5BBJ(~shqVzYgA&qqnN0;wCp-V6VW?Xp9scQ5qxeyMoT{7c+}O?F9s|Y#%M&xAaQ`pWp9tK&V>%t0I9d`l-7J ze%C&R?c0Yl;M3z7)9?j!a2X0rDsjvw5U~3$_7?5}_4J)QwW9p#c`juD;sWuKJPngb z{x*IpM4s?h^fuPWs2K5R? zA@IPG(m2YC>Gku1&552U@kBw&N<%>&4*YjRX&L1YY()VC`t|kOb@TK3x9c3r8|V_D z1dh5=?2UrAo;cBWO4v~lo)^iZuPqo|!u9Y{Axs|17@>K8s>Aa)<@$kn%rrG5KoU}u8YJo(?CStR)Cd6* zh*`WLj9`*gd_vJN<8xe93RgTWtXYaLs>-l$Sgb9KWlc$lwNqPorS8u!gd~NM0DOdJ25C7mg3{(5~yVn`Lha`(O0$f18O=|5csD@8@LFYDRC62~u#Uj;etW`ylm&)Z=k z>@C#Z|L}E?^iSHyeIU<8@%hcKRW+Yv4aBw|n~B8Ady})5ub{tANPuGoUU2uZw+a~4 zar228asUr!2+$aRkyZq5XOV}bQm{4{ENnjOG4*d0%U3s$7LxGnzI^1|@-$OWd&^LJ zzejK}RQq)s``occ;KP4R7hvc5wqJ~+^7)c`6^5Ugg}B9+Zvb%2*A2x4Eh=m%#=C+0 zDSQ<5#(^IM1)@m(r(FvKeLT=9;pISrXd3EZs^j5`NK(_YT~G`~kZQ!P?kuh!n7cL1 z_{9s$6GJ_I=xT|M#TuaMeL<*ydQ=YjeQ#SBI7h$y#32T66+o}(E&ThfS43lPyBZkq zU|V}0Dd6z(es+Plhw7K_AME(AOXd0fX~vSXR5W*(VDJDy#QCs71bWmUz~?)!$+V>o zCnLx*rJu~TW$vsKS*m*#*I@1Vxp;XS;V80&G<;CFCUNux5)vHLofCn&I6d`2epW}T zPp@F|G%8~xs!qNL=WEF7&2}laIDlc%^BssDF$4v_BR>BYsM< zBl2*99^D+f=Ik6)<)GOM#VLV)TpuFdJd2C{VHd5nM8s()uWc~O6T79X$+9vN_6V6_ zF~L&91`VrBrx0^n8jV?9rGYx7F{AYWMVv-0RaSsRAErR0?LStsF9}-Ogr9}$-|AH6 zS*McU>eK_N5%GEiVwGJiKfIJ5$|nk}lpuQl;o}jQ&^ZT8^t+mtAuBcn0d3;$S0ThM zeG7z=!6^DpID)v7FYVR`NPbZ`0*>I5dnT7Wi68#g8%O0!zxAnmcqL7}#tzSq1N0kg z;{u-4O@te5Jb(LOljA5N?@AmfWd9S_1|xWoW;UdlOraorfQ@Zx z9;qH{>VXVald#C3pSp6^iO@z$%Fkd)g)#m8n68es!!}^G?WgV`8g5>w?dBmm_7sgX zb?zPTcp#Vb>eF!k_cqfVXNw}!LCSj#x6O7E*JJ(IFZBmrtylMKT6^{(n$vY&tS}wL zfmt{uEc*ykSKOvR?bN z0@~DZP)~)VsWO1T7oOG|d|FUOeLN!~c&*0^+Cr?r)+M9!XVn*tuzA7;^2MI~O<4Q= zGQ{8Tg>Kb4GSEhFPlbm)INZLvY;cN&yw~^XIky_!HEDl*^UvSQXX;UhLEPI#{O-L3 zhFAG^75}FfahjIoa+u*tTpkcp1E=-d9RCOM2g}ng&6`lSF5n#ld&g6YMnb9fa}V!H zAcrp_nGWEVM!@vzGP__r2r8hZzdTl`a&l`b9c}Kt`g}BWOer_aW@q05;-MxF;LTJDnE* zOr%|xUS4mj$h$49K>AzMbaESd(7^p;B~?;h>W@~yKfeR4BkOcf&%^qh-u=TK5z%1UsF%Q?)hDC@}xYu4vpHN z?W&#=u+JG3tiDn6vV0V<6u-4};nW}g=1xCrg(vmt$;Eh&<$GG2pL~q3v3#3%@h;q0 z{QYJ8<^exn1@eB%|5q>L`MrO76(G6aKh4zC^JVQ;Z}~$x$qw!Pz)=9mj-duO;cm zI$p^~Ag625s(hu}9X*>2C5Fh@;A>9+(rf$XV^ zcC)Y{8s3+C!{%(5n*@VHg!q{!^YpR~kBFIUEXv;nmf|H4${DTdORQh-92%arkX*PM zmCI@&$Q}o7hdz6BEvIJ-{zTuxq1pp~h?mjr?pWw_PIK=vaM*b4AGZ_eCtgx6Pr<^!3t^DN1yT&aL(2m)^>GJW&dmW#oUl_6sjt_{Vx^{S<_mD$Cu!CKjT z+|&!H721t%QRM)z5B0Kc#2wNF#1i;jWxaA&KwKPWs|;#Js1o}U$R!30n+3z_JT$^ z0c;Z=3*oN~6Z8XOv4yPSiP3k&r0=sX~ADtR7e+v74>sSCQ;<;Kgfr5uaf=C zbej-Gf6&;9nm7KbRsR3mH0PhM@3a{fiZksg=d*o{HrXOw-gFdk7F)GO~dL8OF|` zYc_m7P^%&YEJ9D*mTIEi_@Un6dzO^;^}*0P9ISkTp19fy$3i041{e#sR?*?*IYOP) zW+~}w=ogl|3_sqaTcJewF$1JjsT5QO>5 z<>)u2gYPs+CPoXrlJqb#V;?*;X_9$6+%gjg6EnH|=sKwkiNSSdrt*~>vwZVi6H(4L zu%hFbS|W@ADnh$rTTb#Q?^nmc zH^Tzu662+~aE6LhkY2D58;Ii)>^vmeFHuYxa3b!Z4E|2X=$WRf{hkU@O3oOkEZGW+hyqVqEPP^LbSE9 z7Y`sD!{XJn^lHma_crdUM6>5LSeNHib$csP3yJMfX+E-|^Q<-5PTu3^2T{v2!FkzCfZSauTMWc3jd*A^Ka`c*FXCMn{TXAF3$IXeTq9G zhfRSfso}V5erZYuf6td{_Gvq_otb@Ap0DyQ9YY<19Jd+-2N?Ta%|5eSUeTxU8F=e@ zeNjlsqU-493XZ2AUBF+NjDPYNgJTUWXX6VKQJmiN1Yd50%Jl?P=k@n(jmq$zJ<0c$ z&^k;j{8KqPilV^0RTw0*8`J^RwsnN6#>H`Tu<; z)!MW*;(|vxqoBbK8w7l{wQB6NdhF~SrmP+#n}x;snsFoq#sm>RJ)o6u_3d(5FQn79%w_Xg#&TKjAM>e z)*Nm@cTXRw5&}-?VddScr3Dz!1ae$#+7&S0Wry@G;~o=SEE(L@{<#9ca1Oc&%veMTMxaj44jWyk zhq6?OD>PUXh;4?RgHm`1igh=2E{fyc^q8)UU_m^b=lHttPU{)926q*nE|9%b+8Tvc z!FKBv3OEST5x zI)iLl4wReYNssx8GASqan+?fBnli+{o|1*RyxFdRE)dpIC;fiPBdT!cvASr@zTd-m z&%a`ozwZz2w99pv;YFMJs14_hwxYI4L|0@WnT@p)xzN^06Px8Gydag1fhe>iDBv}* zAi64ckjwP2L!jeV!XbkpKfpE@xkJ^LV-FmpQ|)1DztH>)Wb)(XG8>(lPU~!XJeJ7) zzRyDG)bPZx24J2VEWC2`x44K!c@t1jnC7jL-;S_XZklA4bI>9k{3>=kAFQ+cAu-Ly zt_vn(JSeCxXu;%;f*Lij+e*BB98V7Okx8XoA+X|m3m>(H0y}7SH{Jw$BR4`auGGX! zfQ{wQD+ilC99h^=|IBJsb)O9$7Xh@zPxL#?_@Ji(7`SizIcQUoF;BTMY>_04$UuZI zO9Dby0gPgYHFNMbJf~4@2C+cD(xbj&;8>E5ROrJ4B(!x7w=+-O?iD7|Dtf@E6@v2D zK;bq$SW$vzd8~U=7YzP#ovyB$P}0TNS3W<)XlkR@lk$dQAYX@(**n;6SWr@-K0h2J<&kM zErql>P+<_MJR0Zlcxkc)9zZloOhkAQ!Xd-oFFJ%*>h0!M9k&&IWH82`bv($NMo(H>6|c8$|6wXG>+{*k}W!ETv0LtjH|meB_XYPpAAx4Vz=t`t=~)WZmeKCW!L(T&@NGyz<+ zozgOogNo;kRjUj_(X1G(fzVJky1T@tSzj=jqAx_z!_8vVHQEaJc$Kof2x~SN|2Q77 z{%eZy|C;vke@$!bzb1P9UlX;m$m2gYFge+Oj&Kuvnc9M@{jH!V!+(T)u9M*(Gkp90 zJ%A`5a5wNzBlN$fEqwpmpZkwL0QA;;zazT)_(T2Ak74WIpZETM|Jz>+9q!qpTYmad zD41LP+(UR4L*|d6!UhaLAdKZrVm$` zg+mv5RVA{AHiCf(%w>BKg0P@nSA{Uu1KQLTpzM9BL%7Kl>{pY-JtCJ)O^}GgI)Ofs ztB$P3dT)*n%SkdEdtbRZx-K!y9_DS%{N!gDP^$p0`vHxxO$!cx415m&X{yE(M9D^2 z+d_Wk15n%mkuxVqzRsQ+M-Z#GCt2OafNOX?knKpiZBOD%X3tjvRE%Ec%OQ(AJB2Re z19YHu=nh$ozohjFlx7eU*S0bo1I)MC5W}#XJ#Hp?k| zr!EO>HX!hSzwIfgIQ|e}=5T<^VaV6anj&MFS)D4sX)EOU+D#CX_^#837UYbwZ#)

WlUe-_t{Nzd&(G(Z)PWL*x)m8VrOh8;ZfKz~i4&-!)P@D^6aQJ_DAVz&m}9XJ!;o|P=? zj>R;r#P*y)nUD87g;z8ZK?gsq3Pb@$3n3;Qyi76l+97}#UmFu(f;DAHY)<|Tt~2=c zd~a>IzT#fpMJ74FlrBGX#zB7dp3C|JHz%)AX*toN+H2UkwJzJ7D&ylCNMY-3G6NdJ zK+QASYh;VXr@su??7lw1Z0KU|tN*MLFpU9=E zUL#48$W#Bg@1-t_7a8Mtj5}vuEM+JHYITDH<{^(}QMlNlyDR7pdQUwcs&gdOYq5p! zvK=bN{B;qg&XV1X5DeTcjNKZ7LKl7c*zAs*MUoh*fo#=l@+dO2sE=b6$k)wj*?KMb z^|}2y6Ixa^DpCNh`El8g{YAKEsumLmpswgDM;|Mj9PM@|*IK@~NJv)O0pwsqu%ebg zMkDjE{8)5hZ{nk=wiq8JAnyL0Q_?lxrzymrTqJ3ofO4i+$n>M3@fL7$dZQ)iYnB77 z@7>RZhrh&H@*-VtcW&9TMH3FkyZ|T4uSQ=#5b~j(dzl-4uN6G zA@-LhQTS&>$`RI%&5Un2YVZdPenL>Hxm_$-$YU?*`dO}(5`t{qQ6_Glp+8Rb=ofg> z$!Vls;j?lVL^TBghe1(6lWPme&p86{I8HzrBi?oh|P%iQ;j>o?7HsH;9K$_GlT!@STHnxkhIG|TdMow4R8aGCE z#O^^PvjUxq0EBpO2R3Z)#X?F%lRoFV+?+8=S;*B@U13%WxQ5`NW4A}E7mr~`#XnXC zG3@uI$SeOCs%rhp#PGNMlTn|0WBw_41}`6@Mr{^_Mn@Qx3*zo!aGIbDqi0AKrn2gk@icCI6XIVnDLYxB}w9_c#9O z(f{<|2n^PK^XSjA;Ll#HZ&s{$zIlX*9PFz)oNlWl1+mf_=CU#+m`-+93BiM%7-Tx% zrVf_b8H?@0N~fvw@?38&*REO#Q1*c&WqF5K*KKkZ1f)BItngv#ITjtRV%~M=wIJ1c zaf4xsiz|dgC3Na+a_Pv@;Fj7?W>21bYX=Ssk4XSf-fvFE$zRWwiy?h4=zxPfUT@}u zbim$;E&`A?4A?r&wi~c@UYJ=vD$J&(;jn36%mj_lZKHkMPAsEBXG~TuUS>n zZ%r#L_G=s{Fl6XHielAHvsN61`Y0T1bLrvNaqd?iIfidutlx+VKE0jLcYdet#y`-- zRa%CPyD}qfI*XCpmq&r#Q{6>r%3oc~&lV``QsiO<(=e&A+BPnEiYsSNp%O0H% z>TbUZ56Pi6+)*xzU>aHEuXDd5G0<&zTD_L#N^jnv%1^+iLlBwOjZu3 zBCZ(6iI-dPAk&xj&WIaD*{bvU)dp zMR!1#1|$ieh9JU^R(Osl{RB-$X(9C8%1zGobtA$3pU~{^kmJE(1&Rq*d`s^yK&!XK zYC!HF4rbQjZ5Q^7X-ghvNYh&-OcbbzImC;5Tqtpl z&H%;Rs>l+LP-eusqz(jCB&UqZMF9PWfy0mt5NB`O(JeOzgEM?@b!7h30;Ls2q+g5H zmqF5B*DB{ZJSwmchZSpDGD-fj-UnyUmnP=ZWdzHS`regz*~Y=fCwax;+}3zMdK6vRGyf!4jtEp>S@<#Ek4GUsAD~ z8b-xA%N}!l)2Hxu$sBx%U9o95ZBt>w=aL!?4J4&vHgN#jAMzP-gm8P3c>H_MJGl<$xg7iPmzxozu(U0j7=l`40_Od*whA)@`x(cbqf7TO zjf^^RZwH(B5YzocuOdNM4s9~XeS2Z9mc{q#so*S5o!R00J!&FV+6iROs>C*O)L&ar z-c+1yj{?r3?7AfrT`_R$43dWS2@X{4OVu1z^|(R!`y$yupfzr6Z`;Df_kn6yLrbq? z+4DID+;u8WJzPZj!5IR#gi;_ko=4jCfnH|l)0yR z5a@-*EvRmklYpEvYwI;cLh&jO@vMup6y3ZtOw^q`nD%FH;qP_&K-^T=eIAhf?LfA0 zlx7a>iTthv1e&1CJ~IQFclY2M$*{8mJ6Jj)+N!!*8^PJ6i=)5qa*&mhjp(VD9h9%` zF;zXTvJcoAFcR&iM(XL$KyR{bAzbKX#-~YWryRmIY?40thrisDuBpM&`(?HJZR_N( z%i!f%vRyuBJK!n*Rm+27epry6-u&-XNoLKBK#rB5Zaz` zK|%z1)sREC83K3n)g>jdBTB^r1;=&e&AnRwJ4fbcwq}dr>51J6#n$HWI?u6n7?_x@ z#Al#E1UD66%(65buIi544u?}#_}9hMUSp~=c{|Z@rU9GXxmq008?!`Lu?S4-(773x zj?QK{+qLH@H+5j0HfQ%{u-UAnVG__Iq0n07(NP(DwT1%kLF{U4j5`GxooLAU&bu&W zMsaa}xw|`K#c5ulgTmQ9A6+yt?}`$48_LOPVW~m_*ghUPbrTnmSMU0m06CONxhGkq z(C~W{;d;{7m0GtCc^4cR-S&<-EC=D)NAL7v&%j49&j#IPi&IlDH&DLr(CZBf!z-4Y ze7p-5jqlu$=5aYjn;ip8XYWX1yJ5GtkM_op&t)^@X}!E2icJX>3ZweQH)3l7v-IeD zf|6k)Zr|4$F36Ao234YV4OfL;E;sb)2WH0yvDJMV3XGLOapGtn4OM2x&r1jzSWn&O z^BVeW-W?fo3BiS4-5lqtCh)qFmes8tKf7M9rq@lSFE^E`7AkXvKlcfAY41QF7~qB$ ze)TK3o_;v^{`K7Z#NY}6t}-2D_hBcVS=JJDEr_s%$km4Ev4KCFg|3s*$G*0trl&1; zTrSc6k{)3DEgY3E+75<@JDR)7h1m!KCItHwSu*L&F8Bl|!Pc7v`qAs}@qyLq2$&Bd z=71M;ksPbqgQ8IMPBeR*>H{2k!Lzl8kc&IvPG=S@r`#P3Px)ohuo){qmaAnF^YPM^ zZWs88G78&yQw)Cm?Q*311s&WM`7u}w2hm&7s+~sYt=+lucVm@pSJ=?MNdS0c(4y|XCDGnvThzH8c&g6t$)*HG%sHCPJ zPZ9zK&dactjy!p;2Xt6%O)@wWVw5}j9}m9&HXivI<@O)8u>ZRLE}yosTli6i>RdPh zEWdsLw++&s6S(eD4T6<^XhZkh6ZlLFAeagL)X&zlo;64FG*yFe^P_EQkUj4=P0IfR5tx zWBmFQ|EmP%a#Wr=b7+o3rG7y^qUcnb`Wnalifev0CV_A88D|R5^rtjaz!R)K%6&w# zzrBGFKL->A;Nmw==*&lB{C%s*zeD0a-(x|34j#UA4?aSFzeBlvwhxp!_v(W$fG|^q z_hfOqOW7LYHQDY&T?)u#T>MfHSj2*Jc_Y_Zr{EORBV-M>0HE0SCrGK?ppYw8;~T#2XPp$YUnwA18m8nOK`P zn-SGIXIO_*JxsEuEh-NnC+R{DL zQ}2^{WmV4NoGg|VTO`ATpJH*vc~D8!ONl0KodJE|!3P78lSUl5f}{$n*(DPRwEyD` zIaMyS0g{DQmO!h;{DZDw2cXUj%I&aifWzC#ghsUTk>!>Y%xDYfaqLt3bcTI3yQvjw z$Dbq@M1~srZ|#H6?g4xM0E+NLqw+8VeH%N|!wkw25I1M}ZKq`boz#2JbmctOo>H^cuG}9A)T_6I=lqIs z_hnIk+ME!_k*D7!8NUY^|0bh3{wbsRHOl(is&-&Va4eob;h7x_RKnvSM$$&Vt69@Vgi2FiHbO^a*3 zL3YbtoLa#E9f|Y1FnUrKz{K}ULF#uNPoy4FkjyYm2%bt_h3wdVdt|iKSV#RxKfUK~ zFCErJnF#@50xFG(RPgnhI|=UgT+_X}-}^9!nr#K)*X7O;1NBj4j+e9S+YN-%`@@5pdZe_9`YEP8&K;r?&ehtK8VeK3!}S^#j6=Tzo-4ZTkI z^Xr8FRAPQhdb#~-efV*C0E))9==m=YCV=Yw9H#M{NXJdk!q^Cm;UH?Lt2u<}_Q$&N zoHt2d7ZxZ8f4Q*yn|0-7T>3W)3#==@9Cv@6cE4g|==At91oqvok+ge+araXq^ik8C z>NM^bcj0l{ZT+S$%pzpCNo62&NmHhvsX>Y67Oj7G3Jg{%`ybkaA@x+puvWh+Vs8=P8EPyW*t|SoN zFSgP)x5J2;__ydUHwHw4%VZ?%sDGz zhT_W}leH7%=plEo&AQ774-a#EFdQ*I3hnir`;E$g`V$hUK?@jcLPZT4X)JB9(!5ik z-p1W8kI_eW6#=vb^KaMC&V5`f9t3Yd*j^OtBlxuoa+zRm1g=o<$$yPZl-? z3MqgnpoY5m@VQ`2U7LJzqtAB4?eNoPPx#K7DWVCs-wQbc%_~@8rfp({5b_xjA8pYmioP0i?7Xi12})COY=i57Zct>4{EV(UIIVhuxg;tr0F z!1Yh^vE3Q51#Cyki)$q5mOh1wy?;M})wJB)`CU9h`V7ng?vQTZ2c(hYOmLG=2FceV z5YBff8E$)jOa8Z=`u|u8{@i^1+s;9E&z+?!dri$v|T1`~z1O z0LWiY{NIYh|Fsi8{`JKFte)UFy#8-F@jnmzFHcqIKG)n2Xx>jJ{>P{P|CyZ&X3{Sw zekf@nM;B;v&jUa5-*w`D9{52U21x^t|NRsH^T3aMwpaes6MsQrAcNtl2h8T=^&SQa zJd7)D!15t;5(8&AN)G>G&HtRD|MnP6IcLQ=8P2({`s<1b&m#p@FNokB&ymRs zppf2PI~+8?&=iw0uhTMbLU37hp-)@sc5lO6EJk4?SjM$@nB_?O%c1w?B9cnpy6QxY zG^cSAq+{AnpukB4K>;+9T7~zzG5Y=e#;h65qPa!Z$cG55y6({5460Uh>K4zieqK^T z(jP>pm+1{dnl`*r{x|(M->)BkTRYg>b8x){UK0SM z;7qLRRL2J3q+lN`1B1+x%{or_X^QjKF}#1t4*AwGoJr^Hya&vgDgeD-Wj*0=5>352 zVPD*kP+bMk1vs>j2-HM5^$|R+!pGgf0S4a57PuTg_?a{8weX31e&C>@`tlFoY?e|E z3Qjh-LttO_5fYWuPKk)1T7~h=J*p=#ntz`CpiJC z9N)eyJntHze_4s{f2>3iII4Ow^)CO+WYvMp`p|hr)_uFz;9h(1 z_vWP~{V?|b(vSqGooBDt*!)V3`L#TKe*L35oiG-r>MW%wLyk^vv_!#wM9T$&*0frl z61^6c?WRftRh+r~%_*}8>Yei)-~~+x!7t<>r$fB;gwW$5#;V-)r7kpTsxC_OIMD(O zuy_rT^Fx;QE=)GI@|oMYBFC{SkJ21Ka0;p>C&|XgNP_NHt~JtgQ)h9Pj3mr5*f~+z zd3~34zF7#8L}1ANe1i0HaL!=IgEvwVz5~?`z$N4oCVLHcgZ7qmvVCzCcjj^9>GSfo z(fOe)IFK??vXS`K;6bdGa@dKWC6b}935L+2n*^_|!%db3S1Ta);w`-kBQZ8tLoS{0 zCNfc>S>0jpkn$O$`Kx_%mN6_;Q^qqJ_YoV&ph4z&H@M-2tcs8Fbj?3tBzFJpTjBQ!Wh2$Rb$EGI6j z)pX@M5mS+Hr)eqQ*(R0t$yDBeyW@Tdy9F`%=`J;|>kiIXu!_`AKi?jUL8APOP6+^E z^D)#zm{%@}iGk3yHQD5BPm(jOjMo(Ln8C;wgymgP_nS3QvOAN!6vKSD4R*;NS-Gx)=+<;&g+M8I517SG#r2*gL(Bt zDe)GJ^!IX4gxT32tO?PU(6i>^jtAG!AnO;bHN6&`X&r?vs7V;n)BUvZ=MlBQa=Qq; zHHdBQSLl4stJ84O*V`c(J*L&dVxb`;A3$x}wOFXTdr<&Qlr_ipjI z!+iggaoHxiXYk7QWvPzx?fQTO&x$U~3$&pIf7}W){Fb zQpI#H29tOx{iN@IQC2^`G-JM%)&C9K;&WGgW@P+!TZB6F%Z~QvZSlD)BA?r$ZI6K7 zdCsyJcAmc630P-&ZjK-13>{6>ucsC;urO?e&$xGZW(s^R`N&78z}K+R*CsQ6%GIEG z3smgCgqA$tKah35Me#o0z*jTtf8+fF`v7G3($r_F-tWqafAjvmLQ0->#dl@J|Kj@x z<;1r)@K5jG34l<)Ped^rr)hVHJ+vi2H3sl^07_rnFH@oB?aQ7c6=_j}en_dA+-UOd4EdCPqg}>>>-GU4UL*(g+;LY`TF#G~UU#pn8 z+@<$Dg?A0 zlEkBk&1ga2UUg`OBjjP+n+)U?IcdllhahZ;JL=RA!4dn~gA?4NIfK_TOMtPB-!!#pZ$4R9)x-8JJKyfcXC` zGWgQ=JwEY*%-e_wh=Bbw?bhP=#nYDsg*bOhp#P$SIVr~Fr+%#u=rT2W*EoH7)VBvM z-=)0iGq(`dM|*@m#q^eCm`>030`_?$(3;yHY-Ye#{Q^Xc;REuGy($~_$iA)WphKEo z$0`}(q9KoQsG(MU`qhC(4K`V3=`8iNj{7JtC0A!emO|^#J`m_*g@-`e(K~fBu#1Z&yB@C|ksUCt zAzXcTk&1(iX$!7pmf%6yqcCKK<%gk($Z^9kaR#zP1f1G*`+nn)XmtV(9=NTk4m5E4 z3qCEkXt~Vk5Jl&1dG*hL_bYNda5`g6fC%Z9J-o~Hx;sy`!Hd#qM9%Y^n99wyiFk8b z=;6AL-3-nlt#6I&Z@JIC6 zowt+@iZE#j`L^`#Vq#(m14d~Nqd$S)u6-c-q~|ujSVM^TgK7t{m2GN_UeLQLmc;DP za}V2C$datGrL2Sn(P{hRscMs(zdH9^Uj`^=D%WW36tc*SXs|vXAxsd7;K{lUrn~d) z!dQ%U$I<0{=T9jCgv)xJw)ZNtqe~{?w?%6>#pPr=*^*CgXZ5g~G43W6(YnMEkQ3gI4hSM<`w+VGs>@6(gU1$gMsjD=U(ZI{~u6_F(4%CWhp$yTe-AXif0A4kw^;0)SQWI#hs02}_!Mr(rji*C#%> zW_rb5SNWEN@Q$6?-cGWnc^de#?YeJ?^OuD zW0K&IgL?$ra2q3P@B=V2#^ptou|Ro%zWHqD5!P{R252SJdjMjzZfDv+K1`oMK9?zbdQ}~FCRE3Q(M=Y9>W{66 z(AMe(FI(YjFF3CAu#QIm+%9itH`r+%X5U0Xor82tWbPj9>4mqTE(8#&`nc>}FE_8l zuJd_NEjZf^vfg#uGfMN?RfK%l@c_xxhM-#6%^4R4ad~J{A-ih}1*{JsfgyJxQKbue z1yG-V-(FWJM4?%^c*u5?m?J|s>u6~89cqdPQ{T0a?-J+bQmc~sjJo$Ik9c^Vvd&G0 zA+pCr*?_XyT?!{J7|;mdh0&76YqTS90=c@i0rT-oO6iyoDa+fV_LZxhE-nyqRH!AP zgj;HRx`B7wZsEn3h2^J^F$%8ft49&oWwj!1TD*C>UcL)#|J5O5IRh%^WqTo6bEXb5 z3&0l6K8Ykbf`D-UB?W>;NW-5#&jo3!$YIbz7g#KGov#SfrG%mE${ErG-)<@Lc3E@GZ+!r z%=V~fFahZdcggwsg|xl9J{HJ%X@bUP4DE-rz0YACh6Jk)GfrYbCOFxdZ zMoBggeKvE*>!_UDcFGlAMA=nutCh>#{7^x_6V30*xN_vtb*95HZGbAPlwO+qgJ+WG zBqSE7K)PJ(G8kh6Y4~tD8KXNHiZidy^2v2fb0Eh4crFpT^`*rYr`Ng5_5)tty-g4u z?&D4=n#UdLn;F1G5g{)Cvgup<2R2^~jJF{G6B|Iq@6pX9-4D|gKUxm4jhdT9VsC7L zV`IQI817Y$;6Ob7^njhB$;O&Zu;w_xruNk$HH}v989Rj(mQL5nCvTvIlZUc%`3x#vF4__mkK&`=CJFXbxXQMxCOT=a7j;e zOwJ3OTW84Ss2;}y9fwM*Z%SJ?@Eo&X;e5n04l*m+hY`23vWH}Sjqjs(4L}RGpG$o* z)2rxRqP*A3g|%}Yhl_)Vn&bFwG(>@--&OOP9P!{WwpF$b>M=H{3m$J>YAq2LRcZ{v zw6B&dxQnsoF^Ed`*0J8jxAU}@YoyttLm!8dU7@n|x zK0)9+^6QkP({_-JRn=tK6qnA*N)3W$@n!>o>zieI+!MKJ3Z{f%7igKB2~Qgv8xMFC zl)kfGI9=w%ik@{Pd^n^63z;d@&e{M2nv3O1w=OOccN-$M z(PohDCD#rKZ`rEv50xiwmuFd7XTTWd?lUTtyY!gm=hIT-gx(D8+D}Z5fF#^d6WbyS z{B`7+O05!kC0Bx&U9TA&7XU%mT69}KaQ)0U57J+623>|x4Po)94ylsNVaHk-SMHm} zSpmp^_KGWblPFqgq&_Th2vpEXe3E^{L3ecmNJ+Y>@cS~k4|up~^&89pS30njv+Kq- zJZ!bQpp%lK_eT#>`Bdzs?8A5T@WJ5wc6xephF{ynm*W%jtK-x31F!^)_}tqMk0qHh za)TtD01x#Uc9(D6 zek$iJVV%%1Y z)an5h4O!m<_b(K8Gl_3q@|x5?_2Lj^{L7W=ud7z{?0;3CS{>@wCUMID;mq@NNPZp= zz_OhqZw|@zuM8ny+A{Amfa06I@+qKxGTea{1T6R0+}(Tu%|T%KY|keExBxf#Q(Fn6 za>mA#H|PCe*c{<4 ziUwVBOZ?m^P=PP3=&YT4oJbk0HT;@Lb0ZJ(S;%ee8zVY{?Lq{Sv*oJ!AvgsZAv{u@J+Yv`89p$W5FfGk=VJ~|Y zqj4`V&?CR>G(;uHsV&X=!d`#UhCn75I$x3UC-Dt#7 zSth3qFNVBuTJHq2Vb^x2)5n| zMIK;_dNd1a2|CNwGKNyjJ1^Aprq$Xk&cua6;!S0=INlTM6$^hRy{p3aR|5M^3PNsl4cnIR?4sX?fa>~ z-;Baf4qgWi_q=?-rM|n+i3je znf&-f-clz1(`WJvPVZ9{^H#8>uY!$!$zoELTyBmI?Ckuh)B6XPiH|!*Iy6*S4{KTS zZo~=>F=AchL#t<(<^14Hp(+U_5TP4lwND55|3e{mJ?CPJ;jCw?Of@h)8A#o8cLa*h z)t*lEZWDqZnLMVQR6)YjS~wchM0ix-CE1NZz+AW0YLA(9A;GVf%ScxhA4--*@kcbA|BNlj^kxOfK_KgybHo zlBHhkyG1rK$xJJAJ%e!3k33@E+(bP<4ey@pZn{!%`6C+X>nb?c%QXae>nj+8s@*w) zZoOVD%}WZwm78X1neN^IVu)Z#s!BM~@oq0Q2>KhTD6>TORA?=B1PwSOT3w-~w_9`j z2*<8jjSZYQ@ShqjhBTYAr|=j$H9xYM+Zx3yi}H@J-tn{#l_6O1S~6DE4z zSe7G1Z@{6|Bo;Oc9e5za^&=dF-w)CN*$t>g5O$qjH4 zmRi08O0pkj4sEAp$H#COhSPiruQsv={TB#ZKUApyJa~aG$i4D<}{xCEi|~#1)(RPg56~U@ZWB`N-ehuwgE2K zF%h>0w}85zC1{D4gcBUrPVMTjbRvRqi9tZMu|#Iwyj7{~px0TIHSI|6-0eD-(iR%Q z8`#@U6t}dr{aUcRaFdFw?Ub7TA9e4trl`JkefGVI-RG&|AfPk_OM4%$1otbFIDK@9os;tV|=)P(vs4Kj#>~alPC{NYpCmEFYTYp6vVhz?raO zax$(dRze&l*MhDj&)Z;UmzQ=Y)WY-_d1{oJPIX_>L<%g)Q>3lwuDpkf*uK9Y>27## zjWl$#Z2u0r$+a5ZS>1{du1_yuE>@+}Nj!1XpxgO8WX@i>7jsPx^_|^y01h2)2jB2Z zVK4*&lCEBT&`>bb7v$%r1`fD?R_|?MXF}7%5Nl)?piCkIoNdjh@;t_t=sk^4&L@2?9`e(W0erDFwT;FN(R1WAJp z7Gk&0p~JW)y3Kwm*<_C+ikNM%BvpM)aCq$-B;fy zwG_car&@@Aan8m_5E#Ojk(DN8kDS(2@`5aG|3O9Y$E53j5g5k&+#&oRzWV&*KeY@; z?!6^~xVkTOvI31YV!nWGx$c8sKW1<1GbjeQUrtWHBxL@o82HQW0OOkM(0+jVo zea(S1sr>xX#0j1qFOlqnBdUw?H09K8ztut|I{K|O(BdfsIa$>EyS z={8+_A>x*X&tN8+<&bQ>G%GsX@1O?;qkfY#XsOP`@{}M+K#eoXnT&_qiog@pg5=I+ z$87OJx5Ef6t{g`jGp9O47t&4S1Dv&a$@F6q0+KWD6!cC85N?x{==+1#kOTq3e4_#l zVbjhvUJtVeDvnG1ie!|kcRC3%^Fpn;EL#-MXDfCPmDYsRWjD?)0HH9m)9{Ocz`eog z({sXHNtR`LY;b9gI&f9MxTa!FDcE_*{$=YFYIL$9pS}Igd%C7%MoicqpAscD#x8|8 z>|RN*D7~&G_DIp!h$Ec~8;`GxaLTjDf2H~TDN)8z`F)sd%+k<|`-t1zITP#W5G%5bos=H}F?z4xwy10OWtexU^Jli*?XS+<|l*4tE+v-n< zT^UV@OgfOk#Bo1zd~(^y=vk|GWYouE8AW4CR=}7JoBQczUYYDfH<<}EnIjHf33NaX zLR2NJB-9I{qUFx^@{8=e5{P!_cROkW^a~4YbF5c$HAKC{;tHsaCvg{h?P#1a?iyV| zji)E)CRt9XAY_Qkbh;#Yq|Myu-JLKVgb3FXZpDbr;;M@_MD#TdA-`b@;%lo@4kubxZa#hdce-PWvqndBOf4 z7J?tTlXo=X#R6g9=K2u&Z}Y78rVf;q>|1^67C(X%A>^x!KvfQsB;i8=_zPt5^J|;0 zFMdh0$`>34Ntlg&Sjs-7S-;#?uo}=$Uef3I3XClvp%R(=>dy`k*Wb|PkBFr7%f)QN z9l{ax_>EC;dOwBl&!G70Yf$@t`r0OZUlD&`yJXW{htuNk>#6ptqL!uDI?aXYa!7Z# zQukJ>@bm6;f{|*XX#Hp-0%VYenG0r5z?r;49WSwX!qt;zqy?s( zX!?ThuF!_D)VTIeD#aRi7L*O-Ucq6EiIFyFwq#jX4#e34!gIOz58uRB@R!Q8eLbi1 zMcm<|3P7B6DIbtb60~PDR2MF{sDLWWbO8;pZw{U#$h_ys8}{!0I#8U|kAYPn%CNgCyaBerzlxPP+tAF*b6ceeh{UCOapc~tay9JAzWCHYk+O&eH&aD;9{UyK+4+ag-mGRN6?ED zl3V3J0c|<{b$EaMbZFjc3?689gBqYoOV757x)vp>7p*>$glTH`ThF)`64Lw_reM9bohWO1 z*$?ieI-s=RSwkHM9c%B)B&d2ymd_muamxww6nLzU6H#U4!N1}(SJM8?leuSc0|0`t z(t-?;@H48EMTFwyaiH!tNUul?eIyvL`Ya5!4l54B-vjev3o;dj?#yiEQ1KThVr{3{ zo@f5~lr~2WqBj;`&bY~NgA#u1+X&UK5MCh?gWY=Pd+U*t_&@yzX^sZ5~x;`}iBk$_>@!(_~(ww+6cUrAElms9att;0ly zUKE@$8QXUlQtnY2lBhMIzLauvA1)g$wC{_;EddGuomQjKV{*kVIYi$f^yxJxm*6p6 z$?B$XEJ5ff^Tg3mbjEnAF--1V}vZAcpuUx)DZ{=Vbktr|PzF^%!Sw)cxb)3~ar zes*|HQG3l!ead+DGF%FNs92+S3y2b*pui>aRm_T)1AC*DX7@7Z6l|Sv~e>w4q(oV#b3`5wtQ+? zh+aV8z%j?-G1duh0r6I!bHJteB7Cc&ttazkUHA<+ss^baBQrzB9-bu-1qg156 zRnPiP_u0F?v*EKL?1}lzxU&KcqJ=WDs<>}6sCb;q)07?@1CyxIj-6#ot9|c+wJzJ% zgDO;;rnmR|punE>LAvg2k|+iZDG#|O^j13^1irs=2Q2Thb_9Oc6wyzGNF|+Ng4c0A z`VdZA-g9dA#J3jOu2!3j2NXnu!-JC_RU+R+fxe1G1G(QVaB z7RZcx+As2A&jFEil1xmzebB|R%_;RTvdOTM0*A3pwopMJKp%&_cfUo*Q*%ec7s3Z+ z9BcAqD8%1pfXZuJxAFgdZyrDNE&tSr2>bV-hxwkKY#vl@>%&97?9glhs4G6#kK}j$ zTOQQaKj^#Psh$G(;@z);bp(C4YJ08VRG=ynG-&F{AJ1$cntqcssaIfsOyIwP@!xKm zb@Lvaft`l@IJ2$yj~hYPuz(8%_rWXw<4^vlAH4aepZs6+6L4DEb|-$O`<4tF;o&{| zy9^!{Wv-$cISP~3A#oL(0GPiUr+wwk44^0@%7NHPv$ym-E?W>&KBZbw4kw5qyq)JL z1-P;l*yrP549)325XHl~+|t`gVx(bI>R9nlTc3U{3k-+X@Uac!I%8=whw~6EsgJ7# zL``>ttV?w7xxG4}+`wRZG-@=C#@J1zb0$8sVK0awPUw(LD|&*jh;YE>I^i7WtZY_k^a<)bB@y73Bu%`nK=9c=q zV_XW*PrNfp*oKq{XefX+CceIn@X{M}(>I^xiE0cU%;6384Qm*5zuo#b8|bebj6Q#k zI@|p6p?*6Vc-y_Ekh}xScYyR3*O%%k@7T9Ot%CORRB{9=umCA!UK;~2r;14XLDuQ&l5zcolAiTM2OZFAqEeU$6#NF!JRE{u6($#!ut-daF_@n0Z(%vqyYvv zaEIWz1G)(CD&8lJ46r<4;)DFWOY>W6>z|yh-;Vhkmc2sDg53j?ZuYsi8x+Z)RB@&{ z+>68)WRU(GsqsZ{g}#g>+w=wQ2}aBL?y$V*Y9rJ{GP+qJ%6t6^3&+)}x(@UuOe-*5 z4Ofw!c8+B~tZoq2;zqDHn&tE435lv{MJ0gQ!*#ZO$RuHU+my$pD}e{Sb7k=Pqt`xp z=H)1);f+yE1YE6a#U2*i!-hk|_*SPgxN(b=|ud8w%!-<-@{d1E!=)pW` zw4cm@y}lYn9|5-OkNh>K)!H~rUM^8Ew50Lf2&S0)aqqX--ORuj(N7QTL1iFR&binE z*v2NstCz}O{BFHsgNE%8{?zOcoy?O_x9s&+s~KXlb4IOn4w@fz-$NRNdTmkESYoTs#&>&+Sdc@$GpJ|jcu)Mj=a|dD>H?Ibe>KU!xaRSQ zyLU^`@(;ol>Ad4A~`TmW}WZzWVkvS@L8bC{-2i>`At&ch zf7UtRm>=~9zA1;=29JVyz~86v;}Pf({rNd}hT66OcY*vSdwPpIHP|k~sHVihy#_8f z7|rm2kbJKkKW~GQ{!4^;2_yzrdzqh)P&%%ye)TPw6`AQtf|y1a7QJ<)V49-94nDgxf1gEg zJ$^pr#yNuE1fJ%Pcb2*f#i|9k!nn_5H@J$xd?isv1jm-7cK-dCJUe>51Y#<{Rc3qaKoiJUHm&xx6BO(eVk z(MqOO;bym;CKH##7#Q)ftPG#;I5Tg$VgspPBDNz;emn(@HH!QIBl-rbwFM6z)yVK=7fHo;ngQFnb+jHk?M#o)(as#Pa)Udr;oQV_G z-EO-Ae|9^M32elL#-YDR%an{KLey*Xfl)U*f;|F+y&KxwZ5!XE*f6>-v*j}%^ zC$-&zBytQ-X>_~n1DgkR%&YgoYGBblf)ni=6zu?z__!mPrZnj*Uc20KiA4-yfZY_Y zk=)|J{sMOPX?iW@276Tr5uZ=`eWv^p3&0%*Mgno@P>WJPgL*K>xx*KKPaYNoe=!e3 zObx7yrzhg7L*+fPXuK*o5b3gFvw%D9!lpQ>!1AM*4ShLL$v7E+tIXO0!U~f?CW<3- zLI92#arktB8MkKId8ieS>@dT9jUlopwK*d;pgaNc=(~TD+3-Cz_S4t#b8Pd);sb|u z`koEREYJV!-$rb^=XWO@k?I5T;A99dastOZ#ll>^()fde0Lm?!C14f=v_bdRfAH7$ zKe7}uv(xbSy}Epjox{<{^R6IIoRDIOYfv zP)M%=LsJ1&w0)-vrm`L7E(}0Q?}Emxn31>)-Hqk9B7|DvDY(#|5J+%iwUueH*IwM$ zXWN7+70;AhiSJt@(N7nVL5rz4Fu7eXBZhh|A``@;x=BJK(;JP3@pW2k)2@4}BOLlV z8@FznaAxYeT6%{w(%lo#nbC{{*vb@dd0sd_=S$t`fY@Sph((=PUuN4JqI$1NZ1X;e zI8Ma#f$YK6IA1+6XgEle5s;Hs=%J>?ii!b#mDc!q3g=GWFMIvLiX%8xlG_2|rY%){ z2pcBKi~gQhG7N8z@Db;`ZF0KRlP>5XhFH%d37oh>=4RnE%7c3EbAc0w_ORz_Wp`+_ z%RADtpJi;lpEfHi13vljGE5!4xf7;yEYq*fvnU5R-0qlu(Q8QjJB|j3SIx>YQ~)3( zTqQFxADx{_?Q8gqM;xeC#ZBGufH#2144jXX47{1H3kuo?MjQ8A{DN~V!-45~k|ryM z2)zA16^DZ{m%;e(PZZSmi>?tk!W`V(N;hZme$?UxJZBKr*Hzwr1t*f%-3K%Ey34iV zQhcX2NzR|H;>2AcqBn*uB2E_4a+ni7h`>4fcMG~tZNk64HJNX!=G&_S0)_vexBSP> z(uN5a>wG6=f)=gTF{Jhq+kp7SpAT_gon`;)eChuOo#hXTH%I!Wm4HB8AVv*WASb~} z?ak`6KQtDgulU^SeeL<)9VU2pG#CkO^uID2wy@~?xbb}(blksvUH-1&-u$;6_un<# zoBy`seh>cs^s)fl^6y?3xX%8^UvL5j0Ay|+h?JbvNb180T@T}bLt`-qdH(hjf2Qw{t zxWgiQKOfr{G0K*Uj+Ztp;c(ZoGMQVC(?IezStyg&E*9RTCb!eEO`s^))i8*4&OqEP zgAnAtTOR^U4N;EQ0Z!T$aGK1{&8|Fk4=#mKoPFK3kI64mBqVQ7S=>pbKt_?lZqSs4 zkxb;$Tx{wVu4y!JL6!UXkZn}e;6%#6u^2)huV`_4$k|n(YLLdBFG;b85=i@}>11Ux zBtGitVdF>yoSUNC>C&7;&U`iCsEMB?o7ka`nDp6CBnA-f_{o7Jbxb7WXbXN5co$Rq z#Kd`J+|7O5##cy0(>4-1-rXCm-c_uww-S)QXQmXx2FEd)4|(s^z|l`3qL;rlF_p2X zvq8Srl<0t$6~#9&I_gnL$=WSV;>~#`u3)O^U!ciq=tG5WPk5AV<1jA!AfN3_XN9sS z?^NurQuLBs+%BGtyn7V)X{!^!HmzYuON^*!3meH<>ctG>%wRfN>~DtV=RKzG@)v*> zUzt4<>JdM9^R%~03UWzPBt?!b&@Ts*aBOB~8mwWOb9-czZ1W1loef2+z(mc)*6?P* zURts5vaAPp1m8D_I-}8cYezco!$t49Zy1oH<6c#_JOsq8unH}g()bI^kU~Zr*zy4Q z`6pD6_Knl|h3TZY`|~ahlN0i7*NwQl_eKZMLGE|~p8)yU2^Fj?1u$-e5L5fN|KQ{M zpCa2oZMK8%v-=_N=7ULWdF~HW!Mk%V0VgLZKzKMbAa$)Eq8z{13d}3b6b`d+&i4R! z2nb=0g%c|z0ep2-n;%-L>921r=i>*O?=4zz9nJ-vSaHX+RVE>e0`dkwkuKoav`zPY z9{p_3zV3{5)ba>~n)?f;N}uq>nfelrft=#&@CuCGHh`$?pUi5IO3~f zuD;yZcqlysZVr`+e6DOv91BU}ECh?@4U&3mF0H6r^s8aJ3)%xA30e&cos;=AkFixI zMB>X!hmCv{JD$J!x;K0;VuJthdY1^?)PAwYYr(a zH_v(9pOmt$YtlAkux71~<>+)9X!wIYsGA|X5ge3>AhMuu?)pZ<)YdXv5C)&b*hWDf z2PU#>weJC+k)L+)D={<@B9*o1=5*~N-7Ve|lHYR0Uz_nrrt!4r?20!-a)IRdnVQTA zt!XC?T^1XfspNJ&5QX`6oQviYrW11u4Wp*CtwkDu5xW{oNivzZEJU_DvWYHsJG1zg~y$qz^b%e<#7i zB;qYaYkvAWXsi9gaIXf-tUOgb~w zcuKt_&kfVSY3Rve#Fo3xtIYPMi?9GkVvN>M@$w~)keTNN9oZZt6k3A_(pCW5Qz4E| zK(KIITxEw+ujtc+Xj$ZWf=Ds%nJ}dK+Fb+Ta5>TaxnW^~XVtHTPe4$ULz4$2Zyk^& zqMA5;Hm3t$(1&I{V+<~`3@8c4A=)Hbwnuh{&ZTV|wrQ4PdYM?lAedW#Qgbb~^ove| z=6t%l_h$^K`tBCjkW_cR@8(?QcQ(G&v~dxxrB-e9gW@YM(Hi*Sbt;&#kMnze5SW^A zC<52P+DM@4Il4Y~Sz=A=d1iawIMki(2w-Zwt>p3kU6}iS7P`nkZ<%>Fg9V@&=#AO1 zt}x2Lb|q3Y{`Iu?SLh-a5I9cZ$>ZYtcmA3P$oX}hBb&%%nKFWFi~+;%zM1r*Rly9}i zEE=U%@gr#Hyp6sWLyA8YJEv#}(OFfAbWzx8)%z{V66u9lPUe{dwq+#1oTe@=AY6$H ze8-K(DZ%#?6~i;=JwoJ-^G1cWpL2rv#W*=Tba8xOt;_ZvnnbP)DD691lNWeSF*BHc zUup_}1aJs3VxUB*mih^)lFD(a)-9c__}^7&AQpB>4)3l1wKDyWfsFk2U8nmWI39nf z)5ZT*omL#synWSaNdS`Id&=i~K$c})AZ0Y+gXy6f0&^c6F<zv;B z!N2~|Kh|wX+WiTFNd0GZd;hbF_p5FLoByK*e=pqsShsEWC4aGNkMsP-Hon(J6_8`o zjVF4=O{9Rt25v~-TfbeW;0p2rUE|kfs`}|4{VvhtUB@^7RLK9k1{|L8Db3-jHtyN2jR=M>ig4)TjN|@SZ z%SBm*>E`gl`3z+T0ew}CWQlnYu>Du*)>e6c{#`PH?=u90HNXgXpkF;b9 z00%9%tkfTX{Nd}12IM|9zY78UeDt!@lTG08WV?&>sA}S2l7k}0J%e6NogFv z7xMomJQsFzzwq~@m!@S11QfIAEa6QPA0Ywt|0- z2C8vi8-W5(Abm++0tGlR0@7$=Sk;F#;n+rQZX|#fZS($f^5zJE@#+ z3EVmy(j;OMUd10;do610xog<~%&`uo*H*0DBs@snF`#{RQHZpYn} z-{by&ucCi%!~bc}%kSQnwBfsi;Eyf%R&=zWFOK{oniZ|F+C;eysCYz_9K<+FPXQ&kf`hiE9<(Sz8}t>5J%5wT9U zqWy!MpR^QQ$6GO6E4h-q3H(|H%DUD4GOFHu$!a#v6W`KH{Z+6%K7@N2Ye6`HECQ5Eq4EY>))G9?j%bF;R?GrR!0 zo2Gg5Olk}x(L13lY;afXX%=%mQEP)&#*i=qsrW1m`ulDu>4(5>I<0m+9rBU(_q>O- zbd6W;O+oil-b}OL-XoVy1=8g_=b9sbx!iQw zV7KdX3`F4VeJ*M?wj6GG@J;^JyR)kPyd5K=j?VKVfw7SszQDJVKoFIHUiC)OA#R6N z0|o+t?zbD%xUdPcoHL9Kblv=l$XNffBWZ!?QZ$Pf9Z<0`ZHKFZ?OTz9gecCepTnuU zr-@7K+tY=m=wbzU`r;?3pKrDE{6e<= zX&~@4*vavt*1*2Wrb9E-yo)`&t#kv~Eo)bt-rG6-cP0OjB;cKMx)GS5Uy88&R{fwn z|6aG@5C2%Yowu-|u)o{kV1O$^E7SHDfHFa3>JN6f4<|8zo&If#^0uRYX%ZTZ!-U6& zTFJAP2;izeq}TC03q#INmDjiAIv#j1@BKU2r9B5(n++Vx!h6zBx_BPxexlsuOQOfZP9l)x{778Hc|tPHseN{GaCiHN)-ZZhgtwsu z2Cl+$cWs5$O>ptNvr@JX^kNEE5;*WTIEtLjn$I`S3nnTTtZou&+QIKg(c$`mySD=m z(ldSvV7>N2uSal7Z=>TV(;bVX@8yOGg!7)upv#Lv3ln2*&xnH3dlq? z42rzf@Ic=CSg4VZ*vm7iPHmm#fg^8dC@|iMd>)hggxk6+2nR^8hK$eK9V@d-OO~XHfPkwd(oSF}N}{Buk1U{@U8f zb$XEYaU8`GB zc;fi?aJ-eA-aWcl-bC_UlPZL&^DX_vwGIehgwg7Nw8}NPbj=xJDz5K-My|W7^^H z06$|(ud}%4@pM`l6B}L+(-UI>DC6u&e|dBoZZZTLka`-6LsvZgnW;7C=&Hq|^bJGbZUQ=C3b@vs&BLVr?~?`B3?PI8b47b*4vHEqyPFDxc@l|h_= z57(uFOGuGVY&Sk+eQo`%eK_&h1Iv-u8kb`crimO26%c2efgGD^WV*SaKnJbgg_;CO zg0$@8lwDf}v*##eOFHO0W`hR8l)}o7Q;bkJCUa9Hk`<6}j*q9{lsj8AXj4*2_a!uI zXB&vw|@xhHi zjQzQDgItiq3pl{P?U(+hvi(ID=2`vM&J7|Bz2SE8hHq8v-L!$@3_3K(wfgMZ%)hGI z=WTy{6u)+D@1_j~jqm>PKYSE_fP#K-z<~++-W7g_g3hd(JUtXKL1WJVIh#apJuHvN z2l!|95<@q<_T0)?3hcfiL}G_D#KMM_O!0M95PdG&nBk204WME&fL8XmE;hNQ^{nC`O1vN ziwty_Fs7fC#{&N-w->@HprqzE<}o8RdIDpAr+0S0H?o_ufCa5Nc*73!0QH^+?;8=@yKY`@^qP@%#ecu73ew4kqCwC zz6W!X=$SXhH0)>$vqHu8J)_GT8&PFMLhPp$hyaJG4B*kfOrSKES8#47>%jPnXG_yK z%-TUoc7o#8+74|@EE2Ia4}`~I_o#O^HDct39$&0f%(7RO@cO^D2ZfgTo?S_wdC(U{ z(s&?anLWP*Eq4%Cp^~USO#hB zlX2=Yj*)>xEu78xNDkseup#DL&MyJ0N;N&4afc%G^Vw_=eI@!D6lRb6 zPe=W4X1UMP`xbt$S4|$u2jlvn7x3&OT!XC}#Mu16)Y$;|6U=iTNd4af41UpM@&F6? z3RhV@3^T7KNkewc6Ht#61VI~ek5xA}n2D2&Q_l(pQOpH*r`y&#r?RE)ubD2ZskRls zM}P2O%b8))eX#A=0Bql446iz8$f|*{lRi*;o+zFC`0VQ0)E;sm)V+Obeac&>Vhc@SAom5Zdg(vL(!j`fwi? zL5JgxLMBhRGTVecvcwr|@-NiqP3;8j^TEoWcW2Neimnjsd=_YXqf+{-y*=(B9Wlol zN9Ht>dylGV{3t7N{ZIg+e+tAqR#Yn|B=N(%Vc_Kfc7nt~8XPGd8xAJn=F62%8-#q} z@`d2e#;Ns`W1t6MiS-+L4nd7fKEx6-R~BV}y=MBnVPzCarx-NS(yScnmGwb{!s&0&hflHkES+N9Hw@jSHnHL1y z!#M)L`(PC?j7z`_4NKcd&^t*$OrdJlqoTUuW}Qt5v^r!%QEb+|j+i+53->(e27&Hg zw_@uRLgrvdfzt6Q25{4%YDDXGHUGg__v10+>oWYWBgg&Wobiu?6c&A7j<4U>n{uSw zD@dP0UdJeD=T@%Pq030lK5-2^q(}tqZOXl8J zUtMc1xU=iF@{DJJ!>Eu38uSIp&*H70)UtSVY{ti@)r2Md8CLpOPnAh7jzKZ<*r;xS z3dc+s4|x`j0BJ0g8#!6VRTmJ6t&2sr0}Kcs#T(}IqtFuk$2P=hS2Q3-z$zVB+JWb9 z6Lr9EJKx~{0Av15s3T-Lo}jr(pBY5b8jurxctoOuM-XlJ zaTEu9;h#Pt|G~6zd@qWg=WjhL&mJA%#r(zzApPQ_tlqRh`32OO_p17|InI?Af|>~e zz9(6*swRUtt%e*+b%7toiNA={uv~D$J|2!iw-tWsd34Q}4 zs^ecMc!)8?-RM&%Zpu-=RatajGW|v0g(IYuL6k5S;LQ3dcl^~v_bY4ouNlGV)^xTC zUV7rupiGV(^C-uurI)fJ$-v0_RWmYH(39OAM-S2@EUwrTb`o=>Qecpj!SfMidVSt^ z+|Bfs$NdcJ4k=M(=AGj-`|3OW*W3orZl9$dAFxlqK`D2O0jiPg41DvjaR_bbDl@Gw z(LtUVvc5jRUaK&cRD_LgW%G8O?Gk7#rFOUPC&}b>W50^_t)fBEJgoF(uER#5Zp9`T zwplkRtiOL=y+&W}XIm5pc{amlnsUtX>tJ%m?3|h;>cddFVNWnSPc6Ie`B^oeryQt2 z$bs_ISq2`>wXUHHWuKw4<7@i~2IWWE*N4Id(hTQOC`ir(AHdL|KdcU(^d$8dN^ zFll}L?Tp|8&c%CD-bNuN~}0LBcA z5a0j+D3f;yegj0X7hQseRDg{TRsH3@hdyQnuT+uZpmv2V(K~bGr`ulFFX7mSDD?x? zSjj&KdEX%0&kFhVQ)gj4c%P4`cX-f!LH$m_JHMWtl7#H0RkN?Jjq;_A;#vGFlL=H* z&?vu2x#k7x^jp!YfooGxAnX8WE^nFJ9~?{@03Q9EEvpbPiV7W)My38Sj2gnl1Hk*d zU`wTt{Y7v(!MBmS1{G{fj?_#RR{;kf-9x%et+Qi&@*%tFTu!HZy zN8=E{j)7#2z-(*gdAB1uNNN3l!<87Gn%>(yYWPhvSK)tC?)q8 zpf=PU9R>z8^mtp!qsI|@ggsEkl{sqwC0B`q#Pxekpm}J!*41jQ(070W4A}|Sf`unh zxJ9Y>$Qr9m&X@^Zfwyr}b!r1)vD^jpY%j*B60O2zCc&6+jVT?~Qx&mtiKve|lN$4d zo+6=J4OmN`@nc=%c0+&_1H@~Rp@*9pVrNEzWg;SwJXt;*eYV$nu{pC-2OLZXA4!r) zIPeprh<24&EVn%s2Q2UhgpO6H?B6=WLU(5<=pFaf_T_u66RZ zFdYtJ;jb)23Veo;d@&OLe!KvD#P?_O+hs~G)F2~Do5U=OdF?3XQUb%WZ=XGX024o4 z=j_ArEf3NTFA-cWY@9+!L<*e2H-Hf)oSPq((_fb?pbK&)ay|~nU`a*SUcqK3a^N8qn#j2V zju2PmdVJDmd%yy6`=oJ3@POse$x}H$Tw^zI+Qq+8YjLUxmb<(p65G@Y0$C-H%eCLb z0f_*;T-4k(4RU1pn$TUcf(Vs39#JkOWoqwEaF$9>vjvn}DP`|&O=p7H0&t4J|)N4#|mxbO)^=m|X! z!`Y+{i)o{%_*BmlKNAkeFIk@XK`hqeG9bvP-^)Owb5a2>HQ-aq}z;nwu-?PQqQ0U<}A$RA+O z6r@8CM!l+@p`;uP2;v^aAuRbVL30>(yp2K>9XDXq$B{@@_gO-8V(2NVVqgHVc>$I? zfr1Sb70S8X6@2FyFtJtkVG0A;@*-r{(}@g|;sr{Y(ch&H1KmvNKnNA+1Ca0F?GoOBPuu}aTwkdne`*RK#JYcRpE@!T z4lk~^{zc{i?4Yvoj)LN0!dZ3U{9t`ox2b@~_$HrbHTwh2@S!>8Il=WX;Ld-ez5j4F z17+I>pZLeK*|)RS2cr<^JInie{mCi>8w!}HA*vBSJ1*rH>`#yOO-cN>hx@ShoXGZYcBv=y&%o4!WSv7sM|Y`<4Zqwuh^kswjx{RceO^TP= zs*0b&?pFEqT|(jiV8#O@MiO7F*;hxX3{!Aqk7IA*E~es9=yM zIH;un^n{U@xj)0C5d}L8x^@@BzNSieiZr~T&Nq{=(o3k)+5`u`6Qi4AN6m;a$td1! z7Q{93HPv@%w?|XtT0`c`)}L+2BvaFn%t>p$9(GSlBunYr_3C5L^P4#hIB5Sc)cG0c z`#cN%qljqLpA;jmY+kgAg5&)MEPlT`&Nj>ogWu*~`Ll-ZZH)-r7U5Ik51D(*S+neD zScDOj^00X>hoywZT~1sKGo4N;0lG}l*F!>9+y-FG7Udadb-ym)B{`y_Vgh1XOz!I~ z$qveylJQe@UeK}c*r@6+acJ%s{TZ~RcalAthDM@eX-KH3{EZ3LB-hFjPkEx&Q3RnK znU0U@zU#8>dZ&7cCip7L7`}7e^VOM8XF#G+)K03~#c$3lBqdFQv6|e|yF#L1m>>jB z`N`=hSErHRue*ew>RS(krdOsvV|;uj+jR@jC(d1yo!+6ipmWW= zUN+YZ%hPqa%t;ws^SBRe^@6RdNL}g0-2+LWd%e)QKWh}f+eNZlT6?MchxzVD{OsFp z_}0jcb$-7M@2dG3MN9lc&HTrL8NCZ8M45jtn7=i%u+c9C^BqcCY1{|?=Ln~$`^LpQ z{vC?=eSW&F-mJy}hFH9_ki7$WjKJvnY2x!0M*Cr;`@nNuyb&_ivTp_Rqte1)YWX@n z!STy|htcA2EL*=$Pru&wy8JSe-q_V){zYdE6J6N737^6~2&ARnoW~H(Zzi@MVaDcK z+>hLc-jOQ3dV?syy=_rnlrDV0fgLn2$v)i5N*?R!w1&4sd zmJhBhnD9^jr1wMxWavO%nhWqmfkC(3QuqIlyEj>L6YIKl`&`A>=lLH|sG>;?qOL(b z5E39jfB;ck{ho>lJ8h>k{q4QaIgQhBI#P~MplYqT<{aZ46eJrEkTH}Gp7>mo3Qb!S zMNoH3=n8$9ZqdxcUR17lm}%jzI6nZyK6JPm#@3m(AigiKng{#ZfB>!aH6Pps`e+Lo z*?Z?SxqubRM##rj>%fg5B-_2;o#TW&Lr_e$A20W3+`>U_pa-_@aUm-$U>S7K*AgM~ zLE1^X&|Oh=Ph7W!0=Ae61_AI%;%`Yk<#s7v*+UZ9&wYOLl`;l&*AN)Z{c)=xI9pn> zO|hBjur@eT);h7Ro-1Tr#P`=RnUhf3;LtEN2JmP{dzgo5-bNg7$C+YC2%Q}4C=8%g zVF7%6>;HMkNOwXPrWJF}j|fDvZMog0H%wkRaI5*dOzwYNRDWsrB0uPfHKWsc2+$Pz z%hkR0naTn&9t72wLsj*x+MPn;sW@$Ly*5WkdTNDBbDFvP(^*CIF(~{U88=b+fbhFb zv(#&^I>d3&Hvw~g*M zY?rxeQH|2YsqI(nVAqVGkox6^@&pui`?7KF51a8ywLL^6OrX=d0w({4Z*EFTozR|s zHW>MD^(D{#5B+`a^{0hT@Zp2XaNkuY)&WG4d&!Wp2L zpu>|tP;Ja=6vx*$5N0aA@6;L-7>}qVWR=vy8!FnvTj36PPf&+{zJgybpz?lUU}!1e z@As1pQ+e2hU=;BCmmgk;925-wn{^EBOjy%Cdg?qpo1*P$17s-!;`CoeBEL>V`bCvo zR0*v%knJsGhU8dy1jfmU+1bZkp&-)^bVnF#F(E5OT1j^xo;}-TA=o$8BIepYH9Es> zcgfyYA(H(*Y+L@3R`)Wp>n)o>^sNdV@B=BZSBT8I?rpBqZ`@OQp1afH&QN&OKD0mv zli4^>0dlcXD(Crd+VpemOWJLxtDv$=gLBw1aw8oc0ugMRN3cbtmswd45a!(s#S!f^ z%N>`1_siy>TbI{~fRwe=s+b*ive0;%=+}@xxpLbbz?{AUOHCBv9Y$WS(9Dg&>T%~F za80hr=Xf!Q$L_Hvm&e;jw68Xdu<7=(YP=zY5~%F&48~+oj%PeigItBS zG={x1Q1w9*>!(1Ee_mOTzb!2sjsG0xLAPQ7FWrB!L?OSdQNM}KasaGLs>Ef0 zy7>Bep|6#3#{K7}5BbB&l_vze0|7CjDD*c{Y(7Mr5I5JDf%I9&eSu3UZzr;BnLyH4 zV7Z3X4D@I{MHLQYK(c4HU30JW3#5+wp&MT82@_l68+jJT> z7iHL!X&tJfbvtH+6`qLa7x9vd8sdpUWTW3Z`ZGu&?zV#^^r z{@)|wrE67P;e_%Z8fq{QgkJswXsrL(*ZvwmFZqAuM?Vw;Ncoz_r@IsSK?H{5e>lT@ zSCanv#h>4uYY)d4SQD!ttklc z^7BirH{e>WMmVFvNzn%s3pK(P{Oxe~#t_0ogID?o1k3MioZnoW2o3fPXvUB2D>l%Y zi&RK=K-sDD`GY=2c3ufNaE=Id$D3;!)w*|eIh|6Jg2#8#^Wu=6zIB?;*$t_T;1*gM zMaAn$CQ)^k`WFm>V_862K&sZ(Jl(FaU!Yig-C-e`7^xx9W?QwpGGbr)eqUp&bQqlI z^l;}GIpC6@P-qZdduVy9@r8f%Nw&)M{i;(No{0FqR%PXiN%xhrsCz5$)Am+APqQo$ zMn{RF67@n!-jc(J92ds6s*XGC3;-X8bJP;I+O63pNinr~0UK>Ns2fgZhlaXZU0lvf zrAVi>^o+Qr1U-+OT^Bm0z;nQM)%U#>*!{rN30>>MNpwtGm8*TfOH&&3nbo30Z0Xmr z%U}w~eSlo{?_>TSr~HUULmt$7e)1LI{_7sqwgS7c_1r0pE2~)TF3ntqH6Z}Tn?Mow zwhUYu5TKbIeS|xMzVfnrT<$c)S87mfdK1&gyjuGuBrJpmV_yZEA zUBLOqJGwuQ3wDptP z-Oj~6&yI-OG43OgAsl>!g_;kBl3=&=BsfadQwKD4 zeSN{fGnM<$cFvm6iX5`3QwlJlYke^4sI@eWURYXTSGs-tnQ4d8f56_rV3!19mTYY_Mg;Q zH258Uv^xN3j&Gg1R1L@u(}KxU^q1$3fG~cZV7QfS*=(QxlVfx0Z&?g^Wt01C*4klO^o$)g?!Kg~ z2lGIy2B-sKNFdFe!Lt@wJJ`lLt|d-9%E%W;t((+sxq~DF^@ZZ}!Hv~NI!hg&jk@bg zj}%G|=a^j+^%)<{kr0yWu|oJ8aJb7;PGMcRm&X~74f}H>F3{gIsde3m=1V;Kof=$a z_9=}H#&10ruLLTauZn;|nhGVXM-&2hHwPrwbus`z&hzB(k8yvT_|9}%b8E9wp+V{) z;5IG7(C`~SodAGRkz--AcapD=It z#02zE+;#)1Zb4{wgMtdcRZFCxH}5eb!geI70f`P%k5lC-@z5hp<0(VLkFO za-+Gq`wc-tOw!?QD)Zz6hKU|Dg{l|P4Dbi`y%TxYVAA-L-9bwc|ltXJABWVP3p5U(|$~Hi4j9t_iogVY^$>ci_BYk?pdC zAqExM+1+o7PD zr7Dyfgy{6+d{MXQN#?~Z%%j+oYpHR+DQ9BcjGorh_=Ai#$rxBk$JVD#*{bTnR<@^brOQwAr$s8il+jh>bm*&OUzu&o=xrKXxHDsyi3? zcC|6@wP#HTkJ_ruVG-n~wom*cN-Qa-gn5;H(`x@dvi?K!4W)x%I$z3z--^EfbdcoE z?3kInzxGL+w$$_u2KeSs$APmhEPd;c2Y zV9x%VTf@fWS>&KBhGXvAt>JR`=S1w?>~zHn6pbLJ=6I+IV7ddDMbHC=)&K2}u-{iJ zdIB^>Yw86SV$S;E1ooqz=^x_hee1g09`uyE&4B*Aw=dw5(?or<*?o6GGg*TUO9~^J z+CpqkM`@!2zHGz2T#T$?{63(8;y1DT5OX!A9j)AHta;}geQk;;DlfUWqwZAjy27C3 zR^(FQN*C@?m58)^IKknG-UxOB*((o|%i6fuRHZe5jdFekx;HH8PCGwD2*pE(A|KJ{4gL7K-Ly^8;ZH@o37Y(ZNbAj&MMHhZsUXOi zR~oauV~GhRc8yVa2DGJIT_s|yp5p%DY}Wy40L%L%bY0zsj=%-6TJE*|U5TKQ&r4`h z8c#RhZq)rzE0v~{((Ve;65Gr-=G7BhH+&HG890j{Colx+c^9tXpA6QwkB*?D@$Z)( z_}Y8)!B^L42;qd4=h-mt51Z1vTiQjN4TeL(aX~~Lz4q*Qyf>4#S(c0_(_}(XMvadkma^qwqoHnglafoYmd9hE z`wL-`-XomqV11`2mb4baU<*ANEV2}jHiXyN-}YM_REc5<4EXbo84VnQ*PPPQifylW z&p4#{xHq>rBQL0R;QDl0a^C8b;~;WqTU%fRLymq?wHc;!gmi7syYv?_LQH2!DK3rMx zqFB6sz7Ft~*2C&K$ZN#^tNQv)#~eU5@K>7e)qVDc=<& zp8}Hpy$Di2E`qQIp1>>uEpD*MzgLx9(-99&M_^9@iVpZBBpW6I{1XCRzb!k(ms9}8 zOg0eFVeIq{o&QO+&@t13` z`Z6`%&47gB0yu<eADYA9XDnWA2}iJp1WMG+*T#` zY2@kUHjS%fUuqitLeIz^&3iXw5-5i+WZb5!a%8mYr0pq1-y7ZKik?Rb0C&(!ka1$i zZr9Bf$j*nYg-<9n|2lDsebv64LO2UI&?f{8$pIj~VVL=PAZ{JWl14tK_4$5+quAz1 znNK}wrA9AnR4nthI4S{fI-R~Q!^!F_{MGK{ve+QwV`x!{lh8*)5_+a%fGm152L{xz zv4MO|HA|k?XS(US%TagK8z~oSAKyTEzkP1Ij92bwbiP9rnh!dm`*Ircvb#*Y!U40N zues$~pbW9s$ITK=6(mNJQ56myM)mvSb52r%ez6r^jB%b@-Q|_swe6g;Uhg90VboGa z2MNgcgfo_Z`$95k-h7^vz7o#7=}!zf1iFgGhYg+Is)xBNEn%z#q6Rf$gT*|^6XOF2 zkv?VO@?=2`2grxGy;LG2_1Fx={Xbsz{^1j^VCSz+%xQ2vSv z`}ld}Z+8G*4=6bymC-MOU4}uL_QxG%m*bCfJ{BgFECehDAeVZ>gt4~@3i%3~Y~RbV z^7RjIC70qbS}Iy2xb)#<$;a9G{Jpl7dC)EZ&K9m3y8?$DCf_*>Q838U@iOT6-#;5% zbmu}4;`@%jO3}~8*F%Fm8A!U6>;@RVADrLxoq7oa|F@PQ4$dtMP~gsBO7PR@!C@>g zR)T7xgiy+J9)lzUR1^>b0^yy%JV(DiMTq*#lMKlDQzW0k#hGj^Kx~0flA|*k_zIcG zLTaN!iz3QHnx17n1&C6FdHnKql_CO<7s5Gp7dqrWUGm?q_;-6LZNQtGr|-=M*jDxq zxtXGH+fk>40AcxU)HazbOo3|OJVkj423gU1t#RnQn>xrZWc*V|5fF~6gKpEXj0h#< z;>j#mt_y=2K*6T8@m`J_W1*$x;_E(ayxYnRnKzRfA;=|UKyFTR_@v|c*|`N-I8GC8 zuQbYS3UpA-TiL4pfI;{WVmvc+eVrlBdMBN?vbFqvGJkA7mgC?=fXmV2qZloET_6`;mitQ2wDxNVaa~< zFnF0DUUDZYzF=Y%2c+fnqbrF_rncJ@dYxbBDrWf~~0TdB6I`l=~6WgI>X# z7DcmmiCQawUzvcEd_NU)UbSZ7m&16uk=P1ls&jF?_zNT@Rz#w%K-v{JXCCo0)Uk3;Teia{7!8cKrr|c;^|su|O65s2xk)8p zND=zFQkDG3SMlIN)`TL4^@y(yd%jUe>p2pnHP*U9sgb$cSXe0*+nF1MWFf*Md`xd$ zixr@w_3?c%R*1C=J0WsXR>tb23X+am9RtE1q<|})+8o%93v*roW5Xo2xDCH^!#A;AC*trOV@xhz4GtUJ4`&onBi-VjddCZB+!c4JY+gB@hfIJ&X!k^gfW4 z{1qZTPRHGq4ae9ttn3PvKCIWWyP4Pvb=Y^FwkbUC9s*_Rh4MR81JXSri1I!SO!Ep| zne0Bcsp-B$E?N3 zy1!=7N)_3`q;_rWl>G5?e@cPwUO69&nKpYU(x<0qfkA=zY|jqaKFG>VxI%AuG95r^#IN&W=||8-K(=wk z`=SCkrt8qq&`Hnu7=>=8mi zSd*e}Z+0`M@_mp)>6V0>bg1?lqQT8DaQAkSUhe`{vkNg*C~}I1!&oWK<9=x75Q6Ir zM!66}zHXC?wb^Xs+x8whwnC-)z!5Uf_yD}A;V88DJ7?K>V)W8f4h+;O4@qKZwt!+B z*T^&3(E_+bBnD4_Lwey(Qr4VgxyZR5#CRCN`ZS%jlw$6<$`h8oEGYg)0ZMg8fSa9H(0^`*t7aw^dCHgPmcPp(s14k8ABc;PI{+bmKD^ zIBxb@{D^i+yaQ*q;H2>Twt$^drecY8KCpno#;8Scub8uKAF;lb4B zA=bm+T}0s>^2c}!wll!Z53QUPa{FdDKwdwG;J~!RPWUxs@^^qe2v|S<*1iRwzDL&3 zbVuHNXV|M3{SNZsHJiZf1#bQ~DDbD-Cing`Bgrkn`{~lj=PzrZOMAkR@4wC02H*@p zJ3m?>Ns!cj<|VNypyZ=ahdF@WfBX$j|DQVWVA%f^g7MXX|HZJc-=y$$V;IUNQ4EA0 zri;f{choW|X|~aACzSd)rZ|$}D!4V~T=0s61flA8K%p}biSFsx;2Q~Xg(0?ynjaK!#$n}u;4#S=@j?DmTQNbHRpTX z-e@V>1gHVXhU2iue zo}LLLFS%|9Zm_T)k5vhPq>DbnTkO{KTXDVDY;`@G*KNL6Oq^qq6kwki3?Dl%Ui-op z!dI!&^q4alS#6=gFV)lQN#1TYm*HkcKB-;zXA49m8%o%b zQ;~xeWa|d=N9O3;u>Wa*{JmlSJz@W=m7~>kiZVsnsJPv(>-b8wiP~?QJ+}J?ug~9B zmQPYToVh*xm{UnN8I`6G%S zFdv??x!n^zLKE0{0shx)7(;WwG(Ns!0MuNrGi^!xG_(?xe!i?eNY4^4-&fg(R<_n= zIf(nZnH-F2oGN|CZ!unmE}zs(X#&ySNnk_LHhX;5%hNxkJvSd>%{a%Cxr-Sq zpfZ?xH|VV|E@=f`c3gZN9R9hZFWmO%AaS>O9rE4&nVpm(zdX~|zW3#_RQcm(cq$LK zS(@^EJ1Cd)A!Lc&Ld3+d&lA3a7-Xvg>uNr2x~hxRC`GtOsckOL?j$qI1k8%#9Vqa%C!9mx%Kob~|>Ux@oSguT`s=&oByEQI$MWl7uePRh-GYEM+RHv6ToISgqQ z)soTC3m$DtTIj|Su6>MG77-igZE!&EmascPa46X-=@p*pU`$m9EGeQ9Dakc9x4LrJ z4b(9yL>8HXZ09CU6o}_ylXf(Dkam`-7vr?YvO^T}#UabJ9oPw4f^DQZSCc@0IR@^5=3(;uGjT#i zDCX_^@x)cu5&}at0ux$CG!uPzytHXnn<_yM z+kTv0E^ygT3E*YL7v%PQ_ys^L4jDjy3C90nn37mSzp$+)YQc^Gvz@Q%q|%cqVRfH_O|nAw z73O$df(j>In`V5=9ze_xHQBE8(XOB_N~_tSBa6>|!^(`Jp&~NM^c4nPcI&Q-@YJQp zZ3O|e#4i*hU3f8H8tu%o^Kh(i@*y`KPg#U?QbDO0k))E;y@t6?`YSbev^{xW9y$0~Q@l?0&l7@u_(;o$%K(-xu`Y z+<6`RvX?!;t`WsaaALUg$A=F__5GMa%j{Y*Rk^)wrH0k=F%a?QXlw+nkBlsc?5;3N z{jj<~D-xfOJzv&zPyj+-UXi_4@?|31I>V#;fdNLvkt=t!w!wMI-`GqtN@}AXo=X7G zsmofTT-?PcSVnvzyzrI|r)Qircr8puNCP{&>Mc*6yo27$GL&6OI={5~>;dap#X0lk z`Ypv_{+h*=N*__G5%-n);>H72U3G}IzELM*?l{imuE^C`uLIPv~|; z4-k03!4bQ7ao%*8d&lGfRDl^J_0Bp@xQmw@>aH8&y(^8(b6#JwULb6{k;e1oU-xPE zf81+z1rEf2#HvZ+>XV`KakwV`)jRd4lQlQJyW!nm-SEE~p5O8f@In1@hP8pVtE_bU z?F@^^l{I*O5g$N-X@kR+ff#DQ!3!T2S{TduaBfY92o_BVbVZ*(+-t(mKkI$sdEdh^ z5WJs5`3HD|rbz+_wZJuW_Q7$rFcRc|79f)UCWiky6l>q`Isgv-a8%QPjqr%ib~>*0j}EvLA3%%$tA}@a`0HCR2Taue^N05 zDm|N1RGeNX<&a$gY;psd!$}Xe!)Dcwyb8&2h3r>*kj_}CYb^>w4W@Z9ZD&XemoaoP ze+Upg`kItt_G#)YPe9Nz3~~v%X=AI4YX%~q#xVW$f)+cT8Mbuf#RgcSyU0Uy;9@%P z*#Ia*9FxY3YWtRT*2SYjPT(CNmxe^K^Z?7#R$qVYFZq*{fty^Mgy)S&s)^|6o&|0= zu;Gxx#LhP|kfa%%#i?CS!niwM>E74!3?rh@L?zAV^tH6)J&^tm>Afx_Pzf8#9$!v6 zq>k=)gW+cnhYAqv%00ts(D(t-xOVY>qrtMXGJL&B2t4ZL$Z- zYTy)CX4|^0$+d#z1%Kf2@cb`wIu=Yx&+DH~PaosS|DxN;)9*ET{JthzzRc|!$sEjy z(U#^BZAqzi{`S83&>G`Ec0k`+W5ITRfHG&(+4A8W@=Z1e){^um zxbeU_E=L@c$AFfG^_SDWMxELeDgy@D-kK|oUSZ7Tun8(1u| zACm)1M#!ouCMx#scCW=l zAE=#770)K{mg_hg0)_?z-5$#LbWgOahPdo*_u7}jMyxJXgcm5RjE9SE-%{4y)$3E^ zU-?TSHeUNOlE+XT@5MYR@^T=QB{rDcJMu(z+w_&%5XiHgF6}CtyKuqgn!+|=AMKSn zJXlc%;DZS;h143~>*h93FM01=s4;BGDSzHchVlw2VXxF<@qzXfObA7Wgc;jqOr6c$ zaYsL`O$uG?W09X+7<`=2nNHnzc63e!oFh#6Ey}WaLyY;6zoRW#aKHmYTSy=tbi^dI z#MX2k2W7(Yyz2P8Q_i)khgxvSPzfd_MSS4*_oKUoBQ1=AVnO}34rfs_WfAC*zm#9V z_Lepb{b%XdcjXtOF2ViK`T4S0t++ql_-cWQ5C?}h0to|eHEIe=B&u;gG7vPVAhI_n z0SE*a4q~YPQgBV$4;m_s|Mq>z`x_x;;fHT5KL&(<2Z6rj(~uIb(R!Cx(tzP%19Hdl zAat-`UJ2B`BXhLRJ!mLZ&uj}+!{Q8fFhLak7sW{m0P{@}Yx)^-vVtf7JTOi=-}7q7 z!DVcwdbLekoB=F^2i>VoLn^t220e`TI!oktB6#&N+U6)9+sa3A@ROHt*5m?Cv)iV$ zSaJp2=HbG0W%VrM=Qd@;x`{aJY|iU$L`J95Ij=tP(PatHvkG{uGBnQE1>ocYuwbj( z;XoV&e&@E+lS`kwr?y^-`>DsT8I{RFK}YJ)omH8=dkA?a)Tet9JQA$3{c^PCbPit+ zVP(2Dx*o_hTi46WUY>9artgttA2%=2XHO9TM!}R~PJN#qYlt4OcU&y}CRu*1I=v0O zd@77v)ZznA1VDvTo@mY-FEkivY4U3-2VZ~}Mt6Cb%3bD9O59t@4gQ$>_uHl{InL%v zQ{P5@dgXEt;iUS2{q%4PC_8h7KmgDJl!Z3_VT*|g{`*zI^O(q3OAgCGCkV_P-aHaj5nE>Gq z@YaIe^dIJh{3qc1Tl6&y^USQ%7T|#i*H}3$fT4T3%_%i??I>p?^B4<`(vj%JrGU&a zqqyvb)LljZ;X)+!%Otu>Lh8iny2WIf8~4xKG}BLA*~YNr=~?dqoxW-yWI+rwsvuiP z8$%SY2A8xaq6Zs(9;lUd3~2${X&Kw)4oEN@3I!YoHqLyRD0ROvkEiCjg6J-W_~Q81 z@M13)ud65xON=PFCsLg`Q3fXox^3T%C`J&(%icv{O{S3kl+F*w(x}$j5m4+}I{yWvHv`C{36 z4|cYqJUq8NB$)aapYqRvUEr~jAdFCpi+Cb;9pU;iu$5sx&3_vUa z`v~=iedLduhW7qs&)<&_92=SIuWy03?^olopF@*MThMH8;@<_-JDmplB)kd%hVT5s zZ>^itN>|@jP3di$`&u!-odke=00Im8Em2@(kSDyC8qh6X5r}PiyK12F_ken=;kui@ zL2vJT?4NG?(^b7M3i*HLs{VHtK;2jzKm^(-h1ZL@H;PT*@xe)VpD>hrp#(rjI)mmA z-o{9eE^e;ZHWe4F9wmCw{sKJq&D9Icg4htDlDd*19SP)`KO@jRxN{t2W|w=DFw z#NbFuxK=d0F{$L%gR7+&TZ=iI^~Mbx({QA_Ey}FRv;t_tAPU6es20qc8~b8PbVS)8 z<7zJ59(xJV={7@>w<^MFdZv}d4>gW5Abbp$biY*&=XqsV$?Bdki#~YtQk?r)?6peh z{7P@F`Xy~zXQ;K-?p zkU)lZ=>oDj3_XA^&XI-f#)R@`77xjIqaHvvfAPL8fY8^lp@Ij~!ap@rezMP-WDKXl zo2GAbSi@Q4wmhRnKOtLFNd-fLtjQwXNP7raJ?|3{oE0445eaa& z0(vcd!M zU#;j2&kd$3AQQ6&nJEaW2~Ns>*@CX zd?JRkyI<Gxe#3eK&R!%12EO>JunL*+VfjPAxit;1gVxFqnYG88rv{Q``(q7k8 z2tx-JSbVvy7roDfD6zO3i#}-qhoKixW{Ax|(1(XFL}S;o?J$ORABa`-=k%}R>OJ#LZT;<_Cp8{@kJx1 z?Q%5bppK`e=742hi|lyoqq5qzITG$f}f1eQd3yt6;Awm*nx}UL1pdDL9SW*sP5T`${C|_PHP>(s^*Xn1}OBGMIrBPM!&d; zdMZMXQs>>t1B`<f4G4?rM1YF2b+ z4tMRK;6<1koVqzzV((VO(SdHlxwF75eudaqE*V&9B&h^-kwXy8*>)8#t|Phmt$S`k z&TP+t6>ke2-;&3iJYx=~t3+kLQ(4-k*(*;{5}#5om@I1K0ExlJIetNsW)Fbd=G9*f zl6#fAoVrU!0CeM59CJaV&SJGd)ZIHvX{XlT*4{7BE2bOfU!QY zXb*seP`_z7+_QgNLIMV^&@zO*ZG3Mzzgs!Jjv5%Kl4DbGyuvufd*ta3a4G;E$+0R~~?G^RA7voX#BZHg83yTPWobT_-CyQjcdF;kv^a}fh5;4W1B z>Gf&^W{lR&{()yqd(iQfbk$DtU&_5cjs6RnsAWqpQummXSrr`o-;Nrl!$PO(0wI_` z94r2GggE7IJT~zikIk^Z^+~}(Xm4lpP9MM4cvtt{v_}et3ijL7S-v~!Ke`+Ni4DF? zh!~4QaF4?v7dX;Dv=mCU>pa0tWdsp`14uNzHC+^p!_dG&4qHghx@Gdw%2S+D$&p4#ADF|e zxlQ^St-MVRZK(|Mx%@SeUav>X5?a|~XdjD(q7LLyEUq5x7%Dwd8jRpj>n3j@@E-Is zWs@VIziC-zovEB>i8DxI8|+n$5le<4E3j>h_Z4-zKmw=IKJu&DzXsuGn%xTz4jV|n z^e6}~?5}XZG;0Hb8IEFSDJMvE(~|a)7)mIBpmh1eV|_TkXh7k%viEjF;AM%H0_+8_63$ zrS+<>iEq4ev}57}m!oDcX-%Jk^e600)RW-O#{6`KkND_hp?ispfTuMa7jc^72dz0C zW94qXG;lMOlUi~q)uNYEUkCc0ga(ze+1HQ6cNE`Sz$h@J=paBCP#Prnd6|-Ow{&;K zRES_Y3IuT>rP=b# zy|dWvJ8Dzxc>HWH+Nxd>Q*?^V8ZGG{-$2MqsQV0na(m0ut5Mva!UMYXmVrq02%i@BJC{KVpPad2#@laDn1Z z;DAyzjEkHiGk`ki_)bBDhf|_NG;D!;*+P4LuT6j)u%T1}$TLJTzkBQc9>@W}Vm|(S{;AH;E&Cn~Cc(fx zh0uX_dL~dC?Q#-6+i1W$VEA|K^(G*H#v(AVI|)6QeBQW*Pt-DaGTz?<;Aeo}9XDybU1?k-GWGj8glWK? z{xE?5MDEXb4H&%bkF(21HpTC*(4oqUsQo&f{>#0}4(I)%oX4%xAuhGI=0OxMjsav3 z!?sEG0JNv<0Fc`qL5diPKQc0P@S9qt`?rWf_g+JNVB6k45E3@G@6KK&cl2^)MaA=TqdnwL2|5=-5sXm+ACrXeD}&pDjIqf#ZmR?n-)!uF9D1+R88O< zM2)RYhF^oRBPJYq9K~GnAD3K~M%TI(jv7Os5H_Pk0vFp3RVVKn8~e?;V=AM+!>o&s zK=EFbdnePb^PGU%x|QlvkUI}V5NN?wEZSe`eoB0p%ulG)I4{Ff&0R|Oz2h87jN=X= zb$6b?TbNG(>j~H1xXA-5xUaKXAEzZ4udfE#wd&Ar`IA7uj#cWyH_}M+>F?u-CL<%W@~yX4)g9bX zM0gC3dXD^`X7AtLOWvE!$_R=O-H+{P1O&_Dt{%y#?B1py===9xyq{|x(@(@Md*6>F z+bsirt^cWCI%j#~Lsr2U_f0(hhZc`>+m~=d()RVY?6r^L3-2Knl8YR~61=^IHeRaom9eau1Y^_fPi0 zXK4LN6Jl>q*CgOS_n!xU)+gW#382yXKzY8jRu!}Xf}Q`VIRv#YL}-7F)4`1k(?8e? zeay8y?5bf$RM_8wfquIUrZIp_`IGe*M)ZKfgj(h+LL0oloqAoBcoPHTB0ta!KqL^TrmKfem*@24zDJu^R*w#2NiS1;o>s*Xu z#7)+7RP=2t0ZDJL%nhF0Ic+Puo=`)A0HllbZ&>KyS{M(xo%m_4vzsU z$3`lhrZCLfc*9I-x4T@#T2}!o8J^lc>xAOc^=o%}-*Rv2-7tL2_AvX|ZW#~clp6dQ zp+g8-sP*7=^GIkcK)A)QEe^?97V{e)(>#Xda9EC9;Js|Urdm$}kL23k&H#P=qD3Im zUpDT4H%k0-6c2dylv|iEI1Ygnhv@~Yk9#}3I3%t9K@E29xdl~;;)IW#a#87VegxjJ z?c_{e=M~;SeZ1gLED2p;f=34gb#?G(-U#P9tM+*>+L@}WQ7azs2Q4{A96zQJ;7}QM zcmY_?b6zs03Jt+j4;8T!?*=Bg{Hq%$DTQkLc_E$djS^vTAQ%Ynlx z^cb^LTX~o6p-HCD_wPA4PCZm>mlBA3E##LZQYE25%+#EG|OMFaUXGS z;d8wCedhgvXkH#f1S>+V0EXr-o(TxA{6}WyN8AhTz$c?k+?eP0i=D++8UYOne4W@UxMGaw&*L<>aK6ANWCx`&3`x5-(AV>ZLoCPZT4HF8D-u;)i;16l? zCmQE+IV1nol!59Y-!d69!NM+6fGD`&O%O|G;9>B6F{9kp=_;b6%q6CVt1eAG1mMO5~PIg>L?|DkbrA>J5c0JmcsEY&H5I68`xX#-G@iyyFC;-pS zb+AJayLNz3h(jnp)ji&MwGz7E>AxRbQes#v!6$DAB^=><>7jiHsq6?!WmT=0t;>0K zAP0f-VR{3>PveyBgXJxWXK}1%!bFd*JWZJjEThVu%WP=YA(o4FX%9oE0zt|CR z&ej8Z0XO;n-bsklPj!>vpvM-koxKx3>#3F6@9+2GnBFioj=&DBa&IO+7>1Ez7lP?u zrjHgPB~Xy`xouMPSiOK)F(0|7G6Rty%s7<`1vTPzFR-T6ulmzG zT<|)OJ)7JG>rNLruU=_8u7D`2o=$<_=IF5i*lJaY?VA7(WCebI@5(FJ*bHquCySL03Jyr5(3N4V$?_7`1B$DhGFFt}&a?b}3FGLGM5U>^#j=gr7> z{X_JbP=F+=D&F^FDm1G9tc|c@TWix`Nqmb>&y8n z-%q;TF|RB*(K+8r!qJ+izp^s_^ZR}&N`LVVu)o9-tmpn(ipTNvZe=$Qs#mgylH*RA zNsvDErY2t3Y}If-5GQ=#p)W$-xH2~y%)KbVx-$nhh6tW+34^gI21AxMbuv{>Bf%hNK%yl{O!pC@ICBa6@hqNG8eTo>Z4yPQr9TP#N?98qHu z>XG+&V(=ZLW=_goYD=|o%!b+sNNfbDkX>yRmZ57j<6N?9==$BB56(zw)gwmf*K*%m zkTpdKyDR&APkBv+G<|B3-2l02JMFwij4Q}+ah=ZZat$;4?qg5*!ZF#^2IB~BQ-Jcu2|8gya{HtQ`y@iKLA)7{k#YMxWLHW1zI{O&!fUX_RG`L=&}$b+StM#NeRdjRw&qymxq z8z@~F)wkE`tyrl+43{-wDEP1Ow%DF{1*+p4z_8^t-E>z>pVAglw5*z1s$iK#0=;^X_acBD;)zlYHi-2C`ffeBrPf_s^&H{M zJ{`psBwHobgE>rVV92OdT(@sslg#wRZ0kEGV%a%%E+EugS)AGIXg^p6-k`ACb zd$GwIrb}W%qPu;PQEY>X?$4bOR1m2Lli+ViYyE3a^o@Khia*vnm#^$vW9Cy&@-8;Y z*id@>`uF1R7f!Hmf>h!^`C?50N_;jb@QdYP3t9$jP(I@0@y;}V?a=>nU*wlN|AiI7 ze8(tPT(_~^>3-kX5Ywr}1;ztL9^NM}Dw`epDEgEy@=O8hMMoD!jRKt-k124cy~HSg zN5vtYPB%|^kVHEMr=z7S5G_*qFq_mK%@N~)ymurm(tgig-Ne>hD!~JpJ91XC{d*yL z{-GwX7#s&H(bnsHMxED$mCKIFJ%g`2TubKKdY>R|@@5u53oQ>y+5yUb|G0@fhuJjZ z&H!%MJEz(tAE$vv9TrCXb9)j)xRsh-byTcsKvXvo5;YiCq8-&&(wCcDV(Us@A-P!s zVxWzUc`YG_)2fIKh2m;s0d{Lh?iK%TU$2u(Qc9gJC0)Jnu21n@Id$;akr?>3Op8OK z3mJ$(t&xCXzAVIq&F>MMQ1#w0y>o=}3|vg~QNsy{#Fbj+M5%cB)c9>V0HMAFoYmaO z)*wgOOx~ORsISJuAevVJa#_$?J1;~g>QQykWDmMHKXjwXIvuyrM`vh9lbX6?#3_ra z7ewFM+M5-oi@Q9vLj%gx?ZDRPD!kmM?-v=ttqda7tVw9m<6_cRuL0rynCrtjP@J2s ztCO)#8C~a>-iu>+eQon%HOW+;}URjKvS3WR>2=E$VB(edQtqOnUnU@lRO zbxAIJ7@1>Ln(d#Q*Z7gE(DYuAo{$p1YWy=lhc!eY9+HJF74AgSZz;CC$pHwYZtKJx zTy}UlET|Kf8VvM=XEG>lfA{z8`=3z}P)Kn3kf-0K6y{%}b^qmr!v9Ptu%8nOnNd}) zo(@JSlI`!>E*5|TD)^f~93+1`D`9q4X~5r8X9O7O-=!iQyjqz3x*ufWGy8n;``4iV z?>?K+?g>%1N~2D{Y)zqD0DL-xV1K@jz#YE%a^bsuSG&M`7wlaY1KlUY8-3*+8o%E* zgIn!qh4V>ke4xXEz|!0N_H;w*T*?q>4}x!4@WNbl`QvL){gj{Es|J*Q5I9RNB7iY} zlmz_8-2ihHD z+l3D5oqa^6;|dA}8^Sg%?eGdm@lJbK+x5b2xOi#r5%A7fp;{!u32I1n<;QL0t^|`9 zfNd(3r_*pS6;52n+;F6(rW>RXit&|+?LwSr@&b!ji4c$V^nxHX?7Z}}i}i<_9ADB- zSV?2C{B4Jy1Ze^=d9~HcGfd*$p(&Abeq9v6g#cf219^eVOZZ{(w9@12MA`WR{Sj{!6EN7SUrX-zYv(!FQO9_eI zIza26u*P(qQ_wOks^4grYV)MlVL_T(R7J~WG`{-NjVPeEdSgim0fl&yQYR3X_>F42 z_J)pcz$Xd7TpSPx0}c++wV*aBkTwI3iXlE+amTmu1{@$Z%N_gr@XC39Eh)M3{( zARh;B9d2q%og*XIT7M(r_hZWQ9sfFjA>2fJRx^>sPQ54O_nmPe)`gTt}Gt}$N) zIQE3?faHX`BD{l;$D)N~$IiPRGZliP4w+j)u2|w8Row}!<-{V&vhpa|NaWa_qX|4| z_{L7`%1LZMRiK7#A+{PF@+f#aCqFVr-Ev#$CF`CRO4npvTk0MKnRAB?uZqABze}{s z(|X7vtq=e(k3b%m?K*I(hUtxS1maz89Sgv=SHiv8lfRa*tI8GFK6|(nprWUyjjnej8g^iQjl52mA@VVVu<49UFYqBz9!Xi>!2JKZ+WG9i zu6{V$kWp}g9LB5Em(FIugyl`l?-C?WVgoP(q+%AYxUu%D7>nTfl079Wubm=7o4Yg6 z8v(I#FdW&r+$jN^W^)q9SYMNu;1du~*w%Olz_XIfnA1jU$OD!})O0$StBCC(vvN6V zWmiM~N{FSr!gS6usCnrW9YPLg4@<@FxW05PrTbBVsT8`&h)?gbC2WZ`#yfPU~;C{Xajg|E*YqygeGsIr0Vfjsb5s0AVL_i?vW*Y?oqzQ6@fa z91Fw<^6(mAvc36xVh#Z;=Q0iK#!#N8z<>Ns)d5uW@27U}U0;)Q=N?c_?js9`KXm%F z8`=S7a>}#K=2(ck7i4*=TZwWPU-!`B4xq9CLe^$RD1Zk)5SImC>poJK4m6dASg5g4 zp%I2Q*=JZ90E7_0a?JR3IqxILX}uja`2-z`tE1%I^`WJL6b6`(weKSu1HeM$N5iFt zg@|q|COmc+bw@;Y;2oIvt)WGY%Pob4gn6YC2aeQZlO-l(p6;@eES1VrV;+wg^IBi2 zkOk4%(aUf?(;)2}{D$5AWh3bk#L338NyfCA9cLOve=|hN?h^o;T(PMl@3+L+#d*tU zcL&?ZX1Ys*zRii=E2;g)&9|-*9=|H4kHBQNSx*=)otS4dr2`x2P_$THH7;2OV8sJ( zTvQ;LPexW@S8CN#qMwSK;%-jROq2E;@#l8(Wh3!;q-@*n>R|mXgUl`$J%Dco;Jv4O&N)SkqZV!tD**Fg_-#;5ChEU#2Ji&E{K^W-!4JivvjJwo3 z4_uw^5)?K;_Uv<_>g{D;Ql|J+4xIc*ZsyP^>Pu-g+0*C8 zDOOV~eT`draJn<_J&Xzc{j~l?80LY^jccBkeo1Tk*{~r6Qznp=NO;VRoty7pdz1zw zE|7I=K}E*10Rt#(1S1R4DDL&pudz%XR58rEH$)C$n|BL52&#G&Vp|jVuF;BwUZ&Up zVXOB_#1M z>&l>dN7)46Z!pD@fnpTFo`adN93zprdsco9eA7MyvJ^Y^TdNi1dyc8E@=53cI0~Tkm?~Q zcaWj&)%gO>XZ%17`^ayNc>j6;8v$qXYG*v)-+|QxOwkah?(BlEnAl6iZ2*Z^MLEZ7 z(Tx>EF$<%A14+=LsJ0hnM^c=4{+YcWMh4T%6GRN|WX`1|CcM=fny=GwQOI@Rd*Th{ z2?W~3$&hLKGq-?P2stHrX@iF0IRZm^eC~-YU`Nb+>D4_;x=suK@w8^nXWL{h&tIDA ze|0`fD9E({RrzB&e{qK!(Usc1yMb;PLd1UK{mhUJd_F>`G>lyWK9o zh>aDFiHtj1u?DI+s)5euZxRK5zA?;kdt^E^w)gCD;=O+bOF%+It1{_Cm#)_$9| z`i~9rcVyPj4mo)F)82c$+lg1dB@ zDZD3$KS6+BeK!W`$TaJNB8Fl}j9H<7?74w?4{)Cb-36G7`ebL{qHOsi+(JsK|vWdu8Z@j3=9 zcTo1|^#ZI5RSwN#4G5s@mP?X;FLyk01ta8BlJaK=5!=rtqK%d+;iGHL+2cuHI_G z0VcK5-Ic7`p^2+GS#zAy0N-KP77Y44krapVG8!!kF>$c4m-QEC45G9fA7C#9{IT1W zKIDCRqN?G?gN%SIHYqRVD(th(po_cH-9!)Cv&iUQvGc@p{o^T(M>Ue4=Bt2u--h~fSKeHlC-TI^fp ze<6r%%uhci@`oW4+*O1JLPhlrx_@w>fl11#CItoC8;BXf*|{md@&Z22s`UhxxQYVF zc>$pC36$b8`dP#ORDEv@n`K)2L-Y-*`z<^lz_Fm=U=P~`#SwdY zu|T^A-zvF(e_s;*MfUc4KBfjP_?w<+Yi!xc)1g|a(uP$!T21^z>ZK@5Y%7|CFQnOzwXMB?x& z8PQ-a3|lhd!BxqKAZjq!;`8t04DrophIyoHhA=mjiBpgg!vj2x z&!02g5&qmNX+Qsd&TPeqB;(DW2jqYKhL6uTMBob(BOaN6Vc(1xGPD8D z48BwR^?)jT19-;p%zcBcKhFg256@hMe{M8YJ15@xjt2BGeaP#%d-8zbAD`H(UVypnq5k31pGxo5a2Jv}ECB(H>B3E*9O zg_t-S%&9o}Mci?32w<1|h8>^^BukVzkG(8o?}k6HU~7DAZDo(djgb-SzFUC&-$Vu@ zFMwFO8d=g*^)NQn*kHzdNp)5N%+>x~lIPCz2;=hT&$_~9bKFU|#zkaf#QBJ44uK43 zJ-Skbh3Ae$$C+*N_ysD09W0;7UJq|}S>CWht+3WKjCxM_41GaV*zwq$*-m29cj{pE zf#gjE999=<>$>}01t-D7d0q4A(cI@~GrJwS@b@(q{a_+(H=A$0&UqFLqT)Qcx-pE~ zfY-S(8MZL^u)^5XO%W}GEFXnJ-4LSy8@keMQiBU+0`0sAPVjnu_8mlYEPH9C+N5>;NgiivKLq}WVy;n|p^gj)xEO2dohm8Nw zx&DpH^1y~9nt-`L`?UmKH0wKhR^WeI zYnkwIxd5o`YpZny0dDnxde}7{*C)QM>87%m6ZhTE5yIi&SdbX{)dqfre0it&Xx zh@p&joRDP3)unmhgH`&y0kilBi9h)Iw*B|@_8hF~I`dLF-Zzv{l864Z!Bpzq)*UN( zkSzr8PV7;%ZMx5BVeq_3R2*}4%G|)G-ISUb)>wK3}Weg=ee?mvY3{>yYEFs&|R$Gi|xI4rHEAR2~WH zOSjd=H?g58F2j>yYH(oU)=Pu+(&>Z@D?S9zb6)w%Z94(DZVplL8FbTGd|h3tzA4o0 z`e?IfQzpalhMk=x#zsRj-|7q0y}5>SN*Z{2%j`R3mF+zku1yx)T)OEp!HJaN;O4Lm z79ae%0!dBqJUL!zO-&}{whZdqGqA-X1?&vmmQ3vZMrpgQ0GuRJ7HTvr$sI5nmv>t4 zm2)Wsv)nh+?)Y9`N9V{I1uD#;7q36Af~`Q4bfqT*P_tBK1i={~ zi{b*VNGkE|A%ztC9EG`FB1cLQa4@xi^iikeYvXnAUPA+0yiQAl9gj&&+&_}t{_%>` z9k))QDV)#z6|XB$-CwkK0Xu`sG|meNNpM$=-aW{Las&w+8QN{$Uv*MNj&>|sLuH@9 zM1x;#pv`x0EINWYTew{uXBj8nji0u_4u@pZ7BP3U*1X`>Ni^q{!=o$XayR!(dd-j` z``8L7BhMz8Je@<3F{~R|5>FPQZBx>QMU4S4)dRh2@+v+Z1=C~qF`iDV;yQ$Z=GI~V zJS?plr9zb=mA;VmfFoa5C&*_&KL6m&VBZms8_F{<6d~WYNM{ zP&11%9piU?!hPz7%l)b&%qhJdp(iwZ^Z>F3huTaSY{0>sh$Fq*hpCWVsK-Q7wKGu3 z%8Y?~F_U_jpZn(&!=mOw^T)@;@h_rAa>#yb2BlAzJn{P>kVR$-)op-E542JsqKJ3U zqS5l@sFpM=*aizXEfAKyo#!UA`l|z<=j>yrj8TsWFXf_0G{vIp;QD%`eGWODib^r! zb$=+llC)!LStuil>_k7<+4acNTkLGUC>dt%cNbgklz5ny-AEwY%cDj^-7F$757_cx zY(j~3O9sA@&bOqi+_kp4#r^(OuaFmKu+(yu*t{{q=a*XQU*)B)#vd2Qnu%}VA|j3P~f+Fd>4W92>9oePv(a2KzcY1 z#W?6B{s{1ZxXj9|0

-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 literal 0 HcmV?d00001 From 8c49a7b68f8c6523c9240e7d19259f3d6c8ea135 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Fri, 31 Mar 2017 22:33:18 -0400 Subject: [PATCH 02/16] Add composer.json --- composer.json | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 composer.json diff --git a/composer.json b/composer.json new file mode 100644 index 0000000000..b5c225e5b9 --- /dev/null +++ b/composer.json @@ -0,0 +1,32 @@ +{ + "name": "friendica/friendica", + "description": "A decentralized social network part of The Federation", + "type": "project", + "keywords": [ + "social network", + "dfrn", + "ostatus", + "diaspora" + ], + "licence": "GNU-Affero", + "support": { + "issues": "https://github.com/friendica/friendica/issues" + }, + "require": { + }, + "autoload": { + "psr-4": { + "Friendica\\": "include/" + } + }, + "config": { + "autoloader-suffix": "Friendica", + "optimize-autoloader": true, + "preferred-install": "dist" + }, + "archive": { + "exclude": [ + "log", "cache", "/photo", "/proxy" + ] + } +} \ No newline at end of file From cae0543629e522ababa2a6cd6fd98e3acb50ce60 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Fri, 31 Mar 2017 22:34:30 -0400 Subject: [PATCH 03/16] Composer: Add vendor directry - Add gitignore to avoid committing libraries' .git folder --- .gitignore | 3 + vendor/autoload.php | 7 + vendor/composer/ClassLoader.php | 445 ++++++++++++++++++++++++ vendor/composer/LICENSE | 21 ++ vendor/composer/autoload_classmap.php | 12 + vendor/composer/autoload_namespaces.php | 9 + vendor/composer/autoload_psr4.php | 10 + vendor/composer/autoload_real.php | 52 +++ vendor/composer/autoload_static.php | 38 ++ vendor/composer/installed.json | 1 + 10 files changed, 598 insertions(+) create mode 100644 vendor/autoload.php create mode 100644 vendor/composer/ClassLoader.php create mode 100644 vendor/composer/LICENSE create mode 100644 vendor/composer/autoload_classmap.php create mode 100644 vendor/composer/autoload_namespaces.php create mode 100644 vendor/composer/autoload_psr4.php create mode 100644 vendor/composer/autoload_real.php create mode 100644 vendor/composer/autoload_static.php create mode 100644 vendor/composer/installed.json diff --git a/.gitignore b/.gitignore index c78df3afc1..cd299f2d85 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,6 @@ nbproject #ignore things from transifex-client venv/ + +#ignore git projects in vendor +vendor/**/.git diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100644 index 0000000000..c40d3df89a --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath.'\\'; + if (isset($this->prefixDirsPsr4[$search])) { + foreach ($this->prefixDirsPsr4[$search] as $dir) { + $length = $this->prefixLengthsPsr4[$first][$search]; + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100644 index 0000000000..f27399a042 --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +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/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000000..52bd422c0a --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,12 @@ + $baseDir . '/include/Core/Config.php', + 'Friendica\\Core\\PConfig' => $baseDir . '/include/Core/PConfig.php', + 'Friendica\\ParseUrl' => $baseDir . '/include/ParseUrl.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000000..b7fc0125db --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($baseDir . '/include'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 0000000000..cb8c78eab7 --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,52 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require_once __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInitFriendica::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 0000000000..9136a25cac --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,38 @@ + + array ( + 'Friendica\\' => 10, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Friendica\\' => + array ( + 0 => __DIR__ . '/../..' . '/include', + ), + ); + + public static $classMap = array ( + 'Friendica\\Core\\Config' => __DIR__ . '/../..' . '/include/Core/Config.php', + 'Friendica\\Core\\PConfig' => __DIR__ . '/../..' . '/include/Core/PConfig.php', + 'Friendica\\ParseUrl' => __DIR__ . '/../..' . '/include/ParseUrl.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInitFriendica::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitFriendica::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitFriendica::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1 @@ +[] From 799e60aa6204a7244558ea60fcbf84600d8013f9 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Fri, 31 Mar 2017 23:02:38 -0400 Subject: [PATCH 04/16] Replace existing autoloader with Composer-supplied - Move Friendica namespace to `src` - Move required `ezyang/htmlpurifier` to vendor - Remove existing static autoloader - Change boot.php reference to the autoloader --- boot.php | 2 +- composer.json | 3 +- include/autoloader.php | 69 --- include/autoloader/ClassLoader.php | 413 ------------------ include/autoloader/LICENSE.composer | 19 - include/autoloader/autoload_classmap.php | 9 - include/autoloader/autoload_namespaces.php | 10 - include/autoloader/autoload_psr4.php | 10 - {include => src}/Core/Config.php | 0 {include => src}/Core/PConfig.php | 0 {include => src}/ParseUrl.php | 0 vendor/composer/autoload_classmap.php | 237 +++++++++- .../composer}/autoload_files.php | 2 +- vendor/composer/autoload_namespaces.php | 2 + vendor/composer/autoload_psr4.php | 2 +- vendor/composer/autoload_real.php | 18 + vendor/composer/autoload_static.php | 261 ++++++++++- vendor/composer/installed.json | 103 ++++- .../ezyang/htmlpurifier/CREDITS | 0 .../ezyang/htmlpurifier/INSTALL | 0 .../ezyang/htmlpurifier/INSTALL.fr.utf8 | 0 .../ezyang/htmlpurifier/LICENSE | 0 {library => vendor}/ezyang/htmlpurifier/NEWS | 0 .../ezyang/htmlpurifier/README | 0 {library => vendor}/ezyang/htmlpurifier/TODO | 0 .../ezyang/htmlpurifier/VERSION | 0 .../ezyang/htmlpurifier/WHATSNEW | 0 .../ezyang/htmlpurifier/WYSIWYG | 0 .../ezyang/htmlpurifier/composer.json | 0 .../extras/ConfigDoc/HTMLXSLTProcessor.php | 0 .../ezyang/htmlpurifier/extras/FSTools.php | 0 .../htmlpurifier/extras/FSTools/File.php | 0 .../extras/HTMLPurifierExtras.auto.php | 0 .../extras/HTMLPurifierExtras.autoload.php | 0 .../extras/HTMLPurifierExtras.php | 0 .../ezyang/htmlpurifier/extras/README | 0 .../library/HTMLPurifier.auto.php | 0 .../library/HTMLPurifier.autoload.php | 0 .../library/HTMLPurifier.composer.php | 0 .../library/HTMLPurifier.func.php | 0 .../library/HTMLPurifier.includes.php | 0 .../library/HTMLPurifier.kses.php | 0 .../library/HTMLPurifier.path.php | 0 .../htmlpurifier/library/HTMLPurifier.php | 0 .../library/HTMLPurifier.safe-includes.php | 0 .../library/HTMLPurifier/Arborize.php | 0 .../library/HTMLPurifier/AttrCollections.php | 0 .../library/HTMLPurifier/AttrDef.php | 0 .../library/HTMLPurifier/AttrDef/CSS.php | 0 .../HTMLPurifier/AttrDef/CSS/AlphaValue.php | 0 .../HTMLPurifier/AttrDef/CSS/Background.php | 0 .../AttrDef/CSS/BackgroundPosition.php | 0 .../HTMLPurifier/AttrDef/CSS/Border.php | 0 .../HTMLPurifier/AttrDef/CSS/Color.php | 0 .../HTMLPurifier/AttrDef/CSS/Composite.php | 0 .../AttrDef/CSS/DenyElementDecorator.php | 0 .../HTMLPurifier/AttrDef/CSS/Filter.php | 0 .../library/HTMLPurifier/AttrDef/CSS/Font.php | 0 .../HTMLPurifier/AttrDef/CSS/FontFamily.php | 0 .../HTMLPurifier/AttrDef/CSS/Ident.php | 0 .../AttrDef/CSS/ImportantDecorator.php | 0 .../HTMLPurifier/AttrDef/CSS/Length.php | 0 .../HTMLPurifier/AttrDef/CSS/ListStyle.php | 0 .../HTMLPurifier/AttrDef/CSS/Multiple.php | 0 .../HTMLPurifier/AttrDef/CSS/Number.php | 0 .../HTMLPurifier/AttrDef/CSS/Percentage.php | 0 .../AttrDef/CSS/TextDecoration.php | 0 .../library/HTMLPurifier/AttrDef/CSS/URI.php | 0 .../library/HTMLPurifier/AttrDef/Clone.php | 0 .../library/HTMLPurifier/AttrDef/Enum.php | 0 .../HTMLPurifier/AttrDef/HTML/Bool.php | 0 .../HTMLPurifier/AttrDef/HTML/Class.php | 0 .../HTMLPurifier/AttrDef/HTML/Color.php | 0 .../HTMLPurifier/AttrDef/HTML/FrameTarget.php | 0 .../library/HTMLPurifier/AttrDef/HTML/ID.php | 0 .../HTMLPurifier/AttrDef/HTML/Length.php | 0 .../HTMLPurifier/AttrDef/HTML/LinkTypes.php | 0 .../HTMLPurifier/AttrDef/HTML/MultiLength.php | 0 .../HTMLPurifier/AttrDef/HTML/Nmtokens.php | 0 .../HTMLPurifier/AttrDef/HTML/Pixels.php | 0 .../library/HTMLPurifier/AttrDef/Integer.php | 0 .../library/HTMLPurifier/AttrDef/Lang.php | 0 .../library/HTMLPurifier/AttrDef/Switch.php | 0 .../library/HTMLPurifier/AttrDef/Text.php | 0 .../library/HTMLPurifier/AttrDef/URI.php | 0 .../HTMLPurifier/AttrDef/URI/Email.php | 0 .../AttrDef/URI/Email/SimpleCheck.php | 0 .../library/HTMLPurifier/AttrDef/URI/Host.php | 0 .../library/HTMLPurifier/AttrDef/URI/IPv4.php | 0 .../library/HTMLPurifier/AttrDef/URI/IPv6.php | 0 .../library/HTMLPurifier/AttrTransform.php | 0 .../HTMLPurifier/AttrTransform/Background.php | 0 .../HTMLPurifier/AttrTransform/BdoDir.php | 0 .../HTMLPurifier/AttrTransform/BgColor.php | 0 .../HTMLPurifier/AttrTransform/BoolToCSS.php | 0 .../HTMLPurifier/AttrTransform/Border.php | 0 .../HTMLPurifier/AttrTransform/EnumToCSS.php | 0 .../AttrTransform/ImgRequired.php | 0 .../HTMLPurifier/AttrTransform/ImgSpace.php | 0 .../HTMLPurifier/AttrTransform/Input.php | 0 .../HTMLPurifier/AttrTransform/Lang.php | 0 .../HTMLPurifier/AttrTransform/Length.php | 0 .../HTMLPurifier/AttrTransform/Name.php | 0 .../HTMLPurifier/AttrTransform/NameSync.php | 0 .../HTMLPurifier/AttrTransform/Nofollow.php | 0 .../HTMLPurifier/AttrTransform/SafeEmbed.php | 0 .../HTMLPurifier/AttrTransform/SafeObject.php | 0 .../HTMLPurifier/AttrTransform/SafeParam.php | 0 .../AttrTransform/ScriptRequired.php | 0 .../AttrTransform/TargetBlank.php | 0 .../HTMLPurifier/AttrTransform/Textarea.php | 0 .../library/HTMLPurifier/AttrTypes.php | 0 .../library/HTMLPurifier/AttrValidator.php | 0 .../library/HTMLPurifier/Bootstrap.php | 0 .../library/HTMLPurifier/CSSDefinition.php | 0 .../library/HTMLPurifier/ChildDef.php | 0 .../HTMLPurifier/ChildDef/Chameleon.php | 0 .../library/HTMLPurifier/ChildDef/Custom.php | 0 .../library/HTMLPurifier/ChildDef/Empty.php | 0 .../library/HTMLPurifier/ChildDef/List.php | 0 .../HTMLPurifier/ChildDef/Optional.php | 0 .../HTMLPurifier/ChildDef/Required.php | 0 .../ChildDef/StrictBlockquote.php | 0 .../library/HTMLPurifier/ChildDef/Table.php | 0 .../library/HTMLPurifier/Config.php | 0 .../library/HTMLPurifier/ConfigSchema.php | 0 .../ConfigSchema/Builder/ConfigSchema.php | 0 .../HTMLPurifier/ConfigSchema/Builder/Xml.php | 0 .../HTMLPurifier/ConfigSchema/Exception.php | 0 .../HTMLPurifier/ConfigSchema/Interchange.php | 0 .../ConfigSchema/Interchange/Directive.php | 0 .../ConfigSchema/Interchange/Id.php | 0 .../ConfigSchema/InterchangeBuilder.php | 0 .../HTMLPurifier/ConfigSchema/Validator.php | 0 .../ConfigSchema/ValidatorAtom.php | 0 .../HTMLPurifier/ConfigSchema/schema.ser | Bin .../schema/Attr.AllowedClasses.txt | 0 .../schema/Attr.AllowedFrameTargets.txt | 0 .../ConfigSchema/schema/Attr.AllowedRel.txt | 0 .../ConfigSchema/schema/Attr.AllowedRev.txt | 0 .../schema/Attr.ClassUseCDATA.txt | 0 .../schema/Attr.DefaultImageAlt.txt | 0 .../schema/Attr.DefaultInvalidImage.txt | 0 .../schema/Attr.DefaultInvalidImageAlt.txt | 0 .../schema/Attr.DefaultTextDir.txt | 0 .../ConfigSchema/schema/Attr.EnableID.txt | 0 .../schema/Attr.ForbiddenClasses.txt | 0 .../ConfigSchema/schema/Attr.IDBlacklist.txt | 0 .../schema/Attr.IDBlacklistRegexp.txt | 0 .../ConfigSchema/schema/Attr.IDPrefix.txt | 0 .../schema/Attr.IDPrefixLocal.txt | 0 .../schema/AutoFormat.AutoParagraph.txt | 0 .../ConfigSchema/schema/AutoFormat.Custom.txt | 0 .../schema/AutoFormat.DisplayLinkURI.txt | 0 .../schema/AutoFormat.Linkify.txt | 0 .../AutoFormat.PurifierLinkify.DocURL.txt | 0 .../schema/AutoFormat.PurifierLinkify.txt | 0 .../AutoFormat.RemoveEmpty.Predicate.txt | 0 ...rmat.RemoveEmpty.RemoveNbsp.Exceptions.txt | 0 .../AutoFormat.RemoveEmpty.RemoveNbsp.txt | 0 .../schema/AutoFormat.RemoveEmpty.txt | 0 ...utoFormat.RemoveSpansWithoutAttributes.txt | 0 .../schema/CSS.AllowImportant.txt | 0 .../ConfigSchema/schema/CSS.AllowTricky.txt | 0 .../ConfigSchema/schema/CSS.AllowedFonts.txt | 0 .../schema/CSS.AllowedProperties.txt | 0 .../ConfigSchema/schema/CSS.DefinitionRev.txt | 0 .../schema/CSS.ForbiddenProperties.txt | 0 .../ConfigSchema/schema/CSS.MaxImgLength.txt | 0 .../ConfigSchema/schema/CSS.Proprietary.txt | 0 .../ConfigSchema/schema/CSS.Trusted.txt | 0 .../schema/Cache.DefinitionImpl.txt | 0 .../schema/Cache.SerializerPath.txt | 0 .../schema/Cache.SerializerPermissions.txt | 0 .../schema/Core.AggressivelyFixLt.txt | 0 .../schema/Core.AllowHostnameUnderscore.txt | 0 .../schema/Core.CollectErrors.txt | 0 .../schema/Core.ColorKeywords.txt | 0 .../schema/Core.ConvertDocumentToFragment.txt | 0 .../Core.DirectLexLineNumberSyncInterval.txt | 0 .../schema/Core.DisableExcludes.txt | 0 .../ConfigSchema/schema/Core.EnableIDNA.txt | 0 .../ConfigSchema/schema/Core.Encoding.txt | 0 .../schema/Core.EscapeInvalidChildren.txt | 0 .../schema/Core.EscapeInvalidTags.txt | 0 .../schema/Core.EscapeNonASCIICharacters.txt | 0 .../schema/Core.HiddenElements.txt | 0 .../ConfigSchema/schema/Core.Language.txt | 0 .../ConfigSchema/schema/Core.LexerImpl.txt | 0 .../schema/Core.MaintainLineNumbers.txt | 0 .../schema/Core.NormalizeNewlines.txt | 0 .../schema/Core.RemoveInvalidImg.txt | 0 .../Core.RemoveProcessingInstructions.txt | 0 .../schema/Core.RemoveScriptContents.txt | 0 .../ConfigSchema/schema/Filter.Custom.txt | 0 .../Filter.ExtractStyleBlocks.Escaping.txt | 0 .../Filter.ExtractStyleBlocks.Scope.txt | 0 .../Filter.ExtractStyleBlocks.TidyImpl.txt | 0 .../schema/Filter.ExtractStyleBlocks.txt | 0 .../ConfigSchema/schema/Filter.YouTube.txt | 0 .../ConfigSchema/schema/HTML.Allowed.txt | 0 .../schema/HTML.AllowedAttributes.txt | 0 .../schema/HTML.AllowedComments.txt | 0 .../schema/HTML.AllowedCommentsRegexp.txt | 0 .../schema/HTML.AllowedElements.txt | 0 .../schema/HTML.AllowedModules.txt | 0 .../schema/HTML.Attr.Name.UseCDATA.txt | 0 .../ConfigSchema/schema/HTML.BlockWrapper.txt | 0 .../ConfigSchema/schema/HTML.CoreModules.txt | 0 .../schema/HTML.CustomDoctype.txt | 0 .../ConfigSchema/schema/HTML.DefinitionID.txt | 0 .../schema/HTML.DefinitionRev.txt | 0 .../ConfigSchema/schema/HTML.Doctype.txt | 0 .../schema/HTML.FlashAllowFullScreen.txt | 0 .../schema/HTML.ForbiddenAttributes.txt | 0 .../schema/HTML.ForbiddenElements.txt | 0 .../ConfigSchema/schema/HTML.MaxImgLength.txt | 0 .../ConfigSchema/schema/HTML.Nofollow.txt | 0 .../ConfigSchema/schema/HTML.Parent.txt | 0 .../ConfigSchema/schema/HTML.Proprietary.txt | 0 .../ConfigSchema/schema/HTML.SafeEmbed.txt | 0 .../ConfigSchema/schema/HTML.SafeIframe.txt | 0 .../ConfigSchema/schema/HTML.SafeObject.txt | 0 .../schema/HTML.SafeScripting.txt | 0 .../ConfigSchema/schema/HTML.Strict.txt | 0 .../ConfigSchema/schema/HTML.TargetBlank.txt | 0 .../ConfigSchema/schema/HTML.TidyAdd.txt | 0 .../ConfigSchema/schema/HTML.TidyLevel.txt | 0 .../ConfigSchema/schema/HTML.TidyRemove.txt | 0 .../ConfigSchema/schema/HTML.Trusted.txt | 0 .../ConfigSchema/schema/HTML.XHTML.txt | 0 .../schema/Output.CommentScriptContents.txt | 0 .../schema/Output.FixInnerHTML.txt | 0 .../schema/Output.FlashCompat.txt | 0 .../ConfigSchema/schema/Output.Newline.txt | 0 .../ConfigSchema/schema/Output.SortAttr.txt | 0 .../ConfigSchema/schema/Output.TidyFormat.txt | 0 .../ConfigSchema/schema/Test.ForceNoIconv.txt | 0 .../schema/URI.AllowedSchemes.txt | 0 .../ConfigSchema/schema/URI.Base.txt | 0 .../ConfigSchema/schema/URI.DefaultScheme.txt | 0 .../ConfigSchema/schema/URI.DefinitionID.txt | 0 .../ConfigSchema/schema/URI.DefinitionRev.txt | 0 .../ConfigSchema/schema/URI.Disable.txt | 0 .../schema/URI.DisableExternal.txt | 0 .../schema/URI.DisableExternalResources.txt | 0 .../schema/URI.DisableResources.txt | 0 .../ConfigSchema/schema/URI.Host.txt | 0 .../ConfigSchema/schema/URI.HostBlacklist.txt | 0 .../ConfigSchema/schema/URI.MakeAbsolute.txt | 0 .../ConfigSchema/schema/URI.Munge.txt | 0 .../schema/URI.MungeResources.txt | 0 .../schema/URI.MungeSecretKey.txt | 0 .../schema/URI.OverrideAllowedSchemes.txt | 0 .../schema/URI.SafeIframeRegexp.txt | 0 .../HTMLPurifier/ConfigSchema/schema/info.ini | 0 .../library/HTMLPurifier/ContentSets.php | 0 .../library/HTMLPurifier/Context.php | 0 .../library/HTMLPurifier/Definition.php | 0 .../library/HTMLPurifier/DefinitionCache.php | 0 .../DefinitionCache/Decorator.php | 0 .../DefinitionCache/Decorator/Cleanup.php | 0 .../DefinitionCache/Decorator/Memory.php | 0 .../DefinitionCache/Decorator/Template.php.in | 0 .../HTMLPurifier/DefinitionCache/Null.php | 0 .../DefinitionCache/Serializer.php | 0 .../DefinitionCache/Serializer/README | 0 .../HTMLPurifier/DefinitionCacheFactory.php | 0 .../library/HTMLPurifier/Doctype.php | 0 .../library/HTMLPurifier/DoctypeRegistry.php | 0 .../library/HTMLPurifier/ElementDef.php | 0 .../library/HTMLPurifier/Encoder.php | 0 .../library/HTMLPurifier/EntityLookup.php | 0 .../HTMLPurifier/EntityLookup/entities.ser | 0 .../library/HTMLPurifier/EntityParser.php | 0 .../library/HTMLPurifier/ErrorCollector.php | 0 .../library/HTMLPurifier/ErrorStruct.php | 0 .../library/HTMLPurifier/Exception.php | 0 .../library/HTMLPurifier/Filter.php | 0 .../Filter/ExtractStyleBlocks.php | 0 .../library/HTMLPurifier/Filter/YouTube.php | 0 .../library/HTMLPurifier/Generator.php | 0 .../library/HTMLPurifier/HTMLDefinition.php | 0 .../library/HTMLPurifier/HTMLModule.php | 0 .../library/HTMLPurifier/HTMLModule/Bdo.php | 0 .../HTMLModule/CommonAttributes.php | 0 .../library/HTMLPurifier/HTMLModule/Edit.php | 0 .../library/HTMLPurifier/HTMLModule/Forms.php | 0 .../HTMLPurifier/HTMLModule/Hypertext.php | 0 .../HTMLPurifier/HTMLModule/Iframe.php | 0 .../library/HTMLPurifier/HTMLModule/Image.php | 0 .../HTMLPurifier/HTMLModule/Legacy.php | 0 .../library/HTMLPurifier/HTMLModule/List.php | 0 .../library/HTMLPurifier/HTMLModule/Name.php | 0 .../HTMLPurifier/HTMLModule/Nofollow.php | 0 .../HTMLModule/NonXMLCommonAttributes.php | 0 .../HTMLPurifier/HTMLModule/Object.php | 0 .../HTMLPurifier/HTMLModule/Presentation.php | 0 .../HTMLPurifier/HTMLModule/Proprietary.php | 0 .../library/HTMLPurifier/HTMLModule/Ruby.php | 0 .../HTMLPurifier/HTMLModule/SafeEmbed.php | 0 .../HTMLPurifier/HTMLModule/SafeObject.php | 0 .../HTMLPurifier/HTMLModule/SafeScripting.php | 0 .../HTMLPurifier/HTMLModule/Scripting.php | 0 .../HTMLModule/StyleAttribute.php | 0 .../HTMLPurifier/HTMLModule/Tables.php | 0 .../HTMLPurifier/HTMLModule/Target.php | 0 .../HTMLPurifier/HTMLModule/TargetBlank.php | 0 .../library/HTMLPurifier/HTMLModule/Text.php | 0 .../library/HTMLPurifier/HTMLModule/Tidy.php | 0 .../HTMLPurifier/HTMLModule/Tidy/Name.php | 0 .../HTMLModule/Tidy/Proprietary.php | 0 .../HTMLPurifier/HTMLModule/Tidy/Strict.php | 0 .../HTMLModule/Tidy/Transitional.php | 0 .../HTMLPurifier/HTMLModule/Tidy/XHTML.php | 0 .../HTMLModule/Tidy/XHTMLAndHTML4.php | 0 .../HTMLModule/XMLCommonAttributes.php | 0 .../HTMLPurifier/HTMLModuleManager.php | 0 .../library/HTMLPurifier/IDAccumulator.php | 0 .../library/HTMLPurifier/Injector.php | 0 .../HTMLPurifier/Injector/AutoParagraph.php | 0 .../HTMLPurifier/Injector/DisplayLinkURI.php | 0 .../library/HTMLPurifier/Injector/Linkify.php | 0 .../HTMLPurifier/Injector/PurifierLinkify.php | 0 .../HTMLPurifier/Injector/RemoveEmpty.php | 0 .../Injector/RemoveSpansWithoutAttributes.php | 0 .../HTMLPurifier/Injector/SafeObject.php | 0 .../library/HTMLPurifier/Language.php | 0 .../Language/classes/en-x-test.php | 0 .../Language/messages/en-x-test.php | 0 .../Language/messages/en-x-testmini.php | 0 .../HTMLPurifier/Language/messages/en.php | 0 .../library/HTMLPurifier/LanguageFactory.php | 0 .../library/HTMLPurifier/Length.php | 0 .../library/HTMLPurifier/Lexer.php | 0 .../library/HTMLPurifier/Lexer/DOMLex.php | 0 .../library/HTMLPurifier/Lexer/DirectLex.php | 0 .../library/HTMLPurifier/Lexer/PH5P.php | 0 .../library/HTMLPurifier/Node.php | 0 .../library/HTMLPurifier/Node/Comment.php | 0 .../library/HTMLPurifier/Node/Element.php | 0 .../library/HTMLPurifier/Node/Text.php | 0 .../library/HTMLPurifier/PercentEncoder.php | 0 .../library/HTMLPurifier/Printer.php | 0 .../HTMLPurifier/Printer/CSSDefinition.php | 0 .../HTMLPurifier/Printer/ConfigForm.css | 0 .../HTMLPurifier/Printer/ConfigForm.js | 0 .../HTMLPurifier/Printer/ConfigForm.php | 0 .../HTMLPurifier/Printer/HTMLDefinition.php | 0 .../library/HTMLPurifier/PropertyList.php | 0 .../HTMLPurifier/PropertyListIterator.php | 0 .../library/HTMLPurifier/Queue.php | 0 .../library/HTMLPurifier/Strategy.php | 0 .../HTMLPurifier/Strategy/Composite.php | 0 .../library/HTMLPurifier/Strategy/Core.php | 0 .../HTMLPurifier/Strategy/FixNesting.php | 0 .../HTMLPurifier/Strategy/MakeWellFormed.php | 0 .../Strategy/RemoveForeignElements.php | 0 .../Strategy/ValidateAttributes.php | 0 .../library/HTMLPurifier/StringHash.php | 0 .../library/HTMLPurifier/StringHashParser.php | 0 .../library/HTMLPurifier/TagTransform.php | 0 .../HTMLPurifier/TagTransform/Font.php | 0 .../HTMLPurifier/TagTransform/Simple.php | 0 .../library/HTMLPurifier/Token.php | 0 .../library/HTMLPurifier/Token/Comment.php | 0 .../library/HTMLPurifier/Token/Empty.php | 0 .../library/HTMLPurifier/Token/End.php | 0 .../library/HTMLPurifier/Token/Start.php | 0 .../library/HTMLPurifier/Token/Tag.php | 0 .../library/HTMLPurifier/Token/Text.php | 0 .../library/HTMLPurifier/TokenFactory.php | 0 .../htmlpurifier/library/HTMLPurifier/URI.php | 0 .../library/HTMLPurifier/URIDefinition.php | 0 .../library/HTMLPurifier/URIFilter.php | 0 .../URIFilter/DisableExternal.php | 0 .../URIFilter/DisableExternalResources.php | 0 .../URIFilter/DisableResources.php | 0 .../HTMLPurifier/URIFilter/HostBlacklist.php | 0 .../HTMLPurifier/URIFilter/MakeAbsolute.php | 0 .../library/HTMLPurifier/URIFilter/Munge.php | 0 .../HTMLPurifier/URIFilter/SafeIframe.php | 0 .../library/HTMLPurifier/URIParser.php | 0 .../library/HTMLPurifier/URIScheme.php | 0 .../library/HTMLPurifier/URIScheme/data.php | 0 .../library/HTMLPurifier/URIScheme/file.php | 0 .../library/HTMLPurifier/URIScheme/ftp.php | 0 .../library/HTMLPurifier/URIScheme/http.php | 0 .../library/HTMLPurifier/URIScheme/https.php | 0 .../library/HTMLPurifier/URIScheme/mailto.php | 0 .../library/HTMLPurifier/URIScheme/news.php | 0 .../library/HTMLPurifier/URIScheme/nntp.php | 0 .../HTMLPurifier/URISchemeRegistry.php | 0 .../library/HTMLPurifier/UnitConverter.php | 0 .../library/HTMLPurifier/VarParser.php | 0 .../HTMLPurifier/VarParser/Flexible.php | 0 .../library/HTMLPurifier/VarParser/Native.php | 0 .../HTMLPurifier/VarParserException.php | 0 .../library/HTMLPurifier/Zipper.php | 0 .../ezyang/htmlpurifier/package.php | 0 .../ezyang/htmlpurifier/phpdoc.ini | 0 .../ezyang/htmlpurifier/plugins/modx.txt | 0 .../htmlpurifier/plugins/phorum/.gitignore | 0 .../htmlpurifier/plugins/phorum/Changelog | 0 .../htmlpurifier/plugins/phorum/INSTALL | 0 .../ezyang/htmlpurifier/plugins/phorum/README | 0 .../plugins/phorum/config.default.php | 0 .../plugins/phorum/htmlpurifier.php | 0 .../htmlpurifier/plugins/phorum/info.txt | 0 .../plugins/phorum/init-config.php | 0 .../plugins/phorum/migrate.bbcode.php | 0 .../htmlpurifier/plugins/phorum/settings.php | 0 .../plugins/phorum/settings/form.php | 0 .../phorum/settings/migrate-sigs-form.php | 0 .../plugins/phorum/settings/migrate-sigs.php | 0 .../plugins/phorum/settings/save.php | 0 .../ezyang/htmlpurifier/release1-update.php | 0 .../ezyang/htmlpurifier/release2-tag.php | 0 .../htmlpurifier/test-settings.sample.php | 0 419 files changed, 618 insertions(+), 542 deletions(-) delete mode 100644 include/autoloader.php delete mode 100644 include/autoloader/ClassLoader.php delete mode 100644 include/autoloader/LICENSE.composer delete mode 100644 include/autoloader/autoload_classmap.php delete mode 100644 include/autoloader/autoload_namespaces.php delete mode 100644 include/autoloader/autoload_psr4.php rename {include => src}/Core/Config.php (100%) rename {include => src}/Core/PConfig.php (100%) rename {include => src}/ParseUrl.php (100%) rename {include/autoloader => vendor/composer}/autoload_files.php (77%) rename {library => vendor}/ezyang/htmlpurifier/CREDITS (100%) rename {library => vendor}/ezyang/htmlpurifier/INSTALL (100%) rename {library => vendor}/ezyang/htmlpurifier/INSTALL.fr.utf8 (100%) rename {library => vendor}/ezyang/htmlpurifier/LICENSE (100%) rename {library => vendor}/ezyang/htmlpurifier/NEWS (100%) rename {library => vendor}/ezyang/htmlpurifier/README (100%) rename {library => vendor}/ezyang/htmlpurifier/TODO (100%) rename {library => vendor}/ezyang/htmlpurifier/VERSION (100%) rename {library => vendor}/ezyang/htmlpurifier/WHATSNEW (100%) rename {library => vendor}/ezyang/htmlpurifier/WYSIWYG (100%) rename {library => vendor}/ezyang/htmlpurifier/composer.json (100%) rename {library => vendor}/ezyang/htmlpurifier/extras/ConfigDoc/HTMLXSLTProcessor.php (100%) rename {library => vendor}/ezyang/htmlpurifier/extras/FSTools.php (100%) rename {library => vendor}/ezyang/htmlpurifier/extras/FSTools/File.php (100%) rename {library => vendor}/ezyang/htmlpurifier/extras/HTMLPurifierExtras.auto.php (100%) rename {library => vendor}/ezyang/htmlpurifier/extras/HTMLPurifierExtras.autoload.php (100%) rename {library => vendor}/ezyang/htmlpurifier/extras/HTMLPurifierExtras.php (100%) rename {library => vendor}/ezyang/htmlpurifier/extras/README (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier.auto.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier.autoload.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier.composer.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier.func.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier.includes.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier.kses.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier.path.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Background.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Length.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeObject.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeParam.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Textarea.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/List.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Config.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Context.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Null.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Filter.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Scripting.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/StyleAttribute.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tables.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Target.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/TargetBlank.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Text.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Name.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Strict.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Transitional.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTML.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModuleManager.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/IDAccumulator.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Injector.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Injector/AutoParagraph.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Injector/DisplayLinkURI.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Injector/Linkify.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Injector/PurifierLinkify.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveEmpty.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Injector/SafeObject.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Language.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Language/classes/en-x-test.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en-x-test.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en-x-testmini.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/LanguageFactory.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Length.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Lexer.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DirectLex.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Node.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Node/Comment.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Composite.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/RemoveForeignElements.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/ValidateAttributes.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/StringHash.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/StringHashParser.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Font.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Simple.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Token.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Token/Comment.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Token/Empty.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Token/End.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Token/Start.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Token/Tag.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Token/Text.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/TokenFactory.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URI.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIDefinition.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternal.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternalResources.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableResources.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/HostBlacklist.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/MakeAbsolute.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/Munge.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/SafeIframe.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIParser.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/data.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/file.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/ftp.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/http.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/https.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/mailto.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/news.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/nntp.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/URISchemeRegistry.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/UnitConverter.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/VarParserException.php (100%) rename {library => vendor}/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php (100%) rename {library => vendor}/ezyang/htmlpurifier/package.php (100%) rename {library => vendor}/ezyang/htmlpurifier/phpdoc.ini (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/modx.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/.gitignore (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/Changelog (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/INSTALL (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/README (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/config.default.php (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/htmlpurifier.php (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/info.txt (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/init-config.php (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/migrate.bbcode.php (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/settings.php (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/settings/form.php (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/settings/migrate-sigs-form.php (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/settings/migrate-sigs.php (100%) rename {library => vendor}/ezyang/htmlpurifier/plugins/phorum/settings/save.php (100%) rename {library => vendor}/ezyang/htmlpurifier/release1-update.php (100%) rename {library => vendor}/ezyang/htmlpurifier/release2-tag.php (100%) rename {library => vendor}/ezyang/htmlpurifier/test-settings.sample.php (100%) diff --git a/boot.php b/boot.php index 6f036d846e..fc851eca51 100644 --- a/boot.php +++ b/boot.php @@ -17,7 +17,7 @@ * easily as email does today. */ -require_once('include/autoloader.php'); +require_once(__DIR__ . DIRECTORY_SEPARATOR. 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php'); use \Friendica\Core\Config; diff --git a/composer.json b/composer.json index b5c225e5b9..b3a1e8441e 100644 --- a/composer.json +++ b/composer.json @@ -13,10 +13,11 @@ "issues": "https://github.com/friendica/friendica/issues" }, "require": { + "ezyang/htmlpurifier": "~4.7.0" }, "autoload": { "psr-4": { - "Friendica\\": "include/" + "Friendica\\": "src/" } }, "config": { diff --git a/include/autoloader.php b/include/autoloader.php deleted file mode 100644 index 6caa082915..0000000000 --- a/include/autoloader.php +++ /dev/null @@ -1,69 +0,0 @@ - $path) { - $loader->set($namespace, $path); - } - - $map = require __DIR__ . '/autoloader/autoload_psr4.php'; - foreach ($map as $namespace => $path) { - $loader->setPsr4($namespace, $path); - } - - $classMap = require __DIR__ . '/autoloader/autoload_classmap.php'; - if ($classMap) { - $loader->addClassMap($classMap); - } - - $loader->register(true); - - $includeFiles = require __DIR__ . '/autoloader/autoload_files.php'; - foreach ($includeFiles as $fileIdentifier => $file) { - friendicaRequire($fileIdentifier, $file); - } - - - return $loader; - } -} - -function friendicaRequire($fileIdentifier, $file) -{ - if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - require $file; - - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; - } -} - - - -return FriendicaAutoloaderInit::getLoader(); diff --git a/include/autoloader/ClassLoader.php b/include/autoloader/ClassLoader.php deleted file mode 100644 index d916d802fe..0000000000 --- a/include/autoloader/ClassLoader.php +++ /dev/null @@ -1,413 +0,0 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE.composer - * file that was distributed with this source code. - */ - -namespace Composer\Autoload; - -/** - * ClassLoader implements a PSR-0 class loader - * - * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md - * - * $loader = new \Composer\Autoload\ClassLoader(); - * - * // register classes with namespaces - * $loader->add('Symfony\Component', __DIR__.'/component'); - * $loader->add('Symfony', __DIR__.'/framework'); - * - * // activate the autoloader - * $loader->register(); - * - * // to enable searching the include path (eg. for PEAR packages) - * $loader->setUseIncludePath(true); - * - * In this example, if you try to use a class in the Symfony\Component - * namespace or one of its children (Symfony\Component\Console for instance), - * the autoloader will first look for the class under the component/ - * directory, and it will then fallback to the framework/ directory if not - * found before giving up. - * - * This class is loosely based on the Symfony UniversalClassLoader. - * - * @author Fabien Potencier - * @author Jordi Boggiano - */ -class ClassLoader -{ - // PSR-4 - private $prefixLengthsPsr4 = array(); - private $prefixDirsPsr4 = array(); - private $fallbackDirsPsr4 = array(); - - // PSR-0 - private $prefixesPsr0 = array(); - private $fallbackDirsPsr0 = array(); - - private $useIncludePath = false; - private $classMap = array(); - - private $classMapAuthoritative = false; - - public function getPrefixes() - { - if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', $this->prefixesPsr0); - } - - return array(); - } - - public function getPrefixesPsr4() - { - return $this->prefixDirsPsr4; - } - - public function getFallbackDirs() - { - return $this->fallbackDirsPsr0; - } - - public function getFallbackDirsPsr4() - { - return $this->fallbackDirsPsr4; - } - - public function getClassMap() - { - return $this->classMap; - } - - /** - * @param array $classMap Class to filename map - */ - public function addClassMap(array $classMap) - { - if ($this->classMap) { - $this->classMap = array_merge($this->classMap, $classMap); - } else { - $this->classMap = $classMap; - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, either - * appending or prepending to the ones previously set for this prefix. - * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories - */ - public function add($prefix, $paths, $prepend = false) - { - if (!$prefix) { - if ($prepend) { - $this->fallbackDirsPsr0 = array_merge( - (array) $paths, - $this->fallbackDirsPsr0 - ); - } else { - $this->fallbackDirsPsr0 = array_merge( - $this->fallbackDirsPsr0, - (array) $paths - ); - } - - return; - } - - $first = $prefix[0]; - if (!isset($this->prefixesPsr0[$first][$prefix])) { - $this->prefixesPsr0[$first][$prefix] = (array) $paths; - - return; - } - if ($prepend) { - $this->prefixesPsr0[$first][$prefix] = array_merge( - (array) $paths, - $this->prefixesPsr0[$first][$prefix] - ); - } else { - $this->prefixesPsr0[$first][$prefix] = array_merge( - $this->prefixesPsr0[$first][$prefix], - (array) $paths - ); - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, either - * appending or prepending to the ones previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-0 base directories - * @param bool $prepend Whether to prepend the directories - * - * @throws \InvalidArgumentException - */ - public function addPsr4($prefix, $paths, $prepend = false) - { - if (!$prefix) { - // Register directories for the root namespace. - if ($prepend) { - $this->fallbackDirsPsr4 = array_merge( - (array) $paths, - $this->fallbackDirsPsr4 - ); - } else { - $this->fallbackDirsPsr4 = array_merge( - $this->fallbackDirsPsr4, - (array) $paths - ); - } - } elseif (!isset($this->prefixDirsPsr4[$prefix])) { - // Register directories for a new namespace. - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } elseif ($prepend) { - // Prepend directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - (array) $paths, - $this->prefixDirsPsr4[$prefix] - ); - } else { - // Append directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - $this->prefixDirsPsr4[$prefix], - (array) $paths - ); - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, - * replacing any others previously set for this prefix. - * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 base directories - */ - public function set($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr0 = (array) $paths; - } else { - $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, - * replacing any others previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories - * - * @throws \InvalidArgumentException - */ - public function setPsr4($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr4 = (array) $paths; - } else { - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } - } - - /** - * Turns on searching the include path for class files. - * - * @param bool $useIncludePath - */ - public function setUseIncludePath($useIncludePath) - { - $this->useIncludePath = $useIncludePath; - } - - /** - * Can be used to check if the autoloader uses the include path to check - * for classes. - * - * @return bool - */ - public function getUseIncludePath() - { - return $this->useIncludePath; - } - - /** - * Turns off searching the prefix and fallback directories for classes - * that have not been registered with the class map. - * - * @param bool $classMapAuthoritative - */ - public function setClassMapAuthoritative($classMapAuthoritative) - { - $this->classMapAuthoritative = $classMapAuthoritative; - } - - /** - * Should class lookup fail if not found in the current class map? - * - * @return bool - */ - public function isClassMapAuthoritative() - { - return $this->classMapAuthoritative; - } - - /** - * Registers this instance as an autoloader. - * - * @param bool $prepend Whether to prepend the autoloader or not - */ - public function register($prepend = false) - { - spl_autoload_register(array($this, 'loadClass'), true, $prepend); - } - - /** - * Unregisters this instance as an autoloader. - */ - public function unregister() - { - spl_autoload_unregister(array($this, 'loadClass')); - } - - /** - * Loads the given class or interface. - * - * @param string $class The name of the class - * @return bool|null True if loaded, null otherwise - */ - public function loadClass($class) - { - if ($file = $this->findFile($class)) { - includeFile($file); - - return true; - } - } - - /** - * Finds the path to the file where the class is defined. - * - * @param string $class The name of the class - * - * @return string|false The path if found, false otherwise - */ - public function findFile($class) - { - // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 - if ('\\' == $class[0]) { - $class = substr($class, 1); - } - - // class map lookup - if (isset($this->classMap[$class])) { - return $this->classMap[$class]; - } - if ($this->classMapAuthoritative) { - return false; - } - - $file = $this->findFileWithExtension($class, '.php'); - - // Search for Hack files if we are running on HHVM - if ($file === null && defined('HHVM_VERSION')) { - $file = $this->findFileWithExtension($class, '.hh'); - } - - if ($file === null) { - // Remember that this class does not exist. - return $this->classMap[$class] = false; - } - - return $file; - } - - private function findFileWithExtension($class, $ext) - { - // PSR-4 lookup - $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; - - $first = $class[0]; - if (isset($this->prefixLengthsPsr4[$first])) { - foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { - if (0 === strpos($class, $prefix)) { - foreach ($this->prefixDirsPsr4[$prefix] as $dir) { - if (is_file($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { - return $file; - } - } - } - } - } - - // PSR-4 fallback dirs - foreach ($this->fallbackDirsPsr4 as $dir) { - if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { - return $file; - } - } - - // PSR-0 lookup - if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name - $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) - . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); - } else { - // PEAR-like class name - $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; - } - - if (isset($this->prefixesPsr0[$first])) { - foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { - if (0 === strpos($class, $prefix)) { - foreach ($dirs as $dir) { - if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - } - } - } - - // PSR-0 fallback dirs - foreach ($this->fallbackDirsPsr0 as $dir) { - if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - - // PSR-0 include paths. - if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { - return $file; - } - } -} - -/** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - */ -function includeFile($file) -{ - include $file; -} diff --git a/include/autoloader/LICENSE.composer b/include/autoloader/LICENSE.composer deleted file mode 100644 index b365b1f5a7..0000000000 --- a/include/autoloader/LICENSE.composer +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2015 Nils Adermann, Jordi Boggiano - -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, andor 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. \ No newline at end of file diff --git a/include/autoloader/autoload_classmap.php b/include/autoloader/autoload_classmap.php deleted file mode 100644 index 3efd09fc69..0000000000 --- a/include/autoloader/autoload_classmap.php +++ /dev/null @@ -1,9 +0,0 @@ - array($vendorDir . '/ezyang/htmlpurifier/library'), -); diff --git a/include/autoloader/autoload_psr4.php b/include/autoloader/autoload_psr4.php deleted file mode 100644 index d000ea28f6..0000000000 --- a/include/autoloader/autoload_psr4.php +++ /dev/null @@ -1,10 +0,0 @@ - array($baseDir . '/include'), -); diff --git a/include/Core/Config.php b/src/Core/Config.php similarity index 100% rename from include/Core/Config.php rename to src/Core/Config.php diff --git a/include/Core/PConfig.php b/src/Core/PConfig.php similarity index 100% rename from include/Core/PConfig.php rename to src/Core/PConfig.php diff --git a/include/ParseUrl.php b/src/ParseUrl.php similarity index 100% rename from include/ParseUrl.php rename to src/ParseUrl.php diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 52bd422c0a..bc30e0f92a 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,7 +6,238 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( - 'Friendica\\Core\\Config' => $baseDir . '/include/Core/Config.php', - 'Friendica\\Core\\PConfig' => $baseDir . '/include/Core/PConfig.php', - 'Friendica\\ParseUrl' => $baseDir . '/include/ParseUrl.php', + 'Detection\\MobileDetect' => $vendorDir . '/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php', + 'Friendica\\Core\\Config' => $baseDir . '/src/Core/Config.php', + 'Friendica\\Core\\PConfig' => $baseDir . '/src/Core/PConfig.php', + 'Friendica\\ParseUrl' => $baseDir . '/src/ParseUrl.php', + 'HTMLPurifier' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.php', + 'HTMLPurifier_Arborize' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php', + 'HTMLPurifier_AttrCollections' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php', + 'HTMLPurifier_AttrDef' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php', + 'HTMLPurifier_AttrDef_CSS' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php', + 'HTMLPurifier_AttrDef_CSS_AlphaValue' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php', + 'HTMLPurifier_AttrDef_CSS_Background' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php', + 'HTMLPurifier_AttrDef_CSS_BackgroundPosition' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php', + 'HTMLPurifier_AttrDef_CSS_Border' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php', + 'HTMLPurifier_AttrDef_CSS_Color' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php', + 'HTMLPurifier_AttrDef_CSS_Composite' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php', + 'HTMLPurifier_AttrDef_CSS_DenyElementDecorator' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php', + 'HTMLPurifier_AttrDef_CSS_Filter' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php', + 'HTMLPurifier_AttrDef_CSS_Font' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php', + 'HTMLPurifier_AttrDef_CSS_FontFamily' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php', + 'HTMLPurifier_AttrDef_CSS_Ident' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php', + 'HTMLPurifier_AttrDef_CSS_ImportantDecorator' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php', + 'HTMLPurifier_AttrDef_CSS_Length' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php', + 'HTMLPurifier_AttrDef_CSS_ListStyle' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php', + 'HTMLPurifier_AttrDef_CSS_Multiple' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php', + 'HTMLPurifier_AttrDef_CSS_Number' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php', + 'HTMLPurifier_AttrDef_CSS_Percentage' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php', + 'HTMLPurifier_AttrDef_CSS_TextDecoration' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php', + 'HTMLPurifier_AttrDef_CSS_URI' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php', + 'HTMLPurifier_AttrDef_Clone' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php', + 'HTMLPurifier_AttrDef_Enum' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php', + 'HTMLPurifier_AttrDef_HTML_Bool' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php', + 'HTMLPurifier_AttrDef_HTML_Class' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php', + 'HTMLPurifier_AttrDef_HTML_Color' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php', + 'HTMLPurifier_AttrDef_HTML_FrameTarget' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php', + 'HTMLPurifier_AttrDef_HTML_ID' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php', + 'HTMLPurifier_AttrDef_HTML_Length' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php', + 'HTMLPurifier_AttrDef_HTML_LinkTypes' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php', + 'HTMLPurifier_AttrDef_HTML_MultiLength' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php', + 'HTMLPurifier_AttrDef_HTML_Nmtokens' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php', + 'HTMLPurifier_AttrDef_HTML_Pixels' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php', + 'HTMLPurifier_AttrDef_Integer' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php', + 'HTMLPurifier_AttrDef_Lang' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php', + 'HTMLPurifier_AttrDef_Switch' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php', + 'HTMLPurifier_AttrDef_Text' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php', + 'HTMLPurifier_AttrDef_URI' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php', + 'HTMLPurifier_AttrDef_URI_Email' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php', + 'HTMLPurifier_AttrDef_URI_Email_SimpleCheck' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php', + 'HTMLPurifier_AttrDef_URI_Host' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php', + 'HTMLPurifier_AttrDef_URI_IPv4' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php', + 'HTMLPurifier_AttrDef_URI_IPv6' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php', + 'HTMLPurifier_AttrTransform' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php', + 'HTMLPurifier_AttrTransform_Background' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Background.php', + 'HTMLPurifier_AttrTransform_BdoDir' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php', + 'HTMLPurifier_AttrTransform_BgColor' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php', + 'HTMLPurifier_AttrTransform_BoolToCSS' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php', + 'HTMLPurifier_AttrTransform_Border' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php', + 'HTMLPurifier_AttrTransform_EnumToCSS' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php', + 'HTMLPurifier_AttrTransform_ImgRequired' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php', + 'HTMLPurifier_AttrTransform_ImgSpace' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php', + 'HTMLPurifier_AttrTransform_Input' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php', + 'HTMLPurifier_AttrTransform_Lang' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php', + 'HTMLPurifier_AttrTransform_Length' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Length.php', + 'HTMLPurifier_AttrTransform_Name' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php', + 'HTMLPurifier_AttrTransform_NameSync' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php', + 'HTMLPurifier_AttrTransform_Nofollow' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php', + 'HTMLPurifier_AttrTransform_SafeEmbed' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php', + 'HTMLPurifier_AttrTransform_SafeObject' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeObject.php', + 'HTMLPurifier_AttrTransform_SafeParam' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeParam.php', + 'HTMLPurifier_AttrTransform_ScriptRequired' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php', + 'HTMLPurifier_AttrTransform_TargetBlank' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php', + 'HTMLPurifier_AttrTransform_Textarea' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Textarea.php', + 'HTMLPurifier_AttrTypes' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php', + 'HTMLPurifier_AttrValidator' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php', + 'HTMLPurifier_Bootstrap' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php', + 'HTMLPurifier_CSSDefinition' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php', + 'HTMLPurifier_ChildDef' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php', + 'HTMLPurifier_ChildDef_Chameleon' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php', + 'HTMLPurifier_ChildDef_Custom' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php', + 'HTMLPurifier_ChildDef_Empty' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php', + 'HTMLPurifier_ChildDef_List' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/List.php', + 'HTMLPurifier_ChildDef_Optional' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php', + 'HTMLPurifier_ChildDef_Required' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php', + 'HTMLPurifier_ChildDef_StrictBlockquote' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php', + 'HTMLPurifier_ChildDef_Table' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php', + 'HTMLPurifier_Config' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Config.php', + 'HTMLPurifier_ConfigSchema' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php', + 'HTMLPurifier_ConfigSchema_Builder_ConfigSchema' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php', + 'HTMLPurifier_ConfigSchema_Builder_Xml' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php', + 'HTMLPurifier_ConfigSchema_Exception' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php', + 'HTMLPurifier_ConfigSchema_Interchange' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange.php', + 'HTMLPurifier_ConfigSchema_InterchangeBuilder' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php', + 'HTMLPurifier_ConfigSchema_Interchange_Directive' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php', + 'HTMLPurifier_ConfigSchema_Interchange_Id' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php', + 'HTMLPurifier_ConfigSchema_Validator' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php', + 'HTMLPurifier_ConfigSchema_ValidatorAtom' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php', + 'HTMLPurifier_ContentSets' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php', + 'HTMLPurifier_Context' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Context.php', + 'HTMLPurifier_Definition' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php', + 'HTMLPurifier_DefinitionCache' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php', + 'HTMLPurifier_DefinitionCacheFactory' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php', + 'HTMLPurifier_DefinitionCache_Decorator' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php', + 'HTMLPurifier_DefinitionCache_Decorator_Cleanup' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php', + 'HTMLPurifier_DefinitionCache_Decorator_Memory' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php', + 'HTMLPurifier_DefinitionCache_Null' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Null.php', + 'HTMLPurifier_DefinitionCache_Serializer' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer.php', + 'HTMLPurifier_Doctype' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php', + 'HTMLPurifier_DoctypeRegistry' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php', + 'HTMLPurifier_ElementDef' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php', + 'HTMLPurifier_Encoder' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php', + 'HTMLPurifier_EntityLookup' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php', + 'HTMLPurifier_EntityParser' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php', + 'HTMLPurifier_ErrorCollector' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php', + 'HTMLPurifier_ErrorStruct' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php', + 'HTMLPurifier_Exception' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php', + 'HTMLPurifier_Filter' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Filter.php', + 'HTMLPurifier_Filter_ExtractStyleBlocks' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php', + 'HTMLPurifier_Filter_YouTube' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php', + 'HTMLPurifier_Generator' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php', + 'HTMLPurifier_HTMLDefinition' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php', + 'HTMLPurifier_HTMLModule' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php', + 'HTMLPurifier_HTMLModuleManager' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModuleManager.php', + 'HTMLPurifier_HTMLModule_Bdo' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php', + 'HTMLPurifier_HTMLModule_CommonAttributes' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php', + 'HTMLPurifier_HTMLModule_Edit' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php', + 'HTMLPurifier_HTMLModule_Forms' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php', + 'HTMLPurifier_HTMLModule_Hypertext' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php', + 'HTMLPurifier_HTMLModule_Iframe' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php', + 'HTMLPurifier_HTMLModule_Image' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php', + 'HTMLPurifier_HTMLModule_Legacy' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php', + 'HTMLPurifier_HTMLModule_List' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php', + 'HTMLPurifier_HTMLModule_Name' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php', + 'HTMLPurifier_HTMLModule_Nofollow' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php', + 'HTMLPurifier_HTMLModule_NonXMLCommonAttributes' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php', + 'HTMLPurifier_HTMLModule_Object' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php', + 'HTMLPurifier_HTMLModule_Presentation' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php', + 'HTMLPurifier_HTMLModule_Proprietary' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php', + 'HTMLPurifier_HTMLModule_Ruby' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php', + 'HTMLPurifier_HTMLModule_SafeEmbed' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php', + 'HTMLPurifier_HTMLModule_SafeObject' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php', + 'HTMLPurifier_HTMLModule_SafeScripting' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php', + 'HTMLPurifier_HTMLModule_Scripting' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Scripting.php', + 'HTMLPurifier_HTMLModule_StyleAttribute' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/StyleAttribute.php', + 'HTMLPurifier_HTMLModule_Tables' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tables.php', + 'HTMLPurifier_HTMLModule_Target' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Target.php', + 'HTMLPurifier_HTMLModule_TargetBlank' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/TargetBlank.php', + 'HTMLPurifier_HTMLModule_Text' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Text.php', + 'HTMLPurifier_HTMLModule_Tidy' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy.php', + 'HTMLPurifier_HTMLModule_Tidy_Name' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Name.php', + 'HTMLPurifier_HTMLModule_Tidy_Proprietary' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php', + 'HTMLPurifier_HTMLModule_Tidy_Strict' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Strict.php', + 'HTMLPurifier_HTMLModule_Tidy_Transitional' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Transitional.php', + 'HTMLPurifier_HTMLModule_Tidy_XHTML' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTML.php', + 'HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php', + 'HTMLPurifier_HTMLModule_XMLCommonAttributes' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php', + 'HTMLPurifier_IDAccumulator' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/IDAccumulator.php', + 'HTMLPurifier_Injector' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector.php', + 'HTMLPurifier_Injector_AutoParagraph' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/AutoParagraph.php', + 'HTMLPurifier_Injector_DisplayLinkURI' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/DisplayLinkURI.php', + 'HTMLPurifier_Injector_Linkify' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/Linkify.php', + 'HTMLPurifier_Injector_PurifierLinkify' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/PurifierLinkify.php', + 'HTMLPurifier_Injector_RemoveEmpty' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveEmpty.php', + 'HTMLPurifier_Injector_RemoveSpansWithoutAttributes' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php', + 'HTMLPurifier_Injector_SafeObject' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/SafeObject.php', + 'HTMLPurifier_Language' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Language.php', + 'HTMLPurifier_LanguageFactory' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/LanguageFactory.php', + 'HTMLPurifier_Language_en_x_test' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Language/classes/en-x-test.php', + 'HTMLPurifier_Length' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Length.php', + 'HTMLPurifier_Lexer' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Lexer.php', + 'HTMLPurifier_Lexer_DOMLex' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php', + 'HTMLPurifier_Lexer_DirectLex' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DirectLex.php', + 'HTMLPurifier_Lexer_PH5P' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php', + 'HTMLPurifier_Node' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Node.php', + 'HTMLPurifier_Node_Comment' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Node/Comment.php', + 'HTMLPurifier_Node_Element' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php', + 'HTMLPurifier_Node_Text' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php', + 'HTMLPurifier_PercentEncoder' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php', + 'HTMLPurifier_Printer' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php', + 'HTMLPurifier_Printer_CSSDefinition' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php', + 'HTMLPurifier_Printer_ConfigForm' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php', + 'HTMLPurifier_Printer_ConfigForm_NullDecorator' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php', + 'HTMLPurifier_Printer_ConfigForm_bool' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php', + 'HTMLPurifier_Printer_ConfigForm_default' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php', + 'HTMLPurifier_Printer_HTMLDefinition' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php', + 'HTMLPurifier_PropertyList' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php', + 'HTMLPurifier_PropertyListIterator' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php', + 'HTMLPurifier_Queue' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php', + 'HTMLPurifier_Strategy' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php', + 'HTMLPurifier_Strategy_Composite' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Composite.php', + 'HTMLPurifier_Strategy_Core' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php', + 'HTMLPurifier_Strategy_FixNesting' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php', + 'HTMLPurifier_Strategy_MakeWellFormed' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php', + 'HTMLPurifier_Strategy_RemoveForeignElements' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/RemoveForeignElements.php', + 'HTMLPurifier_Strategy_ValidateAttributes' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/ValidateAttributes.php', + 'HTMLPurifier_StringHash' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/StringHash.php', + 'HTMLPurifier_StringHashParser' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/StringHashParser.php', + 'HTMLPurifier_TagTransform' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform.php', + 'HTMLPurifier_TagTransform_Font' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Font.php', + 'HTMLPurifier_TagTransform_Simple' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Simple.php', + 'HTMLPurifier_Token' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Token.php', + 'HTMLPurifier_TokenFactory' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/TokenFactory.php', + 'HTMLPurifier_Token_Comment' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Token/Comment.php', + 'HTMLPurifier_Token_Empty' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Token/Empty.php', + 'HTMLPurifier_Token_End' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Token/End.php', + 'HTMLPurifier_Token_Start' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Token/Start.php', + 'HTMLPurifier_Token_Tag' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Token/Tag.php', + 'HTMLPurifier_Token_Text' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Token/Text.php', + 'HTMLPurifier_URI' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URI.php', + 'HTMLPurifier_URIDefinition' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIDefinition.php', + 'HTMLPurifier_URIFilter' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter.php', + 'HTMLPurifier_URIFilter_DisableExternal' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternal.php', + 'HTMLPurifier_URIFilter_DisableExternalResources' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternalResources.php', + 'HTMLPurifier_URIFilter_DisableResources' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableResources.php', + 'HTMLPurifier_URIFilter_HostBlacklist' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/HostBlacklist.php', + 'HTMLPurifier_URIFilter_MakeAbsolute' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/MakeAbsolute.php', + 'HTMLPurifier_URIFilter_Munge' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/Munge.php', + 'HTMLPurifier_URIFilter_SafeIframe' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/SafeIframe.php', + 'HTMLPurifier_URIParser' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIParser.php', + 'HTMLPurifier_URIScheme' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme.php', + 'HTMLPurifier_URISchemeRegistry' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URISchemeRegistry.php', + 'HTMLPurifier_URIScheme_data' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/data.php', + 'HTMLPurifier_URIScheme_file' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/file.php', + 'HTMLPurifier_URIScheme_ftp' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/ftp.php', + 'HTMLPurifier_URIScheme_http' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/http.php', + 'HTMLPurifier_URIScheme_https' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/https.php', + 'HTMLPurifier_URIScheme_mailto' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/mailto.php', + 'HTMLPurifier_URIScheme_news' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/news.php', + 'HTMLPurifier_URIScheme_nntp' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/nntp.php', + 'HTMLPurifier_UnitConverter' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/UnitConverter.php', + 'HTMLPurifier_VarParser' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php', + 'HTMLPurifier_VarParserException' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParserException.php', + 'HTMLPurifier_VarParser_Flexible' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php', + 'HTMLPurifier_VarParser_Native' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php', + 'HTMLPurifier_Zipper' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php', + 'Mobile_Detect' => $vendorDir . '/mobiledetect/mobiledetectlib/Mobile_Detect.php', ); diff --git a/include/autoloader/autoload_files.php b/vendor/composer/autoload_files.php similarity index 77% rename from include/autoloader/autoload_files.php rename to vendor/composer/autoload_files.php index 859135cc48..c25686b153 100644 --- a/include/autoloader/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -2,7 +2,7 @@ // autoload_files.php @generated by Composer -$vendorDir = dirname(dirname(dirname(__FILE__)))."/library"; +$vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php index b7fc0125db..f5eff86f1a 100644 --- a/vendor/composer/autoload_namespaces.php +++ b/vendor/composer/autoload_namespaces.php @@ -6,4 +6,6 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + 'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'), + 'Detection' => array($vendorDir . '/mobiledetect/mobiledetectlib/namespaced'), ); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 0190427df4..a8d577d5ee 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -6,5 +6,5 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( - 'Friendica\\' => array($baseDir . '/include'), + 'Friendica\\' => array($baseDir . '/src'), ); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index cb8c78eab7..48923cf476 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -47,6 +47,24 @@ class ComposerAutoloaderInitFriendica $loader->register(true); + if ($useStaticLoader) { + $includeFiles = Composer\Autoload\ComposerStaticInitFriendica::$files; + } else { + $includeFiles = require __DIR__ . '/autoload_files.php'; + } + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequireFriendica($fileIdentifier, $file); + } + return $loader; } } + +function composerRequireFriendica($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + require $file; + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 9136a25cac..f1f3423d85 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -6,6 +6,10 @@ namespace Composer\Autoload; class ComposerStaticInitFriendica { + public static $files = array ( + '2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', + ); + public static $prefixLengthsPsr4 = array ( 'F' => array ( @@ -16,14 +20,262 @@ class ComposerStaticInitFriendica public static $prefixDirsPsr4 = array ( 'Friendica\\' => array ( - 0 => __DIR__ . '/../..' . '/include', + 0 => __DIR__ . '/../..' . '/src', + ), + ); + + public static $prefixesPsr0 = array ( + 'H' => + array ( + 'HTMLPurifier' => + array ( + 0 => __DIR__ . '/..' . '/ezyang/htmlpurifier/library', + ), + ), + 'D' => + array ( + 'Detection' => + array ( + 0 => __DIR__ . '/..' . '/mobiledetect/mobiledetectlib/namespaced', + ), ), ); public static $classMap = array ( - 'Friendica\\Core\\Config' => __DIR__ . '/../..' . '/include/Core/Config.php', - 'Friendica\\Core\\PConfig' => __DIR__ . '/../..' . '/include/Core/PConfig.php', - 'Friendica\\ParseUrl' => __DIR__ . '/../..' . '/include/ParseUrl.php', + 'Detection\\MobileDetect' => __DIR__ . '/..' . '/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php', + 'Friendica\\Core\\Config' => __DIR__ . '/../..' . '/src/Core/Config.php', + 'Friendica\\Core\\PConfig' => __DIR__ . '/../..' . '/src/Core/PConfig.php', + 'Friendica\\ParseUrl' => __DIR__ . '/../..' . '/src/ParseUrl.php', + 'HTMLPurifier' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.php', + 'HTMLPurifier_Arborize' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php', + 'HTMLPurifier_AttrCollections' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php', + 'HTMLPurifier_AttrDef' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php', + 'HTMLPurifier_AttrDef_CSS' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php', + 'HTMLPurifier_AttrDef_CSS_AlphaValue' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php', + 'HTMLPurifier_AttrDef_CSS_Background' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php', + 'HTMLPurifier_AttrDef_CSS_BackgroundPosition' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php', + 'HTMLPurifier_AttrDef_CSS_Border' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php', + 'HTMLPurifier_AttrDef_CSS_Color' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php', + 'HTMLPurifier_AttrDef_CSS_Composite' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php', + 'HTMLPurifier_AttrDef_CSS_DenyElementDecorator' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php', + 'HTMLPurifier_AttrDef_CSS_Filter' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php', + 'HTMLPurifier_AttrDef_CSS_Font' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php', + 'HTMLPurifier_AttrDef_CSS_FontFamily' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php', + 'HTMLPurifier_AttrDef_CSS_Ident' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php', + 'HTMLPurifier_AttrDef_CSS_ImportantDecorator' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php', + 'HTMLPurifier_AttrDef_CSS_Length' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php', + 'HTMLPurifier_AttrDef_CSS_ListStyle' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php', + 'HTMLPurifier_AttrDef_CSS_Multiple' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php', + 'HTMLPurifier_AttrDef_CSS_Number' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php', + 'HTMLPurifier_AttrDef_CSS_Percentage' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php', + 'HTMLPurifier_AttrDef_CSS_TextDecoration' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php', + 'HTMLPurifier_AttrDef_CSS_URI' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php', + 'HTMLPurifier_AttrDef_Clone' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php', + 'HTMLPurifier_AttrDef_Enum' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php', + 'HTMLPurifier_AttrDef_HTML_Bool' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php', + 'HTMLPurifier_AttrDef_HTML_Class' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php', + 'HTMLPurifier_AttrDef_HTML_Color' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php', + 'HTMLPurifier_AttrDef_HTML_FrameTarget' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php', + 'HTMLPurifier_AttrDef_HTML_ID' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php', + 'HTMLPurifier_AttrDef_HTML_Length' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php', + 'HTMLPurifier_AttrDef_HTML_LinkTypes' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php', + 'HTMLPurifier_AttrDef_HTML_MultiLength' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php', + 'HTMLPurifier_AttrDef_HTML_Nmtokens' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php', + 'HTMLPurifier_AttrDef_HTML_Pixels' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php', + 'HTMLPurifier_AttrDef_Integer' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php', + 'HTMLPurifier_AttrDef_Lang' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php', + 'HTMLPurifier_AttrDef_Switch' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php', + 'HTMLPurifier_AttrDef_Text' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php', + 'HTMLPurifier_AttrDef_URI' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php', + 'HTMLPurifier_AttrDef_URI_Email' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php', + 'HTMLPurifier_AttrDef_URI_Email_SimpleCheck' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php', + 'HTMLPurifier_AttrDef_URI_Host' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php', + 'HTMLPurifier_AttrDef_URI_IPv4' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php', + 'HTMLPurifier_AttrDef_URI_IPv6' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php', + 'HTMLPurifier_AttrTransform' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php', + 'HTMLPurifier_AttrTransform_Background' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Background.php', + 'HTMLPurifier_AttrTransform_BdoDir' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php', + 'HTMLPurifier_AttrTransform_BgColor' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php', + 'HTMLPurifier_AttrTransform_BoolToCSS' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php', + 'HTMLPurifier_AttrTransform_Border' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php', + 'HTMLPurifier_AttrTransform_EnumToCSS' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php', + 'HTMLPurifier_AttrTransform_ImgRequired' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php', + 'HTMLPurifier_AttrTransform_ImgSpace' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php', + 'HTMLPurifier_AttrTransform_Input' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php', + 'HTMLPurifier_AttrTransform_Lang' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php', + 'HTMLPurifier_AttrTransform_Length' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Length.php', + 'HTMLPurifier_AttrTransform_Name' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php', + 'HTMLPurifier_AttrTransform_NameSync' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php', + 'HTMLPurifier_AttrTransform_Nofollow' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php', + 'HTMLPurifier_AttrTransform_SafeEmbed' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php', + 'HTMLPurifier_AttrTransform_SafeObject' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeObject.php', + 'HTMLPurifier_AttrTransform_SafeParam' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeParam.php', + 'HTMLPurifier_AttrTransform_ScriptRequired' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php', + 'HTMLPurifier_AttrTransform_TargetBlank' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php', + 'HTMLPurifier_AttrTransform_Textarea' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Textarea.php', + 'HTMLPurifier_AttrTypes' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php', + 'HTMLPurifier_AttrValidator' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php', + 'HTMLPurifier_Bootstrap' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php', + 'HTMLPurifier_CSSDefinition' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php', + 'HTMLPurifier_ChildDef' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php', + 'HTMLPurifier_ChildDef_Chameleon' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php', + 'HTMLPurifier_ChildDef_Custom' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php', + 'HTMLPurifier_ChildDef_Empty' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php', + 'HTMLPurifier_ChildDef_List' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/List.php', + 'HTMLPurifier_ChildDef_Optional' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php', + 'HTMLPurifier_ChildDef_Required' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php', + 'HTMLPurifier_ChildDef_StrictBlockquote' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php', + 'HTMLPurifier_ChildDef_Table' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php', + 'HTMLPurifier_Config' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Config.php', + 'HTMLPurifier_ConfigSchema' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php', + 'HTMLPurifier_ConfigSchema_Builder_ConfigSchema' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php', + 'HTMLPurifier_ConfigSchema_Builder_Xml' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php', + 'HTMLPurifier_ConfigSchema_Exception' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php', + 'HTMLPurifier_ConfigSchema_Interchange' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange.php', + 'HTMLPurifier_ConfigSchema_InterchangeBuilder' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php', + 'HTMLPurifier_ConfigSchema_Interchange_Directive' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php', + 'HTMLPurifier_ConfigSchema_Interchange_Id' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php', + 'HTMLPurifier_ConfigSchema_Validator' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php', + 'HTMLPurifier_ConfigSchema_ValidatorAtom' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php', + 'HTMLPurifier_ContentSets' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php', + 'HTMLPurifier_Context' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Context.php', + 'HTMLPurifier_Definition' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php', + 'HTMLPurifier_DefinitionCache' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php', + 'HTMLPurifier_DefinitionCacheFactory' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php', + 'HTMLPurifier_DefinitionCache_Decorator' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php', + 'HTMLPurifier_DefinitionCache_Decorator_Cleanup' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php', + 'HTMLPurifier_DefinitionCache_Decorator_Memory' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php', + 'HTMLPurifier_DefinitionCache_Null' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Null.php', + 'HTMLPurifier_DefinitionCache_Serializer' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer.php', + 'HTMLPurifier_Doctype' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php', + 'HTMLPurifier_DoctypeRegistry' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php', + 'HTMLPurifier_ElementDef' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php', + 'HTMLPurifier_Encoder' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php', + 'HTMLPurifier_EntityLookup' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php', + 'HTMLPurifier_EntityParser' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php', + 'HTMLPurifier_ErrorCollector' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php', + 'HTMLPurifier_ErrorStruct' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php', + 'HTMLPurifier_Exception' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php', + 'HTMLPurifier_Filter' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Filter.php', + 'HTMLPurifier_Filter_ExtractStyleBlocks' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php', + 'HTMLPurifier_Filter_YouTube' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php', + 'HTMLPurifier_Generator' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php', + 'HTMLPurifier_HTMLDefinition' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php', + 'HTMLPurifier_HTMLModule' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php', + 'HTMLPurifier_HTMLModuleManager' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModuleManager.php', + 'HTMLPurifier_HTMLModule_Bdo' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php', + 'HTMLPurifier_HTMLModule_CommonAttributes' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php', + 'HTMLPurifier_HTMLModule_Edit' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php', + 'HTMLPurifier_HTMLModule_Forms' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php', + 'HTMLPurifier_HTMLModule_Hypertext' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php', + 'HTMLPurifier_HTMLModule_Iframe' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php', + 'HTMLPurifier_HTMLModule_Image' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php', + 'HTMLPurifier_HTMLModule_Legacy' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php', + 'HTMLPurifier_HTMLModule_List' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php', + 'HTMLPurifier_HTMLModule_Name' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php', + 'HTMLPurifier_HTMLModule_Nofollow' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php', + 'HTMLPurifier_HTMLModule_NonXMLCommonAttributes' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php', + 'HTMLPurifier_HTMLModule_Object' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php', + 'HTMLPurifier_HTMLModule_Presentation' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php', + 'HTMLPurifier_HTMLModule_Proprietary' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php', + 'HTMLPurifier_HTMLModule_Ruby' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php', + 'HTMLPurifier_HTMLModule_SafeEmbed' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php', + 'HTMLPurifier_HTMLModule_SafeObject' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php', + 'HTMLPurifier_HTMLModule_SafeScripting' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php', + 'HTMLPurifier_HTMLModule_Scripting' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Scripting.php', + 'HTMLPurifier_HTMLModule_StyleAttribute' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/StyleAttribute.php', + 'HTMLPurifier_HTMLModule_Tables' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tables.php', + 'HTMLPurifier_HTMLModule_Target' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Target.php', + 'HTMLPurifier_HTMLModule_TargetBlank' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/TargetBlank.php', + 'HTMLPurifier_HTMLModule_Text' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Text.php', + 'HTMLPurifier_HTMLModule_Tidy' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy.php', + 'HTMLPurifier_HTMLModule_Tidy_Name' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Name.php', + 'HTMLPurifier_HTMLModule_Tidy_Proprietary' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php', + 'HTMLPurifier_HTMLModule_Tidy_Strict' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Strict.php', + 'HTMLPurifier_HTMLModule_Tidy_Transitional' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Transitional.php', + 'HTMLPurifier_HTMLModule_Tidy_XHTML' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTML.php', + 'HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php', + 'HTMLPurifier_HTMLModule_XMLCommonAttributes' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php', + 'HTMLPurifier_IDAccumulator' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/IDAccumulator.php', + 'HTMLPurifier_Injector' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector.php', + 'HTMLPurifier_Injector_AutoParagraph' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/AutoParagraph.php', + 'HTMLPurifier_Injector_DisplayLinkURI' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/DisplayLinkURI.php', + 'HTMLPurifier_Injector_Linkify' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/Linkify.php', + 'HTMLPurifier_Injector_PurifierLinkify' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/PurifierLinkify.php', + 'HTMLPurifier_Injector_RemoveEmpty' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveEmpty.php', + 'HTMLPurifier_Injector_RemoveSpansWithoutAttributes' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php', + 'HTMLPurifier_Injector_SafeObject' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Injector/SafeObject.php', + 'HTMLPurifier_Language' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Language.php', + 'HTMLPurifier_LanguageFactory' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/LanguageFactory.php', + 'HTMLPurifier_Language_en_x_test' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Language/classes/en-x-test.php', + 'HTMLPurifier_Length' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Length.php', + 'HTMLPurifier_Lexer' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Lexer.php', + 'HTMLPurifier_Lexer_DOMLex' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php', + 'HTMLPurifier_Lexer_DirectLex' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DirectLex.php', + 'HTMLPurifier_Lexer_PH5P' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php', + 'HTMLPurifier_Node' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Node.php', + 'HTMLPurifier_Node_Comment' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Node/Comment.php', + 'HTMLPurifier_Node_Element' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php', + 'HTMLPurifier_Node_Text' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php', + 'HTMLPurifier_PercentEncoder' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php', + 'HTMLPurifier_Printer' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php', + 'HTMLPurifier_Printer_CSSDefinition' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php', + 'HTMLPurifier_Printer_ConfigForm' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php', + 'HTMLPurifier_Printer_ConfigForm_NullDecorator' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php', + 'HTMLPurifier_Printer_ConfigForm_bool' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php', + 'HTMLPurifier_Printer_ConfigForm_default' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php', + 'HTMLPurifier_Printer_HTMLDefinition' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php', + 'HTMLPurifier_PropertyList' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php', + 'HTMLPurifier_PropertyListIterator' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php', + 'HTMLPurifier_Queue' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php', + 'HTMLPurifier_Strategy' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php', + 'HTMLPurifier_Strategy_Composite' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Composite.php', + 'HTMLPurifier_Strategy_Core' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php', + 'HTMLPurifier_Strategy_FixNesting' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php', + 'HTMLPurifier_Strategy_MakeWellFormed' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php', + 'HTMLPurifier_Strategy_RemoveForeignElements' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/RemoveForeignElements.php', + 'HTMLPurifier_Strategy_ValidateAttributes' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/ValidateAttributes.php', + 'HTMLPurifier_StringHash' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/StringHash.php', + 'HTMLPurifier_StringHashParser' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/StringHashParser.php', + 'HTMLPurifier_TagTransform' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform.php', + 'HTMLPurifier_TagTransform_Font' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Font.php', + 'HTMLPurifier_TagTransform_Simple' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Simple.php', + 'HTMLPurifier_Token' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Token.php', + 'HTMLPurifier_TokenFactory' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/TokenFactory.php', + 'HTMLPurifier_Token_Comment' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Token/Comment.php', + 'HTMLPurifier_Token_Empty' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Token/Empty.php', + 'HTMLPurifier_Token_End' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Token/End.php', + 'HTMLPurifier_Token_Start' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Token/Start.php', + 'HTMLPurifier_Token_Tag' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Token/Tag.php', + 'HTMLPurifier_Token_Text' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Token/Text.php', + 'HTMLPurifier_URI' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URI.php', + 'HTMLPurifier_URIDefinition' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIDefinition.php', + 'HTMLPurifier_URIFilter' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter.php', + 'HTMLPurifier_URIFilter_DisableExternal' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternal.php', + 'HTMLPurifier_URIFilter_DisableExternalResources' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternalResources.php', + 'HTMLPurifier_URIFilter_DisableResources' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableResources.php', + 'HTMLPurifier_URIFilter_HostBlacklist' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/HostBlacklist.php', + 'HTMLPurifier_URIFilter_MakeAbsolute' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/MakeAbsolute.php', + 'HTMLPurifier_URIFilter_Munge' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/Munge.php', + 'HTMLPurifier_URIFilter_SafeIframe' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/SafeIframe.php', + 'HTMLPurifier_URIParser' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIParser.php', + 'HTMLPurifier_URIScheme' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme.php', + 'HTMLPurifier_URISchemeRegistry' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URISchemeRegistry.php', + 'HTMLPurifier_URIScheme_data' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/data.php', + 'HTMLPurifier_URIScheme_file' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/file.php', + 'HTMLPurifier_URIScheme_ftp' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/ftp.php', + 'HTMLPurifier_URIScheme_http' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/http.php', + 'HTMLPurifier_URIScheme_https' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/https.php', + 'HTMLPurifier_URIScheme_mailto' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/mailto.php', + 'HTMLPurifier_URIScheme_news' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/news.php', + 'HTMLPurifier_URIScheme_nntp' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/nntp.php', + 'HTMLPurifier_UnitConverter' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/UnitConverter.php', + 'HTMLPurifier_VarParser' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php', + 'HTMLPurifier_VarParserException' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParserException.php', + 'HTMLPurifier_VarParser_Flexible' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php', + 'HTMLPurifier_VarParser_Native' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php', + 'HTMLPurifier_Zipper' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php', + 'Mobile_Detect' => __DIR__ . '/..' . '/mobiledetect/mobiledetectlib/Mobile_Detect.php', ); public static function getInitializer(ClassLoader $loader) @@ -31,6 +283,7 @@ class ComposerStaticInitFriendica return \Closure::bind(function () use ($loader) { $loader->prefixLengthsPsr4 = ComposerStaticInitFriendica::$prefixLengthsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInitFriendica::$prefixDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInitFriendica::$prefixesPsr0; $loader->classMap = ComposerStaticInitFriendica::$classMap; }, null, ClassLoader::class); diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index fe51488c70..ebd4ea0a13 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -1 +1,102 @@ -[] +[ + { + "name": "ezyang/htmlpurifier", + "version": "v4.7.0", + "version_normalized": "4.7.0.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "ae1828d955112356f7677c465f94f7deb7d27a40" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/ae1828d955112356f7677c465f94f7deb7d27a40", + "reference": "ae1828d955112356f7677c465f94f7deb7d27a40", + "shasum": "" + }, + "require": { + "php": ">=5.2" + }, + "time": "2015-08-05T01:03:42+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "HTMLPurifier": "library/" + }, + "files": [ + "library/HTMLPurifier.composer.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ] + }, + { + "name": "mobiledetect/mobiledetectlib", + "version": "2.8.25", + "version_normalized": "2.8.25.0", + "source": { + "type": "git", + "url": "https://github.com/serbanghita/Mobile-Detect.git", + "reference": "f0896b5c7274d1450023b0b376240be902c3251c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/f0896b5c7274d1450023b0b376240be902c3251c", + "reference": "f0896b5c7274d1450023b0b376240be902c3251c", + "shasum": "" + }, + "require": { + "php": ">=5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "time": "2017-03-29T13:59:30+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "classmap": [ + "Mobile_Detect.php" + ], + "psr-0": { + "Detection": "namespaced/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Serban Ghita", + "email": "serbanghita@gmail.com", + "homepage": "http://mobiledetect.net", + "role": "Developer" + } + ], + "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", + "homepage": "https://github.com/serbanghita/Mobile-Detect", + "keywords": [ + "detect mobile devices", + "mobile", + "mobile detect", + "mobile detector", + "php mobile detect" + ] + } +] diff --git a/library/ezyang/htmlpurifier/CREDITS b/vendor/ezyang/htmlpurifier/CREDITS similarity index 100% rename from library/ezyang/htmlpurifier/CREDITS rename to vendor/ezyang/htmlpurifier/CREDITS diff --git a/library/ezyang/htmlpurifier/INSTALL b/vendor/ezyang/htmlpurifier/INSTALL similarity index 100% rename from library/ezyang/htmlpurifier/INSTALL rename to vendor/ezyang/htmlpurifier/INSTALL diff --git a/library/ezyang/htmlpurifier/INSTALL.fr.utf8 b/vendor/ezyang/htmlpurifier/INSTALL.fr.utf8 similarity index 100% rename from library/ezyang/htmlpurifier/INSTALL.fr.utf8 rename to vendor/ezyang/htmlpurifier/INSTALL.fr.utf8 diff --git a/library/ezyang/htmlpurifier/LICENSE b/vendor/ezyang/htmlpurifier/LICENSE similarity index 100% rename from library/ezyang/htmlpurifier/LICENSE rename to vendor/ezyang/htmlpurifier/LICENSE diff --git a/library/ezyang/htmlpurifier/NEWS b/vendor/ezyang/htmlpurifier/NEWS similarity index 100% rename from library/ezyang/htmlpurifier/NEWS rename to vendor/ezyang/htmlpurifier/NEWS diff --git a/library/ezyang/htmlpurifier/README b/vendor/ezyang/htmlpurifier/README similarity index 100% rename from library/ezyang/htmlpurifier/README rename to vendor/ezyang/htmlpurifier/README diff --git a/library/ezyang/htmlpurifier/TODO b/vendor/ezyang/htmlpurifier/TODO similarity index 100% rename from library/ezyang/htmlpurifier/TODO rename to vendor/ezyang/htmlpurifier/TODO diff --git a/library/ezyang/htmlpurifier/VERSION b/vendor/ezyang/htmlpurifier/VERSION similarity index 100% rename from library/ezyang/htmlpurifier/VERSION rename to vendor/ezyang/htmlpurifier/VERSION diff --git a/library/ezyang/htmlpurifier/WHATSNEW b/vendor/ezyang/htmlpurifier/WHATSNEW similarity index 100% rename from library/ezyang/htmlpurifier/WHATSNEW rename to vendor/ezyang/htmlpurifier/WHATSNEW diff --git a/library/ezyang/htmlpurifier/WYSIWYG b/vendor/ezyang/htmlpurifier/WYSIWYG similarity index 100% rename from library/ezyang/htmlpurifier/WYSIWYG rename to vendor/ezyang/htmlpurifier/WYSIWYG diff --git a/library/ezyang/htmlpurifier/composer.json b/vendor/ezyang/htmlpurifier/composer.json similarity index 100% rename from library/ezyang/htmlpurifier/composer.json rename to vendor/ezyang/htmlpurifier/composer.json diff --git a/library/ezyang/htmlpurifier/extras/ConfigDoc/HTMLXSLTProcessor.php b/vendor/ezyang/htmlpurifier/extras/ConfigDoc/HTMLXSLTProcessor.php similarity index 100% rename from library/ezyang/htmlpurifier/extras/ConfigDoc/HTMLXSLTProcessor.php rename to vendor/ezyang/htmlpurifier/extras/ConfigDoc/HTMLXSLTProcessor.php diff --git a/library/ezyang/htmlpurifier/extras/FSTools.php b/vendor/ezyang/htmlpurifier/extras/FSTools.php similarity index 100% rename from library/ezyang/htmlpurifier/extras/FSTools.php rename to vendor/ezyang/htmlpurifier/extras/FSTools.php diff --git a/library/ezyang/htmlpurifier/extras/FSTools/File.php b/vendor/ezyang/htmlpurifier/extras/FSTools/File.php similarity index 100% rename from library/ezyang/htmlpurifier/extras/FSTools/File.php rename to vendor/ezyang/htmlpurifier/extras/FSTools/File.php diff --git a/library/ezyang/htmlpurifier/extras/HTMLPurifierExtras.auto.php b/vendor/ezyang/htmlpurifier/extras/HTMLPurifierExtras.auto.php similarity index 100% rename from library/ezyang/htmlpurifier/extras/HTMLPurifierExtras.auto.php rename to vendor/ezyang/htmlpurifier/extras/HTMLPurifierExtras.auto.php diff --git a/library/ezyang/htmlpurifier/extras/HTMLPurifierExtras.autoload.php b/vendor/ezyang/htmlpurifier/extras/HTMLPurifierExtras.autoload.php similarity index 100% rename from library/ezyang/htmlpurifier/extras/HTMLPurifierExtras.autoload.php rename to vendor/ezyang/htmlpurifier/extras/HTMLPurifierExtras.autoload.php diff --git a/library/ezyang/htmlpurifier/extras/HTMLPurifierExtras.php b/vendor/ezyang/htmlpurifier/extras/HTMLPurifierExtras.php similarity index 100% rename from library/ezyang/htmlpurifier/extras/HTMLPurifierExtras.php rename to vendor/ezyang/htmlpurifier/extras/HTMLPurifierExtras.php diff --git a/library/ezyang/htmlpurifier/extras/README b/vendor/ezyang/htmlpurifier/extras/README similarity index 100% rename from library/ezyang/htmlpurifier/extras/README rename to vendor/ezyang/htmlpurifier/extras/README diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier.auto.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier.auto.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier.autoload.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.autoload.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier.autoload.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier.autoload.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier.composer.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.composer.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier.composer.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier.composer.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier.func.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.func.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier.func.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier.func.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier.includes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier.includes.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier.kses.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.kses.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier.kses.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier.kses.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier.path.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.path.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier.path.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier.path.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Background.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Background.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Background.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Background.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/EnumToCSS.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgRequired.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ImgSpace.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Input.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Lang.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Length.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Length.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Length.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Length.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Name.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/NameSync.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Nofollow.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeEmbed.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeObject.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeObject.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeObject.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeObject.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeParam.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeParam.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeParam.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/SafeParam.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/ScriptRequired.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/TargetBlank.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Textarea.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Textarea.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Textarea.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Textarea.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTypes.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrValidator.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Bootstrap.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/CSSDefinition.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Chameleon.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Custom.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Empty.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/List.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/List.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/List.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/List.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Optional.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Required.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/StrictBlockquote.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ChildDef/Table.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Config.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Config.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Config.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Builder/Xml.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Exception.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Directive.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Interchange/Id.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/InterchangeBuilder.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/Validator.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema.ser diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedClasses.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedFrameTargets.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRel.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.AllowedRev.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ClassUseCDATA.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultImageAlt.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImage.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultInvalidImageAlt.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.DefaultTextDir.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.EnableID.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.ForbiddenClasses.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklist.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDBlacklistRegexp.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefix.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Attr.IDPrefixLocal.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.AutoParagraph.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Custom.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.DisplayLinkURI.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.Linkify.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.DocURL.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.PurifierLinkify.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.Predicate.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.Exceptions.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.RemoveNbsp.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveEmpty.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/AutoFormat.RemoveSpansWithoutAttributes.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowImportant.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowTricky.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedFonts.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.AllowedProperties.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.DefinitionRev.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.ForbiddenProperties.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.MaxImgLength.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Proprietary.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/CSS.Trusted.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.DefinitionImpl.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPath.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Cache.SerializerPermissions.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyFixLt.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.AllowHostnameUnderscore.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.CollectErrors.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ColorKeywords.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.ConvertDocumentToFragment.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DirectLexLineNumberSyncInterval.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.DisableExcludes.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EnableIDNA.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Encoding.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidChildren.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeInvalidTags.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.EscapeNonASCIICharacters.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.HiddenElements.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.Language.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.LexerImpl.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.MaintainLineNumbers.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.NormalizeNewlines.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveInvalidImg.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveProcessingInstructions.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Core.RemoveScriptContents.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.Custom.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Escaping.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.Scope.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.TidyImpl.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.ExtractStyleBlocks.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Filter.YouTube.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Allowed.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedAttributes.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedComments.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedCommentsRegexp.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedElements.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.AllowedModules.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Attr.Name.UseCDATA.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.BlockWrapper.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CoreModules.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.CustomDoctype.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionID.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.DefinitionRev.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Doctype.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.FlashAllowFullScreen.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenAttributes.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.ForbiddenElements.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.MaxImgLength.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Nofollow.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Parent.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Proprietary.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeEmbed.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeIframe.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeObject.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.SafeScripting.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Strict.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TargetBlank.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyAdd.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyLevel.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.TidyRemove.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.Trusted.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/HTML.XHTML.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.CommentScriptContents.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FixInnerHTML.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.FlashCompat.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.Newline.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.SortAttr.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Output.TidyFormat.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/Test.ForceNoIconv.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.AllowedSchemes.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Base.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionID.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DefinitionRev.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Disable.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternal.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableExternalResources.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.DisableResources.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Host.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.HostBlacklist.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MakeAbsolute.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.Munge.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeResources.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.MungeSecretKey.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.OverrideAllowedSchemes.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/URI.SafeIframeRegexp.txt diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ConfigSchema/schema/info.ini diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ContentSets.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Context.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Context.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Context.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Context.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Definition.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Memory.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Decorator/Template.php.in diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Null.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Null.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Null.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Null.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer/README diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCacheFactory.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Doctype.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/DoctypeRegistry.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ElementDef.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Encoder.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityLookup/entities.ser diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/EntityParser.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorCollector.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/ErrorStruct.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Exception.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Filter.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Filter.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/ExtractStyleBlocks.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Filter/YouTube.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Generator.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLDefinition.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Bdo.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/CommonAttributes.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Edit.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Forms.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Hypertext.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Iframe.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Image.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Legacy.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/List.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Name.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Nofollow.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Object.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Presentation.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Proprietary.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Ruby.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeEmbed.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeObject.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/SafeScripting.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Scripting.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Scripting.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Scripting.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Scripting.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/StyleAttribute.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/StyleAttribute.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/StyleAttribute.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/StyleAttribute.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tables.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tables.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tables.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tables.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Target.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Target.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Target.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Target.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/TargetBlank.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/TargetBlank.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/TargetBlank.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/TargetBlank.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Text.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Text.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Text.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Text.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Name.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Name.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Name.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Name.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Strict.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Strict.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Strict.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Strict.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Transitional.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Transitional.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Transitional.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/Transitional.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTML.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTML.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTML.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTML.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModuleManager.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModuleManager.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModuleManager.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/HTMLModuleManager.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/IDAccumulator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/IDAccumulator.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/IDAccumulator.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/IDAccumulator.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Injector.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Injector.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/AutoParagraph.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/AutoParagraph.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/AutoParagraph.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/AutoParagraph.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/DisplayLinkURI.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/DisplayLinkURI.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/DisplayLinkURI.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/DisplayLinkURI.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/Linkify.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/Linkify.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/Linkify.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/Linkify.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/PurifierLinkify.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/PurifierLinkify.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/PurifierLinkify.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/PurifierLinkify.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveEmpty.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveEmpty.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveEmpty.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveEmpty.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/SafeObject.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/SafeObject.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Injector/SafeObject.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Injector/SafeObject.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Language.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Language.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Language.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Language.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Language/classes/en-x-test.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Language/classes/en-x-test.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Language/classes/en-x-test.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Language/classes/en-x-test.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en-x-test.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en-x-test.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en-x-test.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en-x-test.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en-x-testmini.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en-x-testmini.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en-x-testmini.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en-x-testmini.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Language/messages/en.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/LanguageFactory.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/LanguageFactory.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/LanguageFactory.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/LanguageFactory.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Length.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Length.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Length.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Length.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Lexer.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Lexer.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DOMLex.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DirectLex.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DirectLex.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DirectLex.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/DirectLex.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Lexer/PH5P.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Node.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Node.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Comment.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Comment.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Comment.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Comment.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Element.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Node/Text.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/PercentEncoder.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/CSSDefinition.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.css diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.js diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/ConfigForm.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Printer/HTMLDefinition.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyList.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/PropertyListIterator.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Queue.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Composite.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Composite.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Composite.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Composite.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/Core.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/FixNesting.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/MakeWellFormed.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/RemoveForeignElements.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/RemoveForeignElements.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/RemoveForeignElements.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/RemoveForeignElements.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/ValidateAttributes.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/ValidateAttributes.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/ValidateAttributes.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Strategy/ValidateAttributes.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/StringHash.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/StringHash.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/StringHash.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/StringHash.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/StringHashParser.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/StringHashParser.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/StringHashParser.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/StringHashParser.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Font.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Font.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Font.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Font.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Simple.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Simple.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Simple.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/TagTransform/Simple.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Token.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Token.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Token/Comment.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Comment.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Token/Comment.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Comment.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Token/Empty.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Empty.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Token/Empty.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Empty.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Token/End.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/End.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Token/End.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/End.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Token/Start.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Start.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Token/Start.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Start.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Token/Tag.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Tag.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Token/Tag.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Tag.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Token/Text.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Text.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Token/Text.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Token/Text.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/TokenFactory.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/TokenFactory.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/TokenFactory.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/TokenFactory.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URI.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URI.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URI.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URI.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIDefinition.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIDefinition.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIDefinition.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIDefinition.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternal.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternal.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternal.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternal.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternalResources.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternalResources.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternalResources.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableExternalResources.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableResources.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableResources.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableResources.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/DisableResources.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/HostBlacklist.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/HostBlacklist.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/HostBlacklist.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/HostBlacklist.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/MakeAbsolute.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/MakeAbsolute.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/MakeAbsolute.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/MakeAbsolute.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/Munge.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/Munge.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/Munge.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/Munge.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/SafeIframe.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/SafeIframe.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/SafeIframe.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIFilter/SafeIframe.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIParser.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIParser.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIParser.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIParser.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/data.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/data.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/data.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/data.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/file.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/file.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/file.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/file.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/ftp.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/ftp.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/ftp.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/ftp.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/http.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/http.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/http.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/http.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/https.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/https.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/https.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/https.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/mailto.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/mailto.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/mailto.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/mailto.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/news.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/news.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/news.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/news.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/nntp.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/nntp.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/nntp.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URIScheme/nntp.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/URISchemeRegistry.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/URISchemeRegistry.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/URISchemeRegistry.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/URISchemeRegistry.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/UnitConverter.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/UnitConverter.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/UnitConverter.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/UnitConverter.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Flexible.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParser/Native.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/VarParserException.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParserException.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/VarParserException.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/VarParserException.php diff --git a/library/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php b/vendor/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php similarity index 100% rename from library/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php rename to vendor/ezyang/htmlpurifier/library/HTMLPurifier/Zipper.php diff --git a/library/ezyang/htmlpurifier/package.php b/vendor/ezyang/htmlpurifier/package.php similarity index 100% rename from library/ezyang/htmlpurifier/package.php rename to vendor/ezyang/htmlpurifier/package.php diff --git a/library/ezyang/htmlpurifier/phpdoc.ini b/vendor/ezyang/htmlpurifier/phpdoc.ini similarity index 100% rename from library/ezyang/htmlpurifier/phpdoc.ini rename to vendor/ezyang/htmlpurifier/phpdoc.ini diff --git a/library/ezyang/htmlpurifier/plugins/modx.txt b/vendor/ezyang/htmlpurifier/plugins/modx.txt similarity index 100% rename from library/ezyang/htmlpurifier/plugins/modx.txt rename to vendor/ezyang/htmlpurifier/plugins/modx.txt diff --git a/library/ezyang/htmlpurifier/plugins/phorum/.gitignore b/vendor/ezyang/htmlpurifier/plugins/phorum/.gitignore similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/.gitignore rename to vendor/ezyang/htmlpurifier/plugins/phorum/.gitignore diff --git a/library/ezyang/htmlpurifier/plugins/phorum/Changelog b/vendor/ezyang/htmlpurifier/plugins/phorum/Changelog similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/Changelog rename to vendor/ezyang/htmlpurifier/plugins/phorum/Changelog diff --git a/library/ezyang/htmlpurifier/plugins/phorum/INSTALL b/vendor/ezyang/htmlpurifier/plugins/phorum/INSTALL similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/INSTALL rename to vendor/ezyang/htmlpurifier/plugins/phorum/INSTALL diff --git a/library/ezyang/htmlpurifier/plugins/phorum/README b/vendor/ezyang/htmlpurifier/plugins/phorum/README similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/README rename to vendor/ezyang/htmlpurifier/plugins/phorum/README diff --git a/library/ezyang/htmlpurifier/plugins/phorum/config.default.php b/vendor/ezyang/htmlpurifier/plugins/phorum/config.default.php similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/config.default.php rename to vendor/ezyang/htmlpurifier/plugins/phorum/config.default.php diff --git a/library/ezyang/htmlpurifier/plugins/phorum/htmlpurifier.php b/vendor/ezyang/htmlpurifier/plugins/phorum/htmlpurifier.php similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/htmlpurifier.php rename to vendor/ezyang/htmlpurifier/plugins/phorum/htmlpurifier.php diff --git a/library/ezyang/htmlpurifier/plugins/phorum/info.txt b/vendor/ezyang/htmlpurifier/plugins/phorum/info.txt similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/info.txt rename to vendor/ezyang/htmlpurifier/plugins/phorum/info.txt diff --git a/library/ezyang/htmlpurifier/plugins/phorum/init-config.php b/vendor/ezyang/htmlpurifier/plugins/phorum/init-config.php similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/init-config.php rename to vendor/ezyang/htmlpurifier/plugins/phorum/init-config.php diff --git a/library/ezyang/htmlpurifier/plugins/phorum/migrate.bbcode.php b/vendor/ezyang/htmlpurifier/plugins/phorum/migrate.bbcode.php similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/migrate.bbcode.php rename to vendor/ezyang/htmlpurifier/plugins/phorum/migrate.bbcode.php diff --git a/library/ezyang/htmlpurifier/plugins/phorum/settings.php b/vendor/ezyang/htmlpurifier/plugins/phorum/settings.php similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/settings.php rename to vendor/ezyang/htmlpurifier/plugins/phorum/settings.php diff --git a/library/ezyang/htmlpurifier/plugins/phorum/settings/form.php b/vendor/ezyang/htmlpurifier/plugins/phorum/settings/form.php similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/settings/form.php rename to vendor/ezyang/htmlpurifier/plugins/phorum/settings/form.php diff --git a/library/ezyang/htmlpurifier/plugins/phorum/settings/migrate-sigs-form.php b/vendor/ezyang/htmlpurifier/plugins/phorum/settings/migrate-sigs-form.php similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/settings/migrate-sigs-form.php rename to vendor/ezyang/htmlpurifier/plugins/phorum/settings/migrate-sigs-form.php diff --git a/library/ezyang/htmlpurifier/plugins/phorum/settings/migrate-sigs.php b/vendor/ezyang/htmlpurifier/plugins/phorum/settings/migrate-sigs.php similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/settings/migrate-sigs.php rename to vendor/ezyang/htmlpurifier/plugins/phorum/settings/migrate-sigs.php diff --git a/library/ezyang/htmlpurifier/plugins/phorum/settings/save.php b/vendor/ezyang/htmlpurifier/plugins/phorum/settings/save.php similarity index 100% rename from library/ezyang/htmlpurifier/plugins/phorum/settings/save.php rename to vendor/ezyang/htmlpurifier/plugins/phorum/settings/save.php diff --git a/library/ezyang/htmlpurifier/release1-update.php b/vendor/ezyang/htmlpurifier/release1-update.php similarity index 100% rename from library/ezyang/htmlpurifier/release1-update.php rename to vendor/ezyang/htmlpurifier/release1-update.php diff --git a/library/ezyang/htmlpurifier/release2-tag.php b/vendor/ezyang/htmlpurifier/release2-tag.php similarity index 100% rename from library/ezyang/htmlpurifier/release2-tag.php rename to vendor/ezyang/htmlpurifier/release2-tag.php diff --git a/library/ezyang/htmlpurifier/test-settings.sample.php b/vendor/ezyang/htmlpurifier/test-settings.sample.php similarity index 100% rename from library/ezyang/htmlpurifier/test-settings.sample.php rename to vendor/ezyang/htmlpurifier/test-settings.sample.php From 806368f15165933d2db45846be0e6c634f4d2891 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Fri, 31 Mar 2017 23:05:07 -0400 Subject: [PATCH 05/16] Move MobileDetect library to vendor - Bumped the version to 2.8.25 (from 2.8.11) --- boot.php | 1 - composer.json | 3 +- composer.lock | 114 ++++++ library/Mobile_Detect/.gitignore | 11 - library/Mobile_Detect/.gitmodules | 3 - library/Mobile_Detect/.php_cs | 24 -- library/Mobile_Detect/.travis.yml | 17 - library/Mobile_Detect/Mobile_Detect.json | 1 - library/Mobile_Detect/README.md | 219 ----------- .../mobiledetect/mobiledetectlib}/LICENSE.txt | 2 +- .../mobiledetectlib/Mobile_Detect.json | 1 + .../mobiledetectlib}/Mobile_Detect.php | 348 ++++++++++++------ vendor/mobiledetect/mobiledetectlib/README.md | 283 ++++++++++++++ .../mobiledetectlib}/composer.json | 4 +- .../mobiledetectlib/export/exportToJSON.php | 67 ++++ .../namespaced/Detection/MobileDetect.php | 2 +- .../mobiledetect/mobiledetectlib/ruleset.xml | 187 ++++++++++ 17 files changed, 890 insertions(+), 397 deletions(-) create mode 100644 composer.lock delete mode 100644 library/Mobile_Detect/.gitignore delete mode 100644 library/Mobile_Detect/.gitmodules delete mode 100644 library/Mobile_Detect/.php_cs delete mode 100644 library/Mobile_Detect/.travis.yml delete mode 100644 library/Mobile_Detect/Mobile_Detect.json delete mode 100644 library/Mobile_Detect/README.md rename {library/Mobile_Detect => vendor/mobiledetect/mobiledetectlib}/LICENSE.txt (96%) create mode 100644 vendor/mobiledetect/mobiledetectlib/Mobile_Detect.json rename {library/Mobile_Detect => vendor/mobiledetect/mobiledetectlib}/Mobile_Detect.php (75%) create mode 100644 vendor/mobiledetect/mobiledetectlib/README.md rename {library/Mobile_Detect => vendor/mobiledetect/mobiledetectlib}/composer.json (86%) create mode 100644 vendor/mobiledetect/mobiledetectlib/export/exportToJSON.php rename {library/Mobile_Detect => vendor/mobiledetect/mobiledetectlib}/namespaced/Detection/MobileDetect.php (96%) create mode 100644 vendor/mobiledetect/mobiledetectlib/ruleset.xml diff --git a/boot.php b/boot.php index fc851eca51..6cfb8fa757 100644 --- a/boot.php +++ b/boot.php @@ -29,7 +29,6 @@ require_once('include/datetime.php'); require_once('include/pgettext.php'); require_once('include/nav.php'); require_once('include/cache.php'); -require_once('library/Mobile_Detect/Mobile_Detect.php'); require_once('include/features.php'); require_once('include/identity.php'); require_once('update.php'); diff --git a/composer.json b/composer.json index b3a1e8441e..9e83d04b45 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,8 @@ "issues": "https://github.com/friendica/friendica/issues" }, "require": { - "ezyang/htmlpurifier": "~4.7.0" + "ezyang/htmlpurifier": "~4.7.0", + "mobiledetect/mobiledetectlib": "2.8.*" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000000..2ca9991bfb --- /dev/null +++ b/composer.lock @@ -0,0 +1,114 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "49b00f1ed3192e5173bd5577a3b91ba2", + "packages": [ + { + "name": "ezyang/htmlpurifier", + "version": "v4.7.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "ae1828d955112356f7677c465f94f7deb7d27a40" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/ae1828d955112356f7677c465f94f7deb7d27a40", + "reference": "ae1828d955112356f7677c465f94f7deb7d27a40", + "shasum": "" + }, + "require": { + "php": ">=5.2" + }, + "type": "library", + "autoload": { + "psr-0": { + "HTMLPurifier": "library/" + }, + "files": [ + "library/HTMLPurifier.composer.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "time": "2015-08-05T01:03:42+00:00" + }, + { + "name": "mobiledetect/mobiledetectlib", + "version": "2.8.25", + "source": { + "type": "git", + "url": "https://github.com/serbanghita/Mobile-Detect.git", + "reference": "f0896b5c7274d1450023b0b376240be902c3251c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/f0896b5c7274d1450023b0b376240be902c3251c", + "reference": "f0896b5c7274d1450023b0b376240be902c3251c", + "shasum": "" + }, + "require": { + "php": ">=5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "type": "library", + "autoload": { + "classmap": [ + "Mobile_Detect.php" + ], + "psr-0": { + "Detection": "namespaced/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Serban Ghita", + "email": "serbanghita@gmail.com", + "homepage": "http://mobiledetect.net", + "role": "Developer" + } + ], + "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", + "homepage": "https://github.com/serbanghita/Mobile-Detect", + "keywords": [ + "detect mobile devices", + "mobile", + "mobile detect", + "mobile detector", + "php mobile detect" + ], + "time": "2017-03-29T13:59:30+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/library/Mobile_Detect/.gitignore b/library/Mobile_Detect/.gitignore deleted file mode 100644 index 48b35e7145..0000000000 --- a/library/Mobile_Detect/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -vendor/ -nbproject/ -/*.buildpath -/*.project -/.settings -/error.log -/export/nicejson -.idea/ -*.iml -/coverage -/phpunit.phar diff --git a/library/Mobile_Detect/.gitmodules b/library/Mobile_Detect/.gitmodules deleted file mode 100644 index 306e55ae54..0000000000 --- a/library/Mobile_Detect/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "export/nicejson"] - path = export/nicejson - url = https://github.com/GerHobbelt/nicejson-php.git diff --git a/library/Mobile_Detect/.php_cs b/library/Mobile_Detect/.php_cs deleted file mode 100644 index 336ef0c87d..0000000000 --- a/library/Mobile_Detect/.php_cs +++ /dev/null @@ -1,24 +0,0 @@ -notName('LICENSE') - ->notName('README.md') - ->notName('.php_cs') - ->notName('composer.*') - ->notName('phpunit.xml*') - ->notName('*.phar') - ->exclude('vendor') - ->exclude('examples') - ->exclude('Symfony/CS/Tests/Fixer') - ->notName('ElseifFixer.php') - ->exclude('data') - ->in(__DIR__) -; - -return Symfony\CS\Config\Config::create() - ->finder($finder) -; - - diff --git a/library/Mobile_Detect/.travis.yml b/library/Mobile_Detect/.travis.yml deleted file mode 100644 index 29af5249f0..0000000000 --- a/library/Mobile_Detect/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -language: php -php: - - "5.2" - - "5.3" - - "5.4" - - "5.5" - - "5.6" - -branches: - only: - - devel - -script: - - phpunit -v -c tests/phpunit.xml - -notifications: - email: false diff --git a/library/Mobile_Detect/Mobile_Detect.json b/library/Mobile_Detect/Mobile_Detect.json deleted file mode 100644 index 0ba0163198..0000000000 --- a/library/Mobile_Detect/Mobile_Detect.json +++ /dev/null @@ -1 +0,0 @@ -{"version":"2.8.11","headerMatch":{"HTTP_ACCEPT":{"matches":["application\/x-obml2d","application\/vnd.rim.html","text\/vnd.wap.wml","application\/vnd.wap.xhtml+xml"]},"HTTP_X_WAP_PROFILE":null,"HTTP_X_WAP_CLIENTID":null,"HTTP_WAP_CONNECTION":null,"HTTP_PROFILE":null,"HTTP_X_OPERAMINI_PHONE_UA":null,"HTTP_X_NOKIA_GATEWAY_ID":null,"HTTP_X_ORANGE_ID":null,"HTTP_X_VODAFONE_3GPDPCONTEXT":null,"HTTP_X_HUAWEI_USERID":null,"HTTP_UA_OS":null,"HTTP_X_MOBILE_GATEWAY":null,"HTTP_X_ATT_DEVICEID":null,"HTTP_UA_CPU":{"matches":["ARM"]}},"uaHttpHeaders":["HTTP_USER_AGENT","HTTP_X_OPERAMINI_PHONE_UA","HTTP_X_DEVICE_USER_AGENT","HTTP_X_ORIGINAL_USER_AGENT","HTTP_X_SKYFIRE_PHONE","HTTP_X_BOLT_PHONE_UA","HTTP_DEVICE_STOCK_UA","HTTP_X_UCBROWSER_DEVICE_UA"],"uaMatch":{"phones":{"iPhone":"\\biPhone\\b|\\biPod\\b","BlackBerry":"BlackBerry|\\bBB10\\b|rim[0-9]+","HTC":"HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m","Nexus":"Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6","Dell":"Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b","Motorola":"Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925","Samsung":"Samsung|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750","LG":"\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802)","Sony":"SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533","Asus":"Asus.*Galaxy|PadFone.*Mobile","Micromax":"Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b","Palm":"PalmSource|Palm","Vertu":"Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature","Pantech":"PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790","Fly":"IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250","iMobile":"i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)","SimValley":"\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b","Wolfgang":"AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q","Alcatel":"Alcatel","Nintendo":"Nintendo 3DS","Amoi":"Amoi","INQ":"INQ","GenericPhone":"Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser"},"tablets":{"iPad":"iPad|iPad.*Mobile","NexusTablet":"Android.*Nexus[\\s]+(7|9|10)|^.*Android.*Nexus(?:(?!Mobile).)*$","SamsungTablet":"SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-I9205|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T707A|SM-T807A|SM-T237P|SM-T807P|SM-P607T|SM-T217T|SM-T337T","Kindle":"Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI)\\b","SurfaceTablet":"Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)","HPTablet":"HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10","AsusTablet":"^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG","BlackBerryTablet":"PlayBook|RIM Tablet","HTCtablet":"HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410","MotorolaTablet":"xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617","NookTablet":"Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2","AcerTablet":"Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b","ToshibaTablet":"Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO","LGTablet":"\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b","FujitsuTablet":"Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b","PrestigioTablet":"PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD","LenovoTablet":"Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)","DellTablet":"Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7","YarvikTablet":"Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b","MedionTablet":"Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB","ArnovaTablet":"AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2","IntensoTablet":"INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004","IRUTablet":"M702pro","MegafonTablet":"MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b","EbodaTablet":"E-Boda (Supreme|Impresspeed|Izzycomm|Essential)","AllViewTablet":"Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)","ArchosTablet":"\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b","AinolTablet":"NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark","SonyTablet":"Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551","PhilipsTablet":"\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b","CubeTablet":"Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT","CobyTablet":"MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010","MIDTablet":"M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733","MSITablet":"MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b","SMiTTablet":"Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)","RockChipTablet":"Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A","FlyTablet":"IQ310|Fly Vision","bqTablet":"bq.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant)|Maxwell.*Lite|Maxwell.*Plus","HuaweiTablet":"MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim","NecTablet":"\\bN-06D|\\bN-08D","PantechTablet":"Pantech.*P4100","BronchoTablet":"Broncho.*(N701|N708|N802|a710)","VersusTablet":"TOUCHPAD.*[78910]|\\bTOUCHTAB\\b","ZyncTablet":"z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900","PositivoTablet":"TB07STA|TB10STA|TB07FTA|TB10FTA","NabiTablet":"Android.*\\bNabi","KoboTablet":"Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build","DanewTablet":"DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b","TexetTablet":"NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE","PlaystationTablet":"Playstation.*(Portable|Vita)","TrekstorTablet":"ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab","PyleAudioTablet":"\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b","AdvanTablet":"Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ","DanyTechTablet":"Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1","GalapadTablet":"Android.*\\bG1\\b","MicromaxTablet":"Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b","KarbonnTablet":"Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b","AllFineTablet":"Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide","PROSCANTablet":"\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b","YONESTablet":"BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026","ChangJiaTablet":"TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503","GUTablet":"TX-A1301|TX-M9002|Q702|kf026","PointOfViewTablet":"TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10","OvermaxTablet":"OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)","HCLTablet":"HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync","DPSTablet":"DPS Dream 9|DPS Dual 7","VistureTablet":"V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10","CrestaTablet":"CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989","MediatekTablet":"\\bMT8125|MT8389|MT8135|MT8377\\b","ConcordeTablet":"Concorde([ ]+)?Tab|ConCorde ReadMan","GoCleverTablet":"GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042","ModecomTablet":"FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003","VoninoTablet":"\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b","ECSTablet":"V07OT2|TM105A|S10OT1|TR10CS1","StorexTablet":"eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab","VodafoneTablet":"SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7","EssentielBTablet":"Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2","RossMoorTablet":"RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711","iMobileTablet":"i-mobile i-note","TolinoTablet":"tolino tab [0-9.]+|tolino shine","AudioSonicTablet":"\\bC-22Q|T7-QC|T-17B|T-17P\\b","AMPETablet":"Android.* A78 ","SkkTablet":"Android.* (SKYPAD|PHOENIX|CYCLOPS)","TecnoTablet":"TECNO P9","JXDTablet":"Android.*\\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b","iJoyTablet":"Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)","FX2Tablet":"FX2 PAD7|FX2 PAD10","XoroTablet":"KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151","ViewsonicTablet":"ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a","OdysTablet":"LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10","CaptivaTablet":"CAPTIVA PAD","IconbitTablet":"NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S","TeclastTablet":"T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi","JaytechTablet":"TPC-PA762","BlaupunktTablet":"Endeavour 800NG|Endeavour 1010","DigmaTablet":"\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b","EvolioTablet":"ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b","LavaTablet":"QPAD E704|\\bIvoryS\\b|E-TAB IVORY","CelkonTablet":"CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b","MiTablet":"\\bMI PAD\\b|\\bHM NOTE 1W\\b","NibiruTablet":"Nibiru M1|Nibiru Jupiter One","NexoTablet":"NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI","UbislateTablet":"UbiSlate[\\s]?7C","PocketBookTablet":"Pocketbook","Hudl":"Hudl HT7S3","TelstraTablet":"T-Hub2","GenericTablet":"Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bJolla\\b"},"browsers":{"Chrome":"\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?","Dolfin":"\\bDolfin\\b","Opera":"Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+","Skyfire":"Skyfire","IE":"IEMobile|MSIEMobile","Firefox":"fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile","Bolt":"bolt","TeaShark":"teashark","Blazer":"Blazer","Safari":"Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari","Tizen":"Tizen","UCBrowser":"UC.*Browser|UCWEB","baiduboxapp":"baiduboxapp","baidubrowser":"baidubrowser","DiigoBrowser":"DiigoBrowser","Puffin":"Puffin","Mercury":"\\bMercury\\b","ObigoBrowser":"Obigo","NetFront":"NF-Browser","GenericBrowser":"NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger"},"os":{"AndroidOS":"Android","BlackBerryOS":"blackberry|\\bBB10\\b|rim tablet os","PalmOS":"PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino","SymbianOS":"Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b","WindowsMobileOS":"Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;","WindowsPhoneOS":"Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;","iOS":"\\biPhone.*Mobile|\\biPod|\\biPad","MeeGoOS":"MeeGo","MaemoOS":"Maemo","JavaOS":"J2ME\/|\\bMIDP\\b|\\bCLDC\\b","webOS":"webOS|hpwOS","badaOS":"\\bBada\\b","BREWOS":"BREW"},"utilities":{"DesktopMode":"WPDesktop","TV":"SonyDTV|HbbTV","WebKit":"(webkit)[ \/]([\\w.]+)","Bot":"Googlebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|facebookexternalhit","MobileBot":"Googlebot-Mobile|YahooSeeker\/M1A1-R2D2","Console":"\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b","Watch":"SM-V700"}}} \ No newline at end of file diff --git a/library/Mobile_Detect/README.md b/library/Mobile_Detect/README.md deleted file mode 100644 index db46648e63..0000000000 --- a/library/Mobile_Detect/README.md +++ /dev/null @@ -1,219 +0,0 @@ -[![Build Status](https://travis-ci.org/serbanghita/Mobile-Detect.svg?branch=devel)](https://travis-ci.org/serbanghita/Mobile-Detect) [![Latest Stable Version](https://poser.pugx.org/mobiledetect/mobiledetectlib/v/stable.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib) [![Total Downloads](https://poser.pugx.org/mobiledetect/mobiledetectlib/downloads.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib) [![Daily Downloads](https://poser.pugx.org/mobiledetect/mobiledetectlib/d/daily.png)](https://packagist.org/packages/mobiledetect/mobiledetectlib) [![License](https://poser.pugx.org/mobiledetect/mobiledetectlib/license.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib) -[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/serbanghita/Mobile-Detect?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) - -![Mobile Detect](http://demo.mobiledetect.net/logo-github.png) - -> Motto: "Every business should have a mobile detection script to detect mobile readers." - -Mobile_Detect is a lightweight PHP class for detecting mobile devices (including tablets). -It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment. - -> We're commited to make Mobile_Detect the best open-source mobile detection resource and this is why before each release we're running [unit tests](./tests), we also research and update the detection rules on daily and weekly basis. - -Your website's _content strategy_ is important! You need a complete toolkit to deliver an experience that is _optimized_, _fast_ and _relevant_ to your users. Mobile_Detect class is a [server-side detection](http://www.w3.org/TR/mwabp/#bp-devcap-detection) tool that can help you with your RWD strategy, it is not a replacement for CSS3 media queries or other forms of client-side feature detection. - -##### This month updates - -First of all a **BIG THANK YOU** to our growing community for your continuous support and for all the feedback received! I'm still working my way with the current issues and all the emails. - -Nick is almost done with all the code for the upcoming `3.0.0` so that I only have to integrate the new parsing engine. We will release minor `2.8.xx` versions until a feature freeze where we will switch to the new branch. You will all be announced before this and hopefully we can make the transition smooth for everyone. - - Last but not least, special thanks for supporting us to our friends from [TryCatch.us](http://trycatch.us/) who _are set to carefully curate the most talented developers in Europe_! - -Thank you all and we're excited for the new release! - -##### Download and demo - -|Download|Docs|Examples| -|-------------|-------------|-------------| -|[Go to releases](../../tags)|[Become a contributor](../../wiki/Become-a-contributor)|[Code examples](../../wiki/Code-examples) -|[Mobile_Detect.php](./Mobile_Detect.php)|[History](../../wiki/History)|[:iphone: Live demo!](http://is.gd/mobiletest) -|[Composer package](https://packagist.org/packages/mobiledetect/mobiledetectlib)| - -##### Help - -|Pledgie|Paypal| -|-------|------| -|[Donate :+1:](http://pledgie.com/campaigns/21856)|[Donate :beer:](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=mobiledetectlib%40gmail%2ecom&lc=US&item_name=Mobile%20Detect¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted)| - - -I'm currently paying for hosting and spend a lot of my family time to maintain the project and planning the future releases. -I would highly appreciate any money donations that will keep the research going. - -Special thanks to the community :+1: for donations, [BrowserStack](http://browserstack.com) - for providing access to their great platform, [Zend](http://zend.com) - for donating licenses, [Dragos Gavrila](https://twitter.com/grafician) who contributed with the logo. - -##### 3rd party modules / [Submit new](../../issues/new?title=New%203rd%20party%20module&body=Name, Link and Description of the module.) - -:point_right: Keep `Mobile_Detect.php` class in a separate `module` and do NOT include it in your script core because of the high frequency of updates. -:point_right: When including the class into you `web application` or `module` always use `include_once '../path/to/Mobile_Detect.php` to prevent conflicts. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Varnish Cache -

Varnish Mobile Detect - Drop-in varnish solution to mobile user detection based on the Mobile-Detect library. Made by willemk

-

mobiledetect2vcl - Python script to transform the Mobile Detect JSON database into an UA-based mobile detection VCL subroutine easily integrable in any Varnish Cache configuration. Made by Carlos Abalde

-
WordPress -

WordPress Mobile Detect - Gives you the ability to wrap that infographic in a `[notdevice][/notdevice]` shortcode so at the server level WordPress will decide to show that content only if the user is NOT on a phone or tablet. Made by Jesse Friedman.

- -

mobble - provides mobile related conditional functions for your site. e.g. is_iphone(), is_mobile() and is_tablet(). Made by Scott Evans.

- -

WordPress Responsage - A small WordPress theme plugin that allows you to make your images responsive. Made by Adrian Ciaschetti.

- -

Social PopUP - This plugin will display a popup or splash screen when a new user visit your site showing a Google+, Twitter and Facebook follow links. It uses Mobile_Detect to detect mobile devices.

-
Drupal -

Drupal Mobile Switch - The Mobile Switch Drupal module provides a automatic theme switch functionality for mobile devices, - detected by Browscap or Mobile Detect. Made by Siegfried Neumann.

- -

Drupal Context Mobile Detect - This is a Drupal context module which integrates Context and PHP Mobile Detect library. - Created by Artem Shymko.

- -

Drupal Mobile Detect - Lightweight mobile detect module for Drupal created by Matthew Donadio

-
Joomla

yagendoo Joomla! Mobile Detection Plugin - Lightweight PHP plugin for Joomla! that detects a mobile browser using the Mobile Detect class. Made by yagendoo media.

Magento

Magento - This Magento helper from Optimise Web enables the use of all functions provided by MobileDetect.net. - Made by Kathir Vel.

PrestaShop

PrestaShop is a free, secure and open source shopping cart platform. Mobile_Detect is included in the default package since 1.5.x.

Zend Framework -

ZF2 Mobile-Detect - Zend Framework 2 module that provides Mobile-Detect features (Mobile_Detect class as a service, helper for views and plugin controllers). Made by neilime

- -

ZF2 MobileDetectModule - Facilitates integration of a PHP MobileDetect class with some ZF2-based application. Has similar idea like the existing ZF2 Mobile-Detect module, but differs in initialization and provision routine of the actual Mobile_Detect class. Appropriate view helper and controller plugin also have different conceptions. Made by Nikola Posa

-
Symfony

Symfony2 Mobile Detect Bundle - The bundle for detecting mobile devices, manage mobile view and redirect to the mobile and tablet version. - Made by Nikolay Ivlev.

-

Silex Mobile Detect Service Provider - Silex service provider to interact with Mobile detect class methods. Made by Lhassan Baazzi.

-
Laravel -

Laravel-Agent a user agent class for Laravel, based on Mobile Detect with some additional functionality. Made by Jens Segers.

-

BrowserDetect is a browser & mobile detection package, collects and wrap together the best user-agent identifiers for Laravel. Created by Varga Zsolt.

-
ExpressionEngine

EE2 Detect Mobile - Lightweight PHP plugin for EE2 that detects a mobile browser using the Mobile Detect class. Made by Gareth Davies.

Yii Framework

Yii Extension - Mobile detect plugin for Yii framework. Made by Alexey Salnikov.

CakePHP

CakePHP MobileDetect - plugin component for CakePHP 2.x. Made by Gregory Gaskill

FuelPHPSpecial Agent is a FuelPHP package which uses php-mobile-detect to determine whether a device is mobile or not. -It overrides the Fuelphp Agent class its methods. Made by Robbie Bardjin.
Typo3px_mobiledetect is an extension that helps to detect visitor's mobile device class (if that’s tablet or mobile device like smartphone). Made by Alexander Tretyak.
Statamic

Statamic CMS Mobile Detect - plugin. Made by Sergei Filippov of Haiku Lab.

Kohana

Kohana Mobile Detect - an example of implementation of Mobile_Detect class with Kohana framework. Written by Luiz Alberto S. Ribeiro.

mobile-detect.js

A JavaScript port of Mobile-Detect class. Made by Heinrich Goebl

Perl

MobileDetect.pm - Perl module for Mobile Detect. Made by Sebastian Enger.

python

pymobiledetect - Mobile detect python package. Made by Bas van Oostveen.

Ruby

mobile_detect.rb - A Ruby gem using the JSON data exposed by the php project and implementing a basic subset of the API (as much as can be done by the exposed data). Made by Karthik T.

GoMobileDetect

GoMobileDetect - Go port of Mobile Detect class. Made by Shaked.

MemHT

MemHT is a Free PHP CMS and Blog that permit the creation and the management online of websites with few and easy steps. Has the class included in the core.

concrete5

concrete5 is a CMS that is free and open source. The library is included in the core.

engine7

ExEngine 7 PHP Open Source Framework. The Mobile_Detect class is included in the engine.

Zikula

Zikula is a free and open-source Content Management Framework, which allows you to run impressive websites and build powerful online applications. The core uses Mobile-Detect to switch to a special Mobile theme, using jQueryMobile

UserAgentInfo

UserAgentInfo is a PHP class for parsing user agent strings (HTTP_USER_AGENT). Includes mobile checks, bot checks, browser types/versions and more. -Based on browscap, Mobile_Detect and ua-parser. Created for high traffic websites and fast batch processing. Made by quentin389

Craft CMS

LJ Mobile Detect is a simple implementation of Mobile Detect for Craft CMS. Made by Lewis Jenkins

diff --git a/library/Mobile_Detect/LICENSE.txt b/vendor/mobiledetect/mobiledetectlib/LICENSE.txt similarity index 96% rename from library/Mobile_Detect/LICENSE.txt rename to vendor/mobiledetect/mobiledetectlib/LICENSE.txt index 101abf8be5..90e632a787 100644 --- a/library/Mobile_Detect/LICENSE.txt +++ b/vendor/mobiledetect/mobiledetectlib/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (c) <2011-2014> +Copyright (c) <2011-2015> Serban Ghita, Nick Ilyin and contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/vendor/mobiledetect/mobiledetectlib/Mobile_Detect.json b/vendor/mobiledetect/mobiledetectlib/Mobile_Detect.json new file mode 100644 index 0000000000..dc5420f309 --- /dev/null +++ b/vendor/mobiledetect/mobiledetectlib/Mobile_Detect.json @@ -0,0 +1 @@ +{"version":"2.8.25","headerMatch":{"HTTP_ACCEPT":{"matches":["application\/x-obml2d","application\/vnd.rim.html","text\/vnd.wap.wml","application\/vnd.wap.xhtml+xml"]},"HTTP_X_WAP_PROFILE":null,"HTTP_X_WAP_CLIENTID":null,"HTTP_WAP_CONNECTION":null,"HTTP_PROFILE":null,"HTTP_X_OPERAMINI_PHONE_UA":null,"HTTP_X_NOKIA_GATEWAY_ID":null,"HTTP_X_ORANGE_ID":null,"HTTP_X_VODAFONE_3GPDPCONTEXT":null,"HTTP_X_HUAWEI_USERID":null,"HTTP_UA_OS":null,"HTTP_X_MOBILE_GATEWAY":null,"HTTP_X_ATT_DEVICEID":null,"HTTP_UA_CPU":{"matches":["ARM"]}},"uaHttpHeaders":["HTTP_USER_AGENT","HTTP_X_OPERAMINI_PHONE_UA","HTTP_X_DEVICE_USER_AGENT","HTTP_X_ORIGINAL_USER_AGENT","HTTP_X_SKYFIRE_PHONE","HTTP_X_BOLT_PHONE_UA","HTTP_DEVICE_STOCK_UA","HTTP_X_UCBROWSER_DEVICE_UA"],"uaMatch":{"phones":{"iPhone":"\\biPhone\\b|\\biPod\\b","BlackBerry":"BlackBerry|\\bBB10\\b|rim[0-9]+","HTC":"HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m","Nexus":"Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6","Dell":"Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b","Motorola":"Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b","Samsung":"\\bSamsung\\b|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C","LG":"\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)","Sony":"SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533","Asus":"Asus.*Galaxy|PadFone.*Mobile","NokiaLumia":"Lumia [0-9]{3,4}","Micromax":"Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b","Palm":"PalmSource|Palm","Vertu":"Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature","Pantech":"PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790","Fly":"IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250","Wiko":"KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM","iMobile":"i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)","SimValley":"\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b","Wolfgang":"AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q","Alcatel":"Alcatel","Nintendo":"Nintendo 3DS","Amoi":"Amoi","INQ":"INQ","GenericPhone":"Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser"},"tablets":{"iPad":"iPad|iPad.*Mobile","NexusTablet":"Android.*Nexus[\\s]+(7|9|10)","SamsungTablet":"SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587","Kindle":"Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\\b|Android.*Silk\/[0-9.]+ like Chrome\/[0-9.]+ (?!Mobile)","SurfaceTablet":"Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)","HPTablet":"HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10","AsusTablet":"^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z","BlackBerryTablet":"PlayBook|RIM Tablet","HTCtablet":"HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410","MotorolaTablet":"xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617","NookTablet":"Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2","AcerTablet":"Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20\\b|\\bA3-A30","ToshibaTablet":"Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO","LGTablet":"\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b","FujitsuTablet":"Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b","PrestigioTablet":"PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002","LenovoTablet":"Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)","DellTablet":"Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7","YarvikTablet":"Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b","MedionTablet":"Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB","ArnovaTablet":"97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2","IntensoTablet":"INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004","IRUTablet":"M702pro","MegafonTablet":"MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b","EbodaTablet":"E-Boda (Supreme|Impresspeed|Izzycomm|Essential)","AllViewTablet":"Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)","ArchosTablet":"\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b","AinolTablet":"NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark","NokiaLumiaTablet":"Lumia 2520","SonyTablet":"Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31","PhilipsTablet":"\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b","CubeTablet":"Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT","CobyTablet":"MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010","MIDTablet":"M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10","MSITablet":"MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b","SMiTTablet":"Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)","RockChipTablet":"Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A","FlyTablet":"IQ310|Fly Vision","bqTablet":"Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris [E|M]10)|Maxwell.*Lite|Maxwell.*Plus","HuaweiTablet":"MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim","NecTablet":"\\bN-06D|\\bN-08D","PantechTablet":"Pantech.*P4100","BronchoTablet":"Broncho.*(N701|N708|N802|a710)","VersusTablet":"TOUCHPAD.*[78910]|\\bTOUCHTAB\\b","ZyncTablet":"z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900","PositivoTablet":"TB07STA|TB10STA|TB07FTA|TB10FTA","NabiTablet":"Android.*\\bNabi","KoboTablet":"Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build","DanewTablet":"DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b","TexetTablet":"NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE","PlaystationTablet":"Playstation.*(Portable|Vita)","TrekstorTablet":"ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab","PyleAudioTablet":"\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b","AdvanTablet":"Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ","DanyTechTablet":"Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1","GalapadTablet":"Android.*\\bG1\\b","MicromaxTablet":"Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b","KarbonnTablet":"Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b","AllFineTablet":"Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide","PROSCANTablet":"\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b","YONESTablet":"BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026","ChangJiaTablet":"TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503","GUTablet":"TX-A1301|TX-M9002|Q702|kf026","PointOfViewTablet":"TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10","OvermaxTablet":"OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)","HCLTablet":"HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync","DPSTablet":"DPS Dream 9|DPS Dual 7","VistureTablet":"V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10","CrestaTablet":"CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989","MediatekTablet":"\\bMT8125|MT8389|MT8135|MT8377\\b","ConcordeTablet":"Concorde([ ]+)?Tab|ConCorde ReadMan","GoCleverTablet":"GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042","ModecomTablet":"FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003","VoninoTablet":"\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b","ECSTablet":"V07OT2|TM105A|S10OT1|TR10CS1","StorexTablet":"eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab","VodafoneTablet":"SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497","EssentielBTablet":"Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2","RossMoorTablet":"RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711","iMobileTablet":"i-mobile i-note","TolinoTablet":"tolino tab [0-9.]+|tolino shine","AudioSonicTablet":"\\bC-22Q|T7-QC|T-17B|T-17P\\b","AMPETablet":"Android.* A78 ","SkkTablet":"Android.* (SKYPAD|PHOENIX|CYCLOPS)","TecnoTablet":"TECNO P9","JXDTablet":"Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b","iJoyTablet":"Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)","FX2Tablet":"FX2 PAD7|FX2 PAD10","XoroTablet":"KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151","ViewsonicTablet":"ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a","OdysTablet":"LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10","CaptivaTablet":"CAPTIVA PAD","IconbitTablet":"NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S","TeclastTablet":"T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi","OndaTablet":"\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+","JaytechTablet":"TPC-PA762","BlaupunktTablet":"Endeavour 800NG|Endeavour 1010","DigmaTablet":"\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b","EvolioTablet":"ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b","LavaTablet":"QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b","AocTablet":"MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712","MpmanTablet":"MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010","CelkonTablet":"CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b","WolderTablet":"miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b","MiTablet":"\\bMI PAD\\b|\\bHM NOTE 1W\\b","NibiruTablet":"Nibiru M1|Nibiru Jupiter One","NexoTablet":"NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI","LeaderTablet":"TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100","UbislateTablet":"UbiSlate[\\s]?7C","PocketBookTablet":"Pocketbook","KocasoTablet":"\\b(TB-1207)\\b","HisenseTablet":"\\b(F5281|E2371)\\b","Hudl":"Hudl HT7S3|Hudl 2","TelstraTablet":"T-Hub2","GenericTablet":"Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bTP750\\b"},"browsers":{"Chrome":"\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?","Dolfin":"\\bDolfin\\b","Opera":"Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+","Skyfire":"Skyfire","Edge":"Mobile Safari\/[.0-9]* Edge","IE":"IEMobile|MSIEMobile","Firefox":"fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS","Bolt":"bolt","TeaShark":"teashark","Blazer":"Blazer","Safari":"Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari","UCBrowser":"UC.*Browser|UCWEB","baiduboxapp":"baiduboxapp","baidubrowser":"baidubrowser","DiigoBrowser":"DiigoBrowser","Puffin":"Puffin","Mercury":"\\bMercury\\b","ObigoBrowser":"Obigo","NetFront":"NF-Browser","GenericBrowser":"NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger","PaleMoon":"Android.*PaleMoon|Mobile.*PaleMoon"},"os":{"AndroidOS":"Android","BlackBerryOS":"blackberry|\\bBB10\\b|rim tablet os","PalmOS":"PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino","SymbianOS":"Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b","WindowsMobileOS":"Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;","WindowsPhoneOS":"Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;","iOS":"\\biPhone.*Mobile|\\biPod|\\biPad","MeeGoOS":"MeeGo","MaemoOS":"Maemo","JavaOS":"J2ME\/|\\bMIDP\\b|\\bCLDC\\b","webOS":"webOS|hpwOS","badaOS":"\\bBada\\b","BREWOS":"BREW"},"utilities":{"Bot":"Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom","MobileBot":"Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2","DesktopMode":"WPDesktop","TV":"SonyDTV|HbbTV","WebKit":"(webkit)[ \/]([\\w.]+)","Console":"\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b","Watch":"SM-V700"}}} \ No newline at end of file diff --git a/library/Mobile_Detect/Mobile_Detect.php b/vendor/mobiledetect/mobiledetectlib/Mobile_Detect.php similarity index 75% rename from library/Mobile_Detect/Mobile_Detect.php rename to vendor/mobiledetect/mobiledetectlib/Mobile_Detect.php index 3a82c29690..4e44ff3679 100644 --- a/library/Mobile_Detect/Mobile_Detect.php +++ b/vendor/mobiledetect/mobiledetectlib/Mobile_Detect.php @@ -22,7 +22,7 @@ * README: https://github.com/serbanghita/Mobile-Detect/blob/master/README.md * HOWTO: https://github.com/serbanghita/Mobile-Detect/wiki/Code-examples * - * @version 2.8.11 + * @version 2.8.25 */ class Mobile_Detect @@ -66,7 +66,7 @@ class Mobile_Detect /** * Stores the version number of the current release. */ - const VERSION = '2.8.11'; + const VERSION = '2.8.25'; /** * A type for the version() method indicating a string return value. @@ -78,6 +78,12 @@ class Mobile_Detect */ const VERSION_TYPE_FLOAT = 'float'; + /** + * A cache for resolved matches + * @var array + */ + protected $cache = array(); + /** * The User-Agent HTTP header is stored in here. * @var string @@ -90,6 +96,12 @@ class Mobile_Detect */ protected $httpHeaders = array(); + /** + * CloudFront headers. E.g. CloudFront-Is-Desktop-Viewer, CloudFront-Is-Mobile-Viewer & CloudFront-Is-Tablet-Viewer. + * @var array + */ + protected $cloudfrontHeaders = array(); + /** * The matching Regex. * This is good for debug. @@ -161,11 +173,12 @@ class Mobile_Detect 'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6', // @todo: Is 'Dell Streak' a tablet or a phone? ;) 'Dell' => 'Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b', - 'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925', - 'Samsung' => 'Samsung|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750', - 'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802)', + 'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\bMoto E\b', + 'Samsung' => '\bSamsung\b|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C', + 'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)', 'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533', 'Asus' => 'Asus.*Galaxy|PadFone.*Mobile', + 'NokiaLumia' => 'Lumia [0-9]{3,4}', // http://www.micromaxinfo.com/mobiles/smartphones // Added because the codes might conflict with Acer Tablets. 'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b', @@ -177,7 +190,9 @@ class Mobile_Detect 'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790', // http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones. 'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250', - 'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)', + // http://fr.wikomobile.com + 'Wiko' => 'KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM', + 'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)', // Added simvalley mobile just for fun. They have some interesting devices. // http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html 'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b', @@ -200,11 +215,14 @@ class Mobile_Detect * @var array */ protected static $tabletDevices = array( - 'iPad' => 'iPad|iPad.*Mobile', // @todo: check for mobile friendly emails topic. - 'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)|^.*Android.*Nexus(?:(?!Mobile).)*$', - 'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-I9205|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T707A|SM-T807A|SM-T237P|SM-T807P|SM-P607T|SM-T217T|SM-T337T', // SCH-P709|SCH-P729|SM-T2558 - Samsung Mega - treat them like a regular phone. + // @todo: check for mobile friendly emails topic. + 'iPad' => 'iPad|iPad.*Mobile', + // Removed |^.*Android.*Nexus(?!(?:Mobile).)*$ + // @see #442 + 'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)', + 'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone. // http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html - 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI)\b', + 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\b|Android.*Silk/[0-9.]+ like Chrome/[0-9.]+ (?!Mobile)', // Only the Surface tablets with Windows RT are considered mobile. // http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx 'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)', @@ -212,7 +230,7 @@ class Mobile_Detect 'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10', // Watch out for PadFone, see #132. // http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/ - 'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG', + 'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\bME70C\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z', 'BlackBerryTablet' => 'PlayBook|RIM Tablet', 'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410', 'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617', @@ -222,7 +240,7 @@ class Mobile_Detect // http://us.acer.com/ac/en/US/content/group/tablets // http://www.acer.de/ac/de/DE/content/models/tablets/ // Can conflict with Micromax and Motorola phones codes. - 'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b', + 'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b|\bA3-A11\b|\bA3-A20\b|\bA3-A30', // http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/ // http://us.toshiba.com/tablets/tablet-finder // http://www.toshiba.co.jp/regza/tablet/ @@ -232,15 +250,15 @@ class Mobile_Detect 'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b', 'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b', // Prestigio Tablets http://www.prestigio.com/support - 'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD', + 'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002', // http://support.lenovo.com/en_GB/downloads/default.page?# - 'LenovoTablet' => 'Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)', + 'LenovoTablet' => 'Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)', // http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets 'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7', // http://www.yarvik.com/en/matrix/tablets/ 'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b', 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB', - 'ArnovaTablet' => 'AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2', + 'ArnovaTablet' => '97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2', // http://www.intenso.de/kategorie_en.php?kategorie=33 // @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate 'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004', @@ -252,13 +270,15 @@ class Mobile_Detect // http://www.allview.ro/produse/droseries/lista-tablete-pc/ 'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)', // http://wiki.archosfans.com/index.php?title=Main_Page - 'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b', + // @note Rewrite the regex format after we add more UAs. + 'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b', // http://www.ainol.com/plugin.php?identifier=ainol&module=product 'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark', + 'NokiaLumiaTablet' => 'Lumia 2520', // @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER // Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser // http://www.sony.jp/support/tablet/ - 'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551', + 'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31', // http://www.support.philips.com/support/catalog/worldproducts.jsp?userLanguage=en&userCountry=cn&categoryid=3G_LTE_TABLET_SU_CN_CARE&title=3G%20tablets%20/%20LTE%20range&_dyncharset=UTF-8 'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b', // db + http://www.cube-tablet.com/buy-products.html @@ -266,7 +286,7 @@ class Mobile_Detect // http://www.cobyusa.com/?p=pcat&pcat_id=3001 'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010', // http://www.match.net.cn/products.asp - 'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733', + 'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10', // http://www.msi.com/support // @todo Research the Windows Tablets. 'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b', @@ -282,7 +302,7 @@ class Mobile_Detect // http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/ 'FlyTablet' => 'IQ310|Fly Vision', // http://www.bqreaders.com/gb/tablets-prices-sale.html - 'bqTablet' => 'bq.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant)|Maxwell.*Lite|Maxwell.*Plus', + 'bqTablet' => 'Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris [E|M]10)|Maxwell.*Lite|Maxwell.*Plus', // http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290 // http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets) 'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim', @@ -366,7 +386,7 @@ class Mobile_Detect // @note: no need to add all the tablet codes since they are guided by the first regex. 'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab', // Generic Vodafone tablets. - 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7', + 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497', // French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb // Aka: http://www.essentielb.fr/ 'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2', @@ -387,7 +407,7 @@ class Mobile_Detect // Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1 'TecnoTablet' => 'TECNO P9', // JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3 - 'JXDTablet' => 'Android.*\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b', + 'JXDTablet' => 'Android.* \b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b', // i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/ 'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)', // http://www.intracon.eu/tablet @@ -405,6 +425,8 @@ class Mobile_Detect 'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S', // http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63 'TeclastTablet' => 'T98 4G|\bP80\b|\bX90HD\b|X98 Air|X98 Air 3G|\bX89\b|P80 3G|\bX80h\b|P98 Air|\bX89HD\b|P98 3G|\bP90HD\b|P89 3G|X98 3G|\bP70h\b|P79HD 3G|G18d 3G|\bP79HD\b|\bP89s\b|\bA88\b|\bP10HD\b|\bP19HD\b|G18 3G|\bP78HD\b|\bA78\b|\bP75\b|G17s 3G|G17h 3G|\bP85t\b|\bP90\b|\bP11\b|\bP98t\b|\bP98HD\b|\bG18d\b|\bP85s\b|\bP11HD\b|\bP88s\b|\bA80HD\b|\bA80se\b|\bA10h\b|\bP89\b|\bP78s\b|\bG18\b|\bP85\b|\bA70h\b|\bA70\b|\bG17\b|\bP18\b|\bA80s\b|\bA11s\b|\bP88HD\b|\bA80h\b|\bP76s\b|\bP76h\b|\bP98\b|\bA10HD\b|\bP78\b|\bP88\b|\bA11\b|\bA10t\b|\bP76a\b|\bP76t\b|\bP76e\b|\bP85HD\b|\bP85a\b|\bP86\b|\bP75HD\b|\bP76v\b|\bA12\b|\bP75a\b|\bA15\b|\bP76Ti\b|\bP81HD\b|\bA10\b|\bT760VE\b|\bT720HD\b|\bP76\b|\bP73\b|\bP71\b|\bP72\b|\bT720SE\b|\bC520Ti\b|\bT760\b|\bT720VE\b|T720-3GE|T720-WiFi', + // Onda - http://www.onda-tablet.com/buy-android-onda.html?dir=desc&limit=all&order=price + 'OndaTablet' => '\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\b[\s]+', 'JaytechTablet' => 'TPC-PA762', 'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010', // http://www.digma.ru/support/download/ @@ -415,24 +437,37 @@ class Mobile_Detect // @todo: Research some more 'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b', // @todo http://www.lavamobiles.com/tablets-data-cards - 'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY', + 'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY|\bE-TAB\b', + // http://www.breezetablet.com/ + 'AocTablet' => 'MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712', + // http://www.mpmaneurope.com/en/products/internet-tablets-14/android-tablets-14/ + 'MpmanTablet' => 'MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\bMPG7\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010', // https://www.celkonmobiles.com/?_a=categoryphones&sid=2 'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b', + // http://www.wolderelectronics.com/productos/manuales-y-guias-rapidas/categoria-2-miTab + 'WolderTablet' => 'miTab \b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\b', // http://www.mi.com/en 'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b', // http://www.nbru.cn/index.html 'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One', // http://navroad.com/products/produkty/tablety/ 'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI', + // http://leader-online.com/new_site/product-category/tablets/ + // http://www.leader-online.net.au/List/Tablet + 'LeaderTablet' => 'TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100', // http://www.datawind.com/ubislate/ 'UbislateTablet' => 'UbiSlate[\s]?7C', // http://www.pocketbook-int.com/ru/support 'PocketBookTablet' => 'Pocketbook', + // http://www.kocaso.com/product_tablet.html + 'KocasoTablet' => '\b(TB-1207)\b', + // http://global.hisense.com/product/asia/tablet/Sero7/201412/t20141215_91832.htm + 'HisenseTablet' => '\b(F5281|E2371)\b', // http://www.tesco.com/direct/hudl/ - 'Hudl' => 'Hudl HT7S3', + 'Hudl' => 'Hudl HT7S3|Hudl 2', // http://www.telstra.com.au/home-phone/thub-2/ 'TelstraTablet' => 'T-Hub2', - 'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W|arc 10HD|\bJolla\b' + 'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W|arc 10HD|\bTP750\b' ); /** @@ -451,7 +486,8 @@ class Mobile_Detect // http://wifeng.cn/?r=blog&a=view&id=106 // http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx // http://msdn.microsoft.com/library/ms537503.aspx - 'WindowsPhoneOS' => 'Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;', + // https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx + 'WindowsPhoneOS' => 'Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;', 'iOS' => '\biPhone.*Mobile|\biPod|\biPad', // http://en.wikipedia.org/wiki/MeeGo // @todo: research MeeGo in UAs @@ -468,16 +504,23 @@ class Mobile_Detect /** * List of mobile User Agents. * + * IMPORTANT: This is a list of only mobile browsers. + * Mobile Detect 2.x supports only mobile browsers, + * it was never designed to detect all browsers. + * The change will come in 2017 in the 3.x release for PHP7. + * * @var array */ protected static $browsers = array( + //'Vivaldi' => 'Vivaldi', // @reference: https://developers.google.com/chrome/mobile/docs/user-agent 'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?', 'Dolfin' => '\bDolfin\b', 'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+|Coast/[0-9.]+', 'Skyfire' => 'Skyfire', + 'Edge' => 'Mobile Safari/[.0-9]* Edge', 'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+ - 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile', + 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS', 'Bolt' => 'bolt', 'TeaShark' => 'teashark', 'Blazer' => 'Blazer', @@ -485,7 +528,7 @@ class Mobile_Detect 'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari', // http://en.wikipedia.org/wiki/Midori_(web_browser) //'Midori' => 'midori', - 'Tizen' => 'Tizen', + //'Tizen' => 'Tizen', 'UCBrowser' => 'UC.*Browser|UCWEB', 'baiduboxapp' => 'baiduboxapp', 'baidubrowser' => 'baidubrowser', @@ -502,6 +545,8 @@ class Mobile_Detect // @reference: http://en.wikipedia.org/wiki/Minimo // http://en.wikipedia.org/wiki/Vision_Mobile_Browser 'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger', + // @reference: https://en.wikipedia.org/wiki/Pale_Moon_(web_browser) + 'PaleMoon' => 'Android.*PaleMoon|Mobile.*PaleMoon', ); /** @@ -513,11 +558,12 @@ class Mobile_Detect // Experimental. When a mobile device wants to switch to 'Desktop Mode'. // http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/ // https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011 + // https://developers.facebook.com/docs/sharing/best-practices + 'Bot' => 'Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom', + 'MobileBot' => 'Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker/M1A1-R2D2', 'DesktopMode' => 'WPDesktop', 'TV' => 'SonyDTV|HbbTV', // experimental 'WebKit' => '(webkit)[ /]([\w.]+)', - 'Bot' => 'Googlebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|facebookexternalhit', - 'MobileBot' => 'Googlebot-Mobile|YahooSeeker/M1A1-R2D2', // @todo: Include JXD consoles. 'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\b', 'Watch' => 'SM-V700', @@ -568,11 +614,13 @@ class Mobile_Detect 'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'), 'Coast' => array('Coast/[VER]'), 'Dolfin' => 'Dolfin/[VER]', - // @reference: https://developer.mozilla.org/en-US/docs/User_Agent_Strings_Reference - 'Firefox' => 'Firefox/[VER]', + // @reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/Firefox + 'Firefox' => array('Firefox/[VER]', 'FxiOS/[VER]'), 'Fennec' => 'Fennec/[VER]', - // @reference: http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx - 'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];'), + // http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx + // https://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx + 'Edge' => 'Edge/[VER]', + 'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'Trident/[0-9.]+;.*rv:[VER]'), // http://en.wikipedia.org/wiki/NetFront 'NetFront' => 'NetFront/[VER]', 'NokiaBrowser' => 'NokiaBrowser/[VER]', @@ -584,6 +632,7 @@ class Mobile_Detect 'MicroMessenger' => 'MicroMessenger/[VER]', 'baiduboxapp' => 'baiduboxapp/[VER]', 'baidubrowser' => 'baidubrowser/[VER]', + 'SamsungBrowser' => 'SamsungBrowser/[VER]', 'Iron' => 'Iron/[VER]', // @note: Safari 7534.48.3 is actually Version 5.1. // @note: On BlackBerry the Version is overwriten by the OS. @@ -591,14 +640,16 @@ class Mobile_Detect 'Skyfire' => 'Skyfire/[VER]', 'Tizen' => 'Tizen/[VER]', 'Webkit' => 'webkit[ /][VER]', + 'PaleMoon' => 'PaleMoon/[VER]', // Engine 'Gecko' => 'Gecko/[VER]', 'Trident' => 'Trident/[VER]', 'Presto' => 'Presto/[VER]', + 'Goanna' => 'Goanna/[VER]', // OS - 'iOS' => ' \bOS\b [VER] ', + 'iOS' => ' \bi?OS\b [VER][ ;]{1}', 'Android' => 'Android [VER]', 'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'), 'BREW' => 'BREW [VER]', @@ -647,25 +698,28 @@ class Mobile_Detect * Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers. * * @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract - * the headers. The default null is left for backwards compatibilty. + * the headers. The default null is left for backwards compatibility. */ public function setHttpHeaders($httpHeaders = null) { - //use global _SERVER if $httpHeaders aren't defined + // use global _SERVER if $httpHeaders aren't defined if (!is_array($httpHeaders) || !count($httpHeaders)) { $httpHeaders = $_SERVER; } - //clear existing headers + // clear existing headers $this->httpHeaders = array(); - //Only save HTTP headers. In PHP land, that means only _SERVER vars that - //start with HTTP_. + // Only save HTTP headers. In PHP land, that means only _SERVER vars that + // start with HTTP_. foreach ($httpHeaders as $key => $value) { - if (substr($key,0,5) == 'HTTP_') { + if (substr($key, 0, 5) === 'HTTP_') { $this->httpHeaders[$key] = $value; } } + + // In case we're dealing with CloudFront, we need to know. + $this->setCfHeaders($httpHeaders); } /** @@ -690,13 +744,13 @@ class Mobile_Detect */ public function getHttpHeader($header) { - //are we using PHP-flavored headers? + // are we using PHP-flavored headers? if (strpos($header, '_') === false) { $header = str_replace('-', '_', $header); $header = strtoupper($header); } - //test the alternate, too + // test the alternate, too $altHeader = 'HTTP_' . $header; //Test both the regular and the HTTP_ prefix @@ -725,6 +779,47 @@ class Mobile_Detect return self::$uaHttpHeaders; } + + /** + * Set CloudFront headers + * http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device + * + * @param array $cfHeaders List of HTTP headers + * + * @return boolean If there were CloudFront headers to be set + */ + public function setCfHeaders($cfHeaders = null) { + // use global _SERVER if $cfHeaders aren't defined + if (!is_array($cfHeaders) || !count($cfHeaders)) { + $cfHeaders = $_SERVER; + } + + // clear existing headers + $this->cloudfrontHeaders = array(); + + // Only save CLOUDFRONT headers. In PHP land, that means only _SERVER vars that + // start with cloudfront-. + $response = false; + foreach ($cfHeaders as $key => $value) { + if (substr(strtolower($key), 0, 16) === 'http_cloudfront_') { + $this->cloudfrontHeaders[strtoupper($key)] = $value; + $response = true; + } + } + + return $response; + } + + /** + * Retrieves the cloudfront headers. + * + * @return array + */ + public function getCfHeaders() + { + return $this->cloudfrontHeaders; + } + /** * Set the User-Agent to be used. * @@ -734,19 +829,28 @@ class Mobile_Detect */ public function setUserAgent($userAgent = null) { - if (!empty($userAgent)) { + // Invalidate cache due to #375 + $this->cache = array(); + + if (false === empty($userAgent)) { return $this->userAgent = $userAgent; } else { $this->userAgent = null; foreach ($this->getUaHttpHeaders() as $altHeader) { - if (!empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban) + if (false === empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban) $this->userAgent .= $this->httpHeaders[$altHeader] . " "; } } - return $this->userAgent = (!empty($this->userAgent) ? trim($this->userAgent) : null); - + if (!empty($this->userAgent)) { + return $this->userAgent = trim($this->userAgent); + } } + + if (count($this->getCfHeaders()) > 0) { + return $this->userAgent = 'Amazon CloudFront'; + } + return $this->userAgent = null; } /** @@ -774,7 +878,7 @@ class Mobile_Detect $type = self::DETECTION_TYPE_MOBILE; } - if ($type != self::DETECTION_TYPE_MOBILE && $type != self::DETECTION_TYPE_EXTENDED) { + if ($type !== self::DETECTION_TYPE_MOBILE && $type !== self::DETECTION_TYPE_EXTENDED) { return; } @@ -930,10 +1034,10 @@ class Mobile_Detect { foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) { - if ( isset($this->httpHeaders[$mobileHeader]) ) { - if ( is_array($matchType['matches']) ) { + if (isset($this->httpHeaders[$mobileHeader])) { + if (is_array($matchType['matches'])) { foreach ($matchType['matches'] as $_match) { - if ( strpos($this->httpHeaders[$mobileHeader], $_match) !== false ) { + if (strpos($this->httpHeaders[$mobileHeader], $_match) !== false) { return true; } } @@ -960,8 +1064,8 @@ class Mobile_Detect */ public function __call($name, $arguments) { - //make sure the name starts with 'is', otherwise - if (substr($name, 0, 2) != 'is') { + // make sure the name starts with 'is', otherwise + if (substr($name, 0, 2) !== 'is') { throw new BadMethodCallException("No such method exists: $name"); } @@ -975,7 +1079,7 @@ class Mobile_Detect /** * Find a detection rule that matches the current User-agent. * - * @param null $userAgent deprecated + * @param null $userAgent deprecated * @return boolean */ protected function matchDetectionRulesAgainstUA($userAgent = null) @@ -985,6 +1089,7 @@ class Mobile_Detect if (empty($_regex)) { continue; } + if ($this->match($_regex, $userAgent)) { return true; } @@ -995,37 +1100,39 @@ class Mobile_Detect /** * Search for a certain key in the rules array. - * If the key is found the try to match the corresponding - * regex agains the User-Agent. + * If the key is found then try to match the corresponding + * regex against the User-Agent. * * @param string $key - * @param null $userAgent deprecated - * @return mixed + * + * @return boolean */ - protected function matchUAAgainstKey($key, $userAgent = null) + protected function matchUAAgainstKey($key) { // Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc. $key = strtolower($key); + if (false === isset($this->cache[$key])) { - //change the keys to lower case - $_rules = array_change_key_case($this->getRules()); + // change the keys to lower case + $_rules = array_change_key_case($this->getRules()); - if (array_key_exists($key, $_rules)) { - if (empty($_rules[$key])) { - return null; + if (false === empty($_rules[$key])) { + $this->cache[$key] = $this->match($_rules[$key]); } - return $this->match($_rules[$key], $userAgent); + if (false === isset($this->cache[$key])) { + $this->cache[$key] = false; + } } - return false; + return $this->cache[$key]; } /** * Check if the device is mobile. * Returns true if any type of mobile device detected, including special ones - * @param null $userAgent deprecated - * @param null $httpHeaders deprecated + * @param null $userAgent deprecated + * @param null $httpHeaders deprecated * @return bool */ public function isMobile($userAgent = null, $httpHeaders = null) @@ -1039,6 +1146,14 @@ class Mobile_Detect $this->setUserAgent($userAgent); } + // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront' + if ($this->getUserAgent() === 'Amazon CloudFront') { + $cfHeaders = $this->getCfHeaders(); + if(array_key_exists('HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] === 'true') { + return true; + } + } + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); if ($this->checkHttpHeadersForMobile()) { @@ -1059,6 +1174,14 @@ class Mobile_Detect */ public function isTablet($userAgent = null, $httpHeaders = null) { + // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront' + if ($this->getUserAgent() === 'Amazon CloudFront') { + $cfHeaders = $this->getCfHeaders(); + if(array_key_exists('HTTP_CLOUDFRONT_IS_TABLET_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_TABLET_VIEWER'] === 'true') { + return true; + } + } + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); foreach (self::$tabletDevices as $_regex) { @@ -1075,9 +1198,9 @@ class Mobile_Detect * userAgent. * @todo: The httpHeaders part is not yet used. * - * @param string $key - * @param string $userAgent deprecated - * @param string $httpHeaders deprecated + * @param string $key + * @param string $userAgent deprecated + * @param string $httpHeaders deprecated * @return bool|int|null */ public function is($key, $userAgent = null, $httpHeaders = null) @@ -1113,9 +1236,7 @@ class Mobile_Detect */ public function match($regex, $userAgent = null) { - // Escape the special character which is the delimiter. - $regex = str_replace('/', '\/', $regex); - $match = (bool) preg_match('/'.$regex.'/is', (!empty($userAgent) ? $userAgent : $this->userAgent), $matches); + $match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : $this->userAgent), $matches); // If positive match is found, store the results for debug. if ($match) { $this->matchingRegex = $regex; @@ -1175,15 +1296,15 @@ class Mobile_Detect return false; } - //set the $type to the default if we don't recognize the type - if ($type != self::VERSION_TYPE_STRING && $type != self::VERSION_TYPE_FLOAT) { + // set the $type to the default if we don't recognize the type + if ($type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT) { $type = self::VERSION_TYPE_STRING; } $properties = self::getProperties(); // Check if the property exists in the properties array. - if (array_key_exists($propertyName, $properties)) { + if (true === isset($properties[$propertyName])) { // Prepare the pattern to be matched. // Make sure we always deal with an array (string is converted). @@ -1193,14 +1314,11 @@ class Mobile_Detect $propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString); - // Escape the special character which is the delimiter. - $propertyPattern = str_replace('/', '\/', $propertyPattern); - // Identify and extract the version. - preg_match('/'.$propertyPattern.'/is', $this->userAgent, $match); + preg_match(sprintf('#%s#is', $propertyPattern), $this->userAgent, $match); - if (!empty($match[1])) { - $version = ( $type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1] ); + if (false === empty($match[1])) { + $version = ($type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]); return $version; } @@ -1223,9 +1341,9 @@ class Mobile_Detect if ( // Apple iOS 4-7.0 – Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3 / 5.1 / 6.1), iPad 3 (5.1 / 6.0), iPad Mini (6.1), iPad Retina (7.0), iPhone 3GS (4.3), iPhone 4 (4.3 / 5.1), iPhone 4S (5.1 / 6.0), iPhone 5 (6.0), and iPhone 5S (7.0) - $this->isIOS() && $this->version('iPad', self::VERSION_TYPE_FLOAT)>=4.3 || - $this->isIOS() && $this->version('iPhone', self::VERSION_TYPE_FLOAT)>=4.3 || - $this->isIOS() && $this->version('iPod', self::VERSION_TYPE_FLOAT)>=4.3 || + $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) >= 4.3 || + $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) >= 4.3 || + $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) >= 4.3 || // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM @@ -1234,29 +1352,29 @@ class Mobile_Detect ( $this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit') ) || // Windows Phone 7.5-8 - Tested on the HTC Surround (7.5), HTC Trophy (7.5), LG-E900 (7.5), Nokia 800 (7.8), HTC Mazaa (7.8), Nokia Lumia 520 (8), Nokia Lumia 920 (8), HTC 8x (8) - $this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT)>=7.5 || + $this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT) >= 7.5 || // Tested on the Torch 9800 (6) and Style 9670 (6), BlackBerry® Torch 9810 (7), BlackBerry Z10 (10) - $this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)>=6.0 || + $this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 6.0 || // Blackberry Playbook (1.0-2.0) - Tested on PlayBook $this->match('Playbook.*Tablet') || // Palm WebOS (1.4-3.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0), HP TouchPad (3.0) - ( $this->version('webOS', self::VERSION_TYPE_FLOAT)>=1.4 && $this->match('Palm|Pre|Pixi') ) || + ( $this->version('webOS', self::VERSION_TYPE_FLOAT) >= 1.4 && $this->match('Palm|Pre|Pixi') ) || // Palm WebOS 3.0 - Tested on HP TouchPad $this->match('hp.*TouchPad') || // Firefox Mobile 18 - Tested on Android 2.3 and 4.1 devices - ( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT)>=18 ) || + ( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 18 ) || // Chrome for Android - Tested on Android 4.0, 4.1 device - ( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT)>=4.0 ) || + ( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 4.0 ) || // Skyfire 4.1 - Tested on Android 2.3 device - ( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT)>=4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3 ) || + ( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT) >= 4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) || // Opera Mobile 11.5-12: Tested on Android 2.3 - ( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT)>=11.5 && $this->is('AndroidOS') ) || + ( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11.5 && $this->is('AndroidOS') ) || // Meego 1.2 - Tested on Nokia 950 and N9 $this->is('MeeGoOS') || @@ -1266,76 +1384,76 @@ class Mobile_Detect // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser // @todo: more tests here! - $this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT)>=2.0 || + $this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT) >= 2.0 || // UC Browser - Tested on Android 2.3 device - ( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3 ) || + ( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) || // Kindle 3 and Fire - Tested on the built-in WebKit browser for each ( $this->match('Kindle Fire') || - $this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT)>=3.0 ) || + $this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT) >= 3.0 ) || // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet $this->is('AndroidOS') && $this->is('NookTablet') || // Chrome Desktop 16-24 - Tested on OS X 10.7 and Windows 7 - $this->version('Chrome', self::VERSION_TYPE_FLOAT)>=16 && !$isMobile || + $this->version('Chrome', self::VERSION_TYPE_FLOAT) >= 16 && !$isMobile || // Safari Desktop 5-6 - Tested on OS X 10.7 and Windows 7 - $this->version('Safari', self::VERSION_TYPE_FLOAT)>=5.0 && !$isMobile || + $this->version('Safari', self::VERSION_TYPE_FLOAT) >= 5.0 && !$isMobile || // Firefox Desktop 10-18 - Tested on OS X 10.7 and Windows 7 - $this->version('Firefox', self::VERSION_TYPE_FLOAT)>=10.0 && !$isMobile || + $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 10.0 && !$isMobile || // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 - $this->version('IE', self::VERSION_TYPE_FLOAT)>=7.0 && !$isMobile || + $this->version('IE', self::VERSION_TYPE_FLOAT) >= 7.0 && !$isMobile || // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 - $this->version('Opera', self::VERSION_TYPE_FLOAT)>=10 && !$isMobile + $this->version('Opera', self::VERSION_TYPE_FLOAT) >= 10 && !$isMobile ){ return self::MOBILE_GRADE_A; } if ( - $this->isIOS() && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 || - $this->isIOS() && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<4.3 || - $this->isIOS() && $this->version('iPod', self::VERSION_TYPE_FLOAT)<4.3 || + $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 || + $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<4.3 || + $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT)<4.3 || // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 - $this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)>=5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 || + $this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 || //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 - ($this->version('Opera Mini', self::VERSION_TYPE_FLOAT)>=5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT)<=7.0 && - ($this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3 || $this->is('iOS')) ) || + ($this->version('Opera Mini', self::VERSION_TYPE_FLOAT) >= 5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT) <= 7.0 && + ($this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 || $this->is('iOS')) ) || // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) $this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || // @todo: report this (tested on Nokia N71) - $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT)>=11 && $this->is('SymbianOS') + $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11 && $this->is('SymbianOS') ){ return self::MOBILE_GRADE_B; } if ( // Blackberry 4.x - Tested on the Curve 8330 - $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<=5.0 || + $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) <= 5.0 || // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) - $this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT)<=5.2 || + $this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT) <= 5.2 || // Tested on original iPhone (3.1), iPhone 3 (3.2) - $this->isIOS() && $this->version('iPad', self::VERSION_TYPE_FLOAT)<=3.2 || - $this->isIOS() && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<=3.2 || - $this->isIOS() && $this->version('iPod', self::VERSION_TYPE_FLOAT)<=3.2 || + $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) <= 3.2 || + $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) <= 3.2 || + $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) <= 3.2 || // Internet Explorer 7 and older - Tested on Windows XP - $this->version('IE', self::VERSION_TYPE_FLOAT)<=7.0 && !$isMobile + $this->version('IE', self::VERSION_TYPE_FLOAT) <= 7.0 && !$isMobile ){ return self::MOBILE_GRADE_C; } - //All older smartphone platforms and featurephones - Any device that doesn't support media queries - //will receive the basic, C grade experience. + // All older smartphone platforms and featurephones - Any device that doesn't support media queries + // will receive the basic, C grade experience. return self::MOBILE_GRADE_C; } } diff --git a/vendor/mobiledetect/mobiledetectlib/README.md b/vendor/mobiledetect/mobiledetectlib/README.md new file mode 100644 index 0000000000..2bbcf05fc2 --- /dev/null +++ b/vendor/mobiledetect/mobiledetectlib/README.md @@ -0,0 +1,283 @@ +![Mobile Detect](http://demo.mobiledetect.net/logo-github.png) + +> Motto: "Every business should have a mobile detection script to detect mobile readers." + +[![Build Status](https://travis-ci.org/serbanghita/Mobile-Detect.svg?branch=devel)](https://travis-ci.org/serbanghita/Mobile-Detect) +[![Latest Stable Version](https://poser.pugx.org/mobiledetect/mobiledetectlib/v/stable.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib) +[![Total Downloads](https://poser.pugx.org/mobiledetect/mobiledetectlib/downloads.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib) +[![Daily Downloads](https://poser.pugx.org/mobiledetect/mobiledetectlib/d/daily.png)](https://packagist.org/packages/mobiledetect/mobiledetectlib) +[![License](https://poser.pugx.org/mobiledetect/mobiledetectlib/license.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib) + +*Mobile_Detect is a lightweight PHP class for detecting mobile devices (including tablets). +It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.* + +We're committed to make Mobile_Detect the best open-source mobile detection resource and this is why before +each release we're running [unit tests](./tests), we also research and update the detection rules on **daily** +and **weekly** basis. + +Your website's _content strategy_ is important! You need a complete toolkit to deliver an experience that is _optimized_, _fast_ and _relevant_ to your users. Mobile_Detect class is a [server-side detection](http://www.w3.org/TR/mwabp/#bp-devcap-detection) tool that can help you with your RWD strategy, it is not a replacement for CSS3 media queries or other forms of client-side feature detection. + +##### Announcements + +For `2.x` branch we are no longer taking optimizations pull requests, but only new regexes and User-Agents for our tests. +On `2.x` releases we are focusing on **new tablets only**. All the pull requests about TVs, bots or optimizations will be closed and analyzed after `3.0.0-beta` is released. + +Still working on `3.0.0` branch to provide you with device detection! +We're really excited on this one! +We would like to speed this up, but life and family gets in the way ;) + +Special thanks to **JetBrains** for providing licenses for **PHPStorm**. In case you never heard or tried PHPStorm, you're +clearly missing out! [Check PHPStorm](https://www.jetbrains.com/phpstorm/) out! + +##### Download and demo + +|Download|Docs|Examples| +|-------------|-------------|-------------| +|[Go to releases](../../tags)|[Become a contributor](../../wiki/Become-a-contributor)|[Code examples](../../wiki/Code-examples) +|[Mobile_Detect.php](./Mobile_Detect.php)|[History](../../wiki/History)|[:iphone: Live demo!](http://is.gd/mobiletest) +|[Composer package](https://packagist.org/packages/mobiledetect/mobiledetectlib)| + +#### Continuous updates + +You can use [composer](https://getcomposer.org/doc/00-intro.md) in your release and update process to make sure you have the latest Mobile_Detect version. + +``` +composer require mobiledetect/mobiledetectlib +``` + +```json +{ + "require": { + "mobiledetect/mobiledetectlib": "^2.8" + } +} +``` + +##### Help + +|Pledgie|Paypal| +|-------|------| +|[Donate :+1:](https://pledgie.com/campaigns/21856)|[Donate :beer:](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=mobiledetectlib%40gmail%2ecom&lc=US&item_name=Mobile%20Detect¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted)| + + +I'm currently paying for hosting and spend a lot of my family time to maintain the project and planning the future releases. +I would highly appreciate any money donations that will keep the research going. + +Special thanks to the community :+1: for donations, [BrowserStack](https://www.browserstack.com/) - for providing access to their great platform, [Zend](http://www.zend.com/) - for donating licenses, [Dragos Gavrila](https://twitter.com/grafician) who contributed with the logo. + +##### 3rd party modules / [Submit new](../../issues/new?title=New%203rd%20party%20module&body=Name, Link and Description of the module.) + +:point_right: Keep `Mobile_Detect.php` class in a separate `module` and do NOT include it in your script core because of the high frequency of updates. +:point_right: When including the class into you `web application` or `module` always use `include_once '../path/to/Mobile_Detect.php` to prevent conflicts. + +**JavaScript** + +* mobile-detect.js - A [JavaScript port](https://github.com/hgoebl/mobile-detect.js) of Mobile-Detect class. Made by [Heinrich Goebl](https://github.com/hgoebl). + +**Varnish Cache** + +* [Varnish Mobile Detect](https://github.com/willemk/varnish-mobiletranslate) - Drop-in varnish solution to mobile user +detection based on the Mobile-Detect library. Made by [willemk](https://github.com/willemk). +* [mobiledetect2vcl](https://github.com/carlosabalde/mobiledetect2vcl) - Python script to transform the Mobile +Detect JSON database into an UA-based mobile detection VCL subroutine easily integrable in any Varnish Cache +configuration. Made by [Carlos Abalde](https://github.com/carlosabalde). + +**LUA** + +* [mobile-detect.lua](https://github.com/yourpalmark/mobile-detect.lua) is a port of Mobile-Detect to Lua for +NGINX HTTP servers. Follows closely to mobile-detect.js. Supports all methods that server-side +mobile-detect.js supports. Fully unit-tested and synced with Travis CI (Build Passing badge included). +Made by [Mark Walters](https://github.com/yourpalmark). + +**PHP** + +**WordPress** + +* [WordPress Mobile Detect](https://wordpress.org/plugins/wp-mobile-detect/) - Gives you the ability to wrap that +infographic in a `[notdevice][/notdevice]` shortcode so at the server level WordPress will +decide to show that content only if the user is NOT on a phone or tablet. +Made by [Jesse Friedman](https://profiles.wordpress.org/professor44/). + +* [mobble](https://wordpress.org/plugins/mobble/) - provides mobile related conditional functions for your site. +e.g. `is_iphone()`, `is_mobile()` and `is_tablet()`. Made by Scott Evans. + +* [WordPress Responsage](https://github.com/iamspacehead/responsage) - A small WordPress theme plugin that allows +you to make your images responsive. Made by [Adrian Ciaschetti](https://github.com/iamspacehead). + +* [WP247 Body Classes](https://wordpress.org/plugins/wp247-body-classes/) - Add unique classes to the `body` tag for +easy styling based on various attributes (archive, user, post, mobile) and various WordPress "is" functions. +Mobile attributes include type of device, Operating System, Browser, etc. Examples: .is-mobile, .is-not-mobile, +.is-tablet, .is-ios, .is-not-ios, .is-androidos, .is-chromebrowser. +Made by [wescleveland56](https://github.com/wescleveland56). + +**Drupal** + +* [Drupal Mobile Switch](https://www.drupal.org/project/mobile_switch) - The Mobile Switch Drupal module provides a +automatic theme switch functionality for mobile devices, detected by Browscap or Mobile Detect. +Made by [Siegfried Neumann](https://www.drupal.org/user/45267). + +* [Drupal Context Mobile Detect](https://www.drupal.org/project/context_mobile_detect) - This is a Drupal context module +which integrates Context and PHP Mobile Detect library. +Created by [Artem Shymko](https://www.drupal.org/user/432492). + +* [Drupal Mobile Detect](https://www.drupal.org/project/mobile_detect]) - Lightweight mobile detect module for Drupal + created by [Matthew Donadio](https://www.drupal.org/user/325244). + +**Joomla** + +* [yagendoo Joomla! Mobile Detection Plugin](http://www.yagendoo.com/en/blog/free-mobile-detection-plugin-for-joomla.html) - Lightweight PHP plugin for Joomla! +that detects a mobile browser using the Mobile Detect class. +Made by yagendoo media. + +* [User Agent Detector plugin](https://github.com/renekreijveld/UserAgentDetector) - This system plugin detects the user +agent of your website visitor and sets a session variable accordingly. Based on the user agent, the plugin detects if the +site is running on a desktop pc, tablet or smartphone. It can also detect if the visitor is a spider bot (search engine). +Session variable that is set: `ualayout`. Possible values: desktop, tablet, mobile, bot. +Made by @ReneKreijveld. + +**Magento** + +* [Magento helper](http://www.magentocommerce.com/magento-connect/catalog/product/view/id/16835/) from Optimise Web enables +the use of all functions provided by Mobile Detect. Made by [Kathir Vel](http://www.kathirvel.com). + +* [Magento 2 Mobile Detect Theme Change](https://github.com/EaDesgin/magento2-mobiledetect) is an extension for Magento 2 +that will change the theme or redirect to a different URL. Also containing a helper to check for the device type. + +**PrestaShop** + +* [PrestaShop](https://www.prestashop.com) is a free, secure and open source shopping cart platform. Mobile_Detect +is included in the default package since 1.5.x. + +**Laravel** + +* [Agent](https://github.com/jenssegers/agent) is a user agent class for Laravel based on Mobile Detect with some +additional functionality. +Made by [Jens Segers](https://github.com/jenssegers). + +* [BrowserDetect](https://github.com/hisorange/browser-detect) is a browser and mobile detection package, collects +and wrap together the best user-agent identifiers for Laravel. +Created by [Varga Zsolt](https://github.com/hisorange). + +**Zend Framework** + +* [ZF2 Mobile-Detect](https://github.com/neilime/zf2-mobile-detect.git) is a Zend Framework 2 module that provides +Mobile-Detect features (Mobile_Detect class as a service, helper for views and plugin controllers). +Made by [neilime](https://github.com/neilime). + +* [ZF2 MobileDetectModule](https://github.com/nikolaposa/MobileDetectModule) facilitates integration of a PHP MobileDetect +class with some ZF2-based application. Has similar idea like the existing ZF2 Mobile-Detect module, +but differs in initialization and provision routine of the actual Mobile_Detect class. +Appropriate view helper and controller plugin also have different conceptions. +Made by [Nikola Posa](https://github.com/nikolaposa). + +**Symfony** + +* [Symfony2 Mobile Detect Bundle](https://github.com/suncat2000/MobileDetectBundle) is a bundle for detecting mobile devices, +manage mobile view and redirect to the mobile and tablet version. +Made by [Nikolay Ivlev](https://github.com/suncat2000). + +* [Silex Mobile Detect Service Provider](https://github.com/jbinfo/MobileDetectServiceProvider) is a service provider to +interact with Mobile detect class methods. +Made by [Lhassan Baazzi](https://github.com/jbinfo). + +**Slim Framework** + +* [Slim_Mobile_Detect](https://github.com/zguillez/slim_mobile_detect) implements Mobile_Detect lib for different +responses write on Slim Framework App. + +**ExpressionEngine** + +* [EE2 Detect Mobile](https://github.com/garethtdavies/detect-mobile) is a lightweight PHP plugin for EE2 that detects + a mobile browser using the Mobile Detect class. Made by [Gareth Davies](https://github.com/garethtdavies). + +**Yii Framework** + +* [Yii Extension](https://github.com/iamsalnikov/MobileDetect) - Mobile detect plugin for Yii framework. +Made by [Alexey Salnikov](https://github.com/iamsalnikov). + +* [Yii Extension](https://github.com/candasm/yii1-mobile-detect-component) - Mobile detect component for Yii framework +1.x version which supports composer package manager. Made by [Candas Minareci](https://github.com/candasm). + +* [Yii2 Device Detect](https://github.com/alexandernst/yii2-device-detect/) - Yii2 extension for Mobile-Detect library. +Made by [Alexander Nestorov](https://github.com/alexandernst). + +**CakePHP** + +* [CakePHP MobileDetect](https://github.com/chronon/CakePHP-MobileDetectComponent-Plugin) is a plugin component for +CakePHP 2.x. Made by [Gregory Gaskill](https://github.com/chronon). + +**FuelPHP** + +* [Special Agent](https://github.com/rob-bar/special_agent) is a FuelPHP package which uses php-mobile-detect to +determine whether a device is mobile or not. It overrides the Fuelphp Agent class its methods. +Made by [Robbie Bardjin](https://github.com/rob-bar). + + +**TYPO3** + +* [px_mobiledetect](https://typo3.org/extensions/repository/view/px_mobiledetect) is an extension that helps to detect +visitor's mobile device class (if that’s tablet or mobile device like smartphone). Made by Alexander Tretyak. + +**Other** + +* [PageCache](https://github.com/mmamedov/page-cache) is a lightweight PHP library for full page cache, +with built-in Mobile-Detect support. Made by [Muhammed Mamedov](https://github.com/mmamedov). + +* [Statamic CMS Mobile Detect](https://github.com/haikulab/statamic-mobile-detect) is a plugin. +Made by [Sergei Filippov](https://github.com/haikulab/statamic-mobile-detect) of Haiku Lab. + +* [Kohana Mobile Detect](https://github.com/madeinnordeste/kohana-mobile-detect) is an example of implementation of +Mobile_Detect class with Kohana framework. +Written by [Luiz Alberto S. Ribeiro](https://github.com/madeinnordeste). + +* [MemHT](https://www.memht.com) is a Free PHP CMS and Blog that permit the creation and the management online +of websites with few and easy steps. Has the class included in the core. + +* [concrete5](https://www.concrete5.org) is a CMS that is free and open source. The library is included in the core. + +* [engine7](https://github.com/QOXCorp/exengine) is PHP Open Source Framework. The Mobile_Detect class is included in +the engine. + +* [Zikula](http://zikula.org) is a free and open-source Content Management Framework, which allows you to run +impressive websites and build powerful online applications. The core uses Mobile-Detect to switch to a special +Mobile theme, using jQueryMobile. + +* [UserAgentInfo](https://github.com/quentin389/UserAgentInfo) is a PHP class for parsing user agent strings +(HTTP_USER_AGENT). Includes mobile checks, bot checks, browser types/versions and more. +Based on browscap, Mobile_Detect and ua-parser. Created for high traffic websites and fast batch processing. +Made by [quentin389](https://github.com/quentin389). + +* [LJ Mobile Detect](https://github.com/lewisjenkins/craft-lj-mobiledetect) is a simple implementation of Mobile Detect +for Craft CMS. Made by [Lewis Jenkins](https://github.com/lewisjenkins). + +* [Grav Plugin Mobile Detect](https://github.com/dimitrilongo/grav-plugin-mobile-detect/) is a simple implementation +of Mobile Detect for Grav CMS. Made by [Dimitri Longo](https://github.com/dimitrilongo). + + +**Perl** + + * [MobileDetect.pm](https://www.buzzerstar.com/development/) is a Perl module for Mobile Detect. + Made by [Sebastian Enger](https://devop.tools/). + +**Python** + +* [pymobiledetect](https://pypi.python.org/pypi/pymobiledetect) - Mobile detect python package. +Made by Bas van Oostveen. + +**Ruby** + +* [mobile_detect.rb](https://github.com/ktaragorn/mobile_detect) is a Ruby gem using the JSON data exposed by the +php project and implementing a basic subset of the API (as much as can be done by the exposed data). +Made by [Karthik T](https://github.com/ktaragorn). + +**Go** + +* [GoMobileDetect](https://github.com/Shaked/gomobiledetect) is a Go port of Mobile Detect class. +Made by [https://github.com/Shaked](Shaked). + + +**LUA** + +* [ua-lua](https://github.com/robinef/ua-lua) is a small lib written in LUA providing device type detection. +ua-lua is detecting mobile or tablet devices based on user-agent inside nginx daemon. +Made by [Frédéric Robinet](https://github.com/robinef). diff --git a/library/Mobile_Detect/composer.json b/vendor/mobiledetect/mobiledetectlib/composer.json similarity index 86% rename from library/Mobile_Detect/composer.json rename to vendor/mobiledetect/mobiledetectlib/composer.json index c56611fb6b..0131e4937e 100644 --- a/library/Mobile_Detect/composer.json +++ b/vendor/mobiledetect/mobiledetectlib/composer.json @@ -17,9 +17,7 @@ "php": ">=5.0.0" }, "require-dev": { - "phpunit/phpunit": "*", - "johnkary/phpunit-speedtrap": "~1.0@dev", - "codeclimate/php-test-reporter": "dev-master" + "phpunit/phpunit": "*" }, "autoload": { "classmap": ["Mobile_Detect.php"], diff --git a/vendor/mobiledetect/mobiledetectlib/export/exportToJSON.php b/vendor/mobiledetect/mobiledetectlib/export/exportToJSON.php new file mode 100644 index 0000000000..e2c72aece1 --- /dev/null +++ b/vendor/mobiledetect/mobiledetectlib/export/exportToJSON.php @@ -0,0 +1,67 @@ + $detect->getScriptVersion(), + + // All headers that trigger 'isMobile' to be 'true', + // before reaching the User-Agent match detection. + 'headerMatch' => $detect->getMobileHeaders(), + + // All possible User-Agent headers. + 'uaHttpHeaders' => $detect->getUaHttpHeaders(), + + // All the regexes that trigger 'isMobile' or 'isTablet' + // to be true. + 'uaMatch' => array( + // If match is found, triggers 'isMobile' to be true. + 'phones' => $detect->getPhoneDevices(), + // Triggers 'isTablet' to be true. + 'tablets' => $detect->getTabletDevices(), + // If match is found, triggers 'isMobile' to be true. + 'browsers' => $detect->getBrowsers(), + // If match is found, triggers 'isMobile' to be true. + 'os' => $detect->getOperatingSystems(), + // Various utilities. To be further discussed. + 'utilities' => $detect->getUtilities() + ) +); + +$fileName = dirname(__FILE__).'/../Mobile_Detect.json'; +// Write the JSON file to disk.11 +// You can import this file in your app. +if (file_put_contents( + $fileName, + function_exists('json_format') ? json_format($json) : json_encode($json) +)) { + echo 'Done. Check '.realpath($fileName).' file.'; +} +else { + echo 'Failed to write '.realpath($fileName).' to disk.'; +} diff --git a/library/Mobile_Detect/namespaced/Detection/MobileDetect.php b/vendor/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php similarity index 96% rename from library/Mobile_Detect/namespaced/Detection/MobileDetect.php rename to vendor/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php index ca70fe8076..ca7efec23f 100644 --- a/library/Mobile_Detect/namespaced/Detection/MobileDetect.php +++ b/vendor/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php @@ -4,7 +4,7 @@ * the Symfony Universal ClassLoader by Fabien Potencier. Since PSR-0 handles an underscore in * classnames (on the filesystem) as a slash, "Mobile_Detect.php" autoloaders will try to convert * the classname and path to "Mobile\Detect.php". This script will ensure autoloading with: - * - Namespace: Detection + * - Namespace: Detection * - Classname: MobileDetect * - Namespased: \Detection\MobileDetect * - Autoload path: ./namespaced diff --git a/vendor/mobiledetect/mobiledetectlib/ruleset.xml b/vendor/mobiledetect/mobiledetectlib/ruleset.xml new file mode 100644 index 0000000000..21462efd99 --- /dev/null +++ b/vendor/mobiledetect/mobiledetectlib/ruleset.xml @@ -0,0 +1,187 @@ + + + The PSR-2 coding standard. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From f6d7ee278116c5d9d6ba77606087ecbd8a379e7d Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 1 Apr 2017 08:28:42 +0000 Subject: [PATCH 06/16] Issue 3142: mcrypt is no more (as well as phpseclib) --- INSTALL.txt | 2 +- boot.php | 1 - htconfig.php | 5 +- include/crypto.php | 209 +- include/dfrn.php | 14 +- include/diaspora.php | 8 +- include/user.php | 12 +- .../defuse/php-encryption-1.2.1/Crypto.php | 6 +- library/phpsec/Crypt/AES.php | 479 --- library/phpsec/Crypt/DES.php | 945 ----- library/phpsec/Crypt/Hash.php | 816 ---- library/phpsec/Crypt/RC4.php | 493 --- library/phpsec/Crypt/RSA.php | 2119 ---------- library/phpsec/Crypt/Random.php | 130 - library/phpsec/Crypt/Rijndael.php | 1242 ------ library/phpsec/Crypt/TripleDES.php | 690 ---- library/phpsec/Math/BigInteger.php | 3545 ----------------- library/phpsec/Net/SFTP.php | 1461 ------- library/phpsec/Net/SSH1.php | 1160 ------ library/phpsec/Net/SSH2.php | 2302 ----------- .../phpsec/PHP/Compat/Function/array_fill.php | 43 - .../phpsec/PHP/Compat/Function/bcpowmod.php | 67 - .../phpsec/PHP/Compat/Function/str_split.php | 59 - library/phpsec/crypt.html | 135 - library/phpsec/docbook.css | 43 - library/phpsec/index.html | 5 - library/phpsec/intro.html | 20 - library/phpsec/math.html | 157 - library/phpsec/misc_crypt.html | 155 - library/phpsec/net.html | 153 - library/phpsec/sym_crypt.html | 118 - mod/admin.php | 7 +- mod/dfrn_confirm.php | 4 +- mod/dfrn_notify.php | 6 +- mod/install.php | 24 - view/templates/htconfig.tpl | 5 +- 36 files changed, 85 insertions(+), 16555 deletions(-) delete mode 100644 library/phpsec/Crypt/AES.php delete mode 100644 library/phpsec/Crypt/DES.php delete mode 100644 library/phpsec/Crypt/Hash.php delete mode 100644 library/phpsec/Crypt/RC4.php delete mode 100644 library/phpsec/Crypt/RSA.php delete mode 100644 library/phpsec/Crypt/Random.php delete mode 100644 library/phpsec/Crypt/Rijndael.php delete mode 100644 library/phpsec/Crypt/TripleDES.php delete mode 100644 library/phpsec/Math/BigInteger.php delete mode 100644 library/phpsec/Net/SFTP.php delete mode 100644 library/phpsec/Net/SSH1.php delete mode 100644 library/phpsec/Net/SSH2.php delete mode 100644 library/phpsec/PHP/Compat/Function/array_fill.php delete mode 100644 library/phpsec/PHP/Compat/Function/bcpowmod.php delete mode 100644 library/phpsec/PHP/Compat/Function/str_split.php delete mode 100644 library/phpsec/crypt.html delete mode 100644 library/phpsec/docbook.css delete mode 100644 library/phpsec/index.html delete mode 100644 library/phpsec/intro.html delete mode 100644 library/phpsec/math.html delete mode 100644 library/phpsec/misc_crypt.html delete mode 100644 library/phpsec/net.html delete mode 100644 library/phpsec/sym_crypt.html diff --git a/INSTALL.txt b/INSTALL.txt index 4c57064f6b..81dfdfd272 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -37,7 +37,7 @@ local .htaccess file - PHP *command line* access with register_argc_argv set to true in the php.ini file [or see 'poormancron' in section 8] - - curl, gd (with at least jpeg support), mysql, mbstring, mcrypt, and openssl extensions + - curl, gd (with at least jpeg support), mysql, mbstring and openssl extensions - some form of email server or email gateway such that PHP mail() works diff --git a/boot.php b/boot.php index 6f036d846e..74d6ee4c4f 100644 --- a/boot.php +++ b/boot.php @@ -648,7 +648,6 @@ class App { set_include_path( 'include' . PATH_SEPARATOR . 'library' . PATH_SEPARATOR - . 'library/phpsec' . PATH_SEPARATOR . 'library/langdet' . PATH_SEPARATOR . '.' ); diff --git a/htconfig.php b/htconfig.php index 41317c4608..5967e79f4e 100644 --- a/htconfig.php +++ b/htconfig.php @@ -65,9 +65,8 @@ $a->config['php_path'] = 'php'; $a->config['system']['huburl'] = '[internal]'; // Server-to-server private message encryption (RINO) is allowed by default. -// Encryption will only be provided if this setting is set to a non zero -// value and the PHP mcrypt extension is installed on both systems -// set to 0 to disable, 2 to enable, 1 is deprecated but wont need mcrypt +// Encryption will only be provided if this setting is set to a non zero value +// set to 0 to disable, 2 to enable, 1 is deprecated $a->config['system']['rino_encrypt'] = 2; diff --git a/include/crypto.php b/include/crypto.php index f5163a9dac..4600e7291b 100644 --- a/include/crypto.php +++ b/include/crypto.php @@ -1,94 +1,52 @@ =') || $alg === 'sha1') { - openssl_sign($data,$sig,$key,(($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg)); - } - else { - if(strlen($key) < 1024 || extension_loaded('gmp')) { - require_once('library/phpsec/Crypt/RSA.php'); - $rsa = new CRYPT_RSA(); - $rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1; - $rsa->setHash($alg); - $rsa->loadKey($key); - $sig = $rsa->sign($data); - } - else { - logger('rsa_sign: insecure algorithm used. Please upgrade PHP to 5.3'); - openssl_private_encrypt(hex2bin('3031300d060960864801650304020105000420') . hash('sha256',$data,true), $sig, $key); - } - } +function rsa_sign($data, $key, $alg = 'sha256') { + openssl_sign($data, $sig, $key, (($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg)); return $sig; } -function rsa_verify($data,$sig,$key,$alg = 'sha256') { - - if (version_compare(PHP_VERSION, '5.3.0', '>=') || $alg === 'sha1') { - $verify = openssl_verify($data,$sig,$key,(($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg)); - } - else { - if(strlen($key) <= 300 || extension_loaded('gmp')) { - require_once('library/phpsec/Crypt/RSA.php'); - $rsa = new CRYPT_RSA(); - $rsa->signatureMode = CRYPT_RSA_SIGNATURE_PKCS1; - $rsa->setHash($alg); - $rsa->loadKey($key); - $verify = $rsa->verify($data,$sig); - } - else { - // fallback sha256 verify for PHP < 5.3 and large key lengths - $rawsig = ''; - openssl_public_decrypt($sig,$rawsig,$key); - $verify = (($rawsig && substr($rawsig,-32) === hash('sha256',$data,true)) ? true : false); - } - } - return $verify; +function rsa_verify($data, $sig, $key, $alg = 'sha256') { + return openssl_verify($data, $sig, $key, (($alg == 'sha1') ? OPENSSL_ALGO_SHA1 : $alg)); } +function DerToPem($Der, $Private = false) { + //Encode: + $Der = base64_encode($Der); + //Split lines: + $lines = str_split($Der, 65); + $body = implode("\n", $lines); + //Get title: + $title = $Private ? 'RSA PRIVATE KEY' : 'PUBLIC KEY'; + //Add wrapping: + $result = "-----BEGIN {$title}-----\n"; + $result .= $body . "\n"; + $result .= "-----END {$title}-----\n"; -function DerToPem($Der, $Private=false) -{ - //Encode: - $Der = base64_encode($Der); - //Split lines: - $lines = str_split($Der, 65); - $body = implode("\n", $lines); - //Get title: - $title = $Private? 'RSA PRIVATE KEY' : 'PUBLIC KEY'; - //Add wrapping: - $result = "-----BEGIN {$title}-----\n"; - $result .= $body . "\n"; - $result .= "-----END {$title}-----\n"; - - return $result; + return $result; } -function DerToRsa($Der) -{ - //Encode: - $Der = base64_encode($Der); - //Split lines: - $lines = str_split($Der, 64); - $body = implode("\n", $lines); - //Get title: - $title = 'RSA PUBLIC KEY'; - //Add wrapping: - $result = "-----BEGIN {$title}-----\n"; - $result .= $body . "\n"; - $result .= "-----END {$title}-----\n"; - - return $result; +function DerToRsa($Der) { + //Encode: + $Der = base64_encode($Der); + //Split lines: + $lines = str_split($Der, 64); + $body = implode("\n", $lines); + //Get title: + $title = 'RSA PUBLIC KEY'; + //Add wrapping: + $result = "-----BEGIN {$title}-----\n"; + $result .= $body . "\n"; + $result .= "-----END {$title}-----\n"; + + return $result; } - -function pkcs8_encode($Modulus,$PublicExponent) { +function pkcs8_encode($Modulus, $PublicExponent) { //Encode key sequence $modulus = new ASNValue(ASNValue::TAG_INTEGER); $modulus->SetIntBuffer($Modulus); @@ -111,8 +69,7 @@ function pkcs8_encode($Modulus,$PublicExponent) { return $PublicDER; } - -function pkcs1_encode($Modulus,$PublicExponent) { +function pkcs1_encode($Modulus, $PublicExponent) { //Encode key sequence $modulus = new ASNValue(ASNValue::TAG_INTEGER); $modulus->SetIntBuffer($Modulus); @@ -126,22 +83,20 @@ function pkcs1_encode($Modulus,$PublicExponent) { return $bitStringValue; } - -function metopem($m,$e) { - $der = pkcs8_encode($m,$e); - $key = DerToPem($der,false); +function metopem($m, $e) { + $der = pkcs8_encode($m, $e); + $key = DerToPem($der, false); return $key; -} - +} function pubrsatome($key,&$m,&$e) { require_once('library/asn1.php'); require_once('include/salmon.php'); - $lines = explode("\n",$key); + $lines = explode("\n", $key); unset($lines[0]); unset($lines[count($lines)]); - $x = base64_decode(implode('',$lines)); + $x = base64_decode(implode('', $lines)); $r = ASN_BASE::parseASNString($x); @@ -151,21 +106,21 @@ function pubrsatome($key,&$m,&$e) { function rsatopem($key) { - pubrsatome($key,$m,$e); - return(metopem($m,$e)); + pubrsatome($key, $m, $e); + return metopem($m, $e); } function pemtorsa($key) { - pemtome($key,$m,$e); - return(metorsa($m,$e)); + pemtome($key, $m, $e); + return metorsa($m, $e); } -function pemtome($key,&$m,&$e) { +function pemtome($key, &$m, &$e) { require_once('include/salmon.php'); - $lines = explode("\n",$key); + $lines = explode("\n", $key); unset($lines[0]); unset($lines[count($lines)]); - $x = base64_decode(implode('',$lines)); + $x = base64_decode(implode('', $lines)); $r = ASN_BASE::parseASNString($x); @@ -173,82 +128,36 @@ function pemtome($key,&$m,&$e) { $e = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[1]->asnData); } -function metorsa($m,$e) { - $der = pkcs1_encode($m,$e); +function metorsa($m, $e) { + $der = pkcs1_encode($m, $e); $key = DerToRsa($der); return $key; -} +} function salmon_key($pubkey) { - pemtome($pubkey,$m,$e); - return 'RSA' . '.' . base64url_encode($m,true) . '.' . base64url_encode($e,true) ; + pemtome($pubkey, $m, $e); + return 'RSA' . '.' . base64url_encode($m, true) . '.' . base64url_encode($e, true) ; } - - -if(! function_exists('aes_decrypt')) { -// DEPRECATED IN 3.4.1 -function aes_decrypt($val,$ky) -{ - $key="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - for($a=0;$a=0 and ord(substr($dec, strlen($dec)-1,1))<=16)? chr(ord( substr($dec,strlen($dec)-1,1))):null)); -}} - - -if(! function_exists('aes_encrypt')) { -// DEPRECATED IN 3.4.1 -function aes_encrypt($val,$ky) -{ - $key="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - for($a=0;$a strlen($text)) return false; - if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false; - return substr($text, 0, -1 * $pad); -} - - function new_keypair($bits) { - $openssl_options = array( 'digest_alg' => 'sha1', 'private_key_bits' => $bits, - 'encrypt_key' => false + 'encrypt_key' => false ); - $conf = get_config('system','openssl_conf_file'); - if($conf) + $conf = get_config('system', 'openssl_conf_file'); + if ($conf) { $openssl_options['config'] = $conf; - + } $result = openssl_pkey_new($openssl_options); - if(empty($result)) { + if (empty($result)) { logger('new_keypair: failed'); return false; } // Get private key - $response = array('prvkey' => '', 'pubkey' => ''); openssl_pkey_export($result, $response['prvkey']); @@ -258,6 +167,4 @@ function new_keypair($bits) { $response['pubkey'] = $pkey["key"]; return $response; - } - diff --git a/include/dfrn.php b/include/dfrn.php index 0e3cdf76f7..acd16dc618 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -864,6 +864,14 @@ class dfrn { return $entry; } + private static function aes_encrypt($data, $key) { + return openssl_encrypt($data, 'aes-128-ecb', $key, OPENSSL_RAW_DATA); + } + + public static function aes_decrypt($encrypted, $key) { + return openssl_decrypt($encrypted, 'aes-128-ecb', $key, OPENSSL_RAW_DATA); + } + /** * @brief Delivers the atom content to the contacts * @@ -888,8 +896,6 @@ class dfrn { $rino = get_config('system','rino_encrypt'); $rino = intval($rino); - // use RINO1 if mcrypt isn't installed and RINO2 was selected - if ($rino==2 and !function_exists('mcrypt_create_iv')) $rino=1; logger("Local rino version: ". $rino, LOGGER_DEBUG); @@ -1015,8 +1021,8 @@ class dfrn { switch($rino_remote_version) { case 1: // Deprecated rino version! - $key = substr(random_string(),0,16); - $data = aes_encrypt($postvars['data'],$key); + $key = openssl_random_pseudo_bytes(16); + $data = self::aes_encrypt($postvars['data'], $key); break; case 2: // RINO 2 based on php-encryption diff --git a/include/diaspora.php b/include/diaspora.php index 89915c3d14..bdedb9e0b7 100644 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -2640,14 +2640,14 @@ class Diaspora { return false; } - $inner_aes_key = random_string(32); + $inner_aes_key = openssl_random_pseudo_bytes(32); $b_inner_aes_key = base64_encode($inner_aes_key); - $inner_iv = random_string(16); + $inner_iv = openssl_random_pseudo_bytes(16); $b_inner_iv = base64_encode($inner_iv); - $outer_aes_key = random_string(32); + $outer_aes_key = openssl_random_pseudo_bytes(32); $b_outer_aes_key = base64_encode($outer_aes_key); - $outer_iv = random_string(16); + $outer_iv = openssl_random_pseudo_bytes(16); $b_outer_iv = base64_encode($outer_iv); $handle = self::my_handle($user); diff --git a/include/user.php b/include/user.php index cd77707dd0..973d6b8b1f 100644 --- a/include/user.php +++ b/include/user.php @@ -175,17 +175,7 @@ function create_user($arr) { $prvkey = $keys['prvkey']; $pubkey = $keys['pubkey']; - /** - * - * Create another keypair for signing/verifying - * salmon protocol messages. We have to use a slightly - * less robust key because this won't be using openssl - * but the phpseclib. Since it is PHP interpreted code - * it is not nearly as efficient, and the larger keys - * will take several minutes each to process. - * - */ - + // Create another keypair for signing/verifying salmon protocol messages. $sres = new_keypair(512); $sprvkey = $sres['prvkey']; $spubkey = $sres['pubkey']; diff --git a/library/defuse/php-encryption-1.2.1/Crypto.php b/library/defuse/php-encryption-1.2.1/Crypto.php index 60b5a62cc1..5b60f6f121 100644 --- a/library/defuse/php-encryption-1.2.1/Crypto.php +++ b/library/defuse/php-encryption-1.2.1/Crypto.php @@ -342,9 +342,9 @@ final class Crypto */ private static function SecureRandom($octets) { - self::EnsureFunctionExists("mcrypt_create_iv"); - $random = mcrypt_create_iv($octets, MCRYPT_DEV_URANDOM); - if ($random === FALSE) { + self::EnsureFunctionExists("openssl_random_pseudo_bytes"); + $random = openssl_random_pseudo_bytes($octets, $crypto_strong); + if ($crypto_strong === FALSE) { throw new CannotPerformOperationException(); } else { return $random; diff --git a/library/phpsec/Crypt/AES.php b/library/phpsec/Crypt/AES.php deleted file mode 100644 index 681800a81f..0000000000 --- a/library/phpsec/Crypt/AES.php +++ /dev/null @@ -1,479 +0,0 @@ - - * setKey('abcdefghijklmnop'); - * - * $size = 10 * 1024; - * $plaintext = ''; - * for ($i = 0; $i < $size; $i++) { - * $plaintext.= 'a'; - * } - * - * echo $aes->decrypt($aes->encrypt($plaintext)); - * ?> - * - * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * @category Crypt - * @package Crypt_AES - * @author Jim Wigginton - * @copyright MMVIII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: AES.php,v 1.7 2010/02/09 06:10:25 terrafrost Exp $ - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Crypt_Rijndael - */ -require_once 'Rijndael.php'; - -/**#@+ - * @access public - * @see Crypt_AES::encrypt() - * @see Crypt_AES::decrypt() - */ -/** - * Encrypt / decrypt using the Counter mode. - * - * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 - */ -define('CRYPT_AES_MODE_CTR', -1); -/** - * Encrypt / decrypt using the Electronic Code Book mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 - */ -define('CRYPT_AES_MODE_ECB', 1); -/** - * Encrypt / decrypt using the Code Book Chaining mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 - */ -define('CRYPT_AES_MODE_CBC', 2); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_AES::Crypt_AES() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_AES_MODE_INTERNAL', 1); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_AES_MODE_MCRYPT', 2); -/**#@-*/ - -/** - * Pure-PHP implementation of AES. - * - * @author Jim Wigginton - * @version 0.1.0 - * @access public - * @package Crypt_AES - */ -class Crypt_AES extends Crypt_Rijndael { - /** - * mcrypt resource for encryption - * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. - * - * @see Crypt_AES::encrypt() - * @var String - * @access private - */ - var $enmcrypt; - - /** - * mcrypt resource for decryption - * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. - * - * @see Crypt_AES::decrypt() - * @var String - * @access private - */ - var $demcrypt; - - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be - * CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used. - * - * @param optional Integer $mode - * @return Crypt_AES - * @access public - */ - function Crypt_AES($mode = CRYPT_AES_MODE_CBC) - { - if ( !defined('CRYPT_AES_MODE') ) { - switch (true) { - case extension_loaded('mcrypt'): - // i'd check to see if aes was supported, by doing in_array('des', mcrypt_list_algorithms('')), - // but since that can be changed after the object has been created, there doesn't seem to be - // a lot of point... - define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT); - break; - default: - define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL); - } - } - - switch ( CRYPT_AES_MODE ) { - case CRYPT_AES_MODE_MCRYPT: - switch ($mode) { - case CRYPT_AES_MODE_ECB: - $this->mode = MCRYPT_MODE_ECB; - break; - case CRYPT_AES_MODE_CTR: - // ctr doesn't have a constant associated with it even though it appears to be fairly widely - // supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to - // include a compatibility layer. the layer has been implemented but, for now, is commented out. - $this->mode = 'ctr'; - //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR; - break; - case CRYPT_AES_MODE_CBC: - default: - $this->mode = MCRYPT_MODE_CBC; - } - - break; - default: - switch ($mode) { - case CRYPT_AES_MODE_ECB: - $this->mode = CRYPT_RIJNDAEL_MODE_ECB; - break; - case CRYPT_AES_MODE_CTR: - $this->mode = CRYPT_RIJNDAEL_MODE_CTR; - break; - case CRYPT_AES_MODE_CBC: - default: - $this->mode = CRYPT_RIJNDAEL_MODE_CBC; - } - } - - if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) { - parent::Crypt_Rijndael($this->mode); - } - } - - /** - * Dummy function - * - * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything. - * - * @access public - * @param Integer $length - */ - function setBlockLength($length) - { - return; - } - - /** - * Encrypts a message. - * - * $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the - * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following - * URL: - * - * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} - * - * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. - * strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that - * length. - * - * @see Crypt_AES::decrypt() - * @access public - * @param String $plaintext - */ - function encrypt($plaintext) - { - if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { - $this->_mcryptSetup(); - /* - if ($this->mode == CRYPT_AES_MODE_CTR) { - $iv = $this->encryptIV; - $xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($plaintext), $iv)); - $ciphertext = $plaintext ^ $xor; - if ($this->continuousBuffer) { - $this->encryptIV = $iv; - } - return $ciphertext; - } - */ - - if ($this->mode != 'ctr') { - $plaintext = $this->_pad($plaintext); - } - - $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); - } - - return $ciphertext; - } - - return parent::encrypt($plaintext); - } - - /** - * Decrypts a message. - * - * If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is. - * - * @see Crypt_AES::encrypt() - * @access public - * @param String $ciphertext - */ - function decrypt($ciphertext) - { - if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) { - $this->_mcryptSetup(); - /* - if ($this->mode == CRYPT_AES_MODE_CTR) { - $iv = $this->decryptIV; - $xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($ciphertext), $iv)); - $plaintext = $ciphertext ^ $xor; - if ($this->continuousBuffer) { - $this->decryptIV = $iv; - } - return $plaintext; - } - */ - - if ($this->mode != 'ctr') { - // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : - // "The data is padded with "\0" to make sure the length of the data is n * blocksize." - $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0)); - } - - $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); - } - - return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext; - } - - return parent::decrypt($ciphertext); - } - - /** - * Setup mcrypt - * - * Validates all the variables. - * - * @access private - */ - function _mcryptSetup() - { - if (!$this->changed) { - return; - } - - if (!$this->explicit_key_length) { - // this just copied from Crypt_Rijndael::_setup() - $length = strlen($this->key) >> 2; - if ($length > 8) { - $length = 8; - } else if ($length < 4) { - $length = 4; - } - $this->Nk = $length; - $this->key_size = $length << 2; - } - - switch ($this->Nk) { - case 4: // 128 - $this->key_size = 16; - break; - case 5: // 160 - case 6: // 192 - $this->key_size = 24; - break; - case 7: // 224 - case 8: // 256 - $this->key_size = 32; - } - - $this->key = substr($this->key, 0, $this->key_size); - $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0)); - - if (!isset($this->enmcrypt)) { - $mode = $this->mode; - //$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode; - - $this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); - $this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, ''); - } // else should mcrypt_generic_deinit be called? - - mcrypt_generic_init($this->demcrypt, $this->key, $this->iv); - mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv); - - $this->changed = false; - } - - /** - * Encrypts a block - * - * Optimized over Crypt_Rijndael's implementation by means of loop unrolling. - * - * @see Crypt_Rijndael::_encryptBlock() - * @access private - * @param String $in - * @return String - */ - function _encryptBlock($in) - { - $state = unpack('N*word', $in); - - $Nr = $this->Nr; - $w = $this->w; - $t0 = $this->t0; - $t1 = $this->t1; - $t2 = $this->t2; - $t3 = $this->t3; - - // addRoundKey and reindex $state - $state = array( - $state['word1'] ^ $w[0][0], - $state['word2'] ^ $w[0][1], - $state['word3'] ^ $w[0][2], - $state['word4'] ^ $w[0][3] - ); - - // shiftRows + subWord + mixColumns + addRoundKey - // we could loop unroll this and use if statements to do more rounds as necessary, but, in my tests, that yields - // only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it. - for ($round = 1; $round < $this->Nr; $round++) { - $state = array( - $t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0], - $t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1], - $t0[$state[2] & 0xFF000000] ^ $t1[$state[3] & 0x00FF0000] ^ $t2[$state[0] & 0x0000FF00] ^ $t3[$state[1] & 0x000000FF] ^ $w[$round][2], - $t0[$state[3] & 0xFF000000] ^ $t1[$state[0] & 0x00FF0000] ^ $t2[$state[1] & 0x0000FF00] ^ $t3[$state[2] & 0x000000FF] ^ $w[$round][3] - ); - - } - - // subWord - $state = array( - $this->_subWord($state[0]), - $this->_subWord($state[1]), - $this->_subWord($state[2]), - $this->_subWord($state[3]) - ); - - // shiftRows + addRoundKey - $state = array( - ($state[0] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[3] & 0x000000FF) ^ $this->w[$this->Nr][0], - ($state[1] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[0] & 0x000000FF) ^ $this->w[$this->Nr][1], - ($state[2] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[1] & 0x000000FF) ^ $this->w[$this->Nr][2], - ($state[3] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[2] & 0x000000FF) ^ $this->w[$this->Nr][3] - ); - - return pack('N*', $state[0], $state[1], $state[2], $state[3]); - } - - /** - * Decrypts a block - * - * Optimized over Crypt_Rijndael's implementation by means of loop unrolling. - * - * @see Crypt_Rijndael::_decryptBlock() - * @access private - * @param String $in - * @return String - */ - function _decryptBlock($in) - { - $state = unpack('N*word', $in); - - $Nr = $this->Nr; - $dw = $this->dw; - $dt0 = $this->dt0; - $dt1 = $this->dt1; - $dt2 = $this->dt2; - $dt3 = $this->dt3; - - // addRoundKey and reindex $state - $state = array( - $state['word1'] ^ $dw[$this->Nr][0], - $state['word2'] ^ $dw[$this->Nr][1], - $state['word3'] ^ $dw[$this->Nr][2], - $state['word4'] ^ $dw[$this->Nr][3] - ); - - - // invShiftRows + invSubBytes + invMixColumns + addRoundKey - for ($round = $this->Nr - 1; $round > 0; $round--) { - $state = array( - $dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0], - $dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1], - $dt0[$state[2] & 0xFF000000] ^ $dt1[$state[1] & 0x00FF0000] ^ $dt2[$state[0] & 0x0000FF00] ^ $dt3[$state[3] & 0x000000FF] ^ $dw[$round][2], - $dt0[$state[3] & 0xFF000000] ^ $dt1[$state[2] & 0x00FF0000] ^ $dt2[$state[1] & 0x0000FF00] ^ $dt3[$state[0] & 0x000000FF] ^ $dw[$round][3] - ); - } - - // invShiftRows + invSubWord + addRoundKey - $state = array( - $this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $dw[0][0], - $this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $dw[0][1], - $this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $dw[0][2], - $this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $dw[0][3] - ); - - return pack('N*', $state[0], $state[1], $state[2], $state[3]); - } -} - -// vim: ts=4:sw=4:et: -// vim6: fdl=1: \ No newline at end of file diff --git a/library/phpsec/Crypt/DES.php b/library/phpsec/Crypt/DES.php deleted file mode 100644 index 431ad539b3..0000000000 --- a/library/phpsec/Crypt/DES.php +++ /dev/null @@ -1,945 +0,0 @@ - - * setKey('abcdefgh'); - * - * $size = 10 * 1024; - * $plaintext = ''; - * for ($i = 0; $i < $size; $i++) { - * $plaintext.= 'a'; - * } - * - * echo $des->decrypt($des->encrypt($plaintext)); - * ?> - * - * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * @category Crypt - * @package Crypt_DES - * @author Jim Wigginton - * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: DES.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $ - * @link http://phpseclib.sourceforge.net - */ - -/**#@+ - * @access private - * @see Crypt_DES::_prepareKey() - * @see Crypt_DES::_processBlock() - */ -/** - * Contains array_reverse($keys[CRYPT_DES_DECRYPT]) - */ -define('CRYPT_DES_ENCRYPT', 0); -/** - * Contains array_reverse($keys[CRYPT_DES_ENCRYPT]) - */ -define('CRYPT_DES_DECRYPT', 1); -/**#@-*/ - -/**#@+ - * @access public - * @see Crypt_DES::encrypt() - * @see Crypt_DES::decrypt() - */ -/** - * Encrypt / decrypt using the Counter mode. - * - * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 - */ -define('CRYPT_DES_MODE_CTR', -1); -/** - * Encrypt / decrypt using the Electronic Code Book mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 - */ -define('CRYPT_DES_MODE_ECB', 1); -/** - * Encrypt / decrypt using the Code Book Chaining mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 - */ -define('CRYPT_DES_MODE_CBC', 2); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_DES::Crypt_DES() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_DES_MODE_INTERNAL', 1); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_DES_MODE_MCRYPT', 2); -/**#@-*/ - -/** - * Pure-PHP implementation of DES. - * - * @author Jim Wigginton - * @version 0.1.0 - * @access public - * @package Crypt_DES - */ -class Crypt_DES { - /** - * The Key Schedule - * - * @see Crypt_DES::setKey() - * @var Array - * @access private - */ - var $keys = "\0\0\0\0\0\0\0\0"; - - /** - * The Encryption Mode - * - * @see Crypt_DES::Crypt_DES() - * @var Integer - * @access private - */ - var $mode; - - /** - * Continuous Buffer status - * - * @see Crypt_DES::enableContinuousBuffer() - * @var Boolean - * @access private - */ - var $continuousBuffer = false; - - /** - * Padding status - * - * @see Crypt_DES::enablePadding() - * @var Boolean - * @access private - */ - var $padding = true; - - /** - * The Initialization Vector - * - * @see Crypt_DES::setIV() - * @var String - * @access private - */ - var $iv = "\0\0\0\0\0\0\0\0"; - - /** - * A "sliding" Initialization Vector - * - * @see Crypt_DES::enableContinuousBuffer() - * @var String - * @access private - */ - var $encryptIV = "\0\0\0\0\0\0\0\0"; - - /** - * A "sliding" Initialization Vector - * - * @see Crypt_DES::enableContinuousBuffer() - * @var String - * @access private - */ - var $decryptIV = "\0\0\0\0\0\0\0\0"; - - /** - * mcrypt resource for encryption - * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. - * - * @see Crypt_AES::encrypt() - * @var String - * @access private - */ - var $enmcrypt; - - /** - * mcrypt resource for decryption - * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. - * - * @see Crypt_AES::decrypt() - * @var String - * @access private - */ - var $demcrypt; - - /** - * Does the (en|de)mcrypt resource need to be (re)initialized? - * - * @see setKey() - * @see setIV() - * @var Boolean - * @access private - */ - var $changed = true; - - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be - * CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used. - * - * @param optional Integer $mode - * @return Crypt_DES - * @access public - */ - function Crypt_DES($mode = CRYPT_MODE_DES_CBC) - { - if ( !defined('CRYPT_DES_MODE') ) { - switch (true) { - case extension_loaded('mcrypt'): - // i'd check to see if des was supported, by doing in_array('des', mcrypt_list_algorithms('')), - // but since that can be changed after the object has been created, there doesn't seem to be - // a lot of point... - define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT); - break; - default: - define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL); - } - } - - switch ( CRYPT_DES_MODE ) { - case CRYPT_DES_MODE_MCRYPT: - switch ($mode) { - case CRYPT_DES_MODE_ECB: - $this->mode = MCRYPT_MODE_ECB; - break; - case CRYPT_DES_MODE_CTR: - $this->mode = 'ctr'; - //$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_DES_MODE_CTR; - break; - case CRYPT_DES_MODE_CBC: - default: - $this->mode = MCRYPT_MODE_CBC; - } - - break; - default: - switch ($mode) { - case CRYPT_DES_MODE_ECB: - case CRYPT_DES_MODE_CTR: - case CRYPT_DES_MODE_CBC: - $this->mode = $mode; - break; - default: - $this->mode = CRYPT_DES_MODE_CBC; - } - } - } - - /** - * Sets the key. - * - * Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we - * only use the first eight, if $key has more then eight characters in it, and pad $key with the - * null byte if it is less then eight characters long. - * - * DES also requires that every eighth bit be a parity bit, however, we'll ignore that. - * - * If the key is not explicitly set, it'll be assumed to be all zero's. - * - * @access public - * @param String $key - */ - function setKey($key) - { - $this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? substr($key, 0, 8) : $this->_prepareKey($key); - $this->changed = true; - } - - /** - * Sets the initialization vector. (optional) - * - * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed - * to be all zero's. - * - * @access public - * @param String $iv - */ - function setIV($iv) - { - $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0)); - $this->changed = true; - } - - /** - * Generate CTR XOR encryption key - * - * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the - * plaintext / ciphertext in CTR mode. - * - * @see Crypt_DES::decrypt() - * @see Crypt_DES::encrypt() - * @access public - * @param Integer $length - * @param String $iv - */ - function _generate_xor($length, &$iv) - { - $xor = ''; - $num_blocks = ($length + 7) >> 3; - for ($i = 0; $i < $num_blocks; $i++) { - $xor.= $iv; - for ($j = 4; $j <= 8; $j+=4) { - $temp = substr($iv, -$j, 4); - switch ($temp) { - case "\xFF\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); - break; - case "\x7F\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); - break 2; - default: - extract(unpack('Ncount', $temp)); - $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); - break 2; - } - } - } - - return $xor; - } - - /** - * Encrypts a message. - * - * $plaintext will be padded with up to 8 additional bytes. Other DES implementations may or may not pad in the - * same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following - * URL: - * - * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} - * - * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. - * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that - * length. - * - * @see Crypt_DES::decrypt() - * @access public - * @param String $plaintext - */ - function encrypt($plaintext) - { - if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') { - $plaintext = $this->_pad($plaintext); - } - - if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { - if ($this->changed) { - if (!isset($this->enmcrypt)) { - $this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); - } - mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); - $this->changed = false; - } - - $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV); - } - - return $ciphertext; - } - - if (!is_array($this->keys)) { - $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0"); - } - - $ciphertext = ''; - switch ($this->mode) { - case CRYPT_DES_MODE_ECB: - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $ciphertext.= $this->_processBlock(substr($plaintext, $i, 8), CRYPT_DES_ENCRYPT); - } - break; - case CRYPT_DES_MODE_CBC: - $xor = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $block = substr($plaintext, $i, 8); - $block = $this->_processBlock($block ^ $xor, CRYPT_DES_ENCRYPT); - $xor = $block; - $ciphertext.= $block; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - } - break; - case CRYPT_DES_MODE_CTR: - $xor = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $block = substr($plaintext, $i, 8); - $key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT); - $ciphertext.= $block ^ $key; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - } - } - - return $ciphertext; - } - - /** - * Decrypts a message. - * - * If strlen($ciphertext) is not a multiple of 8, null bytes will be added to the end of the string until it is. - * - * @see Crypt_DES::encrypt() - * @access public - * @param String $ciphertext - */ - function decrypt($ciphertext) - { - if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') { - // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : - // "The data is padded with "\0" to make sure the length of the data is n * blocksize." - $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0)); - } - - if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { - if ($this->changed) { - if (!isset($this->demcrypt)) { - $this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, ''); - } - mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); - $this->changed = false; - } - - $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV); - } - - return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext; - } - - if (!is_array($this->keys)) { - $this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0"); - } - - $plaintext = ''; - switch ($this->mode) { - case CRYPT_DES_MODE_ECB: - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $plaintext.= $this->_processBlock(substr($ciphertext, $i, 8), CRYPT_DES_DECRYPT); - } - break; - case CRYPT_DES_MODE_CBC: - $xor = $this->decryptIV; - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $block = substr($ciphertext, $i, 8); - $plaintext.= $this->_processBlock($block, CRYPT_DES_DECRYPT) ^ $xor; - $xor = $block; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - } - break; - case CRYPT_DES_MODE_CTR: - $xor = $this->decryptIV; - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $block = substr($ciphertext, $i, 8); - $key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT); - $plaintext.= $block ^ $key; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - } - } - - return $this->mode != CRYPT_DES_MODE_CTR ? $this->_unpad($plaintext) : $plaintext; - } - - /** - * Treat consecutive "packets" as if they are a continuous buffer. - * - * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets - * will yield different outputs: - * - * - * echo $des->encrypt(substr($plaintext, 0, 8)); - * echo $des->encrypt(substr($plaintext, 8, 8)); - * - * - * echo $des->encrypt($plaintext); - * - * - * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates - * another, as demonstrated with the following: - * - * - * $des->encrypt(substr($plaintext, 0, 8)); - * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); - * - * - * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); - * - * - * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different - * outputs. The reason is due to the fact that the initialization vector's change after every encryption / - * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. - * - * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each - * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that - * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), - * however, they are also less intuitive and more likely to cause you problems. - * - * @see Crypt_DES::disableContinuousBuffer() - * @access public - */ - function enableContinuousBuffer() - { - $this->continuousBuffer = true; - } - - /** - * Treat consecutive packets as if they are a discontinuous buffer. - * - * The default behavior. - * - * @see Crypt_DES::enableContinuousBuffer() - * @access public - */ - function disableContinuousBuffer() - { - $this->continuousBuffer = false; - $this->encryptIV = $this->iv; - $this->decryptIV = $this->iv; - } - - /** - * Pad "packets". - * - * DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not - * a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight. - * - * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1, - * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping - * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is - * transmitted separately) - * - * @see Crypt_DES::disablePadding() - * @access public - */ - function enablePadding() - { - $this->padding = true; - } - - /** - * Do not pad packets. - * - * @see Crypt_DES::enablePadding() - * @access public - */ - function disablePadding() - { - $this->padding = false; - } - - /** - * Pads a string - * - * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8). - * 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7) - * - * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless - * and padding will, hence forth, be enabled. - * - * @see Crypt_DES::_unpad() - * @access private - */ - function _pad($text) - { - $length = strlen($text); - - if (!$this->padding) { - if (($length & 7) == 0) { - return $text; - } else { - user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE); - $this->padding = true; - } - } - - $pad = 8 - ($length & 7); - return str_pad($text, $length + $pad, chr($pad)); - } - - /** - * Unpads a string - * - * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong - * and false will be returned. - * - * @see Crypt_DES::_pad() - * @access private - */ - function _unpad($text) - { - if (!$this->padding) { - return $text; - } - - $length = ord($text[strlen($text) - 1]); - - if (!$length || $length > 8) { - return false; - } - - return substr($text, 0, -$length); - } - - /** - * Encrypts or decrypts a 64-bit block - * - * $mode should be either CRYPT_DES_ENCRYPT or CRYPT_DES_DECRYPT. See - * {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general - * idea of what this function does. - * - * @access private - * @param String $block - * @param Integer $mode - * @return String - */ - function _processBlock($block, $mode) - { - // s-boxes. in the official DES docs, they're described as being matrices that - // one accesses by using the first and last bits to determine the row and the - // middle four bits to determine the column. in this implementation, they've - // been converted to vectors - static $sbox = array( - array( - 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, - 3, 10 ,10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, - 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, - 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13 - ), - array( - 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, - 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, - 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, - 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9 - ), - array( - 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, - 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, - 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, - 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12 - ), - array( - 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, - 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, - 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, - 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14 - ), - array( - 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, - 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, - 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13, - 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3 - ), - array( - 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, - 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, - 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, - 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13 - ), - array( - 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, - 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, - 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, - 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12 - ), - array( - 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, - 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, - 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, - 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11 - ) - ); - - $keys = $this->keys; - - $temp = unpack('Na/Nb', $block); - $block = array($temp['a'], $temp['b']); - - // because php does arithmetic right shifts, if the most significant bits are set, right - // shifting those into the correct position will add 1's - not 0's. this will intefere - // with the | operation unless a second & is done. so we isolate these bits and left shift - // them into place. we then & each block with 0x7FFFFFFF to prevennt 1's from being added - // for any other shifts. - $msb = array( - ($block[0] >> 31) & 1, - ($block[1] >> 31) & 1 - ); - $block[0] &= 0x7FFFFFFF; - $block[1] &= 0x7FFFFFFF; - - // we isolate the appropriate bit in the appropriate integer and shift as appropriate. in - // some cases, there are going to be multiple bits in the same integer that need to be shifted - // in the same way. we combine those into one shift operation. - $block = array( - (($block[1] & 0x00000040) << 25) | (($block[1] & 0x00004000) << 16) | - (($block[1] & 0x00400001) << 7) | (($block[1] & 0x40000100) >> 2) | - (($block[0] & 0x00000040) << 21) | (($block[0] & 0x00004000) << 12) | - (($block[0] & 0x00400001) << 3) | (($block[0] & 0x40000100) >> 6) | - (($block[1] & 0x00000010) << 19) | (($block[1] & 0x00001000) << 10) | - (($block[1] & 0x00100000) << 1) | (($block[1] & 0x10000000) >> 8) | - (($block[0] & 0x00000010) << 15) | (($block[0] & 0x00001000) << 6) | - (($block[0] & 0x00100000) >> 3) | (($block[0] & 0x10000000) >> 12) | - (($block[1] & 0x00000004) << 13) | (($block[1] & 0x00000400) << 4) | - (($block[1] & 0x00040000) >> 5) | (($block[1] & 0x04000000) >> 14) | - (($block[0] & 0x00000004) << 9) | ( $block[0] & 0x00000400 ) | - (($block[0] & 0x00040000) >> 9) | (($block[0] & 0x04000000) >> 18) | - (($block[1] & 0x00010000) >> 11) | (($block[1] & 0x01000000) >> 20) | - (($block[0] & 0x00010000) >> 15) | (($block[0] & 0x01000000) >> 24) - , - (($block[1] & 0x00000080) << 24) | (($block[1] & 0x00008000) << 15) | - (($block[1] & 0x00800002) << 6) | (($block[0] & 0x00000080) << 20) | - (($block[0] & 0x00008000) << 11) | (($block[0] & 0x00800002) << 2) | - (($block[1] & 0x00000020) << 18) | (($block[1] & 0x00002000) << 9) | - ( $block[1] & 0x00200000 ) | (($block[1] & 0x20000000) >> 9) | - (($block[0] & 0x00000020) << 14) | (($block[0] & 0x00002000) << 5) | - (($block[0] & 0x00200000) >> 4) | (($block[0] & 0x20000000) >> 13) | - (($block[1] & 0x00000008) << 12) | (($block[1] & 0x00000800) << 3) | - (($block[1] & 0x00080000) >> 6) | (($block[1] & 0x08000000) >> 15) | - (($block[0] & 0x00000008) << 8) | (($block[0] & 0x00000800) >> 1) | - (($block[0] & 0x00080000) >> 10) | (($block[0] & 0x08000000) >> 19) | - (($block[1] & 0x00000200) >> 3) | (($block[0] & 0x00000200) >> 7) | - (($block[1] & 0x00020000) >> 12) | (($block[1] & 0x02000000) >> 21) | - (($block[0] & 0x00020000) >> 16) | (($block[0] & 0x02000000) >> 25) | - ($msb[1] << 28) | ($msb[0] << 24) - ); - - for ($i = 0; $i < 16; $i++) { - // start of "the Feistel (F) function" - see the following URL: - // http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png - $temp = (($sbox[0][((($block[1] >> 27) & 0x1F) | (($block[1] & 1) << 5)) ^ $keys[$mode][$i][0]]) << 28) - | (($sbox[1][(($block[1] & 0x1F800000) >> 23) ^ $keys[$mode][$i][1]]) << 24) - | (($sbox[2][(($block[1] & 0x01F80000) >> 19) ^ $keys[$mode][$i][2]]) << 20) - | (($sbox[3][(($block[1] & 0x001F8000) >> 15) ^ $keys[$mode][$i][3]]) << 16) - | (($sbox[4][(($block[1] & 0x0001F800) >> 11) ^ $keys[$mode][$i][4]]) << 12) - | (($sbox[5][(($block[1] & 0x00001F80) >> 7) ^ $keys[$mode][$i][5]]) << 8) - | (($sbox[6][(($block[1] & 0x000001F8) >> 3) ^ $keys[$mode][$i][6]]) << 4) - | ( $sbox[7][((($block[1] & 0x1F) << 1) | (($block[1] >> 31) & 1)) ^ $keys[$mode][$i][7]]); - - $msb = ($temp >> 31) & 1; - $temp &= 0x7FFFFFFF; - $newBlock = (($temp & 0x00010000) << 15) | (($temp & 0x02020120) << 5) - | (($temp & 0x00001800) << 17) | (($temp & 0x01000000) >> 10) - | (($temp & 0x00000008) << 24) | (($temp & 0x00100000) << 6) - | (($temp & 0x00000010) << 21) | (($temp & 0x00008000) << 9) - | (($temp & 0x00000200) << 12) | (($temp & 0x10000000) >> 27) - | (($temp & 0x00000040) << 14) | (($temp & 0x08000000) >> 8) - | (($temp & 0x00004000) << 4) | (($temp & 0x00000002) << 16) - | (($temp & 0x00442000) >> 6) | (($temp & 0x40800000) >> 15) - | (($temp & 0x00000001) << 11) | (($temp & 0x20000000) >> 20) - | (($temp & 0x00080000) >> 13) | (($temp & 0x00000004) << 3) - | (($temp & 0x04000000) >> 22) | (($temp & 0x00000480) >> 7) - | (($temp & 0x00200000) >> 19) | ($msb << 23); - // end of "the Feistel (F) function" - $newBlock is F's output - - $temp = $block[1]; - $block[1] = $block[0] ^ $newBlock; - $block[0] = $temp; - } - - $msb = array( - ($block[0] >> 31) & 1, - ($block[1] >> 31) & 1 - ); - $block[0] &= 0x7FFFFFFF; - $block[1] &= 0x7FFFFFFF; - - $block = array( - (($block[0] & 0x01000004) << 7) | (($block[1] & 0x01000004) << 6) | - (($block[0] & 0x00010000) << 13) | (($block[1] & 0x00010000) << 12) | - (($block[0] & 0x00000100) << 19) | (($block[1] & 0x00000100) << 18) | - (($block[0] & 0x00000001) << 25) | (($block[1] & 0x00000001) << 24) | - (($block[0] & 0x02000008) >> 2) | (($block[1] & 0x02000008) >> 3) | - (($block[0] & 0x00020000) << 4) | (($block[1] & 0x00020000) << 3) | - (($block[0] & 0x00000200) << 10) | (($block[1] & 0x00000200) << 9) | - (($block[0] & 0x00000002) << 16) | (($block[1] & 0x00000002) << 15) | - (($block[0] & 0x04000000) >> 11) | (($block[1] & 0x04000000) >> 12) | - (($block[0] & 0x00040000) >> 5) | (($block[1] & 0x00040000) >> 6) | - (($block[0] & 0x00000400) << 1) | ( $block[1] & 0x00000400 ) | - (($block[0] & 0x08000000) >> 20) | (($block[1] & 0x08000000) >> 21) | - (($block[0] & 0x00080000) >> 14) | (($block[1] & 0x00080000) >> 15) | - (($block[0] & 0x00000800) >> 8) | (($block[1] & 0x00000800) >> 9) - , - (($block[0] & 0x10000040) << 3) | (($block[1] & 0x10000040) << 2) | - (($block[0] & 0x00100000) << 9) | (($block[1] & 0x00100000) << 8) | - (($block[0] & 0x00001000) << 15) | (($block[1] & 0x00001000) << 14) | - (($block[0] & 0x00000010) << 21) | (($block[1] & 0x00000010) << 20) | - (($block[0] & 0x20000080) >> 6) | (($block[1] & 0x20000080) >> 7) | - ( $block[0] & 0x00200000 ) | (($block[1] & 0x00200000) >> 1) | - (($block[0] & 0x00002000) << 6) | (($block[1] & 0x00002000) << 5) | - (($block[0] & 0x00000020) << 12) | (($block[1] & 0x00000020) << 11) | - (($block[0] & 0x40000000) >> 15) | (($block[1] & 0x40000000) >> 16) | - (($block[0] & 0x00400000) >> 9) | (($block[1] & 0x00400000) >> 10) | - (($block[0] & 0x00004000) >> 3) | (($block[1] & 0x00004000) >> 4) | - (($block[0] & 0x00800000) >> 18) | (($block[1] & 0x00800000) >> 19) | - (($block[0] & 0x00008000) >> 12) | (($block[1] & 0x00008000) >> 13) | - ($msb[0] << 7) | ($msb[1] << 6) - ); - - return pack('NN', $block[0], $block[1]); - } - - /** - * Creates the key schedule. - * - * @access private - * @param String $key - * @return Array - */ - function _prepareKey($key) - { - static $shifts = array( // number of key bits shifted per round - 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 - ); - - // pad the key and remove extra characters as appropriate. - $key = str_pad(substr($key, 0, 8), 8, chr(0)); - - $temp = unpack('Na/Nb', $key); - $key = array($temp['a'], $temp['b']); - $msb = array( - ($key[0] >> 31) & 1, - ($key[1] >> 31) & 1 - ); - $key[0] &= 0x7FFFFFFF; - $key[1] &= 0x7FFFFFFF; - - $key = array( - (($key[1] & 0x00000002) << 26) | (($key[1] & 0x00000204) << 17) | - (($key[1] & 0x00020408) << 8) | (($key[1] & 0x02040800) >> 1) | - (($key[0] & 0x00000002) << 22) | (($key[0] & 0x00000204) << 13) | - (($key[0] & 0x00020408) << 4) | (($key[0] & 0x02040800) >> 5) | - (($key[1] & 0x04080000) >> 10) | (($key[0] & 0x04080000) >> 14) | - (($key[1] & 0x08000000) >> 19) | (($key[0] & 0x08000000) >> 23) | - (($key[0] & 0x00000010) >> 1) | (($key[0] & 0x00001000) >> 10) | - (($key[0] & 0x00100000) >> 19) | (($key[0] & 0x10000000) >> 28) - , - (($key[1] & 0x00000080) << 20) | (($key[1] & 0x00008000) << 11) | - (($key[1] & 0x00800000) << 2) | (($key[0] & 0x00000080) << 16) | - (($key[0] & 0x00008000) << 7) | (($key[0] & 0x00800000) >> 2) | - (($key[1] & 0x00000040) << 13) | (($key[1] & 0x00004000) << 4) | - (($key[1] & 0x00400000) >> 5) | (($key[1] & 0x40000000) >> 14) | - (($key[0] & 0x00000040) << 9) | ( $key[0] & 0x00004000 ) | - (($key[0] & 0x00400000) >> 9) | (($key[0] & 0x40000000) >> 18) | - (($key[1] & 0x00000020) << 6) | (($key[1] & 0x00002000) >> 3) | - (($key[1] & 0x00200000) >> 12) | (($key[1] & 0x20000000) >> 21) | - (($key[0] & 0x00000020) << 2) | (($key[0] & 0x00002000) >> 7) | - (($key[0] & 0x00200000) >> 16) | (($key[0] & 0x20000000) >> 25) | - (($key[1] & 0x00000010) >> 1) | (($key[1] & 0x00001000) >> 10) | - (($key[1] & 0x00100000) >> 19) | (($key[1] & 0x10000000) >> 28) | - ($msb[1] << 24) | ($msb[0] << 20) - ); - - $keys = array(); - for ($i = 0; $i < 16; $i++) { - $key[0] <<= $shifts[$i]; - $temp = ($key[0] & 0xF0000000) >> 28; - $key[0] = ($key[0] | $temp) & 0x0FFFFFFF; - - $key[1] <<= $shifts[$i]; - $temp = ($key[1] & 0xF0000000) >> 28; - $key[1] = ($key[1] | $temp) & 0x0FFFFFFF; - - $temp = array( - (($key[1] & 0x00004000) >> 9) | (($key[1] & 0x00000800) >> 7) | - (($key[1] & 0x00020000) >> 14) | (($key[1] & 0x00000010) >> 2) | - (($key[1] & 0x08000000) >> 26) | (($key[1] & 0x00800000) >> 23) - , - (($key[1] & 0x02400000) >> 20) | (($key[1] & 0x00000001) << 4) | - (($key[1] & 0x00002000) >> 10) | (($key[1] & 0x00040000) >> 18) | - (($key[1] & 0x00000080) >> 6) - , - ( $key[1] & 0x00000020 ) | (($key[1] & 0x00000200) >> 5) | - (($key[1] & 0x00010000) >> 13) | (($key[1] & 0x01000000) >> 22) | - (($key[1] & 0x00000004) >> 1) | (($key[1] & 0x00100000) >> 20) - , - (($key[1] & 0x00001000) >> 7) | (($key[1] & 0x00200000) >> 17) | - (($key[1] & 0x00000002) << 2) | (($key[1] & 0x00000100) >> 6) | - (($key[1] & 0x00008000) >> 14) | (($key[1] & 0x04000000) >> 26) - , - (($key[0] & 0x00008000) >> 10) | ( $key[0] & 0x00000010 ) | - (($key[0] & 0x02000000) >> 22) | (($key[0] & 0x00080000) >> 17) | - (($key[0] & 0x00000200) >> 8) | (($key[0] & 0x00000002) >> 1) - , - (($key[0] & 0x04000000) >> 21) | (($key[0] & 0x00010000) >> 12) | - (($key[0] & 0x00000020) >> 2) | (($key[0] & 0x00000800) >> 9) | - (($key[0] & 0x00800000) >> 22) | (($key[0] & 0x00000100) >> 8) - , - (($key[0] & 0x00001000) >> 7) | (($key[0] & 0x00000088) >> 3) | - (($key[0] & 0x00020000) >> 14) | (($key[0] & 0x00000001) << 2) | - (($key[0] & 0x00400000) >> 21) - , - (($key[0] & 0x00000400) >> 5) | (($key[0] & 0x00004000) >> 10) | - (($key[0] & 0x00000040) >> 3) | (($key[0] & 0x00100000) >> 18) | - (($key[0] & 0x08000000) >> 26) | (($key[0] & 0x01000000) >> 24) - ); - - $keys[] = $temp; - } - - $temp = array( - CRYPT_DES_ENCRYPT => $keys, - CRYPT_DES_DECRYPT => array_reverse($keys) - ); - - return $temp; - } -} - -// vim: ts=4:sw=4:et: -// vim6: fdl=1: \ No newline at end of file diff --git a/library/phpsec/Crypt/Hash.php b/library/phpsec/Crypt/Hash.php deleted file mode 100644 index ef3a858026..0000000000 --- a/library/phpsec/Crypt/Hash.php +++ /dev/null @@ -1,816 +0,0 @@ - - * setKey('abcdefg'); - * - * echo base64_encode($hash->hash('abcdefg')); - * ?> - * - * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * @category Crypt - * @package Crypt_Hash - * @author Jim Wigginton - * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: Hash.php,v 1.6 2009/11/23 23:37:07 terrafrost Exp $ - * @link http://phpseclib.sourceforge.net - */ - -/**#@+ - * @access private - * @see Crypt_Hash::Crypt_Hash() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_HASH_MODE_INTERNAL', 1); -/** - * Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+. - */ -define('CRYPT_HASH_MODE_MHASH', 2); -/** - * Toggles the hash() implementation, which works on PHP 5.1.2+. - */ -define('CRYPT_HASH_MODE_HASH', 3); -/**#@-*/ - -/** - * Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions. - * - * @author Jim Wigginton - * @version 0.1.0 - * @access public - * @package Crypt_Hash - */ -class Crypt_Hash { - /** - * Byte-length of compression blocks / key (Internal HMAC) - * - * @see Crypt_Hash::setAlgorithm() - * @var Integer - * @access private - */ - var $b; - - /** - * Byte-length of hash output (Internal HMAC) - * - * @see Crypt_Hash::setHash() - * @var Integer - * @access private - */ - var $l = false; - - /** - * Hash Algorithm - * - * @see Crypt_Hash::setHash() - * @var String - * @access private - */ - var $hash; - - /** - * Key - * - * @see Crypt_Hash::setKey() - * @var String - * @access private - */ - var $key = ''; - - /** - * Outer XOR (Internal HMAC) - * - * @see Crypt_Hash::setKey() - * @var String - * @access private - */ - var $opad; - - /** - * Inner XOR (Internal HMAC) - * - * @see Crypt_Hash::setKey() - * @var String - * @access private - */ - var $ipad; - - /** - * Default Constructor. - * - * @param optional String $hash - * @return Crypt_Hash - * @access public - */ - function Crypt_Hash($hash = 'sha1') - { - if ( !defined('CRYPT_HASH_MODE') ) { - switch (true) { - case extension_loaded('hash'): - define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH); - break; - case extension_loaded('mhash'): - define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH); - break; - default: - define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL); - } - } - - $this->setHash($hash); - } - - /** - * Sets the key for HMACs - * - * Keys can be of any length. - * - * @access public - * @param String $key - */ - function setKey($key) - { - $this->key = $key; - } - - /** - * Sets the hash function. - * - * @access public - * @param String $hash - */ - function setHash($hash) - { - switch ($hash) { - case 'md5-96': - case 'sha1-96': - $this->l = 12; // 96 / 8 = 12 - break; - case 'md2': - case 'md5': - $this->l = 16; - break; - case 'sha1': - $this->l = 20; - break; - case 'sha256': - $this->l = 32; - break; - case 'sha384': - $this->l = 48; - break; - case 'sha512': - $this->l = 64; - } - - switch ($hash) { - case 'md2': - $mode = CRYPT_HASH_MODE_INTERNAL; - break; - case 'sha384': - case 'sha512': - $mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; - break; - default: - $mode = CRYPT_HASH_MODE; - } - - switch ( $mode ) { - case CRYPT_HASH_MODE_MHASH: - switch ($hash) { - case 'md5': - case 'md5-96': - $this->hash = MHASH_MD5; - break; - case 'sha256': - $this->hash = MHASH_SHA256; - break; - case 'sha1': - case 'sha1-96': - default: - $this->hash = MHASH_SHA1; - } - return; - case CRYPT_HASH_MODE_HASH: - switch ($hash) { - case 'md5': - case 'md5-96': - $this->hash = 'md5'; - return; - case 'sha256': - case 'sha384': - case 'sha512': - $this->hash = $hash; - return; - case 'sha1': - case 'sha1-96': - default: - $this->hash = 'sha1'; - } - return; - } - - switch ($hash) { - case 'md2': - $this->b = 16; - $this->hash = array($this, '_md2'); - break; - case 'md5': - case 'md5-96': - $this->b = 64; - $this->hash = array($this, '_md5'); - break; - case 'sha256': - $this->b = 64; - $this->hash = array($this, '_sha256'); - break; - case 'sha384': - case 'sha512': - $this->b = 128; - $this->hash = array($this, '_sha512'); - break; - case 'sha1': - case 'sha1-96': - default: - $this->b = 64; - $this->hash = array($this, '_sha1'); - } - - $this->ipad = str_repeat(chr(0x36), $this->b); - $this->opad = str_repeat(chr(0x5C), $this->b); - } - - /** - * Compute the HMAC. - * - * @access public - * @param String $text - * @return String - */ - function hash($text) - { - $mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE; - - if (!empty($this->key)) { - switch ( $mode ) { - case CRYPT_HASH_MODE_MHASH: - $output = mhash($this->hash, $text, $this->key); - break; - case CRYPT_HASH_MODE_HASH: - $output = hash_hmac($this->hash, $text, $this->key, true); - break; - case CRYPT_HASH_MODE_INTERNAL: - /* "Applications that use keys longer than B bytes will first hash the key using H and then use the - resultant L byte string as the actual key to HMAC." - - -- http://tools.ietf.org/html/rfc2104#section-2 */ - $key = strlen($this->key) > $this->b ? call_user_func($this->$hash, $this->key) : $this->key; - - $key = str_pad($key, $this->b, chr(0)); // step 1 - $temp = $this->ipad ^ $key; // step 2 - $temp .= $text; // step 3 - $temp = call_user_func($this->hash, $temp); // step 4 - $output = $this->opad ^ $key; // step 5 - $output.= $temp; // step 6 - $output = call_user_func($this->hash, $output); // step 7 - } - } else { - switch ( $mode ) { - case CRYPT_HASH_MODE_MHASH: - $output = mhash($this->hash, $text); - break; - case CRYPT_HASH_MODE_HASH: - $output = hash($this->hash, $text, true); - break; - case CRYPT_HASH_MODE_INTERNAL: - $output = call_user_func($this->hash, $text); - } - } - - return substr($output, 0, $this->l); - } - - /** - * Returns the hash length (in bytes) - * - * @access private - * @return Integer - */ - function getLength() - { - return $this->l; - } - - /** - * Wrapper for MD5 - * - * @access private - * @param String $text - */ - function _md5($m) - { - return pack('H*', md5($m)); - } - - /** - * Wrapper for SHA1 - * - * @access private - * @param String $text - */ - function _sha1($m) - { - return pack('H*', sha1($m)); - } - - /** - * Pure-PHP implementation of MD2 - * - * See {@link http://tools.ietf.org/html/rfc1319 RFC1319}. - * - * @access private - * @param String $text - */ - function _md2($m) - { - static $s = array( - 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, - 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, - 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, - 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, - 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, - 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, - 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, - 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, - 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, - 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, - 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, - 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, - 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, - 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, - 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, - 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, - 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, - 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 - ); - - // Step 1. Append Padding Bytes - $pad = 16 - (strlen($m) & 0xF); - $m.= str_repeat(chr($pad), $pad); - - $length = strlen($m); - - // Step 2. Append Checksum - $c = str_repeat(chr(0), 16); - $l = chr(0); - for ($i = 0; $i < $length; $i+= 16) { - for ($j = 0; $j < 16; $j++) { - $c[$j] = chr($s[ord($m[$i + $j] ^ $l)]); - $l = $c[$j]; - } - } - $m.= $c; - - $length+= 16; - - // Step 3. Initialize MD Buffer - $x = str_repeat(chr(0), 48); - - // Step 4. Process Message in 16-Byte Blocks - for ($i = 0; $i < $length; $i+= 16) { - for ($j = 0; $j < 16; $j++) { - $x[$j + 16] = $m[$i + $j]; - $x[$j + 32] = $x[$j + 16] ^ $x[$j]; - } - $t = chr(0); - for ($j = 0; $j < 18; $j++) { - for ($k = 0; $k < 48; $k++) { - $x[$k] = $t = $x[$k] ^ chr($s[ord($t)]); - //$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]); - } - $t = chr(ord($t) + $j); - } - } - - // Step 5. Output - return substr($x, 0, 16); - } - - /** - * Pure-PHP implementation of SHA256 - * - * See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}. - * - * @access private - * @param String $text - */ - function _sha256($m) - { - if (extension_loaded('suhosin')) { - return pack('H*', sha256($m)); - } - - // Initialize variables - $hash = array( - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 - ); - // Initialize table of round constants - // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311) - static $k = array( - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 - ); - - // Pre-processing - $length = strlen($m); - // to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64 - $m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F)); - $m[$length] = chr(0x80); - // we don't support hashing strings 512MB long - $m.= pack('N2', 0, $length << 3); - - // Process the message in successive 512-bit chunks - $chunks = str_split($m, 64); - foreach ($chunks as $chunk) { - $w = array(); - for ($i = 0; $i < 16; $i++) { - extract(unpack('Ntemp', $this->_string_shift($chunk, 4))); - $w[] = $temp; - } - - // Extend the sixteen 32-bit words into sixty-four 32-bit words - for ($i = 16; $i < 64; $i++) { - $s0 = $this->_rightRotate($w[$i - 15], 7) ^ - $this->_rightRotate($w[$i - 15], 18) ^ - $this->_rightShift( $w[$i - 15], 3); - $s1 = $this->_rightRotate($w[$i - 2], 17) ^ - $this->_rightRotate($w[$i - 2], 19) ^ - $this->_rightShift( $w[$i - 2], 10); - $w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1); - - } - - // Initialize hash value for this chunk - list($a, $b, $c, $d, $e, $f, $g, $h) = $hash; - - // Main loop - for ($i = 0; $i < 64; $i++) { - $s0 = $this->_rightRotate($a, 2) ^ - $this->_rightRotate($a, 13) ^ - $this->_rightRotate($a, 22); - $maj = ($a & $b) ^ - ($a & $c) ^ - ($b & $c); - $t2 = $this->_add($s0, $maj); - - $s1 = $this->_rightRotate($e, 6) ^ - $this->_rightRotate($e, 11) ^ - $this->_rightRotate($e, 25); - $ch = ($e & $f) ^ - ($this->_not($e) & $g); - $t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]); - - $h = $g; - $g = $f; - $f = $e; - $e = $this->_add($d, $t1); - $d = $c; - $c = $b; - $b = $a; - $a = $this->_add($t1, $t2); - } - - // Add this chunk's hash to result so far - $hash = array( - $this->_add($hash[0], $a), - $this->_add($hash[1], $b), - $this->_add($hash[2], $c), - $this->_add($hash[3], $d), - $this->_add($hash[4], $e), - $this->_add($hash[5], $f), - $this->_add($hash[6], $g), - $this->_add($hash[7], $h) - ); - } - - // Produce the final hash value (big-endian) - return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]); - } - - /** - * Pure-PHP implementation of SHA384 and SHA512 - * - * @access private - * @param String $text - */ - function _sha512($m) - { - if (!class_exists('Math_BigInteger')) { - require_once('Math/BigInteger.php'); - } - - static $init384, $init512, $k; - - if (!isset($k)) { - // Initialize variables - $init384 = array( // initial values for SHA384 - 'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939', - '67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4' - ); - $init512 = array( // initial values for SHA512 - '6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1', - '510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179' - ); - - for ($i = 0; $i < 8; $i++) { - $init384[$i] = new Math_BigInteger($init384[$i], 16); - $init384[$i]->setPrecision(64); - $init512[$i] = new Math_BigInteger($init512[$i], 16); - $init512[$i]->setPrecision(64); - } - - // Initialize table of round constants - // (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409) - $k = array( - '428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc', - '3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118', - 'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2', - '72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694', - 'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65', - '2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5', - '983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4', - 'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70', - '27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df', - '650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b', - 'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30', - 'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8', - '19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8', - '391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3', - '748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec', - '90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b', - 'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178', - '06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b', - '28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c', - '4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817' - ); - - for ($i = 0; $i < 80; $i++) { - $k[$i] = new Math_BigInteger($k[$i], 16); - } - } - - $hash = $this->l == 48 ? $init384 : $init512; - - // Pre-processing - $length = strlen($m); - // to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128 - $m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F)); - $m[$length] = chr(0x80); - // we don't support hashing strings 512MB long - $m.= pack('N4', 0, 0, 0, $length << 3); - - // Process the message in successive 1024-bit chunks - $chunks = str_split($m, 128); - foreach ($chunks as $chunk) { - $w = array(); - for ($i = 0; $i < 16; $i++) { - $temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256); - $temp->setPrecision(64); - $w[] = $temp; - } - - // Extend the sixteen 32-bit words into eighty 32-bit words - for ($i = 16; $i < 80; $i++) { - $temp = array( - $w[$i - 15]->bitwise_rightRotate(1), - $w[$i - 15]->bitwise_rightRotate(8), - $w[$i - 15]->bitwise_rightShift(7) - ); - $s0 = $temp[0]->bitwise_xor($temp[1]); - $s0 = $s0->bitwise_xor($temp[2]); - $temp = array( - $w[$i - 2]->bitwise_rightRotate(19), - $w[$i - 2]->bitwise_rightRotate(61), - $w[$i - 2]->bitwise_rightShift(6) - ); - $s1 = $temp[0]->bitwise_xor($temp[1]); - $s1 = $s1->bitwise_xor($temp[2]); - $w[$i] = $w[$i - 16]->copy(); - $w[$i] = $w[$i]->add($s0); - $w[$i] = $w[$i]->add($w[$i - 7]); - $w[$i] = $w[$i]->add($s1); - } - - // Initialize hash value for this chunk - $a = $hash[0]->copy(); - $b = $hash[1]->copy(); - $c = $hash[2]->copy(); - $d = $hash[3]->copy(); - $e = $hash[4]->copy(); - $f = $hash[5]->copy(); - $g = $hash[6]->copy(); - $h = $hash[7]->copy(); - - // Main loop - for ($i = 0; $i < 80; $i++) { - $temp = array( - $a->bitwise_rightRotate(28), - $a->bitwise_rightRotate(34), - $a->bitwise_rightRotate(39) - ); - $s0 = $temp[0]->bitwise_xor($temp[1]); - $s0 = $s0->bitwise_xor($temp[2]); - $temp = array( - $a->bitwise_and($b), - $a->bitwise_and($c), - $b->bitwise_and($c) - ); - $maj = $temp[0]->bitwise_xor($temp[1]); - $maj = $maj->bitwise_xor($temp[2]); - $t2 = $s0->add($maj); - - $temp = array( - $e->bitwise_rightRotate(14), - $e->bitwise_rightRotate(18), - $e->bitwise_rightRotate(41) - ); - $s1 = $temp[0]->bitwise_xor($temp[1]); - $s1 = $s1->bitwise_xor($temp[2]); - $temp = array( - $e->bitwise_and($f), - $g->bitwise_and($e->bitwise_not()) - ); - $ch = $temp[0]->bitwise_xor($temp[1]); - $t1 = $h->add($s1); - $t1 = $t1->add($ch); - $t1 = $t1->add($k[$i]); - $t1 = $t1->add($w[$i]); - - $h = $g->copy(); - $g = $f->copy(); - $f = $e->copy(); - $e = $d->add($t1); - $d = $c->copy(); - $c = $b->copy(); - $b = $a->copy(); - $a = $t1->add($t2); - } - - // Add this chunk's hash to result so far - $hash = array( - $hash[0]->add($a), - $hash[1]->add($b), - $hash[2]->add($c), - $hash[3]->add($d), - $hash[4]->add($e), - $hash[5]->add($f), - $hash[6]->add($g), - $hash[7]->add($h) - ); - } - - // Produce the final hash value (big-endian) - // (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here) - $temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() . - $hash[4]->toBytes() . $hash[5]->toBytes(); - if ($this->l != 48) { - $temp.= $hash[6]->toBytes() . $hash[7]->toBytes(); - } - - return $temp; - } - - /** - * Right Rotate - * - * @access private - * @param Integer $int - * @param Integer $amt - * @see _sha256() - * @return Integer - */ - function _rightRotate($int, $amt) - { - $invamt = 32 - $amt; - $mask = (1 << $invamt) - 1; - return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask); - } - - /** - * Right Shift - * - * @access private - * @param Integer $int - * @param Integer $amt - * @see _sha256() - * @return Integer - */ - function _rightShift($int, $amt) - { - $mask = (1 << (32 - $amt)) - 1; - return ($int >> $amt) & $mask; - } - - /** - * Not - * - * @access private - * @param Integer $int - * @see _sha256() - * @return Integer - */ - function _not($int) - { - return ~$int & 0xFFFFFFFF; - } - - /** - * Add - * - * _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the - * possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster. - * - * @param String $string - * @param optional Integer $index - * @return String - * @see _sha256() - * @access private - */ - function _add() - { - static $mod; - if (!isset($mod)) { - $mod = pow(2, 32); - } - - $result = 0; - $arguments = func_get_args(); - foreach ($arguments as $argument) { - $result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument; - } - - return fmod($result, $mod); - } - - /** - * String Shift - * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @return String - * @access private - */ - function _string_shift(&$string, $index = 1) - { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; - } -} \ No newline at end of file diff --git a/library/phpsec/Crypt/RC4.php b/library/phpsec/Crypt/RC4.php deleted file mode 100644 index 6f82b2413a..0000000000 --- a/library/phpsec/Crypt/RC4.php +++ /dev/null @@ -1,493 +0,0 @@ - - * setKey('abcdefgh'); - * - * $size = 10 * 1024; - * $plaintext = ''; - * for ($i = 0; $i < $size; $i++) { - * $plaintext.= 'a'; - * } - * - * echo $rc4->decrypt($rc4->encrypt($plaintext)); - * ?> - * - * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * @category Crypt - * @package Crypt_RC4 - * @author Jim Wigginton - * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: RC4.php,v 1.8 2009/06/09 04:00:38 terrafrost Exp $ - * @link http://phpseclib.sourceforge.net - */ - -/**#@+ - * @access private - * @see Crypt_RC4::Crypt_RC4() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_RC4_MODE_INTERNAL', 1); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_RC4_MODE_MCRYPT', 2); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_RC4::_crypt() - */ -define('CRYPT_RC4_ENCRYPT', 0); -define('CRYPT_RC4_DECRYPT', 1); -/**#@-*/ - -/** - * Pure-PHP implementation of RC4. - * - * @author Jim Wigginton - * @version 0.1.0 - * @access public - * @package Crypt_RC4 - */ -class Crypt_RC4 { - /** - * The Key - * - * @see Crypt_RC4::setKey() - * @var String - * @access private - */ - var $key = "\0"; - - /** - * The Key Stream for encryption - * - * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object - * - * @see Crypt_RC4::setKey() - * @var Array - * @access private - */ - var $encryptStream = false; - - /** - * The Key Stream for decryption - * - * If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object - * - * @see Crypt_RC4::setKey() - * @var Array - * @access private - */ - var $decryptStream = false; - - /** - * The $i and $j indexes for encryption - * - * @see Crypt_RC4::_crypt() - * @var Integer - * @access private - */ - var $encryptIndex = 0; - - /** - * The $i and $j indexes for decryption - * - * @see Crypt_RC4::_crypt() - * @var Integer - * @access private - */ - var $decryptIndex = 0; - - /** - * MCrypt parameters - * - * @see Crypt_RC4::setMCrypt() - * @var Array - * @access private - */ - var $mcrypt = array('', ''); - - /** - * The Encryption Algorithm - * - * Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR. - * - * @see Crypt_RC4::Crypt_RC4() - * @var Integer - * @access private - */ - var $mode; - - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. - * - * @param optional Integer $mode - * @return Crypt_RC4 - * @access public - */ - function Crypt_RC4() - { - if ( !defined('CRYPT_RC4_MODE') ) { - switch (true) { - case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')): - // i'd check to see if rc4 was supported, by doing in_array('arcfour', mcrypt_list_algorithms('')), - // but since that can be changed after the object has been created, there doesn't seem to be - // a lot of point... - define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT); - break; - default: - define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL); - } - } - - switch ( CRYPT_RC4_MODE ) { - case CRYPT_RC4_MODE_MCRYPT: - switch (true) { - case defined('MCRYPT_ARCFOUR'): - $this->mode = MCRYPT_ARCFOUR; - break; - case defined('MCRYPT_RC4'); - $this->mode = MCRYPT_RC4; - } - } - } - - /** - * Sets the key. - * - * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will - * be used. If no key is explicitly set, it'll be assumed to be a single null byte. - * - * @access public - * @param String $key - */ - function setKey($key) - { - $this->key = $key; - - if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { - return; - } - - $keyLength = strlen($key); - $keyStream = array(); - for ($i = 0; $i < 256; $i++) { - $keyStream[$i] = $i; - } - $j = 0; - for ($i = 0; $i < 256; $i++) { - $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255; - $temp = $keyStream[$i]; - $keyStream[$i] = $keyStream[$j]; - $keyStream[$j] = $temp; - } - - $this->encryptIndex = $this->decryptIndex = array(0, 0); - $this->encryptStream = $this->decryptStream = $keyStream; - } - - /** - * Dummy function. - * - * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1]. - * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before - * calling setKey(). - * - * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol, - * the IV's are relatively easy to predict, an attack described by - * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir} - * can be used to quickly guess at the rest of the key. The following links elaborate: - * - * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009} - * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack} - * - * @param String $iv - * @see Crypt_RC4::setKey() - * @access public - */ - function setIV($iv) - { - } - - /** - * Sets MCrypt parameters. (optional) - * - * If MCrypt is being used, empty strings will be used, unless otherwise specified. - * - * @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open - * @access public - * @param optional Integer $algorithm_directory - * @param optional Integer $mode_directory - */ - function setMCrypt($algorithm_directory = '', $mode_directory = '') - { - if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { - $this->mcrypt = array($algorithm_directory, $mode_directory); - $this->_closeMCrypt(); - } - } - - /** - * Encrypts a message. - * - * @see Crypt_RC4::_crypt() - * @access public - * @param String $plaintext - */ - function encrypt($plaintext) - { - return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT); - } - - /** - * Decrypts a message. - * - * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). - * Atleast if the continuous buffer is disabled. - * - * @see Crypt_RC4::_crypt() - * @access public - * @param String $ciphertext - */ - function decrypt($ciphertext) - { - return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT); - } - - /** - * Encrypts or decrypts a message. - * - * @see Crypt_RC4::encrypt() - * @see Crypt_RC4::decrypt() - * @access private - * @param String $text - * @param Integer $mode - */ - function _crypt($text, $mode) - { - if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { - $keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream'; - - if ($this->$keyStream === false) { - $this->$keyStream = mcrypt_module_open($this->mode, $this->mcrypt[0], MCRYPT_MODE_STREAM, $this->mcrypt[1]); - mcrypt_generic_init($this->$keyStream, $this->key, ''); - } else if (!$this->continuousBuffer) { - mcrypt_generic_init($this->$keyStream, $this->key, ''); - } - $newText = mcrypt_generic($this->$keyStream, $text); - if (!$this->continuousBuffer) { - mcrypt_generic_deinit($this->$keyStream); - } - - return $newText; - } - - if ($this->encryptStream === false) { - $this->setKey($this->key); - } - - switch ($mode) { - case CRYPT_RC4_ENCRYPT: - $keyStream = $this->encryptStream; - list($i, $j) = $this->encryptIndex; - break; - case CRYPT_RC4_DECRYPT: - $keyStream = $this->decryptStream; - list($i, $j) = $this->decryptIndex; - } - - $newText = ''; - for ($k = 0; $k < strlen($text); $k++) { - $i = ($i + 1) & 255; - $j = ($j + $keyStream[$i]) & 255; - $temp = $keyStream[$i]; - $keyStream[$i] = $keyStream[$j]; - $keyStream[$j] = $temp; - $temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255]; - $newText.= chr(ord($text[$k]) ^ $temp); - } - - if ($this->continuousBuffer) { - switch ($mode) { - case CRYPT_RC4_ENCRYPT: - $this->encryptStream = $keyStream; - $this->encryptIndex = array($i, $j); - break; - case CRYPT_RC4_DECRYPT: - $this->decryptStream = $keyStream; - $this->decryptIndex = array($i, $j); - } - } - - return $newText; - } - - /** - * Treat consecutive "packets" as if they are a continuous buffer. - * - * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets - * will yield different outputs: - * - * - * echo $rc4->encrypt(substr($plaintext, 0, 8)); - * echo $rc4->encrypt(substr($plaintext, 8, 8)); - * - * - * echo $rc4->encrypt($plaintext); - * - * - * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates - * another, as demonstrated with the following: - * - * - * $rc4->encrypt(substr($plaintext, 0, 8)); - * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8))); - * - * - * echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8))); - * - * - * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different - * outputs. The reason is due to the fact that the initialization vector's change after every encryption / - * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. - * - * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each - * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that - * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), - * however, they are also less intuitive and more likely to cause you problems. - * - * @see Crypt_RC4::disableContinuousBuffer() - * @access public - */ - function enableContinuousBuffer() - { - $this->continuousBuffer = true; - } - - /** - * Treat consecutive packets as if they are a discontinuous buffer. - * - * The default behavior. - * - * @see Crypt_RC4::enableContinuousBuffer() - * @access public - */ - function disableContinuousBuffer() - { - if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) { - $this->encryptIndex = $this->decryptIndex = array(0, 0); - $this->setKey($this->key); - } - - $this->continuousBuffer = false; - } - - /** - * Dummy function. - * - * Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is - * included is so that you can switch between a block cipher and a stream cipher transparently. - * - * @see Crypt_RC4::disablePadding() - * @access public - */ - function enablePadding() - { - } - - /** - * Dummy function. - * - * @see Crypt_RC4::enablePadding() - * @access public - */ - function disablePadding() - { - } - - /** - * Class destructor. - * - * Will be called, automatically, if you're using PHP5. If you're using PHP4, call it yourself. Only really - * needs to be called if mcrypt is being used. - * - * @access public - */ - function __destruct() - { - if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) { - $this->_closeMCrypt(); - } - } - - /** - * Properly close the MCrypt objects. - * - * @access prviate - */ - function _closeMCrypt() - { - if ( $this->encryptStream !== false ) { - if ( $this->continuousBuffer ) { - mcrypt_generic_deinit($this->encryptStream); - } - - mcrypt_module_close($this->encryptStream); - - $this->encryptStream = false; - } - - if ( $this->decryptStream !== false ) { - if ( $this->continuousBuffer ) { - mcrypt_generic_deinit($this->decryptStream); - } - - mcrypt_module_close($this->decryptStream); - - $this->decryptStream = false; - } - } -} \ No newline at end of file diff --git a/library/phpsec/Crypt/RSA.php b/library/phpsec/Crypt/RSA.php deleted file mode 100644 index 1c562082b9..0000000000 --- a/library/phpsec/Crypt/RSA.php +++ /dev/null @@ -1,2119 +0,0 @@ - - * createKey()); - * - * $plaintext = 'terrafrost'; - * - * $rsa->loadKey($privatekey); - * $ciphertext = $rsa->encrypt($plaintext); - * - * $rsa->loadKey($publickey); - * echo $rsa->decrypt($ciphertext); - * ?> - * - * - * Here's an example of how to create signatures and verify signatures with this library: - * - * createKey()); - * - * $plaintext = 'terrafrost'; - * - * $rsa->loadKey($privatekey); - * $signature = $rsa->sign($plaintext); - * - * $rsa->loadKey($publickey); - * echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified'; - * ?> - * - * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * @category Crypt - * @package Crypt_RSA - * @author Jim Wigginton - * @copyright MMIX Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: RSA.php,v 1.15 2010/04/10 15:57:02 terrafrost Exp $ - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Math_BigInteger - */ -require_once('Math/BigInteger.php'); - -/** - * Include Crypt_Random - */ -require_once('Crypt/Random.php'); - -/** - * Include Crypt_Hash - */ -require_once('Crypt/Hash.php'); - -/**#@+ - * @access public - * @see Crypt_RSA::encrypt() - * @see Crypt_RSA::decrypt() - */ -/** - * Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding} - * (OAEP) for encryption / decryption. - * - * Uses sha1 by default. - * - * @see Crypt_RSA::setHash() - * @see Crypt_RSA::setMGFHash() - */ -define('CRYPT_RSA_ENCRYPTION_OAEP', 1); -/** - * Use PKCS#1 padding. - * - * Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards - * compatability with protocols (like SSH-1) written before OAEP's introduction. - */ -define('CRYPT_RSA_ENCRYPTION_PKCS1', 2); -/**#@-*/ - -/**#@+ - * @access public - * @see Crypt_RSA::sign() - * @see Crypt_RSA::verify() - * @see Crypt_RSA::setHash() - */ -/** - * Use the Probabilistic Signature Scheme for signing - * - * Uses sha1 by default. - * - * @see Crypt_RSA::setSaltLength() - * @see Crypt_RSA::setMGFHash() - */ -define('CRYPT_RSA_SIGNATURE_PSS', 1); -/** - * Use the PKCS#1 scheme by default. - * - * Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards - * compatability with protocols (like SSH-2) written before PSS's introduction. - */ -define('CRYPT_RSA_SIGNATURE_PKCS1', 2); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_RSA::createKey() - */ -/** - * ASN1 Integer - */ -define('CRYPT_RSA_ASN1_INTEGER', 2); -/** - * ASN1 Sequence (with the constucted bit set) - */ -define('CRYPT_RSA_ASN1_SEQUENCE', 48); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_RSA::Crypt_RSA() - */ -/** - * To use the pure-PHP implementation - */ -define('CRYPT_RSA_MODE_INTERNAL', 1); -/** - * To use the OpenSSL library - * - * (if enabled; otherwise, the internal implementation will be used) - */ -define('CRYPT_RSA_MODE_OPENSSL', 2); -/**#@-*/ - -/**#@+ - * @access public - * @see Crypt_RSA::createKey() - * @see Crypt_RSA::setPrivateKeyFormat() - */ -/** - * PKCS#1 formatted private key - * - * Used by OpenSSH - */ -define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0); -/**#@-*/ - -/**#@+ - * @access public - * @see Crypt_RSA::createKey() - * @see Crypt_RSA::setPublicKeyFormat() - */ -/** - * Raw public key - * - * An array containing two Math_BigInteger objects. - * - * The exponent can be indexed with any of the following: - * - * 0, e, exponent, publicExponent - * - * The modulus can be indexed with any of the following: - * - * 1, n, modulo, modulus - */ -define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 1); -/** - * PKCS#1 formatted public key - */ -define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 2); -/** - * OpenSSH formatted public key - * - * Place in $HOME/.ssh/authorized_keys - */ -define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 3); -/**#@-*/ - -/** - * Pure-PHP PKCS#1 compliant implementation of RSA. - * - * @author Jim Wigginton - * @version 0.1.0 - * @access public - * @package Crypt_RSA - */ -class Crypt_RSA { - /** - * Precomputed Zero - * - * @var Array - * @access private - */ - var $zero; - - /** - * Precomputed One - * - * @var Array - * @access private - */ - var $one; - - /** - * Private Key Format - * - * @var Integer - * @access private - */ - var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1; - - /** - * Public Key Format - * - * @var Integer - * @access public - */ - var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1; - - /** - * Modulus (ie. n) - * - * @var Math_BigInteger - * @access private - */ - var $modulus; - - /** - * Modulus length - * - * @var Math_BigInteger - * @access private - */ - var $k; - - /** - * Exponent (ie. e or d) - * - * @var Math_BigInteger - * @access private - */ - var $exponent; - - /** - * Primes for Chinese Remainder Theorem (ie. p and q) - * - * @var Array - * @access private - */ - var $primes; - - /** - * Exponents for Chinese Remainder Theorem (ie. dP and dQ) - * - * @var Array - * @access private - */ - var $exponents; - - /** - * Coefficients for Chinese Remainder Theorem (ie. qInv) - * - * @var Array - * @access private - */ - var $coefficients; - - /** - * Hash name - * - * @var String - * @access private - */ - var $hashName; - - /** - * Hash function - * - * @var Crypt_Hash - * @access private - */ - var $hash; - - /** - * Length of hash function output - * - * @var Integer - * @access private - */ - var $hLen; - - /** - * Length of salt - * - * @var Integer - * @access private - */ - var $sLen; - - /** - * Hash function for the Mask Generation Function - * - * @var Crypt_Hash - * @access private - */ - var $mgfHash; - - /** - * Length of MGF hash function output - * - * @var Integer - * @access private - */ - var $mgfHLen; - - /** - * Encryption mode - * - * @var Integer - * @access private - */ - var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP; - - /** - * Signature mode - * - * @var Integer - * @access private - */ - var $signatureMode = CRYPT_RSA_SIGNATURE_PSS; - - /** - * Public Exponent - * - * @var Mixed - * @access private - */ - var $publicExponent = false; - - /** - * Password - * - * @var String - * @access private - */ - var $password = ''; - - /** - * The constructor - * - * If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason - * Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires - * openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late. - * - * @return Crypt_RSA - * @access public - */ - function Crypt_RSA() - { - if ( !defined('CRYPT_RSA_MODE') ) { - switch (true) { - //case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>='): - // define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL); - // break; - default: - define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL); - } - } - - $this->zero = new Math_BigInteger(); - $this->one = new Math_BigInteger(1); - - $this->hash = new Crypt_Hash('sha1'); - $this->hLen = $this->hash->getLength(); - $this->hashName = 'sha1'; - $this->mgfHash = new Crypt_Hash('sha1'); - $this->mgfHLen = $this->mgfHash->getLength(); - } - - /** - * Create public / private key pair - * - * Returns an array with the following three elements: - * - 'privatekey': The private key. - * - 'publickey': The public key. - * - 'partialkey': A partially computed key (if the execution time exceeded $timeout). - * Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing. - * - * @access public - * @param optional Integer $bits - * @param optional Integer $timeout - * @param optional Math_BigInteger $p - */ - function createKey($bits = 1024, $timeout = false, $partial = array()) - { - if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL ) { - $rsa = openssl_pkey_new(array('private_key_bits' => $bits)); - openssl_pkey_export($rsa, $privatekey); - $publickey = openssl_pkey_get_details($rsa); - $publickey = $publickey['key']; - - if ($this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_PKCS1) { - $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1))); - $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1))); - } - - return array( - 'privatekey' => $privatekey, - 'publickey' => $publickey, - 'partialkey' => false - ); - } - - static $e; - if (!isset($e)) { - if (!defined('CRYPT_RSA_EXPONENT')) { - // http://en.wikipedia.org/wiki/65537_%28number%29 - define('CRYPT_RSA_EXPONENT', '65537'); - } - if (!defined('CRYPT_RSA_COMMENT')) { - define('CRYPT_RSA_COMMENT', 'phpseclib-generated-key'); - } - // per , this number ought not result in primes smaller - // than 256 bits. - if (!defined('CRYPT_RSA_SMALLEST_PRIME')) { - define('CRYPT_RSA_SMALLEST_PRIME', 4096); - } - - $e = new Math_BigInteger(CRYPT_RSA_EXPONENT); - } - - extract($this->_generateMinMax($bits)); - $absoluteMin = $min; - $temp = $bits >> 1; - if ($temp > CRYPT_RSA_SMALLEST_PRIME) { - $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME); - $temp = CRYPT_RSA_SMALLEST_PRIME; - } else { - $num_primes = 2; - } - extract($this->_generateMinMax($temp + $bits % $temp)); - $finalMax = $max; - extract($this->_generateMinMax($temp)); - - $generator = new Math_BigInteger(); - $generator->setRandomGenerator('crypt_random'); - - $n = $this->one->copy(); - if (!empty($partial)) { - extract(unserialize($partial)); - } else { - $exponents = $coefficients = $primes = array(); - $lcm = array( - 'top' => $this->one->copy(), - 'bottom' => false - ); - } - - $start = time(); - $i0 = count($primes) + 1; - - do { - for ($i = $i0; $i <= $num_primes; $i++) { - if ($timeout !== false) { - $timeout-= time() - $start; - $start = time(); - if ($timeout <= 0) { - return serialize(array( - 'privatekey' => '', - 'publickey' => '', - 'partialkey' => array( - 'primes' => $primes, - 'coefficients' => $coefficients, - 'lcm' => $lcm, - 'exponents' => $exponents - ) - )); - } - } - - if ($i == $num_primes) { - list($min, $temp) = $absoluteMin->divide($n); - if (!$temp->equals($this->zero)) { - $min = $min->add($this->one); // ie. ceil() - } - $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout); - } else { - $primes[$i] = $generator->randomPrime($min, $max, $timeout); - } - - if ($primes[$i] === false) { // if we've reached the timeout - return array( - 'privatekey' => '', - 'publickey' => '', - 'partialkey' => empty($primes) ? '' : serialize(array( - 'primes' => array_slice($primes, 0, $i - 1), - 'coefficients' => $coefficients, - 'lcm' => $lcm, - 'exponents' => $exponents - )) - ); - } - - // the first coefficient is calculated differently from the rest - // ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1]) - if ($i > 2) { - $coefficients[$i] = $n->modInverse($primes[$i]); - } - - $n = $n->multiply($primes[$i]); - - $temp = $primes[$i]->subtract($this->one); - - // textbook RSA implementations use Euler's totient function instead of the least common multiple. - // see http://en.wikipedia.org/wiki/Euler%27s_totient_function - $lcm['top'] = $lcm['top']->multiply($temp); - $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp); - - $exponents[$i] = $e->modInverse($temp); - } - - list($lcm) = $lcm['top']->divide($lcm['bottom']); - $gcd = $lcm->gcd($e); - $i0 = 1; - } while (!$gcd->equals($this->one)); - - $d = $e->modInverse($lcm); - - $coefficients[2] = $primes[2]->modInverse($primes[1]); - - // from : - // RSAPrivateKey ::= SEQUENCE { - // version Version, - // modulus INTEGER, -- n - // publicExponent INTEGER, -- e - // privateExponent INTEGER, -- d - // prime1 INTEGER, -- p - // prime2 INTEGER, -- q - // exponent1 INTEGER, -- d mod (p-1) - // exponent2 INTEGER, -- d mod (q-1) - // coefficient INTEGER, -- (inverse of q) mod p - // otherPrimeInfos OtherPrimeInfos OPTIONAL - // } - - return array( - 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients), - 'publickey' => $this->_convertPublicKey($n, $e), - 'partialkey' => false - ); - } - - /** - * Convert a private key to the appropriate format. - * - * @access private - * @see setPrivateKeyFormat() - * @param String $RSAPrivateKey - * @return String - */ - function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients) - { - $num_primes = count($primes); - $raw = array( - 'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi - 'modulus' => $n->toBytes(true), - 'publicExponent' => $e->toBytes(true), - 'privateExponent' => $d->toBytes(true), - 'prime1' => $primes[1]->toBytes(true), - 'prime2' => $primes[2]->toBytes(true), - 'exponent1' => $exponents[1]->toBytes(true), - 'exponent2' => $exponents[2]->toBytes(true), - 'coefficient' => $coefficients[2]->toBytes(true) - ); - - // if the format in question does not support multi-prime rsa and multi-prime rsa was used, - // call _convertPublicKey() instead. - switch ($this->privateKeyFormat) { - default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1 - $components = array(); - foreach ($raw as $name => $value) { - $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value); - } - - $RSAPrivateKey = implode('', $components); - - if ($num_primes > 2) { - $OtherPrimeInfos = ''; - for ($i = 3; $i <= $num_primes; $i++) { - // OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo - // - // OtherPrimeInfo ::= SEQUENCE { - // prime INTEGER, -- ri - // exponent INTEGER, -- di - // coefficient INTEGER -- ti - // } - $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true)); - $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true)); - $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true)); - $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo); - } - $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos); - } - - $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey); - - if (!empty($this->password)) { - $iv = $this->_random(8); - $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key - $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8); - if (!class_exists('Crypt_TripleDES')) { - require_once('Crypt/TripleDES.php'); - } - $des = new Crypt_TripleDES(); - $des->setKey($symkey); - $des->setIV($iv); - $iv = strtoupper(bin2hex($iv)); - $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" . - "Proc-Type: 4,ENCRYPTED\r\n" . - "DEK-Info: DES-EDE3-CBC,$iv\r\n" . - "\r\n" . - chunk_split(base64_encode($des->encrypt($RSAPrivateKey))) . - '-----END RSA PRIVATE KEY-----'; - } else { - $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" . - chunk_split(base64_encode($RSAPrivateKey)) . - '-----END RSA PRIVATE KEY-----'; - } - - return $RSAPrivateKey; - } - } - - /** - * Convert a public key to the appropriate format - * - * @access private - * @see setPublicKeyFormat() - * @param String $RSAPrivateKey - * @return String - */ - function _convertPublicKey($n, $e) - { - $modulus = $n->toBytes(true); - $publicExponent = $e->toBytes(true); - - switch ($this->publicKeyFormat) { - case CRYPT_RSA_PUBLIC_FORMAT_RAW: - return array('e' => $e->copy(), 'n' => $n->copy()); - case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: - // from : - // string "ssh-rsa" - // mpint e - // mpint n - $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus); - $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . CRYPT_RSA_COMMENT; - - return $RSAPublicKey; - default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1 - // from : - // RSAPublicKey ::= SEQUENCE { - // modulus INTEGER, -- n - // publicExponent INTEGER -- e - // } - $components = array( - 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus), - 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent) - ); - - $RSAPublicKey = pack('Ca*a*a*', - CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])), - $components['modulus'], $components['publicExponent'] - ); - - $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" . - chunk_split(base64_encode($RSAPublicKey)) . - '-----END PUBLIC KEY-----'; - - return $RSAPublicKey; - } - } - - /** - * Break a public or private key down into its constituant components - * - * @access private - * @see _convertPublicKey() - * @see _convertPrivateKey() - * @param String $key - * @param Integer $type - * @return Array - */ - function _parseKey($key, $type) - { - switch ($type) { - case CRYPT_RSA_PUBLIC_FORMAT_RAW: - if (!is_array($key)) { - return false; - } - $components = array(); - switch (true) { - case isset($key['e']): - $components['publicExponent'] = $key['e']->copy(); - break; - case isset($key['exponent']): - $components['publicExponent'] = $key['exponent']->copy(); - break; - case isset($key['publicExponent']): - $components['publicExponent'] = $key['publicExponent']->copy(); - break; - case isset($key[0]): - $components['publicExponent'] = $key[0]->copy(); - } - switch (true) { - case isset($key['n']): - $components['modulus'] = $key['n']->copy(); - break; - case isset($key['modulo']): - $components['modulus'] = $key['modulo']->copy(); - break; - case isset($key['modulus']): - $components['modulus'] = $key['modulus']->copy(); - break; - case isset($key[1]): - $components['modulus'] = $key[1]->copy(); - } - return $components; - case CRYPT_RSA_PRIVATE_FORMAT_PKCS1: - case CRYPT_RSA_PUBLIC_FORMAT_PKCS1: - /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is - "outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to - protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding - two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here: - - http://tools.ietf.org/html/rfc1421#section-4.6.1.1 - http://tools.ietf.org/html/rfc1421#section-4.6.1.3 - - DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell. - DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation - function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's - own implementation. ie. the implementation *is* the standard and any bugs that may exist in that - implementation are part of the standard, as well. - - * OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */ - if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) { - $iv = pack('H*', trim($matches[2])); - $symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key - $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8); - $ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key); - $ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false; - if ($ciphertext === false) { - $ciphertext = $key; - } - switch ($matches[1]) { - case 'DES-EDE3-CBC': - if (!class_exists('Crypt_TripleDES')) { - require_once('Crypt/TripleDES.php'); - } - $crypto = new Crypt_TripleDES(); - break; - case 'DES-CBC': - if (!class_exists('Crypt_DES')) { - require_once('Crypt/DES.php'); - } - $crypto = new Crypt_DES(); - break; - default: - return false; - } - $crypto->setKey($symkey); - $crypto->setIV($iv); - $decoded = $crypto->decrypt($ciphertext); - } else { - $decoded = preg_replace('#-.+-|[\r\n]#', '', $key); - $decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false; - } - - if ($decoded !== false) { - $key = $decoded; - } - - $components = array(); - - if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { - return false; - } - if ($this->_decodeLength($key) != strlen($key)) { - return false; - } - - $tag = ord($this->_string_shift($key)); - if ($tag == CRYPT_RSA_ASN1_SEQUENCE) { - /* intended for keys for which OpenSSL's asn1parse returns the following: - - 0:d=0 hl=4 l= 290 cons: SEQUENCE - 4:d=1 hl=2 l= 13 cons: SEQUENCE - 6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption - 17:d=2 hl=2 l= 0 prim: NULL - 19:d=1 hl=4 l= 271 prim: BIT STRING */ - $this->_string_shift($key, $this->_decodeLength($key)); - $this->_string_shift($key); // skip over the BIT STRING tag - $this->_decodeLength($key); // skip over the BIT STRING length - // "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of - // unused bits in teh final subsequent octet. The number shall be in the range zero to seven." - // -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2) - $this->_string_shift($key); - if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { - return false; - } - if ($this->_decodeLength($key) != strlen($key)) { - return false; - } - $tag = ord($this->_string_shift($key)); - } - if ($tag != CRYPT_RSA_ASN1_INTEGER) { - return false; - } - - $length = $this->_decodeLength($key); - $temp = $this->_string_shift($key, $length); - if (strlen($temp) != 1 || ord($temp) > 2) { - $components['modulus'] = new Math_BigInteger($temp, -256); - $this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER - $length = $this->_decodeLength($key); - $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256); - - return $components; - } - if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) { - return false; - } - $length = $this->_decodeLength($key); - $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256)); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256)); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), -256)); - - if (!empty($key)) { - if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { - return false; - } - $this->_decodeLength($key); - while (!empty($key)) { - if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) { - return false; - } - $this->_decodeLength($key); - $key = substr($key, 1); - $length = $this->_decodeLength($key); - $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); - $this->_string_shift($key); - $length = $this->_decodeLength($key); - $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), -256); - } - } - - return $components; - case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH: - $key = base64_decode(preg_replace('#^ssh-rsa | .+$#', '', $key)); - if ($key === false) { - return false; - } - - $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa"; - - extract(unpack('Nlength', $this->_string_shift($key, 4))); - $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256); - extract(unpack('Nlength', $this->_string_shift($key, 4))); - $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256); - - if ($cleanup && strlen($key)) { - extract(unpack('Nlength', $this->_string_shift($key, 4))); - return array( - 'modulus' => new Math_BigInteger($this->_string_shift($key, $length), -256), - 'publicExponent' => $modulus - ); - } else { - return array( - 'modulus' => $modulus, - 'publicExponent' => $publicExponent - ); - } - } - } - - /** - * Loads a public or private key - * - * Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed) - * - * @access public - * @param String $key - * @param Integer $type optional - */ - function loadKey($key, $type = CRYPT_RSA_PRIVATE_FORMAT_PKCS1) - { - $components = $this->_parseKey($key, $type); - if ($components === false) { - return false; - } - - $this->modulus = $components['modulus']; - $this->k = strlen($this->modulus->toBytes()); - $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent']; - if (isset($components['primes'])) { - $this->primes = $components['primes']; - $this->exponents = $components['exponents']; - $this->coefficients = $components['coefficients']; - $this->publicExponent = $components['publicExponent']; - } else { - $this->primes = array(); - $this->exponents = array(); - $this->coefficients = array(); - $this->publicExponent = false; - } - - return true; - } - - /** - * Sets the password - * - * Private keys can be encrypted with a password. To unset the password, pass in the empty string or false. - * Or rather, pass in $password such that empty($password) is true. - * - * @see createKey() - * @see loadKey() - * @access public - * @param String $password - */ - function setPassword($password) - { - $this->password = $password; - } - - /** - * Defines the public key - * - * Some private key formats define the public exponent and some don't. Those that don't define it are problematic when - * used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a - * message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys - * and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public - * exponent this won't work unless you manually add the public exponent. - * - * Do note that when a new key is loaded the index will be cleared. - * - * Returns true on success, false on failure - * - * @see getPublicKey() - * @access public - * @param String $key - * @param Integer $type optional - * @return Boolean - */ - function setPublicKey($key, $type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) - { - $components = $this->_parseKey($key, $type); - if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) { - return false; - } - $this->publicExponent = $components['publicExponent']; - } - - /** - * Returns the public key - * - * The public key is only returned under two circumstances - if the private key had the public key embedded within it - * or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this - * function won't return it since this library, for the most part, doesn't distinguish between public and private keys. - * - * @see getPublicKey() - * @access public - * @param String $key - * @param Integer $type optional - */ - function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1) - { - if (empty($this->modulus) || empty($this->publicExponent)) { - return false; - } - - $oldFormat = $this->publicKeyFormat; - $this->publicKeyFormat = $type; - $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent); - $this->publicKeyFormat = $oldFormat; - return $temp; - } - - /** - * Generates the smallest and largest numbers requiring $bits bits - * - * @access private - * @param Integer $bits - * @return Array - */ - function _generateMinMax($bits) - { - $bytes = $bits >> 3; - $min = str_repeat(chr(0), $bytes); - $max = str_repeat(chr(0xFF), $bytes); - $msb = $bits & 7; - if ($msb) { - $min = chr(1 << ($msb - 1)) . $min; - $max = chr((1 << $msb) - 1) . $max; - } else { - $min[0] = chr(0x80); - } - - return array( - 'min' => new Math_BigInteger($min, 256), - 'max' => new Math_BigInteger($max, 256) - ); - } - - /** - * DER-decode the length - * - * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See - * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 § 8.1.3} for more information. - * - * @access private - * @param String $string - * @return Integer - */ - function _decodeLength(&$string) - { - $length = ord($this->_string_shift($string)); - if ( $length & 0x80 ) { // definite length, long form - $length&= 0x7F; - $temp = $this->_string_shift($string, $length); - list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4)); - } - return $length; - } - - /** - * DER-encode the length - * - * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See - * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 § 8.1.3} for more information. - * - * @access private - * @param Integer $length - * @return String - */ - function _encodeLength($length) - { - if ($length <= 0x7F) { - return chr($length); - } - - $temp = ltrim(pack('N', $length), chr(0)); - return pack('Ca*', 0x80 | strlen($temp), $temp); - } - - /** - * String Shift - * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @return String - * @access private - */ - function _string_shift(&$string, $index = 1) - { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; - } - - /** - * Determines the private key format - * - * @see createKey() - * @access public - * @param Integer $format - */ - function setPrivateKeyFormat($format) - { - $this->privateKeyFormat = $format; - } - - /** - * Determines the public key format - * - * @see createKey() - * @access public - * @param Integer $format - */ - function setPublicKeyFormat($format) - { - $this->publicKeyFormat = $format; - } - - /** - * Determines which hashing function should be used - * - * Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and - * decryption. If $hash isn't supported, sha1 is used. - * - * @access public - * @param String $hash - */ - function setHash($hash) - { - // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example. - switch ($hash) { - case 'md2': - case 'md5': - case 'sha1': - case 'sha256': - case 'sha384': - case 'sha512': - $this->hash = new Crypt_Hash($hash); - $this->hashName = $hash; - break; - default: - $this->hash = new Crypt_Hash('sha1'); - $this->hashName = 'sha1'; - } - $this->hLen = $this->hash->getLength(); - } - - /** - * Determines which hashing function should be used for the mask generation function - * - * The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's - * best if Hash and MGFHash are set to the same thing this is not a requirement. - * - * @access public - * @param String $hash - */ - function setMGFHash($hash) - { - // Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example. - switch ($hash) { - case 'md2': - case 'md5': - case 'sha1': - case 'sha256': - case 'sha384': - case 'sha512': - $this->mgfHash = new Crypt_Hash($hash); - break; - default: - $this->mgfHash = new Crypt_Hash('sha1'); - } - $this->mgfHLen = $this->mgfHash->getLength(); - } - - /** - * Determines the salt length - * - * To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}: - * - * Typical salt lengths in octets are hLen (the length of the output - * of the hash function Hash) and 0. - * - * @access public - * @param Integer $format - */ - function setSaltLength($sLen) - { - $this->sLen = $sLen; - } - - /** - * Generates a random string x bytes long - * - * @access public - * @param Integer $bytes - * @param optional Integer $nonzero - * @return String - */ - function _random($bytes, $nonzero = false) - { - $temp = ''; - if ($nonzero) { - for ($i = 0; $i < $bytes; $i++) { - $temp.= chr(crypt_random(1, 255)); - } - } else { - $ints = ($bytes + 1) >> 2; - for ($i = 0; $i < $ints; $i++) { - $temp.= pack('N', crypt_random()); - } - $temp = substr($temp, 0, $bytes); - } - return $temp; - } - - /** - * Integer-to-Octet-String primitive - * - * See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}. - * - * @access private - * @param Math_BigInteger $x - * @param Integer $xLen - * @return String - */ - function _i2osp($x, $xLen) - { - $x = $x->toBytes(); - if (strlen($x) > $xLen) { - user_error('Integer too large', E_USER_NOTICE); - return false; - } - return str_pad($x, $xLen, chr(0), STR_PAD_LEFT); - } - - /** - * Octet-String-to-Integer primitive - * - * See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}. - * - * @access private - * @param String $x - * @return Math_BigInteger - */ - function _os2ip($x) - { - return new Math_BigInteger($x, 256); - } - - /** - * Exponentiate with or without Chinese Remainder Theorem - * - * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}. - * - * @access private - * @param Math_BigInteger $x - * @return Math_BigInteger - */ - function _exponentiate($x) - { - if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) { - return $x->modPow($this->exponent, $this->modulus); - } - - $num_primes = count($this->primes); - - if (defined('CRYPT_RSA_DISABLE_BLINDING')) { - $m_i = array( - 1 => $x->modPow($this->exponents[1], $this->primes[1]), - 2 => $x->modPow($this->exponents[2], $this->primes[2]) - ); - $h = $m_i[1]->subtract($m_i[2]); - $h = $h->multiply($this->coefficients[2]); - list(, $h) = $h->divide($this->primes[1]); - $m = $m_i[2]->add($h->multiply($this->primes[2])); - - $r = $this->primes[1]; - for ($i = 3; $i <= $num_primes; $i++) { - $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]); - - $r = $r->multiply($this->primes[$i - 1]); - - $h = $m_i->subtract($m); - $h = $h->multiply($this->coefficients[$i]); - list(, $h) = $h->divide($this->primes[$i]); - - $m = $m->add($r->multiply($h)); - } - } else { - $smallest = $this->primes[1]; - for ($i = 2; $i <= $num_primes; $i++) { - if ($smallest->compare($this->primes[$i]) > 0) { - $smallest = $this->primes[$i]; - } - } - - $one = new Math_BigInteger(1); - $one->setRandomGenerator('crypt_random'); - - $r = $one->random($one, $smallest->subtract($one)); - - $m_i = array( - 1 => $this->_blind($x, $r, 1), - 2 => $this->_blind($x, $r, 2) - ); - $h = $m_i[1]->subtract($m_i[2]); - $h = $h->multiply($this->coefficients[2]); - list(, $h) = $h->divide($this->primes[1]); - $m = $m_i[2]->add($h->multiply($this->primes[2])); - - $r = $this->primes[1]; - for ($i = 3; $i <= $num_primes; $i++) { - $m_i = $this->_blind($x, $r, $i); - - $r = $r->multiply($this->primes[$i - 1]); - - $h = $m_i->subtract($m); - $h = $h->multiply($this->coefficients[$i]); - list(, $h) = $h->divide($this->primes[$i]); - - $m = $m->add($r->multiply($h)); - } - } - - return $m; - } - - /** - * Performs RSA Blinding - * - * Protects against timing attacks by employing RSA Blinding. - * Returns $x->modPow($this->exponents[$i], $this->primes[$i]) - * - * @access private - * @param Math_BigInteger $x - * @param Math_BigInteger $r - * @param Integer $i - * @return Math_BigInteger - */ - function _blind($x, $r, $i) - { - $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i])); - - $x = $x->modPow($this->exponents[$i], $this->primes[$i]); - - $r = $r->modInverse($this->primes[$i]); - $x = $x->multiply($r); - list(, $x) = $x->divide($this->primes[$i]); - - return $x; - } - - /** - * RSAEP - * - * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}. - * - * @access private - * @param Math_BigInteger $m - * @return Math_BigInteger - */ - function _rsaep($m) - { - if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { - user_error('Message representative out of range', E_USER_NOTICE); - return false; - } - return $this->_exponentiate($m); - } - - /** - * RSADP - * - * See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}. - * - * @access private - * @param Math_BigInteger $c - * @return Math_BigInteger - */ - function _rsadp($c) - { - if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) { - user_error('Ciphertext representative out of range', E_USER_NOTICE); - return false; - } - return $this->_exponentiate($c); - } - - /** - * RSASP1 - * - * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}. - * - * @access private - * @param Math_BigInteger $m - * @return Math_BigInteger - */ - function _rsasp1($m) - { - if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) { - user_error('Message representative out of range', E_USER_NOTICE); - return false; - } - return $this->_exponentiate($m); - } - - /** - * RSAVP1 - * - * See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}. - * - * @access private - * @param Math_BigInteger $s - * @return Math_BigInteger - */ - function _rsavp1($s) - { - if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) { - user_error('Signature representative out of range', E_USER_NOTICE); - return false; - } - return $this->_exponentiate($s); - } - - /** - * MGF1 - * - * See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}. - * - * @access private - * @param String $mgfSeed - * @param Integer $mgfLen - * @return String - */ - function _mgf1($mgfSeed, $maskLen) - { - // if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output. - - $t = ''; - $count = ceil($maskLen / $this->mgfHLen); - for ($i = 0; $i < $count; $i++) { - $c = pack('N', $i); - $t.= $this->mgfHash->hash($mgfSeed . $c); - } - - return substr($t, 0, $maskLen); - } - - /** - * RSAES-OAEP-ENCRYPT - * - * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and - * {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}. - * - * @access private - * @param String $m - * @param String $l - * @return String - */ - function _rsaes_oaep_encrypt($m, $l = '') - { - $mLen = strlen($m); - - // Length checking - - // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error - // be output. - - if ($mLen > $this->k - 2 * $this->hLen - 2) { - user_error('Message too long', E_USER_NOTICE); - return false; - } - - // EME-OAEP encoding - - $lHash = $this->hash->hash($l); - $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2); - $db = $lHash . $ps . chr(1) . $m; - $seed = $this->_random($this->hLen); - $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); - $maskedDB = $db ^ $dbMask; - $seedMask = $this->_mgf1($maskedDB, $this->hLen); - $maskedSeed = $seed ^ $seedMask; - $em = chr(0) . $maskedSeed . $maskedDB; - - // RSA encryption - - $m = $this->_os2ip($em); - $c = $this->_rsaep($m); - $c = $this->_i2osp($c, $this->k); - - // Output the ciphertext C - - return $c; - } - - /** - * RSAES-OAEP-DECRYPT - * - * See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error - * messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2: - * - * Note. Care must be taken to ensure that an opponent cannot - * distinguish the different error conditions in Step 3.g, whether by - * error message or timing, or, more generally, learn partial - * information about the encoded message EM. Otherwise an opponent may - * be able to obtain useful information about the decryption of the - * ciphertext C, leading to a chosen-ciphertext attack such as the one - * observed by Manger [36]. - * - * As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}: - * - * Both the encryption and the decryption operations of RSAES-OAEP take - * the value of a label L as input. In this version of PKCS #1, L is - * the empty string; other uses of the label are outside the scope of - * this document. - * - * @access private - * @param String $c - * @param String $l - * @return String - */ - function _rsaes_oaep_decrypt($c, $l = '') - { - // Length checking - - // if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error - // be output. - - if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) { - user_error('Decryption error', E_USER_NOTICE); - return false; - } - - // RSA decryption - - $c = $this->_os2ip($c); - $m = $this->_rsadp($c); - if ($m === false) { - user_error('Decryption error', E_USER_NOTICE); - return false; - } - $em = $this->_i2osp($m, $this->k); - - // EME-OAEP decoding - - $lHash = $this->hash->hash($l); - $y = ord($em[0]); - $maskedSeed = substr($em, 1, $this->hLen); - $maskedDB = substr($em, $this->hLen + 1); - $seedMask = $this->_mgf1($maskedDB, $this->hLen); - $seed = $maskedSeed ^ $seedMask; - $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1); - $db = $maskedDB ^ $dbMask; - $lHash2 = substr($db, 0, $this->hLen); - $m = substr($db, $this->hLen); - if ($lHash != $lHash2) { - user_error('Decryption error', E_USER_NOTICE); - return false; - } - $m = ltrim($m, chr(0)); - if (ord($m[0]) != 1) { - user_error('Decryption error', E_USER_NOTICE); - return false; - } - - // Output the message M - - return substr($m, 1); - } - - /** - * RSAES-PKCS1-V1_5-ENCRYPT - * - * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}. - * - * @access private - * @param String $m - * @return String - */ - function _rsaes_pkcs1_v1_5_encrypt($m) - { - $mLen = strlen($m); - - // Length checking - - if ($mLen > $this->k - 11) { - user_error('Message too long', E_USER_NOTICE); - return false; - } - - // EME-PKCS1-v1_5 encoding - - $ps = $this->_random($this->k - $mLen - 3, true); - $em = chr(0) . chr(2) . $ps . chr(0) . $m; - - // RSA encryption - $m = $this->_os2ip($em); - $c = $this->_rsaep($m); - $c = $this->_i2osp($c, $this->k); - - // Output the ciphertext C - - return $c; - } - - /** - * RSAES-PKCS1-V1_5-DECRYPT - * - * See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}. - * - * For compatability purposes, this function departs slightly from the description given in RFC3447. - * The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the - * private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the - * public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed - * to be 2 regardless of which key is used. for compatability purposes, we'll just check to make sure the - * second byte is 2 or less. If it is, we'll accept the decrypted string as valid. - * - * As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt - * with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but - * not private key encrypted ciphertext's. - * - * @access private - * @param String $c - * @return String - */ - function _rsaes_pkcs1_v1_5_decrypt($c) - { - // Length checking - - if (strlen($c) != $this->k) { // or if k < 11 - user_error('Decryption error', E_USER_NOTICE); - return false; - } - - // RSA decryption - - $c = $this->_os2ip($c); - $m = $this->_rsadp($c); - if ($m === false) { - user_error('Decryption error', E_USER_NOTICE); - return false; - } - $em = $this->_i2osp($m, $this->k); - - // EME-PKCS1-v1_5 decoding - - if (ord($em[0]) != 0 || ord($em[1]) > 2) { - user_error('Decryption error', E_USER_NOTICE); - return false; - } - - $ps = substr($em, 2, strpos($em, chr(0), 2) - 2); - $m = substr($em, strlen($ps) + 3); - - if (strlen($ps) < 8) { - user_error('Decryption error', E_USER_NOTICE); - return false; - } - - // Output M - - return $m; - } - - /** - * EMSA-PSS-ENCODE - * - * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}. - * - * @access private - * @param String $m - * @param Integer $emBits - */ - function _emsa_pss_encode($m, $emBits) - { - // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error - // be output. - - $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8) - $sLen = $this->sLen == false ? $this->hLen : $this->sLen; - - $mHash = $this->hash->hash($m); - if ($emLen < $this->hLen + $sLen + 2) { - user_error('Encoding error', E_USER_NOTICE); - return false; - } - - $salt = $this->_random($sLen); - $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; - $h = $this->hash->hash($m2); - $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2); - $db = $ps . chr(1) . $salt; - $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); - $maskedDB = $db ^ $dbMask; - $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0]; - $em = $maskedDB . $h . chr(0xBC); - - return $em; - } - - /** - * EMSA-PSS-VERIFY - * - * See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}. - * - * @access private - * @param String $m - * @param String $em - * @param Integer $emBits - * @return String - */ - function _emsa_pss_verify($m, $em, $emBits) - { - // if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error - // be output. - - $emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8); - $sLen = $this->sLen == false ? $this->hLen : $this->sLen; - - $mHash = $this->hash->hash($m); - if ($emLen < $this->hLen + $sLen + 2) { - return false; - } - - if ($em[strlen($em) - 1] != chr(0xBC)) { - return false; - } - - $maskedDB = substr($em, 0, $em - $this->hLen - 1); - $h = substr($em, $em - $this->hLen - 1, $this->hLen); - $temp = chr(0xFF << ($emBits & 7)); - if ((~$maskedDB[0] & $temp) != $temp) { - return false; - } - $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1); - $db = $maskedDB ^ $dbMask; - $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0]; - $temp = $emLen - $this->hLen - $sLen - 2; - if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) { - return false; - } - $salt = substr($db, $temp + 1); // should be $sLen long - $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt; - $h2 = $this->hash->hash($m2); - return $h == $h2; - } - - /** - * RSASSA-PSS-SIGN - * - * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}. - * - * @access private - * @param String $m - * @return String - */ - function _rsassa_pss_sign($m) - { - // EMSA-PSS encoding - - $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1); - - // RSA signature - - $m = $this->_os2ip($em); - $s = $this->_rsasp1($m); - $s = $this->_i2osp($s, $this->k); - - // Output the signature S - - return $s; - } - - /** - * RSASSA-PSS-VERIFY - * - * See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}. - * - * @access private - * @param String $m - * @param String $s - * @return String - */ - function _rsassa_pss_verify($m, $s) - { - // Length checking - - if (strlen($s) != $this->k) { - user_error('Invalid signature', E_USER_NOTICE); - return false; - } - - // RSA verification - - $modBits = 8 * $this->k; - - $s2 = $this->_os2ip($s); - $m2 = $this->_rsavp1($s2); - if ($m2 === false) { - user_error('Invalid signature', E_USER_NOTICE); - return false; - } - $em = $this->_i2osp($m2, $modBits >> 3); - if ($em === false) { - user_error('Invalid signature', E_USER_NOTICE); - return false; - } - - // EMSA-PSS verification - - return $this->_emsa_pss_verify($m, $em, $modBits - 1); - } - - /** - * EMSA-PKCS1-V1_5-ENCODE - * - * See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}. - * - * @access private - * @param String $m - * @param Integer $emLen - * @return String - */ - function _emsa_pkcs1_v1_5_encode($m, $emLen) - { - $h = $this->hash->hash($m); - if ($h === false) { - return false; - } - - // see http://tools.ietf.org/html/rfc3447#page-43 - switch ($this->hashName) { - case 'md2': - $t = pack('H*', '3020300c06082a864886f70d020205000410'); - break; - case 'md5': - $t = pack('H*', '3020300c06082a864886f70d020505000410'); - break; - case 'sha1': - $t = pack('H*', '3021300906052b0e03021a05000414'); - break; - case 'sha256': - $t = pack('H*', '3031300d060960864801650304020105000420'); - break; - case 'sha384': - $t = pack('H*', '3041300d060960864801650304020205000430'); - break; - case 'sha512': - $t = pack('H*', '3051300d060960864801650304020305000440'); - } - $t.= $h; - $tLen = strlen($t); - - if ($emLen < $tLen + 11) { - user_error('Intended encoded message length too short', E_USER_NOTICE); - return false; - } - - $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3); - - $em = "\0\1$ps\0$t"; - - return $em; - } - - /** - * RSASSA-PKCS1-V1_5-SIGN - * - * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}. - * - * @access private - * @param String $m - * @return String - */ - function _rsassa_pkcs1_v1_5_sign($m) - { - // EMSA-PKCS1-v1_5 encoding - - $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); - if ($em === false) { - user_error('RSA modulus too short', E_USER_NOTICE); - return false; - } - - // RSA signature - - $m = $this->_os2ip($em); - $s = $this->_rsasp1($m); - $s = $this->_i2osp($s, $this->k); - - // Output the signature S - - return $s; - } - - /** - * RSASSA-PKCS1-V1_5-VERIFY - * - * See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}. - * - * @access private - * @param String $m - * @return String - */ - function _rsassa_pkcs1_v1_5_verify($m, $s) - { - // Length checking - - if (strlen($s) != $this->k) { - user_error('Invalid signature', E_USER_NOTICE); - return false; - } - - // RSA verification - - $s = $this->_os2ip($s); - $m2 = $this->_rsavp1($s); - if ($m2 === false) { - user_error('Invalid signature', E_USER_NOTICE); - return false; - } - $em = $this->_i2osp($m2, $this->k); - if ($em === false) { - user_error('Invalid signature', E_USER_NOTICE); - return false; - } - - // EMSA-PKCS1-v1_5 encoding - - $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k); - if ($em2 === false) { - user_error('RSA modulus too short', E_USER_NOTICE); - return false; - } - - // Compare - - return $em === $em2; - } - - /** - * Set Encryption Mode - * - * Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1. - * - * @access public - * @param Integer $mode - */ - function setEncryptionMode($mode) - { - $this->encryptionMode = $mode; - } - - /** - * Set Signature Mode - * - * Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1 - * - * @access public - * @param Integer $mode - */ - function setSignatureMode($mode) - { - $this->signatureMode = $mode; - } - - /** - * Encryption - * - * Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be. - * If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will - * be concatenated together. - * - * @see decrypt() - * @access public - * @param String $plaintext - * @return String - */ - function encrypt($plaintext) - { - switch ($this->encryptionMode) { - case CRYPT_RSA_ENCRYPTION_PKCS1: - $length = $this->k - 11; - if ($length <= 0) { - return false; - } - - $plaintext = str_split($plaintext, $length); - $ciphertext = ''; - foreach ($plaintext as $m) { - $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m); - } - return $ciphertext; - //case CRYPT_RSA_ENCRYPTION_OAEP: - default: - $length = $this->k - 2 * $this->hLen - 2; - if ($length <= 0) { - return false; - } - - $plaintext = str_split($plaintext, $length); - $ciphertext = ''; - foreach ($plaintext as $m) { - $ciphertext.= $this->_rsaes_oaep_encrypt($m); - } - return $ciphertext; - } - } - - /** - * Decryption - * - * @see encrypt() - * @access public - * @param String $plaintext - * @return String - */ - function decrypt($ciphertext) - { - if ($this->k <= 0) { - return false; - } - - $ciphertext = str_split($ciphertext, $this->k); - $plaintext = ''; - - switch ($this->encryptionMode) { - case CRYPT_RSA_ENCRYPTION_PKCS1: - $decrypt = '_rsaes_pkcs1_v1_5_decrypt'; - break; - //case CRYPT_RSA_ENCRYPTION_OAEP: - default: - $decrypt = '_rsaes_oaep_decrypt'; - } - - foreach ($ciphertext as $c) { - $temp = $this->$decrypt($c); - if ($temp === false) { - return false; - } - $plaintext.= $temp; - } - - return $plaintext; - } - - /** - * Create a signature - * - * @see verify() - * @access public - * @param String $message - * @return String - */ - function sign($message) - { - if (empty($this->modulus) || empty($this->exponent)) { - return false; - } - - switch ($this->signatureMode) { - case CRYPT_RSA_SIGNATURE_PKCS1: - return $this->_rsassa_pkcs1_v1_5_sign($message); - //case CRYPT_RSA_SIGNATURE_PSS: - default: - return $this->_rsassa_pss_sign($message); - } - } - - /** - * Verifies a signature - * - * @see sign() - * @access public - * @param String $message - * @param String $signature - * @return Boolean - */ - function verify($message, $signature) - { - if (empty($this->modulus) || empty($this->exponent)) { - return false; - } - - switch ($this->signatureMode) { - case CRYPT_RSA_SIGNATURE_PKCS1: - return $this->_rsassa_pkcs1_v1_5_verify($message, $signature); - //case CRYPT_RSA_SIGNATURE_PSS: - default: - return $this->_rsassa_pss_verify($message, $signature); - } - } -} \ No newline at end of file diff --git a/library/phpsec/Crypt/Random.php b/library/phpsec/Crypt/Random.php deleted file mode 100644 index a91c4d3c5a..0000000000 --- a/library/phpsec/Crypt/Random.php +++ /dev/null @@ -1,130 +0,0 @@ - - * - * - * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * @category Crypt - * @package Crypt_Random - * @author Jim Wigginton - * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: Random.php,v 1.9 2010/04/24 06:40:48 terrafrost Exp $ - * @link http://phpseclib.sourceforge.net - */ - -/** - * Generate a random value. - * - * On 32-bit machines, the largest distance that can exist between $min and $max is 2**31. - * If $min and $max are farther apart than that then the last ($max - range) numbers. - * - * Depending on how this is being used, it may be worth while to write a replacement. For example, - * a PHP-based web app that stores its data in an SQL database can collect more entropy than this function - * can. - * - * @param optional Integer $min - * @param optional Integer $max - * @return Integer - * @access public - */ -function crypt_random($min = 0, $max = 0x7FFFFFFF) -{ - if ($min == $max) { - return $min; - } - - // see http://en.wikipedia.org/wiki//dev/random - // if open_basedir is enabled file_exists() will ouput an "open_basedir restriction in effect" warning, - // so we suppress it. - if (@file_exists('/dev/urandom')) { - static $fp; - if (!$fp) { - $fp = fopen('/dev/urandom', 'rb'); - } - extract(unpack('Nrandom', fread($fp, 4))); - - // say $min = 0 and $max = 3. if we didn't do abs() then we could have stuff like this: - // -4 % 3 + 0 = -1, even though -1 < $min - return abs($random) % ($max - $min) + $min; - } - - /* Prior to PHP 4.2.0, mt_srand() had to be called before mt_rand() could be called. - Prior to PHP 5.2.6, mt_rand()'s automatic seeding was subpar, as elaborated here: - - http://www.suspekt.org/2008/08/17/mt_srand-and-not-so-random-numbers/ - - The seeding routine is pretty much ripped from PHP's own internal GENERATE_SEED() macro: - - http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3_2/ext/standard/php_rand.h?view=markup */ - if (version_compare(PHP_VERSION, '5.2.5', '<=')) { - static $seeded; - if (!isset($seeded)) { - $seeded = true; - mt_srand(fmod(time() * getmypid(), 0x7FFFFFFF) ^ fmod(1000000 * lcg_value(), 0x7FFFFFFF)); - } - } - - static $crypto; - - // The CSPRNG's Yarrow and Fortuna periodically reseed. This function can be reseeded by hitting F5 - // in the browser and reloading the page. - - if (!isset($crypto)) { - $key = $iv = ''; - for ($i = 0; $i < 8; $i++) { - $key.= pack('n', mt_rand(0, 0xFFFF)); - $iv .= pack('n', mt_rand(0, 0xFFFF)); - } - switch (true) { - case class_exists('Crypt_AES'): - $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR); - break; - case class_exists('Crypt_TripleDES'): - $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); - break; - case class_exists('Crypt_DES'): - $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR); - break; - case class_exists('Crypt_RC4'): - $crypto = new Crypt_RC4(); - break; - default: - extract(unpack('Nrandom', pack('H*', sha1(mt_rand(0, 0x7FFFFFFF))))); - return abs($random) % ($max - $min) + $min; - } - $crypto->setKey($key); - $crypto->setIV($iv); - $crypto->enableContinuousBuffer(); - } - - extract(unpack('Nrandom', $crypto->encrypt("\0\0\0\0"))); - return abs($random) % ($max - $min) + $min; -} -?> \ No newline at end of file diff --git a/library/phpsec/Crypt/Rijndael.php b/library/phpsec/Crypt/Rijndael.php deleted file mode 100644 index f141f3762c..0000000000 --- a/library/phpsec/Crypt/Rijndael.php +++ /dev/null @@ -1,1242 +0,0 @@ - - * setKey('abcdefghijklmnop'); - * - * $size = 10 * 1024; - * $plaintext = ''; - * for ($i = 0; $i < $size; $i++) { - * $plaintext.= 'a'; - * } - * - * echo $rijndael->decrypt($rijndael->encrypt($plaintext)); - * ?> - * - * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * @category Crypt - * @package Crypt_Rijndael - * @author Jim Wigginton - * @copyright MMVIII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: Rijndael.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $ - * @link http://phpseclib.sourceforge.net - */ - -/**#@+ - * @access public - * @see Crypt_Rijndael::encrypt() - * @see Crypt_Rijndael::decrypt() - */ -/** - * Encrypt / decrypt using the Counter mode. - * - * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 - */ -define('CRYPT_RIJNDAEL_MODE_CTR', -1); -/** - * Encrypt / decrypt using the Electronic Code Book mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 - */ -define('CRYPT_RIJNDAEL_MODE_ECB', 1); -/** - * Encrypt / decrypt using the Code Book Chaining mode. - * - * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 - */ -define('CRYPT_RIJNDAEL_MODE_CBC', 2); -/**#@-*/ - -/**#@+ - * @access private - * @see Crypt_Rijndael::Crypt_Rijndael() - */ -/** - * Toggles the internal implementation - */ -define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1); -/** - * Toggles the mcrypt implementation - */ -define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2); -/**#@-*/ - -/** - * Pure-PHP implementation of Rijndael. - * - * @author Jim Wigginton - * @version 0.1.0 - * @access public - * @package Crypt_Rijndael - */ -class Crypt_Rijndael { - /** - * The Encryption Mode - * - * @see Crypt_Rijndael::Crypt_Rijndael() - * @var Integer - * @access private - */ - var $mode; - - /** - * The Key - * - * @see Crypt_Rijndael::setKey() - * @var String - * @access private - */ - var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; - - /** - * The Initialization Vector - * - * @see Crypt_Rijndael::setIV() - * @var String - * @access private - */ - var $iv = ''; - - /** - * A "sliding" Initialization Vector - * - * @see Crypt_Rijndael::enableContinuousBuffer() - * @var String - * @access private - */ - var $encryptIV = ''; - - /** - * A "sliding" Initialization Vector - * - * @see Crypt_Rijndael::enableContinuousBuffer() - * @var String - * @access private - */ - var $decryptIV = ''; - - /** - * Continuous Buffer status - * - * @see Crypt_Rijndael::enableContinuousBuffer() - * @var Boolean - * @access private - */ - var $continuousBuffer = false; - - /** - * Padding status - * - * @see Crypt_Rijndael::enablePadding() - * @var Boolean - * @access private - */ - var $padding = true; - - /** - * Does the key schedule need to be (re)calculated? - * - * @see setKey() - * @see setBlockLength() - * @see setKeyLength() - * @var Boolean - * @access private - */ - var $changed = true; - - /** - * Has the key length explicitly been set or should it be derived from the key, itself? - * - * @see setKeyLength() - * @var Boolean - * @access private - */ - var $explicit_key_length = false; - - /** - * The Key Schedule - * - * @see _setup() - * @var Array - * @access private - */ - var $w; - - /** - * The Inverse Key Schedule - * - * @see _setup() - * @var Array - * @access private - */ - var $dw; - - /** - * The Block Length - * - * @see setBlockLength() - * @var Integer - * @access private - * @internal The max value is 32, the min value is 16. All valid values are multiples of 4. Exists in conjunction with - * $Nb because we need this value and not $Nb to pad strings appropriately. - */ - var $block_size = 16; - - /** - * The Block Length divided by 32 - * - * @see setBlockLength() - * @var Integer - * @access private - * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size - * because the encryption / decryption / key schedule creation requires this number and not $block_size. We could - * derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu - * of that, we'll just precompute it once. - * - */ - var $Nb = 4; - - /** - * The Key Length - * - * @see setKeyLength() - * @var Integer - * @access private - * @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $key_size - * because the encryption / decryption / key schedule creation requires this number and not $key_size. We could - * derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu - * of that, we'll just precompute it once. - */ - var $key_size = 16; - - /** - * The Key Length divided by 32 - * - * @see setKeyLength() - * @var Integer - * @access private - * @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4 - */ - var $Nk = 4; - - /** - * The Number of Rounds - * - * @var Integer - * @access private - * @internal The max value is 14, the min value is 10. - */ - var $Nr; - - /** - * Shift offsets - * - * @var Array - * @access private - */ - var $c; - - /** - * Precomputed mixColumns table - * - * @see Crypt_Rijndael() - * @var Array - * @access private - */ - var $t0; - - /** - * Precomputed mixColumns table - * - * @see Crypt_Rijndael() - * @var Array - * @access private - */ - var $t1; - - /** - * Precomputed mixColumns table - * - * @see Crypt_Rijndael() - * @var Array - * @access private - */ - var $t2; - - /** - * Precomputed mixColumns table - * - * @see Crypt_Rijndael() - * @var Array - * @access private - */ - var $t3; - - /** - * Precomputed invMixColumns table - * - * @see Crypt_Rijndael() - * @var Array - * @access private - */ - var $dt0; - - /** - * Precomputed invMixColumns table - * - * @see Crypt_Rijndael() - * @var Array - * @access private - */ - var $dt1; - - /** - * Precomputed invMixColumns table - * - * @see Crypt_Rijndael() - * @var Array - * @access private - */ - var $dt2; - - /** - * Precomputed invMixColumns table - * - * @see Crypt_Rijndael() - * @var Array - * @access private - */ - var $dt3; - - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be - * CRYPT_RIJNDAEL_MODE_ECB or CRYPT_RIJNDAEL_MODE_CBC. If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used. - * - * @param optional Integer $mode - * @return Crypt_Rijndael - * @access public - */ - function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC) - { - switch ($mode) { - case CRYPT_RIJNDAEL_MODE_ECB: - case CRYPT_RIJNDAEL_MODE_CBC: - case CRYPT_RIJNDAEL_MODE_CTR: - $this->mode = $mode; - break; - default: - $this->mode = CRYPT_RIJNDAEL_MODE_CBC; - } - - $t3 = &$this->t3; - $t2 = &$this->t2; - $t1 = &$this->t1; - $t0 = &$this->t0; - - $dt3 = &$this->dt3; - $dt2 = &$this->dt2; - $dt1 = &$this->dt1; - $dt0 = &$this->dt0; - - // according to (section 5.2.1), - // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so - // those are the names we'll use. - $t3 = array( - 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, - 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, - 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, - 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, - 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, - 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, - 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, - 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, - 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, - 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, - 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, - 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, - 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, - 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, - 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, - 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, - 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, - 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, - 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, - 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, - 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, - 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, - 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, - 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, - 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, - 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, - 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, - 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, - 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, - 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, - 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, - 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C - ); - - $dt3 = array( - 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, - 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, - 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, - 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, - 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, - 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, - 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, - 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, - 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, - 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, - 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, - 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, - 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, - 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, - 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, - 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, - 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, - 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, - 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, - 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, - 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, - 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, - 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, - 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, - 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, - 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, - 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, - 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, - 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, - 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, - 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, - 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 - ); - - for ($i = 0; $i < 256; $i++) { - $t2[$i << 8] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF); - $t1[$i << 16] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF); - $t0[$i << 24] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF); - - $dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF); - $dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF); - $dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF); - } - } - - /** - * Sets the key. - * - * Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and - * whose length is a multiple of 32. If the key is less than 256-bits and the key length isn't set, we round the length - * up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the - * excess bits. - * - * If the key is not explicitly set, it'll be assumed to be all null bytes. - * - * @access public - * @param String $key - */ - function setKey($key) - { - $this->key = $key; - $this->changed = true; - } - - /** - * Sets the initialization vector. (optional) - * - * SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed - * to be all zero's. - * - * @access public - * @param String $iv - */ - function setIV($iv) - { - $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size), $this->block_size, chr(0));; - } - - /** - * Sets the key length - * - * Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to - * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount. - * - * @access public - * @param Integer $length - */ - function setKeyLength($length) - { - $length >>= 5; - if ($length > 8) { - $length = 8; - } else if ($length < 4) { - $length = 4; - } - $this->Nk = $length; - $this->key_size = $length << 2; - - $this->explicit_key_length = true; - $this->changed = true; - } - - /** - * Sets the block length - * - * Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to - * 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount. - * - * @access public - * @param Integer $length - */ - function setBlockLength($length) - { - $length >>= 5; - if ($length > 8) { - $length = 8; - } else if ($length < 4) { - $length = 4; - } - $this->Nb = $length; - $this->block_size = $length << 2; - $this->changed = true; - } - - /** - * Generate CTR XOR encryption key - * - * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the - * plaintext / ciphertext in CTR mode. - * - * @see Crypt_Rijndael::decrypt() - * @see Crypt_Rijndael::encrypt() - * @access public - * @param Integer $length - * @param String $iv - */ - function _generate_xor($length, &$iv) - { - $xor = ''; - $block_size = $this->block_size; - $num_blocks = floor(($length + ($block_size - 1)) / $block_size); - for ($i = 0; $i < $num_blocks; $i++) { - $xor.= $iv; - for ($j = 4; $j <= $block_size; $j+=4) { - $temp = substr($iv, -$j, 4); - switch ($temp) { - case "\xFF\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); - break; - case "\x7F\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); - break 2; - default: - extract(unpack('Ncount', $temp)); - $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); - break 2; - } - } - } - - return $xor; - } - - /** - * Encrypts a message. - * - * $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other Rjindael - * implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's - * necessary are discussed in the following - * URL: - * - * {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html} - * - * An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does. - * strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that - * length. - * - * @see Crypt_Rijndael::decrypt() - * @access public - * @param String $plaintext - */ - function encrypt($plaintext) - { - $this->_setup(); - if ($this->mode != CRYPT_RIJNDAEL_MODE_CTR) { - $plaintext = $this->_pad($plaintext); - } - - $block_size = $this->block_size; - $ciphertext = ''; - switch ($this->mode) { - case CRYPT_RIJNDAEL_MODE_ECB: - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size)); - } - break; - case CRYPT_RIJNDAEL_MODE_CBC: - $xor = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $block = substr($plaintext, $i, $block_size); - $block = $this->_encryptBlock($block ^ $xor); - $xor = $block; - $ciphertext.= $block; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - } - break; - case CRYPT_RIJNDAEL_MODE_CTR: - $xor = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=$block_size) { - $block = substr($plaintext, $i, $block_size); - $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); - $ciphertext.= $block ^ $key; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - } - } - - return $ciphertext; - } - - /** - * Decrypts a message. - * - * If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until - * it is. - * - * @see Crypt_Rijndael::encrypt() - * @access public - * @param String $ciphertext - */ - function decrypt($ciphertext) - { - $this->_setup(); - - if ($this->mode != CRYPT_RIJNDAEL_MODE_CTR) { - // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : - // "The data is padded with "\0" to make sure the length of the data is n * blocksize." - $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + $this->block_size - 1) % $this->block_size, chr(0)); - } - - $block_size = $this->block_size; - $plaintext = ''; - switch ($this->mode) { - case CRYPT_RIJNDAEL_MODE_ECB: - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size)); - } - break; - case CRYPT_RIJNDAEL_MODE_CBC: - $xor = $this->decryptIV; - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $block = substr($ciphertext, $i, $block_size); - $plaintext.= $this->_decryptBlock($block) ^ $xor; - $xor = $block; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - } - break; - case CRYPT_RIJNDAEL_MODE_CTR: - $xor = $this->decryptIV; - for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) { - $block = substr($ciphertext, $i, $block_size); - $key = $this->_encryptBlock($this->_generate_xor($block_size, $xor)); - $plaintext.= $block ^ $key; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - } - } - - return $this->mode != CRYPT_RIJNDAEL_MODE_CTR ? $this->_unpad($plaintext) : $plaintext; - } - - /** - * Encrypts a block - * - * @access private - * @param String $in - * @return String - */ - function _encryptBlock($in) - { - $state = array(); - $words = unpack('N*word', $in); - - $w = $this->w; - $t0 = $this->t0; - $t1 = $this->t1; - $t2 = $this->t2; - $t3 = $this->t3; - $Nb = $this->Nb; - $Nr = $this->Nr; - $c = $this->c; - - // addRoundKey - $i = 0; - foreach ($words as $word) { - $state[] = $word ^ $w[0][$i++]; - } - - // fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components - - // subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding - // Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf. - // Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization. - // Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1], - // equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well. - - // [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf - $temp = array(); - for ($round = 1; $round < $Nr; $round++) { - $i = 0; // $c[0] == 0 - $j = $c[1]; - $k = $c[2]; - $l = $c[3]; - - while ($i < $this->Nb) { - $temp[$i] = $t0[$state[$i] & 0xFF000000] ^ - $t1[$state[$j] & 0x00FF0000] ^ - $t2[$state[$k] & 0x0000FF00] ^ - $t3[$state[$l] & 0x000000FF] ^ - $w[$round][$i]; - $i++; - $j = ($j + 1) % $Nb; - $k = ($k + 1) % $Nb; - $l = ($l + 1) % $Nb; - } - - for ($i = 0; $i < $Nb; $i++) { - $state[$i] = $temp[$i]; - } - } - - // subWord - for ($i = 0; $i < $Nb; $i++) { - $state[$i] = $this->_subWord($state[$i]); - } - - // shiftRows + addRoundKey - $i = 0; // $c[0] == 0 - $j = $c[1]; - $k = $c[2]; - $l = $c[3]; - while ($i < $this->Nb) { - $temp[$i] = ($state[$i] & 0xFF000000) ^ - ($state[$j] & 0x00FF0000) ^ - ($state[$k] & 0x0000FF00) ^ - ($state[$l] & 0x000000FF) ^ - $w[$Nr][$i]; - $i++; - $j = ($j + 1) % $Nb; - $k = ($k + 1) % $Nb; - $l = ($l + 1) % $Nb; - } - $state = $temp; - - array_unshift($state, 'N*'); - - return call_user_func_array('pack', $state); - } - - /** - * Decrypts a block - * - * @access private - * @param String $in - * @return String - */ - function _decryptBlock($in) - { - $state = array(); - $words = unpack('N*word', $in); - - $num_states = count($state); - $dw = $this->dw; - $dt0 = $this->dt0; - $dt1 = $this->dt1; - $dt2 = $this->dt2; - $dt3 = $this->dt3; - $Nb = $this->Nb; - $Nr = $this->Nr; - $c = $this->c; - - // addRoundKey - $i = 0; - foreach ($words as $word) { - $state[] = $word ^ $dw[$Nr][$i++]; - } - - $temp = array(); - for ($round = $Nr - 1; $round > 0; $round--) { - $i = 0; // $c[0] == 0 - $j = $Nb - $c[1]; - $k = $Nb - $c[2]; - $l = $Nb - $c[3]; - - while ($i < $Nb) { - $temp[$i] = $dt0[$state[$i] & 0xFF000000] ^ - $dt1[$state[$j] & 0x00FF0000] ^ - $dt2[$state[$k] & 0x0000FF00] ^ - $dt3[$state[$l] & 0x000000FF] ^ - $dw[$round][$i]; - $i++; - $j = ($j + 1) % $Nb; - $k = ($k + 1) % $Nb; - $l = ($l + 1) % $Nb; - } - - for ($i = 0; $i < $Nb; $i++) { - $state[$i] = $temp[$i]; - } - } - - // invShiftRows + invSubWord + addRoundKey - $i = 0; // $c[0] == 0 - $j = $Nb - $c[1]; - $k = $Nb - $c[2]; - $l = $Nb - $c[3]; - - while ($i < $Nb) { - $temp[$i] = $dw[0][$i] ^ - $this->_invSubWord(($state[$i] & 0xFF000000) | - ($state[$j] & 0x00FF0000) | - ($state[$k] & 0x0000FF00) | - ($state[$l] & 0x000000FF)); - $i++; - $j = ($j + 1) % $Nb; - $k = ($k + 1) % $Nb; - $l = ($l + 1) % $Nb; - } - - $state = $temp; - - array_unshift($state, 'N*'); - - return call_user_func_array('pack', $state); - } - - /** - * Setup Rijndael - * - * Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key - * key schedule. - * - * @access private - */ - function _setup() - { - // Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field. - // See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse - static $rcon = array(0, - 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, - 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, - 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000, - 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000, - 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000, - 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000 - ); - - if (!$this->changed) { - return; - } - - if (!$this->explicit_key_length) { - // we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits - $length = strlen($this->key) >> 2; - if ($length > 8) { - $length = 8; - } else if ($length < 4) { - $length = 4; - } - $this->Nk = $length; - $this->key_size = $length << 2; - } - - $this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0)); - $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, chr(0)); - - // see Rijndael-ammended.pdf#page=44 - $this->Nr = max($this->Nk, $this->Nb) + 6; - - // shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44, - // "Table 8: Shift offsets in Shiftrow for the alternative block lengths" - // shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14, - // "Table 2: Shift offsets for different block lengths" - switch ($this->Nb) { - case 4: - case 5: - case 6: - $this->c = array(0, 1, 2, 3); - break; - case 7: - $this->c = array(0, 1, 2, 4); - break; - case 8: - $this->c = array(0, 1, 3, 4); - } - - $key = $this->key; - - $w = array_values(unpack('N*words', $key)); - - $length = $this->Nb * ($this->Nr + 1); - for ($i = $this->Nk; $i < $length; $i++) { - $temp = $w[$i - 1]; - if ($i % $this->Nk == 0) { - // according to , "the size of an integer is platform-dependent". - // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine, - // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and' - // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is. - $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord - $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk]; - } else if ($this->Nk > 6 && $i % $this->Nk == 4) { - $temp = $this->_subWord($temp); - } - $w[$i] = $w[$i - $this->Nk] ^ $temp; - } - - // convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns - // and generate the inverse key schedule. more specifically, - // according to (section 5.3.3), - // "The key expansion for the Inverse Cipher is defined as follows: - // 1. Apply the Key Expansion. - // 2. Apply InvMixColumn to all Round Keys except the first and the last one." - // also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher" - $temp = array(); - for ($i = $row = $col = 0; $i < $length; $i++, $col++) { - if ($col == $this->Nb) { - if ($row == 0) { - $this->dw[0] = $this->w[0]; - } else { - // subWord + invMixColumn + invSubWord = invMixColumn - $j = 0; - while ($j < $this->Nb) { - $dw = $this->_subWord($this->w[$row][$j]); - $temp[$j] = $this->dt0[$dw & 0xFF000000] ^ - $this->dt1[$dw & 0x00FF0000] ^ - $this->dt2[$dw & 0x0000FF00] ^ - $this->dt3[$dw & 0x000000FF]; - $j++; - } - $this->dw[$row] = $temp; - } - - $col = 0; - $row++; - } - $this->w[$row][$col] = $w[$i]; - } - - $this->dw[$row] = $this->w[$row]; - - $this->changed = false; - } - - /** - * Performs S-Box substitutions - * - * @access private - */ - function _subWord($word) - { - static $sbox0, $sbox1, $sbox2, $sbox3; - - if (empty($sbox0)) { - $sbox0 = array( - 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, - 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, - 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, - 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, - 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, - 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, - 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, - 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, - 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, - 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, - 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, - 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, - 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, - 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, - 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, - 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 - ); - - $sbox1 = array(); - $sbox2 = array(); - $sbox3 = array(); - - for ($i = 0; $i < 256; $i++) { - $sbox1[$i << 8] = $sbox0[$i] << 8; - $sbox2[$i << 16] = $sbox0[$i] << 16; - $sbox3[$i << 24] = $sbox0[$i] << 24; - } - } - - return $sbox0[$word & 0x000000FF] | - $sbox1[$word & 0x0000FF00] | - $sbox2[$word & 0x00FF0000] | - $sbox3[$word & 0xFF000000]; - } - - /** - * Performs inverse S-Box substitutions - * - * @access private - */ - function _invSubWord($word) - { - static $sbox0, $sbox1, $sbox2, $sbox3; - - if (empty($sbox0)) { - $sbox0 = array( - 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, - 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, - 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, - 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, - 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, - 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, - 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, - 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, - 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, - 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, - 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, - 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, - 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, - 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, - 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D - ); - - $sbox1 = array(); - $sbox2 = array(); - $sbox3 = array(); - - for ($i = 0; $i < 256; $i++) { - $sbox1[$i << 8] = $sbox0[$i] << 8; - $sbox2[$i << 16] = $sbox0[$i] << 16; - $sbox3[$i << 24] = $sbox0[$i] << 24; - } - } - - return $sbox0[$word & 0x000000FF] | - $sbox1[$word & 0x0000FF00] | - $sbox2[$word & 0x00FF0000] | - $sbox3[$word & 0xFF000000]; - } - - /** - * Pad "packets". - * - * Rijndael works by encrypting between sixteen and thirty-two bytes at a time, provided that number is also a multiple - * of four. If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to - * pad the input so that it is of the proper length. - * - * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH, - * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping - * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is - * transmitted separately) - * - * @see Crypt_Rijndael::disablePadding() - * @access public - */ - function enablePadding() - { - $this->padding = true; - } - - /** - * Do not pad packets. - * - * @see Crypt_Rijndael::enablePadding() - * @access public - */ - function disablePadding() - { - $this->padding = false; - } - - /** - * Pads a string - * - * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize. - * $block_size - (strlen($text) % $block_size) bytes are added, each of which is equal to - * chr($block_size - (strlen($text) % $block_size) - * - * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless - * and padding will, hence forth, be enabled. - * - * @see Crypt_Rijndael::_unpad() - * @access private - */ - function _pad($text) - { - $length = strlen($text); - - if (!$this->padding) { - if ($length % $this->block_size == 0) { - return $text; - } else { - user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})", E_USER_NOTICE); - $this->padding = true; - } - } - - $pad = $this->block_size - ($length % $this->block_size); - - return str_pad($text, $length + $pad, chr($pad)); - } - - /** - * Unpads a string. - * - * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong - * and false will be returned. - * - * @see Crypt_Rijndael::_pad() - * @access private - */ - function _unpad($text) - { - if (!$this->padding) { - return $text; - } - - $length = ord($text[strlen($text) - 1]); - - if (!$length || $length > $this->block_size) { - return false; - } - - return substr($text, 0, -$length); - } - - /** - * Treat consecutive "packets" as if they are a continuous buffer. - * - * Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets - * will yield different outputs: - * - * - * echo $rijndael->encrypt(substr($plaintext, 0, 16)); - * echo $rijndael->encrypt(substr($plaintext, 16, 16)); - * - * - * echo $rijndael->encrypt($plaintext); - * - * - * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates - * another, as demonstrated with the following: - * - * - * $rijndael->encrypt(substr($plaintext, 0, 16)); - * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16))); - * - * - * echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16))); - * - * - * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different - * outputs. The reason is due to the fact that the initialization vector's change after every encryption / - * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. - * - * Put another way, when the continuous buffer is enabled, the state of the Crypt_Rijndael() object changes after each - * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that - * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), - * however, they are also less intuitive and more likely to cause you problems. - * - * @see Crypt_Rijndael::disableContinuousBuffer() - * @access public - */ - function enableContinuousBuffer() - { - $this->continuousBuffer = true; - } - - /** - * Treat consecutive packets as if they are a discontinuous buffer. - * - * The default behavior. - * - * @see Crypt_Rijndael::enableContinuousBuffer() - * @access public - */ - function disableContinuousBuffer() - { - $this->continuousBuffer = false; - $this->encryptIV = $this->iv; - $this->decryptIV = $this->iv; - } - - /** - * String Shift - * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @return String - * @access private - */ - function _string_shift(&$string, $index = 1) - { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; - } -} - -// vim: ts=4:sw=4:et: -// vim6: fdl=1: \ No newline at end of file diff --git a/library/phpsec/Crypt/TripleDES.php b/library/phpsec/Crypt/TripleDES.php deleted file mode 100644 index 4d0dbbca0a..0000000000 --- a/library/phpsec/Crypt/TripleDES.php +++ /dev/null @@ -1,690 +0,0 @@ - - * setKey('abcdefghijklmnopqrstuvwx'); - * - * $size = 10 * 1024; - * $plaintext = ''; - * for ($i = 0; $i < $size; $i++) { - * $plaintext.= 'a'; - * } - * - * echo $des->decrypt($des->encrypt($plaintext)); - * ?> - * - * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * @category Crypt - * @package Crypt_TripleDES - * @author Jim Wigginton - * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: TripleDES.php,v 1.13 2010/02/26 03:40:25 terrafrost Exp $ - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Crypt_DES - */ -require_once 'DES.php'; - -/** - * Encrypt / decrypt using inner chaining - * - * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3). - */ -define('CRYPT_DES_MODE_3CBC', 3); - -/** - * Encrypt / decrypt using outer chaining - * - * Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC. - */ -define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC); - -/** - * Pure-PHP implementation of Triple DES. - * - * @author Jim Wigginton - * @version 0.1.0 - * @access public - * @package Crypt_TerraDES - */ -class Crypt_TripleDES { - /** - * The Three Keys - * - * @see Crypt_TripleDES::setKey() - * @var String - * @access private - */ - var $key = "\0\0\0\0\0\0\0\0"; - - /** - * The Encryption Mode - * - * @see Crypt_TripleDES::Crypt_TripleDES() - * @var Integer - * @access private - */ - var $mode = CRYPT_DES_MODE_CBC; - - /** - * Continuous Buffer status - * - * @see Crypt_TripleDES::enableContinuousBuffer() - * @var Boolean - * @access private - */ - var $continuousBuffer = false; - - /** - * Padding status - * - * @see Crypt_TripleDES::enablePadding() - * @var Boolean - * @access private - */ - var $padding = true; - - /** - * The Initialization Vector - * - * @see Crypt_TripleDES::setIV() - * @var String - * @access private - */ - var $iv = "\0\0\0\0\0\0\0\0"; - - /** - * A "sliding" Initialization Vector - * - * @see Crypt_TripleDES::enableContinuousBuffer() - * @var String - * @access private - */ - var $encryptIV = "\0\0\0\0\0\0\0\0"; - - /** - * A "sliding" Initialization Vector - * - * @see Crypt_TripleDES::enableContinuousBuffer() - * @var String - * @access private - */ - var $decryptIV = "\0\0\0\0\0\0\0\0"; - - /** - * The Crypt_DES objects - * - * @var Array - * @access private - */ - var $des; - - /** - * mcrypt resource for encryption - * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. - * - * @see Crypt_AES::encrypt() - * @var String - * @access private - */ - var $enmcrypt; - - /** - * mcrypt resource for decryption - * - * The mcrypt resource can be recreated every time something needs to be created or it can be created just once. - * Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode. - * - * @see Crypt_AES::decrypt() - * @var String - * @access private - */ - var $demcrypt; - - /** - * Does the (en|de)mcrypt resource need to be (re)initialized? - * - * @see setKey() - * @see setIV() - * @var Boolean - * @access private - */ - var $changed = true; - - /** - * Default Constructor. - * - * Determines whether or not the mcrypt extension should be used. $mode should only, at present, be - * CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used. - * - * @param optional Integer $mode - * @return Crypt_TripleDES - * @access public - */ - function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC) - { - if ( !defined('CRYPT_DES_MODE') ) { - switch (true) { - case extension_loaded('mcrypt'): - // i'd check to see if des was supported, by doing in_array('des', mcrypt_list_algorithms('')), - // but since that can be changed after the object has been created, there doesn't seem to be - // a lot of point... - define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT); - break; - default: - define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL); - } - } - - if ( $mode == CRYPT_DES_MODE_3CBC ) { - $this->mode = CRYPT_DES_MODE_3CBC; - $this->des = array( - new Crypt_DES(CRYPT_DES_MODE_CBC), - new Crypt_DES(CRYPT_DES_MODE_CBC), - new Crypt_DES(CRYPT_DES_MODE_CBC) - ); - - // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects - $this->des[0]->disablePadding(); - $this->des[1]->disablePadding(); - $this->des[2]->disablePadding(); - - return; - } - - switch ( CRYPT_DES_MODE ) { - case CRYPT_DES_MODE_MCRYPT: - switch ($mode) { - case CRYPT_DES_MODE_ECB: - $this->mode = MCRYPT_MODE_ECB; - break; - case CRYPT_DES_MODE_CTR: - $this->mode = 'ctr'; - break; - case CRYPT_DES_MODE_CBC: - default: - $this->mode = MCRYPT_MODE_CBC; - } - - break; - default: - $this->des = array( - new Crypt_DES(CRYPT_DES_MODE_ECB), - new Crypt_DES(CRYPT_DES_MODE_ECB), - new Crypt_DES(CRYPT_DES_MODE_ECB) - ); - - // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects - $this->des[0]->disablePadding(); - $this->des[1]->disablePadding(); - $this->des[2]->disablePadding(); - - switch ($mode) { - case CRYPT_DES_MODE_ECB: - case CRYPT_DES_MODE_CTR: - case CRYPT_DES_MODE_CBC: - $this->mode = $mode; - break; - default: - $this->mode = CRYPT_DES_MODE_CBC; - } - } - } - - /** - * Sets the key. - * - * Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or - * 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate. - * - * DES also requires that every eighth bit be a parity bit, however, we'll ignore that. - * - * If the key is not explicitly set, it'll be assumed to be all zero's. - * - * @access public - * @param String $key - */ - function setKey($key) - { - $length = strlen($key); - if ($length > 8) { - $key = str_pad($key, 24, chr(0)); - // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this: - // http://php.net/function.mcrypt-encrypt#47973 - //$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24); - } - $this->key = $key; - switch (true) { - case CRYPT_DES_MODE == CRYPT_DES_MODE_INTERNAL: - case $this->mode == CRYPT_DES_MODE_3CBC: - $this->des[0]->setKey(substr($key, 0, 8)); - $this->des[1]->setKey(substr($key, 8, 8)); - $this->des[2]->setKey(substr($key, 16, 8)); - } - $this->changed = true; - } - - /** - * Sets the initialization vector. (optional) - * - * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed - * to be all zero's. - * - * @access public - * @param String $iv - */ - function setIV($iv) - { - $this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0)); - if ($this->mode == CRYPT_DES_MODE_3CBC) { - $this->des[0]->setIV($iv); - $this->des[1]->setIV($iv); - $this->des[2]->setIV($iv); - } - $this->changed = true; - } - - /** - * Generate CTR XOR encryption key - * - * Encrypt the output of this and XOR it against the ciphertext / plaintext to get the - * plaintext / ciphertext in CTR mode. - * - * @see Crypt_DES::decrypt() - * @see Crypt_DES::encrypt() - * @access public - * @param Integer $length - * @param String $iv - */ - function _generate_xor($length, &$iv) - { - $xor = ''; - $num_blocks = ($length + 7) >> 3; - for ($i = 0; $i < $num_blocks; $i++) { - $xor.= $iv; - for ($j = 4; $j <= 8; $j+=4) { - $temp = substr($iv, -$j, 4); - switch ($temp) { - case "\xFF\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4); - break; - case "\x7F\xFF\xFF\xFF": - $iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4); - break 2; - default: - extract(unpack('Ncount', $temp)); - $iv = substr_replace($iv, pack('N', $count + 1), -$j, 4); - break 2; - } - } - } - - return $xor; - } - - /** - * Encrypts a message. - * - * @access public - * @param String $plaintext - */ - function encrypt($plaintext) - { - if ($this->mode != CRYPT_DES_MODE_CTR && $this->mode != 'ctr') { - $plaintext = $this->_pad($plaintext); - } - - // if the key is smaller then 8, do what we'd normally do - if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) { - $ciphertext = $this->des[2]->encrypt($this->des[1]->decrypt($this->des[0]->encrypt($plaintext))); - - return $ciphertext; - } - - if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { - if ($this->changed) { - if (!isset($this->enmcrypt)) { - $this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, ''); - } - mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); - $this->changed = false; - } - - $ciphertext = mcrypt_generic($this->enmcrypt, $plaintext); - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV); - } - - return $ciphertext; - } - - if (strlen($this->key) <= 8) { - $this->des[0]->mode = $this->mode; - - return $this->des[0]->encrypt($plaintext); - } - - // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : - // "The data is padded with "\0" to make sure the length of the data is n * blocksize." - $plaintext = str_pad($plaintext, ceil(strlen($plaintext) / 8) * 8, chr(0)); - - $des = $this->des; - - $ciphertext = ''; - switch ($this->mode) { - case CRYPT_DES_MODE_ECB: - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $block = substr($plaintext, $i, 8); - $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); - $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT); - $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT); - $ciphertext.= $block; - } - break; - case CRYPT_DES_MODE_CBC: - $xor = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $block = substr($plaintext, $i, 8) ^ $xor; - $block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT); - $block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT); - $block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT); - $xor = $block; - $ciphertext.= $block; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - } - break; - case CRYPT_DES_MODE_CTR: - $xor = $this->encryptIV; - for ($i = 0; $i < strlen($plaintext); $i+=8) { - $key = $this->_generate_xor(8, $xor); - $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); - $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); - $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); - $block = substr($plaintext, $i, 8); - $ciphertext.= $block ^ $key; - } - if ($this->continuousBuffer) { - $this->encryptIV = $xor; - } - } - - return $ciphertext; - } - - /** - * Decrypts a message. - * - * @access public - * @param String $ciphertext - */ - function decrypt($ciphertext) - { - if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) { - $plaintext = $this->des[0]->decrypt($this->des[1]->encrypt($this->des[2]->decrypt($ciphertext))); - - return $this->_unpad($plaintext); - } - - // we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic : - // "The data is padded with "\0" to make sure the length of the data is n * blocksize." - $ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0)); - - if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) { - if ($this->changed) { - if (!isset($this->demcrypt)) { - $this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, ''); - } - mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); - $this->changed = false; - } - - $plaintext = mdecrypt_generic($this->demcrypt, $ciphertext); - - if (!$this->continuousBuffer) { - mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV); - } - - return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext; - } - - if (strlen($this->key) <= 8) { - $this->des[0]->mode = $this->mode; - - return $this->_unpad($this->des[0]->decrypt($plaintext)); - } - - $des = $this->des; - - $plaintext = ''; - switch ($this->mode) { - case CRYPT_DES_MODE_ECB: - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $block = substr($ciphertext, $i, 8); - $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT); - $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT); - $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT); - $plaintext.= $block; - } - break; - case CRYPT_DES_MODE_CBC: - $xor = $this->decryptIV; - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $orig = $block = substr($ciphertext, $i, 8); - $block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT); - $block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT); - $block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT); - $plaintext.= $block ^ $xor; - $xor = $orig; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - } - break; - case CRYPT_DES_MODE_CTR: - $xor = $this->decryptIV; - for ($i = 0; $i < strlen($ciphertext); $i+=8) { - $key = $this->_generate_xor(8, $xor); - $key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT); - $key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT); - $key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT); - $block = substr($ciphertext, $i, 8); - $plaintext.= $block ^ $key; - } - if ($this->continuousBuffer) { - $this->decryptIV = $xor; - } - } - - return $this->mode != CRYPT_DES_MODE_CTR ? $this->_unpad($plaintext) : $plaintext; - } - - /** - * Treat consecutive "packets" as if they are a continuous buffer. - * - * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets - * will yield different outputs: - * - * - * echo $des->encrypt(substr($plaintext, 0, 8)); - * echo $des->encrypt(substr($plaintext, 8, 8)); - * - * - * echo $des->encrypt($plaintext); - * - * - * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates - * another, as demonstrated with the following: - * - * - * $des->encrypt(substr($plaintext, 0, 8)); - * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); - * - * - * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); - * - * - * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different - * outputs. The reason is due to the fact that the initialization vector's change after every encryption / - * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. - * - * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each - * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that - * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), - * however, they are also less intuitive and more likely to cause you problems. - * - * @see Crypt_TripleDES::disableContinuousBuffer() - * @access public - */ - function enableContinuousBuffer() - { - $this->continuousBuffer = true; - if ($this->mode == CRYPT_DES_MODE_3CBC) { - $this->des[0]->enableContinuousBuffer(); - $this->des[1]->enableContinuousBuffer(); - $this->des[2]->enableContinuousBuffer(); - } - } - - /** - * Treat consecutive packets as if they are a discontinuous buffer. - * - * The default behavior. - * - * @see Crypt_TripleDES::enableContinuousBuffer() - * @access public - */ - function disableContinuousBuffer() - { - $this->continuousBuffer = false; - $this->encryptIV = $this->iv; - $this->decryptIV = $this->iv; - - if ($this->mode == CRYPT_DES_MODE_3CBC) { - $this->des[0]->disableContinuousBuffer(); - $this->des[1]->disableContinuousBuffer(); - $this->des[2]->disableContinuousBuffer(); - } - } - - /** - * Pad "packets". - * - * DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not - * a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight. - * - * Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1, - * where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping - * away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is - * transmitted separately) - * - * @see Crypt_TripleDES::disablePadding() - * @access public - */ - function enablePadding() - { - $this->padding = true; - } - - /** - * Do not pad packets. - * - * @see Crypt_TripleDES::enablePadding() - * @access public - */ - function disablePadding() - { - $this->padding = false; - } - - /** - * Pads a string - * - * Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8). - * 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7) - * - * If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless - * and padding will, hence forth, be enabled. - * - * @see Crypt_TripleDES::_unpad() - * @access private - */ - function _pad($text) - { - $length = strlen($text); - - if (!$this->padding) { - if (($length & 7) == 0) { - return $text; - } else { - user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE); - $this->padding = true; - } - } - - $pad = 8 - ($length & 7); - return str_pad($text, $length + $pad, chr($pad)); - } - - /** - * Unpads a string - * - * If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong - * and false will be returned. - * - * @see Crypt_TripleDES::_pad() - * @access private - */ - function _unpad($text) - { - if (!$this->padding) { - return $text; - } - - $length = ord($text[strlen($text) - 1]); - - if (!$length || $length > 8) { - return false; - } - - return substr($text, 0, -$length); - } -} - -// vim: ts=4:sw=4:et: -// vim6: fdl=1: \ No newline at end of file diff --git a/library/phpsec/Math/BigInteger.php b/library/phpsec/Math/BigInteger.php deleted file mode 100644 index 5b3a4fc8b9..0000000000 --- a/library/phpsec/Math/BigInteger.php +++ /dev/null @@ -1,3545 +0,0 @@ -> and << cannot be used, nor can the modulo operator %, - * which only supports integers. Although this fact will slow this library down, the fact that such a high - * base is being used should more than compensate. - * - * When PHP version 6 is officially released, we'll be able to use 64-bit integers. This should, once again, - * allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition / - * subtraction). - * - * Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie. - * (new Math_BigInteger(pow(2, 26)))->value = array(0, 1) - * - * Useful resources are as follows: - * - * - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)} - * - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)} - * - Java's BigInteger classes. See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip - * - * Here's an example of how to use this library: - * - * add($b); - * - * echo $c->toString(); // outputs 5 - * ?> - * - * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * @category Math - * @package Math_BigInteger - * @author Jim Wigginton - * @copyright MMVI Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: BigInteger.php,v 1.33 2010/03/22 22:32:03 terrafrost Exp $ - * @link http://pear.php.net/package/Math_BigInteger - */ - -/**#@+ - * Reduction constants - * - * @access private - * @see Math_BigInteger::_reduce() - */ -/** - * @see Math_BigInteger::_montgomery() - * @see Math_BigInteger::_prepMontgomery() - */ -define('MATH_BIGINTEGER_MONTGOMERY', 0); -/** - * @see Math_BigInteger::_barrett() - */ -define('MATH_BIGINTEGER_BARRETT', 1); -/** - * @see Math_BigInteger::_mod2() - */ -define('MATH_BIGINTEGER_POWEROF2', 2); -/** - * @see Math_BigInteger::_remainder() - */ -define('MATH_BIGINTEGER_CLASSIC', 3); -/** - * @see Math_BigInteger::__clone() - */ -define('MATH_BIGINTEGER_NONE', 4); -/**#@-*/ - -/**#@+ - * Array constants - * - * Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and - * multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them. - * - * @access private - */ -/** - * $result[MATH_BIGINTEGER_VALUE] contains the value. - */ -define('MATH_BIGINTEGER_VALUE', 0); -/** - * $result[MATH_BIGINTEGER_SIGN] contains the sign. - */ -define('MATH_BIGINTEGER_SIGN', 1); -/**#@-*/ - -/**#@+ - * @access private - * @see Math_BigInteger::_montgomery() - * @see Math_BigInteger::_barrett() - */ -/** - * Cache constants - * - * $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid. - */ -define('MATH_BIGINTEGER_VARIABLE', 0); -/** - * $cache[MATH_BIGINTEGER_DATA] contains the cached data. - */ -define('MATH_BIGINTEGER_DATA', 1); -/**#@-*/ - -/**#@+ - * Mode constants. - * - * @access private - * @see Math_BigInteger::Math_BigInteger() - */ -/** - * To use the pure-PHP implementation - */ -define('MATH_BIGINTEGER_MODE_INTERNAL', 1); -/** - * To use the BCMath library - * - * (if enabled; otherwise, the internal implementation will be used) - */ -define('MATH_BIGINTEGER_MODE_BCMATH', 2); -/** - * To use the GMP library - * - * (if present; otherwise, either the BCMath or the internal implementation will be used) - */ -define('MATH_BIGINTEGER_MODE_GMP', 3); -/**#@-*/ - -/** - * The largest digit that may be used in addition / subtraction - * - * (we do pow(2, 52) instead of using 4503599627370496, directly, because some PHP installations - * will truncate 4503599627370496) - * - * @access private - */ -define('MATH_BIGINTEGER_MAX_DIGIT52', pow(2, 52)); - -/** - * Karatsuba Cutoff - * - * At what point do we switch between Karatsuba multiplication and schoolbook long multiplication? - * - * @access private - */ -define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25); - -/** - * Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256 - * numbers. - * - * @author Jim Wigginton - * @version 1.0.0RC4 - * @access public - * @package Math_BigInteger - */ -class Math_BigInteger { - /** - * Holds the BigInteger's value. - * - * @var Array - * @access private - */ - var $value; - - /** - * Holds the BigInteger's magnitude. - * - * @var Boolean - * @access private - */ - var $is_negative = false; - - /** - * Random number generator function - * - * @see setRandomGenerator() - * @access private - */ - var $generator = 'mt_rand'; - - /** - * Precision - * - * @see setPrecision() - * @access private - */ - var $precision = -1; - - /** - * Precision Bitmask - * - * @see setPrecision() - * @access private - */ - var $bitmask = false; - - /** - * Mode independant value used for serialization. - * - * If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for - * a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value, - * however, $this->hex is only calculated when $this->__sleep() is called. - * - * @see __sleep() - * @see __wakeup() - * @var String - * @access private - */ - var $hex; - - /** - * Converts base-2, base-10, base-16, and binary strings (eg. base-256) to BigIntegers. - * - * If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using - * two's compliment. The sole exception to this is -10, which is treated the same as 10 is. - * - * Here's an example: - * - * toString(); // outputs 50 - * ?> - * - * - * @param optional $x base-10 number or base-$base number if $base set. - * @param optional integer $base - * @return Math_BigInteger - * @access public - */ - function Math_BigInteger($x = 0, $base = 10) - { - if ( !defined('MATH_BIGINTEGER_MODE') ) { - switch (true) { - case extension_loaded('gmp'): - define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP); - break; - case extension_loaded('bcmath'): - define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH); - break; - default: - define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL); - } - } - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - if (is_resource($x) && get_resource_type($x) == 'GMP integer') { - $this->value = $x; - return; - } - $this->value = gmp_init(0); - break; - case MATH_BIGINTEGER_MODE_BCMATH: - $this->value = '0'; - break; - default: - $this->value = array(); - } - - if (empty($x)) { - return; - } - - switch ($base) { - case -256: - if (ord($x[0]) & 0x80) { - $x = ~$x; - $this->is_negative = true; - } - case 256: - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $sign = $this->is_negative ? '-' : ''; - $this->value = gmp_init($sign . '0x' . bin2hex($x)); - break; - case MATH_BIGINTEGER_MODE_BCMATH: - // round $len to the nearest 4 (thanks, DavidMJ!) - $len = (strlen($x) + 3) & 0xFFFFFFFC; - - $x = str_pad($x, $len, chr(0), STR_PAD_LEFT); - - for ($i = 0; $i < $len; $i+= 4) { - $this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32 - $this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0); - } - - if ($this->is_negative) { - $this->value = '-' . $this->value; - } - - break; - // converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb) - default: - while (strlen($x)) { - $this->value[] = $this->_bytes2int($this->_base256_rshift($x, 26)); - } - } - - if ($this->is_negative) { - if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) { - $this->is_negative = false; - } - $temp = $this->add(new Math_BigInteger('-1')); - $this->value = $temp->value; - } - break; - case 16: - case -16: - if ($base > 0 && $x[0] == '-') { - $this->is_negative = true; - $x = substr($x, 1); - } - - $x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x); - - $is_negative = false; - if ($base < 0 && hexdec($x[0]) >= 8) { - $this->is_negative = $is_negative = true; - $x = bin2hex(~pack('H*', $x)); - } - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = $this->is_negative ? '-0x' . $x : '0x' . $x; - $this->value = gmp_init($temp); - $this->is_negative = false; - break; - case MATH_BIGINTEGER_MODE_BCMATH: - $x = ( strlen($x) & 1 ) ? '0' . $x : $x; - $temp = new Math_BigInteger(pack('H*', $x), 256); - $this->value = $this->is_negative ? '-' . $temp->value : $temp->value; - $this->is_negative = false; - break; - default: - $x = ( strlen($x) & 1 ) ? '0' . $x : $x; - $temp = new Math_BigInteger(pack('H*', $x), 256); - $this->value = $temp->value; - } - - if ($is_negative) { - $temp = $this->add(new Math_BigInteger('-1')); - $this->value = $temp->value; - } - break; - case 10: - case -10: - $x = preg_replace('#^(-?[0-9]*).*#', '$1', $x); - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $this->value = gmp_init($x); - break; - case MATH_BIGINTEGER_MODE_BCMATH: - // explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different - // results then doing it on '-1' does (modInverse does $x[0]) - $this->value = (string) $x; - break; - default: - $temp = new Math_BigInteger(); - - // array(10000000) is 10**7 in base-2**26. 10**7 is the closest to 2**26 we can get without passing it. - $multiplier = new Math_BigInteger(); - $multiplier->value = array(10000000); - - if ($x[0] == '-') { - $this->is_negative = true; - $x = substr($x, 1); - } - - $x = str_pad($x, strlen($x) + (6 * strlen($x)) % 7, 0, STR_PAD_LEFT); - - while (strlen($x)) { - $temp = $temp->multiply($multiplier); - $temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, 7)), 256)); - $x = substr($x, 7); - } - - $this->value = $temp->value; - } - break; - case 2: // base-2 support originally implemented by Lluis Pamies - thanks! - case -2: - if ($base > 0 && $x[0] == '-') { - $this->is_negative = true; - $x = substr($x, 1); - } - - $x = preg_replace('#^([01]*).*#', '$1', $x); - $x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT); - - $str = '0x'; - while (strlen($x)) { - $part = substr($x, 0, 4); - $str.= dechex(bindec($part)); - $x = substr($x, 4); - } - - if ($this->is_negative) { - $str = '-' . $str; - } - - $temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16 - $this->value = $temp->value; - $this->is_negative = $temp->is_negative; - - break; - default: - // base not supported, so we'll let $this == 0 - } - } - - /** - * Converts a BigInteger to a byte string (eg. base-256). - * - * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're - * saved as two's compliment. - * - * Here's an example: - * - * toBytes(); // outputs chr(65) - * ?> - * - * - * @param Boolean $twos_compliment - * @return String - * @access public - * @internal Converts a base-2**26 number to base-2**8 - */ - function toBytes($twos_compliment = false) - { - if ($twos_compliment) { - $comparison = $this->compare(new Math_BigInteger()); - if ($comparison == 0) { - return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; - } - - $temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy(); - $bytes = $temp->toBytes(); - - if (empty($bytes)) { // eg. if the number we're trying to convert is -1 - $bytes = chr(0); - } - - if (ord($bytes[0]) & 0x80) { - $bytes = chr(0) . $bytes; - } - - return $comparison < 0 ? ~$bytes : $bytes; - } - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - if (gmp_cmp($this->value, gmp_init(0)) == 0) { - return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; - } - - $temp = gmp_strval(gmp_abs($this->value), 16); - $temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp; - $temp = pack('H*', $temp); - - return $this->precision > 0 ? - substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) : - ltrim($temp, chr(0)); - case MATH_BIGINTEGER_MODE_BCMATH: - if ($this->value === '0') { - return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; - } - - $value = ''; - $current = $this->value; - - if ($current[0] == '-') { - $current = substr($current, 1); - } - - while (bccomp($current, '0', 0) > 0) { - $temp = bcmod($current, '16777216'); - $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value; - $current = bcdiv($current, '16777216', 0); - } - - return $this->precision > 0 ? - substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) : - ltrim($value, chr(0)); - } - - if (!count($this->value)) { - return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : ''; - } - $result = $this->_int2bytes($this->value[count($this->value) - 1]); - - $temp = $this->copy(); - - for ($i = count($temp->value) - 2; $i >= 0; --$i) { - $temp->_base256_lshift($result, 26); - $result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT); - } - - return $this->precision > 0 ? - str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) : - $result; - } - - /** - * Converts a BigInteger to a hex string (eg. base-16)). - * - * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're - * saved as two's compliment. - * - * Here's an example: - * - * toHex(); // outputs '41' - * ?> - * - * - * @param Boolean $twos_compliment - * @return String - * @access public - * @internal Converts a base-2**26 number to base-2**8 - */ - function toHex($twos_compliment = false) - { - return bin2hex($this->toBytes($twos_compliment)); - } - - /** - * Converts a BigInteger to a bit string (eg. base-2). - * - * Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're - * saved as two's compliment. - * - * Here's an example: - * - * toBits(); // outputs '1000001' - * ?> - * - * - * @param Boolean $twos_compliment - * @return String - * @access public - * @internal Converts a base-2**26 number to base-2**2 - */ - function toBits($twos_compliment = false) - { - $hex = $this->toHex($twos_compliment); - $bits = ''; - for ($i = 0; $i < strlen($hex); $i+=8) { - $bits.= str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT); - } - return $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0'); - } - - /** - * Converts a BigInteger to a base-10 number. - * - * Here's an example: - * - * toString(); // outputs 50 - * ?> - * - * - * @return String - * @access public - * @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10) - */ - function toString() - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - return gmp_strval($this->value); - case MATH_BIGINTEGER_MODE_BCMATH: - if ($this->value === '0') { - return '0'; - } - - return ltrim($this->value, '0'); - } - - if (!count($this->value)) { - return '0'; - } - - $temp = $this->copy(); - $temp->is_negative = false; - - $divisor = new Math_BigInteger(); - $divisor->value = array(10000000); // eg. 10**7 - $result = ''; - while (count($temp->value)) { - list($temp, $mod) = $temp->divide($divisor); - $result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', 7, '0', STR_PAD_LEFT) . $result; - } - $result = ltrim($result, '0'); - if (empty($result)) { - $result = '0'; - } - - if ($this->is_negative) { - $result = '-' . $result; - } - - return $result; - } - - /** - * Copy an object - * - * PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee - * that all objects are passed by value, when appropriate. More information can be found here: - * - * {@link http://php.net/language.oop5.basic#51624} - * - * @access public - * @see __clone() - * @return Math_BigInteger - */ - function copy() - { - $temp = new Math_BigInteger(); - $temp->value = $this->value; - $temp->is_negative = $this->is_negative; - $temp->generator = $this->generator; - $temp->precision = $this->precision; - $temp->bitmask = $this->bitmask; - return $temp; - } - - /** - * __toString() magic method - * - * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call - * toString(). - * - * @access public - * @internal Implemented per a suggestion by Techie-Michael - thanks! - */ - function __toString() - { - return $this->toString(); - } - - /** - * __clone() magic method - * - * Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone() - * directly in PHP5. You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5 - * only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and PHP5, - * call Math_BigInteger::copy(), instead. - * - * @access public - * @see copy() - * @return Math_BigInteger - */ - function __clone() - { - return $this->copy(); - } - - /** - * __sleep() magic method - * - * Will be called, automatically, when serialize() is called on a Math_BigInteger object. - * - * @see __wakeup() - * @access public - */ - function __sleep() - { - $this->hex = $this->toHex(true); - $vars = array('hex'); - if ($this->generator != 'mt_rand') { - $vars[] = 'generator'; - } - if ($this->precision > 0) { - $vars[] = 'precision'; - } - return $vars; - - } - - /** - * __wakeup() magic method - * - * Will be called, automatically, when unserialize() is called on a Math_BigInteger object. - * - * @see __sleep() - * @access public - */ - function __wakeup() - { - $temp = new Math_BigInteger($this->hex, -16); - $this->value = $temp->value; - $this->is_negative = $temp->is_negative; - $this->setRandomGenerator($this->generator); - if ($this->precision > 0) { - // recalculate $this->bitmask - $this->setPrecision($this->precision); - } - } - - /** - * Adds two BigIntegers. - * - * Here's an example: - * - * add($b); - * - * echo $c->toString(); // outputs 30 - * ?> - * - * - * @param Math_BigInteger $y - * @return Math_BigInteger - * @access public - * @internal Performs base-2**52 addition - */ - function add($y) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_add($this->value, $y->value); - - return $this->_normalize($temp); - case MATH_BIGINTEGER_MODE_BCMATH: - $temp = new Math_BigInteger(); - $temp->value = bcadd($this->value, $y->value, 0); - - return $this->_normalize($temp); - } - - $temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative); - - $result = new Math_BigInteger(); - $result->value = $temp[MATH_BIGINTEGER_VALUE]; - $result->is_negative = $temp[MATH_BIGINTEGER_SIGN]; - - return $this->_normalize($result); - } - - /** - * Performs addition. - * - * @param Array $x_value - * @param Boolean $x_negative - * @param Array $y_value - * @param Boolean $y_negative - * @return Array - * @access private - */ - function _add($x_value, $x_negative, $y_value, $y_negative) - { - $x_size = count($x_value); - $y_size = count($y_value); - - if ($x_size == 0) { - return array( - MATH_BIGINTEGER_VALUE => $y_value, - MATH_BIGINTEGER_SIGN => $y_negative - ); - } else if ($y_size == 0) { - return array( - MATH_BIGINTEGER_VALUE => $x_value, - MATH_BIGINTEGER_SIGN => $x_negative - ); - } - - // subtract, if appropriate - if ( $x_negative != $y_negative ) { - if ( $x_value == $y_value ) { - return array( - MATH_BIGINTEGER_VALUE => array(), - MATH_BIGINTEGER_SIGN => false - ); - } - - $temp = $this->_subtract($x_value, false, $y_value, false); - $temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ? - $x_negative : $y_negative; - - return $temp; - } - - if ($x_size < $y_size) { - $size = $x_size; - $value = $y_value; - } else { - $size = $y_size; - $value = $x_value; - } - - $value[] = 0; // just in case the carry adds an extra digit - - $carry = 0; - for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) { - $sum = $x_value[$j] * 0x4000000 + $x_value[$i] + $y_value[$j] * 0x4000000 + $y_value[$i] + $carry; - $carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT52; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 - $sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT52 : $sum; - - $temp = (int) ($sum / 0x4000000); - - $value[$i] = (int) ($sum - 0x4000000 * $temp); // eg. a faster alternative to fmod($sum, 0x4000000) - $value[$j] = $temp; - } - - if ($j == $size) { // ie. if $y_size is odd - $sum = $x_value[$i] + $y_value[$i] + $carry; - $carry = $sum >= 0x4000000; - $value[$i] = $carry ? $sum - 0x4000000 : $sum; - ++$i; // ie. let $i = $j since we've just done $value[$i] - } - - if ($carry) { - for (; $value[$i] == 0x3FFFFFF; ++$i) { - $value[$i] = 0; - } - ++$value[$i]; - } - - return array( - MATH_BIGINTEGER_VALUE => $this->_trim($value), - MATH_BIGINTEGER_SIGN => $x_negative - ); - } - - /** - * Subtracts two BigIntegers. - * - * Here's an example: - * - * subtract($b); - * - * echo $c->toString(); // outputs -10 - * ?> - * - * - * @param Math_BigInteger $y - * @return Math_BigInteger - * @access public - * @internal Performs base-2**52 subtraction - */ - function subtract($y) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_sub($this->value, $y->value); - - return $this->_normalize($temp); - case MATH_BIGINTEGER_MODE_BCMATH: - $temp = new Math_BigInteger(); - $temp->value = bcsub($this->value, $y->value, 0); - - return $this->_normalize($temp); - } - - $temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative); - - $result = new Math_BigInteger(); - $result->value = $temp[MATH_BIGINTEGER_VALUE]; - $result->is_negative = $temp[MATH_BIGINTEGER_SIGN]; - - return $this->_normalize($result); - } - - /** - * Performs subtraction. - * - * @param Array $x_value - * @param Boolean $x_negative - * @param Array $y_value - * @param Boolean $y_negative - * @return Array - * @access private - */ - function _subtract($x_value, $x_negative, $y_value, $y_negative) - { - $x_size = count($x_value); - $y_size = count($y_value); - - if ($x_size == 0) { - return array( - MATH_BIGINTEGER_VALUE => $y_value, - MATH_BIGINTEGER_SIGN => !$y_negative - ); - } else if ($y_size == 0) { - return array( - MATH_BIGINTEGER_VALUE => $x_value, - MATH_BIGINTEGER_SIGN => $x_negative - ); - } - - // add, if appropriate (ie. -$x - +$y or +$x - -$y) - if ( $x_negative != $y_negative ) { - $temp = $this->_add($x_value, false, $y_value, false); - $temp[MATH_BIGINTEGER_SIGN] = $x_negative; - - return $temp; - } - - $diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative); - - if ( !$diff ) { - return array( - MATH_BIGINTEGER_VALUE => array(), - MATH_BIGINTEGER_SIGN => false - ); - } - - // switch $x and $y around, if appropriate. - if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) { - $temp = $x_value; - $x_value = $y_value; - $y_value = $temp; - - $x_negative = !$x_negative; - - $x_size = count($x_value); - $y_size = count($y_value); - } - - // at this point, $x_value should be at least as big as - if not bigger than - $y_value - - $carry = 0; - for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) { - $sum = $x_value[$j] * 0x4000000 + $x_value[$i] - $y_value[$j] * 0x4000000 - $y_value[$i] - $carry; - $carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1 - $sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT52 : $sum; - - $temp = (int) ($sum / 0x4000000); - - $x_value[$i] = (int) ($sum - 0x4000000 * $temp); - $x_value[$j] = $temp; - } - - if ($j == $y_size) { // ie. if $y_size is odd - $sum = $x_value[$i] - $y_value[$i] - $carry; - $carry = $sum < 0; - $x_value[$i] = $carry ? $sum + 0x4000000 : $sum; - ++$i; - } - - if ($carry) { - for (; !$x_value[$i]; ++$i) { - $x_value[$i] = 0x3FFFFFF; - } - --$x_value[$i]; - } - - return array( - MATH_BIGINTEGER_VALUE => $this->_trim($x_value), - MATH_BIGINTEGER_SIGN => $x_negative - ); - } - - /** - * Multiplies two BigIntegers - * - * Here's an example: - * - * multiply($b); - * - * echo $c->toString(); // outputs 200 - * ?> - * - * - * @param Math_BigInteger $x - * @return Math_BigInteger - * @access public - */ - function multiply($x) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_mul($this->value, $x->value); - - return $this->_normalize($temp); - case MATH_BIGINTEGER_MODE_BCMATH: - $temp = new Math_BigInteger(); - $temp->value = bcmul($this->value, $x->value, 0); - - return $this->_normalize($temp); - } - - $temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative); - - $product = new Math_BigInteger(); - $product->value = $temp[MATH_BIGINTEGER_VALUE]; - $product->is_negative = $temp[MATH_BIGINTEGER_SIGN]; - - return $this->_normalize($product); - } - - /** - * Performs multiplication. - * - * @param Array $x_value - * @param Boolean $x_negative - * @param Array $y_value - * @param Boolean $y_negative - * @return Array - * @access private - */ - function _multiply($x_value, $x_negative, $y_value, $y_negative) - { - //if ( $x_value == $y_value ) { - // return array( - // MATH_BIGINTEGER_VALUE => $this->_square($x_value), - // MATH_BIGINTEGER_SIGN => $x_sign != $y_value - // ); - //} - - $x_length = count($x_value); - $y_length = count($y_value); - - if ( !$x_length || !$y_length ) { // a 0 is being multiplied - return array( - MATH_BIGINTEGER_VALUE => array(), - MATH_BIGINTEGER_SIGN => false - ); - } - - return array( - MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? - $this->_trim($this->_regularMultiply($x_value, $y_value)) : - $this->_trim($this->_karatsuba($x_value, $y_value)), - MATH_BIGINTEGER_SIGN => $x_negative != $y_negative - ); - } - - /** - * Performs long multiplication on two BigIntegers - * - * Modeled after 'multiply' in MutableBigInteger.java. - * - * @param Array $x_value - * @param Array $y_value - * @return Array - * @access private - */ - function _regularMultiply($x_value, $y_value) - { - $x_length = count($x_value); - $y_length = count($y_value); - - if ( !$x_length || !$y_length ) { // a 0 is being multiplied - return array(); - } - - if ( $x_length < $y_length ) { - $temp = $x_value; - $x_value = $y_value; - $y_value = $temp; - - $x_length = count($x_value); - $y_length = count($y_value); - } - - $product_value = $this->_array_repeat(0, $x_length + $y_length); - - // the following for loop could be removed if the for loop following it - // (the one with nested for loops) initially set $i to 0, but - // doing so would also make the result in one set of unnecessary adds, - // since on the outermost loops first pass, $product->value[$k] is going - // to always be 0 - - $carry = 0; - - for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0 - $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 - $carry = (int) ($temp / 0x4000000); - $product_value[$j] = (int) ($temp - 0x4000000 * $carry); - } - - $product_value[$j] = $carry; - - // the above for loop is what the previous comment was talking about. the - // following for loop is the "one with nested for loops" - for ($i = 1; $i < $y_length; ++$i) { - $carry = 0; - - for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) { - $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; - $carry = (int) ($temp / 0x4000000); - $product_value[$k] = (int) ($temp - 0x4000000 * $carry); - } - - $product_value[$k] = $carry; - } - - return $product_value; - } - - /** - * Performs Karatsuba multiplication on two BigIntegers - * - * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}. - * - * @param Array $x_value - * @param Array $y_value - * @return Array - * @access private - */ - function _karatsuba($x_value, $y_value) - { - $m = min(count($x_value) >> 1, count($y_value) >> 1); - - if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { - return $this->_regularMultiply($x_value, $y_value); - } - - $x1 = array_slice($x_value, $m); - $x0 = array_slice($x_value, 0, $m); - $y1 = array_slice($y_value, $m); - $y0 = array_slice($y_value, 0, $m); - - $z2 = $this->_karatsuba($x1, $y1); - $z0 = $this->_karatsuba($x0, $y0); - - $z1 = $this->_add($x1, false, $x0, false); - $temp = $this->_add($y1, false, $y0, false); - $z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]); - $temp = $this->_add($z2, false, $z0, false); - $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false); - - $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2); - $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]); - - $xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]); - $xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false); - - return $xy[MATH_BIGINTEGER_VALUE]; - } - - /** - * Performs squaring - * - * @param Array $x - * @return Array - * @access private - */ - function _square($x = false) - { - return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ? - $this->_trim($this->_baseSquare($x)) : - $this->_trim($this->_karatsubaSquare($x)); - } - - /** - * Performs traditional squaring on two BigIntegers - * - * Squaring can be done faster than multiplying a number by itself can be. See - * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} / - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information. - * - * @param Array $value - * @return Array - * @access private - */ - function _baseSquare($value) - { - if ( empty($value) ) { - return array(); - } - $square_value = $this->_array_repeat(0, 2 * count($value)); - - for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) { - $i2 = $i << 1; - - $temp = $square_value[$i2] + $value[$i] * $value[$i]; - $carry = (int) ($temp / 0x4000000); - $square_value[$i2] = (int) ($temp - 0x4000000 * $carry); - - // note how we start from $i+1 instead of 0 as we do in multiplication. - for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) { - $temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry; - $carry = (int) ($temp / 0x4000000); - $square_value[$k] = (int) ($temp - 0x4000000 * $carry); - } - - // the following line can yield values larger 2**15. at this point, PHP should switch - // over to floats. - $square_value[$i + $max_index + 1] = $carry; - } - - return $square_value; - } - - /** - * Performs Karatsuba "squaring" on two BigIntegers - * - * See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}. - * - * @param Array $value - * @return Array - * @access private - */ - function _karatsubaSquare($value) - { - $m = count($value) >> 1; - - if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) { - return $this->_baseSquare($value); - } - - $x1 = array_slice($value, $m); - $x0 = array_slice($value, 0, $m); - - $z2 = $this->_karatsubaSquare($x1); - $z0 = $this->_karatsubaSquare($x0); - - $z1 = $this->_add($x1, false, $x0, false); - $z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]); - $temp = $this->_add($z2, false, $z0, false); - $z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false); - - $z2 = array_merge(array_fill(0, 2 * $m, 0), $z2); - $z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]); - - $xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]); - $xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false); - - return $xx[MATH_BIGINTEGER_VALUE]; - } - - /** - * Divides two BigIntegers. - * - * Returns an array whose first element contains the quotient and whose second element contains the - * "common residue". If the remainder would be positive, the "common residue" and the remainder are the - * same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder - * and the divisor (basically, the "common residue" is the first positive modulo). - * - * Here's an example: - * - * divide($b); - * - * echo $quotient->toString(); // outputs 0 - * echo "\r\n"; - * echo $remainder->toString(); // outputs 10 - * ?> - * - * - * @param Math_BigInteger $y - * @return Array - * @access public - * @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}. - */ - function divide($y) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $quotient = new Math_BigInteger(); - $remainder = new Math_BigInteger(); - - list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value); - - if (gmp_sign($remainder->value) < 0) { - $remainder->value = gmp_add($remainder->value, gmp_abs($y->value)); - } - - return array($this->_normalize($quotient), $this->_normalize($remainder)); - case MATH_BIGINTEGER_MODE_BCMATH: - $quotient = new Math_BigInteger(); - $remainder = new Math_BigInteger(); - - $quotient->value = bcdiv($this->value, $y->value, 0); - $remainder->value = bcmod($this->value, $y->value); - - if ($remainder->value[0] == '-') { - $remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0); - } - - return array($this->_normalize($quotient), $this->_normalize($remainder)); - } - - if (count($y->value) == 1) { - list($q, $r) = $this->_divide_digit($this->value, $y->value[0]); - $quotient = new Math_BigInteger(); - $remainder = new Math_BigInteger(); - $quotient->value = $q; - $remainder->value = array($r); - $quotient->is_negative = $this->is_negative != $y->is_negative; - return array($this->_normalize($quotient), $this->_normalize($remainder)); - } - - static $zero; - if ( !isset($zero) ) { - $zero = new Math_BigInteger(); - } - - $x = $this->copy(); - $y = $y->copy(); - - $x_sign = $x->is_negative; - $y_sign = $y->is_negative; - - $x->is_negative = $y->is_negative = false; - - $diff = $x->compare($y); - - if ( !$diff ) { - $temp = new Math_BigInteger(); - $temp->value = array(1); - $temp->is_negative = $x_sign != $y_sign; - return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger())); - } - - if ( $diff < 0 ) { - // if $x is negative, "add" $y. - if ( $x_sign ) { - $x = $y->subtract($x); - } - return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x)); - } - - // normalize $x and $y as described in HAC 14.23 / 14.24 - $msb = $y->value[count($y->value) - 1]; - for ($shift = 0; !($msb & 0x2000000); ++$shift) { - $msb <<= 1; - } - $x->_lshift($shift); - $y->_lshift($shift); - $y_value = &$y->value; - - $x_max = count($x->value) - 1; - $y_max = count($y->value) - 1; - - $quotient = new Math_BigInteger(); - $quotient_value = &$quotient->value; - $quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1); - - static $temp, $lhs, $rhs; - if (!isset($temp)) { - $temp = new Math_BigInteger(); - $lhs = new Math_BigInteger(); - $rhs = new Math_BigInteger(); - } - $temp_value = &$temp->value; - $rhs_value = &$rhs->value; - - // $temp = $y << ($x_max - $y_max-1) in base 2**26 - $temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value); - - while ( $x->compare($temp) >= 0 ) { - // calculate the "common residue" - ++$quotient_value[$x_max - $y_max]; - $x = $x->subtract($temp); - $x_max = count($x->value) - 1; - } - - for ($i = $x_max; $i >= $y_max + 1; --$i) { - $x_value = &$x->value; - $x_window = array( - isset($x_value[$i]) ? $x_value[$i] : 0, - isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0, - isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0 - ); - $y_window = array( - $y_value[$y_max], - ( $y_max > 0 ) ? $y_value[$y_max - 1] : 0 - ); - - $q_index = $i - $y_max - 1; - if ($x_window[0] == $y_window[0]) { - $quotient_value[$q_index] = 0x3FFFFFF; - } else { - $quotient_value[$q_index] = (int) ( - ($x_window[0] * 0x4000000 + $x_window[1]) - / - $y_window[0] - ); - } - - $temp_value = array($y_window[1], $y_window[0]); - - $lhs->value = array($quotient_value[$q_index]); - $lhs = $lhs->multiply($temp); - - $rhs_value = array($x_window[2], $x_window[1], $x_window[0]); - - while ( $lhs->compare($rhs) > 0 ) { - --$quotient_value[$q_index]; - - $lhs->value = array($quotient_value[$q_index]); - $lhs = $lhs->multiply($temp); - } - - $adjust = $this->_array_repeat(0, $q_index); - $temp_value = array($quotient_value[$q_index]); - $temp = $temp->multiply($y); - $temp_value = &$temp->value; - $temp_value = array_merge($adjust, $temp_value); - - $x = $x->subtract($temp); - - if ($x->compare($zero) < 0) { - $temp_value = array_merge($adjust, $y_value); - $x = $x->add($temp); - - --$quotient_value[$q_index]; - } - - $x_max = count($x_value) - 1; - } - - // unnormalize the remainder - $x->_rshift($shift); - - $quotient->is_negative = $x_sign != $y_sign; - - // calculate the "common residue", if appropriate - if ( $x_sign ) { - $y->_rshift($shift); - $x = $y->subtract($x); - } - - return array($this->_normalize($quotient), $this->_normalize($x)); - } - - /** - * Divides a BigInteger by a regular integer - * - * abc / x = a00 / x + b0 / x + c / x - * - * @param Array $dividend - * @param Array $divisor - * @return Array - * @access private - */ - function _divide_digit($dividend, $divisor) - { - $carry = 0; - $result = array(); - - for ($i = count($dividend) - 1; $i >= 0; --$i) { - $temp = 0x4000000 * $carry + $dividend[$i]; - $result[$i] = (int) ($temp / $divisor); - $carry = (int) ($temp - $divisor * $result[$i]); - } - - return array($result, $carry); - } - - /** - * Performs modular exponentiation. - * - * Here's an example: - * - * modPow($b, $c); - * - * echo $c->toString(); // outputs 10 - * ?> - * - * - * @param Math_BigInteger $e - * @param Math_BigInteger $n - * @return Math_BigInteger - * @access public - * @internal The most naive approach to modular exponentiation has very unreasonable requirements, and - * and although the approach involving repeated squaring does vastly better, it, too, is impractical - * for our purposes. The reason being that division - by far the most complicated and time-consuming - * of the basic operations (eg. +,-,*,/) - occurs multiple times within it. - * - * Modular reductions resolve this issue. Although an individual modular reduction takes more time - * then an individual division, when performed in succession (with the same modulo), they're a lot faster. - * - * The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction, - * although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the - * base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because - * the product of two odd numbers is odd), but what about when RSA isn't used? - * - * In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a - * Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the - * modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however, - * uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and - * the other, a power of two - and recombine them, later. This is the method that this modPow function uses. - * {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates. - */ - function modPow($e, $n) - { - $n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs(); - - if ($e->compare(new Math_BigInteger()) < 0) { - $e = $e->abs(); - - $temp = $this->modInverse($n); - if ($temp === false) { - return false; - } - - return $this->_normalize($temp->modPow($e, $n)); - } - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_powm($this->value, $e->value, $n->value); - - return $this->_normalize($temp); - case MATH_BIGINTEGER_MODE_BCMATH: - $temp = new Math_BigInteger(); - $temp->value = bcpowmod($this->value, $e->value, $n->value, 0); - - return $this->_normalize($temp); - } - - if ( empty($e->value) ) { - $temp = new Math_BigInteger(); - $temp->value = array(1); - return $this->_normalize($temp); - } - - if ( $e->value == array(1) ) { - list(, $temp) = $this->divide($n); - return $this->_normalize($temp); - } - - if ( $e->value == array(2) ) { - $temp = new Math_BigInteger(); - $temp->value = $this->_square($this->value); - list(, $temp) = $temp->divide($n); - return $this->_normalize($temp); - } - - return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT)); - - // is the modulo odd? - if ( $n->value[0] & 1 ) { - return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY)); - } - // if it's not, it's even - - // find the lowest set bit (eg. the max pow of 2 that divides $n) - for ($i = 0; $i < count($n->value); ++$i) { - if ( $n->value[$i] ) { - $temp = decbin($n->value[$i]); - $j = strlen($temp) - strrpos($temp, '1') - 1; - $j+= 26 * $i; - break; - } - } - // at this point, 2^$j * $n/(2^$j) == $n - - $mod1 = $n->copy(); - $mod1->_rshift($j); - $mod2 = new Math_BigInteger(); - $mod2->value = array(1); - $mod2->_lshift($j); - - $part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger(); - $part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2); - - $y1 = $mod2->modInverse($mod1); - $y2 = $mod1->modInverse($mod2); - - $result = $part1->multiply($mod2); - $result = $result->multiply($y1); - - $temp = $part2->multiply($mod1); - $temp = $temp->multiply($y2); - - $result = $result->add($temp); - list(, $result) = $result->divide($n); - - return $this->_normalize($result); - } - - /** - * Performs modular exponentiation. - * - * Alias for Math_BigInteger::modPow() - * - * @param Math_BigInteger $e - * @param Math_BigInteger $n - * @return Math_BigInteger - * @access public - */ - function powMod($e, $n) - { - return $this->modPow($e, $n); - } - - /** - * Sliding Window k-ary Modular Exponentiation - * - * Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} / - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims, - * however, this function performs a modular reduction after every multiplication and squaring operation. - * As such, this function has the same preconditions that the reductions being used do. - * - * @param Math_BigInteger $e - * @param Math_BigInteger $n - * @param Integer $mode - * @return Math_BigInteger - * @access private - */ - function _slidingWindow($e, $n, $mode) - { - static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function - //static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1 - - $e_value = $e->value; - $e_length = count($e_value) - 1; - $e_bits = decbin($e_value[$e_length]); - for ($i = $e_length - 1; $i >= 0; --$i) { - $e_bits.= str_pad(decbin($e_value[$i]), 26, '0', STR_PAD_LEFT); - } - - $e_length = strlen($e_bits); - - // calculate the appropriate window size. - // $window_size == 3 if $window_ranges is between 25 and 81, for example. - for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i); - - $n_value = $n->value; - - // precompute $this^0 through $this^$window_size - $powers = array(); - $powers[1] = $this->_prepareReduce($this->value, $n_value, $mode); - $powers[2] = $this->_squareReduce($powers[1], $n_value, $mode); - - // we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end - // in a 1. ie. it's supposed to be odd. - $temp = 1 << ($window_size - 1); - for ($i = 1; $i < $temp; ++$i) { - $i2 = $i << 1; - $powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode); - } - - $result = array(1); - $result = $this->_prepareReduce($result, $n_value, $mode); - - for ($i = 0; $i < $e_length; ) { - if ( !$e_bits[$i] ) { - $result = $this->_squareReduce($result, $n_value, $mode); - ++$i; - } else { - for ($j = $window_size - 1; $j > 0; --$j) { - if ( !empty($e_bits[$i + $j]) ) { - break; - } - } - - for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1) - $result = $this->_squareReduce($result, $n_value, $mode); - } - - $result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode); - - $i+=$j + 1; - } - } - - $temp = new Math_BigInteger(); - $temp->value = $this->_reduce($result, $n_value, $mode); - - return $temp; - } - - /** - * Modular reduction - * - * For most $modes this will return the remainder. - * - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $n - * @param Integer $mode - * @return Array - */ - function _reduce($x, $n, $mode) - { - switch ($mode) { - case MATH_BIGINTEGER_MONTGOMERY: - return $this->_montgomery($x, $n); - case MATH_BIGINTEGER_BARRETT: - return $this->_barrett($x, $n); - case MATH_BIGINTEGER_POWEROF2: - $lhs = new Math_BigInteger(); - $lhs->value = $x; - $rhs = new Math_BigInteger(); - $rhs->value = $n; - return $x->_mod2($n); - case MATH_BIGINTEGER_CLASSIC: - $lhs = new Math_BigInteger(); - $lhs->value = $x; - $rhs = new Math_BigInteger(); - $rhs->value = $n; - list(, $temp) = $lhs->divide($rhs); - return $temp->value; - case MATH_BIGINTEGER_NONE: - return $x; - default: - // an invalid $mode was provided - } - } - - /** - * Modular reduction preperation - * - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $n - * @param Integer $mode - * @return Array - */ - function _prepareReduce($x, $n, $mode) - { - if ($mode == MATH_BIGINTEGER_MONTGOMERY) { - return $this->_prepMontgomery($x, $n); - } - return $this->_reduce($x, $n, $mode); - } - - /** - * Modular multiply - * - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $y - * @param Array $n - * @param Integer $mode - * @return Array - */ - function _multiplyReduce($x, $y, $n, $mode) - { - if ($mode == MATH_BIGINTEGER_MONTGOMERY) { - return $this->_montgomeryMultiply($x, $y, $n); - } - $temp = $this->_multiply($x, false, $y, false); - return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode); - } - - /** - * Modular square - * - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $n - * @param Integer $mode - * @return Array - */ - function _squareReduce($x, $n, $mode) - { - if ($mode == MATH_BIGINTEGER_MONTGOMERY) { - return $this->_montgomeryMultiply($x, $x, $n); - } - return $this->_reduce($this->_square($x), $n, $mode); - } - - /** - * Modulos for Powers of Two - * - * Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1), - * we'll just use this function as a wrapper for doing that. - * - * @see _slidingWindow() - * @access private - * @param Math_BigInteger - * @return Math_BigInteger - */ - function _mod2($n) - { - $temp = new Math_BigInteger(); - $temp->value = array(1); - return $this->bitwise_and($n->subtract($temp)); - } - - /** - * Barrett Modular Reduction - * - * See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} / - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly, - * so as not to require negative numbers (initially, this script didn't support negative numbers). - * - * Employs "folding", as described at - * {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from - * it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x." - * - * Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that - * usable on account of (1) its not using reasonable radix points as discussed in - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable - * radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that - * (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line - * comments for details. - * - * @see _slidingWindow() - * @access private - * @param Array $n - * @param Array $m - * @return Array - */ - function _barrett($n, $m) - { - static $cache = array( - MATH_BIGINTEGER_VARIABLE => array(), - MATH_BIGINTEGER_DATA => array() - ); - - $m_length = count($m); - - // if ($this->_compare($n, $this->_square($m)) >= 0) { - if (count($n) > 2 * $m_length) { - $lhs = new Math_BigInteger(); - $rhs = new Math_BigInteger(); - $lhs->value = $n; - $rhs->value = $m; - list(, $temp) = $lhs->divide($rhs); - return $temp->value; - } - - // if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced - if ($m_length < 5) { - return $this->_regularBarrett($n, $m); - } - - // n = 2 * m.length - - if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { - $key = count($cache[MATH_BIGINTEGER_VARIABLE]); - $cache[MATH_BIGINTEGER_VARIABLE][] = $m; - - $lhs = new Math_BigInteger(); - $lhs_value = &$lhs->value; - $lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1)); - $lhs_value[] = 1; - $rhs = new Math_BigInteger(); - $rhs->value = $m; - - list($u, $m1) = $lhs->divide($rhs); - $u = $u->value; - $m1 = $m1->value; - - $cache[MATH_BIGINTEGER_DATA][] = array( - 'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1) - 'm1'=> $m1 // m.length - ); - } else { - extract($cache[MATH_BIGINTEGER_DATA][$key]); - } - - $cutoff = $m_length + ($m_length >> 1); - $lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1) - $msd = array_slice($n, $cutoff); // m.length >> 1 - $lsd = $this->_trim($lsd); - $temp = $this->_multiply($msd, false, $m1, false); - $n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1 - - if ($m_length & 1) { - return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m); - } - - // (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2 - $temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1); - // if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2 - // if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1 - $temp = $this->_multiply($temp, false, $u, false); - // if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1 - // if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) - $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1); - // if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1 - // if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1) - $temp = $this->_multiply($temp, false, $m, false); - - // at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit - // number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop - // following this comment would loop a lot (hence our calling _regularBarrett() in that situation). - - $result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); - - while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) { - $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false); - } - - return $result[MATH_BIGINTEGER_VALUE]; - } - - /** - * (Regular) Barrett Modular Reduction - * - * For numbers with more than four digits Math_BigInteger::_barrett() is faster. The difference between that and this - * is that this function does not fold the denominator into a smaller form. - * - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $n - * @return Array - */ - function _regularBarrett($x, $n) - { - static $cache = array( - MATH_BIGINTEGER_VARIABLE => array(), - MATH_BIGINTEGER_DATA => array() - ); - - $n_length = count($n); - - if (count($x) > 2 * $n_length) { - $lhs = new Math_BigInteger(); - $rhs = new Math_BigInteger(); - $lhs->value = $x; - $rhs->value = $n; - list(, $temp) = $lhs->divide($rhs); - return $temp->value; - } - - if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { - $key = count($cache[MATH_BIGINTEGER_VARIABLE]); - $cache[MATH_BIGINTEGER_VARIABLE][] = $n; - $lhs = new Math_BigInteger(); - $lhs_value = &$lhs->value; - $lhs_value = $this->_array_repeat(0, 2 * $n_length); - $lhs_value[] = 1; - $rhs = new Math_BigInteger(); - $rhs->value = $n; - list($temp, ) = $lhs->divide($rhs); // m.length - $cache[MATH_BIGINTEGER_DATA][] = $temp->value; - } - - // 2 * m.length - (m.length - 1) = m.length + 1 - $temp = array_slice($x, $n_length - 1); - // (m.length + 1) + m.length = 2 * m.length + 1 - $temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false); - // (2 * m.length + 1) - (m.length - 1) = m.length + 2 - $temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1); - - // m.length + 1 - $result = array_slice($x, 0, $n_length + 1); - // m.length + 1 - $temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1); - // $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1) - - if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) { - $corrector_value = $this->_array_repeat(0, $n_length + 1); - $corrector_value[] = 1; - $result = $this->_add($result, false, $corrector, false); - $result = $result[MATH_BIGINTEGER_VALUE]; - } - - // at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits - $result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]); - while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) { - $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false); - } - - return $result[MATH_BIGINTEGER_VALUE]; - } - - /** - * Performs long multiplication up to $stop digits - * - * If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved. - * - * @see _regularBarrett() - * @param Array $x_value - * @param Boolean $x_negative - * @param Array $y_value - * @param Boolean $y_negative - * @return Array - * @access private - */ - function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop) - { - $x_length = count($x_value); - $y_length = count($y_value); - - if ( !$x_length || !$y_length ) { // a 0 is being multiplied - return array( - MATH_BIGINTEGER_VALUE => array(), - MATH_BIGINTEGER_SIGN => false - ); - } - - if ( $x_length < $y_length ) { - $temp = $x_value; - $x_value = $y_value; - $y_value = $temp; - - $x_length = count($x_value); - $y_length = count($y_value); - } - - $product_value = $this->_array_repeat(0, $x_length + $y_length); - - // the following for loop could be removed if the for loop following it - // (the one with nested for loops) initially set $i to 0, but - // doing so would also make the result in one set of unnecessary adds, - // since on the outermost loops first pass, $product->value[$k] is going - // to always be 0 - - $carry = 0; - - for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i - $temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0 - $carry = (int) ($temp / 0x4000000); - $product_value[$j] = (int) ($temp - 0x4000000 * $carry); - } - - if ($j < $stop) { - $product_value[$j] = $carry; - } - - // the above for loop is what the previous comment was talking about. the - // following for loop is the "one with nested for loops" - - for ($i = 1; $i < $y_length; ++$i) { - $carry = 0; - - for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) { - $temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry; - $carry = (int) ($temp / 0x4000000); - $product_value[$k] = (int) ($temp - 0x4000000 * $carry); - } - - if ($k < $stop) { - $product_value[$k] = $carry; - } - } - - return array( - MATH_BIGINTEGER_VALUE => $this->_trim($product_value), - MATH_BIGINTEGER_SIGN => $x_negative != $y_negative - ); - } - - /** - * Montgomery Modular Reduction - * - * ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n. - * {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be - * improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function - * to work correctly. - * - * @see _prepMontgomery() - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $n - * @return Array - */ - function _montgomery($x, $n) - { - static $cache = array( - MATH_BIGINTEGER_VARIABLE => array(), - MATH_BIGINTEGER_DATA => array() - ); - - if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { - $key = count($cache[MATH_BIGINTEGER_VARIABLE]); - $cache[MATH_BIGINTEGER_VARIABLE][] = $x; - $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n); - } - - $k = count($n); - - $result = array(MATH_BIGINTEGER_VALUE => $x); - - for ($i = 0; $i < $k; ++$i) { - $temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key]; - $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000))); - $temp = $this->_regularMultiply(array($temp), $n); - $temp = array_merge($this->_array_repeat(0, $i), $temp); - $result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false); - } - - $result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k); - - if ($this->_compare($result, false, $n, false) >= 0) { - $result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false); - } - - return $result[MATH_BIGINTEGER_VALUE]; - } - - /** - * Montgomery Multiply - * - * Interleaves the montgomery reduction and long multiplication algorithms together as described in - * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36} - * - * @see _prepMontgomery() - * @see _montgomery() - * @access private - * @param Array $x - * @param Array $y - * @param Array $m - * @return Array - */ - function _montgomeryMultiply($x, $y, $m) - { - $temp = $this->_multiply($x, false, $y, false); - return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m); - - static $cache = array( - MATH_BIGINTEGER_VARIABLE => array(), - MATH_BIGINTEGER_DATA => array() - ); - - if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) { - $key = count($cache[MATH_BIGINTEGER_VARIABLE]); - $cache[MATH_BIGINTEGER_VARIABLE][] = $m; - $cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m); - } - - $n = max(count($x), count($y), count($m)); - $x = array_pad($x, $n, 0); - $y = array_pad($y, $n, 0); - $m = array_pad($m, $n, 0); - $a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1)); - for ($i = 0; $i < $n; ++$i) { - $temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0]; - $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000))); - $temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key]; - $temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000))); - $temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false); - $a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false); - $a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1); - } - if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) { - $a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false); - } - return $a[MATH_BIGINTEGER_VALUE]; - } - - /** - * Prepare a number for use in Montgomery Modular Reductions - * - * @see _montgomery() - * @see _slidingWindow() - * @access private - * @param Array $x - * @param Array $n - * @return Array - */ - function _prepMontgomery($x, $n) - { - $lhs = new Math_BigInteger(); - $lhs->value = array_merge($this->_array_repeat(0, count($n)), $x); - $rhs = new Math_BigInteger(); - $rhs->value = $n; - - list(, $temp) = $lhs->divide($rhs); - return $temp->value; - } - - /** - * Modular Inverse of a number mod 2**26 (eg. 67108864) - * - * Based off of the bnpInvDigit function implemented and justified in the following URL: - * - * {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js} - * - * The following URL provides more info: - * - * {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85} - * - * As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For - * instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields - * int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't - * auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that - * the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the - * maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to - * 40 bits, which only 64-bit floating points will support. - * - * Thanks to Pedro Gimeno Fortea for input! - * - * @see _montgomery() - * @access private - * @param Array $x - * @return Integer - */ - function _modInverse67108864($x) // 2**26 == 67108864 - { - $x = -$x[0]; - $result = $x & 0x3; // x**-1 mod 2**2 - $result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4 - $result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8 - $result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16 - $result = fmod($result * (2 - fmod($x * $result, 0x4000000)), 0x4000000); // x**-1 mod 2**26 - return $result & 0x3FFFFFF; - } - - /** - * Calculates modular inverses. - * - * Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses. - * - * Here's an example: - * - * modInverse($b); - * echo $c->toString(); // outputs 4 - * - * echo "\r\n"; - * - * $d = $a->multiply($c); - * list(, $d) = $d->divide($b); - * echo $d; // outputs 1 (as per the definition of modular inverse) - * ?> - * - * - * @param Math_BigInteger $n - * @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise. - * @access public - * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information. - */ - function modInverse($n) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_invert($this->value, $n->value); - - return ( $temp->value === false ) ? false : $this->_normalize($temp); - } - - static $zero, $one; - if (!isset($zero)) { - $zero = new Math_BigInteger(); - $one = new Math_BigInteger(1); - } - - // $x mod $n == $x mod -$n. - $n = $n->abs(); - - if ($this->compare($zero) < 0) { - $temp = $this->abs(); - $temp = $temp->modInverse($n); - return $negated === false ? false : $this->_normalize($n->subtract($temp)); - } - - extract($this->extendedGCD($n)); - - if (!$gcd->equals($one)) { - return false; - } - - $x = $x->compare($zero) < 0 ? $x->add($n) : $x; - - return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x); - } - - /** - * Calculates the greatest common divisor and Bézout's identity. - * - * Say you have 693 and 609. The GCD is 21. Bézout's identity states that there exist integers x and y such that - * 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which - * combination is returned is dependant upon which mode is in use. See - * {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity Bézout's identity - Wikipedia} for more information. - * - * Here's an example: - * - * extendedGCD($b)); - * - * echo $gcd->toString() . "\r\n"; // outputs 21 - * echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21 - * ?> - * - * - * @param Math_BigInteger $n - * @return Math_BigInteger - * @access public - * @internal Calculates the GCD using the binary xGCD algorithim described in - * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes, - * the more traditional algorithim requires "relatively costly multiple-precision divisions". - */ - function extendedGCD($n) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - extract(gmp_gcdext($this->value, $n->value)); - - return array( - 'gcd' => $this->_normalize(new Math_BigInteger($g)), - 'x' => $this->_normalize(new Math_BigInteger($s)), - 'y' => $this->_normalize(new Math_BigInteger($t)) - ); - case MATH_BIGINTEGER_MODE_BCMATH: - // it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works - // best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is, - // the basic extended euclidean algorithim is what we're using. - - $u = $this->value; - $v = $n->value; - - $a = '1'; - $b = '0'; - $c = '0'; - $d = '1'; - - while (bccomp($v, '0', 0) != 0) { - $q = bcdiv($u, $v, 0); - - $temp = $u; - $u = $v; - $v = bcsub($temp, bcmul($v, $q, 0), 0); - - $temp = $a; - $a = $c; - $c = bcsub($temp, bcmul($a, $q, 0), 0); - - $temp = $b; - $b = $d; - $d = bcsub($temp, bcmul($b, $q, 0), 0); - } - - return array( - 'gcd' => $this->_normalize(new Math_BigInteger($u)), - 'x' => $this->_normalize(new Math_BigInteger($a)), - 'y' => $this->_normalize(new Math_BigInteger($b)) - ); - } - - $y = $n->copy(); - $x = $this->copy(); - $g = new Math_BigInteger(); - $g->value = array(1); - - while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) { - $x->_rshift(1); - $y->_rshift(1); - $g->_lshift(1); - } - - $u = $x->copy(); - $v = $y->copy(); - - $a = new Math_BigInteger(); - $b = new Math_BigInteger(); - $c = new Math_BigInteger(); - $d = new Math_BigInteger(); - - $a->value = $d->value = $g->value = array(1); - $b->value = $c->value = array(); - - while ( !empty($u->value) ) { - while ( !($u->value[0] & 1) ) { - $u->_rshift(1); - if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) { - $a = $a->add($y); - $b = $b->subtract($x); - } - $a->_rshift(1); - $b->_rshift(1); - } - - while ( !($v->value[0] & 1) ) { - $v->_rshift(1); - if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) { - $c = $c->add($y); - $d = $d->subtract($x); - } - $c->_rshift(1); - $d->_rshift(1); - } - - if ($u->compare($v) >= 0) { - $u = $u->subtract($v); - $a = $a->subtract($c); - $b = $b->subtract($d); - } else { - $v = $v->subtract($u); - $c = $c->subtract($a); - $d = $d->subtract($b); - } - } - - return array( - 'gcd' => $this->_normalize($g->multiply($v)), - 'x' => $this->_normalize($c), - 'y' => $this->_normalize($d) - ); - } - - /** - * Calculates the greatest common divisor - * - * Say you have 693 and 609. The GCD is 21. - * - * Here's an example: - * - * extendedGCD($b); - * - * echo $gcd->toString() . "\r\n"; // outputs 21 - * ?> - * - * - * @param Math_BigInteger $n - * @return Math_BigInteger - * @access public - */ - function gcd($n) - { - extract($this->extendedGCD($n)); - return $gcd; - } - - /** - * Absolute value. - * - * @return Math_BigInteger - * @access public - */ - function abs() - { - $temp = new Math_BigInteger(); - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp->value = gmp_abs($this->value); - break; - case MATH_BIGINTEGER_MODE_BCMATH: - $temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value; - break; - default: - $temp->value = $this->value; - } - - return $temp; - } - - /** - * Compares two numbers. - * - * Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is - * demonstrated thusly: - * - * $x > $y: $x->compare($y) > 0 - * $x < $y: $x->compare($y) < 0 - * $x == $y: $x->compare($y) == 0 - * - * Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y). - * - * @param Math_BigInteger $x - * @return Integer < 0 if $this is less than $x; > 0 if $this is greater than $x, and 0 if they are equal. - * @access public - * @see equals() - * @internal Could return $this->subtract($x), but that's not as fast as what we do do. - */ - function compare($y) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - return gmp_cmp($this->value, $y->value); - case MATH_BIGINTEGER_MODE_BCMATH: - return bccomp($this->value, $y->value, 0); - } - - return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative); - } - - /** - * Compares two numbers. - * - * @param Array $x_value - * @param Boolean $x_negative - * @param Array $y_value - * @param Boolean $y_negative - * @return Integer - * @see compare() - * @access private - */ - function _compare($x_value, $x_negative, $y_value, $y_negative) - { - if ( $x_negative != $y_negative ) { - return ( !$x_negative && $y_negative ) ? 1 : -1; - } - - $result = $x_negative ? -1 : 1; - - if ( count($x_value) != count($y_value) ) { - return ( count($x_value) > count($y_value) ) ? $result : -$result; - } - $size = max(count($x_value), count($y_value)); - - $x_value = array_pad($x_value, $size, 0); - $y_value = array_pad($y_value, $size, 0); - - for ($i = count($x_value) - 1; $i >= 0; --$i) { - if ($x_value[$i] != $y_value[$i]) { - return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result; - } - } - - return 0; - } - - /** - * Tests the equality of two numbers. - * - * If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare() - * - * @param Math_BigInteger $x - * @return Boolean - * @access public - * @see compare() - */ - function equals($x) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - return gmp_cmp($this->value, $x->value) == 0; - default: - return $this->value === $x->value && $this->is_negative == $x->is_negative; - } - } - - /** - * Set Precision - * - * Some bitwise operations give different results depending on the precision being used. Examples include left - * shift, not, and rotates. - * - * @param Math_BigInteger $x - * @access public - * @return Math_BigInteger - */ - function setPrecision($bits) - { - $this->precision = $bits; - if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) { - $this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256); - } else { - $this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0)); - } - - $temp = $this->_normalize($this); - $this->value = $temp->value; - } - - /** - * Logical And - * - * @param Math_BigInteger $x - * @access public - * @internal Implemented per a request by Lluis Pamies i Juarez - * @return Math_BigInteger - */ - function bitwise_and($x) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_and($this->value, $x->value); - - return $this->_normalize($temp); - case MATH_BIGINTEGER_MODE_BCMATH: - $left = $this->toBytes(); - $right = $x->toBytes(); - - $length = max(strlen($left), strlen($right)); - - $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); - $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); - - return $this->_normalize(new Math_BigInteger($left & $right, 256)); - } - - $result = $this->copy(); - - $length = min(count($x->value), count($this->value)); - - $result->value = array_slice($result->value, 0, $length); - - for ($i = 0; $i < $length; ++$i) { - $result->value[$i] = $result->value[$i] & $x->value[$i]; - } - - return $this->_normalize($result); - } - - /** - * Logical Or - * - * @param Math_BigInteger $x - * @access public - * @internal Implemented per a request by Lluis Pamies i Juarez - * @return Math_BigInteger - */ - function bitwise_or($x) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_or($this->value, $x->value); - - return $this->_normalize($temp); - case MATH_BIGINTEGER_MODE_BCMATH: - $left = $this->toBytes(); - $right = $x->toBytes(); - - $length = max(strlen($left), strlen($right)); - - $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); - $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); - - return $this->_normalize(new Math_BigInteger($left | $right, 256)); - } - - $length = max(count($this->value), count($x->value)); - $result = $this->copy(); - $result->value = array_pad($result->value, 0, $length); - $x->value = array_pad($x->value, 0, $length); - - for ($i = 0; $i < $length; ++$i) { - $result->value[$i] = $this->value[$i] | $x->value[$i]; - } - - return $this->_normalize($result); - } - - /** - * Logical Exclusive-Or - * - * @param Math_BigInteger $x - * @access public - * @internal Implemented per a request by Lluis Pamies i Juarez - * @return Math_BigInteger - */ - function bitwise_xor($x) - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - $temp = new Math_BigInteger(); - $temp->value = gmp_xor($this->value, $x->value); - - return $this->_normalize($temp); - case MATH_BIGINTEGER_MODE_BCMATH: - $left = $this->toBytes(); - $right = $x->toBytes(); - - $length = max(strlen($left), strlen($right)); - - $left = str_pad($left, $length, chr(0), STR_PAD_LEFT); - $right = str_pad($right, $length, chr(0), STR_PAD_LEFT); - - return $this->_normalize(new Math_BigInteger($left ^ $right, 256)); - } - - $length = max(count($this->value), count($x->value)); - $result = $this->copy(); - $result->value = array_pad($result->value, 0, $length); - $x->value = array_pad($x->value, 0, $length); - - for ($i = 0; $i < $length; ++$i) { - $result->value[$i] = $this->value[$i] ^ $x->value[$i]; - } - - return $this->_normalize($result); - } - - /** - * Logical Not - * - * @access public - * @internal Implemented per a request by Lluis Pamies i Juarez - * @return Math_BigInteger - */ - function bitwise_not() - { - // calculuate "not" without regard to $this->precision - // (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0) - $temp = $this->toBytes(); - $pre_msb = decbin(ord($temp[0])); - $temp = ~$temp; - $msb = decbin(ord($temp[0])); - if (strlen($msb) == 8) { - $msb = substr($msb, strpos($msb, '0')); - } - $temp[0] = chr(bindec($msb)); - - // see if we need to add extra leading 1's - $current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8; - $new_bits = $this->precision - $current_bits; - if ($new_bits <= 0) { - return $this->_normalize(new Math_BigInteger($temp, 256)); - } - - // generate as many leading 1's as we need to. - $leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3); - $this->_base256_lshift($leading_ones, $current_bits); - - $temp = str_pad($temp, ceil($this->bits / 8), chr(0), STR_PAD_LEFT); - - return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256)); - } - - /** - * Logical Right Shift - * - * Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift. - * - * @param Integer $shift - * @return Math_BigInteger - * @access public - * @internal The only version that yields any speed increases is the internal version. - */ - function bitwise_rightShift($shift) - { - $temp = new Math_BigInteger(); - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - static $two; - - if (!isset($two)) { - $two = gmp_init('2'); - } - - $temp->value = gmp_div_q($this->value, gmp_pow($two, $shift)); - - break; - case MATH_BIGINTEGER_MODE_BCMATH: - $temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0); - - break; - default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten - // and I don't want to do that... - $temp->value = $this->value; - $temp->_rshift($shift); - } - - return $this->_normalize($temp); - } - - /** - * Logical Left Shift - * - * Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift. - * - * @param Integer $shift - * @return Math_BigInteger - * @access public - * @internal The only version that yields any speed increases is the internal version. - */ - function bitwise_leftShift($shift) - { - $temp = new Math_BigInteger(); - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - static $two; - - if (!isset($two)) { - $two = gmp_init('2'); - } - - $temp->value = gmp_mul($this->value, gmp_pow($two, $shift)); - - break; - case MATH_BIGINTEGER_MODE_BCMATH: - $temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0); - - break; - default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten - // and I don't want to do that... - $temp->value = $this->value; - $temp->_lshift($shift); - } - - return $this->_normalize($temp); - } - - /** - * Logical Left Rotate - * - * Instead of the top x bits being dropped they're appended to the shifted bit string. - * - * @param Integer $shift - * @return Math_BigInteger - * @access public - */ - function bitwise_leftRotate($shift) - { - $bits = $this->toBytes(); - - if ($this->precision > 0) { - $precision = $this->precision; - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { - $mask = $this->bitmask->subtract(new Math_BigInteger(1)); - $mask = $mask->toBytes(); - } else { - $mask = $this->bitmask->toBytes(); - } - } else { - $temp = ord($bits[0]); - for ($i = 0; $temp >> $i; ++$i); - $precision = 8 * strlen($bits) - 8 + $i; - $mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3); - } - - if ($shift < 0) { - $shift+= $precision; - } - $shift%= $precision; - - if (!$shift) { - return $this->copy(); - } - - $left = $this->bitwise_leftShift($shift); - $left = $left->bitwise_and(new Math_BigInteger($mask, 256)); - $right = $this->bitwise_rightShift($precision - $shift); - $result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right); - return $this->_normalize($result); - } - - /** - * Logical Right Rotate - * - * Instead of the bottom x bits being dropped they're prepended to the shifted bit string. - * - * @param Integer $shift - * @return Math_BigInteger - * @access public - */ - function bitwise_rightRotate($shift) - { - return $this->bitwise_leftRotate(-$shift); - } - - /** - * Set random number generator function - * - * $generator should be the name of a random generating function whose first parameter is the minimum - * value and whose second parameter is the maximum value. If this function needs to be seeded, it should - * be seeded prior to calling Math_BigInteger::random() or Math_BigInteger::randomPrime() - * - * If the random generating function is not explicitly set, it'll be assumed to be mt_rand(). - * - * @see random() - * @see randomPrime() - * @param optional String $generator - * @access public - */ - function setRandomGenerator($generator) - { - $this->generator = $generator; - } - - /** - * Generate a random number - * - * @param optional Integer $min - * @param optional Integer $max - * @return Math_BigInteger - * @access public - */ - function random($min = false, $max = false) - { - if ($min === false) { - $min = new Math_BigInteger(0); - } - - if ($max === false) { - $max = new Math_BigInteger(0x7FFFFFFF); - } - - $compare = $max->compare($min); - - if (!$compare) { - return $this->_normalize($min); - } else if ($compare < 0) { - // if $min is bigger then $max, swap $min and $max - $temp = $max; - $max = $min; - $min = $temp; - } - - $generator = $this->generator; - - $max = $max->subtract($min); - $max = ltrim($max->toBytes(), chr(0)); - $size = strlen($max) - 1; - $random = ''; - - $bytes = $size & 1; - for ($i = 0; $i < $bytes; ++$i) { - $random.= chr($generator(0, 255)); - } - - $blocks = $size >> 1; - for ($i = 0; $i < $blocks; ++$i) { - // mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems - $random.= pack('n', $generator(0, 0xFFFF)); - } - - $temp = new Math_BigInteger($random, 256); - if ($temp->compare(new Math_BigInteger(substr($max, 1), 256)) > 0) { - $random = chr($generator(0, ord($max[0]) - 1)) . $random; - } else { - $random = chr($generator(0, ord($max[0]) )) . $random; - } - - $random = new Math_BigInteger($random, 256); - - return $this->_normalize($random->add($min)); - } - - /** - * Generate a random prime number. - * - * If there's not a prime within the given range, false will be returned. If more than $timeout seconds have elapsed, - * give up and return false. - * - * @param optional Integer $min - * @param optional Integer $max - * @param optional Integer $timeout - * @return Math_BigInteger - * @access public - * @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}. - */ - function randomPrime($min = false, $max = false, $timeout = false) - { - $compare = $max->compare($min); - - if (!$compare) { - return $min; - } else if ($compare < 0) { - // if $min is bigger then $max, swap $min and $max - $temp = $max; - $max = $min; - $min = $temp; - } - - // gmp_nextprime() requires PHP 5 >= 5.2.0 per . - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) { - // we don't rely on Math_BigInteger::random()'s min / max when gmp_nextprime() is being used since this function - // does its own checks on $max / $min when gmp_nextprime() is used. When gmp_nextprime() is not used, however, - // the same $max / $min checks are not performed. - if ($min === false) { - $min = new Math_BigInteger(0); - } - - if ($max === false) { - $max = new Math_BigInteger(0x7FFFFFFF); - } - - $x = $this->random($min, $max); - - $x->value = gmp_nextprime($x->value); - - if ($x->compare($max) <= 0) { - return $x; - } - - $x->value = gmp_nextprime($min->value); - - if ($x->compare($max) <= 0) { - return $x; - } - - return false; - } - - static $one, $two; - if (!isset($one)) { - $one = new Math_BigInteger(1); - $two = new Math_BigInteger(2); - } - - $start = time(); - - $x = $this->random($min, $max); - if ($x->equals($two)) { - return $x; - } - - $x->_make_odd(); - if ($x->compare($max) > 0) { - // if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range - if ($min->equals($max)) { - return false; - } - $x = $min->copy(); - $x->_make_odd(); - } - - $initial_x = $x->copy(); - - while (true) { - if ($timeout !== false && time() - $start > $timeout) { - return false; - } - - if ($x->isPrime()) { - return $x; - } - - $x = $x->add($two); - - if ($x->compare($max) > 0) { - $x = $min->copy(); - if ($x->equals($two)) { - return $x; - } - $x->_make_odd(); - } - - if ($x->equals($initial_x)) { - return false; - } - } - } - - /** - * Make the current number odd - * - * If the current number is odd it'll be unchanged. If it's even, one will be added to it. - * - * @see randomPrime() - * @access private - */ - function _make_odd() - { - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - gmp_setbit($this->value, 0); - break; - case MATH_BIGINTEGER_MODE_BCMATH: - if ($this->value[strlen($this->value) - 1] % 2 == 0) { - $this->value = bcadd($this->value, '1'); - } - break; - default: - $this->value[0] |= 1; - } - } - - /** - * Checks a numer to see if it's prime - * - * Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the - * $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed accross multiple pageloads - * on a website instead of just one. - * - * @param optional Integer $t - * @return Boolean - * @access public - * @internal Uses the - * {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See - * {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}. - */ - function isPrime($t = false) - { - $length = strlen($this->toBytes()); - - if (!$t) { - // see HAC 4.49 "Note (controlling the error probability)" - if ($length >= 163) { $t = 2; } // floor(1300 / 8) - else if ($length >= 106) { $t = 3; } // floor( 850 / 8) - else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8) - else if ($length >= 68 ) { $t = 5; } // floor( 550 / 8) - else if ($length >= 56 ) { $t = 6; } // floor( 450 / 8) - else if ($length >= 50 ) { $t = 7; } // floor( 400 / 8) - else if ($length >= 43 ) { $t = 8; } // floor( 350 / 8) - else if ($length >= 37 ) { $t = 9; } // floor( 300 / 8) - else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8) - else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8) - else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8) - else { $t = 27; } - } - - // ie. gmp_testbit($this, 0) - // ie. isEven() or !isOdd() - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - return gmp_prob_prime($this->value, $t) != 0; - case MATH_BIGINTEGER_MODE_BCMATH: - if ($this->value === '2') { - return true; - } - if ($this->value[strlen($this->value) - 1] % 2 == 0) { - return false; - } - break; - default: - if ($this->value == array(2)) { - return true; - } - if (~$this->value[0] & 1) { - return false; - } - } - - static $primes, $zero, $one, $two; - - if (!isset($primes)) { - $primes = array( - 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, - 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, - 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, - 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, - 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, - 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, - 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, - 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, - 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, - 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, - 953, 967, 971, 977, 983, 991, 997 - ); - - if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) { - for ($i = 0; $i < count($primes); ++$i) { - $primes[$i] = new Math_BigInteger($primes[$i]); - } - } - - $zero = new Math_BigInteger(); - $one = new Math_BigInteger(1); - $two = new Math_BigInteger(2); - } - - if ($this->equals($one)) { - return false; - } - - // see HAC 4.4.1 "Random search for probable primes" - if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) { - foreach ($primes as $prime) { - list(, $r) = $this->divide($prime); - if ($r->equals($zero)) { - return $this->equals($prime); - } - } - } else { - $value = $this->value; - foreach ($primes as $prime) { - list(, $r) = $this->_divide_digit($value, $prime); - if (!$r) { - return count($value) == 1 && $value[0] == $prime; - } - } - } - - $n = $this->copy(); - $n_1 = $n->subtract($one); - $n_2 = $n->subtract($two); - - $r = $n_1->copy(); - $r_value = $r->value; - // ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s)); - if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) { - $s = 0; - // if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier - while ($r->value[strlen($r->value) - 1] % 2 == 0) { - $r->value = bcdiv($r->value, '2', 0); - ++$s; - } - } else { - for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) { - $temp = ~$r_value[$i] & 0xFFFFFF; - for ($j = 1; ($temp >> $j) & 1; ++$j); - if ($j != 25) { - break; - } - } - $s = 26 * $i + $j - 1; - $r->_rshift($s); - } - - for ($i = 0; $i < $t; ++$i) { - $a = $this->random($two, $n_2); - $y = $a->modPow($r, $n); - - if (!$y->equals($one) && !$y->equals($n_1)) { - for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) { - $y = $y->modPow($two, $n); - if ($y->equals($one)) { - return false; - } - } - - if (!$y->equals($n_1)) { - return false; - } - } - } - return true; - } - - /** - * Logical Left Shift - * - * Shifts BigInteger's by $shift bits. - * - * @param Integer $shift - * @access private - */ - function _lshift($shift) - { - if ( $shift == 0 ) { - return; - } - - $num_digits = (int) ($shift / 26); - $shift %= 26; - $shift = 1 << $shift; - - $carry = 0; - - for ($i = 0; $i < count($this->value); ++$i) { - $temp = $this->value[$i] * $shift + $carry; - $carry = (int) ($temp / 0x4000000); - $this->value[$i] = (int) ($temp - $carry * 0x4000000); - } - - if ( $carry ) { - $this->value[] = $carry; - } - - while ($num_digits--) { - array_unshift($this->value, 0); - } - } - - /** - * Logical Right Shift - * - * Shifts BigInteger's by $shift bits. - * - * @param Integer $shift - * @access private - */ - function _rshift($shift) - { - if ($shift == 0) { - return; - } - - $num_digits = (int) ($shift / 26); - $shift %= 26; - $carry_shift = 26 - $shift; - $carry_mask = (1 << $shift) - 1; - - if ( $num_digits ) { - $this->value = array_slice($this->value, $num_digits); - } - - $carry = 0; - - for ($i = count($this->value) - 1; $i >= 0; --$i) { - $temp = $this->value[$i] >> $shift | $carry; - $carry = ($this->value[$i] & $carry_mask) << $carry_shift; - $this->value[$i] = $temp; - } - - $this->value = $this->_trim($this->value); - } - - /** - * Normalize - * - * Removes leading zeros and truncates (if necessary) to maintain the appropriate precision - * - * @param Math_BigInteger - * @return Math_BigInteger - * @see _trim() - * @access private - */ - function _normalize($result) - { - $result->precision = $this->precision; - $result->bitmask = $this->bitmask; - - switch ( MATH_BIGINTEGER_MODE ) { - case MATH_BIGINTEGER_MODE_GMP: - if (!empty($result->bitmask->value)) { - $result->value = gmp_and($result->value, $result->bitmask->value); - } - - return $result; - case MATH_BIGINTEGER_MODE_BCMATH: - if (!empty($result->bitmask->value)) { - $result->value = bcmod($result->value, $result->bitmask->value); - } - - return $result; - } - - $value = &$result->value; - - if ( !count($value) ) { - return $result; - } - - $value = $this->_trim($value); - - if (!empty($result->bitmask->value)) { - $length = min(count($value), count($this->bitmask->value)); - $value = array_slice($value, 0, $length); - - for ($i = 0; $i < $length; ++$i) { - $value[$i] = $value[$i] & $this->bitmask->value[$i]; - } - } - - return $result; - } - - /** - * Trim - * - * Removes leading zeros - * - * @return Math_BigInteger - * @access private - */ - function _trim($value) - { - for ($i = count($value) - 1; $i >= 0; --$i) { - if ( $value[$i] ) { - break; - } - unset($value[$i]); - } - - return $value; - } - - /** - * Array Repeat - * - * @param $input Array - * @param $multiplier mixed - * @return Array - * @access private - */ - function _array_repeat($input, $multiplier) - { - return ($multiplier) ? array_fill(0, $multiplier, $input) : array(); - } - - /** - * Logical Left Shift - * - * Shifts binary strings $shift bits, essentially multiplying by 2**$shift. - * - * @param $x String - * @param $shift Integer - * @return String - * @access private - */ - function _base256_lshift(&$x, $shift) - { - if ($shift == 0) { - return; - } - - $num_bytes = $shift >> 3; // eg. floor($shift/8) - $shift &= 7; // eg. $shift % 8 - - $carry = 0; - for ($i = strlen($x) - 1; $i >= 0; --$i) { - $temp = ord($x[$i]) << $shift | $carry; - $x[$i] = chr($temp); - $carry = $temp >> 8; - } - $carry = ($carry != 0) ? chr($carry) : ''; - $x = $carry . $x . str_repeat(chr(0), $num_bytes); - } - - /** - * Logical Right Shift - * - * Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder. - * - * @param $x String - * @param $shift Integer - * @return String - * @access private - */ - function _base256_rshift(&$x, $shift) - { - if ($shift == 0) { - $x = ltrim($x, chr(0)); - return ''; - } - - $num_bytes = $shift >> 3; // eg. floor($shift/8) - $shift &= 7; // eg. $shift % 8 - - $remainder = ''; - if ($num_bytes) { - $start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes; - $remainder = substr($x, $start); - $x = substr($x, 0, -$num_bytes); - } - - $carry = 0; - $carry_shift = 8 - $shift; - for ($i = 0; $i < strlen($x); ++$i) { - $temp = (ord($x[$i]) >> $shift) | $carry; - $carry = (ord($x[$i]) << $carry_shift) & 0xFF; - $x[$i] = chr($temp); - } - $x = ltrim($x, chr(0)); - - $remainder = chr($carry >> $carry_shift) . $remainder; - - return ltrim($remainder, chr(0)); - } - - // one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long - // at 32-bits, while java's longs are 64-bits. - - /** - * Converts 32-bit integers to bytes. - * - * @param Integer $x - * @return String - * @access private - */ - function _int2bytes($x) - { - return ltrim(pack('N', $x), chr(0)); - } - - /** - * Converts bytes to 32-bit integers - * - * @param String $x - * @return Integer - * @access private - */ - function _bytes2int($x) - { - $temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT)); - return $temp['int']; - } -} \ No newline at end of file diff --git a/library/phpsec/Net/SFTP.php b/library/phpsec/Net/SFTP.php deleted file mode 100644 index 06812ada35..0000000000 --- a/library/phpsec/Net/SFTP.php +++ /dev/null @@ -1,1461 +0,0 @@ - - * login('username', 'password')) { - * exit('Login Failed'); - * } - * - * echo $sftp->pwd() . "\r\n"; - * $sftp->put('filename.ext', 'hello, world!'); - * print_r($sftp->nlist()); - * ?> - * - * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * @category Net - * @package Net_SFTP - * @author Jim Wigginton - * @copyright MMIX Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: SFTP.php,v 1.21 2010/04/09 02:31:34 terrafrost Exp $ - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Net_SSH2 - */ -require_once('Net/SSH2.php'); - -/**#@+ - * @access public - * @see Net_SFTP::getLog() - */ -/** - * Returns the message numbers - */ -define('NET_SFTP_LOG_SIMPLE', NET_SSH2_LOG_SIMPLE); -/** - * Returns the message content - */ -define('NET_SFTP_LOG_COMPLEX', NET_SSH2_LOG_COMPLEX); -/**#@-*/ - -/** - * SFTP channel constant - * - * Net_SSH2::exec() uses 0 and Net_SSH2::interactiveRead() / Net_SSH2::interactiveWrite() use 1. - * - * @see Net_SSH2::_send_channel_packet() - * @see Net_SSH2::_get_channel_packet() - * @access private - */ -define('NET_SFTP_CHANNEL', 2); - -/**#@+ - * @access public - * @see Net_SFTP::put() - */ -/** - * Reads data from a local file. - */ -define('NET_SFTP_LOCAL_FILE', 1); -/** - * Reads data from a string. - */ -define('NET_SFTP_STRING', 2); -/**#@-*/ - -/** - * Pure-PHP implementations of SFTP. - * - * @author Jim Wigginton - * @version 0.1.0 - * @access public - * @package Net_SFTP - */ -class Net_SFTP extends Net_SSH2 { - /** - * Packet Types - * - * @see Net_SFTP::Net_SFTP() - * @var Array - * @access private - */ - var $packet_types = array(); - - /** - * Status Codes - * - * @see Net_SFTP::Net_SFTP() - * @var Array - * @access private - */ - var $status_codes = array(); - - /** - * The Request ID - * - * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support - * concurrent actions, so it's somewhat academic, here. - * - * @var Integer - * @see Net_SFTP::_send_sftp_packet() - * @access private - */ - var $request_id = false; - - /** - * The Packet Type - * - * The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support - * concurrent actions, so it's somewhat academic, here. - * - * @var Integer - * @see Net_SFTP::_get_sftp_packet() - * @access private - */ - var $packet_type = -1; - - /** - * Packet Buffer - * - * @var String - * @see Net_SFTP::_get_sftp_packet() - * @access private - */ - var $packet_buffer = ''; - - /** - * Extensions supported by the server - * - * @var Array - * @see Net_SFTP::_initChannel() - * @access private - */ - var $extensions = array(); - - /** - * Server SFTP version - * - * @var Integer - * @see Net_SFTP::_initChannel() - * @access private - */ - var $version; - - /** - * Current working directory - * - * @var String - * @see Net_SFTP::_realpath() - * @see Net_SFTP::chdir() - * @access private - */ - var $pwd = false; - - /** - * Packet Type Log - * - * @see Net_SFTP::getLog() - * @var Array - * @access private - */ - var $packet_type_log = array(); - - /** - * Packet Log - * - * @see Net_SFTP::getLog() - * @var Array - * @access private - */ - var $packet_log = array(); - - /** - * Error information - * - * @see Net_SFTP::getSFTPErrors() - * @see Net_SFTP::getLastSFTPError() - * @var String - * @access private - */ - var $errors = array(); - - /** - * Default Constructor. - * - * Connects to an SFTP server - * - * @param String $host - * @param optional Integer $port - * @param optional Integer $timeout - * @return Net_SFTP - * @access public - */ - function Net_SFTP($host, $port = 22, $timeout = 10) - { - parent::Net_SSH2($host, $port, $timeout); - $this->packet_types = array( - 1 => 'NET_SFTP_INIT', - 2 => 'NET_SFTP_VERSION', - /* the format of SSH_FXP_OPEN changed between SFTPv4 and SFTPv5+: - SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.1 - pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 */ - 3 => 'NET_SFTP_OPEN', - 4 => 'NET_SFTP_CLOSE', - 5 => 'NET_SFTP_READ', - 6 => 'NET_SFTP_WRITE', - 8 => 'NET_SFTP_FSTAT', - 9 => 'NET_SFTP_SETSTAT', - 11 => 'NET_SFTP_OPENDIR', - 12 => 'NET_SFTP_READDIR', - 13 => 'NET_SFTP_REMOVE', - 14 => 'NET_SFTP_MKDIR', - 15 => 'NET_SFTP_RMDIR', - 16 => 'NET_SFTP_REALPATH', - 17 => 'NET_SFTP_STAT', - /* the format of SSH_FXP_RENAME changed between SFTPv4 and SFTPv5+: - SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3 - pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */ - 18 => 'NET_SFTP_RENAME', - - 101=> 'NET_SFTP_STATUS', - 102=> 'NET_SFTP_HANDLE', - /* the format of SSH_FXP_NAME changed between SFTPv3 and SFTPv4+: - SFTPv4+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.4 - pre-SFTPv4 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7 */ - 103=> 'NET_SFTP_DATA', - 104=> 'NET_SFTP_NAME', - 105=> 'NET_SFTP_ATTRS', - - 200=> 'NET_SFTP_EXTENDED' - ); - $this->status_codes = array( - 0 => 'NET_SFTP_STATUS_OK', - 1 => 'NET_SFTP_STATUS_EOF', - 2 => 'NET_SFTP_STATUS_NO_SUCH_FILE', - 3 => 'NET_SFTP_STATUS_PERMISSION_DENIED', - 4 => 'NET_SFTP_STATUS_FAILURE', - 5 => 'NET_SFTP_STATUS_BAD_MESSAGE', - 6 => 'NET_SFTP_STATUS_NO_CONNECTION', - 7 => 'NET_SFTP_STATUS_CONNECTION_LOST', - 8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED' - ); - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1 - // the order, in this case, matters quite a lot - see Net_SFTP::_parseAttributes() to understand why - $this->attributes = array( - 0x00000001 => 'NET_SFTP_ATTR_SIZE', - 0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+ - 0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS', - 0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME', - -1 => 'NET_SFTP_ATTR_EXTENDED' // unpack('N', "\xFF\xFF\xFF\xFF") == array(1 => int(-1)) - ); - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 - // the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name - // the array for that $this->open5_flags and similarily alter the constant names. - $this->open_flags = array( - 0x00000001 => 'NET_SFTP_OPEN_READ', - 0x00000002 => 'NET_SFTP_OPEN_WRITE', - 0x00000008 => 'NET_SFTP_OPEN_CREATE', - 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE' - ); - $this->_define_array( - $this->packet_types, - $this->status_codes, - $this->attributes, - $this->open_flags - ); - } - - /** - * Login - * - * @param String $username - * @param optional String $password - * @return Boolean - * @access public - */ - function login($username, $password = '') - { - if (!parent::login($username, $password)) { - return false; - } - - $this->window_size_client_to_server[NET_SFTP_CHANNEL] = $this->window_size; - - $packet = pack('CNa*N3', - NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SFTP_CHANNEL, $this->window_size, 0x4000); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN; - - $response = $this->_get_channel_packet(NET_SFTP_CHANNEL); - if ($response === false) { - return false; - } - - $packet = pack('CNNa*CNa*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SFTP_CHANNEL], strlen('subsystem'), 'subsystem', 1, strlen('sftp'), 'sftp'); - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST; - - $response = $this->_get_channel_packet(NET_SFTP_CHANNEL); - if ($response === false) { - return false; - } - - $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA; - - if (!$this->_send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3")) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_VERSION) { - user_error('Expected SSH_FXP_VERSION', E_USER_NOTICE); - return false; - } - - extract(unpack('Nversion', $this->_string_shift($response, 4))); - $this->version = $version; - while (!empty($response)) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $key = $this->_string_shift($response, $length); - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $value = $this->_string_shift($response, $length); - $this->extensions[$key] = $value; - } - - /* - SFTPv4+ defines a 'newline' extension. SFTPv3 seems to have unofficial support for it via 'newline@vandyke.com', - however, I'm not sure what 'newline@vandyke.com' is supposed to do (the fact that it's unofficial means that it's - not in the official SFTPv3 specs) and 'newline@vandyke.com' / 'newline' are likely not drop-in substitutes for - one another due to the fact that 'newline' comes with a SSH_FXF_TEXT bitmask whereas it seems unlikely that - 'newline@vandyke.com' would. - */ - /* - if (isset($this->extensions['newline@vandyke.com'])) { - $this->extensions['newline'] = $this->extensions['newline@vandyke.com']; - unset($this->extensions['newline@vandyke.com']); - } - */ - - $this->request_id = 1; - - /* - A Note on SFTPv4/5/6 support: - states the following: - - "If the client wishes to interoperate with servers that support noncontiguous version - numbers it SHOULD send '3'" - - Given that the server only sends its version number after the client has already done so, the above - seems to be suggesting that v3 should be the default version. This makes sense given that v3 is the - most popular. - - states the following; - - "If the server did not send the "versions" extension, or the version-from-list was not included, the - server MAY send a status response describing the failure, but MUST then close the channel without - processing any further requests." - - So what do you do if you have a client whose initial SSH_FXP_INIT packet says it implements v3 and - a server whose initial SSH_FXP_VERSION reply says it implements v4 and only v4? If it only implements - v4, the "versions" extension is likely not going to have been sent so version re-negotiation as discussed - in draft-ietf-secsh-filexfer-13 would be quite impossible. As such, what Net_SFTP would do is close the - channel and reopen it with a new and updated SSH_FXP_INIT packet. - */ - if ($this->version != 3) { - return false; - } - - $this->pwd = $this->_realpath('.'); - - return true; - } - - /** - * Returns the current directory name - * - * @return Mixed - * @access public - */ - function pwd() - { - return $this->pwd; - } - - /** - * Canonicalize the Server-Side Path Name - * - * SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns - * the absolute (canonicalized) path. If $mode is set to NET_SFTP_CONFIRM_DIR (as opposed to NET_SFTP_CONFIRM_NONE, - * which is what it is set to by default), false is returned if $dir is not a valid directory. - * - * @see Net_SFTP::chdir() - * @param String $dir - * @param optional Integer $mode - * @return Mixed - * @access private - */ - function _realpath($dir) - { - /* - "This protocol represents file names as strings. File names are - assumed to use the slash ('/') character as a directory separator. - - File names starting with a slash are "absolute", and are relative to - the root of the file system. Names starting with any other character - are relative to the user's default directory (home directory). Note - that identifying the user is assumed to take place outside of this - protocol." - - -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-6 - */ - $file = ''; - if ($this->pwd !== false) { - // if the SFTP server returned the canonicalized path even for non-existant files this wouldn't be necessary - // on OpenSSH it isn't necessary but on other SFTP servers it is. that and since the specs say nothing on - // the subject, we'll go ahead and work around it with the following. - if ($dir[strlen($dir) - 1] != '/') { - $file = basename($dir); - $dir = dirname($dir); - } - - if ($dir == '.' || $dir == $this->pwd) { - return $this->pwd . $file; - } - - if ($dir[0] != '/') { - $dir = $this->pwd . '/' . $dir; - } - // on the surface it seems like maybe resolving a path beginning with / is unnecessary, but such paths - // can contain .'s and ..'s just like any other. we could parse those out as appropriate or we can let - // the server do it. we'll do the latter. - } - - /* - that SSH_FXP_REALPATH returns SSH_FXP_NAME does not necessarily mean that anything actually exists at the - specified path. generally speaking, no attributes are returned with this particular SSH_FXP_NAME packet - regardless of whether or not a file actually exists. and in SFTPv3, the longname field and the filename - field match for this particular SSH_FXP_NAME packet. for other SSH_FXP_NAME packets, this will likely - not be the case, but for this one, it is. - */ - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9 - if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($dir), $dir))) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_NAME: - // although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following - // should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks - // at is the first part and that part is defined the same in SFTP versions 3 through 6. - $this->_string_shift($response, 4); // skip over the count - it should be 1, anyway - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $realpath = $this->_string_shift($response, $length); - break; - case NET_SFTP_STATUS: - extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - default: - user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - // if $this->pwd isn't set than the only thing $realpath could be is for '.', which is pretty much guaranteed to - // be a bonafide directory - return $realpath . '/' . $file; - } - - /** - * Changes the current directory - * - * @param String $dir - * @return Boolean - * @access public - */ - function chdir($dir) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - if ($dir[strlen($dir) - 1] != '/') { - $dir.= '/'; - } - $dir = $this->_realpath($dir); - - // confirm that $dir is, in fact, a valid directory - if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) { - return false; - } - - // see Net_SFTP::nlist() for a more thorough explanation of the following - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_HANDLE: - $handle = substr($response, 4); - break; - case NET_SFTP_STATUS: - extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - default: - user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - } - - $this->pwd = $dir; - return true; - } - - /** - * Returns a list of files in the given directory - * - * @param optional String $dir - * @return Mixed - * @access public - */ - function nlist($dir = '.') - { - return $this->_list($dir, false); - } - - /** - * Returns a list of files in the given directory - * - * @param optional String $dir - * @return Mixed - * @access public - */ - function rawlist($dir = '.') - { - return $this->_list($dir, true); - } - - function _list($dir, $raw = true) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $dir = $this->_realpath($dir); - if ($dir === false) { - return false; - } - - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.2 - if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_HANDLE: - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.2 - // since 'handle' is the last field in the SSH_FXP_HANDLE packet, we'll just remove the first four bytes that - // represent the length of the string and leave it at that - $handle = substr($response, 4); - break; - case NET_SFTP_STATUS: - // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED - extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - default: - user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - $contents = array(); - while (true) { - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.2 - // why multiple SSH_FXP_READDIR packets would be sent when the response to a single one can span arbitrarily many - // SSH_MSG_CHANNEL_DATA messages is not known to me. - if (!$this->_send_sftp_packet(NET_SFTP_READDIR, pack('Na*', strlen($handle), $handle))) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_NAME: - extract(unpack('Ncount', $this->_string_shift($response, 4))); - for ($i = 0; $i < $count; $i++) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $shortname = $this->_string_shift($response, $length); - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->_string_shift($response, $length); // SFTPv4+ drop this field - the "longname" field - $attributes = $this->_parseAttributes($response); // we also don't care about the attributes - if (!$raw) { - $contents[] = $shortname; - } else { - $contents[$shortname] = $attributes; - } - // SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the - // final SSH_FXP_STATUS packet should tell us that, already. - } - break; - case NET_SFTP_STATUS: - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_EOF) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - } - break 2; - default: - user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - } - - if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { - return false; - } - - // "The client MUST release all resources associated with the handle regardless of the status." - // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3 - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - } - - return $contents; - } - - /** - * Returns the file size, in bytes, or false, on failure - * - * Files larger than 4GB will show up as being exactly 4GB. - * - * @param optional String $dir - * @return Mixed - * @access public - */ - function size($filename) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $filename = $this->_realpath($filename); - if ($filename === false) { - return false; - } - - // SFTPv4+ adds an additional 32-bit integer field - flags - to the following: - $packet = pack('Na*', strlen($filename), $filename); - if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_ATTRS: - $attrs = $this->_parseAttributes($response); - return $attrs['size']; - case NET_SFTP_STATUS: - extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - } - - user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - /** - * Set permissions on a file. - * - * Returns the new file permissions on success or FALSE on error. - * - * @param Integer $mode - * @param String $filename - * @return Mixed - * @access public - */ - function chmod($mode, $filename) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $filename = $this->_realpath($filename); - if ($filename === false) { - return false; - } - - // SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to - // SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT. - $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777); - if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) { - return false; - } - - /* - "Because some systems must use separate system calls to set various attributes, it is possible that a failure - response will be returned, but yet some of the attributes may be have been successfully modified. If possible, - servers SHOULD avoid this situation; however, clients MUST be aware that this is possible." - - -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.6 - */ - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_EOF) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - } - - // rather than return what the permissions *should* be, we'll return what they actually are. this will also - // tell us if the file actually exists. - // incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following: - $packet = pack('Na*', strlen($filename), $filename); - if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_ATTRS: - $attrs = $this->_parseAttributes($response); - return $attrs['permissions']; - case NET_SFTP_STATUS: - extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - } - - user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - /** - * Creates a directory. - * - * @param String $dir - * @return Boolean - * @access public - */ - function mkdir($dir) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $dir = $this->_realpath(rtrim($dir, '/')); - if ($dir === false) { - return false; - } - - // by not providing any permissions, hopefully the server will use the logged in users umask - their - // default permissions. - if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*N', strlen($dir), $dir, 0))) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - } - - return true; - } - - /** - * Removes a directory. - * - * @param String $dir - * @return Boolean - * @access public - */ - function rmdir($dir) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $dir = $this->_realpath($dir); - if ($dir === false) { - return false; - } - - if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($dir), $dir))) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED? - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - } - - return true; - } - - /** - * Uploads a file to the SFTP server. - * - * By default, Net_SFTP::put() does not read from the local filesystem. $data is dumped directly into $remote_file. - * So, for example, if you set $data to 'filename.ext' and then do Net_SFTP::get(), you will get a file, twelve bytes - * long, containing 'filename.ext' as its contents. - * - * Setting $mode to NET_SFTP_LOCAL_FILE will change the above behavior. With NET_SFTP_LOCAL_FILE, $remote_file will - * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how - * large $remote_file will be, as well. - * - * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take - * care of that, yourself. - * - * @param String $remote_file - * @param String $data - * @param optional Integer $flags - * @return Boolean - * @access public - * @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - Net_SFTP::setMode(). - */ - function put($remote_file, $data, $mode = NET_SFTP_STRING) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $remote_file = $this->_realpath($remote_file); - if ($remote_file === false) { - return false; - } - - $packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_TRUNCATE, 0); - if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_HANDLE: - $handle = substr($response, 4); - break; - case NET_SFTP_STATUS: - extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - default: - user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - $initialize = true; - - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3 - if ($mode == NET_SFTP_LOCAL_FILE) { - if (!is_file($data)) { - user_error("$data is not a valid file", E_USER_NOTICE); - return false; - } - $fp = fopen($data, 'rb'); - if (!$fp) { - return false; - } - $sent = 0; - $size = filesize($data); - } else { - $sent = 0; - $size = strlen($data); - } - - $size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size; - - $sftp_packet_size = 34000; // PuTTY uses 4096 - $i = 0; - while ($sent < $size) { - $temp = $mode == NET_SFTP_LOCAL_FILE ? fread($fp, $sftp_packet_size) : $this->_string_shift($data, $sftp_packet_size); - $packet = pack('Na*N3a*', strlen($handle), $handle, 0, $sent, strlen($temp), $temp); - if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) { - fclose($fp); - return false; - } - $sent+= strlen($temp); - - $i++; - - if ($i == 50) { - if (!$this->_read_put_responses($i)) { - $i = 0; - break; - } - $i = 0; - } - } - - $this->_read_put_responses($i); - - if ($mode == NET_SFTP_LOCAL_FILE) { - fclose($fp); - } - - if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - } - - return true; - } - - /** - * Reads multiple successive SSH_FXP_WRITE responses - * - * Sending an SSH_FXP_WRITE packet and immediately reading its response isn't as efficient as blindly sending out $i - * SSH_FXP_WRITEs, in succession, and then reading $i responses. - * - * @param Integer $i - * @return Boolean - * @access private - */ - function _read_put_responses($i) - { - while ($i--) { - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - break; - } - } - - return $i < 0; - } - - /** - * Downloads a file from the SFTP server. - * - * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if - * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the - * operation - * - * @param String $remote_file - * @param optional String $local_file - * @return Mixed - * @access public - */ - function get($remote_file, $local_file = false) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $remote_file = $this->_realpath($remote_file); - if ($remote_file === false) { - return false; - } - - $packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0); - if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_HANDLE: - $handle = substr($response, 4); - break; - case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED - extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - default: - user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - $packet = pack('Na*', strlen($handle), $handle); - if (!$this->_send_sftp_packet(NET_SFTP_FSTAT, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_ATTRS: - $attrs = $this->_parseAttributes($response); - break; - case NET_SFTP_STATUS: - extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - default: - user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - if ($local_file !== false) { - $fp = fopen($local_file, 'wb'); - if (!$fp) { - return false; - } - } else { - $content = ''; - } - - $read = 0; - while ($read < $attrs['size']) { - $packet = pack('Na*N3', strlen($handle), $handle, 0, $read, 1 << 20); - if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - switch ($this->packet_type) { - case NET_SFTP_DATA: - $temp = substr($response, 4); - $read+= strlen($temp); - if ($local_file === false) { - $content.= $temp; - } else { - fputs($fp, $temp); - } - break; - case NET_SFTP_STATUS: - extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - break 2; - default: - user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - } - - if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - } - - if (isset($content)) { - return $content; - } - - fclose($fp); - return true; - } - - /** - * Deletes a file on the SFTP server. - * - * @param String $path - * @return Boolean - * @access public - */ - function delete($path) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $remote_file = $this->_realpath($path); - if ($path === false) { - return false; - } - - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3 - if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($path), $path))) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - } - - return true; - } - - /** - * Renames a file or a directory on the SFTP server - * - * @param String $oldname - * @param String $newname - * @return Boolean - * @access public - */ - function rename($oldname, $newname) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - $oldname = $this->_realpath($oldname); - $newname = $this->_realpath($newname); - if ($oldname === false || $newname === false) { - return false; - } - - // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3 - $packet = pack('Na*Na*', strlen($oldname), $oldname, strlen($newname), $newname); - if (!$this->_send_sftp_packet(NET_SFTP_RENAME, $packet)) { - return false; - } - - $response = $this->_get_sftp_packet(); - if ($this->packet_type != NET_SFTP_STATUS) { - user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE); - return false; - } - - // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED - extract(unpack('Nstatus', $this->_string_shift($response, 4))); - if ($status != NET_SFTP_STATUS_OK) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length); - return false; - } - - return true; - } - - /** - * Parse Attributes - * - * See '7. File Attributes' of draft-ietf-secsh-filexfer-13 for more info. - * - * @param String $response - * @return Array - * @access private - */ - function _parseAttributes(&$response) - { - $attr = array(); - extract(unpack('Nflags', $this->_string_shift($response, 4))); - // SFTPv4+ have a type field (a byte) that follows the above flag field - foreach ($this->attributes as $key => $value) { - switch ($flags & $key) { - case NET_SFTP_ATTR_SIZE: // 0x00000001 - // size is represented by a 64-bit integer, so we perhaps ought to be doing the following: - // $attr['size'] = new Math_BigInteger($this->_string_shift($response, 8), 256); - // of course, you shouldn't be using Net_SFTP to transfer files that are in excess of 4GB - // (0xFFFFFFFF bytes), anyway. as such, we'll just represent all file sizes that are bigger than - // 4GB as being 4GB. - extract(unpack('Nupper/Nsize', $this->_string_shift($response, 8))); - if ($upper) { - $attr['size'] = 0xFFFFFFFF; - } else { - $attr['size'] = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size; - } - break; - case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only) - $attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8)); - break; - case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004 - $attr+= unpack('Npermissions', $this->_string_shift($response, 4)); - break; - case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008 - $attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8)); - break; - case NET_SFTP_ATTR_EXTENDED: // 0x80000000 - extract(unpack('Ncount', $this->_string_shift($response, 4))); - for ($i = 0; $i < $count; $i++) { - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $key = $this->_string_shift($response, $length); - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $attr[$key] = $this->_string_shift($response, $length); - } - } - } - return $attr; - } - - /** - * Sends SFTP Packets - * - * See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info. - * - * @param Integer $type - * @param String $data - * @see Net_SFTP::_get_sftp_packet() - * @see Net_SSH2::_send_channel_packet() - * @return Boolean - * @access private - */ - function _send_sftp_packet($type, $data) - { - $packet = $this->request_id !== false ? - pack('NCNa*', strlen($data) + 5, $type, $this->request_id, $data) : - pack('NCa*', strlen($data) + 1, $type, $data); - - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $result = $this->_send_channel_packet(NET_SFTP_CHANNEL, $packet); - $stop = strtok(microtime(), ' ') + strtok(''); - - if (defined('NET_SFTP_LOGGING')) { - $this->packet_type_log[] = '-> ' . $this->packet_types[$type] . - ' (' . round($stop - $start, 4) . 's)'; - if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) { - $this->packet_log[] = $data; - } - } - - return $result; - } - - /** - * Receives SFTP Packets - * - * See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info. - * - * Incidentally, the number of SSH_MSG_CHANNEL_DATA messages has no bearing on the number of SFTP packets present. - * There can be one SSH_MSG_CHANNEL_DATA messages containing two SFTP packets or there can be two SSH_MSG_CHANNEL_DATA - * messages containing one SFTP packet. - * - * @see Net_SFTP::_send_sftp_packet() - * @return String - * @access private - */ - function _get_sftp_packet() - { - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - - // SFTP packet length - while (strlen($this->packet_buffer) < 4) { - $temp = $this->_get_channel_packet(NET_SFTP_CHANNEL); - if (is_bool($temp)) { - $this->packet_type = false; - $this->packet_buffer = ''; - return false; - } - $this->packet_buffer.= $temp; - } - extract(unpack('Nlength', $this->_string_shift($this->packet_buffer, 4))); - $tempLength = $length; - $tempLength-= strlen($this->packet_buffer); - - // SFTP packet type and data payload - while ($tempLength > 0) { - $temp = $this->_get_channel_packet(NET_SFTP_CHANNEL); - if (is_bool($temp)) { - $this->packet_type = false; - $this->packet_buffer = ''; - return false; - } - $this->packet_buffer.= $temp; - $tempLength-= strlen($temp); - } - - $stop = strtok(microtime(), ' ') + strtok(''); - - $this->packet_type = ord($this->_string_shift($this->packet_buffer)); - - if ($this->request_id !== false) { - $this->_string_shift($this->packet_buffer, 4); // remove the request id - $length-= 5; // account for the request id and the packet type - } else { - $length-= 1; // account for the packet type - } - - $packet = $this->_string_shift($this->packet_buffer, $length); - - if (defined('NET_SFTP_LOGGING')) { - $this->packet_type_log[] = '<- ' . $this->packet_types[$this->packet_type] . - ' (' . round($stop - $start, 4) . 's)'; - if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) { - $this->packet_log[] = $packet; - } - } - - return $packet; - } - - /** - * Returns a log of the packets that have been sent and received. - * - * Returns a string if NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX, an array if NET_SFTP_LOGGING == NET_SFTP_LOG_SIMPLE and false if !defined('NET_SFTP_LOGGING') - * - * @access public - * @return String or Array - */ - function getSFTPLog() - { - if (!defined('NET_SFTP_LOGGING')) { - return false; - } - - switch (NET_SFTP_LOGGING) { - case NET_SFTP_LOG_COMPLEX: - return $this->_format_log($this->packet_log, $this->packet_type_log); - break; - //case NET_SFTP_LOG_SIMPLE: - default: - return $this->packet_type_log; - } - } - - /** - * Returns all errors - * - * @return String - * @access public - */ - function getSFTPErrors() - { - return $this->sftp_errors; - } - - /** - * Returns the last error - * - * @return String - * @access public - */ - function getLastSFTPError() - { - return $this->sftp_errors[count($this->sftp_errors) - 1]; - } - - /** - * Get supported SFTP versions - * - * @return Array - * @access public - */ - function getSupportedVersions() - { - $temp = array('version' => $this->version); - if (isset($this->extensions['versions'])) { - $temp['extensions'] = $this->extensions['versions']; - } - return $temp; - } - - /** - * Disconnect - * - * @param Integer $reason - * @return Boolean - * @access private - */ - function _disconnect($reason) - { - $this->pwd = false; - parent::_disconnect($reason); - } -} \ No newline at end of file diff --git a/library/phpsec/Net/SSH1.php b/library/phpsec/Net/SSH1.php deleted file mode 100644 index 7220ee4023..0000000000 --- a/library/phpsec/Net/SSH1.php +++ /dev/null @@ -1,1160 +0,0 @@ - - * login('username', 'password')) { - * exit('Login Failed'); - * } - * - * while (true) { - * echo $ssh->interactiveRead(); - * - * $read = array(STDIN); - * $write = $except = NULL; - * if (stream_select($read, $write, $except, 0)) { - * $ssh->interactiveWrite(fread(STDIN, 1)); - * } - * } - * ?> - * - * - * Here's another short example: - * - * login('username', 'password')) { - * exit('Login Failed'); - * } - * - * echo $ssh->exec('ls -la'); - * ?> - * - * - * More information on the SSHv1 specification can be found by reading - * {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}. - * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * @category Net - * @package Net_SSH1 - * @author Jim Wigginton - * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: SSH1.php,v 1.15 2010/03/22 22:01:38 terrafrost Exp $ - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Math_BigInteger - * - * Used to do RSA encryption. - */ -require_once('Math/BigInteger.php'); - -/** - * Include Crypt_Null - */ -//require_once('Crypt/Null.php'); - -/** - * Include Crypt_DES - */ -require_once('Crypt/DES.php'); - -/** - * Include Crypt_TripleDES - */ -require_once('Crypt/TripleDES.php'); - -/** - * Include Crypt_RC4 - */ -require_once('Crypt/RC4.php'); - -/** - * Include Crypt_Random - */ -require_once('Crypt/Random.php'); - -/**#@+ - * Protocol Flags - * - * @access private - */ -define('NET_SSH1_MSG_DISCONNECT', 1); -define('NET_SSH1_SMSG_PUBLIC_KEY', 2); -define('NET_SSH1_CMSG_SESSION_KEY', 3); -define('NET_SSH1_CMSG_USER', 4); -define('NET_SSH1_CMSG_AUTH_PASSWORD', 9); -define('NET_SSH1_CMSG_REQUEST_PTY', 10); -define('NET_SSH1_CMSG_EXEC_SHELL', 12); -define('NET_SSH1_CMSG_EXEC_CMD', 13); -define('NET_SSH1_SMSG_SUCCESS', 14); -define('NET_SSH1_SMSG_FAILURE', 15); -define('NET_SSH1_CMSG_STDIN_DATA', 16); -define('NET_SSH1_SMSG_STDOUT_DATA', 17); -define('NET_SSH1_SMSG_STDERR_DATA', 18); -define('NET_SSH1_SMSG_EXITSTATUS', 20); -define('NET_SSH1_CMSG_EXIT_CONFIRMATION', 33); -/**#@-*/ - -/**#@+ - * Encryption Methods - * - * @see Net_SSH1::getSupportedCiphers() - * @access public - */ -/** - * No encryption - * - * Not supported. - */ -define('NET_SSH1_CIPHER_NONE', 0); -/** - * IDEA in CFB mode - * - * Not supported. - */ -define('NET_SSH1_CIPHER_IDEA', 1); -/** - * DES in CBC mode - */ -define('NET_SSH1_CIPHER_DES', 2); -/** - * Triple-DES in CBC mode - * - * All implementations are required to support this - */ -define('NET_SSH1_CIPHER_3DES', 3); -/** - * TRI's Simple Stream encryption CBC - * - * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, does define it (see cipher.h), - * although it doesn't use it (see cipher.c) - */ -define('NET_SSH1_CIPHER_BROKEN_TSS', 4); -/** - * RC4 - * - * Not supported. - * - * @internal According to the SSH1 specs: - * - * "The first 16 bytes of the session key are used as the key for - * the server to client direction. The remaining 16 bytes are used - * as the key for the client to server direction. This gives - * independent 128-bit keys for each direction." - * - * This library currently only supports encryption when the same key is being used for both directions. This is - * because there's only one $crypto object. Two could be added ($encrypt and $decrypt, perhaps). - */ -define('NET_SSH1_CIPHER_RC4', 5); -/** - * Blowfish - * - * Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, defines it (see cipher.h) and - * uses it (see cipher.c) - */ -define('NET_SSH1_CIPHER_BLOWFISH', 6); -/**#@-*/ - -/**#@+ - * Authentication Methods - * - * @see Net_SSH1::getSupportedAuthentications() - * @access public - */ -/** - * .rhosts or /etc/hosts.equiv - */ -define('NET_SSH1_AUTH_RHOSTS', 1); -/** - * pure RSA authentication - */ -define('NET_SSH1_AUTH_RSA', 2); -/** - * password authentication - * - * This is the only method that is supported by this library. - */ -define('NET_SSH1_AUTH_PASSWORD', 3); -/** - * .rhosts with RSA host authentication - */ -define('NET_SSH1_AUTH_RHOSTS_RSA', 4); -/**#@-*/ - -/**#@+ - * Terminal Modes - * - * @link http://3sp.com/content/developer/maverick-net/docs/Maverick.SSH.PseudoTerminalModesMembers.html - * @access private - */ -define('NET_SSH1_TTY_OP_END', 0); -/**#@-*/ - -/** - * The Response Type - * - * @see Net_SSH1::_get_binary_packet() - * @access private - */ -define('NET_SSH1_RESPONSE_TYPE', 1); - -/** - * The Response Data - * - * @see Net_SSH1::_get_binary_packet() - * @access private - */ -define('NET_SSH1_RESPONSE_DATA', 2); - -/**#@+ - * Execution Bitmap Masks - * - * @see Net_SSH1::bitmap - * @access private - */ -define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001); -define('NET_SSH1_MASK_LOGIN', 0x00000002); -define('NET_SSH1_MASK_SHELL', 0x00000004); -/**#@-*/ - -/** - * Pure-PHP implementation of SSHv1. - * - * @author Jim Wigginton - * @version 0.1.0 - * @access public - * @package Net_SSH1 - */ -class Net_SSH1 { - /** - * The SSH identifier - * - * @var String - * @access private - */ - var $identifier = 'SSH-1.5-phpseclib'; - - /** - * The Socket Object - * - * @var Object - * @access private - */ - var $fsock; - - /** - * The cryptography object - * - * @var Object - * @access private - */ - var $crypto = false; - - /** - * Execution Bitmap - * - * The bits that are set reprsent functions that have been called already. This is used to determine - * if a requisite function has been successfully executed. If not, an error should be thrown. - * - * @var Integer - * @access private - */ - var $bitmap = 0; - - /** - * The Server Key Public Exponent - * - * Logged for debug purposes - * - * @see Net_SSH1::getServerKeyPublicExponent() - * @var String - * @access private - */ - var $server_key_public_exponent; - - /** - * The Server Key Public Modulus - * - * Logged for debug purposes - * - * @see Net_SSH1::getServerKeyPublicModulus() - * @var String - * @access private - */ - var $server_key_public_modulus; - - /** - * The Host Key Public Exponent - * - * Logged for debug purposes - * - * @see Net_SSH1::getHostKeyPublicExponent() - * @var String - * @access private - */ - var $host_key_public_exponent; - - /** - * The Host Key Public Modulus - * - * Logged for debug purposes - * - * @see Net_SSH1::getHostKeyPublicModulus() - * @var String - * @access private - */ - var $host_key_public_modulus; - - /** - * Supported Ciphers - * - * Logged for debug purposes - * - * @see Net_SSH1::getSupportedCiphers() - * @var Array - * @access private - */ - var $supported_ciphers = array( - NET_SSH1_CIPHER_NONE => 'No encryption', - NET_SSH1_CIPHER_IDEA => 'IDEA in CFB mode', - NET_SSH1_CIPHER_DES => 'DES in CBC mode', - NET_SSH1_CIPHER_3DES => 'Triple-DES in CBC mode', - NET_SSH1_CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC', - NET_SSH1_CIPHER_RC4 => 'RC4', - NET_SSH1_CIPHER_BLOWFISH => 'Blowfish' - ); - - /** - * Supported Authentications - * - * Logged for debug purposes - * - * @see Net_SSH1::getSupportedAuthentications() - * @var Array - * @access private - */ - var $supported_authentications = array( - NET_SSH1_AUTH_RHOSTS => '.rhosts or /etc/hosts.equiv', - NET_SSH1_AUTH_RSA => 'pure RSA authentication', - NET_SSH1_AUTH_PASSWORD => 'password authentication', - NET_SSH1_AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication' - ); - - /** - * Server Identification - * - * @see Net_SSH1::getServerIdentification() - * @var String - * @access private - */ - var $server_identification = ''; - - /** - * Default Constructor. - * - * Connects to an SSHv1 server - * - * @param String $host - * @param optional Integer $port - * @param optional Integer $timeout - * @param optional Integer $cipher - * @return Net_SSH1 - * @access public - */ - function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES) - { - $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout); - if (!$this->fsock) { - user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"), E_USER_NOTICE); - return; - } - - $this->server_identification = $init_line = fgets($this->fsock, 255); - if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) { - user_error('Can only connect to SSH servers', E_USER_NOTICE); - return; - } - if ($parts[1][0] != 1) { - user_error("Cannot connect to SSH $parts[1] servers", E_USER_NOTICE); - return; - } - - fputs($this->fsock, $this->identifier."\r\n"); - - $response = $this->_get_binary_packet(); - if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) { - user_error('Expected SSH_SMSG_PUBLIC_KEY', E_USER_NOTICE); - return; - } - - $anti_spoofing_cookie = $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 8); - - $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4); - - $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2)); - $server_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256); - $this->server_key_public_exponent = $server_key_public_exponent; - - $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2)); - $server_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256); - $this->server_key_public_modulus = $server_key_public_modulus; - - $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4); - - $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2)); - $host_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256); - $this->host_key_public_exponent = $host_key_public_exponent; - - $temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2)); - $host_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256); - $this->host_key_public_modulus = $host_key_public_modulus; - - $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4); - - // get a list of the supported ciphers - extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4))); - foreach ($this->supported_ciphers as $mask=>$name) { - if (($supported_ciphers_mask & (1 << $mask)) == 0) { - unset($this->supported_ciphers[$mask]); - } - } - - // get a list of the supported authentications - extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4))); - foreach ($this->supported_authentications as $mask=>$name) { - if (($supported_authentications_mask & (1 << $mask)) == 0) { - unset($this->supported_authentications[$mask]); - } - } - - $session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie)); - - $session_key = ''; - for ($i = 0; $i < 32; $i++) { - $session_key.= chr(crypt_random(0, 255)); - } - $double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0)); - - if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) { - $double_encrypted_session_key = $this->_rsa_crypt( - $double_encrypted_session_key, - array( - $server_key_public_exponent, - $server_key_public_modulus - ) - ); - $double_encrypted_session_key = $this->_rsa_crypt( - $double_encrypted_session_key, - array( - $host_key_public_exponent, - $host_key_public_modulus - ) - ); - } else { - $double_encrypted_session_key = $this->_rsa_crypt( - $double_encrypted_session_key, - array( - $host_key_public_exponent, - $host_key_public_modulus - ) - ); - $double_encrypted_session_key = $this->_rsa_crypt( - $double_encrypted_session_key, - array( - $server_key_public_exponent, - $server_key_public_modulus - ) - ); - } - - $cipher = isset($this->supported_ciphers[$cipher]) ? $cipher : NET_SSH1_CIPHER_3DES; - $data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_SESSION_KEY', E_USER_NOTICE); - return; - } - - switch ($cipher) { - //case NET_SSH1_CIPHER_NONE: - // $this->crypto = new Crypt_Null(); - // break; - case NET_SSH1_CIPHER_DES: - $this->crypto = new Crypt_DES(); - $this->crypto->disablePadding(); - $this->crypto->enableContinuousBuffer(); - $this->crypto->setKey(substr($session_key, 0, 8)); - break; - case NET_SSH1_CIPHER_3DES: - $this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC); - $this->crypto->disablePadding(); - $this->crypto->enableContinuousBuffer(); - $this->crypto->setKey(substr($session_key, 0, 24)); - break; - //case NET_SSH1_CIPHER_RC4: - // $this->crypto = new Crypt_RC4(); - // $this->crypto->enableContinuousBuffer(); - // $this->crypto->setKey(substr($session_key, 0, 16)); - // break; - } - - $response = $this->_get_binary_packet(); - - if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) { - user_error('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE); - return; - } - - $this->bitmap = NET_SSH1_MASK_CONSTRUCTOR; - } - - /** - * Login - * - * @param String $username - * @param optional String $password - * @return Boolean - * @access public - */ - function login($username, $password = '') - { - if (!($this->bitmap & NET_SSH1_MASK_CONSTRUCTOR)) { - return false; - } - - $data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_USER', E_USER_NOTICE); - return false; - } - - $response = $this->_get_binary_packet(); - - if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) { - $this->bitmap |= NET_SSH1_MASK_LOGIN; - return true; - } else if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) { - user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE', E_USER_NOTICE); - return false; - } - - $data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_AUTH_PASSWORD', E_USER_NOTICE); - return false; - } - - $response = $this->_get_binary_packet(); - - if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) { - $this->bitmap |= NET_SSH1_MASK_LOGIN; - return true; - } else if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) { - return false; - } else { - user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE', E_USER_NOTICE); - return false; - } - } - - /** - * Executes a command on a non-interactive shell, returns the output, and quits. - * - * An SSH1 server will close the connection after a command has been executed on a non-interactive shell. SSH2 - * servers don't, however, this isn't an SSH2 client. The way this works, on the server, is by initiating a - * shell with the -s option, as discussed in the following links: - * - * {@link http://www.faqs.org/docs/bashman/bashref_65.html http://www.faqs.org/docs/bashman/bashref_65.html} - * {@link http://www.faqs.org/docs/bashman/bashref_62.html http://www.faqs.org/docs/bashman/bashref_62.html} - * - * To execute further commands, a new Net_SSH1 object will need to be created. - * - * Returns false on failure and the output, otherwise. - * - * @see Net_SSH1::interactiveRead() - * @see Net_SSH1::interactiveWrite() - * @param String $cmd - * @return mixed - * @access public - */ - function exec($cmd) - { - if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) { - user_error('Operation disallowed prior to login()', E_USER_NOTICE); - return false; - } - - // connect using the sample parameters in protocol-1.5.txt. - // according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text - // terminal is a command line interpreter or shell". thus, opening a terminal session to run the shell. - $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_REQUEST_PTY', E_USER_NOTICE); - return false; - } - - $response = $this->_get_binary_packet(); - - if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) { - user_error('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE); - return false; - } - - $data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_EXEC_CMD', E_USER_NOTICE); - return false; - } - - $output = ''; - $response = $this->_get_binary_packet(); - - do { - $output.= substr($response[NET_SSH1_RESPONSE_DATA], 4); - $response = $this->_get_binary_packet(); - } while ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS); - - $data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION); - - // i don't think it's really all that important if this packet gets sent or not. - $this->_send_binary_packet($data); - - fclose($this->fsock); - - // reset the execution bitmap - a new Net_SSH1 object needs to be created. - $this->bitmap = 0; - - return $output; - } - - /** - * Creates an interactive shell - * - * @see Net_SSH1::interactiveRead() - * @see Net_SSH1::interactiveWrite() - * @return Boolean - * @access private - */ - function _initShell() - { - $data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_REQUEST_PTY', E_USER_NOTICE); - return false; - } - - $response = $this->_get_binary_packet(); - - if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) { - user_error('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE); - return false; - } - - $data = pack('C', NET_SSH1_CMSG_EXEC_SHELL); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_EXEC_SHELL', E_USER_NOTICE); - return false; - } - - $this->bitmap |= NET_SSH1_MASK_SHELL; - - //stream_set_blocking($this->fsock, 0); - - return true; - } - - /** - * Inputs a command into an interactive shell. - * - * @see Net_SSH1::interactiveRead() - * @param String $cmd - * @return Boolean - * @access public - */ - function interactiveWrite($cmd) - { - if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) { - user_error('Operation disallowed prior to login()', E_USER_NOTICE); - return false; - } - - if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) { - user_error('Unable to initiate an interactive shell session', E_USER_NOTICE); - return false; - } - - $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd); - - if (!$this->_send_binary_packet($data)) { - user_error('Error sending SSH_CMSG_STDIN', E_USER_NOTICE); - return false; - } - - return true; - } - - /** - * Reads the output of an interactive shell. - * - * Requires PHP 4.3.0 or later due to the use of the stream_select() function. If you see crap, - * you're seeing ANSI escape codes. According to - * {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT - * does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user, - * there's not going to be much recourse. - * - * @see Net_SSH1::interactiveRead() - * @return String - * @access public - */ - function interactiveRead() - { - if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) { - user_error('Operation disallowed prior to login()', E_USER_NOTICE); - return false; - } - - if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) { - user_error('Unable to initiate an interactive shell session', E_USER_NOTICE); - return false; - } - - $read = array($this->fsock); - $write = $except = null; - if (stream_select($read, $write, $except, 0)) { - $response = $this->_get_binary_packet(); - return substr($response[NET_SSH1_RESPONSE_DATA], 4); - } else { - return ''; - } - } - - /** - * Disconnect - * - * @access public - */ - function disconnect() - { - $this->_disconnect(); - } - - /** - * Destructor. - * - * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call - * disconnect(). - * - * @access public - */ - function __destruct() - { - $this->_disconnect(); - } - - /** - * Disconnect - * - * @param String $msg - * @access private - */ - function _disconnect($msg = 'Client Quit') - { - if ($this->bitmap) { - $data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg); - $this->_send_binary_packet($data); - fclose($this->fsock); - $this->bitmap = 0; - } - } - - /** - * Gets Binary Packets - * - * See 'The Binary Packet Protocol' of protocol-1.5.txt for more info. - * - * Also, this function could be improved upon by adding detection for the following exploit: - * http://www.securiteam.com/securitynews/5LP042K3FY.html - * - * @see Net_SSH1::_send_binary_packet() - * @return Array - * @access private - */ - function _get_binary_packet() - { - if (feof($this->fsock)) { - //user_error('connection closed prematurely', E_USER_NOTICE); - return false; - } - - $temp = unpack('Nlength', fread($this->fsock, 4)); - - $padding_length = 8 - ($temp['length'] & 7); - $length = $temp['length'] + $padding_length; - - $raw = fread($this->fsock, $length); - - if ($this->crypto !== false) { - $raw = $this->crypto->decrypt($raw); - } - - $padding = substr($raw, 0, $padding_length); - $type = $raw[$padding_length]; - $data = substr($raw, $padding_length + 1, -4); - - $temp = unpack('Ncrc', substr($raw, -4)); - - //if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) { - // user_error('Bad CRC in packet from server', E_USER_NOTICE); - // return false; - //} - - return array( - NET_SSH1_RESPONSE_TYPE => ord($type), - NET_SSH1_RESPONSE_DATA => $data - ); - } - - /** - * Sends Binary Packets - * - * Returns true on success, false on failure. - * - * @see Net_SSH1::_get_binary_packet() - * @param String $data - * @return Boolean - * @access private - */ - function _send_binary_packet($data) { - if (feof($this->fsock)) { - //user_error('connection closed prematurely', E_USER_NOTICE); - return false; - } - - $length = strlen($data) + 4; - - $padding_length = 8 - ($length & 7); - $padding = ''; - for ($i = 0; $i < $padding_length; $i++) { - $padding.= chr(crypt_random(0, 255)); - } - - $data = $padding . $data; - $data.= pack('N', $this->_crc($data)); - - if ($this->crypto !== false) { - $data = $this->crypto->encrypt($data); - } - - $packet = pack('Na*', $length, $data); - - return strlen($packet) == fputs($this->fsock, $packet); - } - - /** - * Cyclic Redundancy Check (CRC) - * - * PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so - * we've reimplemented it. A more detailed discussion of the differences can be found after - * $crc_lookup_table's initialization. - * - * @see Net_SSH1::_get_binary_packet() - * @see Net_SSH1::_send_binary_packet() - * @param String $data - * @return Integer - * @access private - */ - function _crc($data) - { - static $crc_lookup_table = array( - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, - 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, - 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, - 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, - 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, - 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, - 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, - 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, - 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, - 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, - 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, - 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, - 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, - 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, - 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, - 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, - 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, - 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D - ); - - // For this function to yield the same output as PHP's crc32 function, $crc would have to be - // set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is. - $crc = 0x00000000; - $length = strlen($data); - - for ($i=0;$i<$length;$i++) { - // We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all - // be zero. PHP, unfortunately, doesn't always do this. 0x80000000 >> 8, as an example, - // yields 0xFF800000 - not 0x00800000. The following link elaborates: - // http://www.php.net/manual/en/language.operators.bitwise.php#57281 - $crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])]; - } - - // In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with - // 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would. - return $crc; - } - - /** - * String Shift - * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @return String - * @access private - */ - function _string_shift(&$string, $index = 1) - { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; - } - - /** - * RSA Encrypt - * - * Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e - * should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1. Could just make anything that - * calls this call modexp, instead, but I think this makes things clearer, maybe... - * - * @see Net_SSH1::Net_SSH1() - * @param Math_BigInteger $m - * @param Array $key - * @return Math_BigInteger - * @access private - */ - function _rsa_crypt($m, $key) - { - /* - if (!class_exists('Crypt_RSA')) { - require_once('Crypt/RSA.php'); - } - - $rsa = new Crypt_RSA(); - $rsa->loadKey($key, CRYPT_RSA_PUBLIC_FORMAT_RAW); - $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1); - return $rsa->encrypt($m); - */ - - // To quote from protocol-1.5.txt: - // The most significant byte (which is only partial as the value must be - // less than the public modulus, which is never a power of two) is zero. - // - // The next byte contains the value 2 (which stands for public-key - // encrypted data in the PKCS standard [PKCS#1]). Then, there are non- - // zero random bytes to fill any unused space, a zero byte, and the data - // to be encrypted in the least significant bytes, the last byte of the - // data in the least significant byte. - - // Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation", - // under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL: - // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf - $temp = chr(0) . chr(2); - $modulus = $key[1]->toBytes(); - $length = strlen($modulus) - strlen($m) - 3; - for ($i = 0; $i < $length; $i++) { - $temp.= chr(crypt_random(1, 255)); - } - $temp.= chr(0) . $m; - - $m = new Math_BigInteger($temp, 256); - $m = $m->modPow($key[0], $key[1]); - - return $m->toBytes(); - } - - /** - * Return the server key public exponent - * - * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead, - * the raw bytes. This behavior is similar to PHP's md5() function. - * - * @param optional Boolean $raw_output - * @return String - * @access public - */ - function getServerKeyPublicExponent($raw_output = false) - { - return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString(); - } - - /** - * Return the server key public modulus - * - * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead, - * the raw bytes. This behavior is similar to PHP's md5() function. - * - * @param optional Boolean $raw_output - * @return String - * @access public - */ - function getServerKeyPublicModulus($raw_output = false) - { - return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString(); - } - - /** - * Return the host key public exponent - * - * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead, - * the raw bytes. This behavior is similar to PHP's md5() function. - * - * @param optional Boolean $raw_output - * @return String - * @access public - */ - function getHostKeyPublicExponent($raw_output = false) - { - return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString(); - } - - /** - * Return the host key public modulus - * - * Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead, - * the raw bytes. This behavior is similar to PHP's md5() function. - * - * @param optional Boolean $raw_output - * @return String - * @access public - */ - function getHostKeyPublicModulus($raw_output = false) - { - return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString(); - } - - /** - * Return a list of ciphers supported by SSH1 server. - * - * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output - * is set to true, returns, instead, an array of constants. ie. instead of array('Triple-DES in CBC mode'), you'll - * get array(NET_SSH1_CIPHER_3DES). - * - * @param optional Boolean $raw_output - * @return Array - * @access public - */ - function getSupportedCiphers($raw_output = false) - { - return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers); - } - - /** - * Return a list of authentications supported by SSH1 server. - * - * Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output - * is set to true, returns, instead, an array of constants. ie. instead of array('password authentication'), you'll - * get array(NET_SSH1_AUTH_PASSWORD). - * - * @param optional Boolean $raw_output - * @return Array - * @access public - */ - function getSupportedAuthentications($raw_output = false) - { - return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications); - } - - /** - * Return the server identification. - * - * @return String - * @access public - */ - function getServerIdentification() - { - return rtrim($this->server_identification); - } -} -?> \ No newline at end of file diff --git a/library/phpsec/Net/SSH2.php b/library/phpsec/Net/SSH2.php deleted file mode 100644 index aa9f6dbe52..0000000000 --- a/library/phpsec/Net/SSH2.php +++ /dev/null @@ -1,2302 +0,0 @@ - - * login('username', 'password')) { - * exit('Login Failed'); - * } - * - * echo $ssh->exec('pwd'); - * echo $ssh->exec('ls -la'); - * ?> - * - * - * - * setPassword('whatever'); - * $key->loadKey(file_get_contents('privatekey')); - * - * $ssh = new Net_SSH2('www.domain.tld'); - * if (!$ssh->login('username', $key)) { - * exit('Login Failed'); - * } - * - * echo $ssh->exec('pwd'); - * echo $ssh->exec('ls -la'); - * ?> - * - * - * LICENSE: This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * @category Net - * @package Net_SSH2 - * @author Jim Wigginton - * @copyright MMVII Jim Wigginton - * @license http://www.gnu.org/licenses/lgpl.txt - * @version $Id: SSH2.php,v 1.46 2010/04/27 21:29:36 terrafrost Exp $ - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include Math_BigInteger - * - * Used to do Diffie-Hellman key exchange and DSA/RSA signature verification. - */ -require_once('Math/BigInteger.php'); - -/** - * Include Crypt_Random - */ -require_once('Crypt/Random.php'); - -/** - * Include Crypt_Hash - */ -require_once('Crypt/Hash.php'); - -/** - * Include Crypt_TripleDES - */ -require_once('Crypt/TripleDES.php'); - -/** - * Include Crypt_RC4 - */ -require_once('Crypt/RC4.php'); - -/** - * Include Crypt_AES - */ -require_once('Crypt/AES.php'); - -/**#@+ - * Execution Bitmap Masks - * - * @see Net_SSH2::bitmap - * @access private - */ -define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001); -define('NET_SSH2_MASK_LOGIN', 0x00000002); -/**#@-*/ - -/**#@+ - * Channel constants - * - * RFC4254 refers not to client and server channels but rather to sender and recipient channels. we don't refer - * to them in that way because RFC4254 toggles the meaning. the client sends a SSH_MSG_CHANNEL_OPEN message with - * a sender channel and the server sends a SSH_MSG_CHANNEL_OPEN_CONFIRMATION in response, with a sender and a - * recepient channel. at first glance, you might conclude that SSH_MSG_CHANNEL_OPEN_CONFIRMATION's sender channel - * would be the same thing as SSH_MSG_CHANNEL_OPEN's sender channel, but it's not, per this snipet: - * The 'recipient channel' is the channel number given in the original - * open request, and 'sender channel' is the channel number allocated by - * the other side. - * - * @see Net_SSH2::_send_channel_packet() - * @see Net_SSH2::_get_channel_packet() - * @access private - */ -define('NET_SSH2_CHANNEL_EXEC', 0); // PuTTy uses 0x100 -/**#@-*/ - -/**#@+ - * @access public - * @see Net_SSH2::getLog() - */ -/** - * Returns the message numbers - */ -define('NET_SSH2_LOG_SIMPLE', 1); -/** - * Returns the message content - */ -define('NET_SSH2_LOG_COMPLEX', 2); -/**#@-*/ - -/** - * Pure-PHP implementation of SSHv2. - * - * @author Jim Wigginton - * @version 0.1.0 - * @access public - * @package Net_SSH2 - */ -class Net_SSH2 { - /** - * The SSH identifier - * - * @var String - * @access private - */ - var $identifier = 'SSH-2.0-phpseclib_0.2'; - - /** - * The Socket Object - * - * @var Object - * @access private - */ - var $fsock; - - /** - * Execution Bitmap - * - * The bits that are set reprsent functions that have been called already. This is used to determine - * if a requisite function has been successfully executed. If not, an error should be thrown. - * - * @var Integer - * @access private - */ - var $bitmap = 0; - - /** - * Error information - * - * @see Net_SSH2::getErrors() - * @see Net_SSH2::getLastError() - * @var String - * @access private - */ - var $errors = array(); - - /** - * Server Identifier - * - * @see Net_SSH2::getServerIdentification() - * @var String - * @access private - */ - var $server_identifier = ''; - - /** - * Key Exchange Algorithms - * - * @see Net_SSH2::getKexAlgorithims() - * @var Array - * @access private - */ - var $kex_algorithms; - - /** - * Server Host Key Algorithms - * - * @see Net_SSH2::getServerHostKeyAlgorithms() - * @var Array - * @access private - */ - var $server_host_key_algorithms; - - /** - * Encryption Algorithms: Client to Server - * - * @see Net_SSH2::getEncryptionAlgorithmsClient2Server() - * @var Array - * @access private - */ - var $encryption_algorithms_client_to_server; - - /** - * Encryption Algorithms: Server to Client - * - * @see Net_SSH2::getEncryptionAlgorithmsServer2Client() - * @var Array - * @access private - */ - var $encryption_algorithms_server_to_client; - - /** - * MAC Algorithms: Client to Server - * - * @see Net_SSH2::getMACAlgorithmsClient2Server() - * @var Array - * @access private - */ - var $mac_algorithms_client_to_server; - - /** - * MAC Algorithms: Server to Client - * - * @see Net_SSH2::getMACAlgorithmsServer2Client() - * @var Array - * @access private - */ - var $mac_algorithms_server_to_client; - - /** - * Compression Algorithms: Client to Server - * - * @see Net_SSH2::getCompressionAlgorithmsClient2Server() - * @var Array - * @access private - */ - var $compression_algorithms_client_to_server; - - /** - * Compression Algorithms: Server to Client - * - * @see Net_SSH2::getCompressionAlgorithmsServer2Client() - * @var Array - * @access private - */ - var $compression_algorithms_server_to_client; - - /** - * Languages: Server to Client - * - * @see Net_SSH2::getLanguagesServer2Client() - * @var Array - * @access private - */ - var $languages_server_to_client; - - /** - * Languages: Client to Server - * - * @see Net_SSH2::getLanguagesClient2Server() - * @var Array - * @access private - */ - var $languages_client_to_server; - - /** - * Block Size for Server to Client Encryption - * - * "Note that the length of the concatenation of 'packet_length', - * 'padding_length', 'payload', and 'random padding' MUST be a multiple - * of the cipher block size or 8, whichever is larger. This constraint - * MUST be enforced, even when using stream ciphers." - * - * -- http://tools.ietf.org/html/rfc4253#section-6 - * - * @see Net_SSH2::Net_SSH2() - * @see Net_SSH2::_send_binary_packet() - * @var Integer - * @access private - */ - var $encrypt_block_size = 8; - - /** - * Block Size for Client to Server Encryption - * - * @see Net_SSH2::Net_SSH2() - * @see Net_SSH2::_get_binary_packet() - * @var Integer - * @access private - */ - var $decrypt_block_size = 8; - - /** - * Server to Client Encryption Object - * - * @see Net_SSH2::_get_binary_packet() - * @var Object - * @access private - */ - var $decrypt = false; - - /** - * Client to Server Encryption Object - * - * @see Net_SSH2::_send_binary_packet() - * @var Object - * @access private - */ - var $encrypt = false; - - /** - * Client to Server HMAC Object - * - * @see Net_SSH2::_send_binary_packet() - * @var Object - * @access private - */ - var $hmac_create = false; - - /** - * Server to Client HMAC Object - * - * @see Net_SSH2::_get_binary_packet() - * @var Object - * @access private - */ - var $hmac_check = false; - - /** - * Size of server to client HMAC - * - * We need to know how big the HMAC will be for the server to client direction so that we know how many bytes to read. - * For the client to server side, the HMAC object will make the HMAC as long as it needs to be. All we need to do is - * append it. - * - * @see Net_SSH2::_get_binary_packet() - * @var Integer - * @access private - */ - var $hmac_size = false; - - /** - * Server Public Host Key - * - * @see Net_SSH2::getServerPublicHostKey() - * @var String - * @access private - */ - var $server_public_host_key; - - /** - * Session identifer - * - * "The exchange hash H from the first key exchange is additionally - * used as the session identifier, which is a unique identifier for - * this connection." - * - * -- http://tools.ietf.org/html/rfc4253#section-7.2 - * - * @see Net_SSH2::_key_exchange() - * @var String - * @access private - */ - var $session_id = false; - - /** - * Message Numbers - * - * @see Net_SSH2::Net_SSH2() - * @var Array - * @access private - */ - var $message_numbers = array(); - - /** - * Disconnection Message 'reason codes' defined in RFC4253 - * - * @see Net_SSH2::Net_SSH2() - * @var Array - * @access private - */ - var $disconnect_reasons = array(); - - /** - * SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254 - * - * @see Net_SSH2::Net_SSH2() - * @var Array - * @access private - */ - var $channel_open_failure_reasons = array(); - - /** - * Terminal Modes - * - * @link http://tools.ietf.org/html/rfc4254#section-8 - * @see Net_SSH2::Net_SSH2() - * @var Array - * @access private - */ - var $terminal_modes = array(); - - /** - * SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes - * - * @link http://tools.ietf.org/html/rfc4254#section-5.2 - * @see Net_SSH2::Net_SSH2() - * @var Array - * @access private - */ - var $channel_extended_data_type_codes = array(); - - /** - * Send Sequence Number - * - * See 'Section 6.4. Data Integrity' of rfc4253 for more info. - * - * @see Net_SSH2::_send_binary_packet() - * @var Integer - * @access private - */ - var $send_seq_no = 0; - - /** - * Get Sequence Number - * - * See 'Section 6.4. Data Integrity' of rfc4253 for more info. - * - * @see Net_SSH2::_get_binary_packet() - * @var Integer - * @access private - */ - var $get_seq_no = 0; - - /** - * Server Channels - * - * Maps client channels to server channels - * - * @see Net_SSH2::_get_channel_packet() - * @see Net_SSH2::exec() - * @var Array - * @access private - */ - var $server_channels = array(); - - /** - * Channel Buffers - * - * If a client requests a packet from one channel but receives two packets from another those packets should - * be placed in a buffer - * - * @see Net_SSH2::_get_channel_packet() - * @see Net_SSH2::exec() - * @var Array - * @access private - */ - var $channel_buffers = array(); - - /** - * Channel Status - * - * Contains the type of the last sent message - * - * @see Net_SSH2::_get_channel_packet() - * @var Array - * @access private - */ - var $channel_status = array(); - - /** - * Packet Size - * - * Maximum packet size indexed by channel - * - * @see Net_SSH2::_send_channel_packet() - * @var Array - * @access private - */ - var $packet_size_client_to_server = array(); - - /** - * Message Number Log - * - * @see Net_SSH2::getLog() - * @var Array - * @access private - */ - var $message_number_log = array(); - - /** - * Message Log - * - * @see Net_SSH2::getLog() - * @var Array - * @access private - */ - var $message_log = array(); - - /** - * The Window Size - * - * Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 4GB) - * - * @var Integer - * @see Net_SSH2::_send_channel_packet() - * @see Net_SSH2::exec() - * @access private - */ - var $window_size = 0x7FFFFFFF; - - /** - * Window size - * - * Window size indexed by channel - * - * @see Net_SSH2::_send_channel_packet() - * @var Array - * @access private - */ - var $window_size_client_to_server = array(); - - /** - * Server signature - * - * Verified against $this->session_id - * - * @see Net_SSH2::getServerPublicHostKey() - * @var String - * @access private - */ - var $signature = ''; - - /** - * Server signature format - * - * ssh-rsa or ssh-dss. - * - * @see Net_SSH2::getServerPublicHostKey() - * @var String - * @access private - */ - var $signature_format = ''; - - /** - * Default Constructor. - * - * Connects to an SSHv2 server - * - * @param String $host - * @param optional Integer $port - * @param optional Integer $timeout - * @return Net_SSH2 - * @access public - */ - function Net_SSH2($host, $port = 22, $timeout = 10) - { - $this->message_numbers = array( - 1 => 'NET_SSH2_MSG_DISCONNECT', - 2 => 'NET_SSH2_MSG_IGNORE', - 3 => 'NET_SSH2_MSG_UNIMPLEMENTED', - 4 => 'NET_SSH2_MSG_DEBUG', - 5 => 'NET_SSH2_MSG_SERVICE_REQUEST', - 6 => 'NET_SSH2_MSG_SERVICE_ACCEPT', - 20 => 'NET_SSH2_MSG_KEXINIT', - 21 => 'NET_SSH2_MSG_NEWKEYS', - 30 => 'NET_SSH2_MSG_KEXDH_INIT', - 31 => 'NET_SSH2_MSG_KEXDH_REPLY', - 50 => 'NET_SSH2_MSG_USERAUTH_REQUEST', - 51 => 'NET_SSH2_MSG_USERAUTH_FAILURE', - 52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS', - 53 => 'NET_SSH2_MSG_USERAUTH_BANNER', - - 80 => 'NET_SSH2_MSG_GLOBAL_REQUEST', - 81 => 'NET_SSH2_MSG_REQUEST_SUCCESS', - 82 => 'NET_SSH2_MSG_REQUEST_FAILURE', - 90 => 'NET_SSH2_MSG_CHANNEL_OPEN', - 91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION', - 92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE', - 93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST', - 94 => 'NET_SSH2_MSG_CHANNEL_DATA', - 95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA', - 96 => 'NET_SSH2_MSG_CHANNEL_EOF', - 97 => 'NET_SSH2_MSG_CHANNEL_CLOSE', - 98 => 'NET_SSH2_MSG_CHANNEL_REQUEST', - 99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS', - 100 => 'NET_SSH2_MSG_CHANNEL_FAILURE' - ); - $this->disconnect_reasons = array( - 1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT', - 2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR', - 3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED', - 4 => 'NET_SSH2_DISCONNECT_RESERVED', - 5 => 'NET_SSH2_DISCONNECT_MAC_ERROR', - 6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR', - 7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE', - 8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED', - 9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE', - 10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST', - 11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION', - 12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS', - 13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER', - 14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE', - 15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME' - ); - $this->channel_open_failure_reasons = array( - 1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED' - ); - $this->terminal_modes = array( - 0 => 'NET_SSH2_TTY_OP_END' - ); - $this->channel_extended_data_type_codes = array( - 1 => 'NET_SSH2_EXTENDED_DATA_STDERR' - ); - - $this->_define_array( - $this->message_numbers, - $this->disconnect_reasons, - $this->channel_open_failure_reasons, - $this->terminal_modes, - $this->channel_extended_data_type_codes, - array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'), - array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK') - ); - - $this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout); - if (!$this->fsock) { - user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"), E_USER_NOTICE); - return; - } - - /* According to the SSH2 specs, - - "The server MAY send other lines of data before sending the version - string. Each line SHOULD be terminated by a Carriage Return and Line - Feed. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded - in ISO-10646 UTF-8 [RFC3629] (language is not specified). Clients - MUST be able to process such lines." */ - $temp = ''; - $extra = ''; - while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) { - if (substr($temp, -2) == "\r\n") { - $extra.= $temp; - $temp = ''; - } - $temp.= fgets($this->fsock, 255); - } - - $ext = array(); - if (extension_loaded('mcrypt')) { - $ext[] = 'mcrypt'; - } - if (extension_loaded('gmp')) { - $ext[] = 'gmp'; - } else if (extension_loaded('bcmath')) { - $ext[] = 'bcmath'; - } - - if (!empty($ext)) { - $this->identifier.= ' (' . implode(', ', $ext) . ')'; - } - - if (defined('NET_SSH2_LOGGING')) { - $this->message_number_log[] = '<-'; - $this->message_number_log[] = '->'; - - if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { - $this->message_log[] = $temp; - $this->message_log[] = $this->identifier . "\r\n"; - } - } - - $this->server_identifier = trim($temp, "\r\n"); - if (!empty($extra)) { - $this->errors[] = utf8_decode($extra); - } - - if ($matches[1] != '1.99' && $matches[1] != '2.0') { - user_error("Cannot connect to SSH $matches[1] servers", E_USER_NOTICE); - return; - } - - fputs($this->fsock, $this->identifier . "\r\n"); - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server', E_USER_NOTICE); - return; - } - - if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) { - user_error('Expected SSH_MSG_KEXINIT', E_USER_NOTICE); - return; - } - - if (!$this->_key_exchange($response)) { - return; - } - - $this->bitmap = NET_SSH2_MASK_CONSTRUCTOR; - } - - /** - * Key Exchange - * - * @param String $kexinit_payload_server - * @access private - */ - function _key_exchange($kexinit_payload_server) - { - static $kex_algorithms = array( - 'diffie-hellman-group1-sha1', // REQUIRED - 'diffie-hellman-group14-sha1' // REQUIRED - ); - - static $server_host_key_algorithms = array( - 'ssh-rsa', // RECOMMENDED sign Raw RSA Key - 'ssh-dss' // REQUIRED sign Raw DSS Key - ); - - static $encryption_algorithms = array( - // from : - 'arcfour256', - 'arcfour128', - - 'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key - - 'aes128-cbc', // RECOMMENDED AES with a 128-bit key - 'aes192-cbc', // OPTIONAL AES with a 192-bit key - 'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key - - // from : - 'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key - 'aes192-ctr', // RECOMMENDED AES with 192-bit key - 'aes256-ctr', // RECOMMENDED AES with 256-bit key - '3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode - - '3des-cbc', // REQUIRED three-key 3DES in CBC mode - 'none' // OPTIONAL no encryption; NOT RECOMMENDED - ); - - static $mac_algorithms = array( - 'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20) - 'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20) - 'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16) - 'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16) - 'none' // OPTIONAL no MAC; NOT RECOMMENDED - ); - - static $compression_algorithms = array( - 'none' // REQUIRED no compression - //'zlib' // OPTIONAL ZLIB (LZ77) compression - ); - - static $str_kex_algorithms, $str_server_host_key_algorithms, - $encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client, - $encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server; - - if (empty($str_kex_algorithms)) { - $str_kex_algorithms = implode(',', $kex_algorithms); - $str_server_host_key_algorithms = implode(',', $server_host_key_algorithms); - $encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms); - $mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms); - $compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms); - } - - $client_cookie = ''; - for ($i = 0; $i < 16; $i++) { - $client_cookie.= chr(crypt_random(0, 255)); - } - - $response = $kexinit_payload_server; - $this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT) - $server_cookie = $this->_string_shift($response, 16); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length'])); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length'])); - - extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1))); - $first_kex_packet_follows = $first_kex_packet_follows != 0; - - // the sending of SSH2_MSG_KEXINIT could go in one of two places. this is the second place. - $kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN', - NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms, - strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server), - $encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client, - strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client), - $mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server, - strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '', - 0, 0 - ); - - if (!$this->_send_binary_packet($kexinit_payload_client)) { - return false; - } - // here ends the second place. - - // we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange - for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++); - if ($i == count($encryption_algorithms)) { - user_error('No compatible server to client encryption algorithms found', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - // we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the - // diffie-hellman key exchange as fast as possible - $decrypt = $encryption_algorithms[$i]; - switch ($decrypt) { - case '3des-cbc': - case '3des-ctr': - $decryptKeyLength = 24; // eg. 192 / 8 - break; - case 'aes256-cbc': - case 'aes256-ctr': - $decryptKeyLength = 32; // eg. 256 / 8 - break; - case 'aes192-cbc': - case 'aes192-ctr': - $decryptKeyLength = 24; // eg. 192 / 8 - break; - case 'aes128-cbc': - case 'aes128-ctr': - $decryptKeyLength = 16; // eg. 128 / 8 - break; - case 'arcfour': - case 'arcfour128': - $decryptKeyLength = 16; // eg. 128 / 8 - break; - case 'arcfour256': - $decryptKeyLength = 32; // eg. 128 / 8 - break; - case 'none'; - $decryptKeyLength = 0; - } - - for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++); - if ($i == count($encryption_algorithms)) { - user_error('No compatible client to server encryption algorithms found', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $encrypt = $encryption_algorithms[$i]; - switch ($encrypt) { - case '3des-cbc': - case '3des-ctr': - $encryptKeyLength = 24; - break; - case 'aes256-cbc': - case 'aes256-ctr': - $encryptKeyLength = 32; - break; - case 'aes192-cbc': - case 'aes192-ctr': - $encryptKeyLength = 24; - break; - case 'aes128-cbc': - case 'aes128-ctr': - $encryptKeyLength = 16; - break; - case 'arcfour': - case 'arcfour128': - $encryptKeyLength = 16; - break; - case 'arcfour256': - $encryptKeyLength = 32; - break; - case 'none'; - $encryptKeyLength = 0; - } - - $keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength; - - // through diffie-hellman key exchange a symmetric key is obtained - for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++); - if ($i == count($kex_algorithms)) { - user_error('No compatible key exchange algorithms found', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - switch ($kex_algorithms[$i]) { - // see http://tools.ietf.org/html/rfc2409#section-6.2 and - // http://tools.ietf.org/html/rfc2412, appendex E - case 'diffie-hellman-group1-sha1': - $p = pack('H256', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . - '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . - '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . - 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF'); - $keyLength = $keyLength < 160 ? $keyLength : 160; - $hash = 'sha1'; - break; - // see http://tools.ietf.org/html/rfc3526#section-3 - case 'diffie-hellman-group14-sha1': - $p = pack('H512', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' . - '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' . - '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' . - 'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' . - '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' . - '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' . - 'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' . - '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF'); - $keyLength = $keyLength < 160 ? $keyLength : 160; - $hash = 'sha1'; - } - - $p = new Math_BigInteger($p, 256); - //$q = $p->bitwise_rightShift(1); - - /* To increase the speed of the key exchange, both client and server may - reduce the size of their private exponents. It should be at least - twice as long as the key material that is generated from the shared - secret. For more details, see the paper by van Oorschot and Wiener - [VAN-OORSCHOT]. - - -- http://tools.ietf.org/html/rfc4419#section-6.2 */ - $q = new Math_BigInteger(1); - $q = $q->bitwise_leftShift(2 * $keyLength); - $q = $q->subtract(new Math_BigInteger(1)); - - $g = new Math_BigInteger(2); - $x = new Math_BigInteger(); - $x->setRandomGenerator('crypt_random'); - $x = $x->random(new Math_BigInteger(1), $q); - $e = $g->modPow($x, $p); - - $eBytes = $e->toBytes(true); - $data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes); - - if (!$this->_send_binary_packet($data)) { - user_error('Connection closed by server', E_USER_NOTICE); - return false; - } - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server', E_USER_NOTICE); - return false; - } - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - if ($type != NET_SSH2_MSG_KEXDH_REPLY) { - user_error('Expected SSH_MSG_KEXDH_REPLY', E_USER_NOTICE); - return false; - } - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']); - - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $public_key_format = $this->_string_shift($server_public_host_key, $temp['length']); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $fBytes = $this->_string_shift($response, $temp['length']); - $f = new Math_BigInteger($fBytes, -256); - - $temp = unpack('Nlength', $this->_string_shift($response, 4)); - $this->signature = $this->_string_shift($response, $temp['length']); - - $temp = unpack('Nlength', $this->_string_shift($this->signature, 4)); - $this->signature_format = $this->_string_shift($this->signature, $temp['length']); - - $key = $f->modPow($x, $p); - $keyBytes = $key->toBytes(true); - - if ($this->session_id === false) { - $source = pack('Na*Na*Na*Na*Na*Na*Na*Na*', - strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier, - strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server), - $kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes), - $eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes - ); - - $source = pack('H*', $hash($source)); - - $this->session_id = $source; - } - - for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++); - if ($i == count($server_host_key_algorithms)) { - user_error('No compatible server host key algorithms found', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) { - user_error('Sever Host Key Algorithm Mismatch', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $packet = pack('C', - NET_SSH2_MSG_NEWKEYS - ); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $response = $this->_get_binary_packet(); - - if ($response === false) { - user_error('Connection closed by server', E_USER_NOTICE); - return false; - } - - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - if ($type != NET_SSH2_MSG_NEWKEYS) { - user_error('Expected SSH_MSG_NEWKEYS', E_USER_NOTICE); - return false; - } - - switch ($encrypt) { - case '3des-cbc': - $this->encrypt = new Crypt_TripleDES(); - // $this->encrypt_block_size = 64 / 8 == the default - break; - case '3des-ctr': - $this->encrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); - // $this->encrypt_block_size = 64 / 8 == the default - break; - case 'aes256-cbc': - case 'aes192-cbc': - case 'aes128-cbc': - $this->encrypt = new Crypt_AES(); - $this->encrypt_block_size = 16; // eg. 128 / 8 - break; - case 'aes256-ctr': - case 'aes192-ctr': - case 'aes128-ctr': - $this->encrypt = new Crypt_AES(CRYPT_AES_MODE_CTR); - $this->encrypt_block_size = 16; // eg. 128 / 8 - break; - case 'arcfour': - case 'arcfour128': - case 'arcfour256': - $this->encrypt = new Crypt_RC4(); - break; - case 'none'; - //$this->encrypt = new Crypt_Null(); - } - - switch ($decrypt) { - case '3des-cbc': - $this->decrypt = new Crypt_TripleDES(); - break; - case '3des-ctr': - $this->decrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); - break; - case 'aes256-cbc': - case 'aes192-cbc': - case 'aes128-cbc': - $this->decrypt = new Crypt_AES(); - $this->decrypt_block_size = 16; - break; - case 'aes256-ctr': - case 'aes192-ctr': - case 'aes128-ctr': - $this->decrypt = new Crypt_AES(CRYPT_AES_MODE_CTR); - $this->decrypt_block_size = 16; - break; - case 'arcfour': - case 'arcfour128': - case 'arcfour256': - $this->decrypt = new Crypt_RC4(); - break; - case 'none'; - //$this->decrypt = new Crypt_Null(); - } - - $keyBytes = pack('Na*', strlen($keyBytes), $keyBytes); - - if ($this->encrypt) { - $this->encrypt->enableContinuousBuffer(); - $this->encrypt->disablePadding(); - - $iv = pack('H*', $hash($keyBytes . $this->session_id . 'A' . $this->session_id)); - while ($this->encrypt_block_size > strlen($iv)) { - $iv.= pack('H*', $hash($keyBytes . $this->session_id . $iv)); - } - $this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size)); - - $key = pack('H*', $hash($keyBytes . $this->session_id . 'C' . $this->session_id)); - while ($encryptKeyLength > strlen($key)) { - $key.= pack('H*', $hash($keyBytes . $this->session_id . $key)); - } - $this->encrypt->setKey(substr($key, 0, $encryptKeyLength)); - } - - if ($this->decrypt) { - $this->decrypt->enableContinuousBuffer(); - $this->decrypt->disablePadding(); - - $iv = pack('H*', $hash($keyBytes . $this->session_id . 'B' . $this->session_id)); - while ($this->decrypt_block_size > strlen($iv)) { - $iv.= pack('H*', $hash($keyBytes . $this->session_id . $iv)); - } - $this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size)); - - $key = pack('H*', $hash($keyBytes . $this->session_id . 'D' . $this->session_id)); - while ($decryptKeyLength > strlen($key)) { - $key.= pack('H*', $hash($keyBytes . $this->session_id . $key)); - } - $this->decrypt->setKey(substr($key, 0, $decryptKeyLength)); - } - - /* The "arcfour128" algorithm is the RC4 cipher, as described in - [SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream - generated by the cipher MUST be discarded, and the first byte of the - first encrypted packet MUST be encrypted using the 1537th byte of - keystream. - - -- http://tools.ietf.org/html/rfc4345#section-4 */ - if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') { - $this->encrypt->encrypt(str_repeat("\0", 1536)); - } - if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') { - $this->decrypt->decrypt(str_repeat("\0", 1536)); - } - - for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++); - if ($i == count($mac_algorithms)) { - user_error('No compatible client to server message authentication algorithms found', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none' - switch ($mac_algorithms[$i]) { - case 'hmac-sha1': - $this->hmac_create = new Crypt_Hash('sha1'); - $createKeyLength = 20; - break; - case 'hmac-sha1-96': - $this->hmac_create = new Crypt_Hash('sha1-96'); - $createKeyLength = 20; - break; - case 'hmac-md5': - $this->hmac_create = new Crypt_Hash('md5'); - $createKeyLength = 16; - break; - case 'hmac-md5-96': - $this->hmac_create = new Crypt_Hash('md5-96'); - $createKeyLength = 16; - } - - for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++); - if ($i == count($mac_algorithms)) { - user_error('No compatible server to client message authentication algorithms found', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $checkKeyLength = 0; - $this->hmac_size = 0; - switch ($mac_algorithms[$i]) { - case 'hmac-sha1': - $this->hmac_check = new Crypt_Hash('sha1'); - $checkKeyLength = 20; - $this->hmac_size = 20; - break; - case 'hmac-sha1-96': - $this->hmac_check = new Crypt_Hash('sha1-96'); - $checkKeyLength = 20; - $this->hmac_size = 12; - break; - case 'hmac-md5': - $this->hmac_check = new Crypt_Hash('md5'); - $checkKeyLength = 16; - $this->hmac_size = 16; - break; - case 'hmac-md5-96': - $this->hmac_check = new Crypt_Hash('md5-96'); - $checkKeyLength = 16; - $this->hmac_size = 12; - } - - $key = pack('H*', $hash($keyBytes . $this->session_id . 'E' . $this->session_id)); - while ($createKeyLength > strlen($key)) { - $key.= pack('H*', $hash($keyBytes . $this->session_id . $key)); - } - $this->hmac_create->setKey(substr($key, 0, $createKeyLength)); - - $key = pack('H*', $hash($keyBytes . $this->session_id . 'F' . $this->session_id)); - while ($checkKeyLength > strlen($key)) { - $key.= pack('H*', $hash($keyBytes . $this->session_id . $key)); - } - $this->hmac_check->setKey(substr($key, 0, $checkKeyLength)); - - for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++); - if ($i == count($compression_algorithms)) { - user_error('No compatible server to client compression algorithms found', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - $this->decompress = $compression_algorithms[$i] == 'zlib'; - - for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++); - if ($i == count($compression_algorithms)) { - user_error('No compatible client to server compression algorithms found', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - $this->compress = $compression_algorithms[$i] == 'zlib'; - - return true; - } - - /** - * Login - * - * @param String $username - * @param optional String $password - * @return Boolean - * @access public - * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis} - * by sending dummy SSH_MSG_IGNORE messages. - */ - function login($username, $password = '') - { - if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) { - return false; - } - - $packet = pack('CNa*', - NET_SSH2_MSG_SERVICE_REQUEST, strlen('ssh-userauth'), 'ssh-userauth' - ); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server', E_USER_NOTICE); - return false; - } - - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) { - user_error('Expected SSH_MSG_SERVICE_ACCEPT', E_USER_NOTICE); - return false; - } - - // although PHP5's get_class() preserves the case, PHP4's does not - if (is_object($password) && strtolower(get_class($password)) == 'crypt_rsa') { - return $this->_privatekey_login($username, $password); - } - - $utf8_password = utf8_encode($password); - $packet = pack('CNa*Na*Na*CNa*', - NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', - strlen('password'), 'password', 0, strlen($utf8_password), $utf8_password - ); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - // remove the username and password from the last logged packet - if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { - $packet = pack('CNa*Na*Na*CNa*', - NET_SSH2_MSG_USERAUTH_REQUEST, strlen('username'), 'username', strlen('ssh-connection'), 'ssh-connection', - strlen('password'), 'password', 0, strlen('password'), 'password' - ); - $this->message_log[count($this->message_log) - 1] = $packet; - } - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server', E_USER_NOTICE); - return false; - } - - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - switch ($type) { - case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // in theory, the password can be changed - if (defined('NET_SSH2_LOGGING')) { - $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'; - } - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length)); - return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); - case NET_SSH2_MSG_USERAUTH_FAILURE: - // either the login is bad or the server employees multi-factor authentication - return false; - case NET_SSH2_MSG_USERAUTH_SUCCESS: - $this->bitmap |= NET_SSH2_MASK_LOGIN; - return true; - } - - return false; - } - - /** - * Login with an RSA private key - * - * @param String $username - * @param Crypt_RSA $password - * @return Boolean - * @access private - * @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis} - * by sending dummy SSH_MSG_IGNORE messages. - */ - function _privatekey_login($username, $privatekey) - { - // see http://tools.ietf.org/html/rfc4253#page-15 - $publickey = $privatekey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_RAW); - if ($publickey === false) { - return false; - } - - $publickey = array( - 'e' => $publickey['e']->toBytes(true), - 'n' => $publickey['n']->toBytes(true) - ); - $publickey = pack('Na*Na*Na*', - strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey['e']), $publickey['e'], strlen($publickey['n']), $publickey['n'] - ); - - $part1 = pack('CNa*Na*Na*', - NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection', - strlen('publickey'), 'publickey' - ); - $part2 = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey), $publickey); - - $packet = $part1 . chr(0) . $part2; - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server', E_USER_NOTICE); - return false; - } - - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - switch ($type) { - case NET_SSH2_MSG_USERAUTH_FAILURE: - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $this->_string_shift($response, $length); - return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER); - case NET_SSH2_MSG_USERAUTH_PK_OK: - // we'll just take it on faith that the public key blob and the public key algorithm name are as - // they should be - if (defined('NET_SSH2_LOGGING')) { - $this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PK_OK'; - } - } - - $packet = $part1 . chr(1) . $part2; - $privatekey->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); - $signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet)); - $signature = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($signature), $signature); - $packet.= pack('Na*', strlen($signature), $signature); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server', E_USER_NOTICE); - return false; - } - - extract(unpack('Ctype', $this->_string_shift($response, 1))); - - switch ($type) { - case NET_SSH2_MSG_USERAUTH_FAILURE: - // either the login is bad or the server employees multi-factor authentication - return false; - case NET_SSH2_MSG_USERAUTH_SUCCESS: - $this->bitmap |= NET_SSH2_MASK_LOGIN; - return true; - } - - return false; - } - - /** - * Execute Command - * - * @param String $command - * @return String - * @access public - */ - function exec($command) - { - if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) { - return false; - } - - // RFC4254 defines the (client) window size as "bytes the other party can send before it must wait for the window to - // be adjusted". 0x7FFFFFFF is, at 4GB, the max size. technically, it should probably be decremented, but, - // honestly, if you're transfering more than 4GB, you probably shouldn't be using phpseclib, anyway. - // see http://tools.ietf.org/html/rfc4254#section-5.2 for more info - $this->window_size_client_to_server[NET_SSH2_CHANNEL_EXEC] = 0x7FFFFFFF; - // 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy - // uses 0x4000, that's what will be used here, as well. - $packet_size = 0x4000; - - $packet = pack('CNa*N3', - NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_EXEC, $this->window_size_client_to_server[NET_SSH2_CHANNEL_EXEC], $packet_size); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN; - - $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); - if ($response === false) { - return false; - } - - // sending a pty-req SSH_MSG_CHANNEL_REQUEST message is unnecessary and, in fact, in most cases, slows things - // down. the one place where it might be desirable is if you're doing something like Net_SSH2::exec('ping localhost &'). - // with a pty-req SSH_MSG_cHANNEL_REQUEST, exec() will return immediately and the ping process will then - // then immediately terminate. without such a request exec() will loop indefinitely. the ping process won't end but - // neither will your script. - - // although, in theory, the size of SSH_MSG_CHANNEL_REQUEST could exceed the maximum packet size established by - // SSH_MSG_CHANNEL_OPEN_CONFIRMATION, RFC4254#section-5.1 states that the "maximum packet size" refers to the - // "maximum size of an individual data packet". ie. SSH_MSG_CHANNEL_DATA. RFC4254#section-5.2 corroborates. - $packet = pack('CNNa*CNa*', - NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('exec'), 'exec', 1, strlen($command), $command); - if (!$this->_send_binary_packet($packet)) { - return false; - } - - $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST; - - $response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); - if ($response === false) { - return false; - } - - $this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA; - - $output = ''; - while (true) { - $temp = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC); - switch (true) { - case $temp === true: - return $output; - case $temp === false: - return false; - default: - $output.= $temp; - } - } - } - - /** - * Disconnect - * - * @access public - */ - function disconnect() - { - $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - - /** - * Destructor. - * - * Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call - * disconnect(). - * - * @access public - */ - function __destruct() - { - $this->disconnect(); - } - - /** - * Gets Binary Packets - * - * See '6. Binary Packet Protocol' of rfc4253 for more info. - * - * @see Net_SSH2::_send_binary_packet() - * @return String - * @access private - */ - function _get_binary_packet() - { - if (feof($this->fsock)) { - user_error('Connection closed prematurely', E_USER_NOTICE); - return false; - } - - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $raw = fread($this->fsock, $this->decrypt_block_size); - $stop = strtok(microtime(), ' ') + strtok(''); - - if ($this->decrypt !== false) { - $raw = $this->decrypt->decrypt($raw); - } - - extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5))); - - $remaining_length = $packet_length + 4 - $this->decrypt_block_size; - $buffer = ''; - while ($remaining_length > 0) { - $temp = fread($this->fsock, $remaining_length); - $buffer.= $temp; - $remaining_length-= strlen($temp); - } - if (!empty($buffer)) { - $raw.= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer; - $buffer = $temp = ''; - } - - $payload = $this->_string_shift($raw, $packet_length - $padding_length - 1); - $padding = $this->_string_shift($raw, $padding_length); // should leave $raw empty - - if ($this->hmac_check !== false) { - $hmac = fread($this->fsock, $this->hmac_size); - if ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) { - user_error('Invalid HMAC', E_USER_NOTICE); - return false; - } - } - - //if ($this->decompress) { - // $payload = gzinflate(substr($payload, 2)); - //} - - $this->get_seq_no++; - - if (defined('NET_SSH2_LOGGING')) { - $temp = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN'; - $this->message_number_log[] = '<- ' . $temp . - ' (' . round($stop - $start, 4) . 's)'; - if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { - $this->message_log[] = substr($payload, 1); - } - } - - return $this->_filter($payload); - } - - /** - * Filter Binary Packets - * - * Because some binary packets need to be ignored... - * - * @see Net_SSH2::_get_binary_packet() - * @return String - * @access private - */ - function _filter($payload) - { - switch (ord($payload[0])) { - case NET_SSH2_MSG_DISCONNECT: - $this->_string_shift($payload, 1); - extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8))); - $this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode($this->_string_shift($payload, $length)); - $this->bitmask = 0; - return false; - case NET_SSH2_MSG_IGNORE: - $payload = $this->_get_binary_packet(); - break; - case NET_SSH2_MSG_DEBUG: - $this->_string_shift($payload, 2); - extract(unpack('Nlength', $this->_string_shift($payload, 4))); - $this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length)); - $payload = $this->_get_binary_packet(); - break; - case NET_SSH2_MSG_UNIMPLEMENTED: - return false; - case NET_SSH2_MSG_KEXINIT: - if ($this->session_id !== false) { - if (!$this->_key_exchange($payload)) { - $this->bitmask = 0; - return false; - } - $payload = $this->_get_binary_packet(); - } - } - - // see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in - if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) { - $this->_string_shift($payload, 1); - extract(unpack('Nlength', $this->_string_shift($payload, 4))); - $this->errors[] = 'SSH_MSG_USERAUTH_BANNER: ' . utf8_decode($this->_string_shift($payload, $length)); - $payload = $this->_get_binary_packet(); - } - - // only called when we've already logged in - if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) { - switch (ord($payload[0])) { - case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4 - $this->_string_shift($payload, 1); - extract(unpack('Nlength', $this->_string_shift($payload))); - $this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . utf8_decode($this->_string_shift($payload, $length)); - - if (!$this->_send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE))) { - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - - $payload = $this->_get_binary_packet(); - break; - case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1 - $this->_string_shift($payload, 1); - extract(unpack('N', $this->_string_shift($payload, 4))); - $this->errors[] = 'SSH_MSG_CHANNEL_OPEN: ' . utf8_decode($this->_string_shift($payload, $length)); - - $this->_string_shift($payload, 4); // skip over client channel - extract(unpack('Nserver_channel', $this->_string_shift($payload, 4))); - - $packet = pack('CN3a*Na*', - NET_SSH2_MSG_REQUEST_FAILURE, $server_channel, NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, 0, '', 0, ''); - - if (!$this->_send_binary_packet($packet)) { - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - - $payload = $this->_get_binary_packet(); - break; - case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST: - $payload = $this->_get_binary_packet(); - } - } - - return $payload; - } - - /** - * Gets channel data - * - * Returns the data as a string if it's available and false if not. - * - * @param $client_channel - * @return Mixed - * @access private - */ - function _get_channel_packet($client_channel) - { - if (!empty($this->channel_buffers[$client_channel])) { - return array_shift($this->channel_buffers[$client_channel]); - } - - while (true) { - $response = $this->_get_binary_packet(); - if ($response === false) { - user_error('Connection closed by server', E_USER_NOTICE); - return false; - } - - extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5))); - - switch ($this->channel_status[$channel]) { - case NET_SSH2_MSG_CHANNEL_OPEN: - switch ($type) { - case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: - extract(unpack('Nserver_channel', $this->_string_shift($response, 4))); - $this->server_channels[$client_channel] = $server_channel; - $this->_string_shift($response, 4); // skip over (server) window size - $temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4)); - $this->packet_size_client_to_server[$client_channel] = $temp['packet_size_client_to_server']; - return true; - //case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE: - default: - user_error('Unable to open channel', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - break; - case NET_SSH2_MSG_CHANNEL_REQUEST: - switch ($type) { - case NET_SSH2_MSG_CHANNEL_SUCCESS: - return true; - //case NET_SSH2_MSG_CHANNEL_FAILURE: - default: - user_error('Unable to request pseudo-terminal', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - - } - - switch ($type) { - case NET_SSH2_MSG_CHANNEL_DATA: - if ($client_channel == NET_SSH2_CHANNEL_EXEC) { - // SCP requires null packets, such as this, be sent. further, in the case of the ssh.com SSH server - // this actually seems to make things twice as fast. more to the point, the message right after - // SSH_MSG_CHANNEL_DATA (usually SSH_MSG_IGNORE) won't block for as long as it would have otherwise. - // in OpenSSH it slows things down but only by a couple thousandths of a second. - $this->_send_channel_packet($client_channel, chr(0)); - } - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $data = $this->_string_shift($response, $length); - if ($client_channel == $channel) { - return $data; - } - if (!isset($this->channel_buffers[$client_channel])) { - $this->channel_buffers[$client_channel] = array(); - } - $this->channel_buffers[$client_channel][] = $data; - break; - case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA: - if ($client_channel == NET_SSH2_CHANNEL_EXEC) { - $this->_send_channel_packet($client_channel, chr(0)); - } - // currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR - extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8))); - $data = $this->_string_shift($response, $length); - if ($client_channel == $channel) { - return $data; - } - if (!isset($this->channel_buffers[$client_channel])) { - $this->channel_buffers[$client_channel] = array(); - } - $this->channel_buffers[$client_channel][] = $data; - break; - case NET_SSH2_MSG_CHANNEL_REQUEST: - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $value = $this->_string_shift($response, $length); - switch ($value) { - case 'exit-signal': - $this->_string_shift($response, 1); - extract(unpack('Nlength', $this->_string_shift($response, 4))); - $this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length); - $this->_string_shift($response, 1); - extract(unpack('Nlength', $this->_string_shift($response, 4))); - if ($length) { - $this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length); - } - //case 'exit-status': - default: - // "Some systems may not implement signals, in which case they SHOULD ignore this message." - // -- http://tools.ietf.org/html/rfc4254#section-6.9 - break; - } - break; - case NET_SSH2_MSG_CHANNEL_CLOSE: - $this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel])); - return true; - case NET_SSH2_MSG_CHANNEL_EOF: - break; - default: - user_error('Error reading channel data', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION); - } - } - } - - /** - * Sends Binary Packets - * - * See '6. Binary Packet Protocol' of rfc4253 for more info. - * - * @param String $data - * @see Net_SSH2::_get_binary_packet() - * @return Boolean - * @access private - */ - function _send_binary_packet($data) - { - if (feof($this->fsock)) { - user_error('Connection closed prematurely', E_USER_NOTICE); - return false; - } - - //if ($this->compress) { - // // the -4 removes the checksum: - // // http://php.net/function.gzcompress#57710 - // $data = substr(gzcompress($data), 0, -4); - //} - - // 4 (packet length) + 1 (padding length) + 4 (minimal padding amount) == 9 - $packet_length = strlen($data) + 9; - // round up to the nearest $this->encrypt_block_size - $packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size; - // subtracting strlen($data) is obvious - subtracting 5 is necessary because of packet_length and padding_length - $padding_length = $packet_length - strlen($data) - 5; - - $padding = ''; - for ($i = 0; $i < $padding_length; $i++) { - $padding.= chr(crypt_random(0, 255)); - } - - // we subtract 4 from packet_length because the packet_length field isn't supposed to include itself - $packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding); - - $hmac = $this->hmac_create !== false ? $this->hmac_create->hash(pack('Na*', $this->send_seq_no, $packet)) : ''; - $this->send_seq_no++; - - if ($this->encrypt !== false) { - $packet = $this->encrypt->encrypt($packet); - } - - $packet.= $hmac; - - $start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838 - $result = strlen($packet) == fputs($this->fsock, $packet); - $stop = strtok(microtime(), ' ') + strtok(''); - - if (defined('NET_SSH2_LOGGING')) { - $temp = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN'; - $this->message_number_log[] = '-> ' . $temp . - ' (' . round($stop - $start, 4) . 's)'; - if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) { - $this->message_log[] = substr($data, 1); - } - } - - return $result; - } - - /** - * Sends channel data - * - * Spans multiple SSH_MSG_CHANNEL_DATAs if appropriate - * - * @param Integer $client_channel - * @param String $data - * @return Boolean - * @access private - */ - function _send_channel_packet($client_channel, $data) - { - while (strlen($data) > $this->packet_size_client_to_server[$client_channel]) { - // resize the window, if appropriate - $this->window_size_client_to_server[$client_channel]-= $this->packet_size_client_to_server[$client_channel]; - if ($this->window_size_client_to_server[$client_channel] < 0) { - $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$client_channel], $this->window_size); - if (!$this->_send_binary_packet($packet)) { - return false; - } - $this->window_size_client_to_server[$client_channel]+= $this->window_size; - } - - $packet = pack('CN2a*', - NET_SSH2_MSG_CHANNEL_DATA, - $this->server_channels[$client_channel], - $this->packet_size_client_to_server[$client_channel], - $this->_string_shift($data, $this->packet_size_client_to_server[$client_channel]) - ); - - if (!$this->_send_binary_packet($packet)) { - return false; - } - } - - // resize the window, if appropriate - $this->window_size_client_to_server[$client_channel]-= strlen($data); - if ($this->window_size_client_to_server[$client_channel] < 0) { - $packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$client_channel], $this->window_size); - if (!$this->_send_binary_packet($packet)) { - return false; - } - $this->window_size_client_to_server[$client_channel]+= $this->window_size; - } - - return $this->_send_binary_packet(pack('CN2a*', - NET_SSH2_MSG_CHANNEL_DATA, - $this->server_channels[$client_channel], - strlen($data), - $data)); - } - - /** - * Disconnect - * - * @param Integer $reason - * @return Boolean - * @access private - */ - function _disconnect($reason) - { - if ($this->bitmap) { - $data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, ''); - $this->_send_binary_packet($data); - $this->bitmap = 0; - fclose($this->fsock); - return false; - } - } - - /** - * String Shift - * - * Inspired by array_shift - * - * @param String $string - * @param optional Integer $index - * @return String - * @access private - */ - function _string_shift(&$string, $index = 1) - { - $substr = substr($string, 0, $index); - $string = substr($string, $index); - return $substr; - } - - /** - * Define Array - * - * Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of - * named constants from it, using the value as the name of the constant and the index as the value of the constant. - * If any of the constants that would be defined already exists, none of the constants will be defined. - * - * @param Array $array - * @access private - */ - function _define_array() - { - $args = func_get_args(); - foreach ($args as $arg) { - foreach ($arg as $key=>$value) { - if (!defined($value)) { - define($value, $key); - } else { - break 2; - } - } - } - } - - /** - * Returns a log of the packets that have been sent and received. - * - * Returns a string if NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX, an array if NET_SSH2_LOGGING == NET_SSH2_LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING') - * - * @access public - * @return String or Array - */ - function getLog() - { - if (!defined('NET_SSH2_LOGGING')) { - return false; - } - - switch (NET_SSH2_LOGGING) { - case NET_SSH2_LOG_SIMPLE: - return $this->message_number_log; - break; - case NET_SSH2_LOG_COMPLEX: - return $this->_format_log($this->message_log, $this->message_number_log); - break; - default: - return false; - } - } - - /** - * Formats a log for printing - * - * @param Array $message_log - * @param Array $message_number_log - * @access private - * @return String - */ - function _format_log($message_log, $message_number_log) - { - static $boundary = ':', $long_width = 65, $short_width = 16; - - $output = ''; - for ($i = 0; $i < count($message_log); $i++) { - $output.= $message_number_log[$i] . "\r\n"; - $current_log = $message_log[$i]; - $j = 0; - do { - if (!empty($current_log)) { - $output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 '; - } - $fragment = $this->_string_shift($current_log, $short_width); - $hex = substr( - preg_replace( - '#(.)#es', - '"' . $boundary . '" . str_pad(dechex(ord(substr("\\1", -1))), 2, "0", STR_PAD_LEFT)', - $fragment), - strlen($boundary) - ); - // replace non ASCII printable characters with dots - // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters - // also replace < with a . since < messes up the output on web browsers - $raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment); - $output.= str_pad($hex, $long_width - $short_width, ' ') . $raw . "\r\n"; - $j++; - } while (!empty($current_log)); - $output.= "\r\n"; - } - - return $output; - } - - /** - * Returns all errors - * - * @return String - * @access public - */ - function getErrors() - { - return $this->errors; - } - - /** - * Returns the last error - * - * @return String - * @access public - */ - function getLastError() - { - return $this->errors[count($this->errors) - 1]; - } - - /** - * Return the server identification. - * - * @return String - * @access public - */ - function getServerIdentification() - { - return $this->server_identifier; - } - - /** - * Return a list of the key exchange algorithms the server supports. - * - * @return Array - * @access public - */ - function getKexAlgorithms() - { - return $this->kex_algorithms; - } - - /** - * Return a list of the host key (public key) algorithms the server supports. - * - * @return Array - * @access public - */ - function getServerHostKeyAlgorithms() - { - return $this->server_host_key_algorithms; - } - - /** - * Return a list of the (symmetric key) encryption algorithms the server supports, when receiving stuff from the client. - * - * @return Array - * @access public - */ - function getEncryptionAlgorithmsClient2Server() - { - return $this->encryption_algorithms_client_to_server; - } - - /** - * Return a list of the (symmetric key) encryption algorithms the server supports, when sending stuff to the client. - * - * @return Array - * @access public - */ - function getEncryptionAlgorithmsServer2Client() - { - return $this->encryption_algorithms_server_to_client; - } - - /** - * Return a list of the MAC algorithms the server supports, when receiving stuff from the client. - * - * @return Array - * @access public - */ - function getMACAlgorithmsClient2Server() - { - return $this->mac_algorithms_client_to_server; - } - - /** - * Return a list of the MAC algorithms the server supports, when sending stuff to the client. - * - * @return Array - * @access public - */ - function getMACAlgorithmsServer2Client() - { - return $this->mac_algorithms_server_to_client; - } - - /** - * Return a list of the compression algorithms the server supports, when receiving stuff from the client. - * - * @return Array - * @access public - */ - function getCompressionAlgorithmsClient2Server() - { - return $this->compression_algorithms_client_to_server; - } - - /** - * Return a list of the compression algorithms the server supports, when sending stuff to the client. - * - * @return Array - * @access public - */ - function getCompressionAlgorithmsServer2Client() - { - return $this->compression_algorithms_server_to_client; - } - - /** - * Return a list of the languages the server supports, when sending stuff to the client. - * - * @return Array - * @access public - */ - function getLanguagesServer2Client() - { - return $this->languages_server_to_client; - } - - /** - * Return a list of the languages the server supports, when receiving stuff from the client. - * - * @return Array - * @access public - */ - function getLanguagesClient2Server() - { - return $this->languages_client_to_server; - } - - /** - * Returns the server public host key. - * - * Caching this the first time you connect to a server and checking the result on subsequent connections - * is recommended. Returns false if the server signature is not signed correctly with the public host key. - * - * @return Mixed - * @access public - */ - function getServerPublicHostKey() - { - $signature = $this->signature; - $server_public_host_key = $this->server_public_host_key; - - extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4))); - $this->_string_shift($server_public_host_key, $length); - - switch ($this->signature_format) { - case 'ssh-dss': - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); - - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $q = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); - - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $g = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); - - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $y = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); - - /* The value for 'dss_signature_blob' is encoded as a string containing - r, followed by s (which are 160-bit integers, without lengths or - padding, unsigned, and in network byte order). */ - $temp = unpack('Nlength', $this->_string_shift($signature, 4)); - if ($temp['length'] != 40) { - user_error('Invalid signature', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $r = new Math_BigInteger($this->_string_shift($signature, 20), 256); - $s = new Math_BigInteger($this->_string_shift($signature, 20), 256); - - if ($r->compare($q) >= 0 || $s->compare($q) >= 0) { - user_error('Invalid signature', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $w = $s->modInverse($q); - - $u1 = $w->multiply(new Math_BigInteger(sha1($this->session_id), 16)); - list(, $u1) = $u1->divide($q); - - $u2 = $w->multiply($r); - list(, $u2) = $u2->divide($q); - - $g = $g->modPow($u1, $p); - $y = $y->modPow($u2, $p); - - $v = $g->multiply($y); - list(, $v) = $v->divide($p); - list(, $v) = $v->divide($q); - - if (!$v->equals($r)) { - user_error('Bad server signature', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); - } - - break; - case 'ssh-rsa': - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); - - $temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4)); - $n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256); - $nLength = $temp['length']; - - /* - $temp = unpack('Nlength', $this->_string_shift($signature, 4)); - $signature = $this->_string_shift($signature, $temp['length']); - - if (!class_exists('Crypt_RSA')) { - require_once('Crypt/RSA.php'); - } - - $rsa = new Crypt_RSA(); - $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); - $rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW); - if (!$rsa->verify($this->session_id, $signature)) { - user_error('Bad server signature', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); - } - */ - - $temp = unpack('Nlength', $this->_string_shift($signature, 4)); - $s = new Math_BigInteger($this->_string_shift($signature, $temp['length']), 256); - - // validate an RSA signature per "8.2 RSASSA-PKCS1-v1_5", "5.2.2 RSAVP1", and "9.1 EMSA-PSS" in the - // following URL: - // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf - - // also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source. - - if ($s->compare(new Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) { - user_error('Invalid signature', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); - } - - $s = $s->modPow($e, $n); - $s = $s->toBytes(); - - $h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->session_id)); - $h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 3 - strlen($h)) . $h; - - if ($s != $h) { - user_error('Bad server signature', E_USER_NOTICE); - return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); - } - } - - return $this->server_public_host_key; - } -} \ No newline at end of file diff --git a/library/phpsec/PHP/Compat/Function/array_fill.php b/library/phpsec/PHP/Compat/Function/array_fill.php deleted file mode 100644 index e02bfa14d8..0000000000 --- a/library/phpsec/PHP/Compat/Function/array_fill.php +++ /dev/null @@ -1,43 +0,0 @@ -, Arpad Ray - * @link http://php.net/function.array_fill - * @author Jim Wigginton - * @version $Revision: 1.1 $ - * @since PHP 4.2.0 - */ -function php_compat_array_fill($start_index, $num, $value) -{ - if ($num <= 0) { - user_error('array_fill(): Number of elements must be positive', E_USER_WARNING); - - return false; - } - - $temp = array(); - - $end_index = $start_index + $num; - for ($i = (int) $start_index; $i < $end_index; $i++) { - $temp[$i] = $value; - } - - return $temp; -} - -// Define -if (!function_exists('array_fill')) { - function array_fill($start_index, $num, $value) - { - return php_compat_array_fill($start_index, $num, $value); - } -} - -?> \ No newline at end of file diff --git a/library/phpsec/PHP/Compat/Function/bcpowmod.php b/library/phpsec/PHP/Compat/Function/bcpowmod.php deleted file mode 100644 index 6ec1b1840c..0000000000 --- a/library/phpsec/PHP/Compat/Function/bcpowmod.php +++ /dev/null @@ -1,67 +0,0 @@ -, Arpad Ray - * @link http://php.net/function.bcpowmod - * @author Sara Golemon - * @version $Revision: 1.1 $ - * @since PHP 5.0.0 - * @require PHP 4.0.0 (user_error) - */ -function php_compat_bcpowmod($x, $y, $modulus, $scale = 0) -{ - // Sanity check - if (!is_scalar($x)) { - user_error('bcpowmod() expects parameter 1 to be string, ' . - gettype($x) . ' given', E_USER_WARNING); - return false; - } - - if (!is_scalar($y)) { - user_error('bcpowmod() expects parameter 2 to be string, ' . - gettype($y) . ' given', E_USER_WARNING); - return false; - } - - if (!is_scalar($modulus)) { - user_error('bcpowmod() expects parameter 3 to be string, ' . - gettype($modulus) . ' given', E_USER_WARNING); - return false; - } - - if (!is_scalar($scale)) { - user_error('bcpowmod() expects parameter 4 to be integer, ' . - gettype($scale) . ' given', E_USER_WARNING); - return false; - } - - $t = '1'; - while (bccomp($y, '0')) { - if (bccomp(bcmod($y, '2'), '0')) { - $t = bcmod(bcmul($t, $x), $modulus); - $y = bcsub($y, '1'); - } - - $x = bcmod(bcmul($x, $x), $modulus); - $y = bcdiv($y, '2'); - } - - return $t; -} - - -// Define -if (!function_exists('bcpowmod')) { - function bcpowmod($x, $y, $modulus, $scale = 0) - { - return php_compat_bcpowmod($x, $y, $modulus, $scale); - } -} -?> \ No newline at end of file diff --git a/library/phpsec/PHP/Compat/Function/str_split.php b/library/phpsec/PHP/Compat/Function/str_split.php deleted file mode 100644 index 8e38bdb894..0000000000 --- a/library/phpsec/PHP/Compat/Function/str_split.php +++ /dev/null @@ -1,59 +0,0 @@ -, Arpad Ray - * @link http://php.net/function.str_split - * @author Aidan Lister - * @version $Revision: 1.1 $ - * @since PHP 5 - * @require PHP 4.0.0 (user_error) - */ -function php_compat_str_split($string, $split_length = 1) -{ - if (!is_scalar($split_length)) { - user_error('str_split() expects parameter 2 to be long, ' . - gettype($split_length) . ' given', E_USER_WARNING); - return false; - } - - $split_length = (int) $split_length; - if ($split_length < 1) { - user_error('str_split() The length of each segment must be greater than zero', E_USER_WARNING); - return false; - } - - // Select split method - if ($split_length < 65536) { - // Faster, but only works for less than 2^16 - preg_match_all('/.{1,' . $split_length . '}/s', $string, $matches); - return $matches[0]; - } else { - // Required due to preg limitations - $arr = array(); - $idx = 0; - $pos = 0; - $len = strlen($string); - - while ($len > 0) { - $blk = ($len < $split_length) ? $len : $split_length; - $arr[$idx++] = substr($string, $pos, $blk); - $pos += $blk; - $len -= $blk; - } - - return $arr; - } -} - - -// Define -if (!function_exists('str_split')) { - function str_split($string, $split_length = 1) - { - return php_compat_str_split($string, $split_length); - } -} diff --git a/library/phpsec/crypt.html b/library/phpsec/crypt.html deleted file mode 100644 index 6720cf7891..0000000000 --- a/library/phpsec/crypt.html +++ /dev/null @@ -1,135 +0,0 @@ - - -Chapter 3. Cryptography

Chapter 3. Cryptography

3.1. Introduction

- All of the cryptographic libraries included in phpseclib use mcrypt, if available, and an internal implementation - if it's not. The libraries all use a common interface although some functions, for some algorithms, carry with - with them certain caveats. Those that do not have caveats attached (or have relatively few attached) are - described below. If you don't know which one to use, try Crypt_TripleDES. -

3.1.1. Dependencies

- The Crypt_* functions require, minimally, PHP 4.0.0. Crypt_TripleDES additionally requires Crypt/DES.php. -

3.1.2. setKey() and setIV()

- Sets the key and the initialization vector, respectively. If neither are set, each assumed to be equal to - some amount of null bytes. The initialization vector is only used in block ciphers and even then only - in CBC mode. If the key or the initialization vector are larger then the block size, they're truncated. - If they're smaller, they're padded with null bytes. -

3.1.3. setMCrypt()

- See php.net's entry on mcrypt_module_open. - The first parameter is equal to $algorithm_directory and the second, to $mode_directory. -

3.1.4. encrypt() and decrypt()

- Self-explanatory. Encrypts or decrypts messages. See the examples in the subsequent sections. -

3.1.5. enableContinuousBuffer() and disableContinuousBuffer()

- Say you have a 16-byte plaintext $plaintext and that you're using Crypt_DES. Using the default behavior, the two following code snippets - will yield different outputs: -

    echo $des->encrypt(substr($plaintext, 0, 8));
-    echo $des->encrypt(substr($plaintext, 8, 8));
    echo $des->encrypt($plaintext);

- The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates - another, as demonstrated with the following: -

    $des->encrypt(substr($plaintext, 0, 8));
-    echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
    echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));

- With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different - outputs. The reason is due to the fact that the initialization vector's change after every encryption / - decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. - - Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each - encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that - continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), - however, they are also less intuitive and more likely to cause you problems. -

3.1.6. enablePadding() and disablePadding()

- Enables / disables PKCS padding on block ciphers. Stream ciphers (Crypt_RC4 is the only stream - cipher currently included) ignore this. -

3.2. Crypt_DES

- Implements DES (a block cipher). Here's an example of how to use it: -

<?php
-    include('Crypt/DES.php');
-
-    $des = new Crypt_DES();
-
-    $des->setKey('abcdefgh');
-
-    $size = 10 * 1024;
-    $plaintext = '';
-    for ($i = 0; $i < $size; $i++) {
-        $plaintext.= 'a';
-    }
-
-    echo $des->decrypt($des->encrypt($plaintext));
-?>

3.2.1. The constructor

- The constructor takes one optional parameter - $mode. $mode can be equal to CRYPT_DES_MODE_ECB - or CRYPT_DES_MODE_CBC. CRYPT_DES_MODE_CBC is generally considered more secure - and is what Crypt_DES uses by default. If you don't know the difference between ECB or CBC, - just use the default settings. -

3.3. Crypt_TripleDES

- Implements TripleDES (a block cipher). Here's an example of how to use it: -

<?php
-    include('Crypt/TripleDES.php');
-
-    $des = new Crypt_TripleDES();
-
-    $des->setKey('abcdefghijklmnopqrstuvwx');
-
-    $size = 10 * 1024;
-    $plaintext = '';
-    for ($i = 0; $i < $size; $i++) {
-        $plaintext.= 'a';
-    }
-
-    echo $des->decrypt($des->encrypt($plaintext));
-?>

3.3.1. The constructor

- The constructor takes one optional parameter - $mode. $mode can be equal to CRYPT_DES_MODE_ECB, - CRYPT_DES_MODE_CBC, CRYPT_DES_MODE_3CBC, or CRYPT_DES_MODE_CBC3. - CRYPT_DES_MODE_CBC3 is an alias CRYPT_DES_MODE_CBC. It's defined to distinguish - it from CRYPT_DES_MODE_3CBC, which uses inner chaining to propogate the initialization vector. - SSH-1 uses this and it is generally considered to be less secure then CRYPT_DES_MODE_CBC3, - which uses outer chaining (and is what SSH-2 uses). -

3.4. Crypt_RC4

- Implements RC4 (a stream cipher). Here's an example of how to use it: -

<?php
-    include('Crypt/RC4.php');
-
-    $rc4 = new Crypt_RC4();
-
-    $rc4->setKey('abcdefghijklmnopqrstuvwx');
-
-    $size = 10 * 1024;
-    $plaintext = '';
-    for ($i = 0; $i < $size; $i++) {
-        $plaintext.= 'a';
-    }
-
-    echo $rc4->decrypt($rc4->encrypt($plaintext));
-?>

3.4.1. The constructor

- Not much to say about this constructor. Since it's a stream cipher, you don't need to worry about which - mode of operation to use. -

3.5. Crypt_Rijndael & Crypt_AES

- Implements Rijndael / AES. Here's an example of how to use Crypt_AES: -

<?php
-    include('Crypt/AES.php');
-
-    $aes = new Crypt_AES();
-
-    $aes->setKey('abcdefghijklmnop');
-
-    $size = 10 * 1024;
-    $plaintext = '';
-    for ($i = 0; $i < $size; $i++) {
-        $plaintext.= 'a';
-    }
-
-    echo $aes->decrypt($aes->encrypt($plaintext));
-?>

3.5.1. The constructor

- Crypt_AES's constructor takes CRYPT_AES_MODE_ECB and CRYPT_AES_MODE_CBC as parameters. Crypt_Rijndael, CRYPT_RIJNDAEL_MODE_ECB and CRYPT_RIJNDAEL_MODE_CBC. In both cases, if no valid mode is defined, CBC will be used. -

3.5.2. AES vs. Rijndael

- AES is a subset of Rijndael. Both have variable key sizes, however, AES's block size is fixed at 128 bytes, whereas Rijndael's is variable. Also, Rijndael supports, by means of an extension to the specification, two key sizes that AES does not - 160 bits and 224 bits. -

3.5.3. setKeyLength()

- Valid key lengths for AES are 128 bits, 192 bits, and 256 bits. If the key that is assigned is invalid and less than 256 bits, they key length is rounded up to the next closest valid size and the key will be null padded to that amount. If the key length is greater than 256 bits, it will be truncated to 256 bits. -

- As an example, if the key is 136 bits, it will be null padded to 192 bits (or 160 bits if Rijndael is being used). -

- If setKeyLength() has been called, this behavior changes somewhat. Say you've set the key length, via this function, to 256 bits. Then, instead of an invalid key being null padded to 192 or 160 bits, it will be null padded to 256 bits. -

3.5.4. setBlockLength()

- setBlockLength() operates in a manner similar to setKeyLength(), with one exception. setBlockLength() only works on Rijndael. Although Crypt_AES inherits setBlockLength() as a function, the function doesn't do anything in AES. -

3.5.5. Speed Comparisons

- The following table compares the speed of five different pure-PHP implementations of AES (one of which is Crypt_Rijndael and one of which is Crypt_AES) when ran on 150KB of text on a 1.8GHz Pentium 4-M. The numbers listed are averaged from five different trials and are measured in seconds. phpseclib's two implementations are highlighted. All implementations can be viewed by clicking on their names. -

Table 3.1. AES Speed Comparisons

movable-type.phpsphpaes.phpsphpclasses1.phpsphpclasses2.phpsphpseclib-aes.phpsphpseclib-rijndael.phps
15.684415817239.953724813515.010015010862.5917131900793.57283110815.24388728142

- As can be seen, phpseclib's implementations are the fastest. phpseclib-aes.phps is faster than phpseclib-rijndael.phps because phpseclib-rijndael.phps has to contend with multiple block sizes whereas phpseclib-aes.phps does not. -

diff --git a/library/phpsec/docbook.css b/library/phpsec/docbook.css deleted file mode 100644 index 4f67aa4cda..0000000000 --- a/library/phpsec/docbook.css +++ /dev/null @@ -1,43 +0,0 @@ -body { - font-family: Georgia, "Times New Roman", Times, serif -} - -div.author h3 { - display: none -} - -a { - text-decoration: none; - color: #369 -} - -a:hover { - text-decoration: underline -} - -.programlisting { - font-family: Monaco, "Andale Mono","Courier New", Courier, mono; - font-size: 10pt -} - -.programlisting, .code { - background: #eee; - color: #181; - font-weight: bold -} - -.red { - color: #e11 -} - -.highlight { - background: #ee1 -} - -thead { - background: #ccc -} - -#crypt_aes_benchmarks_table.tbody { - font-weight: bold -} \ No newline at end of file diff --git a/library/phpsec/index.html b/library/phpsec/index.html deleted file mode 100644 index 6dda0f3699..0000000000 --- a/library/phpsec/index.html +++ /dev/null @@ -1,5 +0,0 @@ - - -PHP Secure Communications Library

PHP Secure Communications Library

Jim TerraFrost Wigginton

Abstract

- The PHP Secure Communications Library contains LGPL-licensed pure-PHP implementations of arbitrary-precision integers, - fully PKCS#1 (v2.1) compliant RSA, DES, 3DES, RC4, Rijndael, AES, SSH-1, SSH-2, and SFTP. This book discusses how to use them.


Table of Contents

1. Introduction
1.1. Who should use phpseclib
1.2. Using phpseclib
2. Math
2.1. Math_BigInteger
2.1.1. Dependencies
2.1.2. The constructor
2.1.3. toString(), toBytes(), toHex() and toBits()
2.1.4. add(), subtract(), multiply() and divide()
2.1.5. powMod() and modInverse()
2.1.6. gcd() and extendedGCD()
2.1.7. abs()
2.1.8. equals() and compare()
2.1.9. setPrecision()
2.1.10. bitwise_and(), bitwise_or(), bitwise_xor() and bitwise_not()
2.1.11. bitwise_rightShift() and bitwise_leftShift()
2.1.12. bitwise_rightRotate() and bitwise_leftRotate()
2.1.13. setRandomGenerator()
2.1.14. isPrime()
2.1.15. random() and randomPrime()
3. Symmetric-key Cryptography
3.1. Introduction
3.1.1. Dependencies
3.1.2. setKey() and setIV()
3.1.3. encrypt() and decrypt()
3.1.4. enableContinuousBuffer() and disableContinuousBuffer()
3.1.5. enablePadding() and disablePadding()
3.1.6. A word of caution about stream ciphers and CTR mode
3.2. Crypt_DES
3.2.1. The constructor
3.3. Crypt_TripleDES
3.3.1. The constructor
3.4. Crypt_RC4
3.4.1. The constructor
3.5. Crypt_Rijndael & Crypt_AES
3.5.1. The constructor
3.5.2. AES vs. Rijndael
3.5.3. setKeyLength()
3.5.4. setBlockLength()
3.5.5. Speed Comparisons
4. Miscellaneous Cryptography
4.1. Crypt_Hash
4.1.1. Supported Algorithms and Dependencies
4.1.2. Example
4.2. Crypt_RSA
4.2.1. Dependencies
4.2.2. Examples
4.2.3. createKey()
4.2.4. setPrivateKeyFormat(), setPublicKeyFormat(), loadKey() and setPassword()
4.2.5. setPublicKey() and getPublicKey()
4.2.6. encrypt(), decrypt() and setEncryptionMode()
4.2.7. sign(), verify(), and setSignatureMode()
4.2.8. setHash(), setMGFHash() and setSaltLength()
5. Networking
5.1. Net_SSH
5.1.1. Dependencies
5.1.2. Net_SSH1 Examples
5.1.3. Net_SSH2 Examples
5.1.4. Host Key Verification
5.1.5. interactiveRead() / interactiveWrite() vs. exec()
5.1.6. SSH-1's exec() vs. SSH-2's exec()
5.1.7. Successive calls to SSH-2's exec()
5.1.8. Debugging SSH-2
5.2. Net_SFTP
5.2.1. Introduction
5.2.2. Dependencies
5.2.3. Net_SFTP Example
5.2.4. put($remote_file, $data [, $mode])
5.2.5. get($remote_file [, $local_file])
5.2.6. pwd(), chdir(), mkdir() and rmdir()
5.2.7. chmod() and size()
5.2.8. nlist() and rawlist()
5.2.9. delete() and rename()
5.2.10. Debugging SFTP

List of Tables

3.1. AES Speed Comparisons
diff --git a/library/phpsec/intro.html b/library/phpsec/intro.html deleted file mode 100644 index 406b22fc59..0000000000 --- a/library/phpsec/intro.html +++ /dev/null @@ -1,20 +0,0 @@ - - -Chapter 1. Introduction

Chapter 1. Introduction

1.1. Who should use phpseclib

- Although many of the features this library implements are implemented in PHP via optional extensions, what are - you, as a developer, going to do when a user tries to run your software on a host which, coincidentally, doesn't - happen to have that optional extension installed? You could, flat-out, tell that user to look for another - software package that does work on their server (or to get another host, or whatever), which is liable to leave - a bad impression on the user, or you could use a library like this - a library that uses those optional - extensions if they're available and falls back on an internal PHP implementation if they're not. -

- Another advantage of using this library over optional PHP extensions is that you, as a developer, may find this - libraries API easier to use then extensions API. -

1.2. Using phpseclib

- This library is written using the same conventions that libraries in the PHP Extension and Application Repository (PEAR) - have been written in. In particular, this library expects to be in your include_path: -

<?php
-set_include_path(get_include_path() . PATH_SEPARATOR . 'phpseclib');
-
-include('Net/SSH2.php');
-?>
diff --git a/library/phpsec/math.html b/library/phpsec/math.html deleted file mode 100644 index 4e5a14a547..0000000000 --- a/library/phpsec/math.html +++ /dev/null @@ -1,157 +0,0 @@ - - -Chapter 2. Math

Chapter 2. Math

2.1. Math_BigInteger

- Implements an arbitrary precision integer arithmetic library. Uses gmp or bcmath, if available, and an - internal implementation, otherwise. Here's an example: -

<?php
-    include('Math/BigInteger.php');
-
-    $a = new Math_BigInteger(2);
-    $b = new Math_BigInteger(3);
-
-    $c = $a->add($b);
-
-    echo $c->toString(); // outputs 5
-?>

2.1.1. Dependencies

- If you're running PHP 5, Math_BigInteger's only dependancy is the PCRE extension (which is enabled by default). Math_BigInteger also works on PHP 4 if PHP/Compat/Function/array_fill.php and PHP/Compat/Function/bcpowmod.php are included. -

2.1.2. The constructor

- The constructor takes two parameters. The first is the number and the second represents the base. Both - are optional (if they're not provided, the Math_BigInteger object will assume a value of 0). -

- The supported bases are base-2, base-10 (default), base-16, and base-256. To set $a, in the - above example, to 2, using base-2, we'd do new Math_BigInteger('10', 2). To do it using - base-16, you could do new Math_BigInteger('2', 16) or new Math_BigInteger('0x2', 16). - To set it to 2 using base-256, you'd do new Math_BigInteger(chr(2), 256). -

- If the base is negative (eg. -256), two's compliment will be used. Thus, new Math_BigInteger(chr(0xFF), -256) - is equal to -1, as is new Math_BigInteger('0xFFFFFFFF', -16) and new Math_BigInteger('11', -2). - Basically, if the leading bit is 1, the number is assumed to be negative. -

2.1.3. toString(), toBytes(), toHex() and toBits()

- toString() returns the base-10 form of a number. toBytes() returns the base-256 - form of a number, toHex() returns the base-16 form, and toBits() the base-2 form. - toBytes(), toHex(), and toBits() also take an optional parameter which, - if set, will return the two's compliment of a number. So if, for example, $a is equal to -1, - toBytes(true) will return chr(0xFF). -

- On PHP 5, toString() is called automatically when used in a string context via the - __toString() magic method. -

2.1.4. add(), subtract(), multiply() and divide()

- subtract() and multiply() operate similarly to add(). divide(), - however, does not. Namely, it returns an array whose first element contains the quotient and whose - second element contains the "common residue". If the remainder would be positive, the "common residue" - and the remainder are the same. If the remainder would be negative, the "common residue" is equal to - the sum of the remainder and the divisor (basically, the "common residue" is the first positive modulo). - Here's an example: -

<?php
-    include('Math/BigInteger.php');
-
-    $a = new Math_BigInteger('10');
-    $b = new Math_BigInteger('20');
-
-    list($quotient, $remainder) = $a->divide($b);
-
-    echo $quotient->toString(); // outputs 0
-    echo "\r\n";
-    echo $remainder->toString(); // outputs 10
-?>

2.1.5. powMod() and modInverse()

- Examples of each follow: -

<?php
-    include('Math/BigInteger.php');
-
-    $a = new Math_BigInteger('10');
-    $b = new Math_BigInteger('20');
-    $c = new Math_BigInteger('30');
-
-    $c = $a->powMod($b, $c);
-
-    echo $c->toString(); // outputs 10
-?>
<?php
-    include('Math/BigInteger.php');
-
-    $a = new Math_BigInteger(30);
-    $b = new Math_BigInteger(17);
-
-    $c = $a->modInverse($b);
-
-    echo $c->toString(); // outputs 4
-?>

2.1.6. gcd() and extendedGCD()

- extendedGCD() returns an array containing three Math_BigInteger values indexed with x, y, - and gcd. x and y represent Bézout's identity. gcd() returns a Math_BigInteger value - equal to the gcd. An example of each follows: -

<?php
-include('Math/BigInteger.php');
-
-$a = new Math_BigInteger(693);
-$b = new Math_BigInteger(609);
-
-extract($a->extendedGCD($b));
-$c = $a->gcd($b);
-
-echo $gcd->toString() . "\r\n"; // outputs 21
-echo $c->toString() . "\r\n"; // outputs 21
-echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
-?>

2.1.7. abs()

- $x->abs() returns the absolute value of $x. -

2.1.8. equals() and compare()

- $x->equals($y) returns true or false depending on whether or not $x and - $y are equal. -

- $x->compare($y) returns 1 if $x > $y, 0 if $x == $y, and -1 if $x < $y. The reason for this - is demonstrated thusly: -

$x  > $y: $x->compare($y)  > 0
-$x  < $y: $x->compare($y)  < 0
-$x == $y: $x->compare($y) == 0
-$x >= $y: $x->compare($y) >= 0
-$x <= $y: $x->compare($y) <= 0

- As a consequence of this, !$x->compare($y) does not mean $x != $y but rather - $x == $y. -

2.1.9. setPrecision()

- Some bitwise operations give different results depending on the precision being used. Examples include - left shift, not, and rotates, as discussed for bitwise_not(). - This function lets you control the precision. -

- Whenever a new Math_BigInteger object is created it's precision is set to the same precision as the - calling object. In other words, if you do $b = $a->bitwise_not() then $b will - have the same precision as $a. -

2.1.10. bitwise_and(), bitwise_or(), bitwise_xor() and bitwise_not()

- bitwise_and(), bitwise_or() and bitwise_xor() operate similar to - add(). bitwise_not() is a bit more complicated. To elaborate, if the - precision (see setPrecision) is arbitrary, - $x->bitwise_not() will always yield a smaller value since the most significant bit is - assumed to have a value of one. With fixed precision, however, the leading bit can be anything. -

2.1.11. bitwise_rightShift() and bitwise_leftShift()

- $a->bitwise_rightShift($shift) shifts $a by $shift bits, effectively dividing by 2**$shift. - $a->bitwise_leftShift($shift) shifts $a by $shift bits, effectively multiplying by 2**$shift. -

2.1.12. bitwise_rightRotate() and bitwise_leftRotate()

- $a->bitwise_rightRotate($shift) and $a->bitwise_leftRotate($shift) are - demonstrated thusly: -

<?php
-include('Math/BigInteger.php');
-
-$a = new Math_BigInteger('00111000', 2);
-$a->setPrecision(8);
-$b = $a->bitwise_leftRotate(2);
-echo $b->toBits(); // returns 11100000
-
-echo "\r\n";
-
-$a = new Math_BigInteger('00111000', 2);
-$b = $a->bitwise_leftRotate(2);
-echo $b->toBits(); // returns 100011
-?>

- Just as with bitwise_not(), these operations are - precision dependant. -

2.1.13. setRandomGenerator()

- Sets the random generator. To set it to mt_rand() (which is what it is by default), call - $x->setRandomGenerator('mt_rand'). -

2.1.14. isPrime()

- Returns true if a number is prime and false if it isn't. -

2.1.15. random() and randomPrime()

- random($min, $max) generates a random number between $min and $max. - randomPrime($min, $max) generates a random prime number between $min and $max. - If no prime number exists between $min and $max false is returned. -

- randomPrime() has an optional third parameter, as well - $timeout. Generating prime numbers - is a particurarly expensive operation and although in certain environments even 512-bit primes can be - generated in a less than a second it can take other environments upwards of around a minute if not more. -

diff --git a/library/phpsec/misc_crypt.html b/library/phpsec/misc_crypt.html deleted file mode 100644 index 9751ddac8a..0000000000 --- a/library/phpsec/misc_crypt.html +++ /dev/null @@ -1,155 +0,0 @@ - - -Chapter 4. Miscellaneous Cryptography

Chapter 4. Miscellaneous Cryptography

4.1. Crypt_Hash

4.1.1. Supported Algorithms and Dependencies

The following algorithms are supported:

md2, md5, md5-96, sha1, sha1-96, sha256, sha384, and sha512

- Crypt_Hash requires, minimally, PHP 4.3.0 (due to its use of - sha1()). If sha384 or sha512 are being used and - you're not running PHP 5.1.2 or greater then Math/BigInteger.php is also required. -

- Crypt_Hash uses the hash extension if it's available (> 5.1.2), mhash if it's not, and it's own - internal implementation if not even mhash is available. -

4.1.2. Example

<?php
-include('Crypt/Hash.php');
-
-$hash = new Crypt_Hash('sha1');
-//$hash->setKey('abcdefg');
-echo bin2hex($hash->hash('abcdefg'));
-?>

If $hash->setKey() had been called $hash->hash() would have returned an HMAC.

4.2. Crypt_RSA

4.2.1. Dependencies

- If you're running PHP 5, Crypt_RSA requires Math/BigInteger.php and Crypt/Hash.php. If you're running - PHP 4, Crypt_RSA also requires PHP/Compat/Function/array_fill.php, PHP/Compat/Function/bcpowmod.php, and - PHP/Compat/Function/str_split.php -

4.2.2. Examples

Here's an example of how to encrypt / decrypt with Crypt_RSA:

<?php
-include('Crypt/RSA.php');
-
-$rsa = new Crypt_RSA();
-extract($rsa->createKey());
-
-$plaintext = 'terrafrost';
-
-$rsa->loadKey($privatekey);
-$ciphertext = $rsa->encrypt($plaintext);
-
-$rsa->loadKey($publickey);
-echo $rsa->decrypt($ciphertext);
-?>

Here's an example of how to create / verify a signature with Crypt_RSA:

<?php
-include('Crypt/RSA.php');
-
-$rsa = new Crypt_RSA();
-extract($rsa->createKey());
-
-$plaintext = 'terrafrost';
-
-$rsa->loadKey($privatekey);
-$signature = $rsa->sign($plaintext);
-
-$rsa->loadKey($publickey);
-echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
->

4.2.3. createKey()

- createKey() takes three parameters - $bits, $timeout, - and $primes. $timeout is present since creating a key has the potential to be - fairly time consuming and will guarantee that createKey() does not run for more than - $timeout seconds. $primes lets provide pre-computed prime numbers to speed - things up. -

- extract($rsa->createKey()) creates three variables - $publickey, - $privatekey, and $partialkey. If createKey hit the timeout then - it'll return all the primes that it had managed to compute so that you might pass them back to - createKey() on a subsequent call. -

- The exponent can be set by defining CRYPT_RSA_EXPONENT and multi-prime RSA can be utilized - by adjusting CRYPT_RSA_SMALLEST_PRIME. Note that these must be done before a Crypt_RSA() - object is initialized. -

- Smaller values for CRYPT_RSA_SMALLEST_PRIME result in increased speed at the cost of security. -

4.2.4. setPrivateKeyFormat(), setPublicKeyFormat(), loadKey() and setPassword()

Crypt_RSA supports the following formats:

CRYPT_RSA_PRIVATE_FORMAT_PKCS1:

-----BEGIN RSA PRIVATE KEY-----
-MIICWgIBAAKBgHx5XHa3LjiugtNq2xkd0oFf2SdsJ04hQYLoeRR3bqAei3Gc+PSy
-AvynCIh/03JCvBsUHaCe8BwjwaTYrpq5QunGo/wvIzvx2d3G9dlrpOIFLiatZYOf
-h07+CkSfaRXhBUKkul/gU87WPhKEcbnPDJS10uD1HqLsHfSKLNitGOf7AgElAoGA
-ENIhQHmedlzFkjEI2eFveURNxw6dhxlANEjtxH7XmRjiaUyQWGsVKQ+nNQpa2Bbb
-JkD9FbSc/OI8wz/gPmwP9eJN29CriebhaV3ebM1L1gbb5r7Vf/D/6rxB0BG/h2lA
-jyZWEZrV/Gi9ZCaw/J+IUu1pAskKid84yHphvszywCUCQQDigrtr+cVkwkUsxOGd
-B378yQCroXmybAD7FQHwVslafuFfTHkaMQSU/ZZLVY1ioMs1VVzzq/vOu0RstZOY
-AfHFAkEAjK3mIWdG4JOM44/SrDkACNatsMtXKOi4K3SlXu9ie6ikXPD+GSZ+bWCX
-GstFaXr9cHRvZPF3qYtK+j2N9UXOvwJBALeoRO/DmSFDkgifoixLRF5CHDgiD6Vs
-U9J/vGIBLaNSHoSe3rtKVr3+CyhTNF3Oe0AABi1bA4UGioGn+yFNr0UCQBbQF3sJ
-1CRq9ECT3PlVWfOYbzFtFQ2NhaYul1uAw9yzkEZsROF73SZ+XbFRZTOzFFds08su
-E2eaDCiUXDWcnhECQQCRUQn2huHlssj8kt35NAVwiHCNfaeSQ5tiDcwfOywA4YXl
-Q+kpuWq5U3V8j/9/n7pE/DL0nXEG/3QpKHJEYV5T
------END RSA PRIVATE KEY-----

CRYPT_RSA_PRIVATE_FORMAT_PKCS1 (with password):

-----BEGIN RSA PRIVATE KEY-----
-Proc-Type: 4,ENCRYPTED
-DEK-Info: DES-EDE3-CBC,0AE1DB47E71463BE
-
-pI2Kk5ceURbMYNo1xQqqA5rm2/QP4hgj/HuvrACtPSz/aesbG+h4lYXGpQ9os6Ha
-AyFW+iX2UWS6BRwJj1ztO20sKT6ckg7eINSfiSSAeOOiG5aHLxOYayO9aQ5UrrJX
-r0QmwRJRiHTW/82PLBNzfFHYskslNI9EWA5L/Gg4NAXDWwDooGvGkDq3ex7WkWLr
-k7DN2JoZuWsUZxwpgTDouRQMsygrsdSjwRDSgbnTn6luEBrL9fc5/oAWf0xoTk5h
-XMiOOHPBNPiZ1883ayq91HL/6895g8U9oIR1wQmdl0USViYYp5jI19ueowCyblzP
-xD3Bfpb6RPaZ/yqECOysPk6PDz257SGDMNk/QrQJ/eZkeniNXHJ8d+nJGuajZeBu
-6A/bglvKGNNNWe8UJMb5P2OAliD7y7F9wXrkV5FnQ/Q49tGxdBl7WXNuGp4x2d9s
-ZEnv3mOtrr1lM+2QE0Zg8mjqSem5b6Dp0LxOj5j45j5IbBrrd3MKu87jJVzp8yHy
-sBC6NMYYtO03qxV/j1kJR+MmAcCF1+4GGRWdFcoc0sXGVqmEOmK4QfYx3T0Vb6Hk
-oLdlh6ofZogezzJ8A1BvV382sTsJ90eqbgz3E+fDl8iR86+EV9bUujFE4IaBgZJP
-gxikVItdTcq1frNKTCSH/RPeRwk+oKWTpCYGgNA+bl641onW1DCLYcd14N6TDKmY
-77cOTf2ZDGOYNPycAF/FnNJJyLO3IYpU63aKBshB4dYeVrfH0FvG6g5Xt0geIkiD
-5W9El4ks7/3r97x443SagDRt6Mceo5TtzzFfAo7cZeA=
------END RSA PRIVATE KEY-----

CRYPT_RSA_PUBLIC_FORMAT_PKCS1:

-----BEGIN PUBLIC KEY-----
-MIGGAoGAfHlcdrcuOK6C02rbGR3SgV/ZJ2wnTiFBguh5FHduoB6LcZz49LIC/KcIiH/TckK8GxQd
-oJ7wHCPBpNiumrlC6caj/C8jO/HZ3cb12Wuk4gUuJq1lg5+HTv4KRJ9pFeEFQqS6X+BTztY+EoRx
-uc8MlLXS4PUeouwd9Ios2K0Y5/sCASU=
------END PUBLIC KEY-----

CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:

ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIB8eVx2ty44roLTatsZHdKBX9knbCdOIUGC6HkUd26gHotx
-nPj0sgL8pwiIf9NyQrwbFB2gnvAcI8Gk2K6auULpxqP8LyM78dndxvXZa6TiBS4mrWWDn4dO/gpEn2kV
-4QVCpLpf4FPO1j4ShHG5zwyUtdLg9R6i7B30iizYrRjn+w== phpseclib-generated-key

- Passwords can be set via setPassword() and are only supported on private keys. - CRYPT_RSA_PUBLIC_FORMAT_OPENSSH generates keys that are intended to go in $HOME/.ssh/authorized_keys - for use with OpenSSH. Another format - CRYPT_RSA_PUBLIC_FORMAT_RAW - is stored as an array with two - indexes - one for the modulus and one for the exponent. Indexes accepted by loadkey() - are as follows: -

- e, exponent, publicExponent, modulus, modulo, n -

- loadKey() has two parameters - $key and the optional $type. - The default type, if $type is not explicitely set, is CRYPT_RSA_PRIVATE_FORMAT_PKCS1. - It should, at this point, be noted that Crypt_RSA treats public and private keys largelly identically. - A key can be formatted as a CRYPT_RSA_PUBLIC_FORMAT_PKCS1 and still conform to the - CRYPT_RSA_PRIVATE_FORMAT_PKCS1 format and vice versa. The only real difference between private keys and - public keys is that private keys *can* contain their public key counterparts whereas public keys cannot. - That said, this distinction is, for the most part, irrelevant and academic. For a more thorough - discussion of this see setPublicKey() and getPublicKey(). -

4.2.5. setPublicKey() and getPublicKey()

- As noted in setPrivateKeyFormat(), setPublicKeyFormat(), loadKey() and setPassword(), - Crypt_RSA treats public and private keys largely identically. The only real difference is that some - private key formats contain the public key within them whereas no public key format does. The reason - you'd want to do this is for indexing purposes. For example, in SSH-2, RSA authentication works by - sending your public key along with a signature created by your private key. The SSH-2 server then looks - the public key up in an index of public keys to see if it's an allowed key and then verifies the signature. - To that end, setPublicKey() defines the public key if it hasn't already been defined and - getPublicKey() returns it. getPublicKey() has an optional parameter - $type - - that sets the format. -

4.2.6. encrypt(), decrypt() and setEncryptionMode()

- Crypt_RSA supports two encryption modes - CRYPT_RSA_ENCRYPTION_OAEP and - CRYPT_RSA_ENCRYPTION_PKCS1. CRYPT_RSA_ENCRYPTION_OAEP uses - Optimal Asymmetric Encryption Padding - and provides more security than CRYPT_RSA_ENCRYPTION_PKCS1. -

- Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 impose limits - on how large the plaintext can be. If the plaintext exceeds these limits the plaintext will be split - up such that each block falls within those limits. -

4.2.7. sign(), verify(), and setSignatureMode()

- Crypt_RSA supports two signature modes - CRYPT_RSA_SIGNATURE_PSS and - CRYPT_RSA_SIGNATURE_PKCS1. The former is assumed to provide more security than the latter. - See Examples for examples. -

4.2.8. setHash(), setMGFHash() and setSaltLength()

- In all likelihood, calling these functions will be unnecessary as the default values should be sufficient. - None-the-less a discussion of them follows. -

- setHash() is used with signature production / verification and (if the encryption mode is - CRYPT_RSA_ENCRYPTION_OAEP) encryption and decryption. If the specified hash isn't supported sha1 will - be used. -

- setMGFHash() determines which hashing function should be used for the mask generation - function as utilized in CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS. PKCS#1 recommends - but does not require that the MGFHash and the Hash be set to the same thing. -

- setSaltLength() is only utilized with CRYPT_RSA_SIGNATURE_PSS. PKCS#1 recommends this - value either be 0 (which is what it is by default) or the length of the output of the hash function as - set via setHash() -

diff --git a/library/phpsec/net.html b/library/phpsec/net.html deleted file mode 100644 index 2752b826d4..0000000000 --- a/library/phpsec/net.html +++ /dev/null @@ -1,153 +0,0 @@ - - -Chapter 5. Networking

Chapter 5. Networking

5.1. Net_SSH

- The Net_SSH1 and Net_SSH2 libraries have, for the most part, an identical API. Some functions, however, do behave differently. -

5.1.1. Dependencies

- Net_SSH1/2 require, minimally, Math/BigInteger.php, Crypt/*.php, and PHP/Compat/Function/*.php. Net_SSH1 requires PHP 4.0.0 unless you're using the interactive functions, which require PHP 4.3.0. Net_SSH2 requires PHP 4.3.0 due to it's use of sha1(). -

5.1.2. Net_SSH1 Examples

<?php
-    include('Net/SSH1.php');
-
-    $ssh = new Net_SSH1('www.domain.tld');
-    if (!$ssh->login('username', 'password')) {
-        exit('Login Failed');
-    }
-
-    while (true) {
-        echo $ssh->interactiveRead();
-
-        $read = array(STDIN);
-        $write = $except = NULL;
-        if (stream_select($read, $write, $except, 0)) {
-            $ssh->interactiveWrite(fread(STDIN, 1));
-        }
-    }
-?>
<?php
-    include('Net/SSH1.php');
-
-    $ssh = new Net_SSH1('www.domain.tld');
-    if (!$ssh->login('username', 'password')) {
-        exit('Login Failed');
-    }
-
-    echo $ssh->exec('ls -la');
-?>

5.1.3. Net_SSH2 Examples

<?php
-    include('Net/SSH2.php');
-
-    $ssh = new Net_SSH2('www.domain.tld');
-    if (!$ssh->login('username', 'password')) {
-        exit('Login Failed');
-    }
-
-    echo $ssh->exec('pwd');
-    echo $ssh->exec('ls -la');
-?>
<?php
-    include('Crypt/RSA.php');
-    include('Net/SSH2.php');
-
-    $key = new Crypt_RSA();
-    //$key->setPassword('whatever');
-    $key->loadKey(file_get_contents('privatekey'));
-
-    $ssh = new Net_SSH2('www.domain.tld');
-    if (!$ssh->login('username', $key)) {
-        exit('Login Failed');
-    }
-
-    echo $ssh->exec('pwd');
-    echo $ssh->exec('ls -la');
-?<

5.1.4. Host Key Verification

- SSH protects itself against active eavesdroppers by providing a host key. The first time you connect the host key is supposed to be cached in some manner. On subsequent connections, the host key being used for this connection should be checked against the cached host key. If they match, it's the same server. If not, it's a different one. -

- In SSH-1, getHostKeyPublicModulus() and getHostKeyPublicExponent() will provide you with the host key. In SSH-2, getServerPublicHostKey() gets you the key. -

- The Net_SSH1 and Net_SSH2 examples omit the key verification stage for brevity. Also, depending on the context in which this library is used, it may even be unnecessary. For example, if you're connecting to www.example.com:22 from www.example.com:80, eavesdroppers are not something you need to worry about. -

5.1.5. interactiveRead() / interactiveWrite() vs. exec()

- Say you wanted to use SSH to get the contents of a directory. If you used interactiveWrite('ls') to do this, and then interactiveRead() to get the output, you, in all likelihood, wouldn't get the whole output. You'd have to call interactiveRead() multiple times - you'd have to call it as many times as it took for you to get the complete output, which, in turn, begs the question... how do you know when you have the complete output? - You could assume that whenever the prompt (eg. root@desktop:/root#) showed up, that that'd mean you had the complete output, but that's not fool proof. And what about messages of the day? The first interactiveRead() you do is liable to include a part of that rather than the directory listing. So, not only do you have to make some sort of guestimate as to when the output ends - you often may have to guestimate as to when it begins. -

- To top it all off, you may also get ANSI escape codes interspersed amongst the output, which would need to be removed. -

- Using exec('ls') resolves all of these issues. If you're implementing an interactive client, the interactive functions are the ones you'll want to use. Otherwise, exec() is likely what you'll want to use. -

- interactiveRead() / interactiveWrite() are not implemented in Net_SSH2. The SSH-2 protocol supports them, however, phpseclib does not. The reasons are discussed in the SSH-1's exec() vs. SSH-2's exec() section. -

5.1.6. SSH-1's exec() vs. SSH-2's exec()

- exec() works by creating a channel, issuing a command, and then subsequently destroying that channel. Since SSH-1 only allows one channel, exec() can only be called once. SSH-2, in contrast, allows an unlimited number of channels, and as such, you can perform as many exec()'s as you see fit. -

- As a consequence of this difference, Net_SSH2 does not implement interactiveRead() / interactiveWrite(), even though the SSH-2 specifications provide for those functions. Simply put, in SSH-1, those functions are necessary to do multiple commands. In SSH-2, they're not, and so they're not implemented. -

5.1.7. Successive calls to SSH-2's exec()

- Successive calls to SSH-2's exec() may not work as expected. Consider the following: -

<?php
-    include('Net/SSH2.php');
-
-    $ssh = new Net_SSH2('www.domain.tld');
-    if (!$ssh->login('username', 'password')) {
-        exit('Login Failed');
-    }
-
-    echo $ssh->exec('pwd');
-    echo $ssh->exec('cd /');
-    echo $ssh->exec('pwd');
-?>

- If done on an interactive shell, the output you'd receive for the first pwd would (depending on how your system is setup) be different than the output of the second pwd. The above code snippet, however, will yield two identical lines. The reason for this is that any "state changes" you make to the one-time shell are gone once the exec() has been ran and the channel has been deleted. - As such, if you want to support cd in your program, it'd be best to just handle that internally and rewrite all commands, before they're passed to exec() such that the relative paths are expanded to the absolute paths. - Alternatively, one could always run a shell script, however, that may not always be an option. -

5.1.8. Debugging SSH-2

- To log output, the NET_SSH2_LOGGING constant will need to be defined. If you want full logs, you'll need to do define('NET_SSH2_LOGGING', NET_SSH2_LOG_COMPLEX). $ssh->getLog() will then return a string containing the unencrypted packets in hex and ASCII. If you want to just record the packet types that are being sent to and fro, you'll need to do define('NET_SSH2_LOGGING', NET_SSH2_LOG_SIMPLE). $ssh->getLog() will then return an array. Both log types include the amount of time it took to send the packet in question. The former is useful for general diagnostics and the latter is more useful for profiling. An example follows: -

<?php
-    include('Net/SSH2.php');
-    define('NET_SSH2_LOGGING', NET_SSH2_LOG_COMPLEX);
-
-    $ssh = new Net_SSH2('www.domain.tld');
-    if (!$ssh->login('username', 'password')) {
-        exit('Login Failed');
-    }
-
-    echo $ssh->exec('pwd');
-    echo $ssh->getLog();
-?>

- Depending on the problem, it may be more effective to just look at the output of $ssh->getLastError() (which returns a string) and $ssh->getErrors() (which returns an array) than to sift through the logs. -

5.2. Net_SFTP

5.2.1. Introduction

- Net_SFTP currently only supports SFTPv3, which, according to wikipedia.org, "is the most widely used - version, implemented by the popular OpenSSH SFTP server". -

5.2.2. Dependencies

- Net_SFTP requires, minimally, PHP 4.3.0 and Net/SSH2.php, Math/BigInteger.php, Crypt/*.php, and PHP/Compat/Function/*.php. -

5.2.3. Net_SFTP Example

<?php
-include('Net/SFTP.php');
-
-$sftp = new Net_SFTP('www.domain.tld');
-if (!$sftp->login('username', 'password')) {
-    exit('Login Failed');
-}
-
-echo $sftp->pwd() . "\r\n";
-$sftp->put('filename.ext', 'hello, world!');
-print_r($sftp->nlist());
-?>

5.2.4. put($remote_file, $data [, $mode])

- By default, put() does not read from the local filesystem. $data is dumped directly into $remote_file. - So, for example, if you set $data to 'filename.ext' and then do get(), you will get a file, twelve bytes - long, containing 'filename.ext' as its contents. -

- Setting $mode to NET_SFTP_LOCAL_FILE will change the above behavior. With NET_SFTP_LOCAL_FILE, $remote_file will - contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how - large $remote_file will be, as well. -

- Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take - care of that, yourself. -

5.2.5. get($remote_file [, $local_file])

- Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if - the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the - operation -

5.2.6. pwd(), chdir(), mkdir() and rmdir()

- pwd() returns the current directory, chdir() changes directories, mkdir() creates direcotires, and rmdir() removes directories. - In the event of failure, they all return false. chdir(), mkdir(), and rmdir() return true on successful completion of the operation. -

5.2.7. chmod() and size()

- chmod() sets the permissions on a file and returns the new file permissions on success or false on error. Permissions are expected to be in octal so to set a file to 777 do $sftp->chmod(0777, $filename) -

- size() returns the size, in bytes, of an arbitrary file. -

5.2.8. nlist() and rawlist()

- nlist($dir = '.') returns the contents of the current directory as a numerically indexed array and rawlist() returns an associate array where the filenames are the array keys and the array values are, themselves, arrays containing the file attributes. The directory can be changed with the first parameter. -

5.2.9. delete() and rename()

- The purpose of both functions should be easy enough to glean - delete() deletes files or directories and rename() renames them. Both return true on success and false on failure. -

5.2.10. Debugging SFTP

- Debbuging SFTP connections in phpseclib works in a manner similar to debugging SSH-2 Instead of the constant being NET_SSH2_LOGGING, however, it's NET_SFTP_LOGGING. And instead of NET_SSH2_LOG_COMPLEX or NET_SSH2_LOG_SIMPLE it's NET_SFTP_LOG_COMPLEX or NET_SFTP_LOG_SIMPLE respectively. And instead of calling $sftp->getLog() you call $sftp->getSFTPLog() or $sftp->getLastSFTPError() or whatever. -

diff --git a/library/phpsec/sym_crypt.html b/library/phpsec/sym_crypt.html deleted file mode 100644 index 956506290c..0000000000 --- a/library/phpsec/sym_crypt.html +++ /dev/null @@ -1,118 +0,0 @@ - - -Chapter 3. Symmetric-key Cryptography

Chapter 3. Symmetric-key Cryptography

3.1. Introduction

- All of the cryptographic libraries included in phpseclib use mcrypt, if available, and an internal implementation - if it's not. The libraries all use a common interface although some functions, for some algorithms, carry with - with them certain caveats. Those that do not have caveats attached (or have relatively few attached) are - described below. If you don't know which one to use, try Crypt_TripleDES. -

3.1.1. Dependencies

- The Crypt_* functions require, minimally, PHP 4.0.0. Crypt_TripleDES additionally requires Crypt/DES.php. -

3.1.2. setKey() and setIV()

- Sets the key and the initialization vector, respectively. If neither are set, each assumed to be equal to - some amount of null bytes. The initialization vector is only used in block ciphers and even then only - in CBC mode. If the key or the initialization vector are larger then the block size, they're truncated. - If they're smaller, they're padded with null bytes. -

3.1.3. encrypt() and decrypt()

- Self-explanatory. Encrypts or decrypts messages. See the examples in the subsequent sections. -

3.1.4. enableContinuousBuffer() and disableContinuousBuffer()

- If the continuous buffer is enabled and you're using a stream cipher or a block cipher mode other than ECB then encrypting the same string twice will yield different ciphertexts. - The reason being that the IV doesn't reset after each encryption / decryption round when the continuous buffer is used. - This provides better security but it may also make for less intuitive behavior. - For this reason, the continuous buffer is disabled by default. -

3.1.5. enablePadding() and disablePadding()

- Enables / disables PKCS padding on block ciphers. Stream ciphers (Crypt_RC4 is the only stream - cipher currently included) ignore this. -

3.1.6. A word of caution about stream ciphers and CTR mode

- Most stream ciphers (and block ciphers operating in a mode - like CTR - that turns them into stream ciphers) work by generating a stream of pseudorandom characters called a keystream and then XOR'ing that with the plaintext. - This *effectively* makes them one-time pads which, in theory, can provide perfect secrecy. The problem with one-time pads is that they're not as versatile as one might desire. - Among other things, a keystream must never be reset, lest it be possible for an attacker to recover the keystream via a known-plaintext attack. ie. $ciphertext ^ $plaintext = $key. If $key is constant (because the keystream's being reset or something) than an attacker can recover any $plaintext, but if not - if it's dynamic - then the only key that an attacker could recover is their own. -

3.2. Crypt_DES

- Implements DES (a block cipher). Here's an example of how to use it: -

<?php
-    include('Crypt/DES.php');
-
-    $des = new Crypt_DES();
-
-    $des->setKey('abcdefgh');
-
-    $size = 10 * 1024;
-    $plaintext = '';
-    for ($i = 0; $i < $size; $i++) {
-        $plaintext.= 'a';
-    }
-
-    echo $des->decrypt($des->encrypt($plaintext));
-?>

3.2.1. The constructor

- The constructor takes one optional parameter - $mode. Valid values for $mode are as follows: -

  • CRYPT_DES_MODE_ECB
  • CRYPT_DES_MODE_CBC: The default value.
  • CRYPT_DES_MODE_CTR

3.3. Crypt_TripleDES

- Implements TripleDES (a block cipher). Here's an example of how to use it: -

<?php
-    include('Crypt/TripleDES.php');
-
-    $des = new Crypt_TripleDES();
-
-    $des->setKey('abcdefghijklmnopqrstuvwx');
-
-    $size = 10 * 1024;
-    $plaintext = '';
-    for ($i = 0; $i < $size; $i++) {
-        $plaintext.= 'a';
-    }
-
-    echo $des->decrypt($des->encrypt($plaintext));
-?>

3.3.1. The constructor

- The constructor takes one optional parameter - $mode. Valid values for $mode are as follows: -

  • CRYPT_DES_MODE_ECB
  • CRYPT_DES_MODE_CBC3: Employs outer chaining to propogate the initialization vector. Used by SSH-2 and generally considered more secure than inner chaining.
  • CRYPT_DES_MODE_3CBC: Employs inner chaining to propogate the initialization vector. Used by SSH-1.
  • CRYPT_DES_MODE_CBC: The default value. An alias for CRYPT_DES_MODE_CBC3.
  • CRYPT_DES_MODE_CTR

3.4. Crypt_RC4

- Implements RC4 (a stream cipher). Here's an example of how to use it: -

<?php
-    include('Crypt/RC4.php');
-
-    $rc4 = new Crypt_RC4();
-
-    $rc4->setKey('abcdefghijklmnopqrstuvwx');
-
-    $size = 10 * 1024;
-    $plaintext = '';
-    for ($i = 0; $i < $size; $i++) {
-        $plaintext.= 'a';
-    }
-
-    echo $rc4->decrypt($rc4->encrypt($plaintext));
-?>

3.4.1. The constructor

- Not much to say about this constructor. Since it's a stream cipher, you don't need to worry about which - mode of operation to use. -

3.5. Crypt_Rijndael & Crypt_AES

- Implements Rijndael / AES. Here's an example of how to use Crypt_AES: -

<?php
-    include('Crypt/AES.php');
-
-    $aes = new Crypt_AES();
-
-    $aes->setKey('abcdefghijklmnop');
-
-    $size = 10 * 1024;
-    $plaintext = '';
-    for ($i = 0; $i < $size; $i++) {
-        $plaintext.= 'a';
-    }
-
-    echo $aes->decrypt($aes->encrypt($plaintext));
-?>

3.5.1. The constructor

- Crypt_AES's constructor's optional parameter can take the following values: -

  • CRYPT_AES_MODE_ECB
  • CRYPT_AES_MODE_CBC: The default value.
  • CRYPT_AES_MODE_CTR

- Crypt_Rijndael takes the following: -

  • CRYPT_RIJNDAEL_MODE_ECB
  • CRYPT_RIJNDAEL_MODE_CBC: The default value.
  • CRYPT_RIJNDAEL_MODE_CTR

3.5.2. AES vs. Rijndael

- AES is a subset of Rijndael. Both have variable key sizes, however, AES's block size is fixed at 128 bits, whereas Rijndael's is variable. Also, Rijndael supports, by means of an extension to the specification, two key sizes that AES does not - 160 bits and 224 bits. -

3.5.3. setKeyLength()

- Valid key lengths for AES are 128 bits, 192 bits, and 256 bits. If the key that is assigned is invalid and less than 256 bits, they key length is rounded up to the next closest valid size and the key will be null padded to that amount. If the key length is greater than 256 bits, it will be truncated to 256 bits. -

- As an example, if the key is 136 bits, it will be null padded to 192 bits (or 160 bits if Rijndael is being used). -

- If setKeyLength() has been called, this behavior changes somewhat. Say you've set the key length, via this function, to 256 bits. Then, instead of an invalid key being null padded to 192 or 160 bits, it will be null padded to 256 bits. -

3.5.4. setBlockLength()

- setBlockLength() operates in a manner similar to setKeyLength(), with one exception. setBlockLength() only works on Rijndael. Although Crypt_AES inherits setBlockLength() as a function, the function doesn't do anything in AES. -

3.5.5. Speed Comparisons

- The following table compares the speed of five different pure-PHP implementations of AES (one of which is Crypt_Rijndael and one of which is Crypt_AES) when ran on 150KB of text on a 1.8GHz Pentium 4-M. The numbers listed are averaged from five different trials and are measured in seconds. phpseclib's two implementations are highlighted. All implementations can be viewed by clicking on their names. -

Table 3.1. AES Speed Comparisons

movable-type.phpsphpaes.phpsphpclasses1.phpsphpclasses2.phpsphpseclib-aes.phpsphpseclib-rijndael.phps
15.684415817239.953724813515.010015010862.5917131900792.035815429687522.62501101493836

- As can be seen, phpseclib's implementations are the fastest. phpseclib-aes.phps is faster than phpseclib-rijndael.phps because phpseclib-rijndael.phps has to contend with multiple block sizes whereas phpseclib-aes.phps does not. Note that if mcrypt weren't explicitily disabled phpseclib would have been even faster. -

diff --git a/mod/admin.php b/mod/admin.php index aee1017b34..caf68007b1 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -811,12 +811,7 @@ function admin_page_site_post(App $a) { set_config('system','worker_dont_fork', $worker_dont_fork); set_config('system','worker_fastlane', $worker_fastlane); set_config('system','frontend_worker', $worker_frontend); - - if (($rino == 2) and !function_exists('mcrypt_create_iv')) { - notice(t("RINO2 needs mcrypt php extension to work.")); - } else { - set_config('system','rino_encrypt', $rino); - } + set_config('system','rino_encrypt', $rino); info(t('Site settings updated.').EOL); goaway('admin/site'); diff --git a/mod/dfrn_confirm.php b/mod/dfrn_confirm.php index e2ce806275..7a3882a5ba 100644 --- a/mod/dfrn_confirm.php +++ b/mod/dfrn_confirm.php @@ -185,10 +185,10 @@ function dfrn_confirm_post(App $a, $handsfree = null) { * */ - $src_aes_key = random_string(); + $src_aes_key = openssl_random_pseudo_bytes(64); $result = ''; - openssl_private_encrypt($dfrn_id,$result,$user[0]['prvkey']); + openssl_private_encrypt($dfrn_id, $result, $user[0]['prvkey']); $params['dfrn_id'] = bin2hex($result); $params['public_key'] = $public_key; diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index d34c959f1f..8df462e58f 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -142,8 +142,6 @@ function dfrn_notify_post(App $a) { $rino = get_config('system','rino_encrypt'); $rino = intval($rino); - // use RINO1 if mcrypt isn't installed and RINO2 was selected - if ($rino==2 and !function_exists('mcrypt_create_iv')) $rino=1; logger("Local rino version: ". $rino, LOGGER_DEBUG); @@ -184,7 +182,7 @@ function dfrn_notify_post(App $a) { case 1: // we got a key. old code send only the key, without RINO version. // we assume RINO 1 if key and no RINO version - $data = aes_decrypt(hex2bin($data),$final_key); + $data = dfrn::aes_decrypt(hex2bin($data),$final_key); break; case 2: try { @@ -315,8 +313,6 @@ function dfrn_notify_content(App $a) { $rino = get_config('system','rino_encrypt'); $rino = intval($rino); - // use RINO1 if mcrypt isn't installed and RINO2 was selected - if ($rino==2 and !function_exists('mcrypt_create_iv')) $rino=1; logger("Local rino version: ". $rino, LOGGER_DEBUG); diff --git a/mod/install.php b/mod/install.php index fa952a79bc..ce229244c0 100755 --- a/mod/install.php +++ b/mod/install.php @@ -78,14 +78,7 @@ function install_post(App $a) { $timezone = notags(trim($_POST['timezone'])); $language = notags(trim($_POST['language'])); $adminmail = notags(trim($_POST['adminmail'])); - // In step 4 of the installer, we passed the check for mcrypt - // already, so we can activate RINO, make RINO2 the default - // and only fall back if the mcrypt_create_iv function is - // not available on the system. $rino = 2; - if (! function_exists('mcrypt_create_iv')) { - $rino = 1; - } // connect to db $db = new dba($dbhost, $dbuser, $dbpass, $dbdata, true); @@ -422,7 +415,6 @@ function check_funcs(&$checks) { check_add($ck_funcs, t('OpenSSL PHP module'), true, true, ""); check_add($ck_funcs, t('mysqli PHP module'), true, true, ""); check_add($ck_funcs, t('mb_string PHP module'), true, true, ""); - check_add($ck_funcs, t('mcrypt PHP module'), true, true, ""); check_add($ck_funcs, t('XML PHP module'), true, true, ""); check_add($ck_funcs, t('iconv module'), true, true, ""); @@ -454,10 +446,6 @@ function check_funcs(&$checks) { $ck_funcs[4]['status']= false; $ck_funcs[4]['help']= t('Error: mb_string PHP module required but not installed.'); } - if (! function_exists('mcrypt_create_iv')){ - $ck_funcs[5]['status']= false; - $ck_funcs[5]['help']= t('Error: mcrypt PHP module required but not installed.'); - } if (! function_exists('iconv_strlen')){ $ck_funcs[7]['status']= false; $ck_funcs[7]['help']= t('Error: iconv PHP module required but not installed.'); @@ -465,18 +453,6 @@ function check_funcs(&$checks) { $checks = array_merge($checks, $ck_funcs); - // check for 'mcrypt_create_iv()', needed for RINO2 - if ($ck_funcs[5]['status']) { - if (function_exists('mcrypt_create_iv')) { - $__status = true; - $__help = t("If you are using php_cli, please make sure that mcrypt module is enabled in its config file"); - } else { - $__status = false; - $__help = t('Function mcrypt_create_iv() is not defined. This is needed to enable RINO2 encryption layer.'); - } - check_add($checks, t('mcrypt_create_iv() function'), $__status, false, $__help); - } - // check for XML DOM Documents being able to be generated try { $xml = new DOMDocument(); diff --git a/view/templates/htconfig.tpl b/view/templates/htconfig.tpl index 78a2e47df2..f8a6bc1c90 100644 --- a/view/templates/htconfig.tpl +++ b/view/templates/htconfig.tpl @@ -80,9 +80,8 @@ $a->config['system']['maximagesize'] = 800000; $a->config['system']['huburl'] = '[internal]'; // Server-to-server private message encryption (RINO) is allowed by default. -// Encryption will only be provided if this setting is set to a non zero -// value and the PHP mcrypt extension is installed on both systems -// set to 0 to disable, 2 to enable, 1 is deprecated but wont need mcrypt +// Encryption will only be provided if this setting is set to a non zero value +// set to 0 to disable, 2 to enable, 1 is deprecated $a->config['system']['rino_encrypt'] = {{$rino}}; From 16d4392573829b5b02db449778cdc4bc4b2e0cbc Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 1 Apr 2017 09:05:56 +0000 Subject: [PATCH 07/16] Documentation added --- include/dfrn.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/dfrn.php b/include/dfrn.php index acd16dc618..4002bb4268 100644 --- a/include/dfrn.php +++ b/include/dfrn.php @@ -864,10 +864,26 @@ class dfrn { return $entry; } + /** + * @brief encrypts data via AES + * + * @param string $data The data that is to be encrypted + * @param string $key The AES key + * + * @return string encrypted data + */ private static function aes_encrypt($data, $key) { return openssl_encrypt($data, 'aes-128-ecb', $key, OPENSSL_RAW_DATA); } + /** + * @brief decrypts data via AES + * + * @param string $encrypted The encrypted data + * @param string $key The AES key + * + * @return string decrypted data + */ public static function aes_decrypt($encrypted, $key) { return openssl_decrypt($encrypted, 'aes-128-ecb', $key, OPENSSL_RAW_DATA); } From 648d5bd047ce59e425db39a3789985f305697ae1 Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 1 Apr 2017 10:07:12 +0000 Subject: [PATCH 08/16] More mcrypt is removed --- doc/Install.md | 1 - doc/de/Install.md | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/Install.md b/doc/Install.md index 9a194254a0..b817339bb0 100644 --- a/doc/Install.md +++ b/doc/Install.md @@ -30,7 +30,6 @@ Requirements * PHP *command line* access with register_argc_argv set to true in the php.ini file * curl, gd, mysql, hash and openssl extensions * some form of email server or email gateway such that PHP mail() works -* mcrypt (optional; used for server-to-server message encryption) * Mysql 5.5.3+ or an equivalant alternative for MySQL (MariaDB, Percona Server etc.) * the ability to schedule jobs with cron (Linux/Mac) or Scheduled Tasks (Windows) (Note: other options are presented in Section 7 of this document.) * Installation into a top-level domain or sub-domain (without a directory/path component in the URL) is preferred. Directory paths will not be as convenient to use and have not been thoroughly tested. diff --git a/doc/de/Install.md b/doc/de/Install.md index df95735f36..740202310c 100644 --- a/doc/de/Install.md +++ b/doc/de/Install.md @@ -26,7 +26,6 @@ Wir planen, diese Einschränkung in einer zukünftigen Version zu beheben. - PHP *Kommandozeilen*-Zugang mit register_argc_argv auf "true" gesetzt in der php.ini-Datei - curl, gd, mysql und openssl-Erweiterung - etwas in der Art eines Email-Servers oder eines Gateways wie PHP mail() - - mcrypt (optional; wird für die Server-zu-Server Nachrichtenentschlüsselung benötigt) - Mysql 5.x - die Möglichkeit, wiederkehrende Aufgaben mit cron (Linux/Mac) oder "Scheduled Tasks" einzustellen (Windows) [Beachte: andere Optionen sind in Abschnitt 7 dieser Dokumentation zu finden] - Installation in einer Top-Level-Domain oder Subdomain (ohne eine Verzeichnis/Pfad-Komponente in der URL) wird bevorzugt. Verzeichnispfade sind für diesen Zweck nicht so günstig und wurden auch nicht ausführlich getestet. @@ -37,7 +36,7 @@ Wir planen, diese Einschränkung in einer zukünftigen Version zu beheben. 1.1. APT-Pakete - Apache: sudo apt-get install apache2 - PHP5: sudo apt-get install php5 - - PHP5-Zusätzliche Pakete: sudo apt-get install php5-curl php5-gd php5-mysql php5-mcrypt + - PHP5-Zusätzliche Pakete: sudo apt-get install php5-curl php5-gd php5-mysql - MySQL: sudo apt-get install mysql-server 2. Entpacke die Friendica-Daten in das Quellverzeichnis (root) des Dokumentenbereichs deines Webservers. From 240a0961c671b1418b2178d17c69b1117894744a Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 1 Apr 2017 17:08:11 +0000 Subject: [PATCH 09/16] Standards ... --- mod/admin.php | 94 +++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/mod/admin.php b/mod/admin.php index caf68007b1..cf0714ef90 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -761,57 +761,57 @@ function admin_page_site_post(App $a) { } else { set_config('system','singleuser', $singleuser); } - set_config('system','maximagesize', $maximagesize); - set_config('system','max_image_length', $maximagelength); - set_config('system','jpeg_quality', $jpegimagequality); + set_config('system', 'maximagesize', $maximagesize); + set_config('system', 'max_image_length', $maximagelength); + set_config('system', 'jpeg_quality', $jpegimagequality); - set_config('config','register_policy', $register_policy); - set_config('system','max_daily_registrations', $daily_registrations); - set_config('system','account_abandon_days', $abandon_days); - set_config('config','register_text', $register_text); - set_config('system','allowed_sites', $allowed_sites); - set_config('system','allowed_email', $allowed_email); - set_config('system','block_public', $block_public); - set_config('system','publish_all', $force_publish); - set_config('system','directory', $global_directory); - set_config('system','thread_allow', $thread_allow); - set_config('system','newuser_private', $newuser_private); - set_config('system','enotify_no_content', $enotify_no_content); - set_config('system','disable_embedded', $disable_embedded); - set_config('system','allow_users_remote_self', $allow_users_remote_self); + set_config('config', 'register_policy', $register_policy); + set_config('system', 'max_daily_registrations', $daily_registrations); + set_config('system', 'account_abandon_days', $abandon_days); + set_config('config', 'register_text', $register_text); + set_config('system', 'allowed_sites', $allowed_sites); + set_config('system', 'allowed_email', $allowed_email); + set_config('system', 'block_public', $block_public); + set_config('system', 'publish_all', $force_publish); + set_config('system', 'directory', $global_directory); + set_config('system', 'thread_allow', $thread_allow); + set_config('system', 'newuser_private', $newuser_private); + set_config('system', 'enotify_no_content', $enotify_no_content); + set_config('system', 'disable_embedded', $disable_embedded); + set_config('system', 'allow_users_remote_self', $allow_users_remote_self); - set_config('system','block_extended_register', $no_multi_reg); - set_config('system','no_openid', $no_openid); - set_config('system','no_regfullname', $no_regfullname); - set_config('system','community_page_style', $community_page_style); - set_config('system','max_author_posts_community_page', $max_author_posts_community_page); - set_config('system','verifyssl', $verifyssl); - set_config('system','proxyuser', $proxyuser); - set_config('system','proxy', $proxy); - set_config('system','curl_timeout', $timeout); - set_config('system','dfrn_only', $dfrn_only); - set_config('system','ostatus_disabled', $ostatus_disabled); - set_config('system','ostatus_poll_interval', $ostatus_poll_interval); - set_config('system','ostatus_full_threads', $ostatus_full_threads); - set_config('system','diaspora_enabled', $diaspora_enabled); + set_config('system', 'block_extended_register', $no_multi_reg); + set_config('system', 'no_openid', $no_openid); + set_config('system', 'no_regfullname', $no_regfullname); + set_config('system', 'community_page_style', $community_page_style); + set_config('system', 'max_author_posts_community_page', $max_author_posts_community_page); + set_config('system', 'verifyssl', $verifyssl); + set_config('system', 'proxyuser', $proxyuser); + set_config('system', 'proxy', $proxy); + set_config('system', 'curl_timeout', $timeout); + set_config('system', 'dfrn_only', $dfrn_only); + set_config('system', 'ostatus_disabled', $ostatus_disabled); + set_config('system', 'ostatus_poll_interval', $ostatus_poll_interval); + set_config('system', 'ostatus_full_threads', $ostatus_full_threads); + set_config('system', 'diaspora_enabled', $diaspora_enabled); - set_config('config','private_addons', $private_addons); + set_config('config', 'private_addons', $private_addons); - set_config('system','force_ssl', $force_ssl); - set_config('system','hide_help', $hide_help); - set_config('system','use_fulltext_engine', $use_fulltext_engine); - set_config('system','itemcache', $itemcache); - set_config('system','itemcache_duration', $itemcache_duration); - set_config('system','max_comments', $max_comments); - set_config('system','temppath', $temppath); - set_config('system','basepath', $basepath); - set_config('system','proxy_disabled', $proxy_disabled); - set_config('system','only_tag_search', $only_tag_search); - set_config('system','worker_queues', $worker_queues); - set_config('system','worker_dont_fork', $worker_dont_fork); - set_config('system','worker_fastlane', $worker_fastlane); - set_config('system','frontend_worker', $worker_frontend); - set_config('system','rino_encrypt', $rino); + set_config('system', 'force_ssl', $force_ssl); + set_config('system', 'hide_help', $hide_help); + set_config('system', 'use_fulltext_engine', $use_fulltext_engine); + set_config('system', 'itemcache', $itemcache); + set_config('system', 'itemcache_duration', $itemcache_duration); + set_config('system', 'max_comments', $max_comments); + set_config('system', 'temppath', $temppath); + set_config('system', 'basepath', $basepath); + set_config('system', 'proxy_disabled', $proxy_disabled); + set_config('system', 'only_tag_search', $only_tag_search); + set_config('system', 'worker_queues', $worker_queues); + set_config('system', 'worker_dont_fork', $worker_dont_fork); + set_config('system', 'worker_fastlane', $worker_fastlane); + set_config('system', 'frontend_worker', $worker_frontend); + set_config('system', 'rino_encrypt', $rino); info(t('Site settings updated.').EOL); goaway('admin/site'); From 1c276b5cd5e9789d71f55581aa571757e9621294 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 1 Apr 2017 17:58:21 -0400 Subject: [PATCH 10/16] Add Composer documentation --- doc/Composer.md | 98 ++++++++++++++++ doc/Developers-Intro.md | 12 +- doc/Home.md | 1 + doc/autoloader.md | 251 +++++++++++++++++++--------------------- 4 files changed, 226 insertions(+), 136 deletions(-) create mode 100644 doc/Composer.md diff --git a/doc/Composer.md b/doc/Composer.md new file mode 100644 index 0000000000..d0e930e343 --- /dev/null +++ b/doc/Composer.md @@ -0,0 +1,98 @@ +Using Composer +============== + +* [Home](help) + * [Developer Intro](help/Developers-Intro) + +Friendica uses [Composer](https://getcomposer.org) to manage dependencies libraries and the class autoloader both for libraries and namespaced Friendica classes. + +It's a command-line tool that downloads required libraries into the `vendor` folder and makes any namespaced class in `src` available through the whole application through `boot.php`. + +* [Class autoloading](help/autoloader) + +## How to use Composer + +If you don't have Composer installed on your system, Friendica ships with a copy of it at `util/composer.phar`. +For the purpose of this help, all examples will use this path to run Composer commands, however feel free to replace them with your own way of calling Composer. +Composer requires PHP CLI and the following examples assume it's available system-wide. + +### Installing/Updating Friendica + +#### From Archive + +If you just unpacked a Friendica release archive, you don't have to use Commposer at all, all the required libraries are already bundled in the archive. + +#### Installing with Git + +If you prefer to use `git`, you will have to run Composer to fetch the required libraries and build the autoloader before you can run Friendica. +Here are the typical commands you will have to run to do so: + +```` +~> git clone https://github.com/friendica/friendica.git friendica +~/friendica> cd friendica +~/friendica> util/composer.phar install +```` + +That's it! Composer will take care of fetching all the required libraries in the `vendor` folder and build the autoloader to make those libraries available to Friendica. + +#### Updating with Git + +Updating Friendica to the current stable or the latest develop version is easy with Git, just remember to run Composer after every branch pull. + +```` +~> cd friendica +~/friendica> git pull +~/friendica> util/composer.phar install +```` + +And that's it. If any library used by Friendica has been upgraded, Composer will fetch the version currently used by Friendica and refresh the autoloader to ensure the best performances. + +### Developing Friendica + +First of all, thanks for contributing to Friendica! +Composer is meant to be used by developers to maintain third-party libraries required by Friendica. +If you don't need to use any third-party library, then you don't need to use Composer beyond what is above to install/update Friendica. + +#### Adding a third-party library to Friendica + +Does your shiny new [Plugin](help/Plugins) need to rely on a third-party library not required by Friendica yet? +First of all, this library should be available on [Packagist](https://packagist.org) so that Composer knows how to fetch it directly just by mentioning its name in `composer.json`. + +This file is the configuration of Friendica for Composer. It lists details about the Friendica project, but also a list of required dependencies and their target version. +Here's a simplified version of the one we currently use on Friendica: + +````json +{ + "name": "friendica/friendica", + "description": "A decentralized social network part of The Federation", + "type": "project", + ... + "require": { + "ezyang/htmlpurifier": "~4.7.0", + "mobiledetect/mobiledetectlib": "2.8.*" + }, + ... +} +```` + +The important part is under the `require` key, this is a list of all the libraries Friendica may need to run. +As you can see, at the moment we only require two, HTMLPurifier and MobileDetect. +Each library has a different target version, and [per Composer documentation about version constraints](https://getcomposer.org/doc/articles/versions.md#writing-basic-version-constraints), this means that: + +* We will update HTMLPurifier up to version 4.8.0 excluded +* We will update MobileDetect up to version 2.9.0 excluded + +There are other operators you can use to allow Composer to update the package up to the next major version excluded. +Or you can specify the exact version of the library if you code requires it, and Composer will never update it although it isn't recommended. + +To add a library, just add its Packagist identifier to the `require` list and set a target version string. + +Then you should run `util/composer.phar update` to add it to your local `vendor` folder and update the `composer.lock` file that specifies the current versions of the dependencies. + +#### Updating an existing dependency + +If a package needs to be updated, whether to the next minor version or to the next major version provided you changed the adequate code in Friendica, simply edit `composer.json` to update the target version string of the relevant library. + +Then you should run `util/composer.phar update` to update it in your local `vendor` folder and update the `composer.lock` file that specifies the current versions of the dependencies. + +Please note that you should commit both `composer.json` and `composer.lock` with your work every time you make a change to the former. \ No newline at end of file diff --git a/doc/Developers-Intro.md b/doc/Developers-Intro.md index 61b300b0cc..5568afeb5d 100644 --- a/doc/Developers-Intro.md +++ b/doc/Developers-Intro.md @@ -6,8 +6,7 @@ Where to get started to help improve Friendica? Do you want to help us improve Friendica? Here we have compiled some hints on how to get started and some tasks to help you choose. A project like Friendica is the sum of many different contributions. -**Very different skills are required to make good software. -Some of them involve coding, others do not.** +**Very different skills are required to make good software, not all of them involve coding!** We are looking for helpers in all areas, whether you write text or code, whether you spread the word to convince people or design new icons. Whether you feel like an expert or like a newbie - join us with your ideas! @@ -47,6 +46,14 @@ We can't promise we have the right skills in the group but we'll try. Programming --- +### Composer + +Friendica uses [Composer](https://getcomposer.org) to manage dependencies libraries and the class autoloader both for libraries and namespaced Friendica classes. + +It's a command-line tool that downloads required libraries into the `vendor` folder and makes any namespaced class in `src` available through the whole application through `boot.php`. + +* [Using Composer](help/Composer) + ###Coding standards For the sake of consistency between contribution and general code readability, Friendica follows the widespread [PSR-2 coding standards](http://www.php-fig.org/psr/psr-2/) to the exception of a few rules. @@ -120,6 +127,7 @@ Ask us to find out whom to talk to about their experiences. Do not worry about cross-posting. ###Client software + As Friendica is using a [Twitter/GNU Social compatible API](help/api) any of the clients for those platforms should work with Friendica as well. Furthermore there are several client projects, especially for use with Friendica. If you are interested in improving those clients, please contact the developers of the clients directly. diff --git a/doc/Home.md b/doc/Home.md index b4b389921a..5490d171f8 100644 --- a/doc/Home.md +++ b/doc/Home.md @@ -47,6 +47,7 @@ Friendica Documentation and Resources * [Protocol Documentation](help/Protocol) * [Database schema documantation](help/database) * [Class Autoloading](help/autoloader) +* [Using Composer](help/Composer) * [Code - Reference(Doxygen generated - sets cookies)](doc/html/) * [Twitter/GNU Social API Functions](help/api) diff --git a/doc/autoloader.md b/doc/autoloader.md index 69c62451cd..83f1010440 100644 --- a/doc/autoloader.md +++ b/doc/autoloader.md @@ -1,209 +1,192 @@ -Autoloader +Autoloader with Composer ========== * [Home](help) + * [Developer Intro](help/Developers-Intro) -There is some initial support to class autoloading in Friendica core. +Friendica uses [Composer](https://getcomposer.org) to manage dependencies libraries and the class autoloader both for libraries and namespaced Friendica classes. -The autoloader code is in `include/autoloader.php`. -It's derived from composer autoloader code. +It's a command-line tool that downloads required libraries into the `vendor` folder and makes any namespaced class in `src` available through the whole application through `boot.php`. -Namespaces and Classes are mapped to folders and files in `library/`, -and the map must be updated by hand, because we don't use composer yet. -The mapping is defined by files in `include/autoloader/` folder. +* [Using Composer](help/Composer) -Currently, only HTMLPurifier library is loaded using autoloader. +## A quick introduction to class autoloading +The autoloader dynamically includes the file defining a class when it is first referenced, either by instantiating an object or simply making sure that it is available, without the need to explicitly use "require_once". -## A quick introdution to class autoloading +Once it is set up you don't have to directly use it, you can directly use any class that is covered by the autoloader (currently `vendor` and `src`) -The autoloader it's a way for php to automagically include the file that define a class when the class is first used, without the need to use "require_once" every time. +Under the hood, Composer registers a callback with [`spl_autoload_register()`](http://php.net/manual/en/function.spl-autoload-register.php) that receives a class name as an argument and includes the corresponding class definition file. +For more info about PHP autoloading, please refer to the [official PHP documentation](http://php.net/manual/en/language.oop5.autoload.php). -Once is setup you don't have to use it in any way. You need a class? you use the class. +### Example -At his basic is a function passed to the "spl_autoload_register()" function, which receive as argument the class name the script want and is it job to include the correct php file where that class is defined. -The best source for documentation is [php site](http://php.net/manual/en/language.oop5.autoload.php). +Let's say you have a PHP file in `src/` that define a very useful class: -One example, based on fictional friendica code. +```php + // src/ItemsManager.php + array($baseDir."/include"); - ); -``` - - -That tells the autoloader code to look for files that defines classes in "Friendica" namespace under "include/" folder. (And btw, that's why the file has the same name as the class it defines.) - -*note*: The structure of files in "include/autoloader/" has been copied from the code generated by composer, to ease the work of enable autoloader for external libraries under "library/" - -Let's say now that you need to load some items in a view, maybe in a fictional "mod/network.php". -Somewere at the start of the scripts, the autoloader was initialized. In Friendica is done at the top of "boot.php", with "require_once('include/autoloader.php');". +Let's say now that you need to load some items in a view, maybe in a fictional `mod/network.php`. +In order for the Composer autoloader to work, it must first be included. In Friendica this is already done at the top of `boot.php`, with `require_once('vendor/autoload.php');`. The code will be something like: -``` - file: mod/network.php - getAll(); + function network_content(App $a) { + $itemsmanager = new \Friendica\ItemsManager(); + $items = $itemsmanager->getAll(); - // pass $items to template - // return result - } + // pass $items to template + // return result + } ``` -That's a quite simple example, but look: no "require()"! -You need to use a class, you use the class and you don't need to do anything more. +That's a quite simple example, but look: no `require()`! +If you need to use a class, you can simply use it and you don't need to do anything else. -Going further: now we have a bunch of "*Manager" classes that cause some code duplication, let's define a BaseManager class, where to move all code in common between all managers: +Going further: now we have a bunch of `*Manager` classes that cause some code duplication, let's define a `BaseManager` class, where we move all common code between all managers: -``` - file: include/BaseManager.php - Date: Sat, 1 Apr 2017 17:58:35 -0400 Subject: [PATCH 11/16] frio: Fix help pages inline code display --- view/theme/frio/css/style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index e0a0b09b76..946f71e21f 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -90,6 +90,7 @@ blockquote { code { white-space: pre-wrap; } +.help-content-wrapper code {display: inline} /* * standard page elements From 07fd61b91230b6c80b2cd602291a1005d127827d Mon Sep 17 00:00:00 2001 From: Michael Date: Sat, 1 Apr 2017 23:39:19 +0000 Subject: [PATCH 12/16] Mastodon: plink for reshares, missing hostnames for avatars --- include/ostatus.php | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/include/ostatus.php b/include/ostatus.php index e6087de087..5329d98e6b 100644 --- a/include/ostatus.php +++ b/include/ostatus.php @@ -27,6 +27,38 @@ class ostatus { const OSTATUS_DEFAULT_POLL_TIMEFRAME = 1440; // given in minutes const OSTATUS_DEFAULT_POLL_TIMEFRAME_MENTIONS = 14400; // given in minutes + /** + * @brief Mix two paths together to possibly fix missing parts + * + * @param string $avatar Path to the avatar + * @param string $base Another path that is hopefully complete + * + * @return string fixed avatar path + */ + private static function fix_avatar($avatar, $base) { + $base_parts = parse_url($base); + + // Remove all parts that could create a problem + unset($base_parts['path']); + unset($base_parts['query']); + unset($base_parts['fragment']); + + $avatar_parts = parse_url($avatar); + + // Now we mix them + $parts = array_merge($base_parts, $avatar_parts); + + // And put them together again + $scheme = isset($parts['scheme']) ? $parts['scheme'] . '://' : ''; + $host = isset($parts['host']) ? $parts['host'] : ''; + $port = isset($parts['port']) ? ':' . $parts['port'] : ''; + $path = isset($parts['path']) ? $parts['path'] : ''; + $query = isset($parts['query']) ? '?' . $parts['query'] : ''; + $fragment = isset($parts['fragment']) ? '#' . $parts['fragment'] : ''; + + return $scheme.$host.$port.$path.$query.$fragment; + } + /** * @brief Fetches author data * @@ -77,7 +109,7 @@ class ostatus { } if (count($avatarlist) > 0) { krsort($avatarlist); - $author["author-avatar"] = current($avatarlist); + $author["author-avatar"] = self::fix_avatar(current($avatarlist), $author["author-link"]); } $displayname = $xpath->evaluate('atom:author/poco:displayName/text()', $context)->item(0)->nodeValue; @@ -499,13 +531,17 @@ class ostatus { $item["author-name"] = $orig_author["author-name"]; $item["author-link"] = $orig_author["author-link"]; - $item["author-avatar"] = $orig_author["author-avatar"]; + $item["author-avatar"] = self::fix_avatar($orig_author["author-avatar"], $orig_author["author-link"]); + $item["body"] = add_page_info_to_body(html2bbcode($orig_body)); $item["created"] = $orig_created; $item["edited"] = $orig_edited; $item["uri"] = $orig_uri; - $item["plink"] = $orig_link; + + if (!isset($item["plink"])) { + $item["plink"] = $orig_link; + } $item["verb"] = $xpath->query('activity:verb/text()', $activityobjects)->item(0)->nodeValue; From 00577eab2cca29c7731d4804a257daa16ef0231a Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sat, 1 Apr 2017 21:09:36 -0400 Subject: [PATCH 13/16] Add EOF newline to composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9e83d04b45..a7800ffff7 100644 --- a/composer.json +++ b/composer.json @@ -31,4 +31,4 @@ "log", "cache", "/photo", "/proxy" ] } -} \ No newline at end of file +} From 54f49169d4dce87d26162f2cca1cf297c2aaa022 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 2 Apr 2017 07:53:55 +0000 Subject: [PATCH 14/16] Show real platform names --- include/contact_selectors.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/include/contact_selectors.php b/include/contact_selectors.php index 62d79d877a..f1f3b07c91 100644 --- a/include/contact_selectors.php +++ b/include/contact_selectors.php @@ -88,7 +88,7 @@ function network_to_name($s, $profile = "") { NETWORK_PUMPIO => t('pump.io'), NETWORK_TWITTER => t('Twitter'), NETWORK_DIASPORA2 => t('Diaspora Connector'), - NETWORK_STATUSNET => t('GNU Social'), + NETWORK_STATUSNET => t('GNU Social Connector'), NETWORK_PNUT => t('pnut'), NETWORK_APPNET => t('App.net') ); @@ -98,17 +98,16 @@ function network_to_name($s, $profile = "") { $search = array_keys($nets); $replace = array_values($nets); - $networkname = str_replace($search,$replace,$s); - - if (($s == NETWORK_DIASPORA) AND ($profile != "") AND Diaspora::is_redmatrix($profile)) { - $networkname = t("Hubzilla/Redmatrix"); + $networkname = str_replace($search, $replace, $s); + if ((in_array($s, array(NETWORK_DIASPORA, NETWORK_OSTATUS))) AND ($profile != "")) { $r = q("SELECT `gserver`.`platform` FROM `gcontact` INNER JOIN `gserver` ON `gserver`.`nurl` = `gcontact`.`server_url` WHERE `gcontact`.`nurl` = '%s' AND `platform` != ''", dbesc(normalise_link($profile))); - if ($r) + if (dbm::is_result($r)) { $networkname = $r[0]["platform"]; + } } return $networkname; From 94f3f0887b6962e54758ffae6829cf40dfed2d79 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 2 Apr 2017 12:37:22 +0000 Subject: [PATCH 15/16] Issue 2957: The avatar problem with mastodon should now finally be solved --- include/Probe.php | 66 ++++++++++++++++++----------------- include/contact_selectors.php | 2 +- include/ostatus.php | 23 +++++++----- 3 files changed, 49 insertions(+), 42 deletions(-) diff --git a/include/Probe.php b/include/Probe.php index d0b799bfba..c2136eec8b 100644 --- a/include/Probe.php +++ b/include/Probe.php @@ -888,33 +888,36 @@ class Probe { * @return array OStatus data */ private function ostatus($webfinger) { - $data = array(); - if (is_array($webfinger["aliases"])) - foreach($webfinger["aliases"] AS $alias) - if (strstr($alias, "@")) + if (is_array($webfinger["aliases"])) { + foreach ($webfinger["aliases"] AS $alias) { + if (strstr($alias, "@")) { $data["addr"] = str_replace('acct:', '', $alias); + } + } + } - if (is_string($webfinger["subject"]) AND strstr($webfinger["subject"], "@")) + if (is_string($webfinger["subject"]) AND strstr($webfinger["subject"], "@")) { $data["addr"] = str_replace('acct:', '', $webfinger["subject"]); - + } $pubkey = ""; foreach ($webfinger["links"] AS $link) { if (($link["rel"] == "http://webfinger.net/rel/profile-page") AND - ($link["type"] == "text/html") AND ($link["href"] != "")) + ($link["type"] == "text/html") AND ($link["href"] != "")) { $data["url"] = $link["href"]; - elseif (($link["rel"] == "salmon") AND ($link["href"] != "")) + } elseif (($link["rel"] == "salmon") AND ($link["href"] != "")) { $data["notify"] = $link["href"]; - elseif (($link["rel"] == NAMESPACE_FEED) AND ($link["href"] != "")) + } elseif (($link["rel"] == NAMESPACE_FEED) AND ($link["href"] != "")) { $data["poll"] = $link["href"]; - elseif (($link["rel"] == "magic-public-key") AND ($link["href"] != "")) { + } elseif (($link["rel"] == "magic-public-key") AND ($link["href"] != "")) { $pubkey = $link["href"]; if (substr($pubkey, 0, 5) === 'data:') { - if (strstr($pubkey, ',')) + if (strstr($pubkey, ',')) { $pubkey = substr($pubkey, strpos($pubkey, ',') + 1); - else + } else { $pubkey = substr($pubkey, 5); + } } elseif (normalise_link($pubkey) == 'http://') { $ret = z_fetch_url($pubkey); if ($ret['errno'] == CURLE_OPERATION_TIMEDOUT) { @@ -930,16 +933,15 @@ class Probe { $e = base64url_decode($key[2]); $data["pubkey"] = metopem($m,$e); } - } } if (isset($data["notify"]) AND isset($data["pubkey"]) AND isset($data["poll"]) AND isset($data["url"])) { $data["network"] = NETWORK_OSTATUS; - } else + } else { return false; - + } // Fetch all additional data from the feed $ret = z_fetch_url($data["poll"]); if ($ret['errno'] == CURLE_OPERATION_TIMEDOUT) { @@ -947,32 +949,32 @@ class Probe { } $feed = $ret['body']; $feed_data = feed_import($feed,$dummy1,$dummy2, $dummy3, true); - if (!$feed_data) + if (!$feed_data) { return false; - - if ($feed_data["header"]["author-name"] != "") + } + if ($feed_data["header"]["author-name"] != "") { $data["name"] = $feed_data["header"]["author-name"]; - - if ($feed_data["header"]["author-nick"] != "") + } + if ($feed_data["header"]["author-nick"] != "") { $data["nick"] = $feed_data["header"]["author-nick"]; - - if ($feed_data["header"]["author-avatar"] != "") - $data["photo"] = $feed_data["header"]["author-avatar"]; - - if ($feed_data["header"]["author-id"] != "") + } + if ($feed_data["header"]["author-avatar"] != "") { + $data["photo"] = ostatus::fix_avatar($feed_data["header"]["author-avatar"], $data["url"]); + } + if ($feed_data["header"]["author-id"] != "") { $data["alias"] = $feed_data["header"]["author-id"]; - - if ($feed_data["header"]["author-location"] != "") + } + if ($feed_data["header"]["author-location"] != "") { $data["location"] = $feed_data["header"]["author-location"]; - - if ($feed_data["header"]["author-about"] != "") + } + if ($feed_data["header"]["author-about"] != "") { $data["about"] = $feed_data["header"]["author-about"]; - + } // OStatus has serious issues when the the url doesn't fit (ssl vs. non ssl) // So we take the value that we just fetched, although the other one worked as well - if ($feed_data["header"]["author-link"] != "") + if ($feed_data["header"]["author-link"] != "") { $data["url"] = $feed_data["header"]["author-link"]; - + } /// @todo Fetch location and "about" from the feed as well return $data; } diff --git a/include/contact_selectors.php b/include/contact_selectors.php index f1f3b07c91..56c032847c 100644 --- a/include/contact_selectors.php +++ b/include/contact_selectors.php @@ -100,7 +100,7 @@ function network_to_name($s, $profile = "") { $networkname = str_replace($search, $replace, $s); - if ((in_array($s, array(NETWORK_DIASPORA, NETWORK_OSTATUS))) AND ($profile != "")) { + if ((in_array($s, array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS))) AND ($profile != "")) { $r = q("SELECT `gserver`.`platform` FROM `gcontact` INNER JOIN `gserver` ON `gserver`.`nurl` = `gcontact`.`server_url` WHERE `gcontact`.`nurl` = '%s' AND `platform` != ''", diff --git a/include/ostatus.php b/include/ostatus.php index 5329d98e6b..aad4c1041a 100644 --- a/include/ostatus.php +++ b/include/ostatus.php @@ -35,7 +35,7 @@ class ostatus { * * @return string fixed avatar path */ - private static function fix_avatar($avatar, $base) { + public static function fix_avatar($avatar, $base) { $base_parts = parse_url($base); // Remove all parts that could create a problem @@ -56,7 +56,11 @@ class ostatus { $query = isset($parts['query']) ? '?' . $parts['query'] : ''; $fragment = isset($parts['fragment']) ? '#' . $parts['fragment'] : ''; - return $scheme.$host.$port.$path.$query.$fragment; + $fixed = $scheme.$host.$port.$path.$query.$fragment; + + logger('Base: '.$base.' - Avatar: '.$avatar.' - Fixed: '.$fixed, LOGGER_DATA); + + return $fixed; } /** @@ -531,7 +535,7 @@ class ostatus { $item["author-name"] = $orig_author["author-name"]; $item["author-link"] = $orig_author["author-link"]; - $item["author-avatar"] = self::fix_avatar($orig_author["author-avatar"], $orig_author["author-link"]); + $item["author-avatar"] = $orig_author["author-avatar"]; $item["body"] = add_page_info_to_body(html2bbcode($orig_body)); $item["created"] = $orig_created; @@ -1104,10 +1108,11 @@ class ostatus { $arr["owner-name"] = $single_conv->actor->portablecontacts_net->displayName; $arr["owner-link"] = $actor; - $arr["owner-avatar"] = $single_conv->actor->image->url; + $arr["owner-avatar"] = self::fix_avatar($single_conv->actor->image->url, $arr["owner-link"]); + $arr["author-name"] = $arr["owner-name"]; - $arr["author-link"] = $actor; - $arr["author-avatar"] = $single_conv->actor->image->url; + $arr["author-link"] = $arr["owner-link"]; + $arr["author-avatar"] = $arr["owner-avatar"]; $arr["body"] = add_page_info_to_body(html2bbcode($single_conv->content)); if (isset($single_conv->status_net->notice_info->source)) @@ -1158,11 +1163,11 @@ class ostatus { $arr["edited"] = $single_conv->object->published; $arr["author-name"] = $single_conv->object->actor->displayName; - if ($arr["owner-name"] == '') + if ($arr["owner-name"] == '') { $arr["author-name"] = $single_conv->object->actor->contact->displayName; - + } $arr["author-link"] = $single_conv->object->actor->url; - $arr["author-avatar"] = $single_conv->object->actor->image->url; + $arr["author-avatar"] = self::fix_avatar($single_conv->object->actor->image->url, $arr["author-link"]); $arr["app"] = $single_conv->object->provider->displayName."#"; //$arr["verb"] = $single_conv->object->verb; From 95a574022915cde9f1fe83d99d7b5eb9a55baf27 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 2 Apr 2017 08:54:11 -0400 Subject: [PATCH 16/16] Add links to EN pages in DE help --- doc/de/Home.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/de/Home.md b/doc/de/Home.md index e3017c0c60..9a8bfb1089 100644 --- a/doc/de/Home.md +++ b/doc/de/Home.md @@ -24,7 +24,7 @@ Friendica - Dokumentation und Ressourcen * [Account löschen](help/Remove-Account) * [Bugs und Probleme](help/Bugs-and-Issues) * [Häufig gestellte Fragen (FAQ)](help/FAQ) - + **Dokumentation für Administratoren** * [Installation](help/Install) @@ -49,6 +49,8 @@ Friendica - Dokumentation und Ressourcen * [Smarty 3 Templates](help/smarty3-templates) * [Protokoll Dokumentation](help/Protocol) (EN) * [Datenbank-Schema](help/database) +* [Class Autoloading](help/autoloader) (EN) +* [Using Composer](help/Composer) (EN) * [Code-Referenz (mit doxygen generiert - setzt Cookies)](doc/html/) * [Twitter/GNU Social API Functions](help/api) (EN)