PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i5h-3LL

HOME


5h-3LL 1.0
DIR: /srv/http/vyvoj.adent.cz/vyvoj/moodle_esf_vz/lib
/srv/http/vyvoj.adent.cz/vyvoj/moodle_esf_vz/lib/
Upload File:
Current File : /srv/http/vyvoj.adent.cz/vyvoj/moodle_esf_vz/lib/olson.php
<?php //$Id: olson.php,v 1.24 2006/08/22 20:10:54 stronk7 Exp $

/***
 *** olson_to_timezones ($filename)
 ***
 *** Parses the olson files for Zones and DST rules.
 *** It updates the Moodle database with the Zones/DST rules
 ***
 *** Returns true/false
 ***
 */
function olson_to_timezones ($filename) {

    $zones = olson_simple_zone_parser($filename);
    $rules = olson_simple_rule_parser($filename);

    $mdl_zones = array();

    /**
     *** To translate the combined Zone & Rule changes
     *** in the Olson files to the Moodle single ruleset
     *** format, we need to trasverse every year and see
     *** if either the Zone or the relevant Rule has a 
     *** change. It's yuck but it yields a rationalized
     *** set of data, which is arguably simpler.
     ***
     *** Also note that I am starting at the epoch (1970)
     *** because I don't think we'll see many events scheduled
     *** before that, anyway. 
     ***
     **/
    $maxyear = localtime(time(), true);
    $maxyear = $maxyear['tm_year'] + 1900 + 10;

    foreach ($zones as $zname => $zbyyear) { // loop over zones
        /**
         *** Loop over years, only adding a rule when zone or rule
         *** have changed. All loops preserver the last seen vars
         *** until there's an explicit decision to delete them
         *** 
         **/ 

        // clean the slate for a new zone
        $zone = NULL;
        $rule = NULL;
        
        //
        // Find the pre 1970 zone rule entries
        //
        for ($y = 1970 ; $y >= 0 ; $y--) {
            if (array_key_exists((string)$y, $zbyyear )) { // we have a zone entry for the year
                $zone = $zbyyear[$y];
                //print_object("Zone $zname pre1970 is in  $y\n");
                break; // Perl's last -- get outta here
            }
        }
        if (!empty($zone['rule']) && array_key_exists($zone['rule'], $rules)) {
            $rule = NULL;
            for ($y = 1970 ; $y > 0 ; $y--) {
                if (array_key_exists((string)$y, $rules[$zone['rule']] )) { // we have a rule entry for the year                    
                    $rule  =  $rules[$zone['rule']][$y];
                    //print_object("Rule $rule[name] pre1970 is $y\n");
                    break; // Perl's last -- get outta here
                }
                
            }  
            if (empty($rule)) {
                // Colombia and a few others refer to rules before they exist 
                // Perhaps we should comment out this warning... 
                // trigger_error("Cannot find rule in $zone[rule] <= 1970");
                $rule  = array();
            }
        } else {
            // no DST this year!
            $rule  = array();
        }
        
        // Prepare to insert the base 1970 zone+rule        
        if (!empty($rule) && array_key_exists($zone['rule'], $rules)) {
            // merge the two arrays into the moodle rule
            unset($rule['name']); // warning: $rule must NOT be a reference! 
            unset($rule['year']);
            $mdl_tz = array_merge($zone, $rule);

            //fix (de)activate_time (AT) field to be GMT
            $mdl_tz['dst_time'] = olson_parse_at($mdl_tz['dst_time'], 'set',   $mdl_tz['gmtoff']);
            $mdl_tz['std_time'] = olson_parse_at($mdl_tz['std_time'], 'reset', $mdl_tz['gmtoff']);
        } else {
            // just a simple zone
            $mdl_tz = $zone;
            // TODO: Add other default values here!
            $mdl_tz['dstoff'] = 0;
        }        

        // Fix the from year to 1970
        $mdl_tz['year'] = 1970;

        // add to the array
        $mdl_zones[] = $mdl_tz;
        //print_object("Zero entry for $zone[name] added");

        $lasttimezone = $mdl_tz;

        ///
        /// 1971 onwards
        /// 
        for ($y = 1971; $y < $maxyear ; $y++) {
            $changed = false;
            ///
            /// We create a "zonerule" entry if either zone or rule change...
            ///
            /// force $y to string to avoid PHP
            /// thinking of a positional array
            ///
            if (array_key_exists((string)$y, $zbyyear)) { // we have a zone entry for the year
                $changed = true;
                $zone    = $zbyyear[(string)$y];
            }
            if (!empty($zone['rule']) && array_key_exists($zone['rule'], $rules)) {                
                if (array_key_exists((string)$y, $rules[$zone['rule']])) {
                    $changed = true;
                    $rule    = $rules[$zone['rule']][(string)$y];
                }
            } else {
                $rule = array();
            }

            if ($changed) {
                //print_object("CHANGE YEAR $y Zone $zone[name] Rule $zone[rule]\n");
                if (!empty($rule)) {
                    // merge the two arrays into the moodle rule
                    unset($rule['name']); 
                    unset($rule['year']);
                    $mdl_tz = array_merge($zone, $rule);

                    // VERY IMPORTANT!!
                    $mdl_tz['year'] = $y;

                    //fix (de)activate_time (AT) field to be GMT
                    $mdl_tz['dst_time'] = olson_parse_at($mdl_tz['dst_time'], 'set',   $mdl_tz['gmtoff']);
                    $mdl_tz['std_time'] = olson_parse_at($mdl_tz['std_time'], 'reset', $mdl_tz['gmtoff']);
                } else {
                    // just a simple zone
                    $mdl_tz = $zone;
                } 

/*
if(isset($mdl_tz['dst_time']) && !strpos($mdl_tz['dst_time'], ':') || isset($mdl_tz['std_time']) &&  !strpos($mdl_tz['std_time'], ':')) {
    print_object($mdl_tz);
    print_object('---');
}
*/
                // This is the simplest way to make the != operator just below NOT take the year into account
                $lasttimezone['year'] = $mdl_tz['year'];

                // If not a duplicate, add and update $lasttimezone
                if($lasttimezone != $mdl_tz) {
                    $mdl_zones[] = $lasttimezone = $mdl_tz;
                }
            }
        } 
        
    }

    /* 
    if (function_exists('memory_get_usage')) {
        trigger_error("We are consuming this much memory: " . get_memory_usage());
    }
    */

/// Since Moodle 1.7, rule is tzrule in DB (reserved words problem), so change it here
/// after everything is calculated to be properly loaded to the timezone table.
/// Pre 1.7 users won't have the old rule if updating this from moodle.org but it
/// seems that such field isn't used at all by the rest of Moodle (at least I haven't 
/// found any use when looking for it).

    foreach($mdl_zones as $key=>$mdl_zone) {
        $mdl_zones[$key]['tzrule'] = $mdl_zones[$key]['rule'];
    }
    
    return $mdl_zones;
}


