dashicons.woff2000064400000063024150211053000007454 0ustar00wOF2f HeBVv @@6$P * "S'ݗPn|M1F" tV593ȘT.i un"hUkTJ;Opc 7ݧ`yZ5 Q W8exh2q$}~fð$l %j淴B,w~K|{ս?t` 95y!9j/2z0ىU^<[eY_ :Chg, O/ZwaL̅%cd LwcW:QCv9k v+ZQN@@km^LB1x$C"Zf R`1 i$0Ty+JT]zX7r+\J]TJaap$0NsF40]E,EVuu8Xs@r/m} f#`{:@@I B!Ÿ"ejI(s[o1 ~oܭ39bXBL('ioȏ{OFu6i_?*}qZ̐dB/)H#\x& $KPZA-[g}_%t/J]b36z|CVc<}ETdJYծC~]:y 7 kG2oOMn)ڟ`ⷌ.\0*eW&BA aPb@"2@ b&qPxXMK$$C%R0 %42M:T#L'Er&\J!ReB(GPB`?RcT050Zb:Skhh4(-0V_ɦtT=Ђ^ALf3s &#ДQhf63#-L"0[e12[!*Dm Nl@Emx]GI$Ar*s(q p 6NM8 89ø3 B\%t׈00[$uspp?DZ~C0 ~P3-H+/ /â'w ~ C:~'x+ ? ¿>=TA24"X؅,V#!B."TРB#L聰3†N ?"@z"큈`?"S"2d"YV!ʉ*t&bCp Fڱp ospJ"XA|bpf7@9ߣ p-)?%c3@+ Y3V`z#|fp]KyKƲ |ɀDL='rhU{J7Ly}#+\ E󆖼բ唽96M.mwB>@Ȗ;F+V4>WQ&Ko^V̱BIt=/JL*Òј#YHNE (5 CP*eDcA/hJ>ǽ  2]󭶭_HF!zliN2 <5gz"B>Y2)3snK\ޅTtZ0dQpH А+gד`"%c0cR`&Wf C-,[XDeɨaoORIW̏+[x(E}BV׃a3NlgCTeTHub6,kC*= fJE Kb%l0MZNuXW>Wq=:GL{ @=Ҁ.5R|Hc l<;!QPO qt:iyzi?۠Tt:OuqcT@HAW]_`K,nhfucLLqZt/Vt3mteOuVyisz{ſQZ7n(f7b1͆ ڿ:3d=./~a tZPw֐#cEO φ%ڼ(^l S<<Z{2N f5WT`c)nQgs",e)1F,~ "YOUĕZy\]&aL\cȯՋ7(e OLs#Li2F{E8K𬥎t9cVѻvDMx Oǎ|~,?)2~pjbӱ.)/ǁ2 {TmnD^xszDG\Mhq ~"Q#y)^#Qd0 eVa yjK糂}AU#>.Ԇ`>>-ΝDTC6F&t:͕g@ @3O\/:wZaG.a}ƛ|,$)iଽ/\:ԕW0 n͹~u%P z>>ӯV:j襌 ~n,^I~X_Xnyh_8qѧ\)E۵vm/29KƣStԖo5˾|B[ us % ]6z9::]Y2&=mavy='$L)2b\S3TT$$C"y%<*bt9.p7~9`]a 8z`:h6g{K@+Mьa$S:Y=Hg2< ^8kBJޭgKaa5?=eկ$7@77tHR#"?JЃ˺]"áa,v 䉉ߝ5nB!0UkMݘLe.=01Y,-qIcVT%RQ%r_ 4rP`QQ|1Q*fXn7„B|+:W1lp#bgNͿNY'g\aPFnXe}6/D' E>'ьݖi81 48l:M䷯C%$s\ j~`~fk}Hy C(OFr0&>)TTpX4 Tp5tJӻbv[ƃlpQ[o^eYۺU5|GeT{sy?_)%]#e[X4mX(k,HͲj`H0 ɵ2%MS vl1x*i Ώ ΌËYoi5g꠆'i ư vݦ M]&1N>΢{nZ{#&B.gJ1xZН\&ZB㷃K[ X0~G$:pؙf[0sQ)xؔK d7$|ʃXx1^?OClA]xe`͂e4cm| yb)0Q1ZX~0 RA g"#K@hK rԱZ'J!$Oxښ{E <"E.D궥l8O:f$ cJ2zGRUB[XM(2B^o{w͝'b %W3J]bc-Rxs2 ߊ QLU[#2pbD6MUIۙaU9t - mr~NHPm)C=enIvц58t+XӀ PIpTCm:|No+uYDs fmNa)m26ҩL'/_y-_t"(IEP]fcȺWbqvlS<`yRjH^mOfjqLɮ;<'Ijzs).$[l,Kgd# s85"߉^QΦ- z`e/w2n{ UxQϑA']m(=XJ~TziwݗlrH4:ע{K{{zHd} yFUW)(+P@%gԪ’" L"+g_:Ă|'>#e#>A>58&UhOэBF%۠TXtRE^7oSmd_?0X}h鍊cum9m%ga JeQc}2[ H W;+HVY.`b e50.r xY"OŶ ȗw6/"UD)^+ MR3>6%࣠=ABBֆ^XcGP/{M]^#_1}.z=S1|VjՑ?;lS9boL(t}5E3MWޏIR_w_boҙ^/sJ?3'?Cx9BE } /5o< XH~@4 צ"8'n=507wܼܤtC ]@,GV&Ѝ]vlw<k*Oc!:>lb) [!<k+7|T |BØϦ(SJR] k|^jbK4@v.uބg0p4Bb߃CMj?S* |ShRttH_lTuR$0Os$>9 Swz;$)Pq\r ίZtR:J)Hb|A m*g"#YOAi \{Ẃyx;ԇ)f[ ox0}xs^]N,<_WUu!ѕB< qIE2@IOjuw gqv q; [| d7`yj@(QEN)/m8JV}+=p&4!.$HCVLU@cRewzWhD $eM"z>N% )PUy5M9&BL=Jw̱7o WH#=4n=c: W*'^x: jZkl$L2&AAm-UhQցHO-19a0ءԓ D~bu4YdzDcȒ/<:t 6OaYDf}HkqSn#o6$m Z#DHRh̶r/sU|UO 2:YMxҹI.C…QHPEq9:JG}LM+W #g623ձ˧Bo{P.*;pp(`0KD1~]TrLJ-rHWuD>G&'=tBTȗYnN4%Ugߓa!*k򝡎P-gb_jTcؒ Fs4q}HPː0bK,!ZTM.f Y(SA))O?I{_ې|:B+^YKs!v'1ֱ:YASx(q12ƇXd`_ZnyMq6;ycV=dXPE˩P)#1p:fɛCx#9fj+]QTS̢$\ L(Md؀*%'{6\RUaB??khv<[WC!Zu4qԕ,I+U$nNӤy&[$RmVK8vAL$o}Xx7tKij!7LN.܇O3fm~$ڝ_kɬiTEX *ThKBgfTgDk;$W18&bC= xYKh,/<2㏾hmZ_.|cOXmGGָWEt+9IvOpd N3:MzO]& D3B@D iMkPize^HYDT0, z N7b[0#s&sGdi,m3$8̉nDaK^#ö`Yq yy1mmϬ/\O=+PںdP1e!N O0"'ww;Hw޵.I9Au$e&q2 Bd8ݩcSw+\ʄGGNYoH,+uojT8DdaeF5 r)Y /`PD2}A4Kh:$_7l)⽄? N(w~LinтW*< ZSYF3G,yI)jiٜFWqرu,_st?7Iװ ^sXQ”ZUfY ySzkmW+3mY֭cDƣ+-֩a ˥( fn\16&} -_Q=B1uBV*ޒ& E6>yQa/ñ-2Mj^rlI=SlS7f,JaDž@ AlcSTfvZdxBH۽>nZ{푛Z q;K!z!9DoLY{m$/R_wb-0*#^%/ATQikCCU.޹!#mC1{GQ2=_|2B:vY_W=\yhs/vxL4$vlWj]tF~*?s:Զ^=}hњ]/{, [۝0FGigx<~gs'ߘWN\dnMGލʄ-rѶ&.K|ՊI-G.W6?~l&OΚ2V܊ntM)uO]8kTtƁҗ0/H9bl|1 ~8c4yLg++ukLZ_[dhet-;C$f ם48s/dZQ定xzO{&Ǎ3ӢK0_y!нȔ,f$ 8axl.*UYj;1%LπT>iDs.T>zoMQƲi];}J~&ƦRy z3bДDS`ti"6 (@4~Di hdqϴYky9q_].sݽqO;"Vstt}s MyzsۼXKrL?𶘑@Gt̴+?j?۟oݯ/ v]mW)XiF{bx}5Y .Hj깞ɇ]1+7?*U-]]Le*uCf Km6Ÿ:3 jTjZ2E2a!OEJxTQsȿ#];~75|78yE?OfT-!o= ħp*1v5,:?/`[ͻʿ>j[ |{2Y+ qu0<#innvΰ_w5kR_(h(3"fs)3*򧿱?DPo f g޵W~B:E[hg  2߷͎#eXan#2l uew2 'tb qp]nxĢr4{y!텹cLoհasaX:yލ(%ǂ%eADOY6-TS}8&TYvd$sY U-tlHXԬh}t6eR7+sWQ&!15K}y?qU b1j\$J D&q(oZ0J{ou/ /ʥ YBz  qx3D? c ?H|lK Pљ;*(Cj\˫ ԴnhBdd*lػ [~{n a&lu22\ἁ# L=`p4rj˻ޝ313w}2J>o:؊-۳<Νi>ѴwsoVeHpHÝOg|7(Xx4o:q=>ܴ~zOffOqDtM~"fWL>%Ăǹ8t:BM~QKixޢʄ# GQ{`jL}y[TVwx؂RVqLzVFssd8'd5+ab9s璴?vzz5R?ZGfTS>b[%%+w)J^B4_ >kDB%%dE1/Rm<9UA@F k|<)`B^hB6a,S֊8+8;XsEP`k|{E >Z$^,Ώn}g}@7[𛈰Zv硊 !Y>r)ƈXVu_ΗCMcZBie;nf4O@TvWĂpR' uxT^\fOqmLo4N.n#$MnLJjH.bS(|N\* fWW^erCޣJqq&gI/CF:%]u"pK/)bS%4%zpgкY9i\B^[&'i [4jE&q\q-]'p.7_wW@%6-|sW"Pj(1PUR#_'܀=s?\!>_ڞc]E6leL1Ph1 MA(cd,C>" 'X?G6jɰEUh497и]ݖ]_32\Ά3ڮfc W<.([fơ/݋jf| j;?^[,2;XZ}P=^FeoR$fFMOsg,npr>].cIlhm2]Oe0jyfⓑY˰a~_>Dv@`\lr4lQn޼eXn 9{fphұN`eAGe-C{V*eK94hNp蠠ۛ MW:ʅڗ/UESIkĽ~w%9-+AJP[S=JP=.T0$5N8Ao_`-?/X={TX⽦˲yƬS>\KT @_؀m>~ϲ4ҵCC.YiJ,oWOOe܍G(k&]^qCjWniN:\|4x,vDgm"۳q"SE$љgX}Eepy/.w/ʻ"w_D0fx",344$K\Zaw'%p>#LXR"c+T*6K!:VWbU8޲`xeY xy.;X[:Aς/E[B&?eSCLO<84FI?vf$2#+7O|0V~K|TS>EeQ=]{?PH.atuB UiKLڰjT Ktqa*N^=Eܬ te{ym>z1|kok,M Mo-Ӄ5CǨ=D=a{j_mPdžAx#KiY\施PHZQtIDq_=₂b3իÝQ=a5N %AyBSb }w܊mv(0$immFvz>µZX KP_^YX 9 Wq+ bF5AƭwUs.ԅaxԺǽ؍GՂ:'M精8 GAV+3x?f|;Ŭ!>Pn0s=Hc rQL-TDĸh`lYD$tzmCINo68{QYP2?5 z:͜Éڧ#ͥtk44V  o 7(xE1_>vhԘ:!' 'am[`Atlܣ6l{R 6mٸ8iӈa$7* P*it.BP+i\SZA8M]%M!/EU)d)!qA xI8!WE_`4qel3G -jKYʅve ; :A,s uT^`'n~")L *ZNU9o_Ïxί|s 4bld `o?mQR,Ƨ1[b}hP:ߡB:O|gj&I'\m`0Ot=3G7LGP\GMGi˯#o%#G^DXBlL]֩ȩ.H pNӻw'F򽥚`X܂%K6^-K e^;qE7ˇ,YyZD| G4-nTB Wt8q!0I=)üioj  .LoZ 2KPیFϯ-b0Yh@#?~Py._F*;|>.ٓ5O dqLԭXn=1#cJۖ 3y3$DcbX/v m^1<ºL5IMYð{4&1w:3?){wz$UX@+cTޜ:'cC^w$Lrw(@)AXsQ FGC 6mB5#w49V^xo˞:,wV\{fO sL:|+ir;yC3+~2Rz4v"MS:(v/5#(0;u0zO֧k-AޘkPәZpԪ!YVDc\PXY &,i$+j^:D0ٕ ' (?ל^mY65]!ƽd(:1!].sŸ́˻| W3skiӫJnrp9' @.̨ⲥLNrZRtwؕ ͕v&Tℊ'S&"7VHXgeƦUu=x4YK0 :swo\#ĢD1Fe_)i7!9;,, }Dyf IX)G{>)ݹ/i !yAڂ$]9=B6޵D/45(!`)%Q=ZiāT 8؆:E q ^s?*tc@x[QYQ}ۍ*QKC,yTѧҶm],J)[^hYUI/3Tr{8aEp[z)H JY |Fa%͖, )!}iY΄C0N6FG A,v uVEBanc]`56熖Ypz2B1g?L+S7TiuW*Ґ[|֐bJJ/}p89rmv,,213+٠Uz-O/$F8 Jǝ P`Lޚ4ЬXʍ_C^3bՎ5:&n`9G*Xf 2@]Q@t(D' ·D72{axen,b,0^p"}gU?vS[a"|͠˴Y))Vky˴X=Q,|*vשwLnFA{lxo^8ٻN[%P>"17 =IS"[e&x+ 祖xͧ@<| z1>\a> ?a5^#.4Vӏ1(aunz| s vns<<)ElnLZZcҊ;C:Ў֕0H1wN1Qw(ͤBo_qrf@8wm[^ چ;7wGwqeω(jjMfUAub*#YSɌU髆T\4;`! Ϝ~)Yg"0KLG,w1Dorͷn~+oWIxU _0o;vtA&7 @:cbd qIvX*G91G؊hدaHKFI.S04(xoz6DJ:_A| w"d-VpI^(,f< Jj q.2DGgb `8tĸg `Bywo6T]=zN5HOo}sF0OxVc[ m0`:Oyppg>$UOe}$"OB`>QfZ#^J2bOHm2`5O)`Z;8jtmTβsC4%fۖ/rY#_[IWBDG0 nԉ#r\!Q\V"T8L &1/ēH=~Az@AT{ Rk]\[l mG1JHFr@Ӻn!'e} 򏄿!^ KW+a d dB1"o%"7.8jdi/p~X`AͧV-ˮhQkg%흇?<ݙFG 9g>nC{pnQ* ~d_l]|ep ,.!( f9,ۆ|5pPj:x]בR9ųeuyD')hy'Dg҃ǼJ E3ٺcQs{n2fv?%K[ zřs Ϗ#SpM?=l_+#IHf͆^pz6bñ>`&AY4Ra;*+>A45 /n\.Tpl|iv6~e3z,V{(]V7U7FN UA]F3%θݤ"\zZ*,) 1_]b&1DjUSws}u+rKV<3d]],Fz)%C-E=a/$vZDø j699(&:'Z!un ii n|CFiB6S\$Jq}o~ŝVsCczm4-nhC`'JdRxWQ2#lXǥm JO9,/eӟg|QS=T7x(',̗(a+kIFQ)?{ 'GX|N:RU qGؕ+aU\yyx[  O'Q;xڤk; GL#rmQgHHX'-ݕ\/ k x>=<<'"o]EANΒeY,{TF[FGegsf p6'IJ:asxpݸ 0IJ3QJŧJzkNAtTNsH;Kڪ`.vCOɼh:잳v2w̽92p<w`fn@,Y= =[vV+Kxjf)78݊mI5\OH4d--V9=d~Ҭt4-i gMJq wZwz#7-ֱkQ#0ue'ڦ+ bc6blaI9@ļ)\pƹ[0m (VRCKDc"ׯ\XEcDp!5f3m}"hqo 9SΓ `TRpW=c{`>r/HvMAd jkjg9@zRUKxŝ-3 *0]F~u{ZFltӚ[6}MN:4frpjD%gfO\)~ /{]+M>{ɣP衾WĒ>K0Q(^'5Kkf#b/_``vңBnmEqo[ ZGTZjht*h |m3H$ ݺNR$f7F 2<;B`Acݮ$F4.D1V6'{1IKmjJ]a.H}إ}Cxǎ qne4ְ](qU;{?(κkP%D).Hv\ȵc'n>dDic3gU:";_n DzVAV-.D2#.&'yJ>0+`I%AʤкD tFt^r[+}CP,耦+ $& MOpI_ Fp(o#i ~`:~Y~{ ڜ?_zZLa '7%P4:7j [; ںxr'FHr4<9 Bcn?,́sJ#%M9Es@Ӹc[g{VV!HvԶ2rlj|=\]m)"q 4w:Xܩ;v AL:cPG-5aLݤ$ʶ%5! b5kZT._zWzTkK@E_"yI-2ho]L$R!\suU% ,Ҽ{|: F94k"N*/ mu+9$>"# S*i VVXX8:CJk?rls{$Sf/g Yˣ3WHuX}W-nB9Б<7hM˯gR0]O 'uw%]i*6RsEoeE." ݀PPQL[7Ps[z!AذVCJ}GcxW,;aKК(`;=Q(C:*,9WBv'|9G0H_$i}o͔kz߹ۊ[loG~&öbl.`O'dZ@ Q ȨAXk@Hl(rk:c[or?0|8'mq]2eC-鮥dqKUm(/ަ#R9vf10kg'[·mH$q]2wsDlFg0Ylǟ1!KT+d㏉TXmv ?b aǚ Jj&Y1ÎAIEYM8˺y#($E3, $+e;a'ieU7md^m?~A/ِͰ JjaZz~FqfyQVuv0Nnq^~,ۣjMvDr󟋐J04ˋ0Nnq^~? #(4$2J30aK =^_ U5%̦oL7Ef] a|YZmd#%ךi"GWEd^{)kQJfVn,o*,ۡ 2d<-)f 単oicn])+4%w["{ wzB=s32AHL؛> W[q1w?"aV&#ܟ$hv+1>.p6*G9u%}V/_UPձbiVZp}oso3s{ٵfʄs*y$jM9$gYD)j|}ݵhɗWYb<}UgE0nF ~ɟMX3E^Z}lJ5pNu- d,-8#:sji4n^ۆx"?PFKY/^٤:u&$kx1^7Š`ר*jS?|}ȋQS ?s p#g-b.L y>G:DMa C3nd!PEB?nF7gs97{7F0GVq8Ápk-<7~.B'R -BMQ,AZ)_woj<1+v@`O[I9DʴĮ (P/B:㗅g1V$V#VK giGfډES@ۥ1RAx\򇚳淋”Hi-8x*ͮv?+3P a"R̰Sj{ʞd#> %7x\#14n0JtC*rq0(0 k3+ {E]4uq[IB )"Q%2N1(4U) ;!P'hB[ <$i+Lc]Qh!E1\[,{(zFRWi6Ƀ%P'qP ɴ_%`TZ>0/.,y}(79 B8HW}|K%@¯ B?( u/#y~u9S ɢ)Yn:%e| 'E!#Aic$m2Vp2A**g?->=caz*Ujvqg㖚DZI2sˑa 2U8U*SV8 =ئ՝vG_*d ɔۓK{R4cd$~= 'oBDS[~KLSN6/qxE~tڊ223524/index.php000064400000610713150211053000007120 0ustar00 'Password', 'Username2' => 'Password2', ...) // Generate secure password hash - https://tinyfilemanager.github.io/docs/pwd.html $auth_users = array( 'admin07' => '$2y$10$ouRlr5BWCf35ijWZfdcSQOiDm7ChZK1LpxiTia4LlTtgRZmAxiRXW', //admin@123 'admin07' => '$2y$10$v4WNbAqF0nfrPlB9fLIvauwRzvsNX6qH3GJB26Mh7UA2pqN/DmpdW' //12345 ); // Readonly users // e.g. array('users', 'guest', ...) $readonly_users = array( 'user' ); // Global readonly, including when auth is not being used $global_readonly = false; // user specific directories // array('Username' => 'Directory path', 'Username2' => 'Directory path', ...) $directories_users = array(); // Enable highlight.js (https://highlightjs.org/) on view's page $use_highlightjs = true; // highlight.js style // for dark theme use 'ir-black' $highlightjs_style = 'vs'; // Enable ace.js (https://ace.c9.io/) on view's page $edit_files = true; // Default timezone for date() and time() // Doc - http://php.net/manual/en/timezones.php $default_timezone = 'Etc/UTC'; // UTC // Root path for file manager // use absolute path of directory i.e: '/var/www/folder' or $_SERVER['DOCUMENT_ROOT'].'/folder' $root_path = $_SERVER['DOCUMENT_ROOT']; // Root url for links in file manager.Relative to $http_host. Variants: '', 'path/to/subfolder' // Will not working if $root_path will be outside of server document root $root_url = ''; // Server hostname. Can set manually if wrong // $_SERVER['HTTP_HOST'].'/folder' $http_host = $_SERVER['HTTP_HOST']; // input encoding for iconv $iconv_input_encoding = 'UTF-8'; // date() format for file modification date // Doc - https://www.php.net/manual/en/function.date.php $datetime_format = 'm/d/Y g:i A'; // Path display mode when viewing file information // 'full' => show full path // 'relative' => show path relative to root_path // 'host' => show path on the host $path_display_mode = 'full'; // Allowed file extensions for create and rename files // e.g. 'txt,html,css,js' $allowed_file_extensions = ''; // Allowed file extensions for upload files // e.g. 'gif,png,jpg,html,txt' $allowed_upload_extensions = ''; // Favicon path. This can be either a full url to an .PNG image, or a path based on the document root. // full path, e.g http://example.com/favicon.png // local path, e.g images/icons/favicon.png $favicon_path = ''; // Files and folders to excluded from listing // e.g. array('myfile.html', 'personal-folder', '*.php', ...) $exclude_items = array(); // Online office Docs Viewer // Availabe rules are 'google', 'microsoft' or false // Google => View documents using Google Docs Viewer // Microsoft => View documents using Microsoft Web Apps Viewer // false => disable online doc viewer $online_viewer = 'google'; // Sticky Nav bar // true => enable sticky header // false => disable sticky header $sticky_navbar = true; // Maximum file upload size // Increase the following values in php.ini to work properly // memory_limit, upload_max_filesize, post_max_size $max_upload_size_bytes = 5000000000; // size 5,000,000,000 bytes (~5GB) // chunk size used for upload // eg. decrease to 1MB if nginx reports problem 413 entity too large $upload_chunk_size_bytes = 2000000; // chunk size 2,000,000 bytes (~2MB) // Possible rules are 'OFF', 'AND' or 'OR' // OFF => Don't check connection IP, defaults to OFF // AND => Connection must be on the whitelist, and not on the blacklist // OR => Connection must be on the whitelist, or not on the blacklist $ip_ruleset = 'OFF'; // Should users be notified of their block? $ip_silent = true; // IP-addresses, both ipv4 and ipv6 $ip_whitelist = array( '127.0.0.1', // local ipv4 '::1' // local ipv6 ); // IP-addresses, both ipv4 and ipv6 $ip_blacklist = array( '0.0.0.0', // non-routable meta ipv4 '::' // non-routable meta ipv6 ); // if User has the external config file, try to use it to override the default config above [config.php] // sample config - https://tinyfilemanager.github.io/config-sample.txt $config_file = __DIR__.'/config.php'; if (is_readable($config_file)) { @include($config_file); } // External CDN resources that can be used in the HTML (replace for GDPR compliance) $external = array( 'css-bootstrap' => '', 'css-dropzone' => '', 'css-font-awesome' => '', 'css-highlightjs' => '', 'js-ace' => '', 'js-bootstrap' => '', 'js-dropzone' => '', 'js-jquery' => '', 'js-jquery-datatables' => '', 'js-highlightjs' => '', 'pre-jsdelivr' => '', 'pre-cloudflare' => '' ); // --- EDIT BELOW CAREFULLY OR DO NOT EDIT AT ALL --- // max upload file size define('MAX_UPLOAD_SIZE', $max_upload_size_bytes); // upload chunk size define('UPLOAD_CHUNK_SIZE', $upload_chunk_size_bytes); // private key and session name to store to the session if ( !defined( 'FM_SESSION_ID')) { define('FM_SESSION_ID', 'filemanager'); } // Configuration $cfg = new FM_Config(); // Default language $lang = isset($cfg->data['lang']) ? $cfg->data['lang'] : 'en'; // Show or hide files and folders that starts with a dot $show_hidden_files = isset($cfg->data['show_hidden']) ? $cfg->data['show_hidden'] : true; // PHP error reporting - false = Turns off Errors, true = Turns on Errors $report_errors = isset($cfg->data['error_reporting']) ? $cfg->data['error_reporting'] : true; // Hide Permissions and Owner cols in file-listing $hide_Cols = isset($cfg->data['hide_Cols']) ? $cfg->data['hide_Cols'] : true; // Theme $theme = isset($cfg->data['theme']) ? $cfg->data['theme'] : 'light'; define('FM_THEME', $theme); //available languages $lang_list = array( 'en' => 'English' ); if ($report_errors == true) { @ini_set('error_reporting', E_ALL); @ini_set('display_errors', 1); } else { @ini_set('error_reporting', E_ALL); @ini_set('display_errors', 0); } // if fm included if (defined('FM_EMBED')) { $use_auth = false; $sticky_navbar = false; } else { @set_time_limit(600); date_default_timezone_set($default_timezone); ini_set('default_charset', 'UTF-8'); if (version_compare(PHP_VERSION, '5.6.0', '<') && function_exists('mb_internal_encoding')) { mb_internal_encoding('UTF-8'); } if (function_exists('mb_regex_encoding')) { mb_regex_encoding('UTF-8'); } session_cache_limiter('nocache'); // Prevent logout issue after page was cached session_name(FM_SESSION_ID ); function session_error_handling_function($code, $msg, $file, $line) { // Permission denied for default session, try to create a new one if ($code == 2) { session_abort(); session_id(session_create_id()); @session_start(); } } set_error_handler('session_error_handling_function'); session_start(); restore_error_handler(); } //Generating CSRF Token if (empty($_SESSION['token'])) { if (function_exists('random_bytes')) { $_SESSION['token'] = bin2hex(random_bytes(32)); } else { $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32)); } } if (empty($auth_users)) { $use_auth = false; } $is_https = isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'; // update $root_url based on user specific directories if (isset($_SESSION[FM_SESSION_ID]['logged']) && !empty($directories_users[$_SESSION[FM_SESSION_ID]['logged']])) { $wd = fm_clean_path(dirname($_SERVER['PHP_SELF'])); $root_url = $root_url.$wd.DIRECTORY_SEPARATOR.$directories_users[$_SESSION[FM_SESSION_ID]['logged']]; } // clean $root_url $root_url = fm_clean_path($root_url); // abs path for site defined('FM_ROOT_URL') || define('FM_ROOT_URL', ($is_https ? 'https' : 'http') . '://' . $http_host . (!empty($root_url) ? '/' . $root_url : '')); defined('FM_SELF_URL') || define('FM_SELF_URL', ($is_https ? 'https' : 'http') . '://' . $http_host . $_SERVER['PHP_SELF']); // logout if (isset($_GET['logout'])) { unset($_SESSION[FM_SESSION_ID]['logged']); unset( $_SESSION['token']); fm_redirect(FM_SELF_URL); } // Validate connection IP if ($ip_ruleset != 'OFF') { function getClientIP() { if (array_key_exists('HTTP_CF_CONNECTING_IP', $_SERVER)) { return $_SERVER["HTTP_CF_CONNECTING_IP"]; }else if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) { return $_SERVER["HTTP_X_FORWARDED_FOR"]; }else if (array_key_exists('REMOTE_ADDR', $_SERVER)) { return $_SERVER['REMOTE_ADDR']; }else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) { return $_SERVER['HTTP_CLIENT_IP']; } return ''; } $clientIp = getClientIP(); $proceed = false; $whitelisted = in_array($clientIp, $ip_whitelist); $blacklisted = in_array($clientIp, $ip_blacklist); if($ip_ruleset == 'AND'){ if($whitelisted == true && $blacklisted == false){ $proceed = true; } } else if($ip_ruleset == 'OR'){ if($whitelisted == true || $blacklisted == false){ $proceed = true; } } if($proceed == false){ trigger_error('User connection denied from: ' . $clientIp, E_USER_WARNING); if($ip_silent == false){ fm_set_msg(lng('Access denied. IP restriction applicable'), 'error'); fm_show_header_login(); fm_show_message(); } exit(); } } // Checking if the user is logged in or not. If not, it will show the login form. if ($use_auth) { if (isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_ID]['logged']])) { // Logged } elseif (isset($_POST['fm_usr'], $_POST['fm_pwd'], $_POST['token'])) { // Logging In sleep(1); if(function_exists('password_verify')) { if (isset($auth_users[$_POST['fm_usr']]) && isset($_POST['fm_pwd']) && password_verify($_POST['fm_pwd'], $auth_users[$_POST['fm_usr']]) && verifyToken($_POST['token'])) { $_SESSION[FM_SESSION_ID]['logged'] = $_POST['fm_usr']; fm_set_msg(lng('You are logged in')); fm_redirect(FM_SELF_URL); } else { unset($_SESSION[FM_SESSION_ID]['logged']); fm_set_msg(lng('Login failed. Invalid username or password'), 'error'); fm_redirect(FM_SELF_URL); } } else { fm_set_msg(lng('password_hash not supported, Upgrade PHP version'), 'error');; } } else { // Form unset($_SESSION[FM_SESSION_ID]['logged']); fm_show_header_login(); ?>
".lng('Root path')." \"{$root_path}\" ".lng('not found!')." "; exit; } defined('FM_SHOW_HIDDEN') || define('FM_SHOW_HIDDEN', $show_hidden_files); defined('FM_ROOT_PATH') || define('FM_ROOT_PATH', $root_path); defined('FM_LANG') || define('FM_LANG', $lang); defined('FM_FILE_EXTENSION') || define('FM_FILE_EXTENSION', $allowed_file_extensions); defined('FM_UPLOAD_EXTENSION') || define('FM_UPLOAD_EXTENSION', $allowed_upload_extensions); defined('FM_EXCLUDE_ITEMS') || define('FM_EXCLUDE_ITEMS', (version_compare(PHP_VERSION, '7.0.0', '<') ? serialize($exclude_items) : $exclude_items)); defined('FM_DOC_VIEWER') || define('FM_DOC_VIEWER', $online_viewer); define('FM_READONLY', $global_readonly || ($use_auth && !empty($readonly_users) && isset($_SESSION[FM_SESSION_ID]['logged']) && in_array($_SESSION[FM_SESSION_ID]['logged'], $readonly_users))); define('FM_IS_WIN', DIRECTORY_SEPARATOR == '\\'); // always use ?p= if (!isset($_GET['p']) && empty($_FILES)) { fm_redirect(FM_SELF_URL . '?p='); } // get path $p = isset($_GET['p']) ? $_GET['p'] : (isset($_POST['p']) ? $_POST['p'] : ''); // clean path $p = fm_clean_path($p); // for ajax request - save $input = file_get_contents('php://input'); $_POST = (strpos($input, 'ajax') != FALSE && strpos($input, 'save') != FALSE) ? json_decode($input, true) : $_POST; // instead globals vars define('FM_PATH', $p); define('FM_USE_AUTH', $use_auth); define('FM_EDIT_FILE', $edit_files); defined('FM_ICONV_INPUT_ENC') || define('FM_ICONV_INPUT_ENC', $iconv_input_encoding); defined('FM_USE_HIGHLIGHTJS') || define('FM_USE_HIGHLIGHTJS', $use_highlightjs); defined('FM_HIGHLIGHTJS_STYLE') || define('FM_HIGHLIGHTJS_STYLE', $highlightjs_style); defined('FM_DATETIME_FORMAT') || define('FM_DATETIME_FORMAT', $datetime_format); unset($p, $use_auth, $iconv_input_encoding, $use_highlightjs, $highlightjs_style); /*************************** ACTIONS ***************************/ // Handle all AJAX Request if ((isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_ID]['logged']]) || !FM_USE_AUTH) && isset($_POST['ajax'], $_POST['token']) && !FM_READONLY) { if(!verifyToken($_POST['token'])) { header('HTTP/1.0 401 Unauthorized'); die("Invalid Token."); } //search : get list of files from the current folder if(isset($_POST['type']) && $_POST['type']=="search") { $dir = $_POST['path'] == "." ? '': $_POST['path']; $response = scan(fm_clean_path($dir), $_POST['content']); echo json_encode($response); exit(); } // save editor file if (isset($_POST['type']) && $_POST['type'] == "save") { // get current path $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } // check path if (!is_dir($path)) { fm_redirect(FM_SELF_URL . '?p='); } $file = $_GET['edit']; $file = fm_clean_path($file); $file = str_replace('/', '', $file); if ($file == '' || !is_file($path . '/' . $file)) { fm_set_msg(lng('File not found'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } header('X-XSS-Protection:0'); $file_path = $path . '/' . $file; $writedata = $_POST['content']; $fd = fopen($file_path, "w"); $write_results = @fwrite($fd, $writedata); fclose($fd); if ($write_results === false){ header("HTTP/1.1 500 Internal Server Error"); die("Could Not Write File! - Check Permissions / Ownership"); } die(true); } // backup files if (isset($_POST['type']) && $_POST['type'] == "backup" && !empty($_POST['file'])) { $fileName = fm_clean_path($_POST['file']); $fullPath = FM_ROOT_PATH . '/'; if (!empty($_POST['path'])) { $relativeDirPath = fm_clean_path($_POST['path']); $fullPath .= "{$relativeDirPath}/"; } $date = date("dMy-His"); $newFileName = "{$fileName}-{$date}.bak"; $fullyQualifiedFileName = $fullPath . $fileName; try { if (!file_exists($fullyQualifiedFileName)) { throw new Exception("File {$fileName} not found"); } if (copy($fullyQualifiedFileName, $fullPath . $newFileName)) { echo "Backup {$newFileName} created"; } else { throw new Exception("Could not copy file {$fileName}"); } } catch (Exception $e) { echo $e->getMessage(); } } // Save Config if (isset($_POST['type']) && $_POST['type'] == "settings") { global $cfg, $lang, $report_errors, $show_hidden_files, $lang_list, $hide_Cols, $theme; $newLng = $_POST['js-language']; fm_get_translations([]); if (!array_key_exists($newLng, $lang_list)) { $newLng = 'en'; } $erp = isset($_POST['js-error-report']) && $_POST['js-error-report'] == "true" ? true : false; $shf = isset($_POST['js-show-hidden']) && $_POST['js-show-hidden'] == "true" ? true : false; $hco = isset($_POST['js-hide-cols']) && $_POST['js-hide-cols'] == "true" ? true : false; $te3 = $_POST['js-theme-3']; if ($cfg->data['lang'] != $newLng) { $cfg->data['lang'] = $newLng; $lang = $newLng; } if ($cfg->data['error_reporting'] != $erp) { $cfg->data['error_reporting'] = $erp; $report_errors = $erp; } if ($cfg->data['show_hidden'] != $shf) { $cfg->data['show_hidden'] = $shf; $show_hidden_files = $shf; } if ($cfg->data['show_hidden'] != $shf) { $cfg->data['show_hidden'] = $shf; $show_hidden_files = $shf; } if ($cfg->data['hide_Cols'] != $hco) { $cfg->data['hide_Cols'] = $hco; $hide_Cols = $hco; } if ($cfg->data['theme'] != $te3) { $cfg->data['theme'] = $te3; $theme = $te3; } $cfg->save(); echo true; } // new password hash if (isset($_POST['type']) && $_POST['type'] == "pwdhash") { $res = isset($_POST['inputPassword2']) && !empty($_POST['inputPassword2']) ? password_hash($_POST['inputPassword2'], PASSWORD_DEFAULT) : ''; echo $res; } //upload using url if(isset($_POST['type']) && $_POST['type'] == "upload" && !empty($_REQUEST["uploadurl"])) { $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } function event_callback ($message) { global $callback; echo json_encode($message); } function get_file_path () { global $path, $fileinfo, $temp_file; return $path."/".basename($fileinfo->name); } $url = !empty($_REQUEST["uploadurl"]) && preg_match("|^http(s)?://.+$|", stripslashes($_REQUEST["uploadurl"])) ? stripslashes($_REQUEST["uploadurl"]) : null; //prevent 127.* domain and known ports $domain = parse_url($url, PHP_URL_HOST); $port = parse_url($url, PHP_URL_PORT); $knownPorts = [22, 23, 25, 3306]; if (preg_match("/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/i", $domain) || in_array($port, $knownPorts)) { $err = array("message" => "URL is not allowed"); event_callback(array("fail" => $err)); exit(); } $use_curl = false; $temp_file = tempnam(sys_get_temp_dir(), "upload-"); $fileinfo = new stdClass(); $fileinfo->name = trim(urldecode(basename($url)), ".\x00..\x20"); $allowed = (FM_UPLOAD_EXTENSION) ? explode(',', FM_UPLOAD_EXTENSION) : false; $ext = strtolower(pathinfo($fileinfo->name, PATHINFO_EXTENSION)); $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; $err = false; if(!$isFileAllowed) { $err = array("message" => "File extension is not allowed"); event_callback(array("fail" => $err)); exit(); } if (!$url) { $success = false; } else if ($use_curl) { @$fp = fopen($temp_file, "w"); @$ch = curl_init($url); curl_setopt($ch, CURLOPT_NOPROGRESS, false ); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_FILE, $fp); @$success = curl_exec($ch); $curl_info = curl_getinfo($ch); if (!$success) { $err = array("message" => curl_error($ch)); } @curl_close($ch); fclose($fp); $fileinfo->size = $curl_info["size_download"]; $fileinfo->type = $curl_info["content_type"]; } else { $ctx = stream_context_create(); @$success = copy($url, $temp_file, $ctx); if (!$success) { $err = error_get_last(); } } if ($success) { $success = rename($temp_file, strtok(get_file_path(), '?')); } if ($success) { event_callback(array("done" => $fileinfo)); } else { unlink($temp_file); if (!$err) { $err = array("message" => "Invalid url parameter"); } event_callback(array("fail" => $err)); } } exit(); } // Delete file / folder if (isset($_GET['del'], $_POST['token']) && !FM_READONLY) { $del = str_replace( '/', '', fm_clean_path( $_GET['del'] ) ); if ($del != '' && $del != '..' && $del != '.' && verifyToken($_POST['token'])) { $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } $is_dir = is_dir($path . '/' . $del); if (fm_rdelete($path . '/' . $del)) { $msg = $is_dir ? lng('Folder').' %s '.lng('Deleted') : lng('File').' %s '.lng('Deleted'); fm_set_msg(sprintf($msg, fm_enc($del))); } else { $msg = $is_dir ? lng('Folder').' %s '.lng('not deleted') : lng('File').' %s '.lng('not deleted'); fm_set_msg(sprintf($msg, fm_enc($del)), 'error'); } } else { fm_set_msg(lng('Invalid file or folder name'), 'error'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Create a new file/folder if (isset($_POST['newfilename'], $_POST['newfile'], $_POST['token']) && !FM_READONLY) { $type = urldecode($_POST['newfile']); $new = str_replace( '/', '', fm_clean_path( strip_tags( $_POST['newfilename'] ) ) ); if (fm_isvalid_filename($new) && $new != '' && $new != '..' && $new != '.' && verifyToken($_POST['token'])) { $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } if ($type == "file") { if (!file_exists($path . '/' . $new)) { if(fm_is_valid_ext($new)) { @fopen($path . '/' . $new, 'w') or die('Cannot open file: ' . $new); fm_set_msg(sprintf(lng('File').' %s '.lng('Created'), fm_enc($new))); } else { fm_set_msg(lng('File extension is not allowed'), 'error'); } } else { fm_set_msg(sprintf(lng('File').' %s '.lng('already exists'), fm_enc($new)), 'alert'); } } else { if (fm_mkdir($path . '/' . $new, false) === true) { fm_set_msg(sprintf(lng('Folder').' %s '.lng('Created'), $new)); } elseif (fm_mkdir($path . '/' . $new, false) === $path . '/' . $new) { fm_set_msg(sprintf(lng('Folder').' %s '.lng('already exists'), fm_enc($new)), 'alert'); } else { fm_set_msg(sprintf(lng('Folder').' %s '.lng('not created'), fm_enc($new)), 'error'); } } } else { fm_set_msg(lng('Invalid characters in file or folder name'), 'error'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Copy folder / file if (isset($_GET['copy'], $_GET['finish']) && !FM_READONLY) { // from $copy = urldecode($_GET['copy']); $copy = fm_clean_path($copy); // empty path if ($copy == '') { fm_set_msg(lng('Source path not defined'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // abs path from $from = FM_ROOT_PATH . '/' . $copy; // abs path to $dest = FM_ROOT_PATH; if (FM_PATH != '') { $dest .= '/' . FM_PATH; } $dest .= '/' . basename($from); // move? $move = isset($_GET['move']); $move = fm_clean_path(urldecode($move)); // copy/move/duplicate if ($from != $dest) { $msg_from = trim(FM_PATH . '/' . basename($from), '/'); if ($move) { // Move and to != from so just perform move $rename = fm_rename($from, $dest); if ($rename) { fm_set_msg(sprintf(lng('Moved from').' %s '.lng('to').' %s', fm_enc($copy), fm_enc($msg_from))); } elseif ($rename === null) { fm_set_msg(lng('File or folder with this path already exists'), 'alert'); } else { fm_set_msg(sprintf(lng('Error while moving from').' %s '.lng('to').' %s', fm_enc($copy), fm_enc($msg_from)), 'error'); } } else { // Not move and to != from so copy with original name if (fm_rcopy($from, $dest)) { fm_set_msg(sprintf(lng('Copied from').' %s '.lng('to').' %s', fm_enc($copy), fm_enc($msg_from))); } else { fm_set_msg(sprintf(lng('Error while copying from').' %s '.lng('to').' %s', fm_enc($copy), fm_enc($msg_from)), 'error'); } } } else { if (!$move){ //Not move and to = from so duplicate $msg_from = trim(FM_PATH . '/' . basename($from), '/'); $fn_parts = pathinfo($from); $extension_suffix = ''; if(!is_dir($from)){ $extension_suffix = '.'.$fn_parts['extension']; } //Create new name for duplicate $fn_duplicate = $fn_parts['dirname'].'/'.$fn_parts['filename'].'-'.date('YmdHis').$extension_suffix; $loop_count = 0; $max_loop = 1000; // Check if a file with the duplicate name already exists, if so, make new name (edge case...) while(file_exists($fn_duplicate) & $loop_count < $max_loop){ $fn_parts = pathinfo($fn_duplicate); $fn_duplicate = $fn_parts['dirname'].'/'.$fn_parts['filename'].'-copy'.$extension_suffix; $loop_count++; } if (fm_rcopy($from, $fn_duplicate, False)) { fm_set_msg(sprintf('Copied from %s to %s', fm_enc($copy), fm_enc($fn_duplicate))); } else { fm_set_msg(sprintf('Error while copying from %s to %s', fm_enc($copy), fm_enc($fn_duplicate)), 'error'); } } else{ fm_set_msg(lng('Paths must be not equal'), 'alert'); } } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Mass copy files/ folders if (isset($_POST['file'], $_POST['copy_to'], $_POST['finish'], $_POST['token']) && !FM_READONLY) { if(!verifyToken($_POST['token'])) { fm_set_msg(lng('Invalid Token.'), 'error'); } // from $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } // to $copy_to_path = FM_ROOT_PATH; $copy_to = fm_clean_path($_POST['copy_to']); if ($copy_to != '') { $copy_to_path .= '/' . $copy_to; } if ($path == $copy_to_path) { fm_set_msg(lng('Paths must be not equal'), 'alert'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } if (!is_dir($copy_to_path)) { if (!fm_mkdir($copy_to_path, true)) { fm_set_msg('Unable to create destination folder', 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } } // move? $move = isset($_POST['move']); // copy/move $errors = 0; $files = $_POST['file']; if (is_array($files) && count($files)) { foreach ($files as $f) { if ($f != '') { $f = fm_clean_path($f); // abs path from $from = $path . '/' . $f; // abs path to $dest = $copy_to_path . '/' . $f; // do if ($move) { $rename = fm_rename($from, $dest); if ($rename === false) { $errors++; } } else { if (!fm_rcopy($from, $dest)) { $errors++; } } } } if ($errors == 0) { $msg = $move ? 'Selected files and folders moved' : 'Selected files and folders copied'; fm_set_msg($msg); } else { $msg = $move ? 'Error while moving items' : 'Error while copying items'; fm_set_msg($msg, 'error'); } } else { fm_set_msg(lng('Nothing selected'), 'alert'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Rename if (isset($_POST['rename_from'], $_POST['rename_to'], $_POST['token']) && !FM_READONLY) { if(!verifyToken($_POST['token'])) { fm_set_msg("Invalid Token.", 'error'); } // old name $old = urldecode($_POST['rename_from']); $old = fm_clean_path($old); $old = str_replace('/', '', $old); // new name $new = urldecode($_POST['rename_to']); $new = fm_clean_path(strip_tags($new)); $new = str_replace('/', '', $new); // path $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } // rename if (fm_isvalid_filename($new) && $old != '' && $new != '') { if (fm_rename($path . '/' . $old, $path . '/' . $new)) { fm_set_msg(sprintf(lng('Renamed from').' %s '. lng('to').' %s', fm_enc($old), fm_enc($new))); } else { fm_set_msg(sprintf(lng('Error while renaming from').' %s '. lng('to').' %s', fm_enc($old), fm_enc($new)), 'error'); } } else { fm_set_msg(lng('Invalid characters in file name'), 'error'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Download if (isset($_GET['dl'], $_POST['token'])) { if(!verifyToken($_POST['token'])) { fm_set_msg("Invalid Token.", 'error'); } $dl = urldecode($_GET['dl']); $dl = fm_clean_path($dl); $dl = str_replace('/', '', $dl); $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } if ($dl != '' && is_file($path . '/' . $dl)) { fm_download_file($path . '/' . $dl, $dl, 1024); exit; } else { fm_set_msg(lng('File not found'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } } // Upload if (!empty($_FILES) && !FM_READONLY) { if(isset($_POST['token'])) { if(!verifyToken($_POST['token'])) { $response = array ('status' => 'error','info' => "Invalid Token."); echo json_encode($response); exit(); } } else { $response = array ('status' => 'error','info' => "Token Missing."); echo json_encode($response); exit(); } $chunkIndex = $_POST['dzchunkindex']; $chunkTotal = $_POST['dztotalchunkcount']; $fullPathInput = fm_clean_path($_REQUEST['fullpath']); $f = $_FILES; $path = FM_ROOT_PATH; $ds = DIRECTORY_SEPARATOR; if (FM_PATH != '') { $path .= '/' . FM_PATH; } $errors = 0; $uploads = 0; $allowed = (FM_UPLOAD_EXTENSION) ? explode(',', FM_UPLOAD_EXTENSION) : false; $response = array ( 'status' => 'error', 'info' => 'Oops! Try again' ); $filename = $f['file']['name']; $tmp_name = $f['file']['tmp_name']; $ext = pathinfo($filename, PATHINFO_FILENAME) != '' ? strtolower(pathinfo($filename, PATHINFO_EXTENSION)) : ''; $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; if(!fm_isvalid_filename($filename) && !fm_isvalid_filename($fullPathInput)) { $response = array ( 'status' => 'error', 'info' => "Invalid File name!", ); echo json_encode($response); exit(); } $targetPath = $path . $ds; if ( is_writable($targetPath) ) { $fullPath = $path . '/' . $fullPathInput; $folder = substr($fullPath, 0, strrpos($fullPath, "/")); if (!is_dir($folder)) { $old = umask(0); mkdir($folder, 0777, true); umask($old); } if (empty($f['file']['error']) && !empty($tmp_name) && $tmp_name != 'none' && $isFileAllowed) { if ($chunkTotal){ $out = @fopen("{$fullPath}.part", $chunkIndex == 0 ? "wb" : "ab"); if ($out) { $in = @fopen($tmp_name, "rb"); if ($in) { if (PHP_VERSION_ID < 80009) { // workaround https://bugs.php.net/bug.php?id=81145 do { for (;;) { $buff = fread($in, 4096); if ($buff === false || $buff === '') { break; } fwrite($out, $buff); } } while (!feof($in)); } else { stream_copy_to_stream($in, $out); } $response = array ( 'status' => 'success', 'info' => "file upload successful" ); } else { $response = array ( 'status' => 'error', 'info' => "failed to open output stream", 'errorDetails' => error_get_last() ); } @fclose($in); @fclose($out); @unlink($tmp_name); $response = array ( 'status' => 'success', 'info' => "file upload successful" ); } else { $response = array ( 'status' => 'error', 'info' => "failed to open output stream" ); } if ($chunkIndex == $chunkTotal - 1) { if (file_exists ($fullPath)) { $ext_1 = $ext ? '.'.$ext : ''; $fullPathTarget = $path . '/' . basename($fullPathInput, $ext_1) .'_'. date('ymdHis'). $ext_1; } else { $fullPathTarget = $fullPath; } rename("{$fullPath}.part", $fullPathTarget); } } else if (move_uploaded_file($tmp_name, $fullPath)) { // Be sure that the file has been uploaded if ( file_exists($fullPath) ) { $response = array ( 'status' => 'success', 'info' => "file upload successful" ); } else { $response = array ( 'status' => 'error', 'info' => 'Couldn\'t upload the requested file.' ); } } else { $response = array ( 'status' => 'error', 'info' => "Error while uploading files. Uploaded files $uploads", ); } } } else { $response = array ( 'status' => 'error', 'info' => 'The specified folder for upload isn\'t writeable.' ); } // Return the response echo json_encode($response); exit(); } // Mass deleting if (isset($_POST['group'], $_POST['delete'], $_POST['token']) && !FM_READONLY) { if(!verifyToken($_POST['token'])) { fm_set_msg(lng("Invalid Token."), 'error'); } $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } $errors = 0; $files = $_POST['file']; if (is_array($files) && count($files)) { foreach ($files as $f) { if ($f != '') { $new_path = $path . '/' . $f; if (!fm_rdelete($new_path)) { $errors++; } } } if ($errors == 0) { fm_set_msg(lng('Selected files and folder deleted')); } else { fm_set_msg(lng('Error while deleting items'), 'error'); } } else { fm_set_msg(lng('Nothing selected'), 'alert'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Pack files zip, tar if (isset($_POST['group'], $_POST['token']) && (isset($_POST['zip']) || isset($_POST['tar'])) && !FM_READONLY) { if(!verifyToken($_POST['token'])) { fm_set_msg(lng("Invalid Token."), 'error'); } $path = FM_ROOT_PATH; $ext = 'zip'; if (FM_PATH != '') { $path .= '/' . FM_PATH; } //set pack type $ext = isset($_POST['tar']) ? 'tar' : 'zip'; if (($ext == "zip" && !class_exists('ZipArchive')) || ($ext == "tar" && !class_exists('PharData'))) { fm_set_msg(lng('Operations with archives are not available'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } $files = $_POST['file']; $sanitized_files = array(); // clean path foreach($files as $file){ array_push($sanitized_files, fm_clean_path($file)); } $files = $sanitized_files; if (!empty($files)) { chdir($path); if (count($files) == 1) { $one_file = reset($files); $one_file = basename($one_file); $zipname = $one_file . '_' . date('ymd_His') . '.'.$ext; } else { $zipname = 'archive_' . date('ymd_His') . '.'.$ext; } if($ext == 'zip') { $zipper = new FM_Zipper(); $res = $zipper->create($zipname, $files); } elseif ($ext == 'tar') { $tar = new FM_Zipper_Tar(); $res = $tar->create($zipname, $files); } if ($res) { fm_set_msg(sprintf(lng('Archive').' %s '.lng('Created'), fm_enc($zipname))); } else { fm_set_msg(lng('Archive not created'), 'error'); } } else { fm_set_msg(lng('Nothing selected'), 'alert'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Unpack zip, tar if (isset($_POST['unzip'], $_POST['token']) && !FM_READONLY) { if(!verifyToken($_POST['token'])) { fm_set_msg(lng("Invalid Token."), 'error'); } $unzip = urldecode($_POST['unzip']); $unzip = fm_clean_path($unzip); $unzip = str_replace('/', '', $unzip); $isValid = false; $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } if ($unzip != '' && is_file($path . '/' . $unzip)) { $zip_path = $path . '/' . $unzip; $ext = pathinfo($zip_path, PATHINFO_EXTENSION); $isValid = true; } else { fm_set_msg(lng('File not found'), 'error'); } if (($ext == "zip" && !class_exists('ZipArchive')) || ($ext == "tar" && !class_exists('PharData'))) { fm_set_msg(lng('Operations with archives are not available'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } if ($isValid) { //to folder $tofolder = ''; if (isset($_POST['tofolder'])) { $tofolder = pathinfo($zip_path, PATHINFO_FILENAME); if (fm_mkdir($path . '/' . $tofolder, true)) { $path .= '/' . $tofolder; } } if($ext == "zip") { $zipper = new FM_Zipper(); $res = $zipper->unzip($zip_path, $path); } elseif ($ext == "tar") { try { $gzipper = new PharData($zip_path); if (@$gzipper->extractTo($path,null, true)) { $res = true; } else { $res = false; } } catch (Exception $e) { //TODO:: need to handle the error $res = true; } } if ($res) { fm_set_msg(lng('Archive unpacked')); } else { fm_set_msg(lng('Archive not unpacked'), 'error'); } } else { fm_set_msg(lng('File not found'), 'error'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } // Change Perms (not for Windows) if (isset($_POST['chmod'], $_POST['token']) && !FM_READONLY && !FM_IS_WIN) { if(!verifyToken($_POST['token'])) { fm_set_msg(lng("Invalid Token."), 'error'); } $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } $file = $_POST['chmod']; $file = fm_clean_path($file); $file = str_replace('/', '', $file); if ($file == '' || (!is_file($path . '/' . $file) && !is_dir($path . '/' . $file))) { fm_set_msg(lng('File not found'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } $mode = 0; if (!empty($_POST['ur'])) { $mode |= 0400; } if (!empty($_POST['uw'])) { $mode |= 0200; } if (!empty($_POST['ux'])) { $mode |= 0100; } if (!empty($_POST['gr'])) { $mode |= 0040; } if (!empty($_POST['gw'])) { $mode |= 0020; } if (!empty($_POST['gx'])) { $mode |= 0010; } if (!empty($_POST['or'])) { $mode |= 0004; } if (!empty($_POST['ow'])) { $mode |= 0002; } if (!empty($_POST['ox'])) { $mode |= 0001; } if (@chmod($path . '/' . $file, $mode)) { fm_set_msg(lng('Permissions changed')); } else { fm_set_msg(lng('Permissions not changed'), 'error'); } $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); } /*************************** ACTIONS ***************************/ // get current path $path = FM_ROOT_PATH; if (FM_PATH != '') { $path .= '/' . FM_PATH; } // check path if (!is_dir($path)) { fm_redirect(FM_SELF_URL . '?p='); } // get parent folder $parent = fm_get_parent_path(FM_PATH); $objects = is_readable($path) ? scandir($path) : array(); $folders = array(); $files = array(); $current_path = array_slice(explode("/",$path), -1)[0]; if (is_array($objects) && fm_is_exclude_items($current_path)) { foreach ($objects as $file) { if ($file == '.' || $file == '..') { continue; } if (!FM_SHOW_HIDDEN && substr($file, 0, 1) === '.') { continue; } $new_path = $path . '/' . $file; if (@is_file($new_path) && fm_is_exclude_items($file)) { $files[] = $file; } elseif (@is_dir($new_path) && $file != '.' && $file != '..' && fm_is_exclude_items($file)) { $folders[] = $file; } } } if (!empty($files)) { natcasesort($files); } if (!empty($folders)) { natcasesort($folders); } // upload form if (isset($_GET['upload']) && !FM_READONLY) { fm_show_header(); // HEADER fm_show_nav_path(FM_PATH); // current path //get the allowed file extensions function getUploadExt() { $extArr = explode(',', FM_UPLOAD_EXTENSION); if(FM_UPLOAD_EXTENSION && $extArr) { array_walk($extArr, function(&$x) {$x = ".$x";}); return implode(',', $extArr); } return ''; } ?>
' . PHP_EOL; } ?>