/***
 *** olson_simple_rule_parser($filename)
 ***
 *** Parses the olson files for DST rules.
 *** It's a simple implementation that simplifies some fields
 ***
 *** Returns a multidimensional array, or false on error
 ***
 */
function olson_simple_rule_parser ($filename) {

    $file = fopen($filename, 'r', 0); 

    if (empty($file)) {
        return false;
    }
    
    $rules = array();
    while ($line = fgets($file)) {
        // only pay attention to rules lines
        if(!preg_match('/^Rule\s/', $line)){
            continue;
        }
        $line = preg_replace('/\n$/', '',$line); // chomp
        $rule = preg_split('/\s+/', $line);
        list($discard,
             $name,
             $from,
             $to,
             $type,
             $in,
             $on,
             $at,
             $save,
             $letter) = $rule;

        $srs = ($save === '0') ? 'reset' : 'set';

        if($to == 'only') {
            $to = $from;
        }
        else if($to == 'max') {
            $to = date('Y');
        }

        for($i = $from; $i <= $to; ++$i) {
            $rules[$name][$i][$srs] = $rule;
        }

    }

    fclose($file);

    $months = array('jan' =>  1, 'feb' =>  2, 
                    'mar' =>  3, 'apr' =>  4, 
                    'may' =>  5, 'jun' =>  6,
                    'jul' =>  7, 'aug' =>  8, 
                    'sep' =>  9, 'oct' => 10, 
                    'nov' => 11, 'dec' => 12);


    // now reformat it a bit to match Moodle's DST table
    $moodle_rules = array();
    foreach ($rules as $rule => $rulesbyyear) {
        foreach ($rulesbyyear as $year => $rulesthisyear) {

            if(!isset($rulesthisyear['reset'])) {
                // No "reset" rule. We will assume that this is somewhere in the southern hemisphere
                // after a period of not using DST, otherwise it doesn't make sense at all.
                // With that assumption, we can put in a fake reset e.g. on Jan 1, 12:00.
                /*
                print_object("no reset");
                print_object($rules);
                die();
                */
                $rulesthisyear['reset'] = array(
                    NULL, NULL, NULL, NULL, NULL, 'jan', 1, '12:00', '00:00', NULL
                );
            }

            if(!isset($rulesthisyear['set'])) {
                // No "set" rule. We will assume that this is somewhere in the southern hemisphere
                // and that it begins a period of not using DST, otherwise it doesn't make sense at all.
                // With that assumption, we can put in a fake set on Dec 31, 12:00, shifting time by 0 minutes.
                $rulesthisyear['set'] = array(
                    NULL, $rulesthisyear['reset'][1], NULL, NULL, NULL, 'dec', 31, '12:00', '00:00', NULL
                );
            }

            list($discard,
                 $name,
                 $from,
                 $to,
                 $type,
                 $in,
                 $on,
                 $at,
                 $save,
                 $letter) = $rulesthisyear['set'];
    
            $moodle_rule = array();
    
            // $save is sometimes just minutes
            // and othertimes HH:MM -- only
            // parse if relevant
            if (!preg_match('/^\d+$/', $save)) {                 
                list($hours, $mins) = explode(':', $save);
                $save = $hours * 60 + $mins;
            }

            // we'll parse $at later
            // $at = olson_parse_at($at); 
            $in = strtolower($in);
            if(!isset($months[$in])) {
                trigger_error('Unknown month: '.$in);
            }
    
            $moodle_rule['name']   = $name;
            $moodle_rule['year']   = $year;
            $moodle_rule['dstoff'] = $save; // time offset

            $moodle_rule['dst_month'] = $months[$in]; // the month
            $moodle_rule['dst_time']  = $at; // the time

            // Encode index and day as per Moodle's specs
            $on = olson_parse_on($on);
            $moodle_rule['dst_startday']  = $on['startday'];
            $moodle_rule['dst_weekday']   = $on['weekday'];
            $moodle_rule['dst_skipweeks'] = $on['skipweeks'];
            
            // and now the "deactivate" data
            list($discard,
                 $name,
                 $from,
                 $to,
                 $type,
                 $in,
                 $on,
                 $at,
                 $save,
                 $letter) = $rulesthisyear['reset'];
    
            // we'll parse $at later
            // $at = olson_parse_at($at);
            $in = strtolower($in);
            if(!isset($months[$in])) {
                trigger_error('Unknown month: '.$in);
            }

            $moodle_rule['std_month'] = $months[$in]; // the month
            $moodle_rule['std_time']  = $at; // the time
    
            // Encode index and day as per Moodle's specs
            $on = olson_parse_on($on);
            $moodle_rule['std_startday']  = $on['startday'];
            $moodle_rule['std_weekday']   = $on['weekday'];
            $moodle_rule['std_skipweeks'] = $on['skipweeks'];
                
            $moodle_rules[$moodle_rule['name']][$moodle_rule['year']] = $moodle_rule;
            //print_object($moodle_rule);

        } // end foreach year within a rule

        // completed with all the entries for this rule
        // if the last entry has a TO other than 'max'
        // then we have to deal with closing the last rule
        //trigger_error("Rule $name ending to $to");
        if (!empty($to) && $to !== 'max') {
            // We can handle two cases for TO: 
            // a year, or "only"
            $reset_rule = $moodle_rule;
            $reset_rule['dstoff'] = '00';
            if (preg_match('/^\d+$/', $to)){
                $reset_rule['year'] = $to;
                $moodle_rules[$reset_rule['name']][$reset_rule['year']] = $reset_rule;
            } elseif ($to === 'only') {
                $reset_rule['year'] = $reset_rule['year'] + 1;
                $moodle_rules[$reset_rule['name']][$reset_rule['year']] = $reset_rule;
            } else {
                trigger_error("Strange value in TO $to rule field for rule $name");
            }

        } // end if $to is interesting

    } // end foreach rule

    return $moodle_rules;
}

/***
 *** olson_simple_zone_parser($filename)
 ***
 *** Parses the olson files for zone info
 ***
 *** Returns a multidimensional array, or false on error
 ***
 */
function olson_simple_zone_parser ($filename) {

    $file = fopen($filename, 'r', 0); 

    if (empty($file)) {
        return false;
    }
    
    $zones = array();
    $lastzone = NULL;

    while ($line = fgets($file)) {
        // skip obvious non-zone lines
        if (preg_match('/^#/', $line)) {
            continue;
        }
        if (preg_match('/^(?:Rule|Link|Leap)/',$line)) {
            $lastzone = NULL; // reset lastzone
            continue;
        }

        // If there are blanks in the start of the line but the first non-ws character is a #,
        // assume it's an "inline comment". The funny thing is that this happens only during
        // the definition of the Rule for Europe/Athens.
        if(substr(trim($line), 0, 1) == '#') {
            continue;
        }

        /*** Notes
         ***
         *** By splitting on space, we are only keeping the
         *** year of the UNTIL field -- that's on purpose.
         ***
         *** The Zone lines are followed by continuation lines
         *** were we reuse the info from the last one seen.
         ***
         *** We are transforming "until" fields into "from" fields
         *** which make more sense from the Moodle perspective, so
         *** each initial Zone entry is "from" the year 0, and for the 
         *** continuation lines, we shift the "until" from the previous field
         *** into this line's "from".
         ***
         *** If a RULES field contains a time instead of a rule we discard it
         *** I have no idea of how to create a DST rule out of that
         *** (what are the start/end times?)
         ***
         *** We remove "until" from the data we keep, but preserve 
         *** it in $lastzone.
         */
        if (preg_match('/^Zone/', $line)) { // a new zone
            $line = trim($line);
            $line = preg_split('/\s+/', $line);
            $zone = array();
            list( $discard, // 'Zone'
                  $zone['name'],
                  $zone['gmtoff'],
                  $zone['rule'],
                  $discard // format
                  ) = $line;
            // the things we do to avoid warnings
            if (!empty($line[5])) { 
                $zone['until'] = $line[5];
            }
            $zone['year'] = '0';
            
            $zones[$zone['name']] = array();

        } else if (!empty($lastzone) && preg_match('/^\s+/', $line)){ 
            // looks like a credible continuation line  
            $line = trim($line);
            $line = preg_split('/\s+/', $line);
            if (count($line) < 3) {
                $lastzone = NULL;
                continue;
            }
            // retrieve info from the lastzone
            $zone = $lastzone;
            $zone['year'] = $zone['until'];
            // overwrite with current data
            list(
                  $zone['gmtoff'],
                  $zone['rule'],
                  $discard // format
                  ) = $line;
            // the things we do to avoid warnings
            if (!empty($line[3])) { 
                $zone['until'] = $line[3];
            }

        } else {
            $lastzone = NULL;
            continue;
        }

        // tidy up, we're done 
        // perhaps we should insert in the DB at this stage?
        $lastzone = $zone;
        unset($zone['until']);
        $zone['gmtoff'] = olson_parse_offset($zone['gmtoff']);
        if ($zone['rule'] === '-') { // cleanup empty rules
            $zone['rule'] = '';
        }
        if (preg_match('/:/',$zone['rule'])) { 
            // we are not handling direct SAVE rules here
            // discard it
            $zone['rule'] = '';
        }
        
        $zones[$zone['name']][(string)$zone['year']] = $zone;
    }

    return $zones;
}