: , ', $copy_files) ?>

:
/

 

Copying

Source path:
Destination folder:

Copy   Move   Cancel

/>
/>
/>

""

:
File size:
MIME-type:
:
:
:
: %
'.lng('Image size').': ' . (isset($image_size[0]) ? $image_size[0] : '0') . ' x ' . (isset($image_size[1]) ? $image_size[1] : '0') . '
'; } // Text info if ($is_text) { $is_utf8 = fm_is_utf8($content); if (function_exists('iconv')) { if (!$is_utf8) { $content = iconv(FM_ICONV_INPUT_ENC, 'UTF-8//IGNORE', $content); } } echo ''.lng('Charset').': ' . ($is_utf8 ? 'utf-8' : '8 bit') . '
'; } ?>

 
 
     
'; } else if($online_viewer == 'microsoft') { echo ''; } } elseif ($is_zip) { // ZIP content if ($filenames !== false) { echo ''; foreach ($filenames as $fn) { if ($fn['folder']) { echo '' . fm_enc($fn['name']) . '
'; } else { echo $fn['name'] . ' (' . fm_get_filesize($fn['filesize']) . ')
'; } } echo '
'; } else { echo '

'.lng('Error while fetching archive info').'

'; } } elseif ($is_image) { // Image content if (in_array($ext, array('gif', 'jpg', 'jpeg', 'png', 'bmp', 'ico', 'svg', 'webp', 'avif'))) { echo '