/***
 *** olson_parse_offset($offset)
 ***
 *** parses time offsets from the GMTOFF and SAVE
 *** fields into +/-MINUTES 
 */
function olson_parse_offset ($offset) {
    $offset = trim($offset);
    
    // perhaps it's just minutes
    if (preg_match('/^(-?)(\d*)$/', $offset)) {
        return intval($offset);
    }
    // (-)hours:minutes(:seconds) 
    if (preg_match('/^(-?)(\d*):(\d+)/', $offset, $matches)) {
        // we are happy to discard the seconds
        $sign    = $matches[1];
        $hours   = intval($matches[2]);
        $seconds = intval($matches[3]);
        $offset  = $sign . ($hours*60 + $seconds);
        return intval($offset);
    } 

    trigger_error('Strange time format in olson_parse_offset() ' .$offset);
    return 0;

}


/***
 *** olson_parse_on_($on)
 ***
 *** see `man zic`. This function translates the following formats 
 *** 5        the fifth of the month
 *** lastSun  the last Sunday in the month
 *** lastMon  the last Monday in the month
 *** Sun>=8   first Sunday on or after the eighth
 *** Sun<=25  last Sunday on or before the 25th
 ***
 *** to a moodle friendly format. Returns an array with:
 ***
 *** startday: the day of the month that we start counting from.
 ***           if negative, it means we start from that day and
 ***           count backwards. since -1 would be meaningless,
 ***           it means "end of month and backwards".
 *** weekday:  the day of the week that we must find. we will
 ***           scan days from the startday until we find the
 ***           first such weekday. 0...6 = Sun...Sat.
 ***           -1 means that any day of the week will do,
 ***           effectively ending the search on startday.
 *** skipweeks:after finding our end day as outlined above,
 ***           skip this many weeks. this enables us to find
 ***           "the second sunday >= 10". usually will be 0.
 */