'; } } elseif ($is_audio) { // Audio content echo '

'; } elseif ($is_video) { // Video content echo '
'; } elseif ($is_text) { if (FM_USE_HIGHLIGHTJS) { // highlight $hljs_classes = array( 'shtml' => 'xml', 'htaccess' => 'apache', 'phtml' => 'php', 'lock' => 'json', 'svg' => 'xml', ); $hljs_class = isset($hljs_classes[$ext]) ? 'lang-' . $hljs_classes[$ext] : 'lang-' . $ext; if (empty($ext) || in_array(strtolower($file), fm_get_text_names()) || preg_match('#\.min\.(css|js)$#i', $file)) { $hljs_class = 'nohighlight'; } $content = '
' . fm_enc($content) . '
'; } elseif (in_array($ext, array('php', 'php4', 'php5', 'phtml', 'phps'))) { // php highlight $content = highlight_string($content, true); } else { $content = '
' . fm_enc($content) . '
'; } echo $content; } ?>
'. $file. ''; header('X-XSS-Protection:0'); fm_show_header(); // HEADER fm_show_nav_path(FM_PATH); // current path $file_url = FM_ROOT_URL . fm_convert_win((FM_PATH != '' ? '/' . FM_PATH : '') . '/' . $file); $file_path = $path . '/' . $file; // normal editer $isNormalEditor = true; if (isset($_GET['env'])) { if ($_GET['env'] == "ace") { $isNormalEditor = false; } } // Save File if (isset($_POST['savedata'])) { $writedata = $_POST['savedata']; $fd = fopen($file_path, "w"); @fwrite($fd, $writedata); fclose($fd); fm_set_msg(lng('File Saved Successfully')); } $ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION)); $mime_type = fm_get_mime_type($file_path); $filesize = filesize($file_path); $is_text = false; $content = ''; // for text if (in_array($ext, fm_get_text_exts()) || substr($mime_type, 0, 4) == 'text' || in_array($mime_type, fm_get_text_mimes())) { $is_text = true; $content = file_get_contents($file_path); } ?>
' . htmlspecialchars($content) . ''; echo ''; } elseif ($is_text) { echo '
' . htmlspecialchars($content) . '
'; } else { fm_set_msg(lng('FILE EXTENSION HAS NOT SUPPORTED'), 'error'); } ?>

:

 

'?'); } if ($group === false) { $group = array('name' => '?'); } } else { $owner = array('name' => '?'); $group = array('name' => '?'); } ?> '?'); } if ($group === false) { $group = array('name' => '?'); } } else { $owner = array('name' => '?'); $group = array('name' => '?'); } ?>
..
>
' . readlink($path . '/' . $f) . '' : '') ?>
">
>
' . readlink($path . '/' . $f) . '' : '') ?>
">
'.fm_get_filesize($all_files_size).'' ?> '.$num_files.'' ?> '.$num_folders.'' ?>
"; return; } echo "$external[$key]"; } /** * Verify CSRF TOKEN and remove after cerify * @param string $token * @return bool */ function verifyToken($token) { if (hash_equals($_SESSION['token'], $token)) { return true; } return false; } /** * Delete file or folder (recursively) * @param string $path * @return bool */ function fm_rdelete($path) { if (is_link($path)) { return unlink($path); } elseif (is_dir($path)) { $objects = scandir($path); $ok = true; if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (!fm_rdelete($path . '/' . $file)) { $ok = false; } } } } return ($ok) ? rmdir($path) : false; } elseif (is_file($path)) { return unlink($path); } return false; } /** * Recursive chmod * @param string $path * @param int $filemode * @param int $dirmode * @return bool * @todo Will use in mass chmod */ function fm_rchmod($path, $filemode, $dirmode) { if (is_dir($path)) { if (!chmod($path, $dirmode)) { return false; } $objects = scandir($path); if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (!fm_rchmod($path . '/' . $file, $filemode, $dirmode)) { return false; } } } } return true; } elseif (is_link($path)) { return true; } elseif (is_file($path)) { return chmod($path, $filemode); } return false; } /** * Check the file extension which is allowed or not * @param string $filename * @return bool */ function fm_is_valid_ext($filename) { $allowed = (FM_FILE_EXTENSION) ? explode(',', FM_FILE_EXTENSION) : false; $ext = pathinfo($filename, PATHINFO_EXTENSION); $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; return ($isFileAllowed) ? true : false; } /** * Safely rename * @param string $old * @param string $new * @return bool|null */ function fm_rename($old, $new) { $isFileAllowed = fm_is_valid_ext($new); if(!is_dir($old)) { if (!$isFileAllowed) return false; } return (!file_exists($new) && file_exists($old)) ? rename($old, $new) : null; } /** * Copy file or folder (recursively). * @param string $path * @param string $dest * @param bool $upd Update files * @param bool $force Create folder with same names instead file * @return bool */ function fm_rcopy($path, $dest, $upd = true, $force = true) { if (is_dir($path)) { if (!fm_mkdir($dest, $force)) { return false; } $objects = scandir($path); $ok = true; if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (!fm_rcopy($path . '/' . $file, $dest . '/' . $file)) { $ok = false; } } } } return $ok; } elseif (is_file($path)) { return fm_copy($path, $dest, $upd); } return false; } /** * Safely create folder * @param string $dir * @param bool $force * @return bool */ function fm_mkdir($dir, $force) { if (file_exists($dir)) { if (is_dir($dir)) { return $dir; } elseif (!$force) { return false; } unlink($dir); } return mkdir($dir, 0777, true); } /** * Safely copy file * @param string $f1 * @param string $f2 * @param bool $upd Indicates if file should be updated with new content * @return bool */ function fm_copy($f1, $f2, $upd) { $time1 = filemtime($f1); if (file_exists($f2)) { $time2 = filemtime($f2); if ($time2 >= $time1 && $upd) { return false; } } $ok = copy($f1, $f2); if ($ok) { touch($f2, $time1); } return $ok; } /** * Get mime type * @param string $file_path * @return mixed|string */ function fm_get_mime_type($file_path) { if (function_exists('finfo_open')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $mime = finfo_file($finfo, $file_path); finfo_close($finfo); return $mime; } elseif (function_exists('mime_content_type')) { return mime_content_type($file_path); } elseif (!stristr(ini_get('disable_functions'), 'shell_exec')) { $file = escapeshellarg($file_path); $mime = shell_exec('file -bi ' . $file); return $mime; } else { return '--'; } } /** * HTTP Redirect * @param string $url * @param int $code */ function fm_redirect($url, $code = 302) { header('Location: ' . $url, true, $code); exit; } /** * Path traversal prevention and clean the url * It replaces (consecutive) occurrences of / and \\ with whatever is in DIRECTORY_SEPARATOR, and processes /. and /.. fine. * @param $path * @return string */ function get_absolute_path($path) { $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path); $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); $absolutes = array(); foreach ($parts as $part) { if ('.' == $part) continue; if ('..' == $part) { array_pop($absolutes); } else { $absolutes[] = $part; } } return implode(DIRECTORY_SEPARATOR, $absolutes); } /** * Clean path * @param string $path * @return string */ function fm_clean_path($path, $trim = true) { $path = $trim ? trim($path) : $path; $path = trim($path, '\\/'); $path = str_replace(array('../', '..\\'), '', $path); $path = get_absolute_path($path); if ($path == '..') { $path = ''; } return str_replace('\\', '/', $path); } /** * Get parent path * @param string $path * @return bool|string */ function fm_get_parent_path($path) { $path = fm_clean_path($path); if ($path != '') { $array = explode('/', $path); if (count($array) > 1) { $array = array_slice($array, 0, -1); return implode('/', $array); } return ''; } return false; } function fm_get_display_path($file_path) { global $path_display_mode, $root_path, $root_url; switch ($path_display_mode) { case 'relative': return array( 'label' => 'Path', 'path' => fm_enc(fm_convert_win(str_replace($root_path, '', $file_path))) ); case 'host': $relative_path = str_replace($root_path, '', $file_path); return array( 'label' => 'Host Path', 'path' => fm_enc(fm_convert_win('/' . $root_url . '/' . ltrim(str_replace('\\', '/', $relative_path), '/'))) ); case 'full': default: return array( 'label' => 'Full Path', 'path' => fm_enc(fm_convert_win($file_path)) ); } } /** * Check file is in exclude list * @param string $file * @return bool */ function fm_is_exclude_items($file) { $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); if (isset($exclude_items) and sizeof($exclude_items)) { unset($exclude_items); } $exclude_items = FM_EXCLUDE_ITEMS; if (version_compare(PHP_VERSION, '7.0.0', '<')) { $exclude_items = unserialize($exclude_items); } if (!in_array($file, $exclude_items) && !in_array("*.$ext", $exclude_items)) { return true; } return false; } /** * get language translations from json file * @param int $tr * @return array */ function fm_get_translations($tr) { try { $content = @file_get_contents('translation.json'); if($content !== FALSE) { $lng = json_decode($content, TRUE); global $lang_list; foreach ($lng["language"] as $key => $value) { $code = $value["code"]; $lang_list[$code] = $value["name"]; if ($tr) $tr[$code] = $value["translation"]; } return $tr; } } catch (Exception $e) { echo $e; } } /** * @param string $file * Recover all file sizes larger than > 2GB. * Works on php 32bits and 64bits and supports linux * @return int|string */ function fm_get_size($file) { static $iswin; static $isdarwin; if (!isset($iswin)) { $iswin = (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'); } if (!isset($isdarwin)) { $isdarwin = (strtoupper(substr(PHP_OS, 0)) == "DARWIN"); } static $exec_works; if (!isset($exec_works)) { $exec_works = (function_exists('exec') && !ini_get('safe_mode') && @exec('echo EXEC') == 'EXEC'); } // try a shell command if ($exec_works) { $arg = escapeshellarg($file); $cmd = ($iswin) ? "for %F in (\"$file\") do @echo %~zF" : ($isdarwin ? "stat -f%z $arg" : "stat -c%s $arg"); @exec($cmd, $output); if (is_array($output) && ctype_digit($size = trim(implode("\n", $output)))) { return $size; } } // try the Windows COM interface if ($iswin && class_exists("COM")) { try { $fsobj = new COM('Scripting.FileSystemObject'); $f = $fsobj->GetFile( realpath($file) ); $size = $f->Size; } catch (Exception $e) { $size = null; } if (ctype_digit($size)) { return $size; } } // if all else fails return filesize($file); } /** * Get nice filesize * @param int $size * @return string */ function fm_get_filesize($size) { $size = (float) $size; $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); $power = ($size > 0) ? floor(log($size, 1024)) : 0; $power = ($power > (count($units) - 1)) ? (count($units) - 1) : $power; return sprintf('%s %s', round($size / pow(1024, $power), 2), $units[$power]); } /** * Get total size of directory tree. * * @param string $directory Relative or absolute directory name. * @return int Total number of bytes. */ function fm_get_directorysize($directory) { $bytes = 0; $directory = realpath($directory); if ($directory !== false && $directory != '' && file_exists($directory)){ foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS)) as $file){ $bytes += $file->getSize(); } } return $bytes; } /** * Get info about zip archive * @param string $path * @return array|bool */ function fm_get_zif_info($path, $ext) { if ($ext == 'zip' && function_exists('zip_open')) { $arch = @zip_open($path); if ($arch) { $filenames = array(); while ($zip_entry = @zip_read($arch)) { $zip_name = @zip_entry_name($zip_entry); $zip_folder = substr($zip_name, -1) == '/'; $filenames[] = array( 'name' => $zip_name, 'filesize' => @zip_entry_filesize($zip_entry), 'compressed_size' => @zip_entry_compressedsize($zip_entry), 'folder' => $zip_folder //'compression_method' => zip_entry_compressionmethod($zip_entry), ); } @zip_close($arch); return $filenames; } } elseif($ext == 'tar' && class_exists('PharData')) { $archive = new PharData($path); $filenames = array(); foreach(new RecursiveIteratorIterator($archive) as $file) { $parent_info = $file->getPathInfo(); $zip_name = str_replace("phar://".$path, '', $file->getPathName()); $zip_name = substr($zip_name, ($pos = strpos($zip_name, '/')) !== false ? $pos + 1 : 0); $zip_folder = $parent_info->getFileName(); $zip_info = new SplFileInfo($file); $filenames[] = array( 'name' => $zip_name, 'filesize' => $zip_info->getSize(), 'compressed_size' => $file->getCompressedSize(), 'folder' => $zip_folder ); } return $filenames; } return false; } /** * Encode html entities * @param string $text * @return string */ function fm_enc($text) { return htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); } /** * Prevent XSS attacks * @param string $text * @return string */ function fm_isvalid_filename($text) { return (strpbrk($text, '/?%*:|"<>') === FALSE) ? true : false; } /** * Save message in session * @param string $msg * @param string $status */ function fm_set_msg($msg, $status = 'ok') { $_SESSION[FM_SESSION_ID]['message'] = $msg; $_SESSION[FM_SESSION_ID]['status'] = $status; } /** * Check if string is in UTF-8 * @param string $string * @return int */ function fm_is_utf8($string) { return preg_match('//u', $string); } /** * Convert file name to UTF-8 in Windows * @param string $filename * @return string */ function fm_convert_win($filename) { if (FM_IS_WIN && function_exists('iconv')) { $filename = iconv(FM_ICONV_INPUT_ENC, 'UTF-8//IGNORE', $filename); } return $filename; } /** * @param $obj * @return array */ function fm_object_to_array($obj) { if (!is_object($obj) && !is_array($obj)) { return $obj; } if (is_object($obj)) { $obj = get_object_vars($obj); } return array_map('fm_object_to_array', $obj); } /** * Get CSS classname for file * @param string $path * @return string */ function fm_get_file_icon_class($path) { // get extension $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); switch ($ext) { case 'ico': case 'gif': case 'jpg': case 'jpeg': case 'jpc': case 'jp2': case 'jpx': case 'xbm': case 'wbmp': case 'png': case 'bmp': case 'tif': case 'tiff': case 'webp': case 'avif': case 'svg': $img = 'fa fa-picture-o'; break; case 'passwd': case 'ftpquota': case 'sql': case 'js': case 'ts': case 'jsx': case 'tsx': case 'hbs': case 'json': case 'sh': case 'config': case 'twig': case 'tpl': case 'md': case 'gitignore': case 'c': case 'cpp': case 'cs': case 'py': case 'rs': case 'map': case 'lock': case 'dtd': $img = 'fa fa-file-code-o'; break; case 'txt': case 'ini': case 'conf': case 'log': case 'htaccess': case 'yaml': case 'yml': case 'toml': case 'tmp': case 'top': case 'bot': case 'dat': case 'bak': case 'htpasswd': case 'pl': $img = 'fa fa-file-text-o'; break; case 'css': case 'less': case 'sass': case 'scss': $img = 'fa fa-css3'; break; case 'bz2': case 'tbz2': case 'tbz': case 'zip': case 'rar': case 'gz': case 'tgz': case 'tar': case '7z': case 'xz': case 'txz': case 'zst': case 'tzst': $img = 'fa fa-file-archive-o'; break; case 'php': case 'php4': case 'php5': case 'phps': case 'phtml': $img = 'fa fa-code'; break; case 'htm': case 'html': case 'shtml': case 'xhtml': $img = 'fa fa-html5'; break; case 'xml': case 'xsl': $img = 'fa fa-file-excel-o'; break; case 'wav': case 'mp3': case 'mp2': case 'm4a': case 'aac': case 'ogg': case 'oga': case 'wma': case 'mka': case 'flac': case 'ac3': case 'tds': $img = 'fa fa-music'; break; case 'm3u': case 'm3u8': case 'pls': case 'cue': case 'xspf': $img = 'fa fa-headphones'; break; case 'avi': case 'mpg': case 'mpeg': case 'mp4': case 'm4v': case 'flv': case 'f4v': case 'ogm': case 'ogv': case 'mov': case 'mkv': case '3gp': case 'asf': case 'wmv': case 'webm': $img = 'fa fa-file-video-o'; break; case 'eml': case 'msg': $img = 'fa fa-envelope-o'; break; case 'xls': case 'xlsx': case 'ods': $img = 'fa fa-file-excel-o'; break; case 'csv': $img = 'fa fa-file-text-o'; break; case 'bak': case 'swp': $img = 'fa fa-clipboard'; break; case 'doc': case 'docx': case 'odt': $img = 'fa fa-file-word-o'; break; case 'ppt': case 'pptx': $img = 'fa fa-file-powerpoint-o'; break; case 'ttf': case 'ttc': case 'otf': case 'woff': case 'woff2': case 'eot': case 'fon': $img = 'fa fa-font'; break; case 'pdf': $img = 'fa fa-file-pdf-o'; break; case 'psd': case 'ai': case 'eps': case 'fla': case 'swf': $img = 'fa fa-file-image-o'; break; case 'exe': case 'msi': $img = 'fa fa-file-o'; break; case 'bat': $img = 'fa fa-terminal'; break; default: $img = 'fa fa-info-circle'; } return $img; } /** * Get image files extensions * @return array */ function fm_get_image_exts() { return array('ico', 'gif', 'jpg', 'jpeg', 'jpc', 'jp2', 'jpx', 'xbm', 'wbmp', 'png', 'bmp', 'tif', 'tiff', 'psd', 'svg', 'webp', 'avif'); } /** * Get video files extensions * @return array */ function fm_get_video_exts() { return array('avi', 'webm', 'wmv', 'mp4', 'm4v', 'ogm', 'ogv', 'mov', 'mkv'); } /** * Get audio files extensions * @return array */ function fm_get_audio_exts() { return array('wav', 'mp3', 'ogg', 'm4a'); } /** * Get text file extensions * @return array */ function fm_get_text_exts() { return array( 'txt', 'css', 'ini', 'conf', 'log', 'htaccess', 'passwd', 'ftpquota', 'sql', 'js', 'ts', 'jsx', 'tsx', 'mjs', 'json', 'sh', 'config', 'php', 'php4', 'php5', 'phps', 'phtml', 'htm', 'html', 'shtml', 'xhtml', 'xml', 'xsl', 'm3u', 'm3u8', 'pls', 'cue', 'bash', 'vue', 'eml', 'msg', 'csv', 'bat', 'twig', 'tpl', 'md', 'gitignore', 'less', 'sass', 'scss', 'c', 'cpp', 'cs', 'py', 'go', 'zsh', 'swift', 'map', 'lock', 'dtd', 'svg', 'asp', 'aspx', 'asx', 'asmx', 'ashx', 'jsp', 'jspx', 'cgi', 'dockerfile', 'ruby', 'yml', 'yaml', 'toml', 'vhost', 'scpt', 'applescript', 'csx', 'cshtml', 'c++', 'coffee', 'cfm', 'rb', 'graphql', 'mustache', 'jinja', 'http', 'handlebars', 'java', 'es', 'es6', 'markdown', 'wiki', 'tmp', 'top', 'bot', 'dat', 'bak', 'htpasswd', 'pl' ); } /** * Get mime types of text files * @return array */ function fm_get_text_mimes() { return array( 'application/xml', 'application/javascript', 'application/x-javascript', 'image/svg+xml', 'message/rfc822', 'application/json', ); } /** * Get file names of text files w/o extensions * @return array */ function fm_get_text_names() { return array( 'license', 'readme', 'authors', 'contributors', 'changelog', ); } /** * Get online docs viewer supported files extensions * @return array */ function fm_get_onlineViewer_exts() { return array('doc', 'docx', 'xls', 'xlsx', 'pdf', 'ppt', 'pptx', 'ai', 'psd', 'dxf', 'xps', 'rar', 'odt', 'ods'); } /** * It returns the mime type of a file based on its extension. * @param extension The file extension of the file you want to get the mime type for. * @return string|string[] The mime type of the file. */ function fm_get_file_mimes($extension) { $fileTypes['swf'] = 'application/x-shockwave-flash'; $fileTypes['pdf'] = 'application/pdf'; $fileTypes['exe'] = 'application/octet-stream'; $fileTypes['zip'] = 'application/zip'; $fileTypes['doc'] = 'application/msword'; $fileTypes['xls'] = 'application/vnd.ms-excel'; $fileTypes['ppt'] = 'application/vnd.ms-powerpoint'; $fileTypes['gif'] = 'image/gif'; $fileTypes['png'] = 'image/png'; $fileTypes['jpeg'] = 'image/jpg'; $fileTypes['jpg'] = 'image/jpg'; $fileTypes['webp'] = 'image/webp'; $fileTypes['avif'] = 'image/avif'; $fileTypes['rar'] = 'application/rar'; $fileTypes['ra'] = 'audio/x-pn-realaudio'; $fileTypes['ram'] = 'audio/x-pn-realaudio'; $fileTypes['ogg'] = 'audio/x-pn-realaudio'; $fileTypes['wav'] = 'video/x-msvideo'; $fileTypes['wmv'] = 'video/x-msvideo'; $fileTypes['avi'] = 'video/x-msvideo'; $fileTypes['asf'] = 'video/x-msvideo'; $fileTypes['divx'] = 'video/x-msvideo'; $fileTypes['mp3'] = 'audio/mpeg'; $fileTypes['mp4'] = 'audio/mpeg'; $fileTypes['mpeg'] = 'video/mpeg'; $fileTypes['mpg'] = 'video/mpeg'; $fileTypes['mpe'] = 'video/mpeg'; $fileTypes['mov'] = 'video/quicktime'; $fileTypes['swf'] = 'video/quicktime'; $fileTypes['3gp'] = 'video/quicktime'; $fileTypes['m4a'] = 'video/quicktime'; $fileTypes['aac'] = 'video/quicktime'; $fileTypes['m3u'] = 'video/quicktime'; $fileTypes['php'] = ['application/x-php']; $fileTypes['html'] = ['text/html']; $fileTypes['txt'] = ['text/plain']; //Unknown mime-types should be 'application/octet-stream' if(empty($fileTypes[$extension])) { $fileTypes[$extension] = ['application/octet-stream']; } return $fileTypes[$extension]; } /** * This function scans the files and folder recursively, and return matching files * @param string $dir * @param string $filter * @return array|null */ function scan($dir = '', $filter = '') { $path = FM_ROOT_PATH.'/'.$dir; if($path) { $ite = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)); $rii = new RegexIterator($ite, "/(" . $filter . ")/i"); $files = array(); foreach ($rii as $file) { if (!$file->isDir()) { $fileName = $file->getFilename(); $location = str_replace(FM_ROOT_PATH, '', $file->getPath()); $files[] = array( "name" => $fileName, "type" => "file", "path" => $location, ); } } return $files; } } /** * Parameters: downloadFile(File Location, File Name, * max speed, is streaming * If streaming - videos will show as videos, images as images * instead of download prompt * https://stackoverflow.com/a/13821992/1164642 */ function fm_download_file($fileLocation, $fileName, $chunkSize = 1024) { if (connection_status() != 0) return (false); $extension = pathinfo($fileName, PATHINFO_EXTENSION); $contentType = fm_get_file_mimes($extension); if(is_array($contentType)) { $contentType = implode(' ', $contentType); } $size = filesize($fileLocation); if ($size == 0) { fm_set_msg(lng('Zero byte file! Aborting download'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); return (false); } @ini_set('magic_quotes_runtime', 0); $fp = fopen("$fileLocation", "rb"); if ($fp === false) { fm_set_msg(lng('Cannot open file! Aborting download'), 'error'); $FM_PATH=FM_PATH; fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); return (false); } // headers header('Content-Description: File Transfer'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Pragma: public'); header("Content-Transfer-Encoding: binary"); header("Content-Type: $contentType"); $contentDisposition = 'attachment'; if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) { $fileName = preg_replace('/\./', '%2e', $fileName, substr_count($fileName, '.') - 1); header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); } else { header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); } header("Accept-Ranges: bytes"); $range = 0; if (isset($_SERVER['HTTP_RANGE'])) { list($a, $range) = explode("=", $_SERVER['HTTP_RANGE']); str_replace($range, "-", $range); $size2 = $size - 1; $new_length = $size - $range; header("HTTP/1.1 206 Partial Content"); header("Content-Length: $new_length"); header("Content-Range: bytes $range$size2/$size"); } else { $size2 = $size - 1; header("Content-Range: bytes 0-$size2/$size"); header("Content-Length: " . $size); } $fileLocation = realpath($fileLocation); while (ob_get_level()) ob_end_clean(); readfile($fileLocation); fclose($fp); return ((connection_status() == 0) and !connection_aborted()); } /** * If the theme is dark, return the text-white and bg-dark classes. * @return string the value of the variable. */ function fm_get_theme() { $result = ''; if(FM_THEME == "dark") { $result = "text-white bg-dark"; } return $result; } /** * Class to work with zip files (using ZipArchive) */ class FM_Zipper { private $zip; public function __construct() { $this->zip = new ZipArchive(); } /** * Create archive with name $filename and files $files (RELATIVE PATHS!) * @param string $filename * @param array|string $files * @return bool */ public function create($filename, $files) { $res = $this->zip->open($filename, ZipArchive::CREATE); if ($res !== true) { return false; } if (is_array($files)) { foreach ($files as $f) { $f = fm_clean_path($f); if (!$this->addFileOrDir($f)) { $this->zip->close(); return false; } } $this->zip->close(); return true; } else { if ($this->addFileOrDir($files)) { $this->zip->close(); return true; } return false; } } /** * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE PATHS) * @param string $filename * @param string $path * @return bool */ public function unzip($filename, $path) { $res = $this->zip->open($filename); if ($res !== true) { return false; } if ($this->zip->extractTo($path)) { $this->zip->close(); return true; } return false; } /** * Add file/folder to archive * @param string $filename * @return bool */ private function addFileOrDir($filename) { if (is_file($filename)) { return $this->zip->addFile($filename); } elseif (is_dir($filename)) { return $this->addDir($filename); } return false; } /** * Add folder recursively * @param string $path * @return bool */ private function addDir($path) { if (!$this->zip->addEmptyDir($path)) { return false; } $objects = scandir($path); if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (is_dir($path . '/' . $file)) { if (!$this->addDir($path . '/' . $file)) { return false; } } elseif (is_file($path . '/' . $file)) { if (!$this->zip->addFile($path . '/' . $file)) { return false; } } } } return true; } return false; } } /** * Class to work with Tar files (using PharData) */ class FM_Zipper_Tar { private $tar; public function __construct() { $this->tar = null; } /** * Create archive with name $filename and files $files (RELATIVE PATHS!) * @param string $filename * @param array|string $files * @return bool */ public function create($filename, $files) { $this->tar = new PharData($filename); if (is_array($files)) { foreach ($files as $f) { $f = fm_clean_path($f); if (!$this->addFileOrDir($f)) { return false; } } return true; } else { if ($this->addFileOrDir($files)) { return true; } return false; } } /** * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE PATHS) * @param string $filename * @param string $path * @return bool */ public function unzip($filename, $path) { $res = $this->tar->open($filename); if ($res !== true) { return false; } if ($this->tar->extractTo($path)) { return true; } return false; } /** * Add file/folder to archive * @param string $filename * @return bool */ private function addFileOrDir($filename) { if (is_file($filename)) { try { $this->tar->addFile($filename); return true; } catch (Exception $e) { return false; } } elseif (is_dir($filename)) { return $this->addDir($filename); } return false; } /** * Add folder recursively * @param string $path * @return bool */ private function addDir($path) { $objects = scandir($path); if (is_array($objects)) { foreach ($objects as $file) { if ($file != '.' && $file != '..') { if (is_dir($path . '/' . $file)) { if (!$this->addDir($path . '/' . $file)) { return false; } } elseif (is_file($path . '/' . $file)) { try { $this->tar->addFile($path . '/' . $file); } catch (Exception $e) { return false; } } } } return true; } return false; } } /** * Save Configuration */ class FM_Config { var $data; function __construct() { global $root_path, $root_url, $CONFIG; $fm_url = $root_url.$_SERVER["PHP_SELF"]; $this->data = array( 'lang' => 'en', 'error_reporting' => true, 'show_hidden' => true ); $data = false; if (strlen($CONFIG)) { $data = fm_object_to_array(json_decode($CONFIG)); } else { $msg = 'Tiny File Manager
Error: Cannot load configuration'; if (substr($fm_url, -1) == '/') { $fm_url = rtrim($fm_url, '/'); $msg .= '
'; $msg .= '
Seems like you have a trailing slash on the URL.'; $msg .= '
Try this link: ' . $fm_url . ''; } die($msg); } if (is_array($data) && count($data)) $this->data = $data; else $this->save(); } function save() { $fm_file = __FILE__; $var_name = '$CONFIG'; $var_value = var_export(json_encode($this->data), true); $config_string = " ' . $_SESSION[FM_SESSION_ID]['message'] . '