function olson_parse_on ($on) {

    $rule = array();
    $days = array('sun' => 0, 'mon' => 1, 
                  'tue' => 2, 'wed' => 3, 
                  'thu' => 4, 'fri' => 5, 
                  'sat' => 6);

    if(is_numeric($on)) {
        $rule['startday']  = intval($on); // Start searching from that day
        $rule['weekday']   = -1;          // ...and stop there, no matter what weekday
        $rule['skipweeks'] = 0;           // Don't skip any weeks.
    }
    else {
        $on = strtolower($on);
        if(substr($on, 0, 4) == 'last') {
            // e.g. lastSun
            if(!isset($days[substr($on, 4)])) {
                trigger_error('Unknown last weekday: '.substr($on, 4));
            }
            else {
                $rule['startday']  = -1;                    // Start from end of month
                $rule['weekday']   = $days[substr($on, 4)]; // Find the first such weekday
                $rule['skipweeks'] = 0;                     // Don't skip any weeks.
            }
        }
        else if(substr($on, 3, 2) == '>=') {
            // e.g. Sun>=8
            if(!isset($days[substr($on, 0, 3)])) {
                trigger_error('Unknown >= weekday: '.substr($on, 0, 3));
            }
            else {
                $rule['startday']  = intval(substr($on, 5));   // Start from that day of the month
                $rule['weekday']   = $days[substr($on, 0, 3)]; // Find the first such weekday
                $rule['skipweeks'] = 0;                        // Don't skip any weeks.
            }
        }
        else if(substr($on, 3, 2) == '<=') {
            // e.g. Sun<=25
            if(!isset($days[substr($on, 0, 3)])) {
                trigger_error('Unknown <= weekday: '.substr($on, 0, 3));
            }
            else {
                $rule['startday']  = -intval(substr($on, 5));  // Start from that day of the month; COUNT BACKWARDS (minus sign)
                $rule['weekday']   = $days[substr($on, 0, 3)]; // Find the first such weekday
                $rule['skipweeks'] = 0;                        // Don't skip any weeks.
            }
        }
        else {
            trigger_error('unknown on '.$on);
        }
    }    
    return $rule;
}


/***
 *** olson_parse_at($at, $set, $gmtoffset)
 ***
 *** see `man zic`. This function translates
 ***
 ***      2        time in hours
 ***      2:00     time in hours and minutes
 ***     15:00     24-hour format time (for times after noon)
 ***      1:28:14  time in hours, minutes, and seconds
 ***
 ***  Any of these forms may be followed by the letter w if the given
 ***  time is local "wall clock" time, s if the given time  is  local
 ***  "standard"  time, or u (or g or z) if the given time is univer-
 ***  sal time; in the absence of an indicator, wall  clock  time  is
 ***  assumed.
 ***
 *** returns a moodle friendly $at, in GMT, which is what Moodle wants
 ***
 *** 
 */
function olson_parse_at ($at, $set = 'set', $gmtoffset) {

    // find the time "signature";
    $sig = '';
    if (preg_match('/[ugzs]$/', $at, $matches)) {
        $sig = $matches[0];
        $at  = substr($at, 0, strlen($at)-1); // chop
    }

    list($hours, $mins) = explode(':', $at);

    // GMT -- return as is!
    if ( !empty($sig) && ( $sig === 'u'
                           || $sig === 'g'
                           || $sig === 'z'    )) {
        return $at;
    }

    // Wall clock
    if (empty($sig) || $sig === 'w') { 
        if ($set !== 'set'){ // wall clock is on DST, assume by 1hr
            $hours = $hours-1;
        } 
        $sig = 's';
    }

    // Standard time
    if (!empty($sig) && $sig === 's') {
        $mins = $mins + $hours*60 + $gmtoffset;
        $hours = $mins / 60;
        $hours = (int)$hours;
        $mins  = abs($mins % 60);
        return sprintf('%02d:%02d', $hours, $mins);
    }

    trigger_error('unhandled case - AT flag is ' . $matches[0]);
}


?>