'; unset($_SESSION[FM_SESSION_ID]['message']); unset($_SESSION[FM_SESSION_ID]['status']); } } /** * Show page header in Login Form */ function fm_show_header_login() { $sprites_ver = '20160315'; header("Content-Type: text/html; charset=utf-8"); header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); header("Pragma: no-cache"); global $lang, $root_url, $favicon_path; ?> '; } ?> <?php echo fm_enc(APP_TITLE) ?> ">
'; } ?> <?php echo fm_enc(APP_TITLE) ?> ">
dashicons.ttf000064400000156110150211053000007225 0ustar00 0GSUB8BOS/2@O%|Vcmap_>$glyfqdE@headf6hhea7H$hmtxPlocalAmaxpo name+_"post#2\,. T_< 66 T  ,DFLTliga fG fPfEd@G.,, <  )9@B )9IIWY`iy )18CG 0@B 0@HPY`bp 03@E<vx"""0BTfnt  4 >JKHILGO. KQ5EF\GW*ZX]g$'.-JR $%p&'() 2M34H[i: OYEAjklmnr6 TRt"#7MSPywvx~}hBCDSQ98 L/0q@P1+N5s76D%&+,()"#:<A@8;=B>??uV*o-z{9/,!U<3{|;INC!bcd^_efa`2=1F  0 V     4 >JKHILG O!!.""##$$ %%&&''(())K**Q++5,,--..E//F0011\2233G44556677W8899*::Z;;X<<]==g>>??@@$AA'BB.CC-DDEEJFFGGRHHIIJJKKLLMMNNOO PPQQ$RR%SSpTTUUVVWWXXYYZZ&[['\\(]])^^ __``aabbccddeeffgghhiijj2kkMll3mm4nnHoo[ppiqq:rr ssttOuuvvYwwExxAyyzzj{{k||l}}m~~nr6 TRt"#7MSPywvx ~ }!!""##$$%%&&h''(())0011223344B55C66D7788S99Q@@BB98 L /0q@P !!1""##+$$N%%&&5''s(())00711622334455667788D99@@%AA&BB+CC,DD(EE)FF"GG#HHIIHH:II<PPAQQ@RR8SS;TT=UUBVV>WW?YY``bbcc?ddueeffgghhiiVppqq*rross-ttzuu{vvww9xx/yy,!U<3{|;I NC!bcd^_ e!!f""a##`$$2%%&&''((=))100113344F556677 88@@AA BB0CCEEFFGGPp0TNnR@">Rx  . @ L ` p | V j  d  @ff lp,&H `v0P<nBt6NfvB"b,d&Rx8f  P t ! !B!"L"""#D###$j$%%,%j%%&h&&''>'~''(P((()).)b)))*D*l**+B++,>,z,--2---.p.../L//0L001 141\1112B22233Z334`44455N556"6d667$7H7^778:8r89969P9j9999:n:; ;~;<<<2<<=N=> >>?(?f???@@r@AA@AABBDBBCCZCCCCD4DDE EDEEEFFTFfFG(GPGhGGH H@HpHHI&IZIIIJJNJJJKK8KLLM@MtMMNN4NNO OZOOPPBPdPPQ Q.Q`QQRRRvRSbST2TXTjT /%'767'7676?676227s& 9 ".   #!  &  .   $    2".4>57\66\n\67\i6\n\66\m]6b32+5#"&=4633 3656'&'&"17>767676676767676  $,$/ 3 #T  ,  -(  #  0%,$    "# '0%#'#5&''7&'#5367'7675373264&"8(6(M(6(77(6'M(6'8 --@--'6(77(6(L(6(88'6(s-@--@- ''753!55#'f4f&'f3("8'764&"&6?>764&67.6?>2'9j .j'99Չ j'89+(8j!-99'j. j9'ډ3j9'+99'j.!*6%54&+'##"3!26'2"&463"&46325#53"&4632M +"f"+   %%5&&̀%5&&Mf3%5&& 33 &5%%5&'%%5&Y%%5&   %)-''7'575#''7''7%#5%#55#!5#mmmgeffL4mmmmfff̀444P``pp;WXZZ4++g__pp__pp3YZZYYZZ@3333'#'7&67>264&"N$0M&M BB'BA U_3%Qz 7!3!33M3M#'767+"&4?547676PS0S d   SSS0S4   c"ZSS!7&'&7676?'76?> //1 .>H H>/1./ 1.>H G>/ 1+G%4&#!"3!26%32+"&=#"&46;5462#"&46;546232+"&5  M             f4  &&Y&& 3T\"2>4..'67&"&'&&7676'32267&'&765&'&'.'&'&676767667>j>>j}j>>j ,   %!  5/   ! I >j}j>>j}j> 3      9!     6* $,'Bl   (0<k"2>4.67#&'&'.'67>76'267&7&'&/..'&'&'&'&&'&6'&'>>j>>j}j>>j       ' W F2  "   #  Ob0>j}j>>j}j>           $  %  .;5 #(.39@ELRX]ci"2>4.3#&75#5'#676#67#6733#&&'&'53=373#675&'3'#&''#63&'673>j>>j}j>>jA7& ]#G&] &A7]R [&iF&\ &A8 8&. 0  - - 1 - 0>j}j>>j}j>#"!P% #"#ErP %cE#"E$!"FE"CO% ON %rE#"E$!""$""!$g$+A$+#,B#* :H"2>4.6'&'&'&'&'>7&'&'>7'.'&7&7&'&'&'&'>j>>j}j>>jh  =.fA    3O" 6   >j}j>>j}j>L,"  # ) >O  P#.&Z+   '"&4?&>7264&"F 6& 2AJHJ &5 E2 JIJ@)"'&'&/&76272"'&/54>3 M F6 #"0S0""5  & &  B/"6@  @5!;&'764'&'764&"'&'7'7>/764&"'764&"'7676Y> .    :Z P.@    a b    >.P Z: "   1 =W ';O5!57>'.5!#'&'5>>.'.>767>'.>767>><4ELc2X 7 -S  R3 (!  A 6- 3Tl41C f  ` 7  a    7    !5!5!!5!Mf33f3f3%!!5!3f3 !5!5#%35#35#!5!MfMMMMf3g333 !5!5!!5!Mff3f3 7#735#35#͙f4̴33 %#'#3#34f4343 !5!35#5##35#!5!MfMMfMMf3333 !5!5!!5!333f3"P[%#"'&326764&7&76327>'672?6'&'54'.#3265>"7#"&54ISo\*h8-U%+' ( "#%, *+(Z  6%'  #  %4  M  #  ' #|  +!%%!!5!3"&46527#53#53#53!5!fg4M-@--:gggggg43fMMM --@-33g4gg !5!!%5#4f44M37'74f33fffg7'3f4'gf3!'7ff4f33fg'7f3Mg%'7Mge75!'7'733ff4f33fg?'73gg͙fge%#'7'4f33f33ffg%''73M?gfM3gM!-767676&'&7>76>76'&   /2o\ <%&@%) $(      A6:3:51*3/S!'-7?'7/'"&462'"&462'73%7'#r4;;43 ;; [*<.'>&5717'7&]2:3\m1$2 * (%TF'-KTF0 .\m>Ms\mc::$2-KTF'-&O2: {{R6 !53'33'33'!5!f@3@3@fg33(5BOk&'&'&'&''&"2?&'&%762'&4&4?62&4?62"7"&4?627.&'&"33264a!  % @ n % 3 Jn n *n nn nm ( $  $$ @ %% o 94 Ps q n* n nFq om * &  %!%265#754&'>7."!5.f{*""+33;#7    7%8' @@&5##5##"!54&#MfM f f4444 7!!"&5463!!"74&"26M -- M >  M3-4-Y3!"&546;#"3!3 --  g-4-9B354636332+"&=#"&=#"&="'"&=#546;5264&"3/ 3 - 3 3/M*  84  44  48  g - $5Bu7656&6&#"3276"2>4."&'.'&4>276&#"3>"767216327>&#"4?672632#"'&'32>4.s] -7_77_n_77_7(G4XhX44X- [&E  !8#,-2/N//Na*7%#}  ,+7_n_77_n_7s5hX44XhX4} ,$  v>{+" , /N^N/ &3<L_2".4>"2>4.2".4>">54&"264&34'&'&'!6'&'&'&'FuEEuuEEuFBpAAppAApB;d;;dvd;;di'!,\,,>,,N    666%  EuuEEuuE AppAAppA;dvd;;dvd;, 1 (,,>,,>,   655$ )Ok4'2674'2654&"26754&"264&'"&=#"&=276767>27>76767".= g ggf1(  (1* " *( * ! 0RbR0     Y  Y  Y  Y /?LL?/8    -o  M//M   #/G#"&46;&546;232!2#!"&46!2#!"&4632++"&547#"&46Z))4  $  >   M  ML-=AEIM4'&/2674'&/2654&+";26754&+";26'7?7?   -   - 3  3  3  3 33333333l    333343/'#'&'&6765.>27&'>7656" 3DC6 #)3- ,>- .5 )`J##K !? a;D;##;D;b@! 2!767676'7'7''70S* f$&__ : 3_X @ KG !n tGI hjNW`n{%"/'&'&'&5"&4?67&547>7#"&4635462354622+>7'264&"7"264&;264'&+"4&+";263264&+"3264&+"-?     ?-#!&  4  ' "" W ED L LYLL@- &  % -@ /: ":*   *:" :/d3  @ ;  3   -=&"2?>&"2?64"/"&4?624'&/;2  =   k  k.     "  =  k  k.   )"'&'7.'76767&327'267'#"'t+&T&+s9&?3 /1v3(#&@@&'R$$K$1 J ~,.- #'+/37;?3!!#53#53#53#53#53#53#53#53#53#53#53#53#53#53#53Mff33g44f3333g44f3333g44f3333g44f33ff3333M33333444443333333333333%.%54'&'&'&#'57'"32767"2>&  )+  !/2F>$' %4% 'O@ ,!MM!,  @{:N00P8''';676?4'&'&'7'"2>&R88/+''+))))$' %4% 'M$$M %>>%)):N00P8GK%&'&'#'7"776?54%267&'&72654'&'&'&'&"'7\\: ".))." %   % j g;;;6^\89HH6E !   '' ,!"3!26=4&#!"&=463!2f  f    !*3<EQZ^!"3!2654&"&462'"&462'"&462"&462'"&462'"&462"&=462'"&4627!5!      M   n!   f \W\W  Z  8WW +/37;?CGKOS3!3546235462#26=4&"26=4&"!7#5;#353#5;#353#5#53#53MfMf    ff3f44g33f44g3344f33@@@@z4444433333333333+/37;3!3546235462#26=4&"26=4&"5!75#35#35#MfM f     ff343g@@@@32#!"&546;73264&"K  j  KMf3*<"264&@  \).@"'8 %2$R$2%  B#! d"36&!%%%%#$  MO7767676'&'6>'&'&/67676&&'&&'&'&''&'3NFKM      $#   !+$ $,( '%("35 !     9     - -( 'H;A"+732#!"&5#"&46;2!#2"&4632"&46  3  M Lf     3g     !!3#3Mf4MM4&/8%>54&"&"'654&"2"&462"&462"&46 * j 6* L   3; '  M %####5#g3f3g3f 1!7&54626327&546327"&='#"' ~l % \ 1U ) R     52'3".4>1R0ʹ1RaS00S0R10S00SaR1-6:>BFJ76"/&4?627&76765.#&#"&4627'7'7'7'71# $~  S$  $B  ~ $2".4>2>4."7/18^77^p^77^8*F**FTF**FsM7^p^77^p^7*FTF**FTF*6R{{  654&#"&#"3!264&'77{<*1  &#,5$%5/R$.a$ *= % 2"$66F4Q$.b$!654&#"&#";5#7#3264&{<*1  &#,5$ZMssLY%5/ *= % 2"$6MssM6F44654&#"&#"3!264&}<*1 &#,5$%5-*=% 2"$66G3$IRx54&'>=46;5#"#2;5#"&&'&'6'.'&765&%"&46274654&+32+32654&4635"&      . .$'S d,    +<76?'5/.   , \./5 ,   \73#3#M͙%7'3]]]]55]]4]]733#MfMMf44 5!5557!'73gg3ggMM&3ML3M&3ML3 7''#37333=\\\{{3{{ 7553#5͚33]4]]{{{{37'#3ggMff&E37'#%#"'&67367654'&'.>##"'&>76764'&'.>33ggE       '       Mff #^#   #6'  (   *  8<!2#!&546!%47676763#!"&=27676762!!8  p     $ 4  ) g   g    3 (09BK7!>54."2"&462"&4632"&467"&4'2"&46!2"&464&"26`@7^p^7 [  V*g > ufB#8^77^8#B4u+7M 0CO264&"7533##5#5467#"".52>=7#".52>=#"'3.'.5f+<=7#".52>=#"'3.'.53264&"7##5#1R0W\1R00RbR00R.1R00RbR0!, \A[0R+<=#"".52>='3.'.53264&"7533'1R0W.1R00RbR0!, \1R00RbR00R1A[0R+<=#"'3.'.5".52>=f+<=#"".52>='3.'.53264&"'7'1R0W.1R00RbR0!, \1R00RbR00R1A[0R+< .?2>4."".52>='".52>='".52>=1R00RbR00R11R00RbR00R11R00RbR00R11R00RbR00RfM  MfM MgMM!$!2+32!546;5#"&5465!73Mf  3  3 X 4  4  紴f 2".4>'7''78^77^p^77^MM3MM3MM3MM7^p^77^p^7MM3MM3MM3MM35!353'35g34MM͚40&'.767676?>327&67626&  JA)   7* !@$7    @ 377/7676!"!$T  $ !!"!$+T  $ #!5#'.#3576&?f3d! g@q)3C!͚f @q) ?677'dE ͏=gE P 5#5!5#5!f33f33g33f33 5#5!5#5!3ff33f33g33f33 5#5!5#5!f33f33g33f3332654&'5>54&#532#32+t5=;C#')8+3-!&',)J'8*3!'733怀MgfM '77'7ffMfffff4ff47'7#7!75#35'!'3:: f `f` f :: f `` fS`` g 99 g `f` g 99 g$235#67654&"#35&'&'&54613*^%UT%] 3v751#33"'/DOPC/'!33 !157 3#3'735'75!#7'g8aga8";aga;3ffa9Gf9aG!_9ff9_ %.4."2>'#5467>4&#"'632&462"0RbR00RbR0(   !%%&1R00RbR00R   ! O "53753355#%53535335353Mff3ff3泳fM33M3ZY3333M44L33M33 5!5#35#35#5!MMfMMMffg444444ff #3#737#73z6H66H6f334 !!!!!!!!3ffff3334333 #'+/37;?!55!7#53#53#53#53#5!55!7#53#53#53#5#5!#53#54fM33433f4fM334̀33͚ffM4444444444ͳ33333333L444444!$#";2654622653264&7M 55  5?5  3   Mgf#S\`dh6235#767654'&/&""#6򥊢'&#"632632+32#"'"'26542735#35#35#35#)H,  1        '3! )       #Of ' (,RV5#?73#5#5767>4.">273#4&#">32+32#"&'32654&'5>3#! I ,    f!      !Mf  E3   2K   "5#5##553%5#5#5##5#5#ff3ff3泳fM3333ZY3333M44L33M33!#";2654622653264& 55  5@5  3   M$,!57264&"732#!"&546;!55#335=CD< '   '44L4MMM  3 <<44$1!57264&"4&+!57#"3!26'#'#'3737=CD<  ''  f M335134MMM3 <= ش'74'&'&&67'32674'&'&&67'326 -##;#)2%!+ -##;#)1& +F24;C/7'!F24;C/7'$"/&=4?62764/&"2n-9-7768677!$#";2654622653264&5M 55  5?5  3   Mf/7=EK27&"3275#"&463'#373732654&'5>54&#532##76732+7''  -"$! 9:;67  n,df $&)8+o @+  ( $  MNAGORZ%267#"'&'#+5##'##7#53733532367>2.#"3#%3/73>4&#1#3+3264  !7$:".- ! .   KK p k,1 @@++@@@@      U* D+  %!!5!#53#53#53#53fg4Mf3444333 %3#373'#7S0i4f0k R&M'} "&"&46273#"&46273#"&46273# 0@ 0@ 0M  3  3  3g#"'&=#27655#f3$63y%'#- ''-33!58;>'?64&"'6?>'3''7.6?27'#'7'' 6+' .= '99͚4f3ͽ#89+$<'!-͚4f399' *'. ?7 'Agf3<$+98#(-!gf3 #'+/37;?CGK##5#3533#5!#5#5#5!#5#5!#5#5!#5#5#5!#5#5!#5#5!#5MMMMf33334"&462%"264&#"264&**3*******-%54&#!"3!26'"/'"'&?'.7676g!hd p67p dh  `h_11_h`  7%>=4&'&7>7>4  {.z.Ks :  !2#!"=47>.'&cS000ڬ  ....ݎcc#)!"3!26=4&#"&463253'757'5fM* ff&&LL&&MMg+n&'&MM&'&'M!"3!26=4&'757'5fb&&LL&&M&'&MM&'&'M$-!"3!26=4&#53'757'5'5'7264&"fȳf&&LL&&M.4 ͙s&'&MM&'&'M@&.>-39!"3!26=4&'&76?'76?>'7&'757'5f ! !  M &&LL&&M " "   J0&'&MM&'&'M#!"3!26=4&'#537'757'5f33f&&LL&&M$1."g&'&MM&'&'M%)%4&#!"3!262"&46!!52"&46!!5 f    W4 W3  f 3#35#7'7'M33ffn$$n33f4n$$n3'5'7#57!3#3$h334fO$M33o73537#5476;5&#"#3K> H & *3??3I. A3-6I$!2+537#546;5&#"#3#"&546Jl h5=  %+55  >'8+'-> l #!2#!"&5465!735335353353  f MM  f MMfMM576762'./5M!!.T.!!! 337#7567'&'&'&3M#.1+#+51&3 $0C"#54&"#54&"26=>=4&3265""26=>'4&  - -%& @@ @@ T  T  ,2#(  (#2 !!!5!55#7#̙L44͙̀gf%6"&46325#"&4632546 4J55%3"%44%3 %55J4 3 ,4J5 &#"5#"&=46;232+'#"&=46#M33Mf$/MMfLL&BK32#!"&=#"&5463!2!!4&"2667676763#52767632#+2  2  K   3      2 K  @ c ͚      >!2#!"&546!4&"2647676763#!"&=2176767632:t**M       tgf+k "  3    )74'&'&&67'32674'&'&&67'326 5)*+#& ;+'2 5)),"& :+'2!%R:"&-2lA-'!%R:"&-2lA- '092"'&476264&"3264&"3264&"2"&462"&46}90099009     = 0))00))0        3  !2%46373#37#37#3!73 4q43M333M f MMMMMMMgf #&),/3#7357#53%'7'35#!#53#57#7'533&M̀&''@'M3&'M''Z&@&Mͳ@&@'MM'& '''g'&&'M@& #77'77535''3'7.E'H.H'E.s'E+.E..H̀.H'E..E'E+'E..HE+.E 357''375#!#77'W$H..H$H.H$H.f.H$H$H..$H$H.H$H..H$H+4=.+"76767627>'&##5#53533"&4627"&462 (( '&   1 s+85W      W58.& *   #3'.'&>727.#"32>5'&pA(2E9",#;H&7^88^7:Z1&L(1E2";$87_n_73[:!2#!"&5465#!5#5#!5#3  f f3f f   ̙͙ !-;J2>."2>."2>."76&"26'"&/&63272"'76'&'6 " "n     1j2 '  " *- -* " **#)$$$$n/88/n &6a ](//(] `7&'7&'"/&47%&'6$Y$v;Vi?^$W$!x%  " #5#3533@@@@M%6767>'&".#&=1,%:11:%3,1J+)1/U..V_)+&<@&"&#764&'677&6762&'+6267>7.26 >**I{",+ E"1/Im    !i< ?q$  rf*<>J? (+ H !.BK8  ;  39;3 f<)%#&'&'67673264&#!";#"3!264& 0.   0.   f6 ''!56 ''!5 #)/575##5335335#53#353373#5##'#3#533'77'7f333$_!3#&L3;;YY.;;YYf4433ggWWP@@Pf:;ZY;:YZ #<@DHL%!!>?6.#"275#5#'"276?54.#5#5#5!5!f  рW#  MMMM43     C3/  4L48<@D%!!>?6.#"25#'"276?54.#5#5#5!f   #  瀀f4t      ff  533%##5#5#535337'#35fMffMMMfgfMffMffLMgf4&"26>.>.f4.#"5>@529925@4.".4>244  ?j==j~j==j?1R00RbR00Rff=j~j==j~j=g0RbR00RbR0 2".4>4&"265#8^77^p^77^R47^p^77^p^7g ܚ %)73535#5##32>4."2".4>!5!4334331R00RbR00R1#;"";F;"";f333330RcR00RcR04";G:"":G;"3 %)##33535#'"2>4.".4>2!54334331R00RbR00R1#;"";F;"";f3333330RcR00RcR0";G:"":G;"33 %"2>4.".4>2##33535#?j==j~j==j?1R00RbR00R4LL4LL=j~j==j~j=g0RbR00RbR0L4LL4G_4&"267"&4627"&462'"#"#;276767676=4'.'&'&#+"'.=4676;2E(:((:($=X==X= %" #%%#  #%!"63%*.3%((:((,==X==B 1  "% %"  #$%#T3%!!--!!- !2#!"&546!!'#5!3!26Mf  Y4Mf4     3ͳf  3#3#73#3#!!3ggfgg?7M4gge 22+"&=4&/&'&54>53++"&5#"&'B'   f   'B&  3  &B'    'B&j   "73#7"264&5#3547>354'&'&@MM&'LL*M!<3~&&+1 %)26?C7!2654&#!"2"&46!!52"&46!!52"&46!!52"&46!!53  f = W4 W4 W4 W   f 33f33g33f33 %7>54&"72"&467'57M&5% 2>4."8^77^p^77^8#;"";F;"";7^p^77^p^7";F;"";F;"  %.!3'7'7'726'&/72"&463gMMf...M...M...' 3  ggM 3  4  3 f  =   '!3'54&#&+"276=7&3263gMMm M  ggM WU;  !'7'37'3g̀33MMfMM33g34MLLM43!3'3gMMggM  #'!353'355!355#'355!5#3gMMfffgMM3MMMML4#!3'5#3373/"&4627#5#53gMM3LM vMMggM癙4444L444M  $(,048<@!5#5#35#35#5#35#35#5#35#35#5#35#35#5#35#3g̴MM4MfM4MfM4MfM4MfM4ggMM33334 !353'355!5!5!5#3gMMfgMM3M333!3'54&+";2653gMM M  M L3ggML  L 3(;O#"++"&7'#'&'.76?>76#67654'&'.'6&'&'&7>9M  ,&:  !!  !  h2! 9 #343   *(n   7!5!!5!!5Mfff4444 7!5!5!5!5!3334 5!5!5!MMMMMM 7!5!5!5!5!Mfff3334 /54&"26732+"&46;5.54622654623**gI73   36J4&'&'"2>4.".4>2        &7_77_n_77_70Q00Q`Q00Q   $$   "' 7_n_77_n_70Q`Q00Q`Q0&;IR!#4&#"&#"!72>?6.#"54.#'"26?2"'654&'>462"&1"(    p ! e))9 #x%%"1      ):)Y%5#3'35#'735#7#35ffLffLffffLffLffLffffLffLffffL26?HP54&+";26'2"&4654&++"&=#"3!26'!54&"2674&"2627"&3 4  4 3 MDM4  M  &~&:N:M  M X4  U%32+"&=46;5#32+"&=46;5#32+"&=46;546;5#"&=46;2+32  f    f    f    f   L  L 33 L  L 33 L  L 33 L  L 3 ''7'77[[$[Z%[[%Z[[[[$[[%ZZ%[[ ''7'776[7Z[6[[6[[6Z7[[6[[6[[7'#7! 3'3M3f4<E267632&"632.#"#476767&#"67632&'&#">4&"26   *g!25!*/,/RD#(, #L   $1+& )A F@ZC=6)%25' # >&/.6?>"&4?64&"6?64&''&'&67676?@~0 ~~~  0,  1BBBB ?~0  @, ",2:7#3264&#!+#532+5327#3##535!533#3264&M.i$$_3&&Mf  3fffff4 *3<E7!654."7462"&462"&67671"&4462"&7462"&7462"&`@-7^p^7tN&%%'- }M8H7^88^7H ) L (LN  -   -9J27654'&#"#27654'&#"7"327654&4&#"3267"32623254.1  P   "#R9&&42+&9)'P55-A!!A- -8'&6?6767'&'776?67676''&76?>5  M  gq  :`  /p A   M f N  q.  BY  q)  A   M  ="6?4'&67632#&=674&1676?32>4.6(&' !37#    '>"+IE(5 P!,+" 0"{'2,$ *FSC& )-15!5!5#%&#"26757&#"26=4&5#5#( * gg33f33g443u)Y)33f33 "&5!5!5#732+"&=467'5#5#gg  XUUggg33f33g444  43M33f33"676.5&'&'&7676.76&%2?3276?'\O.O y=:6EN/A O.O   a }O.Ou`02 >EN3F O/R# b    .>535#5##3)QllQQllFggLgg(llQQllQgLggLg ##5#53534444 ##5#5353MMMMM;%'&4632>54&"264.264/.>676&Ri   .B.i#"YXD"ii0BA! i   /.Ci !CZY!iiBA0 \% 4}7C#"767>;'&+"#76;2#!26?6&+54&+"#"%#7676;2fR ( T tf7  + R aq ,=p:  di < #  % $ g15.5462264&"f+! !+264&"3276?z"11" ."!!0!R S 0E1%'"/"" S S #'+/%#3#3'#37#5!#";!5326=4&#535#53#533MMM33  33 Y4MMgg  fM  8"3'656&'"35.'>75+"&=46;5>232  ! EbOObM  (6(    $$ n '' UMMTTM  g '&&' $+3!354>32632!35471"54'354f";##;"3 -- M433#;" ";#33*#-S3 -#*3l"33" 5##537353'#5#'735gfM3M3gffL33338.3L38.33-6FO%4&"264&#"'#""&"32>=>462"&'"'&762776'"&462<<C GB6 & 0RbR0 (%*#!" 'a  n'% ":"":"  G,355#";#".4>̀*==**F**FMgfM4.".4>2'35?j==j~j==j?1R00RbR00R=j~j==j~j=g0RbR00RbR0445%"#4'723264&">54&"3267332656&'l %%5&#,A,<*. x(.-&5%% l' ,, 'x/+<- , !%34'&'&#234.#2264&"~O87\`oZMK,-OI}I'E7 - 3m^\57M,,ILYH{GM6E%, ,y'7H$lxH$k !!537535353!533533fg3f3gfgggff333MggMM 5#!5#5#!5#f4f͙ ).'&/&'&'.>64&"27#     ([!6HI 5J44J$c)    % !IH6K44K4$-R&'.'&#537>764&"26&>7>75673#'.     vD  "''" U&4&&4&     vD  !''! l    L{&&4&&R    L 5>75!57!3#̀:$0%[S3F+N3fL ,ENN3) '"%2"&547'"&4627&5462"'6s --@-pB--Ap-@--Aqq-@-- ;-@-; --@-;  ;!3'&'&'&'&'&'&'&52767$#.!6  @@   ~\C+  !%).3 !83'&'&'&'&'&'&'&5276737676765'&'&'#$#.!6  @@ #'(   ~\C+  !%).3  # #$  7#535#33#3#344gg6^6R44g4f444g 75!%53735;#'5#5#34433MgM3332+"&546#73  ff  f {,2'&#"1&54632'&#"1&546267'"&'  7Gu"bxb"u{    SD 8FF8 DSM!3!'LM #*14."2>%'>&'7"&4627.'677^p^77^p^7& `1 ` &1*` &1& `18^77^p^77^` &1P& `1**& `1?` &1 0B"2>4.'."'46767"#3'.&'&76'&'&.6767_77_n_77_( )^, 2g/ .j5  :y40HC3 ;IS6 7_n_77_n_7    /   5! 7'7/'7'7MiiM=4&WXAB' &BB  BB& ' D276527652765276='!35335&'&'&5"&'&5"&'&5....MfMf //                 !7'7'?M͡,,$11$Md1$+.!73%#?'73>'5'3J@d&H>(25S,.,MMNAv.$Mg9M  %535#5##3!#3#3#3!!h^^,__ H'].]].]5b!b!bh  #33535#5!!!#3#3#3^^,__ '].]].]5hb!b!b  #/75'7'!%#5'#5'#3753753''7'77!! PT'SP(PR'RP !! F!5B..h<;;+PS'SQ'PR(RP  %#5##3353!#37#37#3!!bJ$JJ$J 5JJ"JJ5bbbbb  33535#5##!%35#35#!!#3J$JJ$J 5˄[JJ"JJ5Bbbbb  #%'7''7!'#'35#735!3#3#!PQ'RP'RT'TP` !-. 5 !PR'RQ&RT'TQ~5!b!bb!b!b!2#!"&546!3f4  $  f 4 3'%264&"L+ͳf++  #'!5!#5#5!!5#5!#5#5!#53#53#5̳fg3fffffMMMMf3333M!2+5#"&=46!!!!#3f4/4M334 !#537#535#535#53Mf34333 !5!5!#5#5!#5!5fgf33f3333g3333f33"7"'1.?64&+"&5471676;#%#53  M 36N 333 F   t  !21;2+53>7>3#F  M 6N33 FVT  t  "4Q_5&%7>&'776&/&326'/.?>323!52645;26=546;+"&&~'# #  ##  fI     ]I''HH('I` F ` F FaF` ML*N f  -f H1 <BJQiy1&%7>&'76.6'#&176/&726/>67.76?'"'&'3!52645265'3'72&#647.77?7#"&~'%OM%OM3"   ' .`  q6 %* U5fm7&'3' I=+Hs4sRQ  #/0 # ?6M E3ffK277#     $132!546;>23."!+"&'3M  M%.%bMk    X   337375#5#5!#3'#3ER..K#@g8O.@$$g$$C));33Cddd%#"=3264&+54&"3265.d!!!-: ! M-66 !!0#"'327.'327.=.47&54632676 :@RNB A30  !* #e:7'$   @<@%**($4"  )2,4 '7"#5532+32>4.3*==**F**FMgfM'2"&46476?'&'1'&7671'&'&>i~i>>i~i> ,2,,2,"  %  "?i>>i~i>>i  y 7>'8D"#$(#j54 /2"&46476?'&'1'&7671'&'& ,2,,2,"  %  "  y 7>'8D"#$(#j54 +54&"#46232#!"&=463'>54&"3*3327.#"#?3#"&'32>73>(.+F(,L25YZZ; <(.+F(,L25&33(F+gg3g'21 (F+#23'3.#"'>".'#7#3267-L26ZZ< >(0+F,M26ZZ< >(0+F(G+ff'22 (G+ff'22 75#7#5#!5#MM4444͚+4A%4&#!"3!26'!!!2#3#3#!"&5464&"26'"&5467  f f    7'&'62"&4"&'672>=4&')EG:+")@>:)  ;i!/I/90 I/!i :9*!6 : (  @ 92B'1/$B29 2".4>7#64&"28^77^p^77^U L 8 $#7^p^77^p^7V  5#5##!5357##5#53533M433MM3333333!2+5#"&=46'7''73M@@@@@@@@@@@@@@@@ '#'%%"264&7&#".#"67 3 &   1QQ1 L$gg  9&.0''0.&#+%4&#!"3!26'2"&'>4&"263!5353  f +O OVO O^**3MM̚  ($%((%$(L+ (,09=AJN%4&#!"3!26!!7353353352"&46;#73#'2"&46;#7352"&46;#   MMMM ,ff ,ffM ,fffM  >gM333333  M  333   !!7627'$n.$$n.%6@.7327>&#'&'&'&'476;2767>am_2L45<2/1S ?*  ) n/1:am/Mam >' !   AMSY4."2>'7>&##'>32&1'2?>&#"'1&305676'.547#"'EvvEEuvEWe;,P   N &!=4:FB"#EvEEvuEEvD /8   '7W '2;?jpC2*  MW]c4."2>2".4>'726&#+>32&1'2?26&#"/"3?676'%.54#"'EuuEEuuE?i>>i~i>>i N Z5'H   EpC7a3?; FuEEuuEEu,>i~i>>i~i> *2  #1N ,n_d<.O %&+"3;2?6'&+";26/;)@: @: @AT ;Rq En p rs "2>4.#'778^77^p^77^H"S"B"7^p^77^p^7t >#'7|""S"Bt =&'&'&"7276765455-$QP 5-$QPx =v=9?;M     " - +6 a t      V &6dashiconsRegulardashiconsdashiconsVersion 1.0dashiconsGenerated by svg2ttf from Fontello project.http://fontello.comdashiconsRegulardashiconsdashiconsVersion 1.0dashiconsGenerated by svg2ttf from Fontello project.http://fontello.comT      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUadmin-appearanceadmin-collapseadmin-commentsadmin-customizer admin-generic admin-home admin-links admin-mediaadmin-multisite admin-network admin-page admin-plugins admin-postadmin-settingsadmin-site-altadmin-site-alt2admin-site-alt3 admin-site admin-tools admin-usersairplanealbum align-centeralign-full-width align-left align-nonealign-pull-leftalign-pull-right align-right align-wideamazon analyticsarchivearrow-down-altarrow-down-alt2 arrow-downarrow-left-altarrow-left-alt2 arrow-leftarrow-right-altarrow-right-alt2 arrow-right arrow-up-alt arrow-up-alt2arrow-up-duplicatearrow-upartawardsbackupbankbeerbell block-defaultbook-altbookbuddicons-activitybuddicons-bbpress-logobuddicons-buddypress-logobuddicons-communitybuddicons-forumsbuddicons-friendsbuddicons-groups buddicons-pmbuddicons-repliesbuddicons-topicsbuddicons-trackingbuilding businessmanbusinessperson businesswomanbutton calculator calendar-altcalendar camera-altcameracarcarrotcartcategory chart-area chart-bar chart-line chart-pie clipboardclock cloud-saved cloud-uploadcloudcode-standardscoffee color-pickercolumns controls-backcontrols-forwardcontrols-pause controls-playcontrols-repeatcontrols-skipbackcontrols-skipforwardcontrols-volumeoffcontrols-volumeon cover-image dashboard database-adddatabase-exportdatabase-importdatabase-remove database-viewdatabasedesktopdismissdownload drumstick edit-large edit-pageediteditor-aligncentereditor-alignlefteditor-alignright editor-bold editor-breakeditor-code-duplicateeditor-contracteditor-customchar editor-expand editor-help editor-indenteditor-insertmore editor-italiceditor-justifyeditor-kitchensink editor-ltr editor-ol-rtl editor-oleditor-outdenteditor-paragrapheditor-paste-texteditor-paste-word editor-quoteeditor-removeformatting editor-rtleditor-spellcheckeditor-strikethrough editor-tableeditor-textcolor editor-uleditor-underline editor-unlink editor-videoellipsis email-alt email-alt2email embed-audio embed-generic embed-photo embed-post embed-video excerpt-viewexitexternal facebook-altfacebookfeedbackfilterflagfood format-aside format-audio format-chatformat-gallery format-image format-quote format-status format-videoformsfullscreen-altfullscreen-exit-altgamesgoogle grid-viewgroupshammerheadinghearthidden hourglasshtmlid-altid image-crop image-filterimage-flip-horizontalimage-flip-verticalimage-rotate-leftimage-rotate-right image-rotate images-alt images-alt2 index-card info-outlineinfo insert-after insert-beforeinsert instagramlaptoplayout leftright lightbulblinkedin list-view location-altlocationlock-duplicatemarker media-archive media-audio media-code media-defaultmedia-documentmedia-interactivemedia-spreadsheet media-text media-video megaphonemenu-alt menu-alt2 menu-alt3menu microphonemigrateminus money-altmoneymovenametag networkingno-altno open-folderpalmtree paperclippdf performancepetsphone pinterestplaylist-audioplaylist-videoplugins-checkedplus-alt plus-alt2pluspodio portfolio post-status pressthisprinterprivacyproducts randomizeredditredoremoverest-apirsssavedschedule screenoptionssearch share-alt share-alt2share shield-altshield shortcodeslides smartphonesmileysortsosspotify star-empty star-filled star-halfstickystore superhero-alt superherotable-col-aftertable-col-beforetable-col-deletetable-row-aftertable-row-beforetable-row-deletetablettagtagcloud testimonial text-pagetext thumbs-down thumbs-up tickets-altticketstide translationtrashtwitch twitter-alttwitterundouniversal-access-altuniversal-accessunlock update-altupdateuploadvault video-alt video-alt2 video-alt3 visibilitywarningwelcome-add-pagewelcome-commentswelcome-learn-morewelcome-view-sitewelcome-widgets-menuswelcome-write-blogwhatsapp wordpress-alt wordpressxingyes-altyesyoutubedashicons.svg000064400000363306150211053000007236 0ustar00admin-appearanceadmin-collapseadmin-commentsadmin-customizeradmin-genericadmin-homeadmin-linksadmin-mediaadmin-multisiteadmin-networkadmin-pageadmin-pluginsadmin-postadmin-settingsadmin-site-altadmin-site-alt2admin-site-alt3admin-siteadmin-toolsadmin-usersairplanealbumalign-centeralign-full-widthalign-leftalign-nonealign-pull-leftalign-pull-rightalign-rightalign-wideamazonanalyticsarchivearrow-down-altarrow-down-alt2arrow-downarrow-left-altarrow-left-alt2arrow-leftarrow-right-altarrow-right-alt2arrow-rightarrow-up-altarrow-up-alt2arrow-up-duplicatearrow-upartawardsbackupbankbeerbellblock-defaultbook-altbookbuddicons-activitybuddicons-communitybuddicons-forumsbuddicons-friendsbuddicons-groupsbuddicons-pmbuddicons-repliesbuddicons-topicsbuddicons-trackingbuildingbusinessmanbusinesspersonbusinesswomanbuttoncalculatorcalendar-altcalendarcamera-altcameracarcarrotcartcategorychart-areachart-barchart-linechart-pieclipboardclockcloud-savedcloud-uploadcloudcode-standardscoffeecolor-pickercolumnscontrols-backcontrols-forwardcontrols-pausecontrols-playcontrols-repeatcontrols-skipbackcontrols-skipforwardcontrols-volumeoffcontrols-volumeoncover-imagedashboarddatabase-adddatabase-exportdatabase-importdatabase-removedatabase-viewdatabasedesktopdismissdownloaddrumstickedit-largeedit-pageediteditor-aligncentereditor-alignlefteditor-alignrighteditor-boldeditor-breakeditor-code-duplicateeditor-codeeditor-contracteditor-customchareditor-expandeditor-helpeditor-indenteditor-insertmoreeditor-italiceditor-justifyeditor-kitchensinkeditor-ltreditor-ol-rtleditor-oleditor-outdenteditor-paragrapheditor-paste-texteditor-paste-wordeditor-quoteeditor-removeformattingeditor-rtleditor-spellcheckeditor-strikethrougheditor-tableeditor-textcoloreditor-uleditor-underlineeditor-unlinkeditor-videoellipsisemail-altemail-alt2emailembed-audioembed-genericembed-photoembed-postembed-videoexcerpt-viewexitexternalfacebook-altfacebookfeedbackfilterflagfoodformat-asideformat-audioformat-chatformat-galleryformat-imageformat-quoteformat-statusformat-videoformsfullscreen-altfullscreen-exit-altgamesgooglegoogleplusgrid-viewgroupshammerheadinghearthiddenhourglasshtmlid-altidimage-cropimage-filterimage-flip-horizontalimage-flip-verticalimage-rotate-leftimage-rotate-rightimage-rotateimages-altimages-alt2index-cardinfo-outlineinfoinsert-afterinsert-beforeinsertinstagramlaptoplayoutleftrightlightbulblinkedinlist-viewlocation-altlocationlock-duplicatelockmarkermedia-archivemedia-audiomedia-codemedia-defaultmedia-documentmedia-interactivemedia-spreadsheetmedia-textmedia-videomegaphonemenu-altmenu-alt2menu-alt3menumicrophonemigrateminusmoney-altmoneymovenametagnetworkingno-altnoopen-folderpalmtreepaperclippdfperformancepetsphonepinterestplaylist-audioplaylist-videoplugins-checkedplus-altplus-alt2pluspodioportfoliopost-statuspressthisprinterprivacyproductsrandomizeredditredoremoverest-apirsssavedschedulescreenoptionssearchshare-altshare-alt2shareshield-altshieldshortcodeslidessmartphonesmileysortsosspotifystar-emptystar-filledstar-halfstickystoresuperhero-altsuperherotable-col-aftertable-col-beforetable-col-deletetable-row-aftertable-row-beforetable-row-deletetablettagtagcloudtestimonialtext-pagetextthumbs-downthumbs-uptickets-altticketstidetranslationtrashtwitchtwitter-alttwitterundouniversal-access-altuniversal-accessunlockupdate-altupdateuploadvaultvideo-altvideo-alt2video-alt3visibilitywarningwelcome-add-pagewelcome-commentswelcome-learn-morewelcome-view-sitewelcome-widgets-menuswelcome-write-blogwhatsappwordpress-altwordpressxingyes-altyesyoutubeclass-wp-font-face-resolver.php000064400000013024150211053000012470 0ustar00 array( 'fontFamilies' => array( 'theme' => $fonts, ), ), ); return static::parse_settings( $settings ); } /** * Parse theme.json settings to extract font definitions with variations grouped by font-family. * * @since 6.4.0 * * @param array $settings Font settings to parse. * @return array Returns an array of fonts, grouped by font-family. */ private static function parse_settings( array $settings ) { $fonts = array(); foreach ( $settings['typography']['fontFamilies'] as $font_families ) { foreach ( $font_families as $definition ) { // Skip if "fontFace" is not defined, meaning there are no variations. if ( empty( $definition['fontFace'] ) ) { continue; } // Skip if "fontFamily" is not defined. if ( empty( $definition['fontFamily'] ) ) { continue; } $font_family_name = static::maybe_parse_name_from_comma_separated_list( $definition['fontFamily'] ); // Skip if no font family is defined. if ( empty( $font_family_name ) ) { continue; } $fonts[] = static::convert_font_face_properties( $definition['fontFace'], $font_family_name ); } } return $fonts; } /** * Parse font-family name from comma-separated lists. * * If the given `fontFamily` is a comma-separated lists (example: "Inter, sans-serif" ), * parse and return the fist font from the list. * * @since 6.4.0 * * @param string $font_family Font family `fontFamily' to parse. * @return string Font-family name. */ private static function maybe_parse_name_from_comma_separated_list( $font_family ) { if ( str_contains( $font_family, ',' ) ) { $font_family = explode( ',', $font_family )[0]; } return trim( $font_family, "\"'" ); } /** * Converts font-face properties from theme.json format. * * @since 6.4.0 * * @param array $font_face_definition The font-face definitions to convert. * @param string $font_family_property The value to store in the font-face font-family property. * @return array Converted font-face properties. */ private static function convert_font_face_properties( array $font_face_definition, $font_family_property ) { $converted_font_faces = array(); foreach ( $font_face_definition as $font_face ) { // Add the font-family property to the font-face. $font_face['font-family'] = $font_family_property; // Converts the "file:./" src placeholder into a theme font file URI. if ( ! empty( $font_face['src'] ) ) { $font_face['src'] = static::to_theme_file_uri( (array) $font_face['src'] ); } // Convert camelCase properties into kebab-case. $font_face = static::to_kebab_case( $font_face ); $converted_font_faces[] = $font_face; } return $converted_font_faces; } /** * Converts each 'file:./' placeholder into a URI to the font file in the theme. * * The 'file:./' is specified in the theme's `theme.json` as a placeholder to be * replaced with the URI to the font file's location in the theme. When a "src" * beings with this placeholder, it is replaced, converting the src into a URI. * * @since 6.4.0 * * @param array $src An array of font file sources to process. * @return array An array of font file src URI(s). */ private static function to_theme_file_uri( array $src ) { $placeholder = 'file:./'; foreach ( $src as $src_key => $src_url ) { // Skip if the src doesn't start with the placeholder, as there's nothing to replace. if ( ! str_starts_with( $src_url, $placeholder ) ) { continue; } $src_file = str_replace( $placeholder, '', $src_url ); $src[ $src_key ] = get_theme_file_uri( $src_file ); } return $src; } /** * Converts all first dimension keys into kebab-case. * * @since 6.4.0 * * @param array $data The array to process. * @return array Data with first dimension keys converted into kebab-case. */ private static function to_kebab_case( array $data ) { foreach ( $data as $key => $value ) { $kebab_case = _wp_to_kebab_case( $key ); $data[ $kebab_case ] = $value; if ( $kebab_case !== $key ) { unset( $data[ $key ] ); } } return $data; } } dashicons.woff000064400000063014150211053000007371 0ustar00wOFFf FFTMDrL"GDEF` 3OS/2@`icmapA@gaspglyf Ylhead\.6 hhea],$hmtx]H@r loca^Pvmaxp`` Yname`V/*vpostb F?webffV=c-xc`d``b `b`d`dd,`9xc`f?8Ue4ʹ)Ja~ _bDR6 xݐKA璨7 Ł$4$"Hhb!] ;[E;F j6y$`aoyÃ` ɀ;Xq9e!A&A6 K#S@SL5ڠh_YVU^jVվ늩S3u0-s`86((@i&1}rUN[Km*SAntCS6K]i9d~Ns( ?_oqK88Ξtvmg]媬ɪ\rN#ĵLNV?TX6ytxڬ |U8\;[[t,7u=l! K/FMnQAPE7D\F"aFmD&CqduFs I_N:̛t[Un'rGNݜIKW]o{*-dcX3LhCg<3G*_ziH(LLf+1[`HCdP@L9%Y0 Ca>x0ְ;geM+ݺ6HieŒ7ji?Ref6Ow[ʳ$-tK^plfeKʕͺU#X!^.*5j. ^m2 R)!:G;iu(MB*׶ƚ[4rzm+ݺ^[ u|"}}1ѐO$ЭIM{66,$;|[FU,o`=zwTKN47Wȵ\6^Sdi$A]%MÎ%H)(%l$abf7oeDjiill|q"}RzUda -&dOнW)MMHXrWk[?7*[c߰Mr;y3Yny45r Gib#Dw]vJ&:U R/u, :;th+~z~#uu©Xn;zp%<}N.+5 X|Twr #T^Jd?0'QO:&;$h. 8p'?K85gq֋!"g] =n#iPX@_"͹=Yo_WONU[Zv-nnbbGn':wJYincw-=;'(`'gt 3 \ivδ-& gCI0/^2{!ޅײvEBy*WΔDDQvVu0 5} !OhR }oUd⏷#}Fi/5dLWWgMPhnڠ5Xp ;=N6?Bk6-^,R&3gWTb9\ +ݪj?4 Ayř3zX= NY3(rY!Oʌ0tH1Wr~C۷:37_x|G^AOsŖCmmWK#U@uqz 5,vo bcB yEߔA8`;LiOQ݈ % Gc `H\:Fڃ\B+ֺ7=HVri;li `0AOpΆOsCD;IlL5<ugԑӑhhie\ϾK>vpTIi;} " b6w&E]r/&սG?[MȊvʲäQ4w8&9Ϋ`y( h70<ɑ~\òo\UUʛ2?{ {)FKymkۊ'9ִ}H_"~82.!>ڣmb% /1\0dJ+^vߞW(`Q wA(\F$Nq1)9`lg_&^d';VRzxgo g}$}/Cwq#(Kl3Hi~8HH{i B9/76?rHg g9'::c=d)'tf)CX AMeHV<5(E]uG@soq’-pɗ"v[OE^>oj4D$<^$z'.pe8Y^=ߐ3zgW :k$@Z7 "\g''^F_Fmۉl8H1!@e#lqe .CM&8i4Q0`Bn׷9Z8E͡g_w݋#4W+~KOQ/J<~=xvg`\zj#\@ۑ=zȼ!p|laYNl$t AF̓[?o aKbC&籙ux$އ& o - &^mǩjKQGNBFOĚ?EP(MڦL!5’"hf^/mh(=]2bZiCwC4C}ƫ-`an!DHϲ{ +&ˑ&ו:JZhQړ\ri5HKr X%֫KA$PfFxD Hɳgt%2@\w%51*XK\J<m eG;O_E"?18v~eYyŌrtݍf`&NYLŚ9#1PCE~m]INӐlI4Oos3+ޭ4M8tPyx$0VH,<{4évcmX+C |1CHFa?w$R(i*ӋL *ǽˮAh'Q w݈gsT-QdNȟFH/cSc4R  c5T0*h?@ 0 sQrr:Dcr t/ Ǎ?ƨK'oB!y:㫿7 Hs-n?/gJ^MxV7nu`~>PHEtg#\}w:1?L>LLJh77ӵl\"@d3 :Qn30](Huu"d A\G|ֆFI;.B3=QЈ=:o:=-;vtc+`o{k煢!)x:nEQ`C$CE 1/" ܮq"8`C80A|ڟ}{]J-*x䏯]6T4Q|Y'(qelP9Aqp(&U+i~ͿJE:[UsK 8)rQ?]7VaRؙ3)?sFmNy8_%v?7>^GG[Snz}6RE'w|FGc&khGp Ty NxB0=L 51d;M@ҞMpy,5߽:;ҀAC$ b Dꖎp^n,Y-&~2t,OrzܙS%3=n,eM6ՑKuaEX`r8&0Uٽ|-;p7_FHcѢE/"Rt}IʳUH5U 6a[/0!bby0H;c!&)=j:~$Ԭ؉5ǀp(`(ITTK:T-Kp> MK7sSu!nǡͼ`t.H63#@=θ5589ISc|̸|!sEMVňċ(C$7\g@r]V/ŃF.AqL?H;S;ҥ0nݗDcO4ҥDRyG\1LU.ѯH(2wx\j\ͩ)8/mt8d_ Kzu},Z6l]Y?Ȃg6Ohhw_Ĥɱ㧌f"#]*x.-'C>7>z±Ha!$&zq8PwF5HG: >oV4(", 0y<;iKs˙J6"1څ#bx=q͈Y⡖٥бp^9gd5n=Fo`3CۨkӲx oXQQﰘt9Ƽl1ۜ.i qR(Oo0z+ |f$ϚW<47(|db+%w4hU_k6a4sPfҫ"E'9EY\^="-bjrx^W-`')} f`ĠҀH(k(=l|ꦛtX[>Mp W?pĀ=J55whl롏'沉A۹ܿhIp'{q?& UkK~ I:Os8\![)ƌ+REփ:r^(BrFd'drss(۸9( r+&LXJ'8_ȧ qȁ-:`@Eb01Ttf1p[gX[yaYEeUKN,;c,6̚?:?XpӔ -:ɠYUkȖM6[Ax @+jRwZ7ri}S4`S {[4Mr:g /l3}ٱŲEC(n"^72Pֻd]1yD= 2s1 bHǷm޸ M/m"DU]$6I&ڼ>ߑ|߀Aw(:ud>A1.Dр!<-̱f9t$` L*_8C |Z({JB\J ȑ.a2ޛm`0ڛm1L<"?//oPB:ȗa%\˨z|mee Ef[Q][Y?f]٨88Cv ̾8m%>E(Vm̀IL:}ze%1Q!6B{Fidj|}?.=.~Pn9) J'GYɬ%&>Uggyr֑_^^Ro+dYN;ydbJyYo#FΞ-vN;41{jzZjwddb02. =$h%,z4gWg/U] W3ߒio{>TH,Z;$j55Dde>n?{Pve:ifsiMߎ (.@M;./?aG=N)C~9ۛ7aNVgtP;SoF# i oLUH5qD:Y:5}\A d*zaGoBE-Avy({EoWf7cQt'"ӄ-':@kStG;tմݨx׉|by'v2~w@teSMj2X4|M"tL ,"+|MvCu?\G}!9? !*)T7C~TCŕyr}Rd.@%owrv`rYJOΛʲ 1\WMG\phmO&Wĥ]%EÚqm\}dKc{)[kF/%匃x!lQT 3yE`dh" :eD"B'7͹5?F3"q` 3w.|tU]6TֶN[+I25kc30L/j454-!9ʴeh#fV KBBӡ N)G)w(!+;*d'3U .$e5&fgY 3: bV\!]+?8lu(/E x*vƀWonVD?GOv+xl~ .k眺\k[{;ECھChkXg09bV \ $Gsf6+xDAcL0/\ǵa !Gk4:N.̂Bv dH!ɽnyDy W3>I$I<"}ŽyVl؋9bvk,%Ufї/AXhRu#TŞUNc-)TPts oa;J^H^ $_V ̿F]o Ge9&PF? ݬ2Ynެ Qݼ*w=ikL ^^<t*بiFkhSxzLp7OIT?vTRyeD'/"PL0Sr\&)̀4,' 06 T$9(/:M{"躗kEUL1&r)uK-'im'G;oTN}SU*;e;?"st*R# Yji 9HOx͌V>23xrTl|3~|KbݟB8/qH.~slI!û<@}rD_;AtGIeڶiSצG.r!q{=vͷM?kaz}ۮ9c3Lgn^nfY T/]\tтG_=b-~Aw \N?ǻyg~w;]>f:;Y|oOogş \d]띗tO[Bz}AM9Yy)U^l,DNZl=4(!G4[5f[Q_ij_hSNǗׇRk-,%t>q钔1;fUW\uֹI˝92/퓭ŕ0.z☑I#Sc7e~bݷHkIzlqsZ ,LTtdP1`!T*`И ʋhR:ڹ ,G2;!\Qh@$`fBHY%7~"aRJ",L9rdɭK/d֓[D]©~w=*)ˢ[hwk(9pQg4ɉ$Mumb7̯ G& ~&EQC>b 9 ɍoю_o" #O=u."\}4Mm=u\V'; o>mM\u"q/̭d}q &$n`^գj2B,qy>6{df4V %rNyDNKQE u7AȐӻw&hYjblڌnw9윬Nh{w+2jH{wȠ&ܽ?ݭ~O S986+vH "5VŮ58Ɉ dG=Hg/Ҁ3_>\頏Ӊ.T EuKCRPQJ DUO7)` fz& Dt_?2  ٢!ܠaqQ({9 r dU#gUɼ,=aXUؑv۱#?nyl\G$A a۬&oj~K$Ceio fO>?*C#Nf{9Y|(?9_&;&;1)Օ :(92g"L.ernTPe.PЋ൐Fe܄;7 `bU-w̽~Iz*6!a.} ՚lJϷNn$*Ixi wJ kR0W'M['+Flk^]=<㶧rmѭNQnJسhIBA2"FɤbwZwV:Ħ?F|WgllO{׻;.*nM;,g<ͭ (`Y >9&?CQK C!gf+gK0zqQg zu-5Q#0#D]9d~^N dKhl~[y &P)5E{Cq# uFjA덮UWGWVTY I'ש| Cz!tvP@Sie>>;:y?~ m!ɚ}a҇˕Oas?7֕DbߙEht/rsA %3I:3t*]a2YͣLt,KN$''۔!k;-ruUU ^v o{ic^ *E`\q>VYu/Oq۝0й&hw;]|{ 9:iiij:7EzvK#Ӟ+G ֎p3w{Uf'DELpgI]јPG:oto*RNJ;WG,Vb%:V2{g{93P_ T'95bNDV#QvU 3 Rl3H>뙍^/G6] PˡCP&!5FQrd@;*UBECpCT)t2fQm?ܑT)cr]EReᎤJ*I|'܍(8._w<.}TA>_G,B>Ć{`'AϠ\D S!$.GH#6'CK,AHfRQ z9"#@_E?Lk\?ǪE[wص\8ݳ7b~6*Wg==ͫNOɯm{~CG\1ԕΩjcF6>UEຯ[kV=֯ T||,rE}Q1|ryyz) X A~(0}xI"k #2zqIiL[+fİO8}UU0@[WG\3hK, UY*HGb"` %d) @7Y.E]Yf7lA#.G![vWQ0űDIsHQ=v84OvTFvP@]Y#c{h_L|㝮cK,/N\#6t_ (%sj>l +B?OWzʟvO=E'{)2ڳ˟_I&椄9558|ЋùQ8n"7 .J>Pl.:瘄 61 ˝>V]_ mag6Ũ ȣG*ól9).\?as~Fd[x#$1+o%E>U3p\U2r`ӛ"_)sMcGuWWk>ӛ}ke=fڛ{nwf^xXmMM ճs)O4KO}5cqԄ}TƂI X" ,Y@ҒסoDD+ J 'ښޚA,&ۤ '}˭o-zVoukA+4hq%_hb5M'dE,+uS޶ϝc%W5O8-Hw x~γٗ cЛɚ?e*NЃE:~^kϏZECO'v]KK )U)ΉecX]BԤja!ڕdAZ݅?y,!Q0ό ;쮤0]|~^zfϬ==k7:ztהz$ڭzgC?$y7Q߳gϬݻ/}G$ cVNUYfȪfr ,CjTBH٫GT.{1|oRځbuA4=o}ym&;GҟFƋ`TOz|2I!.\IE Dz%t%_<_|9Wd蛱/1?_"vT.bUpaVB~ a"0:B+1`{#f!(5=gu5vlɵ@CktѲxk*c+c 5$(h ހ WnN+edKA }H'@ƐKe)颶(ķxЉw^xON21W5FoV@&Wd;ETMTRsv2"*hk@9Ȫ$fY7[,iR5T~-*?͙c.\8N'/w;+yWZk}SnFlֽo?WCdW[I WtB9`Hu޸ZWFoQexV9 &p|\jR7W2-kj;^˹MQBD`cux+/N17x; `g)Mc&Ѫ}w"(Ð8@dE "IMѾCx-ڃZxLbBr(9bf;N6f)3p D9rQNh@k  oh8u,:,oh_xS`Jw+YY]^% '0} KA S`/P]­6p[λzY `dEvfD+ z 2#h}2)2k4#CrV:/h%:vq,*}bR$& )M?f~Ʒ֭{~KO}kݕ%W7ZP?8鶀ak?˵\lg >t])'S%|'"%7!XS:]nzYW]YWC5V`;Yz/[16i/5 [*BSߡIZjwu\DI"Cxk>!*|L1*ϴ5"]73Eߊ+һocb2Nj֝;3DJR=@`}GٕHk8Wg<-`-gȿsL;Sqz< .洤\-3/~EozvKvcfZ.l.){\rg&s J(P?K'^uPkt֗+-ٮkz9a2w+Zմtzz~H].iˡ-LnnrOH 0 0Vr &3~hHl ΝZ"+d`H_N{?z5vhV0 0:,"h#YRd?RCė!y`2хv[L^k]0i1 :n^~8 {7z}*Lh5ƫ2569ETI@9cCЏ;reǪ *9!W Dz$g_{i>yb)coO%Ya+HjMKO=~'浮e@W\JH}]x$c'MڝOI>#߱-x3t r#o [HJUt i=J gi7Dդ\4⍤Q,+}hBT@EHH*ܵzBUB6ߑ-fUhZROa-mT!WI-Uq!6Y/=VQ D&N8Yx~ί?ȂwN/XHB2&-MMUЯK fy>p#́?f=GbZ_Զ'GYcI1Lʇ#X)Ld 24)3K7ctw: &BA &>6eW|mk2Xas6YfۘSkM)7ט%}n^eOZj'秩$)Em lÖD/^aG}?vsjڜS{ dԡ4!vF$'Qv%ٗzfHIㆮK fm-@byyWHXp4" Ff06?fGV=HC/JЏv E9Fq$NzX͌a$ɮDd@" 'lMiAD8h0h! =)%{Jܚi?[i/xJ7Ig0VbL)-!lv% ` VV~hCgp f,α4yM&WG#ՑHbzne2[e xDm!_~>zhˑc%9'1{G5qTx9+{>DY82#ߏ9(Z`P틣~4 rd~ˍE@b#R%6X"^O+:fyfg}}OX9NlizB=CqM9d!LFİnTą Dx@T<с_ɋmoxNwh3J2to,Жh3XDDx$5!.ԗ{xkB^S:i5@u^#5]xlᙆH|wQ[j4$MҤiӴMC[ZZ>ã/Be节պ 2*C[(uuUAgwvqGv(q97>ڛs?" Bt2_JNL@2&< j"h&#(f,$п4MpIah 5p@"\&9+IEehNWˑŤprm!yŒanTB&: iԻUR\BYM ͶrtBŌU3gEX67-I,ѩ%{0RPDW ]sEx^df.M `dZy6\ÛSe`gO8<'Q䵗R CN@%gGL ,/ M4I +i!F d7fj VSgi-iF%݈LΞ;m״7 魲a]uӼ&ənj0Iz?ɰxvk i3Lt ojYbi'5 sZifZ˨rT@F+>Nr4{ NS.g{Cƣk0|lBwAs 22<|I'\%>olQ1*@3V06M7:FDy9gdh5ٲ‚ȭXzq9攕9P4,;q~겱Wwjլ ڔKW( &#]r~fUMsm-v{Aa&NyCvI0O7ϫ-}1 )D? -AQ RpΌANA_;rFhxN+AoI\0+ \`^ݿ}Q[o([W=.rښk`Ԇ]GK-+6mK2Bc /^,;r3w=Bs64lKݵkUԬDMzH׵;],5::KjMU%fˮ]'&?M/ߕWps:fœO%cfђ&F @ ? J3?=%"yڥyŠzҽ|+8wy^tt;&Jc_ܲԑR[~=8 c*]ׇͿ <3,n鈮~Q670>eX<\ g1vy|OBZV9ь)Ӡgpv&axo6|羺ԁͻ i>0P~'N { jZhʔUNf0&3-#.ơI|z/|d;Zb60^xhvkwבpuS;Z=­j|!1j[8O\_3`4`ȲRJ$B?)5 ?tɾǛq\X|sWTnׂ J:2ZqL>}REl?H-\Xpp =ȿ=ft i4XbN,^_ Y,"9%EXOl"d1a4C]h7u^_=< FG ٗ!76tlڀGF3jzay8O]P̢[.aXȽt4u/'@ >3yr +PY.<gxm _?-ؖYP|10lGya @]{CJ{wx<h5o}_jWHSǢ T/X՜t/\qBm%\m4m,A6'r 6r{a;loĩ~855.Z0bD6Pv   " 0 > L , b , t J 4 d ^|2| Hb>Pz R N2B L&^2:j4j>vr  l !!!"$""#`#$V$$$%%@%%%%&'@'((*(@(Z(p(((())&)*H*++,--L--. ..\..//\/00T0001161X12v223 3344466J677J77828T899R9j99:<:t::;;f;<0b>>>>>??~??@P@AvAB&BdBCCbCCCD2D`DE EHE`EFF@xc`d``dc L@ `>xڍRNA=c,,,F5!*"h.2"0S`㙻!lc&3{{<F>684~5cHiC>c>S>sKk[{~G~g~W~wOoadww bQ91+3,f٘J^%WɫTr*9JN$9IN$9INdgg,'ɞϞ//~")/_<>'|.'|>jrj9ZN-x6r9FN#i '', 'fontStyle' => 'normal', 'fontWeight' => '400', 'fontStretch' => '100%', 'unicodeRange' => 'U+0-10FFFF', ); $settings = wp_parse_args( $settings, $defaults ); if ( function_exists( 'mb_strtolower' ) ) { $font_family = mb_strtolower( $settings['fontFamily'] ); } else { $font_family = strtolower( $settings['fontFamily'] ); } $font_style = strtolower( $settings['fontStyle'] ); $font_weight = strtolower( $settings['fontWeight'] ); $font_stretch = strtolower( $settings['fontStretch'] ); $unicode_range = strtoupper( $settings['unicodeRange'] ); // Convert weight keywords to numeric strings. $font_weight = str_replace( array( 'normal', 'bold' ), array( '400', '700' ), $font_weight ); // Convert stretch keywords to numeric strings. $font_stretch_map = array( 'ultra-condensed' => '50%', 'extra-condensed' => '62.5%', 'condensed' => '75%', 'semi-condensed' => '87.5%', 'normal' => '100%', 'semi-expanded' => '112.5%', 'expanded' => '125%', 'extra-expanded' => '150%', 'ultra-expanded' => '200%', ); $font_stretch = str_replace( array_keys( $font_stretch_map ), array_values( $font_stretch_map ), $font_stretch ); $slug_elements = array( $font_family, $font_style, $font_weight, $font_stretch, $unicode_range ); $slug_elements = array_map( function ( $elem ) { // Remove quotes to normalize font-family names, and ';' to use as a separator. $elem = trim( str_replace( array( '"', "'", ';' ), '', $elem ) ); // Normalize comma separated lists by removing whitespace in between items, // but keep whitespace within items (e.g. "Open Sans" and "OpenSans" are different fonts). // CSS spec for whitespace includes: U+000A LINE FEED, U+0009 CHARACTER TABULATION, or U+0020 SPACE, // which by default are all matched by \s in PHP. return preg_replace( '/,\s+/', ',', $elem ); }, $slug_elements ); return sanitize_text_field( implode( ';', $slug_elements ) ); } /** * Sanitizes a tree of data using a schema. * * The schema structure should mirror the data tree. Each value provided in the * schema should be a callable that will be applied to sanitize the corresponding * value in the data tree. Keys that are in the data tree, but not present in the * schema, will be removed in the sanitized data. Nested arrays are traversed recursively. * * @since 6.5.0 * * @access private * * @param array $tree The data to sanitize. * @param array $schema The schema used for sanitization. * @return array The sanitized data. */ public static function sanitize_from_schema( $tree, $schema ) { if ( ! is_array( $tree ) || ! is_array( $schema ) ) { return array(); } foreach ( $tree as $key => $value ) { // Remove keys not in the schema or with null/empty values. if ( ! array_key_exists( $key, $schema ) ) { unset( $tree[ $key ] ); continue; } $is_value_array = is_array( $value ); $is_schema_array = is_array( $schema[ $key ] ) && ! is_callable( $schema[ $key ] ); if ( $is_value_array && $is_schema_array ) { if ( wp_is_numeric_array( $value ) ) { // If indexed, process each item in the array. foreach ( $value as $item_key => $item_value ) { $tree[ $key ][ $item_key ] = isset( $schema[ $key ][0] ) && is_array( $schema[ $key ][0] ) ? self::sanitize_from_schema( $item_value, $schema[ $key ][0] ) : self::apply_sanitizer( $item_value, $schema[ $key ][0] ); } } else { // If it is an associative or indexed array, process as a single object. $tree[ $key ] = self::sanitize_from_schema( $value, $schema[ $key ] ); } } elseif ( ! $is_value_array && $is_schema_array ) { // If the value is not an array but the schema is, remove the key. unset( $tree[ $key ] ); } elseif ( ! $is_schema_array ) { // If the schema is not an array, apply the sanitizer to the value. $tree[ $key ] = self::apply_sanitizer( $value, $schema[ $key ] ); } // Remove keys with null/empty values. if ( empty( $tree[ $key ] ) ) { unset( $tree[ $key ] ); } } return $tree; } /** * Applies a sanitizer function to a value. * * @since 6.5.0 * * @param mixed $value The value to sanitize. * @param callable $sanitizer The sanitizer function to apply. * @return mixed The sanitized value. */ private static function apply_sanitizer( $value, $sanitizer ) { if ( null === $sanitizer ) { return $value; } return call_user_func( $sanitizer, $value ); } /** * Returns the expected mime-type values for font files, depending on PHP version. * * This is needed because font mime types vary by PHP version, so checking the PHP version * is necessary until a list of valid mime-types for each file extension can be provided to * the 'upload_mimes' filter. * * @since 6.5.0 * * @access private * * @return string[] A collection of mime types keyed by file extension. */ public static function get_allowed_font_mime_types() { $php_7_ttf_mime_type = PHP_VERSION_ID >= 70300 ? 'application/font-sfnt' : 'application/x-font-ttf'; return array( 'otf' => 'application/vnd.ms-opentype', 'ttf' => PHP_VERSION_ID >= 70400 ? 'font/sfnt' : $php_7_ttf_mime_type, 'woff' => PHP_VERSION_ID >= 80112 ? 'font/woff' : 'application/font-woff', 'woff2' => PHP_VERSION_ID >= 80112 ? 'font/woff2' : 'application/font-woff2', ); } } index.php000064400000000000150211053000006335 0ustar00class-wp-font-library.php000064400000006653150211053000011411 0ustar00is_collection_registered( $new_collection->slug ) ) { $error_message = sprintf( /* translators: %s: Font collection slug. */ __( 'Font collection with slug: "%s" is already registered.' ), $new_collection->slug ); _doing_it_wrong( __METHOD__, $error_message, '6.5.0' ); return new WP_Error( 'font_collection_registration_error', $error_message ); } $this->collections[ $new_collection->slug ] = $new_collection; return $new_collection; } /** * Unregisters a previously registered font collection. * * @since 6.5.0 * * @param string $slug Font collection slug. * @return bool True if the font collection was unregistered successfully and false otherwise. */ public function unregister_font_collection( string $slug ) { if ( ! $this->is_collection_registered( $slug ) ) { _doing_it_wrong( __METHOD__, /* translators: %s: Font collection slug. */ sprintf( __( 'Font collection "%s" not found.' ), $slug ), '6.5.0' ); return false; } unset( $this->collections[ $slug ] ); return true; } /** * Checks if a font collection is registered. * * @since 6.5.0 * * @param string $slug Font collection slug. * @return bool True if the font collection is registered and false otherwise. */ private function is_collection_registered( string $slug ) { return array_key_exists( $slug, $this->collections ); } /** * Gets all the font collections available. * * @since 6.5.0 * * @return array List of font collections. */ public function get_font_collections() { return $this->collections; } /** * Gets a font collection. * * @since 6.5.0 * * @param string $slug Font collection slug. * @return WP_Font_Collection|null Font collection object, or null if the font collection doesn't exist. */ public function get_font_collection( string $slug ) { if ( $this->is_collection_registered( $slug ) ) { return $this->collections[ $slug ]; } return null; } /** * Utility method to retrieve the main instance of the class. * * The instance will be created if it does not exist yet. * * @since 6.5.0 * * @return WP_Font_Library The main instance. */ public static function get_instance() { if ( null === self::$instance ) { self::$instance = new self(); } return self::$instance; } } class-wp-font-face.php000064400000024016150211053000010634 0ustar00 '', 'font-style' => 'normal', 'font-weight' => '400', 'font-display' => 'fallback', ); /** * Valid font-face property names. * * @since 6.4.0 * * @var string[] */ private $valid_font_face_properties = array( 'ascent-override', 'descent-override', 'font-display', 'font-family', 'font-stretch', 'font-style', 'font-weight', 'font-variant', 'font-feature-settings', 'font-variation-settings', 'line-gap-override', 'size-adjust', 'src', 'unicode-range', ); /** * Valid font-display values. * * @since 6.4.0 * * @var string[] */ private $valid_font_display = array( 'auto', 'block', 'fallback', 'swap', 'optional' ); /** * Array of font-face style tag's attribute(s) * where the key is the attribute name and the * value is its value. * * @since 6.4.0 * * @var string[] */ private $style_tag_attrs = array(); /** * Creates and initializes an instance of WP_Font_Face. * * @since 6.4.0 */ public function __construct() { if ( function_exists( 'is_admin' ) && ! is_admin() && function_exists( 'current_theme_supports' ) && ! current_theme_supports( 'html5', 'style' ) ) { $this->style_tag_attrs = array( 'type' => 'text/css' ); } } /** * Generates and prints the `@font-face` styles for the given fonts. * * @since 6.4.0 * * @param array[][] $fonts Optional. The font-families and their font variations. * See {@see wp_print_font_faces()} for the supported fields. * Default empty array. */ public function generate_and_print( array $fonts ) { $fonts = $this->validate_fonts( $fonts ); // Bail out if there are no fonts are given to process. if ( empty( $fonts ) ) { return; } $css = $this->get_css( $fonts ); /* * The font-face CSS is contained within and open a