Event-1.26/0000755000076400007640000000000012727627261011265 5ustar useruserEvent-1.26/META.json0000644000076400007640000000203312727627261012704 0ustar useruser{ "abstract" : "unknown", "author" : [ "unknown" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.18, CPAN::Meta::Converter version 2.150001", "license" : [ "unknown" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Event", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Test" : "1", "perl" : "5.008000" } } }, "release_status" : "stable", "resources" : { "repository" : { "type" : "git", "url" : "https://github.com/mohawk2/cpan-Event.git", "web" : "https://github.com/mohawk2/cpan-Event" } }, "version" : "1.26" } Event-1.26/TODO0000644000076400007640000000455312357140355011755 0ustar useruserfinish up lexical warnings omitting parked=>1 should be a warning, not an error? demo/tail-f see File::Tail or GNU textutils for implementation examples add timeout for var watchers? find owner for Win32 port perhaps some help with distributing SIGCHLD? documentation how to design new event types (in perl) how to design new event types (in C)?? mjtg@cus.cam.ac.uk signal discussion: The API rsignal overrides the current signal handler. If the signal watcher is cancelled (or otherwise disabled) then rsignal is reset to SIG_DFL. Maybe the original handler should be restored. On the other hand, assignment to %SIG will mess up Event watchers so maybe Event should refuse to watch a signal if a handler is already installed. optimization update io event-mask without invalidating cache determine IntervalEpsilon dynamically & make available from perl use fancy profiler tricks to figure out how to boost performance queue events from both sides? try to hoist system calls from the inner loop there seems to be some sort of bug in the shutdown phase Attempt to free unreferenced scalar during global destruction. Use of uninitialized value during global destruction. Explicit blessing to '' (assuming package main) during global destruction. rethink pe_check_recovery & ENTER/LEAVE points increase the number of priority levels? ASYNC 0 1 2 3 4 5 6 7 8 9 IDLE HIGH NORM loop StarvePrio? ----------------------------------------------------------------------- ----------------------------------------------------------------------- Move process.pm to external module? accept "%f minutes" & "%f hours" for all time specifications? On Wed, Aug 30, 2000 at 02:50:20PM -0400, Joshua N Pritikin wrote: > Wow! I am reading about the Linux linked list implementation. In > comparison to Linux, Event wastes an unnecessary pointer on every link. > I'd better fix this! :-) False alarm? Linux is able to make the assumption that the next & prev pointers are always the same offset from the top of the structure. This assumption is true for pe_watcher.all, pe_event.peer, pe_event.que, and pe_qcallback.ring. However, pe_timeable.ring is stored at lots of different offsets. Hm hm. I guess some bytes are wasted but otherwise Event will need two different kinds of linked lists... Event-1.26/MANIFEST0000644000076400007640000000222212727627261012414 0ustar useruserANNOUNCE c/ev.c c/generic.c c/group.c c/hook.c c/idle.c c/io.c c/queue.c c/signal.c c/tied.c c/timeable.c c/timer.c c/typemap.c c/unix.c c/var.c c/watcher.c Changes demo/echo.t demo/group.t demo/idle2.t demo/msg.pm demo/perlqt.t demo/process.pm demo/queue_pending.t demo/rand_interval.t demo/readline.t demo/repeat.t demo/semaphore.pm Event.h Event.xs INSTALL lib/Event.pm lib/Event.pod lib/Event/EventAPI.h lib/Event/generic.pm lib/Event/generic.pod lib/Event/group.pm lib/Event/idle.pm lib/Event/io.pm lib/Event/MakeMaker.pm lib/Event/signal.pm lib/Event/timer.pm lib/Event/type.pm lib/Event/typemap lib/Event/var.pm lib/Event/Watcher.pm Makefile.PL MANIFEST ppport.h README README.EV t/attach_to.t t/bored.t t/callback.t t/data.t t/delete.t t/eval.t t/fifo.t t/generic.t t/group.t t/hook.t t/hup.t t/idle.t t/io.t t/leak.t t/leak2.t t/loop.t t/now.t t/reenter.t t/signal.t t/timeout_cb.t t/timer.t t/unconfigured.t t/var.t TODO Tutorial.pdf Tutorial.pdf-errata.txt util/bench.pl util/filehandle.txt META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Event-1.26/ANNOUNCE0000644000076400007640000000247612725135313012415 0ustar useruserPerl might have started out as a text processing language, but why shouldn't it expand into all domains of data processing? One of the challenges of developing event driven applications is tweaking all your libraries to use the same event loop. This is especially difficult when no standand perl event loop exists. I hereby present the Event extension. Event has been in development since April 1998. It is known to build correctly on the following architectures. Most unix architectures should work with minor tweaking. linux 2.2.1 ppc-linux linux 2.2.5-15 i686-linux sunos 4.1.4 sun4-sunos solaris 2.5.1 sun4-solaris solaris 2.6 sun4-solaris solaris 7 i86pc-solaris * Perl 5.008 (or better) is required. * Win32 support should not be too difficult but no volunteer has stepped forward to take ownership. * No real additional support is needed or planned for multiple threads. Event has been tested with Insure++. Since there is only really need for a single event loop API, there is tentitive demand for including this extension as part of the main perl distribution. Therefore, I would like to encourage everyone to try it out and send any feedback to the mailing list at perl-loop@perl.org. Thank you very much! Joshua N Pritikin 15 Jul 1999 Event-1.26/INSTALL0000644000076400007640000000034612357140355012312 0ustar useruserTo get high-precision time you'll need to install and use Time::HiRes 01.20. --- The design and implementation of this extension is discussed on the perl-loop mailing list. Please send email to majordomo@perl.org to subscribe! Event-1.26/Tutorial.pdf0000644000076400007640000065614112357140355013571 0ustar useruser%PDF-1.3 % 1 0 obj<>endobj 2 0 obj<>endobj 3 0 obj<>endobj 4 0 obj<>endobj 5 0 obj<>endobj 6 0 obj<>endobj 7 0 obj<>endobj 8 0 obj<>endobj 9 0 obj<>endobj 10 0 obj<>endobj 11 0 obj<>endobj 12 0 obj<>endobj 13 0 obj<>endobj 14 0 obj<>endobj 15 0 obj<>endobj 16 0 obj<>endobj 17 0 obj<>endobj 18 0 obj<>endobj 19 0 obj<>endobj 20 0 obj<>endobj 21 0 obj<>endobj 22 0 obj<>endobj 23 0 obj<>endobj 24 0 obj<>endobj 25 0 obj<>endobj 26 0 obj<>endobj 27 0 obj<>endobj 28 0 obj<>endobj 29 0 obj<>endobj 30 0 obj<>endobj 31 0 obj<>endobj 32 0 obj<>endobj 33 0 obj<>endobj 34 0 obj<>endobj 35 0 obj<>endobj 36 0 obj<>endobj 37 0 obj<>endobj 38 0 obj<>endobj 39 0 obj<>endobj 40 0 obj<>endobj 41 0 obj<>endobj 42 0 obj<>endobj 43 0 obj<>endobj 44 0 obj<>endobj 45 0 obj<>endobj 46 0 obj<>endobj 47 0 obj<>endobj 48 0 obj<>endobj 49 0 obj<>endobj 50 0 obj<>endobj 51 0 obj<>endobj 52 0 obj<>endobj 53 0 obj<>endobj 54 0 obj<>endobj 55 0 obj<>endobj 56 0 obj<>endobj 57 0 obj<>endobj 58 0 obj<>endobj 59 0 obj<>endobj 60 0 obj<>endobj 61 0 obj<>endobj 62 0 obj<>endobj 63 0 obj<>endobj 64 0 obj<>endobj 65 0 obj<>endobj 66 0 obj<>endobj 67 0 obj<>endobj 68 0 obj<>endobj 69 0 obj<>endobj 70 0 obj<>endobj 71 0 obj<>endobj 72 0 obj<>endobj 73 0 obj<>endobj 74 0 obj<>endobj 75 0 obj<>endobj 76 0 obj<>endobj 77 0 obj<>endobj 78 0 obj<>endobj 79 0 obj<>endobj 80 0 obj<>endobj 81 0 obj<>endobj 82 0 obj<>endobj 83 0 obj<>endobj 84 0 obj<>endobj 85 0 obj<>endobj 86 0 obj<>endobj 87 0 obj<>endobj 88 0 obj<>endobj 89 0 obj<>endobj 90 0 obj<>endobj 91 0 obj<>endobj 92 0 obj<>endobj 93 0 obj<>endobj 94 0 obj<>endobj 95 0 obj<>endobj 96 0 obj<>endobj 97 0 obj<>endobj 98 0 obj<>endobj 99 0 obj<>endobj 100 0 obj<>endobj 101 0 obj<>endobj 102 0 obj<>endobj 103 0 obj<>endobj 104 0 obj<>endobj 105 0 obj<>endobj 106 0 obj<>endobj 107 0 obj<>endobj 108 0 obj<>endobj 109 0 obj<>endobj 110 0 obj<>endobj 111 0 obj<>endobj 112 0 obj<>endobj 113 0 obj<>endobj 114 0 obj<>endobj 115 0 obj<>endobj 116 0 obj<>endobj 117 0 obj<>endobj 118 0 obj<>endobj 119 0 obj<>endobj 120 0 obj<>endobj 121 0 obj<>endobj 122 0 obj<>endobj 123 0 obj<>endobj 124 0 obj<>endobj 125 0 obj<>endobj 126 0 obj<>endobj 127 0 obj<>endobj 128 0 obj<>endobj 129 0 obj<>endobj 130 0 obj<>endobj 131 0 obj<>endobj 132 0 obj<>endobj 133 0 obj<>endobj 134 0 obj<>endobj 135 0 obj<>endobj 136 0 obj<>endobj 137 0 obj<>endobj 138 0 obj<>endobj 139 0 obj<>endobj 140 0 obj<>endobj 141 0 obj<>endobj 142 0 obj<>endobj 143 0 obj<>endobj 144 0 obj<>endobj 145 0 obj<>endobj 146 0 obj<>endobj 147 0 obj<>endobj 148 0 obj<>endobj 149 0 obj<>endobj 150 0 obj<>endobj 151 0 obj<>endobj 152 0 obj<>endobj 153 0 obj<>endobj 154 0 obj<>endobj 155 0 obj<>endobj 156 0 obj[11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R 34 0 R 35 0 R 36 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R 42 0 R 43 0 R 44 0 R 45 0 R 46 0 R 47 0 R 48 0 R 49 0 R 50 0 R 51 0 R 52 0 R 53 0 R 54 0 R 55 0 R 56 0 R 57 0 R 58 0 R 59 0 R 60 0 R 61 0 R 62 0 R 63 0 R 64 0 R 65 0 R 66 0 R 67 0 R 68 0 R 69 0 R 70 0 R 71 0 R 72 0 R 73 0 R 74 0 R 75 0 R 76 0 R 77 0 R 78 0 R 79 0 R 80 0 R 81 0 R 82 0 R 83 0 R 84 0 R 85 0 R 86 0 R 87 0 R 89 0 R 91 0 R 93 0 R 94 0 R 95 0 R 96 0 R 97 0 R 98 0 R 99 0 R 100 0 R 101 0 R 102 0 R 103 0 R 104 0 R 105 0 R 106 0 R 107 0 R 108 0 R 109 0 R 110 0 R 111 0 R 112 0 R 113 0 R 114 0 R 115 0 R 116 0 R 117 0 R 118 0 R 119 0 R 120 0 R 121 0 R 122 0 R 123 0 R 124 0 R 125 0 R 126 0 R 127 0 R 128 0 R 129 0 R 130 0 R 131 0 R 132 0 R 133 0 R 134 0 R 135 0 R 136 0 R 137 0 R 138 0 R 139 0 R 140 0 R 141 0 R 142 0 R 143 0 R 144 0 R 145 0 R 146 0 R 147 0 R 148 0 R 149 0 R 150 0 R 151 0 R 152 0 R 153 0 R 154 0 R 155 0 R ]endobj 157 0 obj<>endobj 158 0 obj<>endobj 159 0 obj<>endobj 160 0 obj<>endobj 161 0 obj[157 0 R 158 0 R 159 0 R 160 0 R ]endobj 162 0 obj<>endobj 163 0 obj<>endobj 164 0 obj[163 0 R ]endobj 165 0 obj<>endobj 166 0 obj<>endobj 167 0 obj[166 0 R ]endobj 168 0 obj<>endobj 169 0 obj<>endobj 170 0 obj<>endobj 171 0 obj<>endobj 172 0 obj<>endobj 173 0 obj<>endobj 174 0 obj[169 0 R 171 0 R 173 0 R ]endobj 175 0 obj<>endobj 176 0 obj<>endobj 177 0 obj<>endobj 178 0 obj<>endobj 179 0 obj<>endobj 180 0 obj<>endobj 181 0 obj<>endobj 182 0 obj<>endobj 183 0 obj<>endobj 184 0 obj<>endobj 185 0 obj<>endobj 186 0 obj<>endobj 187 0 obj<>endobj 188 0 obj<>endobj 189 0 obj<>endobj 190 0 obj<>endobj 191 0 obj<>endobj 192 0 obj<>endobj 193 0 obj<>endobj 194 0 obj<>endobj 195 0 obj<>endobj 196 0 obj<>endobj 197 0 obj<>endobj 198 0 obj<>endobj 199 0 obj<>endobj 200 0 obj<>endobj 201 0 obj<>endobj 202 0 obj<>endobj 203 0 obj<>endobj 204 0 obj<>endobj 205 0 obj<>endobj 206 0 obj<>endobj 207 0 obj<>endobj 208 0 obj<>endobj 209 0 obj<>endobj 210 0 obj<>endobj 211 0 obj<>endobj 212 0 obj<>endobj 213 0 obj<>endobj 214 0 obj<>endobj 215 0 obj<>endobj 216 0 obj<>endobj 217 0 obj<>endobj 218 0 obj<>endobj 219 0 obj<>endobj 220 0 obj<>endobj 221 0 obj<>endobj 222 0 obj<>endobj 223 0 obj<>/Dur 10/Trans<>>>>>endobj 224 0 obj<>stream x= D|R MY~ELV>Y]u jF!MzK?v8𮒰# n7}^JGCs@82a}mrE ; + endstream endobj 225 0 obj 137 endobj 226 0 obj<>>>>>endobj 227 0 obj<>stream x+237U&@B(]M-M,LRҸ B f Z endstream endobj 228 0 obj 60 endobj 229 0 obj<>/Dur 10/Trans<>>>/Annots 156 0 R>>endobj 230 0 obj<>stream xڥKs6 <&3"R%Ty;ĭ撋+Jvuv;Ifm?IH@,M\S^/rQj%FܝI#)2W۳W7pY ??ಗo+!$7w@o<6$C _nzm{v6b?hzhCzi|:{C#w2I!ݷB:~(RԋH '"Qp4\OMوGy<ہ_>Yda>>/flo"\ ΘV"X [F@M}iD'.;O 3xw%ậE"M_[QU܅~u ,&6J9y24ꬦxqyUy`+]Pʒ0We oz[Dpb=- SxdyBo8?y:υأ4 p4[pDgoa~?x^^d^vӥ].&XKap8%к)Zxcm=ZnlʊXǐt&. rx=Ү}[% Lc'O5m=%P4U,=]R)08%AOY0edntFhN es C7VVJEh` \."I>Lvڎ)R*R.K=,R^v(5n}WoN5N,"btEiW$ˣQ1])@k1 n6!m3:Hq:ޔ9InIߖ 3om3>FwM $T*9γ%jG6d~?S[S-^X_IDp׾m@—/g,Ej_Iq/+[Jendstream endobj 231 0 obj 1934 endobj 232 0 obj<>/Dur 10/Trans<>>>/Annots 161 0 R>>endobj 233 0 obj<>stream x|kA7 9xQvz&Pڦ9UڀiZ1$T* ,"7}Ih.`_BvD⎉8=LD&3QHCy #_0( SK?Ӣ (@+|46Ƌ<P,O%rqz{w{=^ L#Ow]dI>)eL-Ąh#"#P.O hn!a yB8} 9OߠO hS.C4jcj*ZM?0sY4ބ:4+.ש<5å7YhReyp3Jp;c$=t y<_dS<ъh~?n(ͷK5oIX;Z–vzoQ44E:e-zkEW0Yr s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]IF 1#K#=KJMv oendstream endobj 234 0 obj 727 endobj 235 0 obj<>/Dur 10/Trans<>>>>>endobj 236 0 obj<>stream xs6vƏ,i´7-SCfF#EUT$~K%ڇTv]YOvl'> |n6ď ׳O_/w՛O~./ܽwg7j+Fl\,_f>_߼~z{wb׷7r{?wZ]߿yZS͟?P^ŝ\|>?O>/?]?OrߜV$./p'ٻg_?z{}{k~+_?|x|~V˥7o^܈ۛW/^pw{7/_ݾ}F~NNwϟr۽o^{{ '*$_2Zͫg__og,~׿=u.3dD^/]BBrY(r(bY9:eQ_jOJ8IR:{$곋 >@ N a/]P+?Zߑ+/kwT竳{|Yڑg\j!% ӑ%}>UO8che apUl$"#!@VxD*pͰsy'+ĶG_('c&ғ,`f7s0g< o G<=A35 >Q+ԛD&lAͲ!thgW|QQdj+;3Ч`4śH(..b&b.Gn &$6d,>X)bV$ ZAAAIq9u}WͶVR &j-J;ԟ+Z"2:Wq9H c-i"C9}'Bd PF%]xIެ̄Ї뫠HDa2F+@٬oJ~2k<`9Vh3u5,4A,< z'dX d.>HȠ~숃5d3L~PWkIuA dfl :v & gxp‹\B++BIEjk[wqpAA[N_ oܵ)SDK+!((i7L'(8PKiPHe|q6}7pUeVTtʏ9jJ-ӑbƳ̀q5JOO6qr1ǁ1?+4wшg31eĝb&^ u3GD}0Ff 836)\{DxɢL*LRѸPG،zJ8#0 ]$#,'Nٜ Q>OYMYyg^բIM[6D aј$T]Lwem34O CYh2.$2. nDM)id6D6oE28WMƐUJG;A_q;MǦsg&)"_$tO/P jwC?лgm3^l[#{+7 d; qN 4dvpyobӡqL,sY՟Y #}dWUXwi{"b#l)m~D@RR;clF7  & Ki734'ޤѥ|^oRn廬,l*dgU?a29O$&ϑdDyfDY*qi{7d37qv d8ք d8oIG27NyِnhیzQ]* zD2:(n{mkˣ2IޚeFH^3i`LjvᐟK~}??Bފ@)6#qtMtV(;^r_.gP_gW3o{_ގ}<]muui(\IE ShBc]0qwjApWk2U+Th D4X?Cъd c#м Uqy dlRݡ}0w-{j/2je R+r^akf݅d7fWjq90 SXH2(\I s=2g0ZSIc5d|u)Id`qd2VgBl&բjmj͎.R&k@oMfho;5ޫ-͗TDހ*a /]7Y&nJM<2NeP@󛕹- d |,(KǶMZ1DbX^C7MzMz?GF߇Omӊm&#g Fo n2зNNc<2ȵM2 k{E:N*Z2xf'V[7AxԲfdͥM2Ui#25]јˊ)& -%J LX͠2QF 7C+?L4+{d3@f=*37Yp <./S$%rZ 95wz:mQGrmj#t\]l7QUhd 7R ~Mjirog\v[Ŗo2VM_gOu4lc7ǝ& G^&~ cէ v*bS PHOl&TADtp}z' qF?wL$B5ݱ=LUIV-0M#:]8i hkMR;d l~ֽ&5ɰm-ApNyfɰ]7MmFOth#N cOI @ӈdW$h3Չa;+o2ڌa}&eӽ&&7#x~P^`(l/~SpB/PXx                 bD~p;hbnvT{sjT Z //9S<E_z-@vy?f;_ 9]h&*^AXs?,(@ƶ9gdLP6"(Bn)9&#ƅ /8ȝβG3=x J<^`} ps3;EoA,fA̘H9 d<~x2Qh8 2ZQh (z7HfdTwʩQiKI; mg7tƠz7 co1ZmFv&Uc4gbjdD C*^~$n ]F>xZɠfڌI# me{bP[i) @h2+mV& E%dgT&]+! 5TX:FA'ԁn}0"k3yWZnGxɠUk 7O6E;;j6ch;6w}ޤп D]1krGnN1h\&a` cȨ=]kId{]}E܂"9(6djWpm׍rșw;}+͇蛉c?fɨrބgϖgۋ.z b?omyx_dدǢYxSPߓHuRr& 0ȻOEJ>p3:g2% eK"  ۬7k1na/"&V][:ϝ=?P(0I@^J!\LӜ,gvGߨ7U+䛘P( 2 d 2  d@ z2Xͩ뚖2xgX^nMVK#1.2vƛp;6oi_nu6ďs3)C92f87Eudp3 c5!gz;U\Ҍ֘N@lrԦFUЌ1䪕y3sU;F}7!}X]j# XU\( ynkzO\~eFv>MtLAhi{$LV'W6^Vh[n ,,7cꃵscdjXj.2HҚ^KWPꨰ2DnzS.`=bE:f< aIEDPuZ\W|3y(5z n iax'dLQG˚S8"Pg3w-8%6MAF)Mt9?U,#Stu).Yxxn%g Tx=7zؘ֨71@[EA,U$qM%yeMC~Vˊڋx9{wLm+v1֥N2{zMGnc V+2cE~W*__uDsv Gt27$nƑ"ȹ;71ފ~kVț.i˜% +k.nLx ׍-v¯۰ e+j!wT6c[-F ۾wj9Ś3@A J#~MћD!x&#rǴ&6ch1Lw`AM:[xwǒod4[ ،i2@F߀kd odvdt6!2p7@of@ z`2zz^od<^a3MM@& 6d of@ Zx*)fdMv#6cwɰϴ  ƋmmG~A6gE(ɞA`mM@4ll& 6dl,gyd:*Q}n( m͠`# snA(%| > Mvƈn5~j2 G5pgd?pnRc;^/،=9<8I0[#ÛYMτx'~}u#sD5D66d 6] 6 ΪKY2:kQwq8dod!έx4bx،]3lˬF;(C(thԷcMF+j jeyw|2>"ME&;Mi>h3>d@MV2@  cA7dR, h_2$':LeE@%I< m KOޯHRH^H{RL "+Je z+քJ)N@A5I(bJk%z"I}$JZEP>2h ix$ñPUXHl=}^AI?Y. v$2HH~ ̠zL4k;Hh4,3憛G˚pf1(k2OGߏfBȀkC,N1ZQ~\QkǀY 26'_EȚJڬYm\YSSռgVƊe`Jp,mg[Xh-Iby=5Yl+6RU S8RC.DhRXCܸ?Pe Vb8Y8~VM`}L!Vq`};6]-gfl̬xYg, 43p`cdayx.ߍ`FN~Y[[dcṷ _7f؏uֺ 6igf؏evayx tYY/rf6 kV}k+ŏXY8ɬ%>/Dur 10/Trans<>>>>>endobj 239 0 obj<>stream xjFpLOIt!iV,s(f%y;` zt2o ;#i5FFRSLoV!<;?NgN_޿6 }o=yѓ`7+O?] _bw/O嵿DbC48;|6~ptW7 .p \.pUZ9$\޸219 O..rLU\i;q_芿B=snO]~?:~# !v_T#.p \E k[1h{qQW֘H\TkG.:SȪ r5.Wj%kEqnrb5EIQU .\c*ҁzՔK'U͇RpU o!\U[W6U!`pU7DـqEs@Ŷ߰DknCZ1Rו3DbԒ+˟%PuZS~a]5ʯHlcU3+ A!4*H{P0*: Eh n\&Y(vjUЍ;yWA7CIgUt^gRSDq#*`HzmJUI Θb*å*(#>Ȭk{gN[qF]XU"Då`\'EEUIK긴H/yOD.tQmg؎sDhˊ ktVtKn] ]ØKtّˉ\ s r})v5R!J/}EfiLVL|^#+1]bŕ321qQC.s%>7./0HX]Ԉ+3=DWK+yciz !#%̸.pa.Ջ۸ j74~b. + .appe$mPLHq"iޥgRa&\:c\ͻ mDÀ f階[ʺNڑ%E Ѷ\n+Rnb.tMּK9wKL\-(_""Q5](_,o8Otu o|;OtuxKrtMMNoZ 6YϠ%]HkQ [ra1sKmEU.;p)RDr.ҰhGD{? D_]D.ܬImk:V;iŔօr0K4b.1nإyw&rL%"*0mE;sܥ k3SvRq4Uv r]p1K͵ɺWWU|d2\pekKU\{] TR'pa ^V Hz޼c |Ӑ"R)V;^44J%mq ] ״^~}Q&ҮQ= g פQ:1SnRWUާ ~prkw-Jꟷӆ 8 ժSRo!eۮtұ1,ٕKU`tY>_9a?F󽞺$t]Ǐ7Z.p \.p \.p \u> - \n F,]zmsff]Th|r-[uy@k&MHʵ0y7.rJ9#.o:,4-˺[Ƭ7fl/cӻgS!X2Y't-&HAZ^wZʥ5Yp~tD_ZQlI5P~u7Gk[5vukz\.p \r AOF`W!9Ri-h-A[ՂrPd!醄ue9A"qBV GBQ$;t%qdF(`͛s)yV㋾bk2ZGHFqyvm̠]t]I+mtiHRACŴ > IL>ƿS2z='w#(RoW3td{ve (WwW# #z潆ݼx{`lm G|^=t)%+4gQ&W]5l3\*sR!{4x[Ci ^ (2wmv@K_٘zfh/d4CAɳqڟZYOl=+h~Ymnu+zI%?.@sK?WQ6EIk(@ P(@ P{F>D>O+1V/Y|CP(:J?M_Ma-&4`; _hr(D Plh0Q&0}zż {q(AD}nzgǼre~:Zxdoǃ2?2m*P3LN?<3q#nsE""G9Yo#zI2WEdNvC%ₜOzUCMr]䁞;ы!gg u #I8E}}6w&(@ P(@ P(@ P}Я Pe@1Fg"ЯwjW ΊZk Y!ǡ4 jW(eiְ17Gv cDZ6GZqp 7eZ!] EgiBIHI, q0-?tP4{sN39zKhC {c۸/ PۜHEy}ZlD*6b:4wM:Qd2gUէ{76~N&>ٯ+Wq=yM'm8ϔzo:M3vz;|O"R}>t|qh5:ݷ3_ںi+5?;߼Զ6h]h[ͼz௩OVZb3W տգA f쩻3 Zp2muփ5X'֞U;0jέ|tr:TdduTO > ;z{-X7r s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]I& 1330PO38$3?$Sendstream endobj 240 0 obj 4861 endobj 241 0 obj<>/Dur 10/Trans<>>>>>endobj 242 0 obj<>stream xڔXoFzia "ER ؎l>TE:SSГMBh=? .|͵9ՅAVdnofw)hFl7>~ϔ:G 3 Y:kԦY(XLE_ 3VX<6uV ;<;Ba NB8k 3K#U+udೠŔX!w"l#QluRXm-X\=?Jl 2JIOh˲ԕ9VY5 ՚5C"k+uBTnו,ώpE c68jYq)FZvt?N8Ѩ8A: yQ3TIV.+(J2)k@'Jp$P3ƜqZyV`t8̃YnY0L/b]bvcG0f*43cy 6i*)}=l[D: ܁S'IfS[ir{ !ZS)5ͻGL%P6|]UfX[< jрWkǝ /`,CbqbL}V@|ݝ?ૠcZ}6(ӆ9_d)PML1<}]:@fG9ˎ\zjzmAR8n,p ="JppQpE' ĪZ" *l#j:. u BQ^d+M =bږ:0D|MБ/ \KS3#6!s|Љ4iy$n.:MSY2CdpmJChu:Oi<->3]i)}8BlP6M#4A Hytl у2˓vMbнuFْ ;MP M(.|%\2ja蓭{M+CP<<* |gM.L)tܢ;i 9ϔ:Vu$Py04Q/6 2:?i jaQt:nW:2z)=c*CQݟͩcY2u? Y(7M)'1{P:mqumn>Z9Ǩ)h7Չ9fe*β:|څ7VoH4¼լnq =gÅnyŗY(ZhIA*f#R9Ԇ "GHid̊G>Y>FYۈ # ڌUg屓>4o)nYj67-sBI/PodjiK+W:Ģ0SY>uiyUkgIKzVLgz<;z VOq\ztuSmT۷V&&~N>Kzmn[&$}Bx$W>8|t:N~Ig_;/vgzuj{{n7AӇ;{$ɇO^Y|ܻgwwՃS%w|z6ٝ8K?Iz{}HN{;&Jɽ泤l>l$ڇ骗_Ec/}d#yot y=ܫ~r}2_%\߻_r s 2P0PI03S-IM+I,+VOSH,K(/-V((O/J- 254\CA Uendstream endobj 243 0 obj 2614 endobj 244 0 obj<>/Dur 10/Trans<>>>>>endobj 245 0 obj<>stream xLO`64=x,/+clKM;aă1J" $-]Ō4p?aUNΌM߾ۂ}ۧϷiڷ&3i0/#YTGI>ӹ4z-FQ\P3ČZBCdˉ+?3QE?|ydN3^GH)J*0IKOOŞG3O̘,V MVjKlu61نNڐzugEH`eDa6>/Dur 10/Trans<>>>>>endobj 248 0 obj<>stream xsU#18m\ \3>u:]L.:P$V+$;M@ u]߫h ^,Hq%'Ogo񳽝logmǻO_Nm+ gV4f::;N>F'翏NN'BOߞ>|H{|/N~t.Nӥ%ɢ/қ:8^R;z+y2}]7Ay2O/GO? N/F'ɲYr?7L9;qr?O٨7gOOOQz\'OG(>x{JzKٹ?;u噡:ޞ&kt4{Dz.Ew:L0^37.Yɥ /_ldwllToWˋx?M>ӝnv~/;n^r\Vz>9}\^_~~~4O<pom۷wB!B!B!B!B!B!B!BO"Ц,d+_LgV&&*7/BKbMeoLNLoS3D*h6LHKGPqS~2gM!q?Ad )Q DPrsBo1DT""S:*qMtT!&V.Y2 zUƛCjcqWZD*dz-!1:z0zۭ"FZ2R`ۧSɜH[^ HT2R)kT")~rRq+T")P @*yRHJWie5 HTH5@e1)*%l(U8EBe3TC%QʎdNQ H;~6,JqJPSHS┠]cTJ8%(t RpSjSTC(P8E:ũJlc8E:)J5)NQ*iS*`S**TӨL#TST1NQ)Na`Sj`Sj`Sj`S” ST,SFʘT. efjʈT SƤJ{+w^[Lq7ˮ+Siv+wbBeӎML1ivҙ^0RL"Jor+ˋ˧NԳ(dl%֛яݭW>/Գ=kᏙഛLWfvSK;WU:.SvMiZw h7e( Q8HNfCC+7B5:tx8^ˇWJSWt?SNvfbbS.s)0EbSܦp Ӆҳ+)JNaf|TR2))J()LeOKv!LhOR*:0e/|^2Ձ: 0E|8C'rJqJ@ SjP S43x0ngT2RѣLd:0e){}ԪP7FSԦQp.VE^i} Εp׷[L[# StA~k^5S#췏4>dolmY:Qfz`) S”}n]2LNU:>HL>_3ÜՆ]`t։^' ӰN|W5>`oj|$L/4~XmMhSt)g5۴F?RѦ88 m SL”6MIT~Ҧ0)LiSڔަM mJ”)L[9ڔ6U)m*)smS L´eӦ )m$LiS˔M-e)L[uP´u#y8Uݦݘԡӈ6ӦLg|n1Ydg_bzAq||jgFBڴoReU=39 WͽbYmv:~i֒2iN s/Ӱ8o>/OSNy~rfiVyf5FN!Ө6}nj̣ϛ"mZ^,Mq*Sm65fr_iӹj6`iL>7MMNhA6iS:w'ZٹizA~6iLMɑ1.7:ҿ~n}IGL1ĴiB|4?]ˎVJ_N.Ѧ0sCt=?i֥g9ٽyեͷ)N2È6_sLe0mս"Ҧ+iLyq)}7pڡ6͟Tߦ0UڦKPL57}](|ҦJ~ TMiSҦ)sS榄6Ma:Ҧ0U)LiSڔަxѦ)m SMմi?:Mle֩fڽu4WSũӽ>)LaJlLNLg27N)sSm#Q”)԰ˇ)^0 /HYad|FފQ`J` 2^Ƚ_SW3Des7mbOVjTTFQ` j )JUNNi1;uѥ0:9-Tt77eXj)LR bnRNM:QT^?Q{;AY:w*PiQ6촜R]gj>_= ܧ0UtjOQ.4;uѧ0mgG'&Sjթ>E:S].ZRژxvZS*s9B-)Ju1uzbm<#E:rr-<ÏRUuSTS-nT^Cw٧0UT$pZ}>_O)J0mG_O)S5NSjao`g(S-NU-, ?J0m}M7@RJ6&3m:\U}RL{wST"ꚹe%wSj`{0͞Liwu3Cmº6ud>Li.M[Ayaqm}k:&W{>s"Nti|PA69[p0 ޠ'WB}(v漴XW4q7%T=tEAOQ*Nkox ٤b=x^ſ2~_M)LiKK^TAMUަ>E:ʦVMvALo}*L;pLLQm T gj}MʹYofY<>lvz4ߠ<*&G|G^4{_}RL-GTq|+k8[/M6^)JvnK' ٤iX>"Pyx WU\OBZy^^٧L;mN6lkS trAkpOQ*N[z/Ov* -)JFPҘ C_!Bo 7L(f40SmRoSv8ߦ(ũ6E)N)Ja*MT~ 8ߦ(ô vpwwwwwhA~.F!J|J|!J|J|!J|J|x~h8"ۼ@| B#>1L:1ذ64hWg@j_cc.a.:WC UZoDii$RވBKT NJ#d ԰9(nip(P:~ x!aCHZ[Jh#PfbtfIԸwPZ_YT*r7ߦ{SqJWj{q&M{28~6u=PHJ9;6խ1Ne*u}Hq*w\mP!RpJ8 r" t^#<%HJ-BHq*z,c"鑲!TrZ6\ BdFhoUNm6 5P4 H X uGǂ@Q*T~BpڡiN18Ecb,c#WXpk;~5NQj)uJ)L 8%u)=)e SS ґ}R0%0)S0%]a,RZZ1&?E@FMyi,RLMa224a*MUU|*`J´[LH/OUMd.Ran┴u1Da B!B!B!B!B!B!Br o@!>2*wIS!F"1 9CbCZ@:UL])*`eТQ`"Yql ==t$=b;3XP r NoF }&uó7r$,,brN#۪~98țeR ʊw2&_gjL!G{be;18O_+X](Jn+)t /;b;7k 1?;N#a\Cq9(D\s\wDD }ZirWVk^Wf*;N[soC њO8Jx4jB{vK'BaeJɊt'kQ_s+B 4c-?le WJp3l-zcu&oIkLd'g6(gJV&FZ" ]6?[CƮ:˵M~r Ao0THDɐMvA߱R(j/Dμg2w6gY1*2yE@h–\Z"Z@TkKM Y-hK5N'B"GZO$?ކ ZT2W=//fpyeisΐh|Ѽ<ڪS7P|l%…44x!ɲ/Tendstream endobj 249 0 obj 6157 endobj 250 0 obj<>/Dur 10/Trans<>>>>>endobj 251 0 obj<>stream xS"qߨU>6kզj?RT} *7c\+oe?;=(YL=0##;~<> f! yu (ȋ{ヒxYԟ*Cyڐ_V_w~,}q"ﺽ('VuooL-|tŕk?[:\{Wʶ=b?K\~DÙ{({zz?@ܴFmy;93wwrGO%v4xwym{n]]%^+B~2vz8vz]]-н~#١D5zCq .?{3}/o%^wwsį:.{|/7xިh_vn7.im>~Vbt>pKn~_fzP,o臽>~<Pp^>>RקZݪA/x'_pN>7D7******* >R********/HP|vdj"W&F+r5vՀ UJ\5:B\eՕrP#V*=\ U:+rJ*jҏX 4Q]y&Հ̨3: ʸ{Pg0Ů:kF>j W=u@g5kT#Հ *>b<j"WU:+rJ*jX_L ٕ+UosƬ:9 (uj`m]M̻Pԙ3ݨsbUFTTJҪ,>hPW痀1jfW֧a ~(nվ`rVjyM @ Uoܕ4~j<4.@h9}&5,*NU^s*QU\jUT(6=ɺ*v6d5j;0[Szw7_a0_ y**j3,**KVj"W3P*ogA\EUTQE#VT]Ip****xՍյd @UT TQE@UT TQE@UT TQE@UT TQE@UT TQE@UT TQE@UT TQEUPEUUTөr SMoUU!P$zd8%ZWE` `2Lyϙ8UYe?AYTn銠T*q+㹽o·UUbFϹ9N<63sswMo-ꊣ.1 40աŸ@T@XU[aܡ\wta@U cp`V0HS",z`3kC6@)(W`b!-Tf۠` &Z҈#qF\ua}!HZuvzp2zk$;2&iɽƬɶ؞CJǂDbrK^eYʨA,^Ҕǁ]c>4ljvHlwQ5rmqz>]‚d%1#MZ%;G_a3dFFRxx"F.e#2D,@YvOC :u:G7֠b  "r"2DD{@j$jşH4{$l\ΐ!(\'cL""D$:yu8+(&dg'\R Qa_rԹ+{aӣ@ ĻJZv< s)|X='REȝ];}-c,{̟^CJaH塗HfGSa]=o$xwo,o"^"G5nk[D;">v )_#׻\*3[a?OZo˵~zQ w[~]䫯H o zfo𾷁w7Zv"yC\c+1aF{$ꔇ 柄Pf6 ;xjsC;vCea'T ~zᅅΓf![)sz3#?c5gn'Foo;[r s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]I 1c C=0HO1O!,,3\!? !!\\/tendstream endobj 252 0 obj 3422 endobj 253 0 obj<>/Dur 10/Trans<>>>>>endobj 254 0 obj<>stream xݿaC " ˴uCqH @I6 a"iT==Gef73owgfvI.|ӳx/|>Oǟnɢbs&Ͽ>~Vsc}Nj^>ݟ壯|C{>=.._xOg/ӓL3ߕ/ۿ>z9џOg8_nxI.(KeQei,DYEY(4QeQ&ʢ,DY(4Qei,ʢ,MEY((KeQeiԢDbNXdYENYQ9ZQFlJ꓊@2vňLE0_ʀ22D7#gf3e}ezbEwNSHc)0 (m4Me?mK&1e2j(cnezct)hƧ+ c0w;Ƴqr:gg ŝ!.ʛhpxּeRN302%y)ʇa̢\ %0QQ..F.);5n0lezr2hezq!+sDىG.kFbQ˙9u] Fj \Ng ֋ofc Vi|y`dQFU- .Tnܴ~ln[>j(,kY87yqP^Lܺ9ߴzLYp-p\ww>W([mp- iuY`mb<NSnQP1tɘ΂RneMw`r^4(V~GrEafp5ʭn&i@ʗ{?s}:;t;PmDy֪/f,[!MuI FBR-r6림Z 39ϥˍ0Ø|myin)0(vQf ֶs.07S{lLJp̶&‰rle R^l`쎋fc (mL1,L({l`-Lr$ge2 (Wyr傑 p Ƶ2@8QVfVܲV#婧 ep ƍ*.W0f֕-h =mʎelQv,3OR0[oxq,3Ocw1$)[LcZY B-rա^|Sv`NUʕG-Myj B9 Av8q|R\0N2 ۄ=}XDϔXwe0(-u$6e,3'Zrxlk9IcQvm5ZyF(+ObJ->ek_\eȢL_=RT~8OT޶Two-!/ ؕbe%ʀW9&VVʙ(rsv劍mˈǬO坃GYek2Յ8^C#2G9\_#s k2!luy,c:ں|WYE(OB~?or<,k8_g9YZlYe^PY)2nۿ}TWnL|8ZW&2z=P; u&f'ܻ;.gWcj,/\xT.3 ]ϲ{^^j_|e~Iaۿrc89,{s&rrpe帯2O]\V>4suEe?vuy5C9"˓!GÍ n]DoXq땾T)y\FzR)*Y*.+'^%#\Cr揲Rqm;̐eL`\8۪˱/-O03d`+CܪEVr2k}d#|eV%fQc?!nݢ?w W?{Rn|osƂAz8R2r:\"؇hW0(C vE( BN㎲qQ~ܸ?CePZ02r2C NY6o(秕ϓYCioD9 Wɘ`(9o9Ib,#eP\31)'SfNIV䷲̦{l=\q>g-/Vú2{s3FNLL]>i+ʙEvvcwlUe܋+=>vuq}uMKXfe/ 1Fy[rӒG٪rӛFvaM GW7s[rVߨ\N׌XdwfqausC\ޖopKzmQh{4mުofr ԜGl҉9!dnT66AkkZGHǨv7I/v@f 2>s|AP/ vL߷ýS,Gql(rL1n(w1wB EBЬ.(w/@n E5nّu<^+H:>+^͜G0 QgzQND/2UnD9_4aFWx.W4azpC&r 0vf4DyO۽Eyxam R:e1Jfp+ʃ ̀gkčfLeeBm<7GfDeI;2 b`*fmc'_k kY;{n(LiFC>;jzh:?Xdo`L04ѽ֙QQ ֋Ac{pb;49cC$Kg ND9Y 38eC 3%r;y2Zcn/&*a)_R2zCH();fp"[^G˃^QlGNyI1b >Mq^$pl)2B`(#X܍0 3AGiF~;*/s0x,[(:-d`[w)خ];-\ĉL(x1!,h ֣mZRdyiM9lq?r?KQu*Gy+\+֕V:S{ӢR{0tTފrUZE9Pe7?ʝ&ʢr{w;i`TPFAQt#9 3Kay z!P zׇLڰ1(Ron>*ѦѤH?ʏTrK6:Z.D;en.r s 2P0PI0SpS/K-*L-WOS(HUp-K+QO)I 25(\Cendstream endobj 255 0 obj 5430 endobj 256 0 obj<>/Dur 10/Trans<>>>>>endobj 257 0 obj<>stream xo =Enro$@Q-oE0QC%h3"p(3o7h{{~yw߬~yۻo߭ןVoKoWk^{}sr ۷5Cez?_}j_{y&ojeWWW~uJ ۀF !r!r!raC.B.B.†\ȅ\ȅ\ؐ !r!r!rmϛrc!mۨ\emvM>GVs-KcEW@`=rtFcJl?F]bu-su*NEo(/+3 <\>Wf~ϻ^jervk+Z^1`gh)M1`"_\T`y7*:C?lrHȗp;+d%[5QoT=3%mYRZQhrXgt5s,񭽂G>Ы"ʨ1"'TΈ*~L>FF[)4"_ɂFF\TNO)ɕWOHVs" (+v2ڔT+s02kmeQ'\V\d>z);.ksXL1z\*y튢]e2V?kabwC)9sPX$*݊$Nԫ#1 +#%;l!bۇ.7B-)qM3`\>!\?S o:pɶtc\myV^σpՑsenH&:YXΦ݌OLj9o4-}: :I'stq1\t e˥FrbyտTܳh@A]\ +_*. ˢ-7_gKOj'_\%+`{z#?\O%S=su\kYdzS>P2c͘ 5eK}1 jպx*j8L"J W2+P.qx9;Le\RHz(ςY22}zlp :J|hz.6tP=2)QQKg.xNG5J|ţWnF$߇Frp}5npuȟ׸3Η\|݄B bxgq\ &e@\n>[\` '\"˖C8+&`j:rwJ#W(دBmb\ˡr*kGc45gp:.\ \l m.F<)WOx{ot-k@8z~.s\*z_v͛AG.\2͠B-r9C|.kHD=cU"٫E^%g۪vCX<]rtx.ծǭ|<.tWtEb3`.'ޯ~ڵjysѫ1E[o]t ryX <C.D w;#T.jB]@|Ut @:s5ʵ]y> \mWgjΆr17+Cf"Qfȕy/[] \K\EGBPjv1jD\TVV L-Rƾn> 5/bLծy#qe<ķEҬ]n>a\K7bg_gعizD] b $tƕy;&Ee]и.dp-|qYFµey<#r .T\T { ~ty䊠,/.. k Z\ʅ=3T.q`q{uh.fU\i``rU`ꇀp=`2 \\D.MpA*Tҏ0境y즒%nV!T_{3b{#=z΍W!s}\߹Xu\l ]@\f\.\U.\;W#\z[Fp!WW3\e .2sr .f. ptbB9ݎKH:0>92f\K5y~FӭżqR1HL+Uӭf<?fdMH\ԍvtuL \Ҝ{ς!$%R1^$.qz.t[.Tc \L;+>Kiq l3MK3ݒK.%W,Bl2Isv:|ŋ9^Jh^5ʴ:u{ĕln-\^p6us\9 .ˤk˨ɕPWF--Wz^(+ns\ufԬ+Ez 2r0\_GW{<%K'UO ;+ϥfeı\q}xOL;`j=5cI[.Bl5:eEFNtrĶE\l>K\>+e>+ѱC6>ұsCx!\N\k=rAE+a5W\PsX; q0RxK^\)` \&C62r rt-Mč',]y\Ƨ2>өdtP7UB態U$w.{3EUw-2?\ t.M,g\׬r1Ի}*uF{~߼r]Cb>8$`4s\Yns@D\~ u%OGۄ;cObW\(KEO 9 as]$rsw77)5]=Oqx|Mc=r':\sw=KDQiwbp :p=*$E.x;r#/'|@ 1Ni'2?ws%M!ϥ|(O6D*D~4W3FES$dJcyxO'e$]x -H ]~Sq,\̽X2p\HjԴnIxFTKu]FO.8u/:rߧ,"$Q˞H1&ZH 9M5*A{>3IOkW:+.3,Qt8װSrVz:\nKq5m$7&פ]Y"Gۄ^0F^2W8& mA$ F9ѽΩǿ^4^&^x9T'-&`ZS]zӚ*#SZqɱ y_H֔\ǽa5-՚<]Iy\eBh\, ' \ɹXfrRvl&+g\}J}%5FC.Kr<BW r!r!r!6B.B.B.lȅ\ȅ\ȅ r!r!r!6B.B.B.lȅ\ȅ\ȅ r!r!r!6B.B.B.lr UoUwTP$:Jp (-1MI>gsJS)W,r?A9T^鉠T*ppegvIlRmi?ͼfy&ݗ%ppd9Hxl zbNPDst|38hq + ИU4f1+NpXSX*Dl(}/#o#`DKTƳ*3K0i 0X$ F1l: DCQEbP"9o,S$`X]Xs|. E'15fѰ )CAU HiNUAΉE; \N]'lHҢnEj놝D3CT,FP:ra t+L _K*)&LM(pT@a0Rиy#(lǎL~]I;Ýy0w.[7A5N)4 St [@4J  ׈ILyfAL<ߩt/(iw ݖPgq jjgrh} dK3PΡTT CPf#ˠ Lv,D7=Ј&ӡD/òIE Aj,oQ*%ښY]WLdI K$0zJc S}vyP~'Փcps6ܞ_,ؿ]URD˜RҜ[&܈C, 2[щ%w25zjVB҇\ٹ$~'a<y$a>E"geq?AÿNОBl8Fǧ{[Gnwo,mn$[6+Igr;yI-t“O|UnoI?U5*?<|[Iy@ekY_n6y䣞J{CJ_{^|AV}+RgjJv^[ e-2ʣ/âθ[lyM;Y TL/r#m/Z+D{ڗ^^$q3xn4jj#ߪ![!4vz}[[or s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]I Ac C=cB~YjQYfjB~VS\Cendstream endobj 258 0 obj 5778 endobj 259 0 obj<>/Dur 10/Trans<>>>>>endobj 260 0 obj<>stream xOofO0 '3^iV PTl{aHJS%Q#d'D~(C|߇ǯ=|}<<2~y/^>~ǿ=3 hs<.ǿ>}Gx4-1'y'-II y'yBII y'yBI'y'yBI;.RJI!"-h=mW(4gù_:tbIjFF h?%߇5SQ܈균uu=a=mk ܐs0KKI {aa_k )'TZU^3{\|DGiqi=c[c yG#4Oȓ $܈,s;SSxy.;gO;,oǔN3Ejg`،ۋϔ 'ovcʗ"O3ag LXWO~C\<&|naǘ<$yr|H'OT'd =e &OLTz=5VO v=fޛAwxThΞ]IJSif{13=Ӽ}s)%-⥞H#3#%ᙟgYO$NJғUZk»A+ΧȡD.Փo~t,sb핞'3T[g ~$O$Txyy'y'y'y94%y.u#;]b|`@ϡb)7O;ϸzװX{jo[{ƞzo`D~ ̉Bt'V^<#{zמ;6NT@_|_{ɞJ/?o J8Oӻ=Ÿo`"Sw;ڟkS{7[0ܞ^iE,DSg<<0dbl(ݳ=۷jwAϫ[<2dÞO)yk_ρoD61 tHBJf߈3aOcXpFbb9ߜ){5eC^`KƏXROX<}C!\4 ?]4O<}[J\#r`SWO;..O{C}KBn{Rx)zއy>SgـYД=R{nQ{&>m)lϧJE1(yK_cϯ:g#RyϗWs9;G*>e"2.x"8je, I΍<2|vTcy띹Gȩfhs.h#f3sm2=Zqp<2U@om>ҡtio!(ZM=a+Phgss[m3ƞ[I2:'y s{ϸ9w sψ'M3ZT~]<#A 8NC]CIk =W@皌pٲr=۴K8&AP97  eN'*C3+=CEe) `95-.k\Ė&X82,10sPωmS?/eiy\\/N, {%S1iyUb?i}(3cl։1=7ٯ Ue ID]}b{`b}$n߿MO׀ {`.A^XLy>flXRD5ȹSs)T rgz`\J V$,9CA A-бc٤ `ɾz9Z70-z&ak7JM5G=Hf,x2*#=VH1 瞥ގ48ґj+璮} %5>rSm6rS T*/yD=nQ_c'3P{N*6&zl ѹm=ێГ GGL-qURx.g |h]h@t6C1iE%+00Q< ㇹRhmN!` kچrPG$Հ lT7GT>nTɪ],\K؎>&\p)5cѩQq5ZvPfg lD İlEk_k{ sG gxD)¹Y⹰}Ʀ~(ћۏZ("ujVer)p9)ak#ѡ"/0%̩I%YvWԔ<)UԕA#[:,‱\p<ۖ_l\cZnCYmO|i0!;/&yKrO6/Paߣ(ژ)|rƉӘV2͹z".m7 g4U ]9p:lSԳq ]fq{^ Qs?#}xaR'>IŔ2r⡩ӘH N: Q"SݽMOOZ- ִVo8a-Vč3W~b"BRZx _ÅkW뉗x^NeUY݁}"=Wey֪77VI*תΝ+(kz.T־]]X][U!n;GV*p^xx~}~ſ ~XI(z$n EtmKu=SQ&./,KܺԭzD#Q25+kuU0[{>/Dur 10/Trans<>>>>>endobj 263 0 obj<>stream xOoU0oɅ` '@Q .C.ZM7q{I@{ @$_3tdˢ(wgxyI?y}irug{Q⩇Gϋo}|l<9{0=x=:zٷ_{%~/A~iҶ=@~>o?Mzo'|{odE"H$D"H$D"H$D"H$D"H$D"H$D"H$DmH-y/lڨW1LPo~yf?v/j?Yy%,[o|5bUv3+3{}ؖ3K/7bHU/mi1~\jaWݾ?'z]W ww 8|MJbkjX/N=Gonkӟ໦_qמoSПZПN9;}Pʟqc:?E)g5FόvׁO=&Cj`,_7x|D$~6Z?׶/`'Gw=VHWD?m7Mjc у> W߾f GrnXU}s{f4K}* Em/n~QߦOQg0&@_3ߤB?Y߅`mg"߉>m`Lmn__9\/{Xk>+> ?Z݌|NcgϞ[ ;n۝l!z ~Cs-#$y(] n ,`GH=;VGGԏ]]m}E+G[D.{gp=P{VkѬ#KemۣʕVQEo\Gӧ =N*̹5)g)lbd}6{) W4*1~dGOmT|mTA_'%[d%Ywk~]CsueܷL3g3z^٣z,%mrzdsa~XX_FIv?5w,b?|yh~r Fsקe;=s﯏?r~JUG6IMswl^)+Ҽ>ucQ/` v׳^wM<e;vWPw9vPWڢ[땣c6(zG:[ZwQ46U&R_7ovh7fm%Dn~ݭ{U5X|{(̟/ w]_-\']$?a7{(vx_wϏ.W[:u%.|6|~'eO\eoOe+|~3lL;3wń߁n0G7E3,1w?po$ OTW+RǏTs)duκ~[w??K4:_O:F:Ϟ;ITׅN:u%5Ou~͈?" ?Z?=i_G9#~;xgßs~S?#eg0\!zH6ù_sw쭾2?~O= bV}P ,cQox.EAJ9&޳?=>+k[L{?d5~oEτC:OSmoqIAjUҧ?m// ri~s,;o'!Oφ?=L>¨wqx9c%}~.#)|~YITܿߕJS!ep>П~À6}=iᇭ PMݿp.nU%3X OZx;n/^Li+.y pKq%7p\,er%{*S_Wמ`~Oh`kJw6`Bů-j/ _W/ l8z#kd . *TrWs_>'࿋ n4 |oK}orRB/}|_>~'M(I G @GblP'^(v憠ƏO?mG"?ܼ? o8}g͹n?d.n}qßjO_wncA7Kw@MTtkXm[[儭f@rsATs⒂ws? ] u);n\p.~6Uxz cKgiۂwh}*~t8w+l`;=ďP1GZ4$nhn*n1~7>573ؔ :k~A\?c0;8`Q<ü*ݍ3W۟;nx ls/~:yAiVPwr.9׭43t|G8䤴;qEin\8ЯKi@8٦-N[<68צ.PK 4ǭm>;`UpàN +Oԯ26B 2+V@Pc_Xt_aDEͷKvbq3A_F*? ~W4 }0Wih.0+xZ ~6-?lZ ~6-k-E_ `d kGGoo##E"H$D"H$D"H$D"H$D"H$D"H$D"H$D"xr SoEU!.HI\;]򣭭M[_8`^8NJS)W,r?A9T^鉠T*Vޕ;x:"ݕ{o7v!71d2䊑s:TZQlMj`M#e ) HPX{QGT(5(65GYdbI25X5 8Z㍨ڜ)5^AXjccՠ|DԹ5Y2NƳ1QR4iG!9#|CcX=a a2 ʞ!=i#t>܅Q1Φkǣ xOYw<v`17 ӳ) l qfbJς83\2$O>8 ^n p.ZPxFh6Ϡm2B3C{i&Vn[w/on >ոum^~%ʧ޷vIɗqvC& ?-I? H^yȶ<(w/_=Pa޲T|[=+FrXGfeoe=k^~]o[=Rka LZuPG,.9nnmwSJ&|]G&9dю+}iaΓ}FFdnحIӰI dStuwmXr -K0E]*MJcM}bM?~rrZGf 2!$M)ކ6aƂhfkzjUSʩo*%NE?: ~#qZIendstream endobj 264 0 obj 6013 endobj 265 0 obj<>/Dur 10/Trans<>>>>>endobj 266 0 obj<>stream xڤVoGw#^Z!Rw$⑀*)}8kPq@\˩PMP֊ov^8{tS" 8u4 twC_WP'iMx,$/ 2ٴ99z$Wm3M hO&*5(D]V 1)ܫ^ S"ʠ*: niE+i飩ྔ32P@´E cAHL%Q:PC%"VKU_yJI``uijF1n_hU-+f^XY]։m>5l:[0(&P[ױp9< oX~uwttU#b]&t? Y'}]łl\AϢY'X9M)w"YQ${#3J+U1x:s9\20&j6h녜(wlVjt"kD#?M #cQbٸMP yD渫>z5@-M#!D)wL `b=EV1O޺@C̶ (N5 x,ܐc0`TV}t@yz8Y-(3f,}>/Dur 10/Trans<>>>>>endobj 269 0 obj<>stream xLO`64=x,/+clKM;aă1J" $-]Ō4p?aUNΌM߾ۂ}ۧϷiڷ&3i0/#YTGI>ӹ4z-FQ\P3ČZBCdˉ+?3QE?|ydN3^GH)J*0IKOOŞG3O̘,V MVjKlu61نNڐzugEH`eDa6>/Dur 10/Trans<>>>>>endobj 272 0 obj<>stream xڥXn8}W1պҷh%@AS#n%)!Eb;6 Dg3"X ?XڱK7)['S> YQ>|ye |ಏ6,\1{zk*d20\^~<|f™>G fb -Pr [Y3p-|N7{dǽ{fUg0"cUmX 7K'A/7bH15/ڴe$Xb:dl{b1 Ńew`n ))NDAuԊO) џJ0:1xR?FW ՎmAV4\a^3rK s[wxx}&/yNS3?n~pne.z6xhCE/)Y s8$pd4IV,lf.h螲ȢG2k ƈl4b cQlx-[.~\ESsP;gKH T:1]\ibM!1>ɯBJ!9VQ=1-(X9v!b:"]ڞ..My! ,n L 9jQ2cNn\H=9b .nwڞw+^9%GDIs f fb2'o{^?\x($~QƖ}`guUfqL^dFfO+(8A 40 V~^1Ou'-RPq89y /0._P3tG.馱g$^F:]ې@7͸dark[_CFd1+alh/M;NA_̧QVidgpNhje14+ T?=y<8qA3MXf5}ЀhvNo|xm}[Az|.&3[[w?MQ\$lkz MvsMA 9ߌʚ^@qU5uvzwcendstream endobj 273 0 obj 1555 endobj 274 0 obj<>/Dur 10/Trans<>>>>>endobj 275 0 obj<>stream xڬXo_ !.E*W)Tk]$X*M]zP% )Je^M(CB}(ʅJ^Bt&Cw9XxGSVYp'hi[,dK;M#$- veϮ˫˗$0Zf˅u҉ o8M ]>%A$efsǂjt]M=VRU[]!;Z݊4w0NhQ r6M\cTJH5ɦsϯ, `MJ,),+ ɞf%t PT]E>`lUjrّFPp|ilEl f*6o &5m lXm8`FPMXWeGrX!wml$En3'ڳWzwv؃غֆL|jX*ofթ'5/X'14XċLzcp8p;HUKGOs$,&dxֲ - HiYi *`a1k.:G <:5?ƗK+YXoAgZ< Y{sFjr&0 ~ ߄_Uؕ]=rn9w9<+et$}ϝ<ʣ?LQ?yztڋXΝwN F/V'د zkF3_x$z{Gu;8_{nBJ?OO>QdN$-ZѾ:7>|b/hbG糉~Fͭ[W7>ݻDy7 __߻L(E7i9у}!S0>?}9ߥl Mc'tc!m)`]_[C _~;KBfo{:ߕŨGt GJ}]1 [߉яr s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]If ASXXhTJjIbfHkW ӞWendstream endobj 276 0 obj 2205 endobj 277 0 obj<>/Dur 10/Trans<>>>>>endobj 278 0 obj<>stream xڤWoBziaCERBˎ.upCrzfWFNAO6 C!(6T"[J 8}ofw)RR*@y{oo; 2|-.$,WRyHF3EHJ3Wa<<̾`[2)2YovTvdݛ+9 Q hH,`atqµ%RʨAKZt=&Gh]Z"THHRWfmѠ3!?V1,wGS#/3HRG\FA"# gXac9S?N̓%z1gKZ1]NFn'6ͭnB8.]6\}յ[Gf?<#h/ɢ&R< o[(>đGĞdu["a0t!;D1FlWx|u, cjFSpCvi:Lb3]0FY$͢ÈSo8dacGCǛ2e Oagި4$ 5 .Z⯞XU_+x]jY"&Sm=.(W_RTl;2Ȑ[.Wc HH`yr+ .ۗ58UdJ?Fo=h0u42Ua?ii[MgaͩXJ @ 9|y |v h#',h q5GɨE0 UO7:ڒ t0XST0`e'4D@#G&Y)lX؏n Ar > "Bw0s8%L8ьl"|fR]g4C8NFS~ FE;(0;]w3#bŘ!,iV-x;0sn4iŠB dAma NH :yNPyL_ @!R. CSpoA$l ֭o[P^%@ǛۂyEDHp~Fg#ى< 70j3yjñDZ ЀQh'8ExOTHe}0x#Ԕ4 B*fZմc J n%g޼z.* VxO kW_!Vc.oy1+ /^"J/=OOrӳ##98&=#iV.dS~{\˽'[y2D~iiw@ v~GG H<稹;?}ig;G{õA=7m_Aiz{ޯ޳{wK9>iMgnBO5>}N=᡾wp޶Q[J[CJOu$RO_ lrռߝJHKV끞=XYz8oo޹?V/r s 2P0PI03SOJM.QMKLOM+ 254(14q]Cpendstream endobj 279 0 obj 2072 endobj 280 0 obj<>/Dur 10/Trans<>>>>>endobj 281 0 obj<>stream xkhpSn:oBtSrW7 KHMjoX/B2-ȰK^ jOs!s(]d dE%}ۯ7#).GJ秿y7-\}OkHk~-[;zx~>}~1}~F/߼{7ptXFoy?߾i>|8=}ߝ߿;w>h nwawoN?>|8???oVw 6lذaÆ 6lذaÆ 6lذaÆ 6lذa&e[̓.]UU5Tښ\.B *%gkDȀMkeH֮U%W 뺟`JZN[dNJS$R^*gL(S":懆lN6x*TY;Pˇ;9UdNq#Rۿ(~.n&(\]Eʫ\:E}ՀJ 3_P-͙0hb1gc##o's X9ÚrJnv|a1g+;9̰9ܢdQ#cU{Jc;ݝZ=TMMh;@w%*AcrEWdsL*UL EPy U :,cO9g?Nb/*ƚyPyG!Wch\BVU5w~EŕscrƐF*ryڏߊxh{ |hN,Tx؂хr- |T=xm-[\ TNU6Jkʲ0Peǡ2*˲ʨʨ̿QQʷx[뒕=,+U& VWr~ʿrʛ6)|{M;hy!UX9r;VBvZP- ewW~\9+{ݸTN2N@dt4MͲN 1R''>dף˾+fo`Cъ+oT6 =& ŠĀr )~_i\eF 3wD\Wh<cΊgFLg1r(ζ߰i-d`fTW١*1KyI~ar!l_oφq%)K#]YRp9,mȘ(/Ʀ}wcT`e}>`f(Te`^+/k EIZSdܻ0Nw rrmmѭ;ҹ픰*u[e*xEʶp[4R~ٸTp<{>Els~hb̢ZH ي%NbP&\9 (`¤MtzȐ*3TRrZKɥ({\/[%)!Q1k)CN C<eORn\!MZYp97FFjB.uQȍDhHdjHy47P㞟 9Z;bg<䄳SA}o{!@mfs)#[2~S$Kr/۴Scm:Sl}P7k>"e7_,oƅ|yqVM"GhF9|4{?ʩe^ʮL )'}֝7P.mX}\t!GB[_RP!k߁^{1P9:_9KB˶CUZgNe*G1TN9''ے_V>`vyŔͶ}W;}[{;/_9gU 5-rZF4'* 2CAʹ:=ÐFn]YhlȢa`9KU͕s+}"gr~e~fV>\Of:)3QY{R:CYxG):%Pαa2ozeff툕L~9Kkpsꡲrޢ=ɔ*cWv <-TT.R>GbeeG@X9Z2)mUڔku[ZGOykP=QqeOe eN** 1er:eXyˈ%[A)'KV&({(sG87XSv&)TaQxگnU[d8bk}QVfޓFR.R-S<{-*WU~SkrkoI*WU~skǏr!t^<~n MwX9*e2=3d3puOORrjWFr_i 9 Iveo@D*QP.vI#13R2oפ剮 aKHH0^(#-_l&t槯[T ԠLe_h܃uz ;dI/-G-1,?WNhMš0:- Z$e: 7;K5\fI?9+ ['}4lD/ʅ#)3R~rLaM@E* \%)/^CӈcTz /_Mg0(]!-03# yoNP&'#aE*鳡X*fFBeebtٟl[rT併/pe:j%YrI4Z%FQr-.>+P6􋮴A'x{THZZk=kr[%eGirX׹y੉K|DN<#2hN4m@1YR;U+FYᮈu Feb6QqcV*s3lɣTL߲E`S;[*[-KsW6nc V*u)yN 6>۽ʼ#ʖLNuQrKZ-sɹHW-U +.Sj^ԢT?/ZExSk)wUٳP32UY3r ;e+o֍,z*oP?r@A٩\k;r W ]neF[nMi.ogh;|3ۍe5>SDC\9+U%Wğ`JԶ2r+T(\aD+ALf$4U PibP\ɮafBn P2+|YrY( 2vؕiRfKnQ7E\Ϟj[=iنy.2rr[08^k({[cL|Z]T^Pi:^X);mR>l+KNƜXcTPʴB:&e?WP)$v0[*7++RX@:R>R>`f] K9$mۨY"B#f\DY8 IJm;.c4OrgMRN-P]9K9x u*'meteYi%ڶqܱ,E)'*Ͷq+~eKe;082MB,b_ٕ6/N1?lyT6+kk8O(QْIo+o׷_NSʚySQ$S;%@ʮg>ZR,"/sSn#(KaTUֺ27v9`.!1}p;̘ʓZw)s cqeKȇǫ|*1 }>Q|`^WFcE9y7`De*C2q|cԕ<1q:tq㑡O62`|**ʅЉĘ(2cƹKrP{YlAezeexzBpl+N_cΆӣ/*{ٙ罳mȸg1"d ӦΡXtwqٿ|[6/ dbtmm`ǠAe\qfCAh#&vzuX:p&R>Dy<˺FLRwcGnSMHWD[l^SUK9,$2 !pSdܻ(PSeS˖p'K7ʏzIk=^NUvHctmIvN|ݠWYDѼ#ׄ]tѤʴ-T.K\{|1ker0)+Uf(;6}P`mLg CkӼSQl(1P\]/ez&rt/sv91V%אel Pm?G/ )v 3d1*:~yZQ$~WZ 6-,2\ a.bfLÜtl2[L1Y`gD咕fVˑQv-$Y, &L4*@{rZޑ\g"[%.jfIѳCUQ@ZSPHAb*F6*CAQY@eT%2PeQ\*Q̨\*Q̨\BJyDJyʕ}#; y܉ A岋o(C-KmWgGKbaLs*fMX%lSR+ѱF\żte ҘoҕK al2*m;b!k߁^{c``/f 2r3p3r%=`L9KҎ܌kF*o!"l#r-"1԰@cF bc Fj$aÆ 6lذaÆ 6lr VMoGvGB*#NAJAB*D,!@jUw_]3"zZ**?*k95UP#Thg;~<3d:7NӤIj0ɤI@dС8#.%TX%,I%@PjF%UsxPiEƅOܾWkv m|NXs`*QuR.<3MTݽR9qUMyf<r2$p-LX= 14}<2g_EͱAu8E,wdfɓ˓Q~V+SɁ1銸]iQ;Gnׂ!*"2A>p(RY@Ov/plcgR[&΅ʞ QjPU H-KeQ{2TT$R1, #ƌdYNl3m)wJ;Nn1#iH3%Y|tqzjm#MNL~(W(CGli92;83-27:䤦̐ Q"OƟPMnA+ru :hw{hu6 ]BˉamɕAD?۷;פ|\R>46VեF˛˃~VEKMK?k>_\ƺz,?>{}jͷ= ]m_-2+ 6kz׿|CᾨZΤ|.Ol,;GD^S>,{Cu-{=N7MyWDpe*FͰ$G7d~7"Bdj("&ϋ7&덵p{6n jȦu^۠r -A0D=,uA[ܪɿ@RBmd^fމzTG]oAf~8L0ѥ+6j]pWwnSX~4kEl2TJv{~ڲO>/Dur 10/Trans<>>>>>endobj 284 0 obj<>stream xڔXoBզ:@3 X$~ڑT/N!*x?ESГMBh=? .|͵9ŅAF7%W+Fjg͛y;TH_ $?jT 9b3Ҙ͊[Y/b^Zi9i͐ؖ p.tMLqI:s۲-قChT .LGS9hP JP588JɔXG}ϳ3j,8jբPZ֙'XRٌKBD0QJ]nd'R(a}.v!3@&l(<4?htr6($ GSYAՇ 3s7 A#Л<ɢS4Y_q3KtE?"o=啳kg]Ҷ7˥69ʙҊܒ0cS&&6\_!ba5: ZBd Й rtzl]H 3a%zhU0f#l u9vu7f28M&S< nXe83n"&tRTlZ.܈2iu[IZ D%UDc`@" Юy 9QD daN&aCVDnX. 5\"l #vMjN_]q&!tyfŅDo0ذ"D9,d.LWZ E{׶{~B-R=x1RۦM! I GZ{M*StO5Q*|8ZdWAdMci(~lhu̠ ױO@8LzpW'L=9YSs`MB2޻<:6ɼB &ʆ[$M#j|GJL։>BPEg T vD tiSCkAbV 1LCrTF BreUK_f~%},o5xX Nu//vdIWܟzMEoS?2zdEG]=5=V^ƫi{wGO~zէfև>z{}F0;?=o=9xdsߡ县ߚ@n~ Ow~rӗb4?y+c?f[>O9{zN*w_= _ߙ:3'zu#LK<7}2F=+CĢ}ߙM!| G~}Vսr s 2P0PI03SOJM.QMKLOM+ 254(1q]Cendstream endobj 285 0 obj 2208 endobj 286 0 obj<>/Dur 10/Trans<>>>>>endobj 287 0 obj<>stream xڬXoBzia (B!!?-+ ɒ# KiA:/w]QjZ9=.C‡\S]8$n*H]rԤ@qv޼{oxB2>5Ac>&'IxOLQ2RRdlⅅu88XNY]79^#E^BadA⋳L] 8qlFDA-+Kg2쯿9 Q+ s8֝ عt 74-t8Ҭ٦G<|X.%\`ZρQbܱq n 8!ZP64&PPi4Œ /P;π!p]6%BshV <ԑU72O85@.@ӎSbHLCɤrwZvYQ՗CD0ݑY5Ui::lPy$YGE{T):~)39vvU퉪)c %y 薨K No'mظvgx.% j,3 _#"hf.ڳY9lLDxHV!+Fø'`B1mS iZj2h]jrQ HE\f8N&-f{6NYdz*z[a7:0h.@ .ݘf &(XޘFF1KmՔtHPr`$ 꿜d #S#Isf#j:q-4kae6oJThsP"ө6g _d$g4 &+Da49#o,zMVZS'd*>'R9uL߀ `ʦP(NĀe}nXcζM_c2#[mC891 ND@vE/=pvx dVHxh 2cAT"Y^F pW@BZb.Q57X7 8y] &4B`k]VhDJ@jyrOR.8l`|U`aN@Dt #n/|G*H j]([* *\|: Z*bظf9{y3H0F Mƭ-l*9HT1* E&`,҄J3Xw986XI#uEXw2Rn=.,{];$I]DJSwQH1zL ŽK0ww(hDђnN!npf ҭyu-.ҕ!Vgs9V3'6@J@DQ UКń9U0HcZk+F32O,h`ñ,8_D"39 !՚h;g+Kk7V_(tuZ( A=Zt= Av DDkJ (VUsd‹#dY(Pkʔ{ \bXgX$'k7UGs0:fhQnۥj7qD@[d(_n Vm{#ib6"+ FW)ğWko$V7.KK)xWĊ@%^$^&c$EV\dJO_s/y98ރ?]l]J^{Wzz[~/do?޽)ܻov_ǵG})w;=ߩjVpVBz?: ӻɘaSKD5Ij3T[28YPF-薛endstream endobj 288 0 obj 2344 endobj 289 0 obj<>/Dur 10/Trans<>>>>>endobj 290 0 obj<>stream xXoBzia0bK.X@Z m;h|m B{!qCPmͩDR@$Dc)S]9T2h={3{o޼7sZÀRoZD#AE]~BI3[,_>,{)*ZA kifNf5+Rn3k?_^ =2yC\Rdb Ic A[wx20aluA2b4hj* ͈(ZIlR 22۷7 JMjvȳ[csigoޛľM]yM8 ">a-%VjL>'[}d{(H=pOk9aa6솋dZIJ'I Fva-?nح@.e-ԥAo`z 9L͢v&u}FifS:G&(Z/e,I^Qp6!WL`.%{6HE(֞vmAxhb=wQ@N`n&B؋ߡaRZ"ڎ]8!MG0 &HؾxXN[!QW(]{*v~A+؂PVF2-m⁑3hGjŵT+p&Uѫ CxTPr>NȕG+W2Ԭ1&q8 u]ɨ g}Hy!g*'[occás CN$M/C9RXj51]J7)]J(]UQ))r29$&d?Rb8Ft^Urɽڳ*Wz+tKzrR71x= QQqQeDI B7ྀ (TeWj3[(r<F>9R71R{L񃓞M ^jx~tx 064 PyhZ5iHĔH,,T+ݤ,_GTB}xbD~\K  :pYDO^36ijtE'<>$Gǹe}ӳ|3 ODvÜ&z;aHs˙|Rpe'J!Nf<"O |KMTCIa9 |{ T BdIEAcی8b%Q'sb --bLScdNwzNɶI%er)PCX?B`b;Ķ#[+۝3UQsaΉ=m/+],݋ *0F :̲QPoҤcbHb Z"Uœ6ShCW|Xh>eWo$[^|\ïYi v$&ķ Wj-pnyxonai,}= >Krj$=\^߹qBz87֣߯< ?罿?:|w8w{_qiT[).|+n}c`g/vq+ ZAwKi~s?vk﷝[BZlmq|핝q6ŭ;޽{#~_%3w z<:hfpXw›\J7C<9 _"c Wl|wEi,v~ȗ{%/~)W< )釷[WGIr s 2P0PI03S(/,L- 254!\\4endstream endobj 291 0 obj 2121 endobj 292 0 obj<>/Dur 10/Trans<>>>>>endobj 293 0 obj<>stream xkoؙ`4|E}cϥb:ч]`hdȒF8d1BҤx;s_ʖ-QÇ{xxxW;Fw'w^}kci䩗Lx6@OwmGgáqn{~X,x_KvKxt֟70cy\':l^ r /_'LJ_%/GG7vv#%Ïw^nяql' 5 ... `... `...;ڶ\X:tXUw4䪬kQI\C+4r*3Zɩ53袸v˩0j ĵsBW۽N%pKe.KЫǸىuS|^2ݻPߋLX-0PWǷ-"\ ^FK +6f؉,WC-^!sL\<h+|y[E'D 5t=?1 8=CH.{26',Wt7^bryG<c4ᥫ\!ȳW?ERi:qy;q%Kq.(pU'c2b M.T=nLD+\٪sWUC~Jr1v ,OFQ}Ӄ'U=Z5#cMnʾQfi/}H;/i0N7p5A8[Ÿrjpj6 O\Dĕ%:\cոx0spW_!.>3!'qO!.NGpeة\A .N]tSיʸԉ.^Uu Xު]κRƥL-#ҧKc/B%D py<]D7^˽)\[\7_(ų"q* /sIUQwy{etF%9\ +ng]\ p0z| /ٹx+]tP-9; n:Pyȕ>{u5|wnL~4\{By.%څ+] n\uWw=~\wu"]8d@b.'OzE\wq,+}.Z8BC]t+\U}r C_=RU%3\d.nRr;\"òWTમ$Lū`JpE8ϕGBVZtKȕTdūduѕ廉tݥ>d5qr.<ѵ]owA'!W_WXo-⣦tW*$°Zd.Ĝ;S԰>o*YWTwuuW7]qy(/GE-]w+opQF.QIƒ-..3S..)⣫ ɸWxV.T"\A~.q *_\&['ݕ3, ׀| HrՎC-Peٸ"MhT#?[uXg<ɮqXKv.!8vv]|\%Z\\2-ɹJ FQV.) Wx(=ן˹~,WrV'׬˔K.~t%{;Kw/WղLD;ؕk$+u\ J4Z$r-'M>g?HW;\ \W&MH/"׼{$[7+3[Nԝvfd,V!B؉]%pXΕeZ\qh2;.Nj%N .ٹROK,̒1wWlk:^27F\#r[G9댥+AvFkkc [skHd\9V\]T;pn8.N r׽T+\\\:pr Jڎ7֩s45^R̩n.5Ÿҧe*2sj;b,d-0jWՀKF kɹ4]/-t*ixd-܀ޤjvʝut iKӀKZqia/JF܎3yyq5$d+Wk5҈mrnGᒾ G6.y Ⓕ2Ke.+/.L䮼LRKʋK˗˔+K.骮\#ڇޗ˔+.jUn$FN._N.YVZ\}9UW.W,~ƫ`r˱.,ebm;3懲K3m.V.d}XdaD){.ح6\Qi.q=m:pIl\_pkw]\"W7 \}|\|7ߏk$Tk$Gtqޒ>HbQo&*OR皋Go}W #*HT2g. X+G@0sqߛ6kutFw.Sv.M 5TgEI1U=ݧ^gg\S.+zչ$|q\~p+쳮.#"/enKQuw8Ar5\Nas(E((͎~Tt4!\rBpsBp9@<8Ew6tx̯wUO pY4uDXcQ`=514)%w8Ne Zb;\3N4B-O`A18!x6I?q+Pd+\?rvI LEǕq"M)%Oj.S?9;WG;pbϓ *](HCn%6⪘$f^%)2dWe > OC(“ڡQ< GO$^?d\!/EM]Y,I82 sriuD}^SbA=%kr5ʵ|ϓ~pş=K7HUoj5^ʥbj7YL$WMnSD6zEjxf[^))5]%&K/JH([Gy.q/Ӕ_i/ڸ4l^Rir%&j;D|k\ń)V[nd:}Z xS*Vk\y߄'(u0%672V\H'_RV%E%ρ+JZr^e 曦Zs񎾵^+6b ,xp1%N9Q*Ms]P^oʮqZ(0(Թ-VtְV]1-Q4}t.ܙ1V0U b̌Xj vrFܗ)H.|zrIX?.Dj?#+hOjq}p/bo{ |on]ڌF|n%yD|n^K|hI0R0A +;:W7{? Qw5@ Ѽ]mH;ʷ<>rZތc.nHIr1X>I>1 fT%\07D^hW o_^Abw'1׽v>0w#䡏;B71.y}.v7r -0>ō:P[gMĹPB )׊廻| g :JރysH}Shw q̙RX~[ErRK>/Dur 10/Trans<>>>>>endobj 296 0 obj<>stream xMs#Gr! 8#ѷ䕭VFeic {3d rG"TW7Aۉ^xO~>}GN{qh=}?7o/ywWo/?7ۿ}e/~k ؿ럿ۛ7?￿ywyӫޔ{Տ5o^r˿?޼>-5M_sx#z[_^\}߿/_^O^ugig#??<7߾_t|}T>~iW_}_|Q%}[^W^<|,[Jo7{'T z>83SH}^PնlB܇iݽL|d=p wd's#ρ _"wuL{{%PE'!w;udѦޏ?r 93=곢f2nJGRC3xg SVc \wzl]֯<3fh"̑ .djLeB>nU\k#w?SFλh˶lމ:2^ͅ|#w;3s^ҽ5?8L+NRZ#<3 ީCP>|a&ƉteqxM=JixG!jb'w)Xan?azBql෉Qяgw:9sZ΋"n}B}&f";~lS{tJꌒZ <ĕ>Zb'7qŮ)U_{Ye=i=,UhOmUrWYuw.x4J%\iS^J} {ZWBy hU^4E^'XelgZw/zɘ8̧sUN111q`D #ʥ]"~.ag>@Fdy}[Fet,o5*ge`ܛ^sVdF0s>IȔrsb% rmmb|Tz\E /}_Nq6Ps UPܖY§}VN ]1l\liŵ 5gL0p3v۶Ks6ɷ4iӑ8adU?@y3ݝ*^K }$x}?E;U^엵G_tA 循=nCg[wqGi3IInqjZ4ymQ/}!]u2w]"3w V9w ˾sA9Cd#OQ{\%ǖzb  I+^xե׷bL7*,)%O['g.w'+Nq+Y 6᧌>/VϘnH8^\ ~t=D]]{ӫT=;m@͚}mbUK^5=m \w }#(\5l4'Zj]*nnF.]cN1z$]T"`WGgJzFrkgG#_r_Z@N^JOAw|Kyt. INRҲVnr"Z P:M4zm0v𥗤'Io/y'Zl 2fdj-awtnܖB_%;r NWo27qreL8+z廛u36 brܺl2Ij>Xu ;eA]oWv[E^J#2 {#3FI2|rsB6S~Y~ms83cVQ1GN^ 81tl~MmhNu:3Һ*T=23gw?2YU1MsmLu\`iwB%1"L 1[{Xh-ւ}򡪑39Tx?3uJ"(.Kp𽲵lYW}}EtYu<[.OZ(7M U1TvR3( &SIC?-TA͋ZJﲨnJΥ˪LW7rY,g:PU[WjgwWwm7$$]`2w73!{>f ^K|]q֨:XV}umC93k#uk)c^ߓO3cU5DlgrKǤ{gth47.>OF%=YO 6TQo⸻L-kױE톟wQe#Ry憮yiTgMU*@SKf'We$S)gfN0W!KeQ?V ox) ^ggT{[83GDZnOnVޡf{ l|EӼW7^6>A 2l>)܂D&ٝA=YWޏ7]nrϒ3c&RyE?t:.`\-eF}q!r0)%CK4U9awm)nuEQdz& x/ÃUsy{bE|O8Oʂ~^,*?WAdF-.LhC6^ҿWOBU&~Q L;k^.Z&9A;-Jo]i}I4OFz[q!E=khK5Lo؛&s$ϴ [*L UO dKaw':lG0`̳}gFtMo;UpqGt}ܶ/Gw{m.*,̖nĠܮ&VN+KU$gfRqcmpb^ܶZ~;7`$2Sxxv<Cwq_ty4.^ץm`=w(uJnghY b@byciYs;Q٨r2_(y/`?n~jhѪF:@T3Z+h*IE;9.YwqB=7\w؏Nr!ffD .OMW)3=oi!Y%M3ι3C=0uK|\K#\׮u~8)43KΌqjrܸL!j Y\܅%5.gujz4m`VyޣeNӛk;]' K7KX] W"OSmE6ΐx5ƫپZ)\Z%.q/ȫ_+s潟܋ _i>F~K)30̔vjںſLNR'v5:I OOʖ MĊscM e Si,ރ,X9 :U3.诨$^]7߫sq/OIb)>g/=WK52 %ۋ-R^xas̵ȪAR>ZC/S7\?ڥJ-Xq+-*m6TӵҞwƶ5ӷAw?Zj 3;`G~kOax뭵vukkb?3eyg)kqxcw sɽpýrq_>unn$WS+g^OV 3𞱡7Lo^#>EԪݹhdzv#ok+.:G[異0¶vǘJNю yr/A0]N6TiNjG'ORKknRwi*9v=/&I'LjG^"X6gRG2'= {ɘy1d 3f.hy^5M>C [TQvqn86\.mn3_ ܜ*V3A쑙qwo^z\F/w?f/1yd83,^ Qj]Ir/z~ݜ~]kдqw/Dm\1է>fFXtgT&zҕ'.o󊨵au!ꩤJ䭽/ ׶aL >YLzG?Kp=0) 0RݫʈTx%nLu Xd%3ȟ<} Ӿ.ˉF~ŲcjՏ6-qyj6Kр~5hq}frOWô)1s21 ?uwش>-vnXnf06+qs/&)|Vd&svѺ{=}&kIqF\aӾhͰW(;awj&o$XLoDLD0d"NF jf)r4}ՙɱ6{JNL*#wô|w/b/w[Ľ\R1{0eܛ]aӾs(\'əYLNج&ڋkUbz&ʪ|wʹfTey)aӾUC`}\B,bkDJٛU t'(Q rLwK mVdHzGQOgr>ute!Z983p >F{Okv1UKKY p;O1T{`{]o{aGY~1JIެRSgB5ۥEIuƬ-rYpĚT5jP"wOּ7,Hm;<ĠR)6 $+guW:}ér,~tpN~oTuC;ipqXO]8Y5g/[}맗.1pr/kAEN 8QPy/`]̬uݰf<9.|q+S붡_ך+dK 'r%0PMɽtr/;<2T]]Ⱥ_:'?T]5PuVa?1?CU89ޙrl*TӕE^kAkwٞP.SqjnÉqkO.], V\Vׁ#Z[wo4''5Y8Aˣe`3wAOO}r@Br@@ w 2 wDf w;T;rxgܻ&Nd^xs Hu X6k|$q RG%,sa4_ڦjgt}$ Jr7~u=f\;= S6?x7zt;qtG363;d7j Oolv`qZlX@vH-7ұ'$tw@ل?v_'m»ky.z`o%wEmRdwÏru)wDԝ|3n{2 d%S5xMw'E!D+݌T0ٳ!5-ՙUvŴ%ӉLI"26-2$LjU4[K6H[ZhLn&Kdd?[eG(~Oơڦ fakG(nxޛ@R-(LT z6ybmMQQ T|JFT =O )B!#~O&~Pp1;ۥRm9.lt:xأ$tГ^8FPCGujY>C (tB P C 9HEr,iY;s_uL03RQꐭ"VGUaQ/TbU@CUP.6 ЃfG?_X:V%ϛ|A $))M ] &`"X1_w q[^6Kāꆫ-* P K@=yݸ h8*E7qulgwhAh,Fh3Pxd D4:yHߪw{2SɜJWqbU ۿp@@)mf[h %B׀ X$X`L"{݅Qh> )Ӄ5AH+eTK0ԑaN&wKe* HbjEXBnx5 ;:9|ENeo:-Z?il2v8RMP+?&m&LJ94qw#}q??ȗV;F`qloZ8O=sڥ? k!yթ-~?˟rWv_\z'Ϝ V󠹷$=ka~s/粻?T拥hf{͵wO=X{٣%Z=&fm7oq֞[[n㏜y~ٕev'+'|9\9@q{u>/Dur 10/Trans<>>>>>endobj 299 0 obj<>stream xڬXKoBՇݴ0\*̈/=,vq*%y 5wFUЕMBh]d^Ef۬Aq+U DB߹([j4};|\nLY*>dE4e ֘,G%Vf{ryˊx|`V*W>}f^K0.kq^`N6q|ܲj\WlKZBi7=؊u\gS񦶣_vR]\}krz1:tڦE_*g9K2k Xa3ٴ M)WiʲP8VEg-<6>V)NdtlkIɶZl1r| _#a4 jJp q6n5- Z #]S(@8Dn:M[h"Y0R`k nkv2ijjiLқ+ eGpؼfl ]Qr+6vv@6BA vg|UTMӡ9>*uѐ@"`mruQ7*xodqepQG*@qSWƺCD/ Q.8Tǒ/ObGuu:8!)ĆF !QksQBK(c7uZ0DŽVoRca;8DKrhpC@ 'GQ%Ӗ͖G~>B%a:jkx#n]žlv蘂qMSQ.W4<`,2 OsxJ)vhY, PpBި;HLLjqLꔨ7| ˔b$K V`Wc4b[J/+:؞}lVoq t._~m. usMv? CX̝HS>iZL=Lݧ PJ:-]"t2زO,F)bMJ;-8p|xHjP7Yih>ʠzըF[stlŘ7kLb<ՒĥPvZP~tbqKP"w (! "KEi*7yт0ج(AOK“gNZ7Ҕ=+MW"Uʓ b: UM|2IőgQ-q-A:/ i3tZ)q QzDjPA*1sG.HĸKn0'l+دFV!,D_;uugy)t cƈzB8:`&B^-d$^Ia^AA {dL-fRZ/%#bBg#=?R=wR૖C|J&櫡tIb_|d'U-9+sGF\ # 㞉:φ5(: $"#hDY[g.͟;wδáLw̝ [;DF=/DL/LWLۄf)r _eevrWu+ ,t[@ҌEטH-ٖQ{-osYNZy3CN_\XyhD]\NJP<ǝ@ZAp,"_ȺDV^B)gZ_~'#5\&XXybO"kcvJd?@unzWP}c/]b;•?eэ7vǩoXHΖrHncr'Ե2sͬܺJ/_^Ϭ0O̫ܙ\e%d0{1tT:gpt$;=t?.]HFo_ol3}KOߝ> ^c ϻヌIXe|}Կۣz ?f7Ǿ7{';wG_~h|w ֿhvo[7h4o/v{|ܽ `Nc;n093,GA)->x4h Ѿh~{w)y?=S8:Na%~0u G ۽Gwwno8r -A Db(E&uB1[L޼ 3FZ >.N9,!' s!ry,mz9(';nKoQoګ2 Z6x˽ {.endstream endobj 300 0 obj 2409 endobj 301 0 obj<>/Dur 10/Trans<>>>>>endobj 302 0 obj<>stream xڭWo6bh8j8Z[ЮZ%"*I5{GJv$N?, Y"w=};8I.#|_] ~Ϯr4$+i~0tziqjm'ohpdG }>]Jh!]e.&x{Ix8œrdфKԙ&RI~)h%imߔ2)V)h΢d2`xǏ|p|+%d$RʲSa W^"*S m6ڑB]ɕӣ>-Ò蓠^.ռc05@h{2+xEFԫ7+}C*YXQ ZyuxFw},AV曝3V@8P0u.LE)ibP$@et6(9r.E>`K^a![u]p!u3g zʁAުO/D #bSn'gnsf̀/zJS͸FURxW rK&˦Ž'laG^ŢduA{ճ:Uナ#{uP"see$Z! P *7&_Q2m; }Q +th!4BP4L f1JP~rL-:?hU33@VN@XԡO_n~RjTn`!Ak ]f&JM˹B .˵JT3FR^A`$صrp\;h:~wM;gty:OZ}/͇~s̥p\5hG4[fv!Nu'N=?tztᏽ47l?ǪcUy?vz:Ԫ7YT@q[@ޥnLH>`*Xˢ)E*KtZ58_O>?~==devDzKJ}+s+ntp-:t WHB'pD>/Dur 10/Trans<>>>>>endobj 305 0 obj<>stream xWoEwPDȁ  iQG?H궉hP[Qpvwݙ8 (+DQ+ e8;YuJHf{y>7MFpW&[CY޳Mځ\C9(v" {@eatm,HD*,Jز3kPsNܱ♡,ڞ˪5ӳ'Re'TGS5e^]liĮFN N*h$L_r[ofOoWA' "1.S EHtjȡ͗PUbGG|Id.[Q\jpZ^܊,JP>/_ '|%}.c26"!spJRshv]sVVi՟ 9P;dr)b6YGnD"  wTԲLG9GpROrwRW>ቃ`4Ctt(o`gYz&Cz-}''~X1eacSy.WF nF{!6,d6-Ǖ hm<&.oB:0ԑA3򱢐F5) GN̫'_+lDNT6WA5G>2x ! kUh<@~ M'=)%Kc}@nѨuE\Jf4=LjRϪHڒ|!5&-51T8@ÂݝZeNm<`񘇭8ZRʘ/`@uqlRL ٧*f i870[%{.aiqRS=P@`5e-(6`$B231D79qNxno뚚Le›PYL]-,iiVZVy,cV yvl+ԝsA\ uXz;PkmTǷ^@&a$ 'MC7} ) F8@TzNz9ݰ 痭A]욖lRepBXjT!G̕t?j8Z/nЎuϚm+tat 69+9ax~Pr6c `<|mcjMۄFG3OJӇV(gOanr2ju%W.C;&Y{sOZD*u2O)d^?|M?3]dN=#h́GkАEJ??mNNϦDҭnq@\}կt+xŸAqW_~.n{-W/`Bo䭒n~۾5`AxmwVp$ߵ Ϭ>c֯Rz5Qǁ`{~S q1oajumJ/#]ZȮ%nB qw˰XLl{ApO|8/c`U\ ae&Ň:JJp~E:J;=0ڡxʅL-UpJZҪXZj^ion,kcW?r s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]IFf A#XDO!<$9#X!R!"15+ *3endstream endobj 306 0 obj 1895 endobj 307 0 obj<>/Dur 10/Trans<>>>>>endobj 308 0 obj<>stream xڴXoFՇ0LmP%bDzx KaCrz6r z)\ąA6p!hHU]zW (),wv158bpen;57f :Wlr {2arYgUpS6%*̬9!鱆pmϱeɚ]aܕSa~FYK.״ZLuH|邩enxF980fsZJv`Kv:Ti=2v17oԅ{Q~%C4evNi$MOd,wjS}kLdI|L"vi9W tgA#%\C˼&K<ڞ=Qf*X#Җ/ |dx)io"@i*jjۼ*`@jxcUQ~T$Tglĕqb B.6X`˱?@6$+[i`FKm5a%ipO D"Lχ^ Y{(>AAI)z 'k5mxCYR 8~@8.I7pt ,e!|sfg_Bk&ғhMM[(D郘%yI| AK:SE*:k&$["茒*br2 j!RGϸxdLPe"Z!4HN9r(7Z,^Y*Wl"4:H0x_:@t)=/L6$)E%pkDLPU*:h7U+cʏ`UznBIO]U`R ~˱~eM,Ă d,)^]"M4؞Eޤy&)ea9 lF~h0b~@:t;hTrNrЭڢ|lfÇqWΦTtR WGn#rT1R(UYF#g )=4 !,UE5Ē@Jحz! 0gP QvWTeMO:l$Ej\R BBnr9vy\OcbMz8 ZWeS n8P{(yް$YI&PT#̒rZK@}j2@/E%B!x<>|~B,~Mɳ.체L#D T1(H?Qߊ#nPO$% QfPF;[8efUYFq'[?A5p^im$5 R{ty!J:(+ܓ( Jyr|@Cth U' ? st)<_uz\0|؄x2=E#:`GiMMCc] &O~%gntJ#ѬxYFC Bӊ9Ŗc~!etd4шiZV,q ӹ)6tHVqi@ܶ#} B-'nMsLO,oܸ~ sŠJG)]Zzc8vEB_Xn nsclrjK,ϊOW w쯞;ϭjO&'Wf.czgZ=f{<,l{ӽ|' ?o?0{AjdAxkmFP_mnNguzgjulKֿhvg}Ϳhuo/֟1y8~ܾ.~~wަp0d/OO';޳`Kw @9mk/{k;a>^-\x,lh{ƯQh淿}yw^SlooIvýDw{R:a7>/Dur 10/Trans<>>>>>endobj 311 0 obj<>stream xڬnUBP%8*⨩i/  bQWe<ϸHjZuXuKQQ[]-ŠV*(${g. 1>s=לJ%&oYML]~Ƨa*@yHLV:R}ccS`YS[%|pA7d-fF %3-˕=Ssu, &˖1Ty!J@S B ,SM&c_mb1jZf6jjE Q#QV\I~.x*9ށK(WL(C} [ #cOՊiO J$:SöF1jFΌk"Dā@F#0n>^ZjD5Y$TWvsbf#`y|}RAGܒj̄e0^6/vաco2 Jfk. ӥl̲\Pku>(9tuhcV%Fؠl|AX0?Yƕ6EH95`fyK왔rBf9Yr[=͵l =+I%tgJ ! q([[2XQ XFgTҒJFpM ӡAGΐB&ʿ젟d/PD6ɲЍlZN^X8ɨJ !!Jg9@iف]IˎKIݲ]`:՗ۖUd5J9{]a cPCg B+qdޕ\'}! Ai;@dg5ZI 4] ʆZ`h?g,ޱ?(./]72\ܪKe&aTc"m-kD#gv ˳b~j"F(ML0} Yz-l$=RW "K-r(#EscbBݶXĬ]Ul⋻T&5,q1fifge&^"62aCx\fsu|[ET 9Akbg 2quCX5w  :+8jPe>"Wu\sy_Wo {O3}OW7;~=mom|xW =l~ }Do7+bS $“Q\e9toNޠGbk*}/tK֟[jp>Jse)]il|s2hus)<>:ּ5G/^ڼ܊ S o0]A~=OVEH zmEx^ .lR%65Ӻ !nGox,`nʃ9Ay6)-M[5io?t> ͻzrpi~r s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]IF As 0DXO!$37$̅˞endstream endobj 312 0 obj 1945 endobj 313 0 obj<>/Dur 10/Trans<>>>>>endobj 314 0 obj<>stream xڤWoBզ:@ (R$eIdɔc&`pwHnCbU)צp!r>EڜA q*U DBNߛJP徝7ޛ]e/x9;^r75;3gP׏a,%ܖÇܖ,y.ѥ7r06#$RkR&r9^a@HؙIy;ry2Zi`.%iס^f[&`Tle0/=Klg w}KĆ<ࢨrWHkwcg"jPHhǰCȬ#zJ}0*! ǫo9<>y' Rx>'|˼.Ä>#1 A$H+Px,Jpo @y.I_A 0ۑdͺ(ܑ~A&rsnt=iՙLwEڜBw6VF7v)F CAp@߳{Xp,|@L ÆKqF+_ev!eľ(s 5˯nb6wJ hwl)f,7h c4:5F/:kICGHɜӴ Ŷ=awo}S̆ū/_2(ºiqbPۘCݿx@X^Am0w >$͝R`X^JX 22i*6Q=OD6tDe_mGG^lɿJW}RdQp$'ӰO,wl"rnlD [/aQzj[֘#UlWT٨9MqPWʽ:lfp8#.D4JaQQI]8$^ Cm)u)9 q:ٌg5ˀέq2pS$EƠi8Xxyg WT9!rgmvvM`iŧ{/M*jF2%kꞡc#8BsB<_CUAg ,NG(' C} p8לTOSO Ze*o!(,=)'ΘKh\wJ #^quδo-yVX67 }bxʋz,OL өNL. %6hmDb./ LNk^Js-f/ݼ]޸z/_ǿ蓿Y<+lLk01%|e[|eHKiFbpTmuP/ 'Wt=5k߈zH|O O OUwQO|xQL+>nZn>\P6kݻ-&>l(a8Po3  z9aތk{j>/Dur 10/Trans<>>>>>endobj 317 0 obj<>stream xڬXoBդ:@3a HB$~VXCզEݡ8~P;Y76r z)\ąA6p!hJU{3wILkv{ޛ~\g|gHB35;EfΝ!#ႾU g__ jy<ɞ%ee{r/5\ގt,:O& 3i#~H'Y@߯&\Z'ss 28C3y,:NlhLk%HJA({BRa6);a2YmAjnUUe+FdƉWiKZ҇]=¶"ODFrXT,Y?*eKdf=&"- *KSzK0F"*R*&UޠB@G~kT`/dHpb0;/gUٖDXC%X . z+U蒶I=[ *$UȴoГIR[ fHTkqЄDR g:6H1wHLAP­:='!ƪE(tb-#Uݞ'À9 'Dmׇ8p!uĺ0n9@Al'#u+uZȭU1Z 'uy/Lk\V=snƽR9KC8Mhpű-^8C(}IiSWLup+_bF",)qE7.댼owUBy#庮 MwPb˜?ocr69oQhfL`!PӕpH xlX1V3W*%=9rۡ6M !q aF3u 8㡏AcK PnP91zFC(N\Z֣ Ț BXC:c~LRl^%jBL 5R32QYLp{bxZ'8Qe/uǡ4ZជklFX(b3B-ռY%^[2NI#GjO:8sۈ`@:lbuUù]Z^#gfy%lVF[ʽ|Rڕҥ1%"^fsW٩şL dê=0𜊮j v{z6wV?-^ĿG  | RsoYhܽ>WJ}x:?GC %ڛO,6m6Y};{Wͽ7rw;cojG~W_\j[P4n_ڽ% ~P[QS nX}1TC_mԝC̵; %u}cWՍ6WUjEi[iUEʧPcfHkY5UK&ת~`Ǭ~p}՝3r s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]I As 0DXO!$37$TXendstream endobj 318 0 obj 2319 endobj 319 0 obj<>/Dur 10/Trans<>>>>>endobj 320 0 obj<>stream xڴWoBzia8E!?dɒB / ,r(nήEZ9=.C‡\S]84n*HfvIJ6C$xft𱈏+,be..֜Gv"Y&peeR6YMdȃ0jv/lR3ܘ}/}F/gseTgw:neG9p޶vx׶2 EtIdvIa^Ck5Z|[02JGvmR9ٮ__Hl~̏!mWrszsk=wQ>ܗ vvDp JW Q/,Ҝ-8,lْI+aR5v\ `frlmm..;Pk-POaw]5צK!&(@$ksEv[~vbÂ$Hx` )&7I3.-طDΐ9 c%݈Gi=u{U9 Y"׸C wgb'-<^cmCd#ihAVKRӀ-u`$ &"0,MHI3RTٵ&*X[K%x_ }A6Raqqlצi^ m!#m.kf@/\ɍ"ɀbd5FG :#K$=Ȩqʱ<%ѡ1qmI՚ 3t_,^,.x;R^РˬG ҽ5!E߈-mR,U_\]2{}t?)UK?zmU^v_s姥*Mt:TZqUXj01J~;15331?qzI?v?xb'_{2Du}P`V~GGs=OEjs?S?JcNxw@c}<mM}Yov׿FTwR/v{>Uz|01aW)[}<'u[SHꅮl?`PkPR;GZS;GZOU'VW_k~Q53^o{'c5?`꫙~ww6Xr s 2P0PI03SM-* 254!\\endstream endobj 321 0 obj 2120 endobj 322 0 obj<>/Dur 10/Trans<>>>>>endobj 323 0 obj<>stream xڔXoFziaE%Rԇ%1۱c|q|roW4FNAO6 C!(6T"SJ`yow)( o9oof~37Ƨy9|;~ o~ifP/GE=E567V9k֪(0;g-3O,X-\ :E(Nɓ3s$G"|{^ C6\ .k@)D5Q%jsq+@lp H?U-2/Mx4qU` ope((O Mxyʂsa2 0ΰؙImٰtyQ* $pE(D2AC]%  F0ס%WeDZ1x#4^.O* ,sgt -]ׂ:fWD@qCA$R:=gRE{®CnrEɱ:ץ̠آ .unp)Lγg^6p0q=8P$q*r[FИ5yMkeo@C%QŤ4gma6RP =,T ʓ婬}HI"clԲJt:(,@gQ )NCcDF̖^UB_GqF P ?-d lfQDo4prZ *L [瘮;#.Y<)t0]p+M,VL=KO=dXfCa arP$q?d%d`y>qdg?UAUb٠6WKkRI ǏеDz?#Y f'zsXT"DT qZ)i$]bZLIc4 ڦ^fib NJ$Hɇ&Sio)A ?#3nFs╌lI+&q9o6hGpȽye:Z*\V\)`xHa8YeN)&=,dy2dfB sf\-bW, 6/6hX\B|up(H' Uڿ|M diR΁=ƸV u*^ЄPaHNކ\g-l2tؗ:qЯh, w5N*~d:〭ogaFI#;eY*YvN+I9AvC[ze3QYUtuhlOJmR-3),9h;H*Ñxt_xn?򒎉p-,~k"G笊Í-O:bPI$W@8@kr[T]gt#BHjūHE_Ez?躢` &ҟpMiRIZn$r~:=Ŀ3'RU~p+*7gᄇv̭&4 3Ž Tb5FvTsbSۅרisޒzV 篾YX-sP<}bk* 5ԽTsx,Ql(~ucտ'E[OjV-,OGO޿q/z86?>ݽ}ֹ]֓ؑ:Qѭ/Ec;ǟS/u^/O\}~7`Ӡ|ߣO,Y=v/^uݾ_u,:ojw?X1wG;;6it;kVݨ{2_Gv꧷Yr s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]IF ASS0DDOS_<$9#$_9endstream endobj 324 0 obj 2588 endobj 325 0 obj<>/Dur 10/Trans<>>>>>endobj 326 0 obj<>stream xWoU !k {ai52FqlbĖV!G90(&{<~$ʂ+dZ *Zy܏cOAag^šb~j2ӠP$LOš24f`8},whn qwmSEΏRpQ!g;\.8TcEs ^N0Ty+ @_Vp[PFi'/SoYmZu6sOZS߷jz; T!9 Awa62&`i #ϝ;:2{R9j3Jó!=)6e +n0W<,V%dH[&.P'gnZ%jV-f4gVSBWB >30W8b YVlx$J-ρU~ߝ9Kǡ4gRy>'98ؓۅ d O>sWD!1+K5X+G4Q.Yz!c0d41.XqZHS`fgH `QY0 T<=L!}: J[ݕn뵭= +mx{HOuz}[7^x$d~~sv\」ov=K]yp7Z ov諑nmй5ߐzc{v7XA:lVۿqCkͿ5?>;ko6+oEw_]o_՟W3ZlXgz('3h[_Jf!6qҖK%]]:])ԛ?M-hv`n,m=XzEGхX͕3׾or s 2P0PI03SW(O,IH-* 254!\\endstream endobj 327 0 obj 1842 endobj 328 0 obj<>/Dur 10/Trans<>>>>>endobj 329 0 obj<>stream xڌWoBziayVj($ƢX;pwVhwޙ-SГMBh=? .|͵9ՅAVh Q;}3CJ"%JZ {3{y3{w¯ -C?s0;5o` ./aXoaXzfs .#p|N\T.3Py Vi(_=z: >|y\A+IX%##skPv0H! C0_R!s2 GOˌó 4Dnx ;mp3LGod%3iCHPQSCXIFȎJt72_q=g: x$8,!Л 2!B CYx]\DH/,@\$ QjXKwamn٫_4V"ggah9C(y6dsV)ucбjd=wT. <.Ъ)8Uꬴ&NŰb~[JNfDe<~c9 jyFvK%u$uzU `,\la+GQgV/&9bQ?0ς~)sg04y䶖t4˸ `.=+eP'5ntJw+iC4WJ fT$LQyA95ApH c Tx,M!sD49&$ `F!$(A(BB.]>ƺP2  ?vm{B DI.Bh%y($)sQK,Y=Tn*77o~L2ϣ&`:(V|Y;F+`* 5Vc@,$~V>zϡQQU,zc{ÐqaqPkVhW҃8NOyJ5?LB[Hʟ L~ꭋ VzAjXhˎD,E$d&:"KWGaCBi0 m.삞Kv^XE:`n̜ȥ-؊&$.z:/˞Mk[1f )Z_"Hy=k5ElZP;TbR\+>jɔuvb/ܱXJ4Î^2BnyI \e4fJ/Ƣhԫb Rii ?4}d[}$CvR7Uendstream endobj 330 0 obj 1920 endobj 331 0 obj<>/Dur 10/Trans<>>>>>endobj 332 0 obj<>stream xtXoF>@3pXheIk!v,[F"(h!9+a#'_…^{ȡ@\qks ƍ%0 ~ofcˠ43o|{jyacgYdU/ͳŹ ֘6ְ,Tby50ykSlz1:[%ZDɰħnLV骝9M3.{ ?=ru_IaƒYf3ɢ9T^"맊VVXuŴ Dܒa0cf#䛫aCŮsYW%T_'N̩J V.EɠϺTpq![.,8S?3=rA<+>39gEF)gk*Mc@\X^e(S%3c%"B"^,f< eDŽ-mHESbKvO'a!,Uwk?`|C$-ݖ T$2 ؖ5xC!M4?n#l.7 \ZR_' $%Se Q<p0p!|*Bext^/K9:['5(]@Pq4 FnA ar ^+R!G)Pud K"~Z·'b%p>p8Aqε,6-4 M\38Uf ޵[ ΐ[:`p+0*91 t )rb#d]]<}uLl1B࠳!cXB|҄@S­)ʃ ]f+F hK/ 7?Az4/U-/~dF^BsI.Hq|KA]9X-=o5@Kc0bt ,D[(CaαlS4怱cLgge hQ1sn}JI}K!5kUܵ3 !unb48RQ@ o,glHQ':DǠ[`4OK:bDúZ){xdRfV$ZDKksY*mt%ܦ*EB'<$gŻK׎x3kyrR#Ņ;{u@ulc=[k&6;OJQ38T٫WϞ ijYD睞;Sg 4]u0 !D N!&7Nj P'}7ZxjK+οUYeq*W|µl:&&^Lݿ^ڛ8zl4OadltOFep#ޑ^w6F&&y凃M?K{^w'z4wx4>8Ǿ{:̻ïv֞;q^O{{wGP/Az}`?}wǢl?I?'mЍzM,z]3oՎҧY;꧇鱧j;M:ߎ~|kp/r s 2P0PI033SpT-)LL+Q(N-*K- 25436q]C=رendstream endobj 333 0 obj 2618 endobj 334 0 obj<>/Dur 10/Trans<>>>>>endobj 335 0 obj<>stream xڔXoB6:@3P B(~SB 42b9n2J[-w0MSГMBh=? .|͵9ŅAF!2I⛙{orw>(|c-w~5 rjΧReW؟֚\,?-y%,5pxkz VKEmlYt_Zz>)Nt =Zx vlg8WnJRFmbN=z*WqaxJ1JwI/dKH7Z~{ؼbC 0udXg`34*Q[ȷLU\N,<3,[CiQNMbyîǔB ^M+Ҋr=5IoccW0}[ Ljw$_LZT&3i!4 4 WYa+BjHnv,ņ hl M%1"U `MwU5f1BLn|аg),N`$ȜEf6u.Df!mh42B\#MasǰmCs(fdes:u2ӰH.2TfV&)_|zr\i+dV/+t,(Vڵ\i;cו.,"rmIknc5zAMA1-"[_RMZPTlN-ki"sm4baO)O)uv!OST`Gis mCLD9>ƑU`#opW8XϨfK9wfXD4ŧs~Ԝx8ڻE6 ش }r)+Epɱ5YWs hF-=SpĂ ck0R$$mnx¯ 6F7l0P>D[6Iµ3l\& &Cֹ"n(,BC ,c&KgK1SjyrfqjrSMQ<\5#=.Yt&a CM/T;fd^0ux@q0)vQH|mC0pܱEXgpn82 =Bqv䩏q@ -Hhaa1#="ﰈ5v׉%܈Cy"k[+cqD] 5u2GFp GlDE4v9lq9t>+?_K ~J 'c+)Z= sEFTdWe0eP rzi4 dP3Oחk]M* ]7k)rYLBmvZOOFm~HV2T(OY5~z|(}iJUBI +<|uQ4y-Gc#. G/*,}{eԣqq9%g~DW{w>C-.WN=:xhΧ ߲>}k{ ?=9!> ~/95?iߌzw?gF dxS\Aw;O{"z?z0sGO 'Ogz4'g@}'ApDQw[4-[!գGx.z7[_'z = t@Npo gwۛG+r -A0D=,uAUKIpI/`KB>-׊ɛV3 U#fm6B!°&&{~xoCp#vHs&MrՃ(֣TչTe*d%qO.ڧy</봸endstream endobj 336 0 obj 2225 endobj 337 0 obj<>/Dur 10/Trans<>>>>>endobj 338 0 obj<>stream xڌX͏_dE(C.%4첻,K+Y)dV!%553eca䓕8"Z%|`"Vd_㓉bbV,W= XL{W֗v:bű#"RoG;cxñ117+ػL _^VBB:2F<%ZwwC,zQ؉_6[$2pkXk#a +AXot9ƾYqx)n)G&:Tv+7W[E*MFH:ULJCVC$mb9Ӑ6TcS$ ɨ;Z o3:Ntb/~Y"Sc'Qjk }]vSSNHyj6@߂,85!LȨ Eq2?(JfęJra,"E' ]`i8l{VUr5x5g@JYl ʿd81cSQnjCָ`+] -ʔm,9YX+:q[H!LD| !ѱdIG1$aZh =-iP^qV/,3])VU)H%..I^ؖ,QlRll ά+YKvhD0ڢ<'js`fr|q@) }p1RhP"lJFK:(TQchȸ: ut[Ѩ4U]M(E})4(<˹Xڟ[99\ToeYC_l*~60Yی|$Df-A|F.,de}Si97hzhtP>TaS I|-C+A4Ei&Q7WƒW&l+ckbٍ7OسP_CQRP_W$2길(1B%u1[TtiڎvX 2F^PԚ*&٠ {m&W׍ ec̍'ǯA;p9A _ʛ 9 ~i ٣|qиzx S0>ȕ˲sČ^łKh" O=wDR81O!nJY*R࡙NEP2 iE9Fl{%tOUfRe7Ya-@3p5 St邑*&T椧in;&i䠵Mkh< H0C[.ѼėGé;[N^ $KRg@WOGI6g?_#~rRL#S,4k;vsK9v;-%3rnřdmh:&\ߚ~ @0M)s1? ,*[1ۓC }i8&)\/ aNWH%0`)Ohla7H[Bnb"(LP$nh>DQ'asw6U;8Mh8,Ozkެbzn-wk$-/Y;Cq 7Ԟz~N8hv0I}WđcY~̸ ˋx_Z;=n\kZWNgWϾN U#ˍsb~q1'^ޗ^L0N?^3}^hbu;ʁbu{Ӄ=o_ZݝpV7,m޻'oݚV~>y]l/;[Ww{wov>mڮÿ~C~?;W{6wo/Z?|ڻ𽇿N8ڼbkέ]`nMh"郩ۣ ttaw81Vcgc4NٴQJo>JӫF2_O{n#7\ G+_t>yg`q$ݿ=oW;nɧƮ~FعmW߿>var s 2P0PI03SpH.-*NRH,.KW(-N-RHI,I 25456q]CY(Nendstream endobj 339 0 obj 2722 endobj 340 0 obj<>/Dur 10/Trans<>>>>>endobj 341 0 obj<>stream xڤWoGwGB*OU|DAZuՎxzٍ!zZ*TP-rj "Thͬb@z{oޛߛlk}{.)dZQ˟kC8>],v,Z7ePmQpj3bh2fSN}BK:mz4f85gmtN`s0n01=ECGIƝ 9vLgWv@@7i4`dw?R5B(A K4Nj&<5(PЉ 9+2E5w,I*,G!U<᜙Ĥ"KT0^G'man{_+ή}UD g\Muʦ« x4Qu5A@jDwЩfB8z`.PAqF9i;Pz,>mP8RC5d13-0X BۦjSSG,RU .V*`YXy2յ!ʈ.b,s$ڑIf%;,_Jzڲwbmyvs2i][`w' ɏTQe~&TLP=ƒq˛v'R뻓+ {}ia4>pU"@P vzLJ8`om춈FT^yIk=ЅwbKآ[SC@h^z"۟B 0XjC䮛ґįcKV`z/;ɫ|;=Yl4v0$K7 ~F;T3;>s_nF?n~$GT>"ͭ_bMiQ,mnYʭvפ}MnI\"7#߸.7.݌#cuTBgBP:h^)-7{+?Һ@*hxk_҇sӫ r s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]I AS#XDLO3%'U<$9#5+ [30endstream endobj 342 0 obj 1774 endobj 343 0 obj<>/Dur 10/Trans<>>>>>endobj 344 0 obj<>stream xڴVoGwGB*I&$^ۉ"$H 0p&뱳~8j=p@*ʵ*ڤe8;}|j/RY[kvޛf7-~0Ol n0(d"4 '-7o C o2g|0&Iĝ'>1ב) Hԗ|8T?CqpNeG+HiY2z΂1AS䵰дD,7s -]XLwAJ-^%iA~qQ+;G346VP'*r'IbHdT!9l[q@=ҹ:M\3%5 S؜AJ:q TѐD6EjtU{vv=AԔ Ii$LIAp2ƴH"g˶4pE%S΀@$*NZƢ*q[ x:U8aj„)j`$fr<#7^0;UΑVI斬a6 \"S ^(7>k dJ4Z֙|R햤PSu"~ -ދpNGMp_I9Jr*ZERy04Exw%.N } i+ #qy4Hk~ ) :c W[qA9W J<9UpyI\-.9G;hr"VĮ:ӫ,~eӫ@O.+fEG Ie%<˫F{'u\.xʬy顋qΖ=3{x r s 2P0PI03SK,LLIU(O,IH-* 254(1q]C;mendstream endobj 345 0 obj 1418 endobj 346 0 obj<>/Dur 10/Trans<>>>>>endobj 347 0 obj<>stream xڼWOG7*TVH+AZwH4Ub)e=m]; ('MEer*Q6RE -ԉXfofmlTuly7os Wo7ԅSOa௻:A'0K^m G=A`{Q6jc#E"piZD=E:R.y'2ӰBm:ۧBjJ:v.TBWB K:$$*qdcm`_+GU;1tHo (4;egc(!]vBIE,U\EX $0 Ka$5i\WA\2η.x}>m1zjGPU 3Ѵk@507h?x\]vkuz8_ciPGgX`c% R4!"Q 1K@g )L@m:.2q}rOTvT)Ď,*J25(Lt*[)\M*v RP'zZoJKe(HP ېpܮ ΢c,"{P#Ulx0d}*)(Jzħ`hr\혎j!1M|"Ř]'PT%RLOvDB15\"q?J aT׵,@};-v)׾-xZ cQ)أk|$$sW?()1W{:@y9r"VwwJDܡP=Z.8q6EGO^O|o)v ;p>Ļ-@ԐQ+kMm)jjy J IPǨ eHa:\g0|}=66 Q/14ljx=qu?Wpga2QxD>1jS;77ޡ:W6͇wԖοm_Ϟ33y>x=dBW=5e;UP[٭8k|9㍬,/w3R:һULg>0Et2MⷺT}6v{d;=1W=cQd _Y#s4e1s&f [鶬֬SKS,&gsRUgQ ^mε^Me!k̦|6fYx̰/eL?Jԇ?6/r -A Db(VnM[M@ z}%ɻ][A/I45Ho/pwnxFZ3Ѡ\]i6[DUDߤ\*u@AJ8>>Gk;iendstream endobj 348 0 obj 1473 endobj 349 0 obj<>/Dur 10/Trans<>>>>>endobj 350 0 obj<>stream xڜOQƧ!>p!#D#DjM_LBҰ"؊4u? b@J ZH{3CI0sg;{w&3,.03qA n{ ڒlN MfCa6VXy&8!B| 5,bt<N IIB@i=_c#b2jၦF)9'4@Z Ē;VK8v66vk eQ{e;[riBBe3dD D d*ISp&&oܭxl8LC;wu[$fX-l9mR H8ac-$W{Hk=.A}*p,M|PiΒ:l-$Hnn׫m2eI̹AZ9>jVYR֌4繁G%)j墺WŊzK#CN\!5*Mȹҫ/T2*\%eRGs;y_A*bx9[HsU87Xj V')Q5iB+8")-tNK8EGh=8ZTH'%z|zAِ}z\0{*XER$fZgHCy,+7r s 2P0PI0ѳSp//-P(O,IH-* 254!\\tq'endstream endobj 351 0 obj 766 endobj 352 0 obj<>/Dur 10/Trans<>>>>>endobj 353 0 obj<>stream xLO`64=x,/+clKM;aă1J" $-]Ō4p?aUNΌM߾ۂ}ۧϷiڷ&3i0/#YTGI>ӹ4z-FQ\P3ČZBCdˉ+?3QE?|ydN3^GH)J*0IKOOŞG3O̘,V MVjKlu61نNڐzugEH`eDa6>/Dur 10/Trans<>>>>>endobj 356 0 obj<>stream xڝXo6?b.ZnܞԷqzh-6YtI> %+)^)2Eμ vp'z dVƧ?Ӱ!#iym.ͱ ˾aDMХo!?WnH#R i{A/~a>= _EkiN N'Ov2uaFT,- JBK4,9B6EZAQ1pFDϬX1,#'Fy\,qRDt(0 \-fFv(H$%ƿzɤnencsF-2'ִϝFN c`4kݸ7 eJn&Eg⨏{qmQ!mJaP7GaH*NdsW_ yM~+)[KWexSB9;ΠK;%mpG۬ s'B|r 9잤ߐ?%MUԮpC`U丨}Pׅ'\pv ?'ܛ=rZ[OʶxoB;_Zd+DVCQa+?ΚzJ~Uߙ_: PܣC̿(Y5P9VҾRIߜiþkDbٖto7H8ڷy/4^0țNPl%`:=O#9$g)RlY%HX|^vLe`R5)R@ԊI{jǹXSFHR,(I+Yr _H5;UNgsȀt2^$#-)]ݩ\NS[3pMFF)h ,Be1:Fh5Kn/`.3 _0x zc_2cAb.ktM(ͫ-8׷,Jy!$3¨,)`Y}JJ>/Dur 10/Trans<>>>>>endobj 359 0 obj<>stream xڤXoB$:@2p*%)ۑG]RC8Crzw4FNAO6 C!("J%D,.%JqHb7PW IxqTS'iT+":UV/BZ-ڙ̮riS/v注M-"ΐ1'^i \V&F^[``rd^eVCbԻ1YʖR65)бҳ*AG.!N(beܨWi& hXMd0"&қ6̹KuXc}l\t%|R8<\BhgR}!97򉌛>qX R.2g$r 6B (W}JaeChx໇DzO3fK*Օ2,L`IleHd5$5Q$ ubi0.A)>p]׉S.s=TC $C2ZQGOb^#.XӀ$R̷̄!$!P!U4H<y7(6u<\Up 5t"%wu3O.Q(:+5SQ%Ρ e'nJ 1ljNrUPf=:lT9QƼ, ΀m&/,^o{.?Ph& \ІjON(YԆ ;NGY)[6ek9T#ti٘*P@ FUNd&s8|!`L .SLgG2=җGS2 REMZ-*M-^f;i+ydkһ(mM\97pJFXp+]3RG1~tzI XTŃF^ygW$ExXZgJS?̌|,ϭ>+gQ ExGdMd'g/CE|~Ls DIb}Oz,J^6Fd2maQ}xޝB|ܾ!,?Ep}.*'Aۙ'ۆk[M9׶ןi+%v~߇DZ;>cX-Z^XXz$jF#b+4E.l}_BVkc4g$]1:I-_zG["ٛ׶n?~r -A0D=,uj,KMpɿ@c?XB_+&ovgP>zva}oz1޻YF9S|1VO6AkΧ>6aUblѱIxBK>wJendstream endobj 360 0 obj 2011 endobj 361 0 obj<>/Dur 10/Trans<>>>>>endobj 362 0 obj<>stream xڴWoBմ:@ 0JKRDRlYvxF zw;$'zgWFNAO6 C!(6T"[J 8yo\k|,ogG/Cfg`.7>pVeauܖW20gLz u+N 1G'`Ra|KU`t2d6I[H??=><-ǟQfbS|Dg&S=OO_̂({uy~[P&sMn,6Yĭom[ O].-1l/ۡ方LW}0JBM2WO."ȀIBdeWfAr:jvK7ΈcX/.@ťdRL\wS!ºS]f+<1]d-nT7bbPQTC? 5CJd4G?s\37Hʂ0W0#e"jBeA*$DP/4+P5= efS)ur8NOV3ƴ+ Ksӈpq$`6:9BZGWELamvй(pܦ֗P mu/|jnfRrūLHL^b>|b`X\ ,!6LådrR lϫb%mDrLP Ѳzpnr6TDz& x2?.sQlfFeQu&!O@!Æl@ұG{D \n |+к.v鞫;8x3b1Yc;Ȱbu馰Ü jA+0n*.!(l۫1ָ&sƅrhګTW\{׹o7PNjs8 :1]=,8RU㒞3=(HwT]HZBs0OЩ$B8qţ*etf Mz_r5'*~d@ИMxN1(d;N\B׊IDش;,V6r;%L 1ɗ XG/>sx70Lnek{S/N(,]LPѓm8=Of6wٙ7K}qJ00=t}/iȱuc9{?.WgwLÁo5~QCskcԣ |G/wopWJ}x:ܡzxaPFg[k}stǚ=k9awkkpy3?zǃ}~=4oo?~qgyyoY}Ҹ^]yo`RnK}6v5;cGꙆjj;G\nջQԝցv6ZUluonEע^ihPcOuHk:F>Knh>؏nze"kr s 2P0PI03Sp.-.ͬJ, 254H!\\q/:$endstream endobj 363 0 obj 2075 endobj 364 0 obj<>/Dur 10/Trans<>>>>>endobj 365 0 obj<>stream xڔVOG7*TKHͧ$ & UޱDj1޲cvf14MPNQO6U*^{ȡ@RUIks*QPԤ0;ff<8.1݂&,͂$1 mI}x̗b9EfE`X@&rȳ"!V.Ј 33E*j S%znzv.mR83uֈneYgkKLn4l*]-MN#\a'e0VH7-=Wᄉpv3f )v,]d)ooESx'\6E>ex2Uؑ]&ePDǎlZf] j#xkF9XLMIT ?Q.T.Iue>TK)8R\}-% ګRqj9ۈlXL7y(FÛ*oA4&* vj3Sxm)>njmc jV|P=J@U9X61F(E5UgԞ ^sk+zֳ?)T^%Y{VMM7'b0$M_YCAW5tܝP(Zya5FY rp}4/;:Yyum(CALu rx ng&o`Gȣ_sEja01Zk8Em3iI˩j09lVNul[E2+[`US3KyEL4{&r1{m|7GWh*0%KfU<a8a4,?$ao|A"pVEb `W*"F|WB\3cE m J ̄M(Zu83&p}[V/fXbsӸ L[WlNk-MAT F F t?I#ц+d9H?# jUCptҧœ?vb(,: vhtuGOA[Gt ΰ ǕnqK.AM=A-:5{N[oP-wf9zL3wn˹kwCJܽ5}PO܇yקfWgJq.xЛe+_]Y$Ң+ﭔSu37u4]wVT}yfGvg|f^_(헏iy~7TؕF:BNJ\[7D>rF=oIޜ $ox2F.'=F\\iߔszK/Gn7J "Wecy-J,WZz祇KѴwҭr s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]I&f A XTXO$?7*$3?5+ fendstream endobj 366 0 obj 1637 endobj 367 0 obj<>/Dur 10/Trans<>>>>>endobj 368 0 obj<>stream xڭXksF_qi?a8JfC:g:kim/bwv{X@v{5mo'2KlLрA4},$.fNhSF.,YOB8.]{%D)fGQ}ɣwPrqg.V2qL[,e5܂C)boT_ˎ7S҈<~9]|ɃG$ ѠCX59pRvJnztϼpN i8CTI}Lk*gKI\蘿(2UnN @8|O~9MDt$>R-qY}wHAhJ `Ns0eS:Tz3jr %1t\֙<>DJ X)iaNs_r\.UQԤ`/ %{$W3 Ns}EAU!?nJ .p%P|!Wλ5)7, hFB*h=nŰ)6]~%͒psˀ2z/w m7;z%ڱd KlU@U2hj5 Y6a>ȣEܕ{ @C` MDsp.ow$dbXjkezvnV+[zCZYD]vg*`v̈́v$ ͱh!0Af#z+֜*)*ցC_AC>^ЮgfAz!@PKQeÈ;S]缩b8ʴ0:x-\b"l23W^̃i=~sne7QV~\c31Du[4("Be`#`(: j;#jsew 0E1x{ƍ [@;TZ6 |7aǖ,;o7i>=s X梉~3h&Z\wJӎ^`~2O'a,~o,ECCO:v][=uku;XZيxJ_гg[K>xDrzZc &6LJg`waq:9W챹s4Ŭ[i: nR{4̎~}"9ލf)|Sfct+Թ=f⬓T| lnjqշvȟoDǍ5"5?jɻoTwendstream endobj 369 0 obj 1725 endobj 370 0 obj<>/Dur 10/Trans<>>>/Annots 164 0 R>>endobj 371 0 obj<>stream xڜXoFzia@.dv%YI,Ċ,9ErimkSk9 "nsmNq Bи^A͐%Cg{sĴ5?G2 s D4-Α:N9|6  |V4MւS!%bC=yR:v49[6kv38znQi4~j߰5a^fW 7μT0Tx0D~BBΈyX1D.vXKFg8 mJEy=0IIE  M#H6 z͹CqmF`$UѬ_$kҨxnHqtY@FAt]n.i7Iq!شH9m 4@%@#V.H@}f60VІ*O"Φ #=Ŋ zC[m"k He/PtZ ApN6}PTMS09rmɨI m.m 'U6L1 / x˩&s5%Քh=]D0*9l[xЦ빪n+1,"]0p;°jxZN.ZÄTAf򭠄W ;tam40m&0 ̺q|hyTy$MgJ}$*Q\B": Nn0AƙCBmqsH1Qע,y0ᘳISH*d6ܧMAD(P r!im*ڹ mkbg ٞ X6\m͢鮑|I7QIA]/k5Lէ=-eP;DAHϣ̂&u\MY2×?p58J@9*^+d.ʼe݆eTRFF4>zhGe_.1; [s7n02GM >[ 5Dj 7Tz&7|J 5fft  OQ kn %RrmJ]!ru."lŖ :4aŦp(̰$V`3K@o[5NZ d-v(ۨM,5[e[2a7P 7qz`p6^O!miur'p8XRl6Q~QW9YR;}qa Vif/$m;racuӢ>TT1܀M}tظ}z:y\}ĘӜqy4YcFtvCK> 15~nf {ʴʊf?):F((} 5u)5эd%ri$r2[@s3'-Zdinٚs:"‚M*JKj۵ps,EsՐ;D(k]^~ BBC5"$iTCIjawD:$@*.t՞,-Q ]>(J tAycÜL lE>47ꗺ L!Fw\']88ֺ2گ#Y84&1]0z)DnR{JtgUHeN0)':}S(*7tl )KM9ΕeE. ;TC/IQtHtABha`ܡ¡sa?,YՕPTFy\},ókMGO>HFxw`o[63?3f'.`pc{5r s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]I& AK0LO!Y1$, endstream endobj 372 0 obj 2849 endobj 373 0 obj<>/Dur 10/Trans<>>>>>endobj 374 0 obj<>stream xO0Q)8ҤPAҖmB#=L-:MnҰĥFOU='t"@Ljϭ=;̹^W+xXۀJY\ z9T56%ذmbul&\Dg }_P@ҿT/R6sGDg\vF'BѬe~cAaFc>܇(7\ޣ8ߠY w~M^Q*̴V ֯,مH{/5yANReENA3+;bG\1jぎL0`81D1&܂c^mrzA! .xIq8$Q'Ԓ玫ri^k\JyZO_ 5{GfץTdju]L7aysއJlBj{P}AdAdAdA1(G2(dAOp&G.)5 فv4Ql87&`՞~CD2 7h_KdqP1{4j86i8 pC2pTǬ(^Wlp5z_A 2 A;g*Ø nȸ1 sj֖WdAs>J!lـ>ꅂ~iꊌnep,Y }pҐuPj麚W;tڕj?%dAdAdAd?r MoHpqj%|6'y $j҅.7ZmW+ܢ">'OcJXp] (?/NK"5 ]1C<|ql=v(tС!Xo{q6 f2+(rࢍ|rKB:+ɮ\[; o^P>+؏3`Sx4,jCaSm|*,OY/pZ1ꯞ጖ݿ~*Vh@/6  N(m_ u(j(am(a(,clS = tECpztzŘZamaЬ9~ =}Ba`F^~0?N,Bnvq,ۜ]*V۴~ }k|Ȯev(/CӁ#p~YETqhK\ȁ+M^ݮ搵5cz>@鬚?cS5Y ?.Agl^*y} _h#zl6vqrߡ$.WPoE@@@~6-چc PJcD;nwdHFҏixEUFLNr 5@. y PO$ Udcг m,"Lz["lp ?{ m.(U 6Q[%䄆 P6mG l' I@Ikek$E oX%P{.3 x"x,˺uAoovYћ?}F@fHtv\@zw'dW:pgSxt*HePRz#Dq& Pr|@;f?{+ ?~FSswۧ錮GrxD~:(@K= o{IR Tr{V~*ѪvFw?rSхt}n|mI:O;oB;~%ܩͮHwLjtê7 hvuv{,>/Dur 10/Trans<>>>>>endobj 377 0 obj<>stream xMo0"iH)麵tBVz N6})>Y8-POZ'5z3:s[b2_1)Bw?IJ*$=㣃`ur<w V"~搏^ qlcU/7oh8#>9G (`wd [=Մ3!_#s q͝AKfA2.* 0)Ts,@fn I,ׁk e؋̲V-PI& :oG;dv%0ͤ略L&}KIB p3E{,.d^u\ b 0%P].| `'\ lEYtm1d?KF뀹ދ\H]#K[@]^B}WZDlhUhnAN(%e~X]"K/ oӂ~D*CtDTU"]*RDkjMjԣ(*Ɣ_Q,mUK*x^D(l|F*J /T^]ffG䑝i$'&,Kx%j7T- r odSMzĞc'Fѱv=mj#q`h/uvUV;Mze(+VÄVؕ(hbe T[qۤ_?}yg cb\{2 NCB2,y\ƺbbWຆlY&T"BtG,۬vd^X@)UlU5=' ;Keônm/|1&‡$XэZ4I ,ij`@ c6 KH^tH31RVak"  XGS&|#V٨"{٥(Q)upK6O4qv /yV+l y Oba\c^;g3_\vokuQ]Jws~}B#tN<_;XoZ[@Oi36;OBN;TkWۛ_r s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]I AK0LO!Y1$2endstream endobj 378 0 obj 1908 endobj 379 0 obj<>/Dur 10/Trans<>>>>>endobj 380 0 obj<>stream xj#NaLa:ݙd7B!)65}2ME ˂_w[6*ٖVR9|,-}UUh Owcc`XQmxeEG[ik}~wСֶ̘{DDDDl?]v+'.ٵNyMe5\\d/ѡۨDgfVDV;Dgӟ\?n ~;7vmGҨM{?Sc۳{&D4K&Z+vё~e{vJ>惡fWe3:rKGvo=N|$@AAAAAĦ E" "H؛_"a+DWDLI "W"}މoW? 0p\" "V+\-DADNP#n)RʙW~ER$̫96͘n=Gyƚo䝨`8@DAtEK֋V`я 6Rz`!" G\J:?sQ(SuYQ](@EDWE};Ȭ(wۉv5b a~("QsDy,Q*]i5R:*&ӳi # HNl u$kJJEHhjzK }VKasDtF$e>~XݺҎ8s5c- b}vļ;y'RF " ȻADqムF=Li갉*OjȴQF?"/Mjٜ+O@tjmj&5R E=tDlo!=X0[$Rdr?a}dsYVEnKa~r,B-i!JDLiDBN<mĊH}9sىDjcU 7ȢV< C>CBDADW\rYe Y&j DfPF-7elQýiSfTxZzRi/" "ٵhj;V.)WѳQInNܩokX]DJBfIH;J$3kac j!" \-DADH Dx']#R(X3j$#_F.N+CTrZ-|PDħfyp >̩= F " "BDADrDMD5ŅΊiJu %!S&R0Ta$]Mv5r϶TQ"\(wDR[ޫEi?r}yNZ_ Ұv!g6k8.-*&׉" +\-DADNP#n+Dṉq3) ;%*T#wU[ƚo_(DA͂Q " ZHFF$Bf?DREboE" Oj#%D׉|Gvy22Qħ } u"Q" *oASw"Ojژ͔G}VMM6UMԨ)hSZ uckdEU끨vTMuZQK϶ʼnFkv׏~1GPAAAr UoEwTP$TPN6V$m.K=tѲ^opwID=Ur(Ȃ+C蕞JUʮ׮)[{fv6?b}X%A~ bH%IG&VKrpU{KeMHHضbÊdfņUɑQ#EGp 1&1>AْJDP·% Tl0*;2DYHR?)A7MT˖IsfQa'C 2phS#=9Aφ=\G_)6ij؎i XeU^Ԕ c@+㉙cxf[NK넣Q#qbHug㌲\hOPY>N00ldOa,P0ˌTD q7Dq9QdiF3{)D1$͍AO=WEH( cҏ#S-BHYJƠF#\eRFI 9ϥ0MY2죱gQU&_p:lvbx@ʊ@AI^hձe u==uLM]7hF ]Zx8 %h"aFʣSL'zۜ-e %}-2.i/6B~Rɩ$9EݷN#-.Ycpu%UlhN]` F񻅿4I|RY]r\z~_8f>* w 4wirs "=\FrwQ1pSw.5Gg>޹~e'"Ww~򐸿[7!侻y5:mBPzP#E^\;nJwHe~7fa U; Oy7E~yuOՃӵlΒ{9hhnoGY<$ȐK}IpIpdwDQ Q D6#wЯd(:耔e\[{}F6!jc27!O!6BF~Or s 2P0PI0S-KW(HUpVp 254H!\\ rendstream endobj 381 0 obj 3189 endobj 382 0 obj<>/Dur 10/Trans<>>>>>endobj 383 0 obj<>stream xڬYoBzia)H.WZe,H],jK(|m B{!qCPm).DR@$Dq.]V$P7o}fk$ DR;$4)^%STڄi)iɥ$dYi nZrI FjQY6KXahFIuT8Eƥ7՗QffF'AfC+UJ V#Sʆven6Sc1Sfd(fH`9d5$~|󍅹͹7ˎ?%:sl_E6/G'ٌZJM+ƽئk)lk1KIfj25TM(OMOuݬSa5VEPmMeVBcbiU'dZ]e1҂^lY hƶnGjN44]fB9)f<,B>^֘RT*='so-/ >:5J.-|dcs l}ziNAB!BFiW]gPrd\ `;E!pq!<:GkgZ>,m PWV)0U~zc>Չ\َӓ3 7!QdZ;lD in@vAS=hRʁ E T-#Z,a|w Fj@Ěe;Qi;/_JTcBͪ a,W.ogM*_n Tmo!qۨu [q<ĩW}#BtD}?s64&F΄ f3V}'ZTx8mۭPٖ&6A6_!6$\C 泀sTC!*|o1j<5)thu@RHX(Qʴʍ}[f_鐙AքXeeǗYՙ4VY MeiwO ֗?S"Kq|s3 !e9H%T蠟\`Ŋɇ>N:&&:션p]BL\X`JsL.&YB#B7CS TيD|RIqb&Jq*+NKvλGo N()IϪEj4Ι qngzxȾ~L:υ%}.<>77Ip,oliO=bU]cN>@lH~ዋkKŵ%Eڒ_TN^)J-+^}A¢ iCOIirq/_i$܍eH'ʼn'zF0`ت.닋sWc,2C#=:^cQI:SIZP T>#8weܫ3x0U}Rw.}Ys :i9s2 ;>0 Fp= .{JSq sBNAu:5F¶Ks WK8yt_AIl Kz^_l(w^ji:cҗ={49-nD5Bѕ ]HXѓDOh)ck܈KXK _OR$1]NЙ!IZLwKgђan]6]]Ŏ~SZ(Oq+TLi059M_BQF?5BP ZpB >jo3m"7F)LŬA Ctx0 cv섔h5.}'Nُg.ˣ$@kEMUf]m?&r8cۼqĨl񸣎FE&^MEW3d<-Xr ی<цG8acI'ߊ%tb )W/P἗Hw@XsXӜGMJr~gɕ-"$ b{: U[kD"+ ׼CѿvG/S;:x雃m{l/8yw<>kz~Q =h)^뫽lV{|4>/Dur 10/Trans<>>>>>endobj 386 0 obj<>stream xYoBզ:@3! r,Ďl Ec#RUv]zw)Zha#'_…^{ȡ@\qksƍT% Q;}oҤ+_"KofyoG7rrR8$jT y0RSDBsVaX#JVk.U=}f9P u[ N=]K`H3̑ypHzZ9D%4尌WΏp#v I7]'[uiҮZ7,m&-jtÄlhaĶmvidvE:[ mAۂd.҄uQY\l eo2y Ni cfsJʫ.Ӡ I]raT&&l :nqyrnTHdSTP" ga -΄.G[!AXUaRX m 0:[bkdh$]Ϥ&15ICLg2s%tV᮰]ΫזϞwx-}`yΌ kRc`Q #吜0X{庵-~Z,nue72xDgkUG6dԈU,>=bա,>C.SsFظF)XZc<9Tb z rwDrXN桃 ]vSVדItRaPNǝNw|{(vvlrŽEI;{' _d{;J+O~Ч7^__]b/:כu[Ȼݽ_tď|@R箔~}@J?߾zpR?r s 2P0PI0S-KW(HUpVp 254H!\\ъendstream endobj 387 0 obj 2174 endobj 388 0 obj<>/Dur 10/Trans<>>>/Annots 167 0 R>>endobj 389 0 obj<>stream xڌWoB4:@3pњ$_bb ,BƈEXݡ>YRD9=.C‡\S]8$n*HfwZFVj3{k.( rp+MR_ɓR.C\Fsi*Mi-K Ē'E[oQg 0<?`I]N:O:wiqRw\xy [oͥr:)Q9#\ԘF}Iݷ5n8G(c؜:ӑƈFMXR|„g,oK39\A͛[o7=0idТҠ-FllPdSgXMS>"(Mp&/x{ *"t: )\^px!{ op,'v;uGKh|l:z2(V0-Fau9Ӱ~ld(I}K8oS@km7bhsh4堢Uf ͳ˦K/Mրb8 5@ #QNA.Jܱ(Gw}x"]pms1^۷j̅F{4 q ޏɡ^itڈ[u;Ԝ03 pD# nP[QD6*wTL~ qmF•L9D'Q041gʋ1G)[B45yrRLϗA%r~9\`^'p! [xg%֡Das|VdWDz** TL\8H9od%qnIQV2 *ʨY\\FvT`eA/SK<mpBe\THC6Ս_^V3Bu/Vp]d1Um9NFU`2 ,&m] ݋0I#SD6x7LSBEz>xee-,U YYkyoueyfTk4xPr(D`y]mln2T 8n%xƭ Jmgc0P\e+LE1b&ɖT,VEzT ?6)trɍO7Be8#i, j8)QNUUˆ:RW πyu޺Ư*0U=-4jGڤ0U${ƨrNPP}Q19u Jc:S%!JyxY^ZL$;v^ݪ&&13H6oJJBHIwlL_3|E~erk7MzYl+ɫЕɋҜb/nlv~D[wD={GcgD<ڙ!Jqugăݺ7b>fŗ'ޏ@|L wQR??ȹ?=ZZdǽ?~)ϙ_!noOg^>Rݽ?;B<4}~{G\ѝ}~l泮Db^t{'s]1x?8wG J`H#bh@#hjÁe.o?ソpvPD}1P{xP?3r s wPTIS0413U077PIp-K+QH) EEy y E9 ^IFDin~JiNfH. ]I& AK0LO!Y1$_-endstream endobj 390 0 obj 2144 endobj 391 0 obj<>/Dur 10/Trans<>>>>>endobj 392 0 obj<>stream xڔWoBմ:@3PZr%W")M%Ȳ!%CU!;-SГMBh=? .|͵9ŅAV7ˏ'Dy>vO<|HP'9xJ'# S]2B,orbeȒ@*5P^{295Syc"{LM,[v|]jisdiO1P6g~krBg/d}T2+NͱHBN%XH.eSh@TC1Lmƶݞ)oo .eӚ2Mͦ . qH4Pa,s)f C(xҬɨp:5MBN zlgRJ7SW'E__\_Z- VBTEЩP䑷RWK/b-qLJ,ȗ$l6 RkpOPlThSA6]FC~GX F`V.9uq06AU\` GB4p DgaͥݯrATtР!2bs_;)LkZK戋M?E@!Bi 47mɨ{L4WVRbY;p%hY(H<. jB-6F>Xy#B(Ƣ`ĹY|Wu>Tݖe5L@ 6z<^e{J|ܣ>3e9r d, ̐$%$K ur+*8T& [q@PpR!^]YQ}ͧn8; 2i>ddQXH F,@ ^ T0!] RaV ky:L f&.@{ Uo`N+6LYxDgI7Z@Nf ļHGR:i \^`=:s!ӱKgn!5HryrL ?^6|PerQu1m8=VV]L{$(DR 0!ӃG&5QS \T fMY9SY覧rRAs6EI4q! .(y +"a8D]ZLp6 =mdž#Uʠ3l1]-D8ul.AV}U*2aNb 'M}B `3 g7kjg6ftʺ˫%,#LF%G*/+ixM' w_2M$49OLsR(9(ToK\6ր&xPbvUTu6مZ!K2쟏㼩x`0%T4EO9z=z*x@BUuB땉d~ȩ|K\\+]寲_Lׯ֯_g7Ų[q)2Y(d/oƕ e2Ց@<@z(N{| ʅ1u8&u>| NgVF??:'}7=)ܹ(ίsw{?ރ 5̳=K<8;=7J羋xo@G/vȏ;_^t*ocFIގnH3)oD4ɦՋ>/Dur 10/Trans<>>>>>endobj 395 0 obj<>stream xڌWoWwGB*CVrHJA@.A}^?' ];A'RQE*hSSB4g_Ny;{3y;  / sſp2Rt žD徣h"SQȄ0[D4칾T4Lb*4 BMS dR*|>QՄC|gMbQ;1p_;%tv*N y*AaBAU3aV|U1ASa%0 @7iFV'Us^ ='B-Ax^UmA(("2>al* .Ki1 Dž!04qM@ R0`;Ű 6*9]N"N!W`jIQwqNTBŤ:+L*EK3Ǟ:5%/"1䕬S*5 IbZm%:xٗAuJL['3n[Jؖ9ԈGk+ 'KI-8 rCny I/W|5rn<ˣk@otk, _|26ĶF*쎭9CT217b6>KNMLiNYsGq;}FEsow*,,'(R!e,ݢ4stJ:H8r^,u~t?ӑӟG#ɩ/"8`Wi,iÑ8DL/O`bV%6iI+luM{?oJc=nݳ\pg.-oZK+ߏgZsl_x֭Q -_1z__巎[e暽ʾ ѐg[^_Gw=s־_\V_vRoci71:`/8:V;[WW6w=-ƀ]=gk۾n/G>'JQ3ba/n/7mK/XEnx6l/N.,{|ܓqWF}Zɕ6ol$\J_1n҇W+'7nJr -A bXgMT~_vw2#'sehفU>B0A8g|qb~Eu^QYU&)N(6JaMG;N \endstream endobj 396 0 obj 1863 endobj 397 0 obj<>/Dur 10/Trans<>>>>>endobj 398 0 obj<>stream xڔXoBzia ,4ER(TYl]j#CY(!9rwKHa#'_…^{ȡ@\qks ƍT% Q7.F J{{liWW#9[# գ<Fcl l,|lUamS~uFZ7#&)~ש C*4ɲ*3h bxzپ~]2ExõX&}N}v ʍx%[p#\dž_6=V|:aԨG` n7+1`,f"mVS7$X݅"b~eN+=] W,{8Ufzm , j"m]htڅBll٪;W>:JP;xPև͡.'P_ 1a0 ^d|v+\-K7>h5jQbXoR_~ ,쪰W1]Mt4f&I"+@,:o9ޱ (dYc0m q@h` " DPTe#-dg#L/ףF\3ْr6RAϱ :f`>lVnAA^]&J K|`VV/ז0Fg!Ԓ%ԩ(wYVk NRxPZ쉠ϖ^ `zT8kyt mH%/?N]H]]a~US%.I~&q7iyemy0S006|Ut xol$_oYr̤ٞi,,QzGuh.g_2Qz[hsT\U l0Ʃy"]1Y/]RX(-|J9XڜY͙ׯ]%W7?˿$;řdvn5'ȋ2tdgdlb0z+ow8|=/r s 2P0PI03SpV(O,IH-RHKQH-QHNIJL 254(65q]C 0=endstream endobj 399 0 obj 2353 endobj 400 0 obj<>/Dur 10/Trans<>>>>>endobj 401 0 obj<>stream xڜWoBziaJ ?EJc "BDԺAY'q-rw6r z)\ąA76p!hJU3䊎R’;f7{{,^fR{Ll[cy+k(ƛKa.-dEj3E~~pZ [ciΤDDir<ܛ-Fn\^yrV瀞ubyt95[Ӎmp,t4VW54ӫWƚ*вu-f:uM#Xmi28z'š;dFl`1=rl2!h2CL&o}Og4Dpe ph2VsR\,^v03s3\N^jf6=@o" MĂ˃%Bk FLXcv鹈mM=Ks Z5]nsVPSʘGifd68R"jUc9.u9*s !>( zsy}/iyQSg5hzrL)aSZd$XPoޛIS!*uP]~9bB<"&?Zj)WvO B.,M/HgYY~=p6.-<ٙasB&L7oN>leC Ӄۃ[CmS %eei#%aq,. ܻ\=3[p3U< vֺnp49";jY #m6aiwA%)/ &F+)j-@s=lfMn@",i\,/0+vʞ4s}W\d"TuQa:2rZ*IgZ&Ԟ%D/O\T_7<+J)NO&{@T~vX<'> ҺǾ_d,۟tYT:?)TqNQg:rѱ׿(r -K -uQ֦5آ@z}E\dN 5v6Kwy 9G38idjzȡ_KVRhhE-t**#'endstream endobj 402 0 obj 2055 endobj 403 0 obj<>/Dur 10/Trans<>>>>>endobj 404 0 obj<>stream xڍUMF+|pUmZrI6 \|I-3!3#X_K,^X/Lw~Z,#\&LW4/[d43UQ4t* n?/h4KRZV#y,of mF*jgU5>,n?i4X/8ڮhW.b 8*0:~6=KҖ"cFHʖ"Vg ;ht&'/orldϣ.@;Ӵ+RyC\_\G~N&ݹBA*2Qe2:.qIf9_&4O<'{c:Pe_VQ%? 8X/]IMGr3Ɔiw脖kqrөL~Թ>Yڞ֫+l3+ࢼ&>WH_% r:"4q p{"wԒKm(싞,dvS缧k\+kq~$S*ޓ*ޱB-/!QyAA*_B2/dR; ɢ aRm"l;$kP^z6Vj֡ V*Ω< އˆyۆFXت, HsQa5&Jħ^CGQĉ]Clq\Hd$$ˠ53BPks:!Nuc5dűVER{]M ifYCjtǣK6w!ly;pZ|+Dn"2qx~dvgvFIZtlv67eendstream endobj 405 0 obj 924 endobj 406 0 obj<>/Dur 10/Trans<>>>>>endobj 407 0 obj<>stream xLO`64=x,/+clKM;aă1J" $-]Ō4p?aUNΌM߾ۂ}ۧϷiڷ&3i0/#YTGI>ӹ4z-FQ\P3ČZBCdˉ+?3QE?|ydN3^GH)J*0IKOOŞG3O̘,V MVjKlu61نNڐzugEH`eDa6>/Dur 10/Trans<>>>>>endobj 410 0 obj<>stream xڍSMo0 W'G: ;l`gŢm.#iENJ,ټڬ-|Gs<moY]jZf;q ;7Ւv-7:oͶo)vfi>|Xf#8ٶ IL2YWŅ>)Zѣ(M9?5l hPb#[e&e5 tdFynltPS/2L;iȣMXb"C#!CgG6n,T 謟Ф0[(K|siY]HFb`VI^0Y Cy\0Sk%f!1 $-Hy]*͖^ŊS:ݘ_XgrZOh!Orr;! tU^f":o2Wbodmv^N}#Kendstream endobj 411 0 obj 567 endobj 412 0 obj<>/Dur 10/Trans<>>>>>endobj 413 0 obj<>stream xLO`64=x,/+clKM;aă1J" $-]Ō4p?aUNΌM߾ۂ}ۧϷiڷ&3i0/#YTGI>ӹ4z-FQ\P3ČZBCdˉ+?3QE?|ydN3^GH)J*0IKOOŞG3O̘,V MVjKlu61نNڐzugEH`eDa6>/Dur 10/Trans<>>>/Annots 174 0 R>>endobj 416 0 obj<>stream xڕWKo8W zrD,?w/M\tlE -TI*n )ٵ8)Ȓ87P?.t xe21FC06C2T^Y]p[ir$۬w[E'p=Bm Hb6ZxN}@0 І!h4&c S48yW.dXo7`-j#3‰{`xe\]FgCd;B&7$BXpF~,@+hJwt2|^<8*uVyпcb9?#n'|DJHʠhb,]y9PJT>/Dur 10/Trans<>>>>>endobj 419 0 obj<>stream xLO`64=x,/+clKM;aă1J" $-]Ō4p?aUNΌM߾ۂ}ۧϷiڷ&3i0/#YTGI>ӹ4z-FQ\P3ČZBCdˉ+?3QE?|ydN3^GH)J*0IKOOŞG3O̘,V MVjKlu61نNڐzugEH`eDa6>1<>2<>]>>>>endobj xref 0 422 0000000000 65535 f 0000000015 00000 n 0000000217 00000 n 0000001774 00000 n 0000001848 00000 n 0000001927 00000 n 0000002009 00000 n 0000002085 00000 n 0000002166 00000 n 0000002250 00000 n 0000002338 00000 n 0000002398 00000 n 0000002483 00000 n 0000002586 00000 n 0000002690 00000 n 0000002793 00000 n 0000002897 00000 n 0000003002 00000 n 0000003105 00000 n 0000003209 00000 n 0000003314 00000 n 0000003419 00000 n 0000003524 00000 n 0000003627 00000 n 0000003731 00000 n 0000003836 00000 n 0000003941 00000 n 0000004046 00000 n 0000004149 00000 n 0000004252 00000 n 0000004356 00000 n 0000004461 00000 n 0000004566 00000 n 0000004671 00000 n 0000004776 00000 n 0000004879 00000 n 0000004983 00000 n 0000005088 00000 n 0000005193 00000 n 0000005296 00000 n 0000005400 00000 n 0000005505 00000 n 0000005608 00000 n 0000005712 00000 n 0000005817 00000 n 0000005922 00000 n 0000006025 00000 n 0000006129 00000 n 0000006234 00000 n 0000006339 00000 n 0000006442 00000 n 0000006546 00000 n 0000006651 00000 n 0000006756 00000 n 0000006859 00000 n 0000006963 00000 n 0000007068 00000 n 0000007171 00000 n 0000007275 00000 n 0000007380 00000 n 0000007483 00000 n 0000007587 00000 n 0000007692 00000 n 0000007797 00000 n 0000007902 00000 n 0000008005 00000 n 0000008109 00000 n 0000008212 00000 n 0000008316 00000 n 0000008421 00000 n 0000008524 00000 n 0000008628 00000 n 0000008733 00000 n 0000008836 00000 n 0000008940 00000 n 0000009045 00000 n 0000009148 00000 n 0000009252 00000 n 0000009357 00000 n 0000009462 00000 n 0000009565 00000 n 0000009669 00000 n 0000009774 00000 n 0000009877 00000 n 0000009981 00000 n 0000010086 00000 n 0000010191 00000 n 0000010294 00000 n 0000010398 00000 n 0000010439 00000 n 0000010522 00000 n 0000010563 00000 n 0000010647 00000 n 0000010688 00000 n 0000010773 00000 n 0000010876 00000 n 0000010980 00000 n 0000011085 00000 n 0000011190 00000 n 0000011295 00000 n 0000011398 00000 n 0000011503 00000 n 0000011609 00000 n 0000011713 00000 n 0000011818 00000 n 0000011924 00000 n 0000012028 00000 n 0000012133 00000 n 0000012239 00000 n 0000012343 00000 n 0000012448 00000 n 0000012554 00000 n 0000012658 00000 n 0000012763 00000 n 0000012869 00000 n 0000012973 00000 n 0000013078 00000 n 0000013184 00000 n 0000013288 00000 n 0000013393 00000 n 0000013497 00000 n 0000013602 00000 n 0000013708 00000 n 0000013814 00000 n 0000013920 00000 n 0000014026 00000 n 0000014130 00000 n 0000014235 00000 n 0000014341 00000 n 0000014447 00000 n 0000014553 00000 n 0000014657 00000 n 0000014762 00000 n 0000014866 00000 n 0000014971 00000 n 0000015077 00000 n 0000015183 00000 n 0000015289 00000 n 0000015395 00000 n 0000015499 00000 n 0000015604 00000 n 0000015710 00000 n 0000015816 00000 n 0000015922 00000 n 0000016026 00000 n 0000016131 00000 n 0000016237 00000 n 0000016343 00000 n 0000016449 00000 n 0000016555 00000 n 0000016658 00000 n 0000016762 00000 n 0000016867 00000 n 0000016969 00000 n 0000017072 00000 n 0000017174 00000 n 0000017277 00000 n 0000018345 00000 n 0000018449 00000 n 0000018553 00000 n 0000018658 00000 n 0000018764 00000 n 0000018814 00000 n 0000018893 00000 n 0000018980 00000 n 0000019006 00000 n 0000019085 00000 n 0000019171 00000 n 0000019197 00000 n 0000019284 00000 n 0000019371 00000 n 0000019428 00000 n 0000019515 00000 n 0000019576 00000 n 0000019662 00000 n 0000019704 00000 n 0000019738 00000 n 0000019772 00000 n 0000021012 00000 n 0000021061 00000 n 0000021110 00000 n 0000021159 00000 n 0000021208 00000 n 0000021257 00000 n 0000021306 00000 n 0000021355 00000 n 0000021404 00000 n 0000021453 00000 n 0000021502 00000 n 0000021551 00000 n 0000021600 00000 n 0000021649 00000 n 0000021698 00000 n 0000021747 00000 n 0000021796 00000 n 0000021845 00000 n 0000021894 00000 n 0000021943 00000 n 0000021992 00000 n 0000022041 00000 n 0000022090 00000 n 0000022139 00000 n 0000022188 00000 n 0000022237 00000 n 0000022286 00000 n 0000022335 00000 n 0000022384 00000 n 0000022433 00000 n 0000022482 00000 n 0000022531 00000 n 0000022580 00000 n 0000022629 00000 n 0000022678 00000 n 0000022727 00000 n 0000022776 00000 n 0000022825 00000 n 0000022874 00000 n 0000022923 00000 n 0000022972 00000 n 0000023021 00000 n 0000023070 00000 n 0000023119 00000 n 0000023168 00000 n 0000023765 00000 n 0000023927 00000 n 0000024135 00000 n 0000024156 00000 n 0000024291 00000 n 0000024422 00000 n 0000024442 00000 n 0000024619 00000 n 0000026624 00000 n 0000026646 00000 n 0000026835 00000 n 0000027633 00000 n 0000027654 00000 n 0000027837 00000 n 0000037433 00000 n 0000037455 00000 n 0000037656 00000 n 0000042588 00000 n 0000042610 00000 n 0000042829 00000 n 0000045514 00000 n 0000045536 00000 n 0000045710 00000 n 0000046429 00000 n 0000046450 00000 n 0000046651 00000 n 0000052879 00000 n 0000052901 00000 n 0000053102 00000 n 0000056595 00000 n 0000056617 00000 n 0000056800 00000 n 0000062301 00000 n 0000062323 00000 n 0000062533 00000 n 0000068382 00000 n 0000068404 00000 n 0000068605 00000 n 0000074135 00000 n 0000074157 00000 n 0000074367 00000 n 0000080451 00000 n 0000080473 00000 n 0000080665 00000 n 0000082297 00000 n 0000082319 00000 n 0000082493 00000 n 0000083198 00000 n 0000083219 00000 n 0000083408 00000 n 0000085034 00000 n 0000085056 00000 n 0000085266 00000 n 0000087542 00000 n 0000087564 00000 n 0000087783 00000 n 0000089926 00000 n 0000089948 00000 n 0000090149 00000 n 0000099027 00000 n 0000099049 00000 n 0000099268 00000 n 0000101547 00000 n 0000101569 00000 n 0000101788 00000 n 0000104203 00000 n 0000104225 00000 n 0000104444 00000 n 0000106636 00000 n 0000106658 00000 n 0000106868 00000 n 0000113349 00000 n 0000113371 00000 n 0000113581 00000 n 0000122886 00000 n 0000122908 00000 n 0000123118 00000 n 0000125598 00000 n 0000125620 00000 n 0000125809 00000 n 0000127481 00000 n 0000127503 00000 n 0000127713 00000 n 0000129679 00000 n 0000129701 00000 n 0000129929 00000 n 0000132277 00000 n 0000132299 00000 n 0000132518 00000 n 0000134534 00000 n 0000134556 00000 n 0000134766 00000 n 0000136787 00000 n 0000136809 00000 n 0000137019 00000 n 0000139409 00000 n 0000139431 00000 n 0000139641 00000 n 0000141832 00000 n 0000141854 00000 n 0000142073 00000 n 0000144732 00000 n 0000144754 00000 n 0000144955 00000 n 0000146868 00000 n 0000146890 00000 n 0000147091 00000 n 0000149082 00000 n 0000149104 00000 n 0000149305 00000 n 0000151994 00000 n 0000152016 00000 n 0000152217 00000 n 0000154513 00000 n 0000154535 00000 n 0000154745 00000 n 0000157538 00000 n 0000157560 00000 n 0000157779 00000 n 0000159624 00000 n 0000159646 00000 n 0000159838 00000 n 0000161327 00000 n 0000161349 00000 n 0000161541 00000 n 0000163085 00000 n 0000163107 00000 n 0000163290 00000 n 0000164127 00000 n 0000164148 00000 n 0000164322 00000 n 0000165025 00000 n 0000165046 00000 n 0000165244 00000 n 0000167201 00000 n 0000167223 00000 n 0000167433 00000 n 0000169515 00000 n 0000169537 00000 n 0000169747 00000 n 0000171893 00000 n 0000171915 00000 n 0000172107 00000 n 0000173815 00000 n 0000173837 00000 n 0000174035 00000 n 0000175831 00000 n 0000175853 00000 n 0000176087 00000 n 0000179007 00000 n 0000179029 00000 n 0000179239 00000 n 0000182134 00000 n 0000182156 00000 n 0000182357 00000 n 0000184336 00000 n 0000184358 00000 n 0000184550 00000 n 0000187810 00000 n 0000187832 00000 n 0000188042 00000 n 0000190644 00000 n 0000190666 00000 n 0000190885 00000 n 0000193130 00000 n 0000193152 00000 n 0000193377 00000 n 0000195592 00000 n 0000195614 00000 n 0000195824 00000 n 0000197873 00000 n 0000197895 00000 n 0000198123 00000 n 0000200057 00000 n 0000200079 00000 n 0000200280 00000 n 0000202704 00000 n 0000202726 00000 n 0000202927 00000 n 0000205053 00000 n 0000205075 00000 n 0000205255 00000 n 0000206250 00000 n 0000206271 00000 n 0000206445 00000 n 0000207151 00000 n 0000207172 00000 n 0000207343 00000 n 0000207981 00000 n 0000208002 00000 n 0000208176 00000 n 0000208874 00000 n 0000208895 00000 n 0000209090 00000 n 0000210626 00000 n 0000210648 00000 n 0000210822 00000 n 0000211517 00000 n 0000211538 00000 n trailer <> startxref 211736 %%EOF Event-1.26/META.yml0000644000076400007640000000101412727627261012532 0ustar useruser--- abstract: unknown author: - unknown build_requires: ExtUtils::MakeMaker: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.18, CPAN::Meta::Converter version 2.150001' license: unknown meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Event no_index: directory: - t - inc requires: Test: '1' perl: '5.008000' resources: repository: https://github.com/mohawk2/cpan-Event.git version: '1.26' Event-1.26/demo/0000755000076400007640000000000012727627261012211 5ustar useruserEvent-1.26/demo/group.t0000644000076400007640000000106412357140355013524 0ustar useruser#!./perl -w use strict; use Test; plan test => 6; use Event qw(time); require Event::group; my $g = Event->group(parked=>1, timeout => 1.95, cb => sub { my $e = shift; warn "timeout at ".$e->w->cbtime; }, add => Event->timer(desc => '1', interval => 2, cb => sub { my $e = shift; warn "boink #1 at ".$e->w->cbtime }), add => Event->timer(desc => '2', interval => 2.5, cb => sub { my $e = shift; warn "boink #2 at ".$e->w->cbtime }), ); $g->start; Event::loop(); Event-1.26/demo/echo.t0000644000076400007640000000136012357140355013305 0ustar useruser#!./perl -w $| = 1; use Event qw(time); require Event::io; print "This demo echoes whatever you type. If you don't type anything for as long as 2.5 seconds then it will complain. Enter an empty line to exit. "; my $recent = time; Event->io(fd => \*STDIN, timeout => 2.5, poll => "r", repeat => 1, cb => sub { my $e = shift; my $got = $e->got; #print scalar(localtime), " "; if ($got eq "r") { sysread(STDIN, $buf, 80); chop $buf; my $len = length($buf); Event::unloop if !$len; print "read[$len]:$buf:\n"; $recent = time; } else { print "nothing for ".(time - $recent)." seconds\n"; } }); Event::loop(); Event-1.26/demo/semaphore.pm0000644000076400007640000000243412357140355014526 0ustar useruserdie "SysV semaphores are not implemented yet. Send email to perl-loop@perl.org if you think this is a problem. Thanks!\n"; package Event::semaphore; use Event; use IPC::Semaphore; register Event; my $LABEL = "sem000000"; my %SEM = (); sub new { use attrs qw(locked method); my $class = shift; my %arg = @_; my $sem = $arg{'-semaphore'}; my $op = $arg{'-op'}; my $cb = $arg{'-callback'}; croak 'Event->semaphore( -semaphore => $sem, -op => $arrayref, -callback => $coderef)' unless(UNIVERSAL::isa($msg,'IPC::Semaphore') && UNIVERSAL::isa($op,'ARRAY') && UNIVERSAL::isa($cb,'CODE')); my $obj = bless { callback => $cb, semaphore => $sem, semop => $op, label => $LABEL++, }, $class; $SEM{$obj->{'label'}} = $obj; $obj; } sub prepare { 3600 } sub check { my $obj; my @del = (); foreach $obj (values %SEM) { if($obj->{'semaphore'}->op(@{$obj->{'semop'}}) >= 0) { my($o,$cb,$s,$op) = ($obj,$obj->{'callback'}, $obj->{'semaphore'},$obj->{'semop'}); Event->queueEvent( sub { $cb->($o,$s) } ); push @del, $obj->{'label'}; } } delete @sem{@del}; 1; } sub cancel { my $self = shift; delete $SEM{$self->{'label'}}; } sub again { my $self = shift; $SEM{$self->{'label'}} = $self; } 1; Event-1.26/demo/msg.pm0000644000076400007640000000177012357140355013333 0ustar useruserdie "SysV messages are not implemented yet. Send email to perl-loop@perl.org if you think this is a problem. Thanks!\n"; package Event::msg; use Event; use IPC::Msg; register Event; my %MSG; my $LABEL = "msg000000"; sub new { use attrs qw(locked method); my $class = shift; my %arg = @_; my $msg = $arg{'-msg'}; my $cb = $arg{'-callback'}; croak 'Event->msg( -msg => $msg, -callback => $coderef)' unless(UNIVERSAL::isa($msg,'IPC::Msg') && UNIVERSAL::isa($cb,'CODE')); my $obj = { callback => $cb, msg => $msg, label => $label++ }, $class; $msg{$obj->{'label'}} = $obj; $obj; } sub cancel { my $self = shift; delete $msg{$self->{'label'}}; } sub prepare { 3600 } sub check { my $obj; my @del = (); foreach $obj (values %msg) { my $ds = $obj->{'msg'}->stat; if($ds->qnum && $ds->lspid != $$) my($o,$cb,$msg) = ($obj,$obj->{'callback'},$obj->{'msg'}); Event->queueEvent( sub { $cb->($o,$msg) } ); } } 1; } 1; Event-1.26/demo/queue_pending.t0000644000076400007640000000143012357140355015215 0ustar useruser#!/usr/bin/perl use warnings; use strict; use Event qw(queue_pending); # Zefram # # If you already have a signal watcher, and then start a second one for # the same signal, the counting continues unaffected by the start of # the second watcher. Both watchers will generate events for a signal # received shortly before the second one was started. Event->signal(signal => "USR1", cb => sub { print "handler 0 got hits=", $_[0]->hits, "\n"; }); kill "USR1" => 0; # If "queue_pending();" is added to the program, immediately before # the creation of the second watcher, then it produces different output. # # queue_pending(); Event->signal(signal => "USR1", cb => sub { print "handler 1 got hits=", $_[0]->hits, "\n"; }); kill "USR1" => 0; Event::loop; Event-1.26/demo/readline.t0000644000076400007640000000444712725135405014162 0ustar useruser#!/usr/bin/env perl -w # # Test script to combine Term::Readline::Gnu and Event. # Derived from the ptksh+ script by A. Bohnet which comes # with Term::Readline::Gnu. # # The script does nothing more than just demonstrating how # Term::Readline::Gnu can be combined with event loops built # by using the Event module. # # The running event loop can be visualized by using the # option -idle. # # J. Stenzel (perl@jochen-stenzel.de) # # check perl version require 5.008; # pragmata use strict; # load modules use Event; use Getopt::Long; use File::Basename; use Term::ReadLine; # inits and declarations my ($script, %options)=basename($0); # get options GetOptions(\%options, "idle"); # init readline my $term=new Term::ReadLine($script); my $attribs=$term->Attribs; $term->callback_handler_install("$script> ", \&processLine); # store output buffer in a scalar (for print) my $outstream=$attribs->{'outstream'}; # install STDIN handler Event->io( desc => 'STDIN handler', # description; fd => \*STDIN, # handle; poll => 'r', # wait for income; cb => sub {&{$attribs->{'callback_read_char'}}()}, # callback; repeat => 1, # keep alive after events; ); # install an additional idle task just to demonstrate that the loop works fine, if necessary Event->idle( desc => 'idle task', # description; prio => 5, # low priority; min => 1, # minimal pending time in seconds; max => 5, # invoked after at least this number of seconds; cb => sub {print $outstream "\n\n[Trace] Idle task is running.\n\n"}, # callback; repeat => 1, # keep alive after events; ) if exists $options{'idle'}; # enter event loop Event::loop(); # handle a line completely read sub processLine { # get line my ($line)=@_; # anyhing to process? if (defined $line) { # do something print $outstream "[Trace] $line\n"; $term->add_history($line) if $line ne ''; } else { # well done print $outstream "\n"; $term->callback_handler_remove(); $_->cancel for Event::all_watchers; } } Event-1.26/demo/repeat.t0000644000076400007640000000174612357140355013657 0ustar useruser#!./perl -w use strict; use Event; # $Event::DebugLevel = 4; my $w=Event->io(fd=>\*STDIN, repeat=>0, cb=>\&callback); Event->timer(interval=>4, cb=>sub { $w->repeat(!$w->repeat); warn "repeat=".$w->repeat."\n"; state($w); }); sub callback { my $w = $_[0]->w; my $h = $w->fd; my $in=<$h>; print "You entered: $in"; if ($in =~ /start|again/) { $w->again; } state($w); } sub state { my ($w)=@_; warn 'Is: '.join(' ', $w->is_active?'ACTIVE':'INACTIVE', $w->is_suspended?'SUSP':'', $w->is_cancelled?'CANCELLED':'')."\n"; } print " This demo shows the function of the repeat flag. If you press return while repeat=1 then the watcher will remain active. If you press return while repeat=0 then the watcher will become inactive. If you type 'again' while the watcher is inactive then again() will be called in the callback and the watcher should continue to be active. Granted, this is not very exciting. :-) "; Event::loop; Event-1.26/demo/perlqt.t0000644000076400007640000000471212357140355013702 0ustar useruser#!./perl -w use Qt 2.0; use Event; package Qt::Application; BEGIN { Qt::app->import; } # must happen prior to this override: { # Won't work unless these are *virtual* functions. Troll Tech # hasn't yet seen fit to make this change. Apply the attached # patch for qt, and recompile. # Don't forget to make similar adjustments to the PerlQt templates. no warnings; sub enter_loop { Event::loop() } sub exit_loop { Event::unloop() } } package MyMainWindow; use base 'Qt::MainWindow'; use Qt::slots 'open_file()'; sub open_file { # call something that does exec(), and therefore enter_loop() Qt::FileDialog::getExistingDirectory(); } use Qt::slots 'quit()'; sub quit { Event::unloop(0) } package main; Qt::app->import; # Some versions of PerlQt don't provide xfd(). Fortunately, it is # easy to add. # # Qt.pig: # # #include # #include # static int xfd() : ConnectionNumber(qt_xdisplay()); Event->io(desc => 'Qt', fd => Qt::xfd(), timeout => .2, # for balloon help, etc. cb => sub { $app->processEvents(3000); #read $app->flushX(); #write }); my $w = MyMainWindow->new; my $mb = $w->menuBar; my $file = Qt::PopupMenu->new; $file->insertItem("Open...", $w, 'open_file()'); $file->insertItem("Quit", $w, 'quit()'); $mb->insertItem("File", $file); my $at = int rand 1000; my $label = Qt::Label->new("$at", $w); $w->setCentralWidget($label); Event->timer(hard => 1, interval => .2, cb => sub { --$at; $at = int rand 1000 if $at < 1; # prove that Event is in control $label->setText($at); }); $w->resize(200, 200); $w->show; $app->setMainWidget($w); exit Event::loop(); __END__ diff -c 'qt-2.1.0/src/kernel/qapplication.h' 'qt-2.1.0.new/src/kernel/qapplication.h' *** ././src/kernel/qapplication.h Wed Apr 12 09:21:53 2000 --- ././src/kernel/qapplication.h Wed Apr 12 13:53:51 2000 *************** *** 112,119 **** void processEvents(); void processEvents( int maxtime ); void processOneEvent(); ! int enter_loop(); ! void exit_loop(); int loopLevel() const; static void exit( int retcode=0 ); --- 112,119 ---- void processEvents(); void processEvents( int maxtime ); void processOneEvent(); ! virtual int enter_loop(); ! virtual void exit_loop(); int loopLevel() const; static void exit( int retcode=0 ); Event-1.26/demo/rand_interval.t0000644000076400007640000000047412357140355015224 0ustar useruser#!./perl -w # contributed by jsalmon@gw.thesalmons.org use Event qw(loop); require Event::timer; $w = Event->timer(interval => 1, parked=>1); $w->cb(sub { my $next = rand(10); print(scalar localtime(Event::time()), ": waiting ", $next, " sec\n"); $w->interval($next); }); $w->start; loop(); Event-1.26/demo/process.pm0000644000076400007640000000313212357140355014215 0ustar useruseruse strict; package Event::process; use Carp; use Event qw(time); use base 'Event::Watcher'; use vars qw($DefaultPriority); $DefaultPriority = Event::PRIO_HIGH(); 'Event::Watcher'->register(); sub new { #lock %Event::; shift if @_ & 1; my %arg = @_; my $o = 'Event::process'->allocate(); $o->init([qw(pid timeout)], \%arg); $o->{any} = 1 if !exists $o->{pid}; $o->start(); $o; } my %cb; # pid => [events] Event->signal(signal => 'CHLD', #CLD? XXX callback => sub { my ($o) = @_; for (my $x=0; $x < $o->{count}; $x++) { my $pid = wait; last if $pid == -1; my $status = $?; my $cbq = delete $cb{$pid} if exists $cb{$pid}; $cbq ||= $cb{any} if exists $cb{any}; next if !$cbq; for my $e (@$cbq) { $e->{pid} = $pid; $e->{status} = $status; Event::queue($e); } } }, desc => "Event::process SIGCHLD handler"); sub _start { my ($o, $repeat) = @_; my $key = exists $o->{any}? 'any' : $o->{pid}; push @{$cb{ $key } ||= []}, $o; if (exists $o->{timeout}) { croak "Timeout for all child processes?" if $o->{any}; $o->{at} = time + $o->{timeout}; } } sub _stop { my $o = shift; my $key = exists $o->{any}? 'any' : $o->{pid}; $cb{ $key } = [grep { $_->{id} != $o->{id} } @{$cb{ $key }} ]; delete $cb{ $key } if @{ $cb{ $key }} == 0; } sub _alarm { my $o = shift; delete $o->{status}; Event::queue($o); } sub _postCB { my $o = shift; if (exists $o->{timeout}) { delete $o->{timeout}; $o->again; } } 1; Event-1.26/demo/idle2.t0000644000076400007640000000232112357140355013364 0ustar useruser# idle daydreams -*-perl-*- # This test is too sensitive to slight variations in timing # to serve as part of the test suite. BEGIN { eval { require Time::HiRes; Time::HiRes->VERSION(1.20); }; if ($@) { print "1..0\n"; print "ok 1 # skipped; requires Time::HiRes 1.20\n"; exit; } } use Test; plan tests => 5; use Event qw(loop unloop time all_events one_event); # $Event::Eval = 1; # $Event::DebugLevel = 4; $Event::DIED = \&Event::verbose_exception_handler; #----------- complex idle events; fuzzy timers my ($cnt,$min,$max,$sum) = (0)x4; my $prev; $min = 100; my $Min = .01; my $Max = .2; Event->idle(min => $Min, max => $Max, desc => "*IDLE*TEST*", cb => sub { my $now = time; if (!$prev) { $prev = time; return } my $d = $now - $prev; $prev = $now; $sum += $d; $min = $d if $d < $min; $max = $d if $d > $max; unloop('done') if ++$cnt > 10; }); my $sleeps=0; Event->idle(repeat => 1, cb => sub { Event::sleep $Min; ++$sleeps }); Event::sleep .1; # try to let CPU settle loop(); my $epsilon = .05; ok $sleeps > 1; #did we test anything? ok $min >= $Min-$epsilon; ok $max < $Max+$epsilon; # fails without high resolution clock XXX ok $sum/$cnt >= $min; ok $sum/$cnt <= $max; Event-1.26/Tutorial.pdf-errata.txt0000644000076400007640000000043612357140355015651 0ustar useruserDate: Wed, 23 Sep 2009 14:41:50 +0200 (CEST) From: "Kiss Gabor (Bitman)" In section 4.3 page 31 (33 according to PDF reader) warn "Event after ", time-startup, " seconds.\n"; should be changed to warn "Event after ", time-$startup, " seconds.\n"; Event-1.26/Event.h0000644000076400007640000000775512357140355012526 0ustar useruser#include "EventAPI.h" #define PE_NEWID ('e'+'v') /* for New() macro */ #define PE_RING_INIT(LNK, SELF) \ STMT_START { \ (LNK)->next = LNK; \ (LNK)->prev = LNK; \ (LNK)->self = SELF; \ } STMT_END #define PE_RING_EMPTY(LNK) ((LNK)->next == LNK) #define PE_RING_UNSHIFT(LNK, ALL) \ STMT_START { \ assert((LNK)->next==LNK); \ (LNK)->next = (ALL)->next; \ (LNK)->prev = ALL; \ (LNK)->next->prev = LNK; \ (LNK)->prev->next = LNK; \ } STMT_END #define PE_RING_ADD_BEFORE(L1,L2) \ STMT_START { \ assert((L1)->next==L1); \ (L1)->next = L2; \ (L1)->prev = (L2)->prev; \ (L1)->next->prev = L1; \ (L1)->prev->next = L1; \ } STMT_END #define PE_RING_DETACH(LNK) \ STMT_START { \ if ((LNK)->next != LNK) { \ (LNK)->next->prev = (LNK)->prev; \ (LNK)->prev->next = (LNK)->next; \ (LNK)->next = LNK; \ } \ } STMT_END /* too bad typeof is a G++ specific extension #define PE_RING_POP(ALL, TO) \ STMT_START { \ pe_ring *lk = (ALL)->prev; \ PE_RING_DETACH(lk); \ TO = (typeof(TO)) lk->self; \ } STMT_END */ typedef struct pe_cbframe pe_cbframe; struct pe_cbframe { pe_event *ev; IV run_id; void *stats; }; typedef struct pe_tied pe_tied; struct pe_tied { pe_watcher base; pe_timeable tm; }; #define WKEYMETH(M) static void M(pe_watcher *ev, SV *nval) #define EKEYMETH(M) static void M(pe_event *ev, SV *nval) /* When this becomes a public API then we should also publish C interfaces to set up perl & C callbacks. For now we can be lazy. */ struct pe_event_vtbl { HV *stash; pe_event *(*new_event)(pe_watcher *); void (*dtor)(pe_event *); pe_ring freelist; }; struct pe_watcher_vtbl { int did_require; HV *stash; void (*dtor)(pe_watcher *); char*(*start)(pe_watcher *, int); void (*stop)(pe_watcher *); void (*alarm)(pe_watcher *, pe_timeable *); pe_event_vtbl *event_vtbl; pe_event *(*new_event)(pe_watcher *); }; #define PE_ACTIVE 0x001 #define PE_POLLING 0x002 #define PE_SUSPEND 0x004 #define PE_PERLCB 0x020 #define PE_RUNNOW 0x040 #define PE_TMPERLCB 0x080 #define PE_CANCELLED 0x400 #define PE_DESTROYED 0x800 #define PE_VISIBLE_FLAGS (PE_ACTIVE | PE_SUSPEND) #ifdef DEBUGGING # define WaDEBUGx(ev) (SvIV(DebugLevel) + WaDEBUG(ev)) #else # define WaDEBUGx(ev) 0 #endif /* logically waiting for something to happen */ #define WaACTIVE(ev) (WaFLAGS(ev) & PE_ACTIVE) #define WaACTIVE_on(ev) (WaFLAGS(ev) |= PE_ACTIVE) #define WaACTIVE_off(ev) (WaFLAGS(ev) &= ~PE_ACTIVE) /* physically registered for poll/select */ #define WaPOLLING(ev) (WaFLAGS(ev) & PE_POLLING) #define WaPOLLING_on(ev) (WaFLAGS(ev) |= PE_POLLING) #define WaPOLLING_off(ev) (WaFLAGS(ev) &= ~PE_POLLING) #define WaSUSPEND(ev) (WaFLAGS(ev) & PE_SUSPEND) #define WaSUSPEND_on(ev) (WaFLAGS(ev) |= PE_SUSPEND) #define WaSUSPEND_off(ev) (WaFLAGS(ev) &= ~PE_SUSPEND) #define WaPERLCB(ev) (WaFLAGS(ev) & PE_PERLCB) #define WaPERLCB_on(ev) (WaFLAGS(ev) |= PE_PERLCB) #define WaPERLCB_off(ev) (WaFLAGS(ev) &= ~PE_PERLCB) #define WaTMPERLCB(ev) (WaFLAGS(ev) & PE_TMPERLCB) #define WaTMPERLCB_on(ev) (WaFLAGS(ev) |= PE_TMPERLCB) #define WaTMPERLCB_off(ev) (WaFLAGS(ev) &= ~PE_TMPERLCB) /* RUNNOW should be event specific XXX */ #define WaRUNNOW(ev) (WaFLAGS(ev) & PE_RUNNOW) #define WaRUNNOW_on(ev) (WaFLAGS(ev) |= PE_RUNNOW) #define WaRUNNOW_off(ev) (WaFLAGS(ev) &= ~PE_RUNNOW) #define WaCANCELLED(ev) (WaFLAGS(ev) & PE_CANCELLED) #define WaCANCELLED_on(ev) (WaFLAGS(ev) |= PE_CANCELLED) #define WaCANCELLED_off(ev) (WaFLAGS(ev) &= ~PE_CANCELLED) #define WaDESTROYED(ev) (WaFLAGS(ev) & PE_DESTROYED) #define WaDESTROYED_on(ev) (WaFLAGS(ev) |= PE_DESTROYED) #define WaDESTROYED_off(ev) (WaFLAGS(ev) &= ~PE_DESTROYED) #define WaCANDESTROY(ev) \ (WaCANCELLED(ev) && ev->refcnt == 0 && !ev->mysv) #define EvFLAGS(ev) ((pe_event*)ev)->flags #define EvPERLCB(ev) (EvFLAGS(ev) & PE_PERLCB) #define EvPERLCB_on(ev) (EvFLAGS(ev) |= PE_PERLCB) #define EvPERLCB_off(ev) (EvFLAGS(ev) &= ~PE_PERLCB) Event-1.26/Changes0000644000076400007640000006207712727627045012574 0ustar useruser1.26 2015-06-13 - fix doc typos (Lucas Kanashiro) 1.25 2015-06-06 - Fix Event::PRIO_NORMAL call in Watcher.pm (Lucas Kanashiro) - update Changes 1.24 2015-02-27 - Don't distribute MANIFEST.SKIP - Update docs & code to require perl 5.008 - Define MIN_PERL_VERSION to pass Kwalitee checks in Makefile.PL (Doran L. Barton) - Added =encoding utf8 to pass Test::Pod/Kwalitee tests. Added t/pod.t (Doran L. Barton) 1.23 2014-07-09 - Add git repo - Rely on Inline "with" hook error message - use "our" not "use vars" 1.22 2014-06-30 - Use updated Inline "with" hook API 1.21 2012-12-14 - http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2012-12/msg00424.html (C warnings avoidance) 1.20 2011-07-27 - Repair test again 1.19 2011-07-24 - Really skip the bad fd test on platforms that don't support it Considering how much trouble this test has caused, I question whether it is worth keeping it. 1.18 2011-06-25 - Repair test to use a truly read-only variable Fix suggested by Father Chrysostomos 1.17 2011-05-18 - Skip bogus fd test for GNU Hurd A test report from Nigel Horne suggested that GNU Hurd either does not support detection of bogus fds or supports it differently than Linux. I do not have Hurd available for testing so I will simply skip the test. - On windows, skip tests correctly APOCAL@cpan.org wrote: The module failed to pass the tests because it emitted incorrect TAP plan. After consulting with some people on IRC and looking at the TAP manual, I found the solution. It seems you were using the "old-style" TAP printouts and with the latest Test::Harness, it complains! The fix is to change those 4 tests: hup, io, reenter, and signal. You need to print one line for the skip, not two! The TAP doc can be found here: http://search.cpan.org/~petdance/TAP-1.00/TAP.pm#Skipping_tests 1.15 2011-05-03 - Clarify conditions for skipping test Spotted by George Hartzell 1.14 2011-05-03 - change skip condition 1.13 2009-09-30 - Freshen MANIFEST - Note new GIT repo location: http://gitorious.org/perl-event/mainline - Add errata for tutorial 1.12 2009-08-26 - Point people to Marc Lehmann's stuff - Skip bogus fd test for armv5tejl 1.11 2008-05-17 - s/double/NV/g to support uselongdouble - Make debug code compile again - Increase minimum version of perl to 5.006_003 - This test is too sensitive to load on the machine causing random failures. Better to remove it from the regression test battery. 1.10 2008-01-15 - min perl 5.006 - Skip bogus_fd test on darwin. Reported by schwern@pobox.com. - Jerry D. Hedden and Ævar Arnfjörð Bjarmason correctly diagnosed that a recent change in perl (#31130, FETCH/STORE/LENGTH callbacks for numbered capture variables) caused $1 to loose its read-only-ness hence breaking test 6. Zefram suggested using $$ instead. I have not tested this patch but it seems trivial enough. 1.09 2007-05-22 - doc git location git://nirmalvihar.info/home/joshua/event.git 1.08 2006-11-01 - Add casts to quell warnings as suggested by JDHEDDEN@cpan.org. 1.07 2006-10-10 - Marc Lehmann suggests using mg_ptr instead of mg_obj. Sounds good to me. 1.06 2005-05-14 - Fix 64 bit issue. Encouraged by Eric Rybski . 1.05 2005-04-24 - Fix ancient memory leak in loop() noticed by Nikita Savin . 1.04 2005-03-29 - Preliminary /dev/poll support from Michael Pergament . As of yet, there is no config test to turn on this code. Patches welcome. 1.03 2005-01-31 - Apply Win32 patch from Graciliano M. P. . 1.02 2004-12-08 - Generic watchers: implementation, documentation, and tests. - Documentation refinements. 1.01 2004-11-29 - Event.xs: Due to popular demand, queue_pending() is now a public API, for better or worse. Beware of race conditions. - A var watcher can currently be created with no variable to watch, provided of course that it is parked. However, once a variable has been set, the watcher cannot be returned to the no-variable state. The variable to watch can be changed, but the watcher rejects any attempt to set the reference to undef. Applied a patch to allow the variable reference of a var watcher to be set to undef. - Applied patch to clarify the documentation (with tweaks from Joshua). 1.00 2004-05-14 - c/watcher.c (pe_watcher_now): Check for a missing callback, not only a missing perl callback. Marc A. Lehmann - lib/Event.pm (import): Make NO_TIME_HIRES actually work. Jerry D. Hedden - c/signal.c (pe_signal_stop): When a signal watcher stops, the signal counter is cleared. Otherwise the signal watcher can generate one last event after being stopped, which is a bug. (Pointed out by Zefram ) 0.88 2004-04-21 - lib/Event.pm: Simplify hooking into Time::HiRes. Add a NO_HIRES_TIME export_ok symbol to turn off the probing. - Event.xs: Remove U2time. Remove install_time_api(). - lib/Event.pod: More refinement from Zefram . - lib/Event.pod: ($watcher->pending & signal watchers): More specific description by Zefram . - c/watcher.c (pe_watcher_now): Fix SEGV reported by Zefram . Add test. - lib/Event.pod (timer): Correction by Randal L. Schwartz . - lib/Event.pod (timer): Doc clarification (jdhedden@1979.usna.com). 0.87 2003-02-18 - c/var.c (tracevar_r, tracevar_w): Fix declaration for recent versions of perl (patch from Nick Eggleston ). 0.86 2002-05-25 - c/unix.c: Solaris works better without POLLWRBAND (Clemens Schrimpe ). 0.85 2002-02-01 - Apply patch from Allen Smith to avoid infinite polling loop on some select implementations. Also reported by Marc Lehmann . 0.84 2002-01-23 - Doc StarvePrio (Allen Smith ). - Remove IRIX special casing. Reports indicate that new versions of IRIX don't need any hacks. (Allen Smith ) 0.83 2001-06-22 - Waste less time in timeable.c. (Peter Lombard ) 0.82 2001-06-21 - Stop watcher if $w->cb(undef) (Damien Neil ) 0.81 2001-01-31 - Fix callback.t fail without Time::HiRes. - Fix typo in EventAPI.h. 0.80 2000-12-07 - Update Tutorial.pdf to Jochen's latest. - Remove silly warning on $io->poll(T). - Fix $DIED doc. (paul@miraclefish.com) - Change C callback prototype to (void(*)(pe_event*)) at request of Jochen. - Warn if loop without active watchers. - Slightly more reliable default_exception_handler. - Inline 0.30 integration (briani@activestate.com) 0.79 2000-11-17 - Removed Event/inactivity.pm - #undef HAS_POLL for sgi (treygraves@yahoo.com) - Moved REENTRANT & HARD flags to EventAPI.h. (Jochen) - Removed obsolete CBTIME flag. (Jochen) - EventAPI += sv_2interval. (Jochen) - Applied patch for IRIS poll() from R.de.Vries@fokkerspace.nl - EventAPI += unloop_all. 0.78 2000-05-24 - Invoke Carp::carp for internal warnings. - Fix SEGV triggered when Event-Stats is enabled while loop is nested. 0.77 2000-05-12 - Fixed an obscure SEGV discovered by uri@sysarch.com. - EventAPI += NVtime. 0.76 2000-04-26 - Fixed a horribly subtle bug in the handling of reentrant INVOKE1-style watchers (e.g. a timer) in nested loops. Added test. This change also removes at least one conditional from a hot code path. - EventAPI += unloop. 0.75 2000-04-24 - Attributes called in "set" mode now return the new value. - Renamed data() to private() and added back the old data(). Added tests & updated the pod. 0.74 2000-04-19 - Resolved data() quandary. Added test. - Updated perlqt.t example. - Spell checked pod. 0.73 2000-03-24 - Fix for 5.6.0 with implicit context enabled. - Rename unix_io.c -> unix.c in anticipation of Win32 support. - Offer assurance about future compatibility (docs). 0.72 2000-03-10 - Rename NetServer::ProcessTop -> NetServer::Portal. - Removed unused QUEUED & RUNNING flags. - Made pending() aware of context. Added tests. 0.71 2000-03-03 - Moved LoopLevel & ExitLevel from Perl to C, squeezing out some potential bugs. - Fixed SEGV triggered if $DebugLevel >= 4. - Warn on unmatched unloop. - Added Tutorial.pdf (by Jochen). - Moved semaphore & msg into demo directory. No one has ever asked for them to be finished, so they aren't. 0.70 2000-02-25 - Fix bug in select() engine spotted by perl@jochen-stenzel.de - Prune demo directory. - Add repeat.t demo. (perl@jochen-stenzel.de) - Add perlqt.t demo. 0.69 2000-02-18 - Tweak documentation. 0.68 2000-02-15 - More careful checking of intervals. (suggested by perl@jochen-stenzel.de) - Fix yet another typemap bug. (perl@jochen-stenzel.de) - Make io default to poll=r; more stringent start test; fix demo/stdin.t (suggested by perl@jochen-stenzel.de) 0.67 2000-02-09 - Fix bomb in group watchers. (perl@jochen-stenzel.de) - Fixed another bug introduced in 0.61. (Insure++) - Tighten typemap. - Warn about non-existant methods. 0.66 2000-02-08 - Fix horrendously subtle bug uncovered by Event-tcp. - Eliminate (hopefully all) silent failures. - Restrict var watchers to scalars. (perl@jochen-stenzel.de is too creative) 0.65 2000-02-07 - Group watchers for watching watchers. See demo/group.t - Fix got() documentation, spotted by perl@jochen-stenzel.de - Make callback a prerequisite for starting watchers. - Add test checking FIFO dispatch of equal priority events. 0.64 2000-02-04 - Applied patch from gbarr@pobox.com that allows one to obtain the number of events a watcher has pending in the event queue. Also, included was a cosmetic fix for the typemap. - Load the basic watcher types by default. - Adjust hup.t test (conrad@fringehead.org). 0.63 2000-02-03 - Allow var watchers to watch the same variable. - Deprecated AUTOLOAD of Event->$type. (Nick & Graham) - Reworked priority documentation based on comments from perl@jochen-stenzel.de. 0.62 2000-02-01 - Allow implied stop() if required attributes are explicitly unset. 0.61 2000-01-31 - is_cancelled() method (requested by perl@jochen-stenzel.de) - Doc updates. - Prevent starting unconfigured or badly configured watchers. Added tests. (perl@jochen-stenzel.de) XXX DANGER! THIS CHANGE CAN BREAK EXISTING CODE !DANGER XXX - Refuse to start cancelled watchers. Added test & updated doc. (perl@jochen-stenzel.de). - If parked=>1 then the constructor will not invoke $watcher->start(). (uri@sysarch.com) 0.60 2000-01-26 - Added $watcher->data() attribute. (This is Uri Guttman 's fault.) - Fixed refcnt problem caused by extra invocations of cancel() (Discovered by uri@sysarch.com.) Added test. 0.59 2000-01-20 - Fixed serious memory leak (isolated by perl@jochen-stenzel.de). Added t/leak2.t. - Doc for timeout_cb (demanded by uri@sysarch.com :-). - Added demo/variable_timer.t along with minor doc update. (jsalmon@gw.thesalmons.org) 0.58 1999-11-22 - timeout_cb for io watchers. Added test. (suggested by Uri Guttman ) - Copy the callback specification from watcher to event for flexibility. - Removed support for clump. The performance trade-off for this feature was probably unmeasurable. Now it's definitely unmeasurable. :-) - Rename Ev* macros to Wa* to make room for new Ev macros. - Remove EvNOW macro. - Added demo/readline.t. (perl@jochen-stenzel.de) 0.57 1999-10-06 - Memory leak fixed: ioevents were being retired to the wrong freelist. (thospel@mail.dma.be) - Document is_active/is_suspended. (perl@jochen-stenzel.de) - Skip hup.t on Win32. (Paul.Moore@uk.origin-it.com) 0.56 1999-09-22 - Fixed detection of EOF. Added test. (Gisle Aas) - Figured out the strange pipe symantics on AIX and modified the io.t test to cope. (dfavor@austin.ibm.com) 0.55 1999-09-13 - Changes for clean threaded build against 5.5.61. Unfortunately, this breaks threaded 5.5.3. If this is a problem for you then send patches. The threading variations in the devel track are driving me crazy. (dfavor@austin.ibm.com) - Fixed coredump trigger by attach_to test (cpan-testers@perl.org). 0.54 1999-09-10 - Improved cb(...) diagnostics. Added tests. - Devel-PPPort (schinder@pobox.com of cpan-testers@perl.org). - If a file is unexpectedly closed, the io watcher is no longer stopped. Instead the file handle is reset. This symantic allows io timeouts to continue to trigger and should make recovery simpler. Added tests. - Prohibit attach_to blessed refs. Added test. - Minor doc updates. 0.53 1999-09-09 - Fix Event::MakeMaker to pick the correct install directory. - This release is NOT binary compatible with 0.52! - Obscure potential typemap bugs fixed. - Reworked the typemap to avoid the exotic 5.6 self-tied hash mechanism. It should now be fairly easy to backport Event to older versions of perl. - In the tradition of adding innovative (or at least strange) features to Event, constructors now accept (attach_to=>$ref). This will cause the watcher to attach its information to the given $ref instead of to a fresh anonymous hash ref. For backwards compatibility the default is still an anonymous hash. - Removed a bunch of deprecated features. - Reformatted the source to be more consistent (if not beautiful). 0.52 1999-08-18 - Moved t/inactivity.t to demo/ because it fails occationally and I don't have time to figure it out. You might say that it takes too much time to write a good test of inactivity. - Make mention of Time::Warp. - Don't complain about Time::HiRes (uri@sysarch.com) - Skip t/idle2.t if Time::HiRes is unavailable (lukka@iki.fi & gbarr@pobox.com). 0.51 1999-07-23 - Notice bogus fds in both poll & select. Added test. - Make mention of the mailing list archive. - Don't request benchmark results (artur@vogon.se). 0.50 1999-07-15 - A few Win32 tweaks to get working tests to pass (jan.dubois). - Minor cleanup in preparation for 0.50. 0.44 1999-06-30 - Release 0.44 (thanks: jan.dubois@ibm.net). - Renamed abort() to scrub() to avoid clashing with Perl's abort. - Removed remaining dependency on gettimeofday. - C++ clean. 0.43 1999-06-22 - Tweaks for threaded compile (dfavor@austin.ibm.com). 0.42 1999-06-19 - Rename event.c -> ev.c (Jan Dubois). - Split flags into individual methods: is_running, is_active, is_suspended, is_queued. - Repaired default_exception_handler. 0.41 1999-05-19 - Added attributes() and configure() methods. - When using eval {} inside a callback, $@ could fool Event into thinking that an exception is being thrown. - Moved attributes from hash entries to methods. - Fix unloop(''). - Regularize event constructors. - Doc fixes catalyzed by perl@jochen-stenzel.de. - Fix broken t/eval.t. - More conservative refcnt policy for watchers. - Rename 'mom' to 'w'. - Deprecate the accessing of watcher attributes via events. - Fix PL_ macros again. (*Argh!*) - Redesign typemap. - Make 'e_cbtime' available from perl. Added test. - Return unloop_all($arg) from loop(). - Make compile with threaded perl. - Documentation updates and reorganization. - Switch inactivity from e_interval to e_timeout. - Plug typemap holes. Implementation still needs improvement. - Make io timeout respect e_repeat. (gisle@aas.no). 0.33 1999-03-30 - Store 'e_max_cb_tm' and hand-off to stats engine. - Morph events into watchers when they go out of scope. - Refine typemap fix. 0.32 1999-03-15 - Apply typemap fix as per gsar@activestate.com. 0.31 1999-03-09 - Simplified typemap in an attempt to squash bugs. - Search @INC in Event::MakeMaker. - Make io timers non-repeating. - Relax io watchers more. Now they can be started with either e_fd or e_timeout or both or neither. - Allow creation of io watchers without a valid e_fd. Should probably do the same with the rest of the watcher types. - Added e_suspend. Do we keep the 'suspend' and 'resume' methods? - Fixed refcnt problem triggered by deleting hash entries. Added test. - Avoid qr// in keys.t. - Reroute C-API croak through Carp::croak. Added test. - Removed backward compatibility up to 0.24 (inclusive). - Factored event init/dtor code. - Added 'callback' hooks. Updated docs. 0.30 1999-02-04 - Constructors now populate the watcher hash with any extra unrecognized key-value pairs. - Better typemap diagnostics. There seem to be bugs lurking but I can't construct a short test case... - Arrange for events to have the same careful typemap treatment as do watchers. Added test. - Unplugged Time::Virtual (suggested mainly by Sarathy, Nick and Graham). See patches/time-hires. - Added AllWatchers & typemap functions to the public API. - Moved Event::Stats to a separate tarball. I wonder if the stats API is too restrictive? - Split Event::Watcher code into a separate file for intuitive importing via 'use' (suggested by artur@vogon-solutions.com). - Fix SEGV in keys %$event (ophir@internap.com & artur@vogon-solutions.com). Added test. - Tweaks to diagnostics. - Event destruction now must be managed explicitly. Use the 'stop' method to disable a watcher and use 'cancel' to destroy a watcher. This change is an unfortunate necessity because of optimizations in perl's reference counting. - Suspend & cancel now abort any pending events. In previous releases, the callback could be called after cancel in some cases. - Replaced newHVhv. Some versions of perl have a buggy implementation. - Fixed a few minor problems detected by Insure++. - Fixed typos in croak messages. - Generous updates to Event.pod. - Renamed (lots of) keys. - Added 'use_keys' method. Comments? - (Try to) remove support for leading dashes (any left?). - Factor out code to Time::Virtual (& Time::HiRes). - Moved process.pm to demo directory. - Added discussion of event loops vs. threads (kudos to Mark.Mielke.markm@nt.com & fellow loop'ers). 0.25 1998-11-20 - Move SAVETMPS/FREETMPS up to Event::_loop. - Split ACTIVE flag into two separate flags, ACTIVE & POLLING, to more accurately track watcher state. - Tweaks to io 'events' mask handling. - Move @EXPORT_OK list for qw(R W E T) to Event::Watcher. - Fix SEGV in all_watchers/all_idle if zero watchers present. - Nuke obsolete backward support code in io.c. (Poll constants to set event mask.) - Rename event_vtbl->watcher. 0.24 1998-11-01 - Reengineered hash-object implementation to use HVs. - Removed tailpoll support from io watchers. File::Tail can just hook up with timers & a generic "block on read" API can be built on top of that if need arises. Nick, this okay? - Split watchers & events into separate C structures. - Fixed misbehaving autoload code. - END hook to cancel all events before global destruction. Still needs more work to be sure the memory is freed. - Fixed bad arithmetic in io timeout code. Renamed interval epsilon and added better diagnostics (see Event::_timeout_too_early). - Timers cancelled within their callback weren't! Fixed. - Fix typo in c/queue.c (thanks again Jan!). 0.23 1998-10-18 - Unified Perl & C API for hooks. - Niggles for Win32 (thanks Jan!). 0.22 1998-10-17 - Include copy of self-tie patch with dist. - Documentation for Event::MakeMaker. - tailpoll revamped. - MIN_PERL_DEFINE clean. - Improve sv_2interval typemap. 0.21 1998-10-08 - Try to normalize benchmark. - 'now' was broken for inactive events. Fixed & added test. - Fixed infinite loop triggered by botched exception recovery. 0.20 1998-10-06 - Rename inactive to inactivity. - Use new self-tie to wrap watcher objects. Leak test now passes for almost all watcher types. - Slight improvements to gettimeofday.c. - Merged c_callback & perl_callback into one pointer slot. - Added timeable methods to the public API. - Var watchers weren't working very well. Set up events/got mask stuff mirroring io watchers. Added tests. Does anyone really want timeouts? 0.19 1998-10-03 - Put in code for tailpoll, but I can't tell if it works because the tail-f behavior seems to already happen automatically. Comments? See demo/tail.t. - Added inactive watchers (& tests). - timeable API changes to allow multiple timers per watcher. - Fixed non-ANSI function declaration in c/signal.c - Reduced C API. - Renamed queueEvent to queue. - Fixed refcnt problem in DELETE. - Dashes depreciated. - Added -timeout to process watchers. Might be useful. - Fixed typo induced polling in one_event. - Moved R/W/E/T flags to Event from Event::io. - Changed the arguments to $Event::DIED in order to cope with $Event::DIED dieing. Fixed sweep exception handling. Added test. - Watchers created with the C API now should require their perl support code automatically. Moved idle support to an autoloaded pm. - Added sweep & loop($timeout). Fixed sleep. 0.18 1998-10-02 - Added non-working export_fail prototype. Suggestions welcome. - Re-factored start & stop better (the preCB method is gone). - Finished up sleep(). Added tests. - Tied watchers are now based on pe_tmevent. - Applied patch from Gisle for pe_sys_sleep/select. - Renamed 'watchvar' to 'var'. - Added tests for 'now' (it was completely broken!). - Tweaked debug levels. Someone needs to inventory debug warnings are decide what is reasonable. 0.17 1998-10-01 - Added tests. - Added sleep(). Truly a tortuous experience. - Added min/max interval to idle watchers. - c_callback no longer prevents watcher destruction. Use refcnt! - Renamed various C APIs for accuracy (unix_io.c). - Reentrant flag added. - loop() now terminates when there are no active watchers left. - Depreciated async. Moved -priority to -nice & added warning. - Fixed minor stuff. - Make io timeouts work for real. (Thanks Gisle :-) 0.15 1998-09-29 - Improved the EventAPI.h version check. - Added -timeout for io watchers. Untested. - Fix io watcher bugs (unix_io.c) pointed out by Gisle Aas. 0.14 1998-09-28 - Gutted the internals to make events reentrant. - The $Now cache was not being refreshed and that was causing timers to be queued, well, never. - Fixed whitespace in Event.pod. (Gisle Aas again.) - Optimized priority queue (hopefully). I probably should have benchmarked it first. :-P 0.13 1998-09-27 - Moved and renamed lots of methods. Yet, added code to ease backward compatibility. (perl-loop suggested) - Integrated rewritten documentation contributed by Gisle Aas. Thanks! 0.12 1998-09-22 - Event::MakeMaker & event_api.h. - Add 'total' stat. Moved stat methods to Event::Loop package. 0.11 1998-09-11 - Regularized exception handling. $Event::DIED is now called if an event dies. - Allow timer interval to be a scalar ref. - Tweaked queue scheduling. Events with priorities <= 5 now starve if higher priority events are available. - Changing the event priority of a queued event will now reque the event into the appropriate queue. - Split NetServer::ProcessTop into it's own tarball. 0.10 1998-09-03 - Fixed serious bug in the event destructor. - Accept file descriptor numbers in addition to filehandles, etc. Maybe non-portable, but nice for unixen. - Fixed repeating timer logic. Tweaks for idle events. - Completed re-write of almost everything in C. - NetServer::ProcessTop implements a top-style control panel available via telnet ($$ % 7000). See util/top.pl. - Proxy "tied" event type that allows completely perl-side implementation of new event handlers. - Event::process is working again (implementation is entirely in perl). - Eliminated race conditions in signal handling. - Zombie events are still not being collected due to mysterious refcnt problems. It is possible that this cannot be resolved until perl implements tied hashes properly (through a VTBL!). - Removed $Event::*::Count since it is superceded by NetServer::ProcessTop. 0.08 1998-08-14 - C rewrite 0.07 1998-08-05 - test callbacks - doc queuing - remove debugging 0.06 1998-07-24 - parameterise register method so 'check' not fixed method but callback - doc priorities - doc callbacks 0.05 1998-07-20 - queuing, waiting - Status method 0.04 1998-07-20 - registering forces class to be child of Event - add waitForEvents 0.03 1998-07-18 - Event::watchvar now passes $ref to callback - added use attrs qw(locked method) to all subs, and code to ensure this will work on pre-threaded perl - Event.xs Fixed so will compile with threaded perl - Event::timer Added -hard option - Tweaks to keys dispatchAsyncEvents() - added Time::HiRes - moved idle events into sub-module - Makefile.PL removed INSTALLDIRS => 'perl' 0.01 1998-01-26 - Initial Event-1.26/lib/0000755000076400007640000000000012727627261012033 5ustar useruserEvent-1.26/lib/Event.pod0000644000076400007640000007314412727626766013642 0ustar useruser=encoding utf8 =head1 NAME Event - Event loop processing =head1 SYNOPSIS use Event qw(loop unloop); # initialize application Event->flavor(attribute => value, ...); my $ret = loop(); # and some callback will call unloop('ok'); =head1 DESCRIPTION ALERT: Marc Lehmann may have taken over the future of event loops in Perl. Check out his libev library and EV Perl module. 25 Aug 2009 The Event module provide a central facility to watch for various types of events and invoke a callback when these events occur. The idea is to delay the handling of events so that they may be dispatched in priority order when it is safe for callbacks to execute. Events (in the ordinary sense of the word) are detected by B, which reify them as B (in the special Event module sense). For clarity, the former type of events may be called "source events", and the latter "target events". Source events, such as signals arriving, happen whether or not they are being watched. If a source event occurs which a watcher is actively watching then the watcher generates a corresponding target event. Target events are only created by watchers. If several watchers are interested in the same source event then each will generate their own target event. Hence, any particular source event may result in zero, one, two, or any number of target events: the same as the number of watchers which were actively watching for it. Target events are queued to be processed in priority order (priority being determined by the creating watcher) and in FIFO order among events of the same priority. Queued ("pending") events can, in some cases, be cancelled before being processed. A queued event is processed by being passed to the callback function (or method on a particular object or class) which was specified to the watcher. A watcher, once created, operates autonomously without the Event user having to retain any reference to it. However, keeping a reference makes it possible to modify most of the watcher's characteristics. A watcher can be switched between active and inactive states. When inactive, it does not generate target events. Some types of source event are not reified as target events immediately. Signals received, for example, are counted initially. The counted signals are reified at certain execution points. Hence, signal events may be processed out of order, and if handled carelessly, on the wrong side of a state change in event handling. A useful way to view this is that occurrence of the source event is not actually the arrival of the signal but is triggered by the counting of the signal. Reification can be forced when necessary. The schedule on which some other events are created is non-obvious. This is especially the case with watchers that watch for a condition rather than an event. In some cases, target events are generated on a schedule that depends on the operation of the event loop. =head1 PERL API Events (the occurrence of such) are noticed and queued by 'event watchers'. The creation and configuration of event watchers is the primary topic of the rest of this document. The following functions control or interrogate the event loop as a whole: =over 4 =item $result = loop([$timeout]) Will enter a loop that calls one_event() until unloop() is called. The argument passed to unloop() is the return value of loop(). Loops can be nested. =item unloop($result) Make the inner-most loop() return with $result. =item unloop_all($result) Cause all pending loop()s to return immediately. This is B implemented with C. It is works as if C were called for all nested loops. =item sweep([$max_prio]) Queue all pending events and dispatch any with priority strictly less than $max_prio (the highest priority is 0). The default is to process all events except idle events. (While idle B are ignored by sweep, idle watchers are B ignored. If you want to avoid triggering an idle watcher then set C to C or C it.) =item one_event([$timeout]) If any events are outstanding then invoke the corresponding callback of the highest priority event. If there are no events available, block forever or until $timeout. Use of this API is not recommended because it is not efficient and does not trap exceptions. However, you might wish to understand how it works: =over 4 =item 1 Queue asyncronous events (signals, etc). That is, previously recorded events are reified. =item 2 If there are any events with priority 5 or less (see StarvePrio) then service the next one and return. =item 3 Calculate the maximum wait time (minimum time till the next timer expiration) and pass control to the poll/select system call. Upon return, queue all pending events. =item 4 Queue asyncronous events again. =item 5 If there are any events then service the next one and return. =item 6 Service the next idle watcher. =back StarvePrio is the priority level for which events are dispatched during step 2. It cannot be changed without a recompile. In the rare case that an event is always pending at step 2 then I/O watchers will starve. However, this is highly unlikely since async watchers should never queue events so rapidly. =item all_watchers() Returns a list of all watchers (including stopped watchers). =item all_running() Returns a list of all watchers with actively running callbacks. Watchers are returned in order of most recent to least recent. =item all_idle() Returns a list of all the idle watchers. If the event queue is very busy, all the idle watchers will sit on the idle queue waiting to run. However, be aware that if an idle watcher has the C attribute set then it will queue a normal event when its C wait time is exceeded. =item queue_pending() Examines asynchronous source events (timers & signals) and reifies them as target events. C is only called implicitly by C and C. Otherwise, C is not called implicitly. NOTE: Signal watchers generate target events according to which watchers are active at the time that C is called rather than according to the time the signal is received. This is best explained by example. See the file C. =back =head2 Event Watcher Constructors All watchers are constructed in one of the following ways: $w = Event->flavor( [attr1 => $value,]... ); $w = Event::flavor($Class, [attr1 => $value,]...); $w = Event::flavor->new([attr1 => $value,]...); Where I is substituted with the kind of watcher. Built-in types include idle, io, signal, timer, and var. New watchers (hopefully) have reasonable defaults and can also be customized by passing extra attributes to the constructor. When created, watcher objects are "started" and are waiting for events (see C<$event-Estart> below). NetServer::Portal can display watchers in real-time, formatted similarly to the popular C program. You may find this a useful aide for debugging. =head2 Shared Watcher Attributes Watchers are configured with attributes (also known as properties). For example: $watcher->cb(\&some_code); # set callback warn $event->w->desc.": ".$event->hits." events happened; Wow!"; All watchers support the following attributes: cb, cbtime, debug, desc, prio, max_cb_tm, reentrant, and repeat. Watcher constructors accept the preceding and additionally: async and nice. Moreover, watchers also offer extra attributes according to their specialty. =head2 Shared Watcher Methods The following methods are available for all watchers: =over 4 =item $watcher->start Activate the watcher. Watchers refuse to C without sufficient configuration information to generate events. Constructors always invoke C unless the C<< parked=>1 >> option is requested. You will need to set the parked option if you preallocate unconfigured watchers. Note: If there are any unreified asynchronous events that are of interest to the watcher, it will see these events even though they happened before it was started. This affects signal watchers, but there will only be existing unreified signal events if Event was already handling the signal, which it would only do if there were another active watcher for the same signal. If this situation might occur, and it would be a problem for the new watcher to see older events, call C immediately before starting the new watcher in order to reify any outstanding events. This explanation may be more clear if read along with C. =item $watcher->again This is the same as the C except if a watcher has special repeat behavior. For example, repeating timers recalculate their alarm time using the C parameter. =item $watcher->now Cause the watcher to generate an event, even if it is stopped. The callback may or may not run immediately depending upon the event's priority. If you must unconditionally invoke the callback, consider something like $w->cb->($w); =item $watcher->stop Don't look for events any more. Running events are allowed to complete but pending events are cancelled. Note that a stopped watcher can be reactivated by calling the C or C methods. Watchers are stopped implicitly if their new configuration deprives them of the ability to generate events. For instance: my $io_watcher = Event->io(timeout => 1); # started $io_watcher->timeout(undef); # stopped implicitly $io_watcher->timeout(1); # still stopped $io_watcher->start; # restarted =item $watcher->cancel Stop and destroy C<$watcher>. Running events are allowed to complete but pending events are cancelled. Cancelled watchers are no longer valid except for read-only operations. For example, prio() can return the watcher's priority, but start() will fail. =item $watcher->is_cancelled Reports whether the C<$watcher> has been cancelled. =item $watcher->is_active Reports whether the C<$watcher> has been started. The return value is not affected by suspend. =item $watcher->is_running Zero if the callback is not running. Otherwise, the number of levels that the callback has been entered. This can be greater than one if a C callback invokes C (or C, with lesser probability). =item $watcher->is_suspended Reports whether the C<$watcher> is suspended. Suspension is a debugging feature; see the discussion of the "suspend" attribute below. =item $watcher->pending In scalar context, returns a boolean indicating whether this watcher has any events pending in the event queue. In array context, returns a list of all the watcher's pending events. Note that this does not check for unreified asynchronous events. Call C first if you want to see signals received since the last operation of the event loop. =back =head2 Watcher Types =over 4 =item idle Extra attributes: min => $seconds, max => $seconds Watches for the Event system to be idle, i.e., to have no events pending. If the system is never idle, an event will be generated at least every C seconds. While Event is idle, events will be generated not more often than C seconds. If neither C nor C is specified, the watcher defaults to one-shot behaviour (C false), otherwise it defaults to repeating. In either case, the default can be overridden by specifying a C attribute. C defaults to 0.01, and C defaults to infinity. =item var Extra attributes: var => \$var, poll => 'rw' Var watchers generate events when the given variable is read from or written to, as specified by C. C defaults to "w". As perl is a concise language, it is often difficult to predict when a variable will be read. For this reason, variable watchers should poll only for writes unless you know what you are doing. =item timer Extra attributes: at => $time, after => $sec, interval => $sec, hard => $bool Generate events at particular times. The C<$time> and C<$sec> are in seconds. Fractional seconds may be used if Time::HiRes is available. C and C are mutually exclusive. C or C specify the initial time that the event will trigger. Subsequent timer events occur at intervals specified by C or C (in that order of preference) if either was supplied. The timer defaults to one-shot behaviour if C was not specified, or repeating behaviour if C was specified; in either case this can be overridden by providing C explicitly. You need to know the time at the start of today if you are trying to set timers to trigger at day relative times. You can find it with: use Time::Local; my $TodaySeconds = int timelocal(0,0,0,(localtime)[3,4,5]); This calculation may seem a little heavy weight. If you want to use UTC rather than local time then you can use this instead: my $TodaySeconds = time - time % 86400; Beware that, due to lags in the event loop, the C timeout may already be in the past. If the C flag is set, the event will be queued for execution relative to the last time the callback was invoked. However, if C is false the new timeout will be calculated relative to the current time. C defaults to false. =item io Extra attributes: fd => $fd, poll => 'rwe' [timeout => $seconds, hard => $bool, timeout_cb => \&code] The callback is invoked when the file descriptor, C, has data to be read, written, or pending exceptions. C can be a GLOB, an IO::Handle object, or a file number (file descriptor). C defaults to "r". Note that it is your option whether to have multiple watchers per file handle or to use a single watcher for all event conditions. If C is set, events are also generated regularly if no actual I/O event occurs. If C is set then timeouts use this alternate callback instead of the main callback. =item signal Extra attribute: signal => $str Generates events based on signal arrival. The events are not actually generated immediately when the signal arrives: signals received are counted and reified by C or implicitly by C. Several signals of the same type may be merged into a single event. In such cases, the number of signals represented by a single event is stored in the "hits" attribute. =back =head2 PRIORITY Priority is used to sort the event queue. Meaningful priorities range from -1 to 6 inclusive. Lower numbers mean higher priority (-1 is the highest priority and 6 is the lowest). If multiple events get queued, the ones with the highest priority are serviced first. Events with equal priority are serviced in first-in-first-out order. use Event qw(PRIO_HIGH PRIO_NORMAL); # some constants LEVELS: -1 0 1 2 3 4 5 6 ----------------------+-------------+--------------- PRIO_HIGH PRIO_NORMAL A negative priority causes the callback to be invoked immediately upon event occurrence. Use this with caution. While it may seem advantageous to use negative priorities, they bypass the whole point of having an event queue. Each watcher has a I, assigned by its constructor: io PRIO_NORMAL signal PRIO_HIGH timer PRIO_NORMAL var PRIO_NORMAL Default priorities are stored in ${"Event::${type}::DefaultPriority"}. If the default priority is not satisfactory for your purposes, the constructor options C, C, or C can be used to adjust it. C specifies an offset from the default priority; C forces the priority to -1; and C assigns a given priority of your choice. If more than one of these options are given then C overrides C overrides C. =head2 WATCHER CONSTRUCTOR ATTRIBUTES These options are only supported as constructor arguments. =over 4 =item after => $seconds See the discussion of the timer watcher. =item async => $bool If $bool then the watcher priority is set to -1. =item nice => $offset Offset from the default priority. =item parked => $yes By default, watcher constructors automatically invoke the C method. If you don't want the watcher started then request C<< parked=>1 >>. =back =head2 WATCHER ATTRIBUTES =over 4 =item at => $time The expiration time in the same units as the system clock. For a timer, C will usually be in the future. =item cb => \&code =item cb => [$class_or_object, $method_name] The function or method to call when an event is dispatched. The callback is invoked with C<$event> as its only argument. Perhaps you are wondering what happens if something goes wrong and an untrapped C occurs within your callback? C<$Event::DIED> is just for this purpose. See the full description of C below. =item cbtime => $time When the callback was invoked most recently. =item data => $anything The C method associates arbitrary data with a watcher. This method is not intended for implementers of watchers. If you are subclassing or implementing a watcher, consider the C method. =item debug => $bool Debugging can be activated globally or per watcher. When debugging is enabled for a particular watcher, $Event::DebugLevel is treated as two levels higher. Levels of 1, 2, 3, or 4 give progressively more diagnostics on STDERR. =item desc => $string An identifying name. If this is not passed explicitly to the constructor, it will be initialized with a string that attempts to identify the location in the source code where the watcher was constructed. =item fd => $filehandle This attribute can accept either a perl-esque filehandle or a system call derived file descriptor number. =item hard => $bool Determines how repeating timers (or timeouts) are recalculated. The timer is restarted either before or after the callback depending on whether it is true or false, respectively. In long-running callbacks this can make a significant difference. =item interval => $seconds How long between repeating timeouts. The C attribute is recalculated using C upon callback return. =item max => $seconds The maximum number of seconds to wait before triggering the callback. Similar to a C. =item max_cb_tm => $seconds The maximum number of seconds to spend in a callback. If a callback uses more time then it is aborted. Defaults to 1 sec. This feature is normally disabled. See Event::Stats. =item min => $seconds Enforce a minimum number of seconds between triggering events. =item poll => $bits Determines which kinds of events are of interest. This attribute can be set with either strings or bit constants. The bit constants are available via 'use Event::Watcher qw(R W E T);'. string constant description ------ -------- --------------- 'r' R read 'w' W write 'e' E exception 't' T timeout Thus, both of these statements enable interest in read: $w->poll($w->poll . 'r'); $w->poll($w->poll | R); A given type of watcher may support all or a subset of the available events. =item prio => $level Changes the watcher's priority to the given level. Events generated by a watcher usually inherit the priority of the watcher. =item private => $anything Use the C method to associate arbitrary data with a watcher. This method is intended for implementers of watchers or watcher subclasses. Each caller's package accesses its own private attribute. =item reentrant => $bool By default, callbacks are allowed to invoke C or C which in turn may invoke the same callback again recursively. This can be useful but can also be confusing. Moreover, if you keep reentering callbacks you will quickly run out of stack space. Disable this feature per watcher by setting reentrant to false. This will cause the watcher to be suspended during recursive calls to C or C. =item repeat => $bool The repeat flag controls whether the callback should either be one-shot or continue waiting for new events. The default setting depends on the type of watcher. I, I, and I default to true. =item signal => $str The callback is invoked after the specified signal is received. The $str string should be something like 'INT' or 'QUIT'. Also see the documentation for C<%SIG>. A given signal can be handled by C<%SIG> or Event, but not both at the same time. Event handles the signal as long as there is at least one active watcher. If all watchers for the signal are cancelled or stopped then Event sets the signal handler to SIG_DFL. =item suspend => $bool Stop looking for events. Running events are allowed to complete, but queued events are cancelled. Suspend is for debugging. If you suspend all watchers in an application then you can examine the complete state unchanged for as long as you like without worrying about timer expirations. If you actually wish to stop a watcher then use the C method. =item timeout => $seconds The number of seconds before a watcher times out. =item timeout_cb => \&code =item timeout_cb => [$class_or_object, $method_name] This is an optional attribute for use when it is desired that timeouts be serviced in a separate code path than normal events. When this attribute is unset, timeouts are serviced by C. =item var => $ref A reference to the variable being watched. =back =head2 EVENT ATTRIBUTES =over 4 =item got => $bits C is available in the callback of watchers with C. C is in the same format as C except that it gives what kind of event actually happened. In contrast, C is just an indication of interest. =item hits => $int Signals in quick succession can be clumped into a single event. The number of signals clumped together is indicated by this attribute. This is always one for event types which don't clump. =item prio => $level Be aware that this priority can differ from the watcher's priority. For instance, the watcher's priority may have changed since the event was generated. Moreover, the C extension API offers the freedom to queue events of arbitrary priority. =item w => $watcher This method return the event's watcher. It is read-only. =back =head2 Customization and Exceptions =over 4 =item * $Event::DebugLevel Enables progressively more debugging output. Meaningful levels range from 1 (least output) to 5 (most output). Also see C. =item * $Event::DIED When C or C is called, an exception context is established for the duration of event processing. If an exception is detected then C<$Event::DIED> is invoked. The default hook uses C to output the exception. After the DIED handler completes, event processing continues as if nothing happened. If you'd like more detailed output you can install the verbose handler: $Event::DIED = \&Event::verbose_exception_handler; Or you can write your own. The handler is invoked like this: $Event::DIED->($event, $@); If you do not want to continue looping after an error, you can do something like this: $Event::DIED = sub { Event::verbose_exception_handler(@_); Event::unloop_all(); }; =item * Event->add_hooks(key => sub { ... }, ...); The bulk of Event's implementation is in C for B performance. The C method allows insertion of perl code at key points in the optimized event processing core. While flexible, this can hurt performance *significantly*. If you want customization *and* performance, please see the C API. Currently support hooks are detailed as follows: hook purpose ------------- ---------------------------------------------- prepare returns minimum time to block (timeable) check assess state after normal return from select/poll asynccheck check for signals, etc callback invoked before each event callback =back =head1 C API Event also has a direct API for callbacks written exclusively in C. See Event::MakeMaker. =head1 WHAT ABOUT THREADS? Event loops and threads are two different solutions to the same problem: asynchronous processing. Event loops have been around since the beginning of computing. They are well understood and proven to be a good solution for many applications. While event loops make use of basic operating system services, the bulk of their implementation is usually outside the kernel. While an event loop may appear to do many things in parallel, it does not, even on multiprocessor hardware. Actions are always dispatched sequentially. This implies that long running callbacks must be avoided because otherwise event processing is halted. Event loops work well when actions are short and to the point. Long-running tasks must be broken into short steps and scheduled for execution. Some sort of a state machine is usually required. While a big, complex application server is usually simpler to implement in a multithreaded fashion, a web browser can easily get by without threads. Consider a JPEG file download and render. When some new bytes are available they are sorted to the right place on the screen. Only a little state must be kept to keep track of how much has been rendered and to process subsequent incoming bytes. Threads can either substitute for an event loop or complement it. Threads are similar to processes in that the operating system manages task switching for you. However, the difference is that all threads share the same address space. This is good and bad. Higher performance can be achieved but since data is shared between threads, extreme care must be taken to access or modify global data. The operating system can switch threads at any moment or can execute multiple threads simultaneously. I hope this sounds dangerous! It is! Threads can introduce maddeningly complicated and hard to debug synchronization problems. Threads are like rocket fuel. They are essential when you really need them but most applications would be better off with a simple event loop. Even if threads are genuinely needed, consider confining them to the parts of an application where truly scalable performance is really worth the difficulty of a multithreaded implementation. For example, most GUIs applications do not need threads and most scientific compute intensive problems can be isolated from event dispatching. On the other hand, high performance transaction servers generally do mandate a truly multithreaded approach. Another consideration is that threads are not quite as widely available as event loops. While a few forward-thinking operating systems have offered threads since the beginning, their addition to many popular operating systems is much more recent and some still offer no threads support. If portability is a requirement, one must check that threads support is available and also carefully test a particular threads implementation to see whether it supports the features you need. It is likely that all platforms will have a solid implementation soon but at this point in history it is best to double check. Many suggestions by Mark Mielke =head1 WHAT ABOUT NON-PREEMPTIVE THREADS? The Java language is oriented to use non-preemptive threads, yet even Java uses an event-loop for Swing (AFAIK). That is one of the reasons I don't use Java for network-centric applications. My belief is that the benefit of multi-threading is the gain in performance on SMP hardware. In my view, non-preemptive threads (java green-threads) are usually poor design. I find them harder to work with, harder to debug, and slower for a rather marginal gain in readability. I really like working with a state machine. I find it leads to more stable and better code. It also has the benefit of abstracting away how concurrency is achieved. Contributed by artur@vogon-solutions.com, 12 Jul 1999. =head1 BUGS No support for epoll, or better, libevent. The scope of events is pretty strange compared to most other perl objects. I'm not sure if this is a bug or a feature (OK, probably it was a mistake). We'll probably want to re-work things for Perl6. The meaning of $io->timeout(0) might change. Use C to unset the timeout. There seems to be some sort of bug in the global destruction phase: Attempt to free unreferenced scalar during global destruction. Use of uninitialized value during global destruction. Explicit blessing to '' (assuming package main) during global destruction. =head1 THE FUTURE Even if this module does not end up being the One and True Event Loop, the author will insure that it is source compatible with its successor, or arrange for gradual migration. Back in the early days, the Event programming API was changing at every release. Care was taken to allow the old API to continue to work, and the transition was eased by printing out lots of warnings about the new usage. So you shouldn't sit on your hands in anticipation of the One and True Event Loop. Just start coding! =head1 ALSO SEE =over 4 =item * Useful and Fun Time::HiRes, NetServer::Portal, Time::Warp =item * Message Passing COPE, IPC::LDT, Event-tcp =item * GUI While Tk does not yet support Event, PerlQt does. =item * C API Inline =back =head1 SUPPORT If you have insights or complaints then please subscribe to the mailing list! Send email to: perl-loop-subscribe@perl.org =head1 AUTHOR Joshua N. Pritikin EFE =head1 ACKNOWLEDGMENT Initial 0.01 implementation by Graham Barr EFE. Other contributors include at least those lists below and folks mentioned in the ChangeLog. Gisle Aas Uri Guttman Nick Ing-Simmons (Tk) Sarathy Jochen Stenzel =head1 COPYRIGHT Copyright © 1997 Joshua Nathaniel Pritikin & Graham Barr Copyright © 1998, 1999, 2000, 2001, 2002, 2003, 2004 Joshua Nathaniel Pritikin All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Event-1.26/lib/Event/0000755000076400007640000000000012727627261013114 5ustar useruserEvent-1.26/lib/Event/signal.pm0000644000076400007640000000056712357140355014730 0ustar useruseruse strict; package Event::signal; use Carp; use base 'Event::Watcher'; use vars qw($DefaultPriority @ATTRIBUTE); $DefaultPriority = Event::PRIO_HIGH(); @ATTRIBUTE = qw(signal); 'Event::Watcher'->register; sub new { # lock %Event:: my $class = shift; my %arg = @_; my $o = allocate($class, delete $arg{attach_to} || {}); $o->init(\%arg); $o; } 1; Event-1.26/lib/Event/EventAPI.h0000644000076400007640000001446212357140355014700 0ustar useruser#ifndef _event_api_H_ #define _event_api_H_ /* The API for the operating system dictates which events are truly asyncronous. Event needs C-level support only for these types of events. */ typedef struct pe_watcher_vtbl pe_watcher_vtbl; typedef struct pe_watcher pe_watcher; typedef struct pe_event_vtbl pe_event_vtbl; typedef struct pe_event pe_event; typedef struct pe_ring pe_ring; struct pe_ring { void *self; pe_ring *next, *prev; }; struct pe_watcher { pe_watcher_vtbl *vtbl; SV *mysv; NV cbtime; /* float? XXX */ void *callback; void *ext_data; void *stats; int running; /* SAVEINT */ U32 flags; SV *desc; pe_ring all; /* all watchers */ pe_ring events; /* this watcher's queued events */ HV *FALLBACK; I16 refcnt; /* internal to Event; not perl related */ I16 prio; I16 max_cb_tm; }; struct pe_event { pe_event_vtbl *vtbl; SV *mysv; pe_watcher *up; U32 flags; void *callback; void *ext_data; pe_ring peer; /* homogeneous */ pe_ring que; /* heterogeneous */ I16 hits; I16 prio; }; /* This must be placed directly after pe_watcher so the memory layouts are always compatible. XXX? */ typedef struct pe_timeable pe_timeable; struct pe_timeable { pe_ring ring; NV at; }; typedef struct pe_qcallback pe_qcallback; struct pe_qcallback { pe_ring ring; int is_perl; void *callback; void *ext_data; }; /* PUBLIC FLAGS */ #define PE_REENTRANT 0x0008 #define PE_HARD 0x0010 #define PE_DEBUG 0x1000 #define PE_REPEAT 0x2000 #define PE_INVOKE1 0x4000 #define WaFLAGS(ev) ((pe_watcher*)ev)->flags #define WaDEBUG(ev) ((WaFLAGS(ev) & PE_DEBUG)? 2:0) /*arthimetical*/ #define WaDEBUG_on(ev) (WaFLAGS(ev) |= PE_DEBUG) #define WaDEBUG_off(ev) (WaFLAGS(ev) &= ~PE_DEBUG) #define WaREPEAT(ev) (WaFLAGS(ev) & PE_REPEAT) #define WaREPEAT_on(ev) (WaFLAGS(ev) |= PE_REPEAT) #define WaREPEAT_off(ev) (WaFLAGS(ev) &= ~PE_REPEAT) #define WaREENTRANT(ev) (WaFLAGS(ev) & PE_REENTRANT) #define WaREENTRANT_on(ev) (WaFLAGS(ev) |= PE_REENTRANT) #define WaREENTRANT_off(ev) (WaFLAGS(ev) &= ~PE_REENTRANT) #define WaHARD(ev) (WaFLAGS(ev) & PE_HARD) #define WaHARD_on(ev) (WaFLAGS(ev) |= PE_HARD) /* :-) */ #define WaHARD_off(ev) (WaFLAGS(ev) &= ~PE_HARD) #define WaINVOKE1(ev) (WaFLAGS(ev) & PE_INVOKE1) #define WaINVOKE1_on(ev) (WaFLAGS(ev) |= PE_INVOKE1) #define WaINVOKE1_off(ev) (WaFLAGS(ev) &= ~PE_INVOKE1) /* QUEUE INFO */ #define PE_QUEUES 7 /* Hard to imagine a need for more than 7 queues... */ #define PE_PRIO_HIGH 2 #define PE_PRIO_NORMAL 4 /* io-ish flags */ #define PE_R 0x1 #define PE_W 0x2 #define PE_E 0x4 #define PE_T 0x8 typedef struct pe_ioevent pe_ioevent; struct pe_ioevent { pe_event base; U16 got; }; typedef struct pe_datafulevent pe_datafulevent; struct pe_datafulevent { pe_event base; SV *data; }; typedef struct pe_idle pe_idle; struct pe_idle { pe_watcher base; pe_timeable tm; pe_ring iring; SV *max_interval, *min_interval; }; typedef struct pe_io pe_io; struct pe_io { pe_watcher base; pe_timeable tm; /*timeout*/ pe_ring ioring; SV *handle; void *tm_callback; void *tm_ext_data; float timeout; U16 poll; /* ifdef UNIX */ int fd; int xref; /*private: for poll*/ /* endif */ }; typedef struct pe_signal pe_signal; struct pe_signal { pe_watcher base; pe_ring sring; IV signal; }; typedef struct pe_timer pe_timer; struct pe_timer { pe_watcher base; pe_timeable tm; SV *interval; }; typedef struct pe_var pe_var; struct pe_var { pe_watcher base; SV *variable; U16 events; }; typedef struct pe_group pe_group; struct pe_group { pe_watcher base; NV since; pe_timeable tm; SV *timeout; int members; pe_watcher **member; }; typedef struct pe_generic pe_generic; struct pe_generic { pe_watcher base; SV *source; pe_ring active; }; typedef struct pe_genericsrc pe_genericsrc; struct pe_genericsrc { SV *mysv; pe_ring watchers; }; typedef struct pe_event_stats_vtbl pe_event_stats_vtbl; struct pe_event_stats_vtbl { int on; /* if frame == -1 then we are timing pe_multiplex */ void*(*enter)(int frame, int max_tm); void (*suspend)(void *); void (*resume)(void *); void (*commit)(void *, pe_watcher *); /* callback finished OK */ void (*scrub)(void *, pe_watcher *); /* callback died */ void (*dtor)(void *); }; struct EventAPI { #define EventAPI_VERSION 22 I32 Ver; /* EVENTS */ void (*queue )(pe_event *ev); void (*start )(pe_watcher *ev, int repeat); void (*now )(pe_watcher *ev); void (*stop )(pe_watcher *ev, int cancel_events); void (*cancel )(pe_watcher *ev); void (*suspend )(pe_watcher *ev); void (*resume )(pe_watcher *ev); /* All constructors optionally take a stash and template. Either or both can be NULL. The template should not be a reference. */ pe_idle *(*new_idle )(HV*, SV*); pe_timer *(*new_timer )(HV*, SV*); pe_io *(*new_io )(HV*, SV*); pe_var *(*new_var )(HV*, SV*); pe_signal *(*new_signal)(HV*, SV*); /* TIMEABLE */ NV (*NVtime)(); void (*tstart)(pe_timeable *); void (*tstop)(pe_timeable *); /* HOOKS */ pe_qcallback *(*add_hook)(char *which, void *cb, void *ext_data); void (*cancel_hook)(pe_qcallback *qcb); /* STATS */ void (*install_stats)(pe_event_stats_vtbl *esvtbl); void (*collect_stats)(int yes); pe_ring *AllWatchers; /* TYPEMAP */ SV *(*watcher_2sv)(pe_watcher *wa); void *(*sv_2watcher)(SV *sv); SV *(*event_2sv)(pe_event *ev); void *(*sv_2event)(SV *sv); int (*sv_2interval)(char *label, SV *in, NV *out); SV *(*events_mask_2sv)(int mask); int (*sv_2events_mask)(SV *sv, int bits); /* EVERYTHING ELSE */ void (*unloop)(SV *); void (*unloop_all)(SV *); }; static struct EventAPI *GEventAPI=0; #define I_EVENT_API(YourName) \ STMT_START { \ SV *sv = perl_get_sv("Event::API",0); \ if (!sv) croak("Event::API not found"); \ GEventAPI = (struct EventAPI*) SvIV(sv); \ if (GEventAPI->Ver != EventAPI_VERSION) { \ croak("Event::API version mismatch (%d != %d) -- please recompile %s", \ GEventAPI->Ver, EventAPI_VERSION, YourName); \ } \ } STMT_END #endif Event-1.26/lib/Event/MakeMaker.pm0000644000076400007640000000646612357140355015314 0ustar useruseruse strict; package Event::MakeMaker; use Config; use base 'Exporter'; use vars qw(@EXPORT_OK $installsitearch); @EXPORT_OK = qw(&event_args $installsitearch); my %opt; for my $opt (split /:+/, $ENV{PERL_MM_OPT}) { my ($k,$v) = split /=/, $opt; $opt{$k} = $v; } my $extra = $Config{sitearch}; $extra =~ s,$Config{prefix},$opt{PREFIX}, if exists $opt{PREFIX}; for my $d ($extra, @INC) { if (-e "$d/Event/EventAPI.h") { $installsitearch = $d; last } } sub event_args { my %arg = @_; $arg{INC} .= " -I$installsitearch/Event"; %arg; } 1; __END__ =head1 NAME Event::MakeMaker - MakeMaker glue for the C-level Event API =head1 SYNOPSIS This is an advanced feature of Event. =head1 DESCRIPTION For optimal performance, hook into Event at the C-level. You'll need to make changes to your C and add code to your C / C file(s). =head1 WARNING When you hook in at the C-level you get a I performance gain, but you also reduce the chances that your code will work unmodified with newer versions of C or C. This may or may not be a problem. Just be aware, and set your expectations accordingly. =head1 HOW TO =head2 Makefile.PL use Event::MakeMaker qw(event_args); # ... set up %args ... WriteMakefile(event_args(%args)); =head2 XS #include "EventAPI.h" BOOT: I_EVENT_API("YourModule"); =head2 API (v21) struct EventAPI { I32 Ver; /* EVENTS */ void (*queue )(pe_event *ev); void (*start )(pe_watcher *ev, int repeat); void (*now )(pe_watcher *ev); void (*stop )(pe_watcher *ev, int cancel_events); void (*cancel )(pe_watcher *ev); void (*suspend )(pe_watcher *ev); void (*resume )(pe_watcher *ev); /* All constructors optionally take a stash and template. Either or both can be NULL. The template should not be a reference. */ pe_idle *(*new_idle )(HV*, SV*); pe_timer *(*new_timer )(HV*, SV*); pe_io *(*new_io )(HV*, SV*); pe_var *(*new_var )(HV*, SV*); pe_signal *(*new_signal)(HV*, SV*); /* TIMEABLE */ void (*tstart)(pe_timeable *); void (*tstop)(pe_timeable *); /* HOOKS */ pe_qcallback *(*add_hook)(char *which, void *cb, void *ext_data); void (*cancel_hook)(pe_qcallback *qcb); /* STATS */ void (*install_stats)(pe_event_stats_vtbl *esvtbl); void (*collect_stats)(int yes); pe_ring *AllWatchers; /* TYPEMAP */ SV *(*watcher_2sv)(pe_watcher *wa); void *(*sv_2watcher)(SV *sv); SV *(*event_2sv)(pe_event *ev); void *(*sv_2event)(SV *sv); }; =head2 EXAMPLE static pe_io *X11_ev=0; static void x_server_dispatch(void *ext_data) { ... } if (!X11_ev) { X11_ev = GEventAPI->new_io(0,0); X11_ev->poll = PE_R; sv_setpv(X11_ev->base.desc, "X::Server"); X11_ev->base.callback = (void*) x_server_dispatch; X11_ev->base.ext_data = ; X11_ev->base.prio = PE_PRIO_NORMAL; } X11_ev->fd = x_fd; GEventAPI->resume((pe_event*) X11_ev); GEventAPI->start((pe_event*) X11_ev, 0); =head2 BUT I NEED A NEW TYPE OF WATCHER FOR MY INTERGALACTIC INFEROMETER I'd prefer not to export the entire Event.h apparatus in favor of minimizing interdependencies. If you really, really need to create a new type of watcher send your problem analysis to the mailing list! =cut Event-1.26/lib/Event/Watcher.pm0000644000076400007640000000477512725135475015063 0ustar useruseruse strict; package Event::Watcher; use base 'Exporter'; use Carp; use vars qw(@EXPORT_OK @ATTRIBUTE); @EXPORT_OK = qw(ACTIVE SUSPEND R W E T); @ATTRIBUTE = qw(cb cbtime desc debug prio reentrant repeat max_cb_tm); sub register { no strict 'refs'; my $package = caller; my $name = $package; $name =~ s/^.*:://; my $sub = \&{"$package\::new"}; die "can't find $package\::new" if !$sub; *{"Event::".$name} = sub { shift; $sub->("Event::".$name, @_); }; &Event::add_hooks if @_; } my $warn_noise = 10; sub init { croak "Event::Watcher::init wants 2 args" if @_ != 2; my ($o, $arg) = @_; for my $k (keys %$arg) { if ($k =~ s/^e_//) { Carp::cluck "'e_$k' is renamed to '$k'" if --$warn_noise >= 0; $arg->{$k} = delete $arg->{"e_$k"}; } } if (!exists $arg->{desc}) { # try to find caller but cope with optimized-away frames & etc for my $up (1..4) { my @fr = caller $up; next if !@fr || $fr[0] =~ m/^Event\b/; my ($file,$line) = @fr[1,2]; $file =~ s,^.*/,,; $o->desc("?? $file:$line"); last; } } # set up prio { no strict 'refs'; $o->prio($ { ref($o)."::DefaultPriority" } || Event::PRIO_NORMAL()); if (exists $arg->{nice}) { $o->prio($o->prio + delete $arg->{nice}); } } $o->prio(-1) if delete $arg->{async}; $o->prio(delete $arg->{prio}) if exists $arg->{prio}; # is parked? my $parked = delete $arg->{parked}; for my $k (keys %$arg) { my $m = $k; if ($o->can($m)) { $o->$m($arg->{$k}); next; } } Carp::cluck "creating ".ref($o)." desc='".$o->desc."'\n" if $Event::DebugLevel >= 3; $o->start unless $parked; $o; } sub attributes { no strict 'refs'; my ($o) = @_; my $pk = ref $o? ref $o : $o; @{"$ {pk}::ATTRIBUTE"}, map { attributes($_) } @{"$ {pk}::ISA"}; } sub configure { my $o = shift; if (! @_) { map { $_, $o->$_() } $o->attributes; } else { while (my ($k,$v)= splice @_, -2) { $o->$k($v)} 1 # whatever } } sub private { # assumes $self is a HASH ref my $self = shift; my $pkg = caller; if (@_) { $self->{$pkg} = shift } else { $self->{$pkg}; } } sub data { # assumes $self is a HASH ref my $self = shift; if (@_) { $self->{_user_data_} = shift } else { $self->{_user_data_}; } } sub clump { require Carp; Carp::cluck "clump is deprecated"; } package Event::Watcher::Tied; use vars qw(@ISA @ATTRIBUTE); @ISA = 'Event::Watcher'; @ATTRIBUTE = qw(hard at flags); 1; Event-1.26/lib/Event/group.pm0000644000076400007640000000101312357140355014572 0ustar useruseruse strict; package Event::group; use Carp; use base 'Event::Watcher'; use vars qw(@ATTRIBUTE); @ATTRIBUTE = qw(timeout); 'Event::Watcher'->register; sub new { my $class = shift; my %arg; my @add; while (my ($k,$v) = splice(@_, 0, 2)) { if ($k eq 'add') { push @add, $v; } elsif ($k eq 'del') { carp "del in constructor (ignored)"; } else { $arg{$k} = $v; } } my $o = allocate($class, delete $arg{attach_to} || {}); $o->init(\%arg); $o->add($_) for @add; $o; } 1; Event-1.26/lib/Event/generic.pm0000644000076400007640000000070312357140355015057 0ustar useruseruse strict; package Event::generic; use base 'Event::Watcher'; use vars qw(@ATTRIBUTE); @ATTRIBUTE = qw(source); 'Event::Watcher'->register; sub new { # lock %Event::; my $class = shift; my %arg = @_; my $o = allocate($class, delete $arg{attach_to} || {}); $o->init(\%arg); $o; } package Event::generic::Source; sub new($) { return allocate($_[0], {}); } sub watch(@) { return Event->generic("source", @_); } 1; Event-1.26/lib/Event/type.pm0000644000076400007640000000046012357140355014424 0ustar useruseruse strict; package Event::type; sub import { shift; # ignore our package for my $t (@_) { if ($t =~ m/^\:/) { if ($t eq ':all') { Event::_load_watcher($_) for qw(idle io signal timer var); } else { # silently ignore } } else { Event::_load_watcher($t) } } } 1; Event-1.26/lib/Event/timer.pm0000644000076400007640000000203712357140355014565 0ustar useruseruse strict; package Event::timer; use Carp; use base 'Event::Watcher'; use vars qw(@ATTRIBUTE); @ATTRIBUTE = qw(at hard interval); 'Event::Watcher'->register; sub new { # lock %Event::; my $class = shift; my %arg = @_; my $o = allocate($class, delete $arg{attach_to} || {}); # deprecated for (qw(at after interval repeat)) { if (exists $arg{"e_$_"}) { carp "'e_$_' is renamed to '$_'"; $arg{$_} = delete $arg{"e_$_"}; } } my $has_at = exists $arg{at}; my $has_after = exists $arg{after}; croak "'after' and 'at' are mutually exclusive" if $has_at && $has_after; if ($has_after) { my $after = delete $arg{after}; $o->at(Event::time() + $after); $has_at=1; $o->interval($after) if !exists $arg{interval}; } elsif ($has_at) { $o->at(delete $arg{at}); } if (exists $arg{interval}) { my $i = delete $arg{interval}; $o->at(Event::time() + (ref $i? $$i : $i)) unless $has_at; $o->interval($i); $o->repeat(1) unless exists $arg{repeat}; } $o->init(\%arg); $o; } 1; Event-1.26/lib/Event/typemap0000644000076400007640000000055312357140355014512 0ustar useruserTYPEMAP pe_watcher * O_WATCHER pe_event * O_EVENT pe_genericsrc * O_GENERICSRC INPUT O_WATCHER $var = ($type) sv_2watcher($arg) O_EVENT $var = ($type) sv_2event($arg) O_GENERICSRC $var = ($type) sv_2genericsrc($arg) OUTPUT O_WATCHER croak("use watcher_2sv($var)") O_EVENT croak("use event_2sv($var)") O_GENERICSRC croak("use genericsrc_2sv($var)") Event-1.26/lib/Event/generic.pod0000644000076400007640000000456412357140355015236 0ustar useruser=head1 NAME Event::generic - generic event handling =head1 SYNOPSIS use Event::generic; $source = Event::generic::Source->new; $w = Event->generic(source => $source, ...); $w = $source->watch(...); $source = $w->source; $w->source($source); $source->event; $source->event($data); $data = $event->data; =head1 DESCRIPTION This module provides a watcher type within the C framework. You must understand the architecture of the C system in order to understand this document. This module provides a system of reified event sources and watchers watching those sources. Events are generated solely by a method on the event source object. The events may carry arbitrary data to the event handler callbacks. This module is intended for situations where the events of interest are best determined by Perl code. =head1 CLASSES =over =item Event::generic::Source A reified event source. =item Event::generic A watcher that can watch C event sources. =item Event::Event::Dataful A (target) event that can carry arbitrary data. =back =head1 EVENT SOURCE CLASS =head2 Constructor =over =item Event::generic::Source->new Creates and returns a new event source. =back =head2 Methods =over =item $source->event =item $source->event(DATA) The invocation of this method is a source event for watchers of the event source. When this method is called, each active watcher of the event source generates a target event. The I, if supplied, is copied into the target event objects, from which it can be retrieved using the C method. =item $source->watch(ATTR => VALUE, ...) Generates and returns a new watcher, configured to watch this event source. The standard watcher attributes may be specified as arguments. The watcher returned is an ordinary C, and may be reconfigured to watch a different event source. =back =head1 WATCHER CLASS =head2 Type-specific attributes =over =item source => $source The event source to watch. This must be either an C object or C. When set to C, no source is being watched, and the watcher cannot be started. =back =head1 EVENT CLASS =head2 Type-specific methods =over =item $event->data Returns the data associated with the event, which may be any scalar. This is read-only, and is set by the event source. =back =head1 SEE ALSO L Event-1.26/lib/Event/idle.pm0000644000076400007640000000107112357140355014357 0ustar useruseruse strict; package Event::idle; use Carp; use base 'Event::Watcher'; use vars qw($DefaultPriority @ATTRIBUTE); @ATTRIBUTE = qw(hard max min); 'Event::Watcher'->register; sub new { # lock %Event::; my $class = shift; my %arg = @_; my $o = allocate($class, delete $arg{attach_to} || {}); # deprecated for (qw(min max repeat)) { if (exists $arg{"e_$_"}) { carp "'e_$_' is renamed to '$_'"; $arg{$_} = delete $arg{"e_$_"}; } } $o->repeat(1) if defined $arg{min} || defined $arg{max}; $o->init(\%arg); $o; } 1; Event-1.26/lib/Event/io.pm0000644000076400007640000000061112357140355014050 0ustar useruseruse strict; package Event::io; use vars qw(@ISA @EXPORT_OK @ATTRIBUTE); @ISA = qw(Event::Watcher Exporter); @EXPORT_OK = qw(R W E T); # bit constants @ATTRIBUTE = qw(poll fd timeout timeout_cb); 'Event::Watcher'->register; sub new { # lock %Event::; my $class = shift; my %arg = @_; my $o = allocate($class, delete $arg{attach_to} || {}); $o->init(\%arg); $o; } 1; Event-1.26/lib/Event/var.pm0000644000076400007640000000046512357140355014240 0ustar useruseruse strict; package Event::var; use base 'Event::Watcher'; use vars qw(@ATTRIBUTE); @ATTRIBUTE = qw(var poll); 'Event::Watcher'->register; sub new { # lock %Event::; my $class = shift; my %arg = @_; my $o = allocate($class, delete $arg{attach_to} || {}); $o->init(\%arg); $o; } 1; Event-1.26/lib/Event.pm0000644000076400007640000001155412727627061013456 0ustar useruseruse strict; BEGIN { # do the right thing for threads? eval { require attrs; } or do { $INC{'attrs.pm'} = ""; *attrs::import = sub {}; } } package Event; require 5.008; use base 'Exporter'; use Carp; eval { require Carp::Heavy; }; # work around perl_call_pv bug XXX our $API; our $VERSION = '1.26'; # If we inherit DynaLoader then we inherit AutoLoader; Bletch! require DynaLoader; # DynaLoader calls dl_load_flags as a static method. *dl_load_flags = DynaLoader->can('dl_load_flags'); (defined(&bootstrap)? \&bootstrap : \&DynaLoader::bootstrap)-> (__PACKAGE__, $VERSION); our $DebugLevel = 0; our $Eval = 0; # avoid because c_callback is exempt our $DIED = \&default_exception_handler; our @EXPORT_OK = qw(time all_events all_watchers all_running all_queued all_idle one_event sweep loop unloop unloop_all sleep queue queue_pending QUEUES PRIO_NORMAL PRIO_HIGH NO_TIME_HIRES); sub import { my $pkg = shift; our $NO_TIME_HIRES; my @sym; for my $sym (@_) { if ($sym eq 'NO_TIME_HIRES') { $NO_TIME_HIRES = 1; } else { push @sym, $sym; } } if (!$NO_TIME_HIRES) { eval { require Time::HiRes; }; if ($@ =~ /^Can\'t locate Time/) { # OK, just continue } elsif ($@) { die if $@; } else { cache_time_api(); # hook in high precision time } } $pkg->export_to_level(1, undef, @sym); } # broadcast_adjust for Time::Warp? XXX sub _load_watcher { my $sub = shift; eval { require "Event/$sub.pm" }; die if $@; croak "Event/$sub.pm did not define Event::$sub\::new" unless defined &$sub; 1; } sub AUTOLOAD { my $sub = ($Event::AUTOLOAD =~ /(\w+)$/)[0]; _load_watcher($sub) or croak $@ . ', Undefined subroutine &' . $sub; carp "Autoloading with Event->$sub(...) is deprecated; \tplease 'use Event::type qw($sub);' explicitly"; goto &$sub; } sub default_exception_handler { my ($run,$err) = @_; my $desc = '?'; my $w; if ($run and ($w = $run->w)) { $desc = "`".$w->desc."'"; } my $m = "Event: trapped error in $desc: $err"; $m .= "\n" if $m !~ m/\n$/; warn $m; #Carp::cluck "Event: fatal error trapped in '$desc'"; } sub verbose_exception_handler { #AUTOLOAD XXX my ($e,$err) = @_; my $m = "Event: trapped error: $err"; $m .= "\n" if $m !~ m/\n$/; return warn $m if !$e; my $w = $e->w; $m .= " in $w --\n"; for my $k ($w->attributes) { $m .= sprintf "%18s: ", $k; eval { my $v = $w->$k(); if (!defined $v) { $m .= ''; } elsif ($v =~ /^-?\d+(\.\d+)?$/) { $m .= $v; } else { $m .= "'$v'"; } }; if ($@) { $m .= "[$@]"; $@=''; } $m .= "\n"; } warn $m; } sub sweep { my $prio = @_ ? shift : QUEUES(); queue_pending(); my $errsv = ''; while (1) { eval { $@ = $errsv; _empty_queue($prio) }; $errsv = $@; if ($@) { # if ($Event::DebugLevel >= 2) { # my $e = all_running(); # warn "Event: '$e->{desc}' died with: $@"; # } next } last; } } use vars qw($Result $TopResult); my $loop_timer; sub loop { use integer; if (@_) { my $how_long = shift; if (!$loop_timer) { $loop_timer = Event->timer(desc => "Event::loop timeout", after => $how_long, cb => sub { unloop($how_long) }, parked=>1); $loop_timer->prio(PRIO_HIGH()); } else { $loop_timer->at(Event::time() + $how_long), } $loop_timer->start; } $TopResult = undef; # allow re-entry of loop after unloop_all local $Result = undef; _incr_looplevel(); my $errsv = ''; while (1) { # like G_EVAL | G_KEEPERR eval { $@ = $errsv; _loop() }; $errsv = $@; if ($@) { warn "Event::loop caught: $@" if $Event::DebugLevel >= 4; next } last; } _decr_looplevel(); $loop_timer->stop if $loop_timer; my $r = $Result; $r = $TopResult if !defined $r; warn "Event: unloop(".(defined $r?$r:'').")\n" if $Event::DebugLevel >= 3; $r } sub add_hooks { shift if @_ & 1; #? while (@_) { my $k = shift; my $v = shift; croak "$v must be CODE" if ref $v ne 'CODE'; _add_hook($k, $v); } } END { $_->cancel for all_watchers() } # buggy? XXX package Event::Event::Io; use vars qw(@ISA); @ISA = 'Event::Event'; package Event::Event::Dataful; use vars qw(@ISA); @ISA = 'Event::Event'; package Event; require Event::Watcher; _load_watcher($_) for qw(idle io signal timer var); # Provide hints to Inline.pm for usage: # use Inline with => 'Event'; sub Inline { my ($class, $language) = @_; return if $language ne 'C'; # Inline gives good error message require Event::MakeMaker; my $path = $Event::MakeMaker::installsitearch; require Config; my $so = $Config::Config{so}; return { INC => "-I $path/Event", TYPEMAPS => "$path/Event/typemap", MYEXTLIB => "$path/auto/Event/Event.$so", AUTO_INCLUDE => '#include "EventAPI.h"', BOOT => 'I_EVENT_API("Inline");', }; } 1; Event-1.26/README0000644000076400007640000000051212357140355012134 0ustar useruserEvent - A Generic Perl Event Loop This extension aims to provide an simple and optimized event loop for a broad class of applications. Available via http://www.perl.com/CPAN/authors/id/JPRIT/ ALERT: Marc Lehmann may have taken over the future of event loops in Perl. Check out his libev library and EV Perl module. 25 Aug 2009 Event-1.26/ppport.h0000644000076400007640000001727412357140355012766 0ustar useruser #ifndef _P_P_PORTABILITY_H_ #define _P_P_PORTABILITY_H_ /* Perl/Pollution/Portability Version 1.0007 */ /* Copyright (C) 1999, Kenneth Albanowski. This code may be used and distributed under the same license as any version of Perl. */ /* For the latest version of this code, please retreive the Devel::PPPort module from CPAN, contact the author at , or check with the Perl maintainers. */ /* If you needed to customize this file for your project, please mention your changes, and visible alter the version number. */ /* In order for a Perl extension module to be as portable as possible across differing versions of Perl itself, certain steps need to be taken. Including this header is the first major one, then using dTHR is all the appropriate places and using a PL_ prefix to refer to global Perl variables is the second. */ /* If you use one of a few functions that were not present in earlier versions of Perl, please add a define before the inclusion of ppport.h for a static include, or use the GLOBAL request in a single module to produce a global definition that can be referenced from the other modules. Function: Static define: Extern define: newCONSTSUB() NEED_newCONSTSUB NEED_newCONSTSUB_GLOBAL */ /* To verify whether ppport.h is needed for your module, and whether any special defines should be used, ppport.h can be run through Perl to check your source code. Simply say: perl -x ppport.h *.c *.h *.xs foo/*.c [etc] The result will be a list of patches suggesting changes that should at least be acceptable, if not necessarily the most efficient solution, or a fix for all possible problems. It won't catch where dTHR is needed, and doesn't attempt to account for global macro or function definitions, nested includes, typemaps, etc. In order to test for the need of dTHR, please try your module under a recent version of Perl that has threading compiled-in. */ /* #!/usr/bin/perl @ARGV = ("*.xs") if !@ARGV; %badmacros = %funcs = %macros = (); $replace = 0; foreach () { $funcs{$1} = 1 if /Provide:\s+(\S+)/; $macros{$1} = 1 if /^#\s*define\s+([a-zA-Z0-9_]+)/; $replace = $1 if /Replace:\s+(\d+)/; $badmacros{$2}=$1 if $replace and /^#\s*define\s+([a-zA-Z0-9_]+).*?\s+([a-zA-Z0-9_]+)/; $badmacros{$1}=$2 if /Replace (\S+) with (\S+)/; } foreach $filename (map(glob($_),@ARGV)) { unless (open(IN, "<$filename")) { warn "Unable to read from $file: $!\n"; next; } print "Scanning $filename...\n"; $c = ""; while () { $c .= $_; } close(IN); $need_include = 0; %add_func = (); $changes = 0; $has_include = ($c =~ /#.*include.*ppport/m); foreach $func (keys %funcs) { if ($c =~ /#.*define.*\bNEED_$func(_GLOBAL)?\b/m) { if ($c !~ /\b$func\b/m) { print "If $func isn't needed, you don't need to request it.\n" if $changes += ($c =~ s/^.*#.*define.*\bNEED_$func\b.*\n//m); } else { print "Uses $func\n"; $need_include = 1; } } else { if ($c =~ /\b$func\b/m) { $add_func{$func} =1 ; print "Uses $func\n"; $need_include = 1; } } } if (not $need_include) { foreach $macro (keys %macros) { if ($c =~ /\b$macro\b/m) { print "Uses $macro\n"; $need_include = 1; } } } foreach $badmacro (keys %badmacros) { if ($c =~ /\b$badmacro\b/m) { $changes += ($c =~ s/\b$badmacro\b/$badmacros{$badmacro}/gm); print "Uses $badmacros{$badmacro} (instead of $badmacro)\n"; $need_include = 1; } } if (scalar(keys %add_func) or $need_include != $has_include) { if (!$has_include) { $inc = join('',map("#define NEED_$_\n", sort keys %add_func)). "#include \"ppport.h\"\n"; $c = "$inc$c" unless $c =~ s/#.*include.*XSUB.*\n/$&$inc/m; } elsif (keys %add_func) { $inc = join('',map("#define NEED_$_\n", sort keys %add_func)); $c = "$inc$c" unless $c =~ s/^.*#.*include.*ppport.*$/$inc$&/m; } if (!$need_include) { print "Doesn't seem to need ppport.h.\n"; $c =~ s/^.*#.*include.*ppport.*\n//m; } $changes++; } if ($changes) { open(OUT,">/tmp/ppport.h.$$"); print OUT $c; close(OUT); open(DIFF, "diff -u $filename /tmp/ppport.h.$$|"); while () { s!/tmp/ppport\.h\.$$!$filename.patched!; print STDOUT; } close(DIFF); unlink("/tmp/ppport.h.$$"); } else { print "Looks OK\n"; } } __DATA__ */ #ifndef PERL_REVISION # ifndef __PATCHLEVEL_H_INCLUDED__ # include "patchlevel.h" # endif # ifndef PERL_REVISION # define PERL_REVISION (5) /* Replace: 1 */ # define PERL_VERSION PATCHLEVEL # define PERL_SUBVERSION SUBVERSION /* Replace PERL_PATCHLEVEL with PERL_VERSION */ /* Replace: 0 */ # endif #endif #define PERL_BCDVERSION ((PERL_REVISION * 0x1000000L) + (PERL_VERSION * 0x1000L) + PERL_SUBVERSION) #ifndef ERRSV # define ERRSV perl_get_sv("@",FALSE) #endif #if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5)) /* Replace: 1 */ # define PL_sv_undef sv_undef # define PL_sv_yes sv_yes # define PL_sv_no sv_no # define PL_na na # define PL_stdingv stdingv # define PL_hints hints # define PL_curcop curcop # define PL_curstash curstash # define PL_copline copline # define PL_Sv Sv /* Replace: 0 */ #endif #ifndef dTHR # ifdef WIN32 # define dTHR extern int Perl___notused # else # define dTHR extern int errno # endif #endif #ifndef dTHX # define dTHX dTHR # define pTHX_ # define aTHX_ #endif #ifndef boolSV # define boolSV(b) ((b) ? &PL_sv_yes : &PL_sv_no) #endif #ifndef gv_stashpvn # define gv_stashpvn(str,len,flags) gv_stashpv(str,flags) #endif #ifndef newSVpvn # define newSVpvn(data,len) ((len) ? newSVpv ((data), (len)) : newSVpv ("", 0)) #endif #ifndef newRV_inc /* Replace: 1 */ # define newRV_inc(sv) newRV(sv) /* Replace: 0 */ #endif #ifndef newRV_noinc # ifdef __GNUC__ # define newRV_noinc(sv) \ ({ \ SV *nsv = (SV*)newRV(sv); \ SvREFCNT_dec(sv); \ nsv; \ }) # else # if defined(CRIPPLED_CC) || defined(USE_THREADS) static SV * newRV_noinc (SV * sv) { SV *nsv = (SV*)newRV(sv); SvREFCNT_dec(sv); return nsv; } # else # define newRV_noinc(sv) \ ((PL_Sv=(SV*)newRV(sv), SvREFCNT_dec(sv), (SV*)PL_Sv) # endif # endif #endif /* Provide: newCONSTSUB */ /* newCONSTSUB from IO.xs is in the core starting with 5.004_63 */ #if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION < 63)) #if defined(NEED_newCONSTSUB) static #else extern void newCONSTSUB _((HV * stash, char * name, SV *sv)); #endif #if defined(NEED_newCONSTSUB) || defined(NEED_newCONSTSUB_GLOBAL) void newCONSTSUB(stash,name,sv) HV *stash; char *name; SV *sv; { U32 oldhints = PL_hints; HV *old_cop_stash = PL_curcop->cop_stash; HV *old_curstash = PL_curstash; line_t oldline = PL_curcop->cop_line; PL_curcop->cop_line = PL_copline; PL_hints &= ~HINT_BLOCK_SCOPE; if (stash) PL_curstash = PL_curcop->cop_stash = stash; newSUB( #if (PERL_VERSION < 3) || ((PERL_VERSION == 3) && (PERL_SUBVERSION < 22)) /* before 5.003_22 */ start_subparse(), #else # if (PERL_VERSION == 3) && (PERL_SUBVERSION == 22) /* 5.003_22 */ start_subparse(0), # else /* 5.003_23 onwards */ start_subparse(FALSE, 0), # endif #endif newSVOP(OP_CONST, 0, newSVpv(name,0)), newSVOP(OP_CONST, 0, &PL_sv_no), /* SvPV(&PL_sv_no) == "" -- GMB */ newSTATEOP(0, Nullch, newSVOP(OP_CONST, 0, sv)) ); PL_hints = oldhints; PL_curcop->cop_stash = old_cop_stash; PL_curstash = old_curstash; PL_curcop->cop_line = oldline; } #endif #endif /* newCONSTSUB */ #endif /* _P_P_PORTABILITY_H_ */ Event-1.26/Makefile.PL0000644000076400007640000000166612725135361013241 0ustar useruser# This -*- perl -*- script makes the Makefile require 5.008; # 5.006_002 fails use ExtUtils::MakeMaker; #push @Safe, OPTIMIZE => '-Wall' if 1; # Parasoft's Insure++! push @Safe, OPTIMIZE => '-g' if 0; push @Safe, CC => 'insure', LD => 'insure', OPTIMIZE => '-g' if 0; my @opt=(PREREQ_PM => { Test => 1 }, MIN_PERL_VERSION => 'v5.8.0', VERSION_FROM => "./lib/Event.pm", NAME => "Event", TYPEMAPS => ['./lib/Event/typemap'], INC => '-Ic -Ilib/Event', H => [glob("c/*"), glob("*.h"), "lib/Event/EventAPI.h"], @Safe, 'clean' => {FILES => join(" ", map { "$_ */$_ */*/$_" } qw(*% *.html *.b[ac]k *.old *.orig)) }, META_MERGE => { "meta-spec" => { version => 2 }, resources => { repository => { type => 'git', url => 'https://github.com/mohawk2/cpan-Event.git', web => 'https://github.com/mohawk2/cpan-Event', }, }, }, ); WriteMakefile(@opt); Event-1.26/README.EV0000644000076400007640000000465612357140355012462 0ustar useruserDate: Sat, 21 Feb 2009 09:07:14 +0100 From: Marc Lehmann To: Joshua N Pritikin Subject: Re: EV On Fri, Feb 20, 2009 at 06:32:57AM -0800, Joshua N Pritikin wrote: > I just noticed EV: > > http://search.cpan.org/~mlehmann/EV-3.53/libev/ev.pod > > It looks like you have based your work on the Event interface and > extended it to be much more flexible. Wonderful work! Actually, the API is much less flexible :-) It is heavily influences by libev, which in turn is influenced by libevent. However, I was using Event for more than a decade, and I think it is correct to say that it was influencing me most when writing libev and EV. I of course surveyed many event toolkits, but Event was the most well-thought-out one. The only "bugs" I identified were: - watcher lifetime != perl object lifetime (it sounds like a nuisance at first, but it is really non-perlish and hard to manage). - the event queue (it is quite possible to get Event into a state where it queues events faster than it can remove it, especially as it becoems less efficient with more events). - the interaction of priorities, queueing and event handling is undocumented, but crucial (starve prio etc.) - EV/libev has no such priority system at all, as priorities only determine order of callback invocation. - Event isn't reentrant (almost no event libs are), which is a non-issue for most uses, but a big issue for me (Coro). So EV/libev is basically Event + some "fixes", as opposed to some new invention, or some other event loop, even though the API is drastically different. It took me some 15 years of gathering experience it write it, too. Event was crucial to my learning :) (And, yeah, once the API is set in stone, the only way to "fix" it is makign a new module - see object lifetimes for example, which you would probably do differently if you would write Event from scratch). And, oh, yeah, the XS interface to Event also inspired me a lot in EV and other modules that offer such an XS interface. Without Event, EV (or Coro) would not have an XS-level interface. So thanks a lot for Event :) -- The choice of a Deliantra, the free code+content MORPG -----==- _GNU_ http://www.deliantra.net ----==-- _ generation ---==---(_)__ __ ____ __ Marc Lehmann --==---/ / _ \/ // /\ \/ / pcg@goof.com -=====/_/_//_/\_,_/ /_/\_\ Event-1.26/c/0000755000076400007640000000000012727627261011507 5ustar useruserEvent-1.26/c/hook.c0000644000076400007640000000311712357140355012606 0ustar useruserstatic pe_ring Prepare, Check, AsyncCheck, Callback; static void boot_hook() { PE_RING_INIT(&Prepare, 0); PE_RING_INIT(&Check, 0); PE_RING_INIT(&AsyncCheck, 0); PE_RING_INIT(&Callback, 0); } static pe_qcallback * pe_add_hook(char *which, int is_perl, void *cb, void *ext_data) { pe_qcallback *qcb; EvNew(2, qcb, 1, pe_qcallback); PE_RING_INIT(&qcb->ring, qcb); qcb->is_perl = is_perl; if (is_perl) { qcb->callback = SvREFCNT_inc((SV*)cb); qcb->ext_data = 0; } else { qcb->callback = cb; qcb->ext_data = ext_data; } if (strEQ(which, "prepare")) PE_RING_UNSHIFT(&qcb->ring, &Prepare); else if (strEQ(which, "check")) PE_RING_UNSHIFT(&qcb->ring, &Check); else if (strEQ(which, "asynccheck")) PE_RING_UNSHIFT(&qcb->ring, &AsyncCheck); else if (strEQ(which, "callback")) PE_RING_UNSHIFT(&qcb->ring, &Callback); else croak("Unknown hook '%s' in pe_add_hook", which); return qcb; } static pe_qcallback *capi_add_hook(char *which, void *cb, void *ext_data) { return pe_add_hook(which, 0, cb, ext_data); } static void pe_cancel_hook(pe_qcallback *qcb) { if (qcb->is_perl) SvREFCNT_dec((SV*)qcb->callback); PE_RING_DETACH(&qcb->ring); EvFree(2, qcb); } static void pe_map_check(pe_ring *List) { pe_qcallback *qcb = (pe_qcallback*) List->prev->self; while (qcb) { if (qcb->is_perl) { dSP; PUSHMARK(SP); PUTBACK; perl_call_sv((SV*)qcb->callback, G_DISCARD); } else { /* !is_perl */ (* (void(*)(void*)) qcb->callback)(qcb->ext_data); } qcb = (pe_qcallback*) qcb->ring.prev->self; } } Event-1.26/c/group.c0000644000076400007640000000724412357140355013007 0ustar useruserstatic struct pe_watcher_vtbl pe_group_vtbl; static pe_watcher *pe_group_allocate(HV *stash, SV *temple) { pe_group *ev; EvNew(12, ev, 1, pe_group); ev->base.vtbl = &pe_group_vtbl; PE_RING_INIT(&ev->tm.ring, ev); ev->tm.at = 0; ev->timeout = &PL_sv_undef; ev->members = 3; EvNew(13, ev->member, ev->members, pe_watcher*); Zero(ev->member, ev->members, pe_watcher*); pe_watcher_init(&ev->base, stash, temple); WaREPEAT_on(ev); return (pe_watcher*) ev; } static void pe_group_dtor(pe_watcher *ev) { int xx; pe_group *gp = (pe_group*) ev; SvREFCNT_dec(gp->timeout); for (xx=0; xx < gp->members; xx++) { pe_watcher *mb = gp->member[xx]; if (mb) --mb->refcnt; } EvFree(13, gp->member); pe_watcher_dtor(ev); EvFree(12, ev); } static char *pe_group_start(pe_watcher *ev, int repeat) { pe_group *gp = (pe_group*) ev; NV timeout; if (!ev->callback) return "without callback"; if (!sv_2interval("group", gp->timeout, &timeout)) return "repeating group has no timeout"; gp->since = WaHARD(ev)? gp->tm.at : NVtime(); gp->tm.at = timeout + gp->since; pe_timeable_start(&gp->tm); return 0; } static void pe_group_stop(pe_watcher *ev) { pe_timeable_stop(&((pe_group*)ev)->tm); } static void pe_group_alarm(pe_watcher *wa, pe_timeable *tm) { STRLEN n_a; pe_group *gp = (pe_group*) wa; NV timeout; NV remaining; NV now = NVtime(); int xx; for (xx=0; xx < gp->members; xx++) { pe_watcher *mb = gp->member[xx]; if (!mb) continue; if (gp->since < mb->cbtime) { gp->since = mb->cbtime; } } if (!sv_2interval("group", gp->timeout, &timeout)) croak("Event: can't extract timeout"); /* impossible */ remaining = gp->since + timeout - now; if (remaining > IntervalEpsilon) { gp->tm.at = now + remaining; pe_timeable_start(&gp->tm); } else { pe_event *ev = (*wa->vtbl->new_event)(wa); ++ev->hits; queueEvent(ev); } } /* publish C API XXX */ static void pe_group_add(pe_group *gp, pe_watcher *wa) { int ok=0; int xx; if (gp == (pe_group*) wa) { STRLEN n_a; croak("Event: can't add group '%s' to itself", SvPV(gp->base.desc, n_a)); } ++wa->refcnt; for (xx=0; xx < gp->members; xx++) { if (!gp->member[xx]) { gp->member[xx] = wa; ok=1; break; } } if (!ok) { /* expand array */ pe_watcher **ary; EvNew(13, ary, gp->members*2, pe_watcher*); Zero(ary, gp->members*2, pe_watcher*); Copy(gp->member, ary, gp->members, sizeof(pe_watcher*)); EvFree(13, gp->member); gp->member = ary; gp->member[gp->members] = wa; gp->members *= 2; } } static void pe_group_del(pe_group *gp, pe_watcher *target) { int xx; for (xx=0; xx < gp->members; xx++) { if (gp->member[xx] != target) continue; --target->refcnt; gp->member[xx] = 0; break; } } WKEYMETH(_group_timeout) { pe_group *gp = (pe_group*)ev; if (nval) { SV *old = gp->timeout; gp->timeout = SvREFCNT_inc(nval); SvREFCNT_dec(old); VERIFYINTERVAL("group", gp->timeout); /* recalc expiration XXX */ } { dSP; XPUSHs(gp->timeout); PUTBACK; } } WKEYMETH(_group_add) { pe_group *gp = (pe_group*)ev; if (!nval) return; pe_group_add(gp, sv_2watcher(nval)); } WKEYMETH(_group_del) { pe_group *gp = (pe_group*)ev; if (!nval) return; pe_group_del(gp, sv_2watcher(nval)); } static void boot_group() { pe_watcher_vtbl *vt = &pe_group_vtbl; memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl)); vt->dtor = pe_group_dtor; vt->start = pe_group_start; vt->stop = pe_group_stop; vt->alarm = pe_group_alarm; pe_register_vtbl(vt, gv_stashpv("Event::group",1), &event_vtbl); } Event-1.26/c/unix.c0000644000076400007640000002701612357140355012635 0ustar useruser#if defined(HAS_DEVPOLL) #include static int dpfd=0; static struct pollfd *Pollfd=0; static int pollMax=200; static int Nfds; #define MAXFD 65000 typedef struct _fdToEvent { pe_io *ev; } FdToEvent; static FdToEvent fdToEvent[MAXFD]; #endif /*HAS_DEVPOLL*/ static void boot_devpoll() { #if defined(HAS_DEVPOLL) memset(fdToEvent, 0, MAXFD*sizeof(FdToEvent)); EvNew(9, Pollfd, pollMax, struct pollfd); /* Open /dev/poll driver */ if (!dpfd) { fprintf(stderr, "INIT Open /dev/poll!!!\n"); if ((dpfd = open("/dev/poll", O_RDWR)) < 0) { croak("Event: Can't open /dev/poll!\n"); } } #endif /*HAS_DEVPOLL*/ } static int pe_sys_fileno(SV *sv, char *context) { IO *io; PerlIO *fp; if (!sv) croak("Event %s: no filehandle available", context); if (SvGMAGICAL(sv)) mg_get(sv); if (SvIOK(sv)) /* maybe non-portable but nice for unixen */ return SvIV(sv); if (SvROK(sv)) sv = SvRV(sv); if (SvTYPE(sv) == SVt_PVGV) { if (!(io=GvIO((GV*)sv)) || !(fp = IoIFP(io))) { croak("Event '%s': GLOB(0x%x) isn't a valid IO", context, sv); } return PerlIO_fileno(fp); } sv_dump(sv); croak("Event '%s': can't find fileno", context); return -1; } static void _queue_io(pe_io *wa, int got) { pe_ioevent *ev; got &= wa->poll; if (!got) { if (WaDEBUGx(wa) >= 3) { STRLEN n_a; warn("Event: io '%s' queued nothing", SvPV(wa->base.desc, n_a)); } return; } ev = (pe_ioevent*) (*wa->base.vtbl->new_event)((pe_watcher*) wa); ++ev->base.hits; ev->got |= got; queueEvent((pe_event*) ev); } /************************************************* DEVPOLL */ #if defined(HAS_DEVPOLL) && !PE_SYS_IO #define PE_SYS_IO 1 static void pe_sys_sleep(NV left) { int ret; NV t0 = NVtime(); NV t1 = t0 + left; while (1) { ret = poll(0, 0, (int) (left * 1000)); /* hope zeroes okay */ if (ret < 0 && errno != EAGAIN && errno != EINTR) croak("poll(%.2f) got errno %d", left, errno); left = t1 - NVtime(); if (left > IntervalEpsilon) { if (ret==0) ++TimeoutTooEarly; continue; } break; } } static void pe_sys_io_add (pe_io *ev) { struct pollfd tmp_pfd; int bits=0; if (ev->fd <= 0 || ev->fd > MAXFD) { croak("pe_sys_io_add: non-valid fd (%d)", ev->fd); return; } if (ev->poll & PE_R) bits |= (POLLIN | POLLPRI); if (ev->poll & PE_W) bits |= POLLOUT; if (ev->poll & PE_E) bits |= (POLLRDBAND | POLLPRI); tmp_pfd.fd = ev->fd; tmp_pfd.events = bits; if (write(dpfd, &tmp_pfd, sizeof(struct pollfd)) != sizeof(struct pollfd)) { fprintf(stderr, "pe_sys_io_add(fd %d): could not write fd to /dev/poll", dpfd); return; } if (fdToEvent[ev->fd].ev != NULL) { fprintf(stderr, "pe_sys_io_add(fd %d): mapping between fd and event already exists!", ev->fd); } else { fdToEvent[ev->fd].ev = ev; } } static void pe_sys_io_del (pe_io *ev) { struct pollfd tmp_pfd; int bits=0; if (ev-> fd <= 0) { return; } if (ev->poll & PE_R) bits |= (POLLIN | POLLPRI); if (ev->poll & PE_W) bits |= POLLOUT; if (ev->poll & PE_E) bits |= (POLLRDBAND | POLLPRI); tmp_pfd.fd = ev->fd; tmp_pfd.events = POLLREMOVE; if (write(dpfd, &tmp_pfd, sizeof(struct pollfd)) != sizeof(struct pollfd)) { fprintf(stderr, "pe_sys_io_del(fd %d): could not write fd to /dev/poll", dpfd); } fdToEvent[ev->fd].ev = NULL; } static void pe_sys_multiplex(NV timeout) { pe_io *ev; int xx, got, mask, fd; int ret; int err, m_rfds; struct dvpoll dopoll; if (pollMax < IOWatchCount) { if (Pollfd) EvFree(9, Pollfd); pollMax = IOWatchCount*2; EvNew(9, Pollfd, pollMax, struct pollfd); IOWatch_OK = 0; } if (!IOWatch_OK) { Nfds = 0; Zero(Pollfd, pollMax, struct pollfd); ev = (pe_io*) IOWatch.next->self; while (ev) { int fd = ev->fd; ev->xref = -1; assert(fd >= 0); { int bits=0; if (ev->poll & PE_R) bits |= (POLLIN | POLLPRI); if (ev->poll & PE_W) bits |= POLLOUT; if (ev->poll & PE_E) bits |= (POLLRDBAND | POLLPRI); assert(bits); { Pollfd[Nfds].fd = fd; Pollfd[Nfds].events |= bits; Nfds++; } } ev = (pe_io*) ev->ioring.next->self; } IOWatch_OK = 1; } for (xx=0; xx < Nfds; xx++) Pollfd[xx].revents = 0; /* needed? XXX */ if (timeout < 0) timeout = 0; dopoll.dp_timeout = (int) (timeout * 1000); dopoll.dp_nfds = pollMax; dopoll.dp_fds = Pollfd; /* Wait for I/O events the clients are interested in */ m_rfds = ioctl(dpfd, DP_POLL, &dopoll); if (m_rfds == -1) { err = errno; fprintf(stderr, "pe_sys_multiplex: poll() returned -1, errno %d\n", err); return; } while (m_rfds >= 1) { m_rfds--; fd = Pollfd[m_rfds].fd; ev = fdToEvent[fd].ev; got = 0; mask = Pollfd[m_rfds].revents; if (mask & (POLLIN | POLLPRI | POLLHUP | POLLERR)) got |= PE_R; if (mask & (POLLOUT | POLLERR)) got |= PE_W; if (mask & (POLLRDBAND | POLLPRI | POLLHUP | POLLERR)) got |= PE_E; if (mask & POLLNVAL) { STRLEN n_a; warn("Event: '%s' was unexpectedly closed", SvPV(ev->base.desc, n_a)); pe_io_reset_handle((pe_watcher*) ev); } else { if ((mask & POLLHUP) && (ev->poll & PE_W) && (!(got & PE_W)) && (!(ev->poll & PE_R)) && (!(ev->poll & PE_E))) { /* Must notify about POLLHUP _some_ way - Allen */ got |= PE_W; } } if (got) _queue_io(ev, got); } } #endif /*HAS_DEVPOLL*/ /************************************************* POLL */ #if defined(HAS_POLL) && !PE_SYS_IO #define PE_SYS_IO 1 static struct pollfd *Pollfd=0; static int pollMax=0; static int Nfds; static void pe_sys_sleep(NV left) { int ret; NV t0 = NVtime(); NV t1 = t0 + left; while (1) { ret = poll(0, 0, (int) (left * 1000)); /* hope zeroes okay */ if (ret < 0 && errno != EAGAIN && errno != EINTR) croak("poll(%.2f) got errno %d", left, errno); left = t1 - NVtime(); if (left > IntervalEpsilon) { if (ret==0) ++TimeoutTooEarly; continue; } break; } } static void pe_sys_io_add (pe_io *ev) {} static void pe_sys_io_del (pe_io *ev) {} static void pe_sys_multiplex(NV timeout) { pe_io *ev; int xx; int ret; if (pollMax < IOWatchCount) { if (Pollfd) EvFree(9, Pollfd); pollMax = IOWatchCount+5; EvNew(9, Pollfd, pollMax, struct pollfd); IOWatch_OK = 0; } if (!IOWatch_OK) { Nfds = 0; Zero(Pollfd, pollMax, struct pollfd); ev = (pe_io*) IOWatch.next->self; while (ev) { int fd = ev->fd; ev->xref = -1; assert(fd >= 0); { int bits=0; if (ev->poll & PE_R) bits |= (POLLIN | POLLPRI); if (ev->poll & PE_W) bits |= POLLOUT; if (ev->poll & PE_E) bits |= (POLLRDBAND | POLLPRI); assert(bits); { int ok=0;; for (xx = 0; xx < Nfds; xx++) { if (Pollfd[xx].fd == fd) { ok=1; break; } } if (!ok) xx = Nfds++; Pollfd[xx].fd = fd; Pollfd[xx].events |= bits; ev->xref = xx; } } ev = (pe_io*) ev->ioring.next->self; } IOWatch_OK = 1; } for (xx=0; xx < Nfds; xx++) Pollfd[xx].revents = 0; /* needed? XXX */ if (timeout < 0) timeout = 0; ret = poll(Pollfd, Nfds, (int) (timeout * 1000)); if (ret < 0) { if (errno == EINTR || errno == EAGAIN) return; if (errno == EINVAL) { warn("poll: bad args %d %.2f", Nfds, timeout); return; } warn("poll got errno %d", errno); return; } ev = (pe_io*) IOWatch.next->self; while (ev) { pe_io *next_ev = (pe_io*) ev->ioring.next->self; STRLEN n_a; int xref = ev->xref; if (xref >= 0) { int got = 0; int mask = Pollfd[xref].revents; if (mask & (POLLIN | POLLPRI | POLLHUP | POLLERR)) got |= PE_R; if (mask & (POLLOUT | POLLERR)) got |= PE_W; if (mask & (POLLRDBAND | POLLPRI | POLLHUP | POLLERR)) got |= PE_E; if (mask & POLLNVAL) { warn("Event: '%s' was unexpectedly closed", SvPV(ev->base.desc, n_a)); pe_io_reset_handle((pe_watcher*) ev); } else { if ((mask & POLLHUP) && (ev->poll & PE_W) && (!(got & PE_W)) && (!(ev->poll & PE_R)) && (!(ev->poll & PE_E))) { /* Must notify about POLLHUP _some_ way - Allen */ got |= PE_W; } if (got) _queue_io(ev, got); /* Can only do this if fd-to-watcher is 1-to-1 if (--ret == 0) { ev=0; continue; } */ } } ev = next_ev; } } #endif /*HAS_POLL*/ /************************************************* SELECT */ #if defined(HAS_SELECT) && !PE_SYS_IO #define PE_SYS_IO 1 static int Nfds; static fd_set Rfds, Wfds, Efds; static void pe_sys_sleep(NV left) { struct timeval tm; NV t0 = NVtime(); NV t1 = t0 + left; int ret; while (1) { tm.tv_sec = left; tm.tv_usec = (left - tm.tv_sec) * 1000000; ret = select(0, 0, 0, 0, &tm); if (ret < 0 && errno != EINTR && errno != EAGAIN) croak("select(%.2f) got errno %d", left, errno); left = t1 - NVtime(); if (left > IntervalEpsilon) { if (ret==0) ++TimeoutTooEarly; continue; } break; } } static void pe_sys_io_add (pe_io *ev) {} static void pe_sys_io_del (pe_io *ev) {} static void pe_sys_multiplex(NV timeout) { struct timeval tm; int ret; fd_set rfds, wfds, efds; pe_io *ev; if (!IOWatch_OK) { Nfds = -1; FD_ZERO(&Rfds); FD_ZERO(&Wfds); FD_ZERO(&Efds); ev = IOWatch.next->self; while (ev) { int fd = ev->fd; if (fd >= 0) { int bits=0; if (ev->poll & PE_R) { FD_SET(fd, &Rfds); ++bits; } if (ev->poll & PE_W) { FD_SET(fd, &Wfds); ++bits; } if (ev->poll & PE_E) { FD_SET(fd, &Efds); ++bits; } if (bits && fd > Nfds) Nfds = fd; } ev = ev->ioring.next->self; } IOWatch_OK = 1; } if (timeout < 0) timeout = 0; tm.tv_sec = timeout; tm.tv_usec = (timeout - tm.tv_sec) * 1000000; if (Nfds > -1) { memcpy(&rfds, &Rfds, sizeof(fd_set)); memcpy(&wfds, &Wfds, sizeof(fd_set)); memcpy(&efds, &Efds, sizeof(fd_set)); ret = select(Nfds+1, &rfds, &wfds, &efds, &tm); } else ret = select(0, 0, 0, 0, &tm); if (ret < 0) { if (errno == EINTR) return; if (errno == EBADF) { STRLEN n_a; ev = IOWatch.next->self; while (ev) { int fd = ev->fd; struct stat buf; if (fd >= 0 && PerlLIO_fstat(fd, &buf) < 0 && errno == EBADF) { warn("Event: '%s' was unexpectedly closed", SvPV(ev->base.desc, n_a)); pe_io_reset_handle((pe_watcher*) ev); return; } ev = ev->ioring.next->self; } warn("select: couldn't find cause of EBADF"); return; } if (errno == EINVAL) { warn("select: bad args %d %.2f", Nfds, timeout); return; } warn("select got errno %d", errno); return; } ev = IOWatch.next->self; while (ev) { pe_io *next_ev = (pe_io*) ev->ioring.next->self; int fd = ev->fd; if (fd >= 0) { int got = 0; if (FD_ISSET(fd, &rfds)) got |= PE_R; if (FD_ISSET(fd, &wfds)) got |= PE_W; if (FD_ISSET(fd, &efds)) got |= PE_E; if (got) _queue_io(ev, got); /* Can only do this if fd-to-watcher is 1-to-1 if (--ret == 0) { ev=0; continue; } */ } ev = next_ev; } } #endif /*HAS_SELECT*/ Event-1.26/c/tied.c0000644000076400007640000000500312357140355012567 0ustar useruserstatic struct pe_watcher_vtbl pe_tied_vtbl; static pe_watcher *pe_tied_allocate(HV *stash, SV *temple) { pe_tied *ev; EvNew(6, ev, 1, pe_tied); ev->base.vtbl = &pe_tied_vtbl; if (!stash) croak("tied_allocate(0)"); pe_watcher_init(&ev->base, stash, temple); PE_RING_INIT(&ev->tm.ring, ev); return (pe_watcher*) ev; } static void pe_tied_dtor(pe_watcher *ev) { pe_watcher_dtor(ev); EvFree(6, ev); } static char *pe_tied_start(pe_watcher *ev, int repeat) { HV *stash = SvSTASH(SvRV(ev->mysv)); GV *gv; dSP; assert(stash); PUSHMARK(SP); XPUSHs(watcher_2sv(ev)); XPUSHs(boolSV(repeat)); PUTBACK; gv = gv_fetchmethod(stash, "_start"); if (!gv) croak("Cannot find %s->_start()", HvNAME(stash)); perl_call_sv((SV*)GvCV(gv), G_DISCARD); /* allow return of error! XXX */ return 0; } static void pe_tied_stop(pe_watcher *ev) { HV *stash = SvSTASH(SvRV(ev->mysv)); GV *gv = gv_fetchmethod(stash, "_stop"); pe_timeable_stop(&((pe_tied*)ev)->tm); if (gv) { dSP; PUSHMARK(SP); XPUSHs(watcher_2sv(ev)); PUTBACK; perl_call_sv((SV*)GvCV(gv), G_DISCARD); } } static void pe_tied_alarm(pe_watcher *ev, pe_timeable *_ign) { HV *stash = SvSTASH(SvRV(ev->mysv)); GV *gv; dSP; PUSHMARK(SP); XPUSHs(watcher_2sv(ev)); PUTBACK; gv = gv_fetchmethod(stash, "_alarm"); if (!gv) croak("Cannot find %s->_alarm()", HvNAME(stash)); perl_call_sv((SV*)GvCV(gv), G_DISCARD); } WKEYMETH(_tied_at) { pe_tied *tp = (pe_tied*) ev; if (nval) { pe_timeable_stop(&tp->tm); if (SvOK(nval)) { tp->tm.at = SvNV(nval); pe_timeable_start(&tp->tm); } } { dSP; XPUSHs(sv_2mortal(newSVnv(tp->tm.at))); PUTBACK; } } WKEYMETH(_tied_flags) { if (nval) { IV nflags = SvIV(nval); IV flip = nflags ^ ev->flags; IV other = flip & ~(PE_INVOKE1); if (flip & PE_INVOKE1) { if (nflags & PE_INVOKE1) WaINVOKE1_on(ev); else WaINVOKE1_off(ev); } if (other) warn("Other flags (0x%x) cannot be changed", other); } { dSP; XPUSHs(sv_2mortal(newSViv(ev->flags & PE_VISIBLE_FLAGS))); PUTBACK; } } static void boot_tied() { pe_watcher_vtbl *vt = &pe_tied_vtbl; memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl)); vt->did_require = 1; /* otherwise tries to autoload Event::Event! */ vt->dtor = pe_tied_dtor; vt->start = pe_tied_start; vt->stop = pe_tied_stop; vt->alarm = pe_tied_alarm; pe_register_vtbl(vt, gv_stashpv("Event::Watcher::Tied",1), &event_vtbl); } Event-1.26/c/watcher.c0000644000076400007640000002276712357142722013317 0ustar useruserstatic int NextID = 0; static pe_ring AllWatchers; static struct pe_watcher_vtbl pe_watcher_base_vtbl; static void pe_watcher_init(pe_watcher *ev, HV *stash, SV *temple) { STRLEN n_a; assert(ev); assert(ev->vtbl); if (!ev->vtbl->stash) croak("sub-class VTBL must have a stash (doesn't!)"); if (!ev->vtbl->did_require) { SV *tmp; char *name = HvNAME(ev->vtbl->stash); dTHX; if (memEQ(name, "Event::", 7)) name += 7; tmp = sv_2mortal(newSVpvf("Event/%s.pm", name)); perl_require_pv(SvPV(tmp, n_a)); if (sv_true(ERRSV)) croak("Event: could not load perl support code for Event::%s: %s", name, SvPV(ERRSV,n_a)); ++ev->vtbl->did_require; } /* if we have a non-default stash then we need to save it! */ ev->mysv = stash || temple ? wrap_watcher(ev, stash, temple) : 0; PE_RING_INIT(&ev->all, ev); PE_RING_INIT(&ev->events, 0); /* no exceptions after this point */ PE_RING_UNSHIFT(&ev->all, &AllWatchers); WaFLAGS(ev) = 0; WaINVOKE1_on(ev); WaREENTRANT_on(ev); ev->FALLBACK = 0; NextID = (NextID+1) & 0x7fff; /* make it look like the kernel :-, */ ev->refcnt = 0; ev->desc = newSVpvn("??",2); ev->running = 0; ev->max_cb_tm = 1; /* make default configurable? */ ev->cbtime = 0; ev->prio = PE_QUEUES; ev->callback = 0; ev->ext_data = 0; ev->stats = 0; } static void pe_watcher_cancel_events(pe_watcher *wa) { pe_event *ev; while (!PE_RING_EMPTY(&wa->events)) { pe_ring *lk = wa->events.prev; ev = (pe_event*) lk->self; dequeEvent(ev); pe_event_release(ev); } } static void pe_watcher_dtor(pe_watcher *wa) { STRLEN n_a; assert(WaCANDESTROY(wa)); if (WaDESTROYED(wa)) { warn("Attempt to destroy watcher 0x%x again (ignored)", wa); return; } WaDESTROYED_on(wa); if (WaDEBUGx(wa) >= 3) warn("Watcher '%s' destroyed", SvPV(wa->desc, n_a)); assert(PE_RING_EMPTY(&wa->events)); if (WaPERLCB(wa)) SvREFCNT_dec(wa->callback); if (wa->FALLBACK) SvREFCNT_dec(wa->FALLBACK); if (wa->desc) SvREFCNT_dec(wa->desc); if (wa->stats) Estat.dtor(wa->stats); /* safefree(wa); do it yourself */ } /********************************** *******************************/ WKEYMETH(_watcher_callback) { if (nval) { AV *av; SV *sv; SV *old=0; if (WaPERLCB(ev)) old = (SV*) ev->callback; if (!SvOK(nval)) { WaPERLCB_off(ev); ev->callback = 0; ev->ext_data = 0; pe_watcher_stop(ev, 0); } else if (SvROK(nval) && (SvTYPE(sv=SvRV(nval)) == SVt_PVCV)) { WaPERLCB_on(ev); ev->callback = SvREFCNT_inc(nval); } else if (SvROK(nval) && (SvTYPE(av=(AV*)SvRV(nval)) == SVt_PVAV) && av_len(av) == 1) { /* method lookup code adapted from universal.c */ STRLEN n_a; SV *pkgsv = *av_fetch(av, 0, 0); HV *pkg = NULL; SV *namesv = *av_fetch(av, 1, 0); char *name = SvPV(namesv, n_a); int ok=0; if(SvROK(pkgsv)) { pkgsv = (SV*)SvRV(pkgsv); if(SvOBJECT(pkgsv)) pkg = SvSTASH(pkgsv); } else { pkg = gv_stashsv(pkgsv, FALSE); } if (pkg) { GV *gv = gv_fetchmethod_autoload(pkg, name, FALSE); if (gv && isGV(gv)) ok=1; } else { warn("Event: package '%s' doesn't exist (creating)", SvPV(pkgsv, n_a)); pkg = gv_stashsv(pkgsv, 1); } if (!ok) { warn("Event: callback method %s->%s doesn't exist", HvNAME(pkg), name); } WaPERLCB_on(ev); ev->callback = SvREFCNT_inc(nval); } else { if (SvIV(DebugLevel) >= 2) sv_dump(sv); croak("Callback must be a code ref or [$object, $method_name]"); } if (old) SvREFCNT_dec(old); } { SV *ret = (WaPERLCB(ev)? (SV*) ev->callback : (ev->callback? sv_2mortal(newSVpvf("", ev->callback, ev->ext_data)) : &PL_sv_undef)); dSP; XPUSHs(ret); PUTBACK; } } WKEYMETH(_watcher_cbtime) { if (!nval) { dSP; XPUSHs(sv_2mortal(newSVnv(ev->cbtime))); PUTBACK; } else croak("'e_cbtime' is read-only"); } WKEYMETH(_watcher_desc) { if (nval) { sv_setsv(ev->desc, nval); } { dSP; XPUSHs(ev->desc); PUTBACK; } } WKEYMETH(_watcher_debug) { if (nval) { if (sv_true(nval)) WaDEBUG_on(ev); else WaDEBUG_off(ev); } { dSP; XPUSHs(boolSV(WaDEBUG(ev))); PUTBACK; } } WKEYMETH(_watcher_priority) { if (nval) { ev->prio = SvIV(nval); } { dSP; XPUSHs(sv_2mortal(newSViv(ev->prio))); PUTBACK; } } WKEYMETH(_watcher_reentrant) { if (nval) { if (sv_true(nval)) WaREENTRANT_on(ev); else { if (ev->running > 1) croak("'reentrant' cannot be turned off while nested %d times", ev->running); WaREENTRANT_off(ev); } } { dSP; XPUSHs(boolSV(WaREENTRANT(ev))); PUTBACK; } } WKEYMETH(_watcher_repeat) { if (nval) { if (sv_true(nval)) WaREPEAT_on(ev); else WaREPEAT_off(ev); } { dSP; XPUSHs(boolSV(WaREPEAT(ev))); PUTBACK; } } WKEYMETH(_watcher_suspend) { if (nval) { if (sv_true(nval)) pe_watcher_suspend(ev); else pe_watcher_resume(ev); } { dSP; XPUSHs(boolSV(WaSUSPEND(ev))); PUTBACK; } } WKEYMETH(_watcher_max_cb_tm) { if (nval) { int tm = SvIOK(nval)? SvIV(nval) : 0; if (tm < 0) { warn("e_max_cb_tm must be non-negative"); tm=0; } ev->max_cb_tm = tm; } { dSP; XPUSHs(sv_2mortal(newSViv(ev->max_cb_tm))); PUTBACK; } } /********************************** *******************************/ static void pe_watcher_nomethod(pe_watcher *ev, char *meth) { HV *stash = ev->vtbl->stash; assert(stash); croak("%s::%s is missing", HvNAME(stash), meth); } static char *pe_watcher_nostart(pe_watcher *ev, int repeat) { pe_watcher_nomethod(ev,"start"); return 0; } static void pe_watcher_nostop(pe_watcher *ev) { pe_watcher_nomethod(ev,"stop"); } static void pe_watcher_alarm(pe_watcher *ev, pe_timeable *tm) { pe_watcher_nomethod(ev,"alarm"); } static void boot_pe_watcher() { HV *stash = gv_stashpv("Event::Watcher", 1); struct pe_watcher_vtbl *vt; PE_RING_INIT(&AllWatchers, 0); vt = &pe_watcher_base_vtbl; vt->stash = 0; vt->did_require = 0; vt->dtor = 0; vt->start = pe_watcher_nostart; vt->stop = pe_watcher_nostop; vt->alarm = pe_watcher_alarm; newCONSTSUB(stash, "ACTIVE", newSViv(PE_ACTIVE)); newCONSTSUB(stash, "SUSPEND", newSViv(PE_SUSPEND)); newCONSTSUB(stash, "R", newSViv(PE_R)); newCONSTSUB(stash, "W", newSViv(PE_W)); newCONSTSUB(stash, "E", newSViv(PE_E)); newCONSTSUB(stash, "T", newSViv(PE_T)); } static void pe_register_vtbl(pe_watcher_vtbl *vt, HV *stash, pe_event_vtbl *evt) { vt->stash = stash; vt->event_vtbl = evt; vt->new_event = evt->new_event; } static void pe_watcher_now(pe_watcher *wa) { pe_event *ev; if (WaSUSPEND(wa)) return; if (!wa->callback) { STRLEN n_a; croak("Event: attempt to invoke now() method with callback unset on watcher '%s'", SvPV(wa->desc,n_a)); } WaRUNNOW_on(wa); /* race condition XXX */ ev = (*wa->vtbl->new_event)(wa); ++ev->hits; queueEvent(ev); } /******************************************************************* The following methods change the status flags. This is the only code that should be changing these flags! */ static void pe_watcher_cancel(pe_watcher *wa) { if (WaCANCELLED(wa)) return; WaSUSPEND_off(wa); pe_watcher_stop(wa, 1); /* peer */ WaCANCELLED_on(wa); PE_RING_DETACH(&wa->all); if (wa->mysv) SvREFCNT_dec(wa->mysv); /* might destroy */ else if (WaCANDESTROY(wa)) (*wa->vtbl->dtor)(wa); } static void pe_watcher_suspend(pe_watcher *ev) { STRLEN n_a; assert(ev); if (WaSUSPEND(ev)) return; if (WaDEBUGx(ev) >= 4) warn("Event: suspend '%s'\n", SvPV(ev->desc,n_a)); pe_watcher_off(ev); pe_watcher_cancel_events(ev); WaSUSPEND_on(ev); /* must happen nowhere else!! */ } static void pe_watcher_resume(pe_watcher *ev) { STRLEN n_a; assert(ev); if (!WaSUSPEND(ev)) return; WaSUSPEND_off(ev); if (WaDEBUGx(ev) >= 4) warn("Event: resume '%s'%s\n", SvPV(ev->desc,n_a), WaACTIVE(ev)?" ACTIVE":""); if (WaACTIVE(ev)) pe_watcher_on(ev, 0); } static char *pe_watcher_on(pe_watcher *wa, int repeat) { STRLEN n_a; char *excuse; if (WaPOLLING(wa) || WaSUSPEND(wa)) return 0; if (WaCANCELLED(wa)) croak("Event: attempt to start cancelled watcher '%s'", SvPV(wa->desc,n_a)); excuse = (*wa->vtbl->start)(wa, repeat); if (excuse) { if (SvIV(DebugLevel)) warn("Event: can't restart '%s' %s", SvPV(wa->desc, n_a), excuse); pe_watcher_stop(wa, 1); /* update flags! */ } else WaPOLLING_on(wa); /* must happen nowhere else!! */ return excuse; } static void pe_watcher_off(pe_watcher *wa) { if (!WaPOLLING(wa) || WaSUSPEND(wa)) return; (*wa->vtbl->stop)(wa); WaPOLLING_off(wa); } static void pe_watcher_start(pe_watcher *ev, int repeat) { char *excuse; STRLEN n_a; if (WaACTIVE(ev)) return; if (WaDEBUGx(ev) >= 4) warn("Event: active ON '%s'\n", SvPV(ev->desc,n_a)); excuse = pe_watcher_on(ev, repeat); if (excuse) croak("Event: can't start '%s' %s", SvPV(ev->desc,n_a), excuse); WaACTIVE_on(ev); /* must happen nowhere else!! */ ++ActiveWatchers; } static void pe_watcher_stop(pe_watcher *ev, int cancel_events) { STRLEN n_a; if (!WaACTIVE(ev)) return; if (WaDEBUGx(ev) >= 4) warn("Event: active OFF '%s'\n", SvPV(ev->desc,n_a)); pe_watcher_off(ev); WaACTIVE_off(ev); /* must happen nowhere else!! */ if (cancel_events) pe_watcher_cancel_events(ev); --ActiveWatchers; } Event-1.26/c/typemap.c0000644000076400007640000001171612357140355013331 0ustar useruserstatic SV *wrap_thing(U16 mgcode, void *ptr, HV *stash, SV *temple) { SV *ref; MAGIC **mgp; MAGIC *mg; assert(ptr); assert(stash); if (!temple) temple = (SV*)newHV(); else SvREFCNT_inc(temple); if (SvOBJECT(temple)) croak("Can't attach to blessed reference"); assert(!SvROK(temple)); assert(mg_find(temple, '~') == 0); /* multiplicity disallowed! */ ref = newRV_noinc(temple); sv_bless(ref, stash); mgp = &SvMAGIC(temple); while ((mg = *mgp)) mgp = &mg->mg_moremagic; New(0, mg, 1, MAGIC); Zero(mg, 1, MAGIC); mg->mg_type = '~'; mg->mg_ptr = (char*) ptr; /* NOT refcnt'd */ mg->mg_private = mgcode; *mgp = mg; return ref; } static void* sv_2thing(U16 mgcode, SV *sv) { MAGIC *mg; SV *origsv = sv; if (!sv || !SvROK(sv)) croak("sv_2thing: not a reference?"); sv = SvRV(sv); if (SvTYPE(sv) < SVt_PVMG) croak("sv_2thing: not a thing"); if (!SvOBJECT(sv)) croak("sv_2thing: not an object"); mg = mg_find(sv, '~'); if (mg) { if (mg->mg_private != mgcode) { croak("Can't find event magic (SV=0x%x)", sv); } return (void*) mg->mg_ptr; } croak("sv_2thing: can't decode SV=0x%x", origsv); return 0; } #define MG_WATCHER_CODE ((((unsigned)'e')<<8) + (unsigned)'v') static SV *wrap_watcher(void *ptr, HV *stash, SV *temple) { return wrap_thing(MG_WATCHER_CODE, ptr, stash, temple); } SV *watcher_2sv(pe_watcher *wa) { /**SLOW IS OKAY**/ assert(!WaDESTROYED(wa)); if (!wa->mysv) { wa->mysv = wrap_watcher(wa, wa->vtbl->stash, 0); if (WaDEBUGx(wa) >= 4) { STRLEN n_a; warn("Watcher=0x%x '%s' wrapped with SV=0x%x", wa, SvPV(wa->desc, n_a), SvRV(wa->mysv)); } } return SvREFCNT_inc(sv_2mortal(wa->mysv)); } void* sv_2watcher(SV *sv) { return sv_2thing(MG_WATCHER_CODE, sv); } #define MG_GENERICSRC_CODE 2422 /* randomly chosen */ static SV *wrap_genericsrc(void *ptr, HV *stash, SV *temple) { return wrap_thing(MG_GENERICSRC_CODE, ptr, stash, temple); } static HV *pe_genericsrc_stash; static SV *genericsrc_2sv(pe_genericsrc *src) { /**SLOW IS OKAY**/ if (!src->mysv) { src->mysv = wrap_genericsrc(src, pe_genericsrc_stash, 0); } return SvREFCNT_inc(sv_2mortal(src->mysv)); } static void* sv_2genericsrc(SV *sv) { return sv_2thing(MG_GENERICSRC_CODE, sv); } /* Events have a short lifetime. mysv is kept alive until the event has been serviced. Once perl finally releases mysv then the event is deallocated (or, more likely, recycled). */ SV *event_2sv(pe_event *ev) { /**MAKE FAST**/ if (!ev->mysv) { SV *rv = newSV(0); SV *sv = newSVrv(rv,0); sv_bless(rv, ev->vtbl->stash); sv_setiv(sv, PTR2IV(ev)); ev->mysv = rv; if (WaDEBUGx(ev->up) >= 4) { STRLEN n_a; warn("Event=0x%x '%s' wrapped with SV=0x%x", ev, SvPV(ev->up->desc, n_a), SvRV(ev->mysv)); } } return SvREFCNT_inc(sv_2mortal(ev->mysv)); } void *sv_2event(SV *sv) { void *ptr; assert(sv); assert(SvROK(sv)); sv = SvRV(sv); ptr = INT2PTR(void *, SvIV(sv)); assert(ptr); return ptr; } /***************************************************************/ #define VERIFYINTERVAL(name, f) \ STMT_START { NV ign; sv_2interval(name, f, &ign); } STMT_END int sv_2interval(char *label, SV *in, NV *out) { SV *sv = in; if (!sv) return 0; if (SvGMAGICAL(sv)) mg_get(sv); if (!SvOK(sv)) return 0; if (SvROK(sv)) sv = SvRV(sv); if (!SvOK(sv)) { warn("Event: %s interval undef", label); *out = 0; } else if (SvNOK(sv)) { *out = SvNVX(sv); } else if (SvIOK(sv)) { *out = SvIVX(sv); } else if (looks_like_number(sv)) { *out = SvNV(sv); } else { sv_dump(in); croak("Event: %s interval must be a number or reference to a number", label); return 0; } if (*out < 0) { warn("Event: %s has negative timeout %.2f (clipped to zero)", label, *out); *out = 0; } return 1; } SV* events_mask_2sv(int mask) { SV *ret = newSV(0); (void)SvUPGRADE(ret, SVt_PVIV); sv_setpvn(ret, "", 0); if (mask & PE_R) sv_catpv(ret, "r"); if (mask & PE_W) sv_catpv(ret, "w"); if (mask & PE_E) sv_catpv(ret, "e"); if (mask & PE_T) sv_catpv(ret, "t"); SvIVX(ret) = mask; SvIOK_on(ret); return ret; } int sv_2events_mask(SV *sv, int bits) { if (SvPOK(sv)) { UV got=0; int xx; STRLEN el; char *ep = SvPV(sv,el); for (xx=0; xx < el; xx++) { switch (ep[xx]) { case 'r': if (bits & PE_R) { got |= PE_R; continue; } case 'w': if (bits & PE_W) { got |= PE_W; continue; } case 'e': if (bits & PE_E) { got |= PE_E; continue; } case 't': if (bits & PE_T) { got |= PE_T; continue; } } warn("Ignored '%c' in poll mask", ep[xx]); } return got; } else if (SvIOK(sv)) { UV extra = SvIVX(sv) & ~bits; if (extra) warn("Ignored extra bits (0x%x) in poll mask", extra); return SvIVX(sv) & bits; } else { sv_dump(sv); croak("Must be a string /[rwet]/ or bit mask"); return 0; /* NOTREACHED */ } } Event-1.26/c/timer.c0000644000076400007640000000424612357140355012772 0ustar useruserstatic struct pe_watcher_vtbl pe_timer_vtbl; static pe_watcher *pe_timer_allocate(HV *stash, SV *temple) { pe_timer *ev; EvNew(7, ev, 1, pe_timer); assert(ev); ev->base.vtbl = &pe_timer_vtbl; PE_RING_INIT(&ev->tm.ring, ev); ev->tm.at = 0; ev->interval = &PL_sv_undef; pe_watcher_init(&ev->base, stash, temple); return (pe_watcher*) ev; } static void pe_timer_dtor(pe_watcher *ev) { pe_timer *tm = (pe_timer*) ev; SvREFCNT_dec(tm->interval); pe_watcher_dtor(ev); EvFree(7, ev); } static char *pe_timer_start(pe_watcher *ev, int repeat) { STRLEN n_a; pe_timer *tm = (pe_timer*) ev; if (!ev->callback) return "without callback"; if (repeat) { /* We just finished the callback and need to re-insert at the appropriate time increment. */ NV interval; if (!sv_2interval("timer", tm->interval, &interval)) return "repeating timer has no interval"; tm->tm.at = interval + (WaHARD(ev)? tm->tm.at : NVtime()); } if (!tm->tm.at) return "timer unset"; pe_timeable_start(&tm->tm); return 0; } static void pe_timer_stop(pe_watcher *ev) { pe_timeable_stop(&((pe_timer*)ev)->tm); } static void pe_timer_alarm(pe_watcher *wa, pe_timeable *tm) { pe_event *ev = (*wa->vtbl->new_event)(wa); ++ev->hits; queueEvent(ev); } WKEYMETH(_timer_at) { pe_timer *tp = (pe_timer*)ev; if (nval) { int active = WaPOLLING(ev); if (active) pe_watcher_off(ev); tp->tm.at = SvNV(nval); if (active) pe_watcher_on(ev, 0); } { dSP; XPUSHs(sv_2mortal(newSVnv(tp->tm.at))); PUTBACK; } } WKEYMETH(_timer_interval) { pe_timer *tp = (pe_timer*)ev; if (nval) { SV *old = tp->interval; tp->interval = SvREFCNT_inc(nval); SvREFCNT_dec(old); VERIFYINTERVAL("timer", tp->interval); /* recalc expiration XXX */ } { dSP; XPUSHs(tp->interval); PUTBACK; } } static void boot_timer() { pe_watcher_vtbl *vt = &pe_timer_vtbl; memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl)); vt->dtor = pe_timer_dtor; vt->start = pe_timer_start; vt->stop = pe_timer_stop; vt->alarm = pe_timer_alarm; pe_register_vtbl(vt, gv_stashpv("Event::timer",1), &event_vtbl); } Event-1.26/c/signal.c0000644000076400007640000001013012357140355013114 0ustar useruser#if !defined(NSIG) || defined(M_UNIX) || defined(M_XENIX) // Fix signal macro compatibility with signal.h of MS VC++: #ifdef WIN32 #define signal win32_signal #endif #include // Get back Perl marcro value defined ad XSUB.h: #ifdef WIN32 #define signal PerlProc_signal #endif #endif static struct pe_watcher_vtbl pe_signal_vtbl; /* GLOBALS: Sigvalid Sigring Sigstat Sigslot */ static U32 Sigvalid[1+NSIG/32]; /*assume 32bit; doesn't matter*/ #define PE_SIGVALID(sig) (Sigvalid[sig>>5] & (1 << ((sig) & 0x1f))) #define PE_SIGVALID_off(sig) Sigvalid[sig>>5] &= ~(1 << ((sig) & 0x1f)) struct pe_sig_stat { U32 Hits; U16 hits[NSIG]; }; typedef struct pe_sig_stat pe_sig_stat; static int Sigslot; static pe_sig_stat Sigstat[2]; static pe_ring Sigring[NSIG]; /* /GLOBALS */ static Signal_t process_sighandler(int sig) { pe_sig_stat *st = &Sigstat[Sigslot]; ++st->Hits; ++st->hits[sig]; } static pe_watcher *pe_signal_allocate(HV *stash, SV *temple) { pe_signal *ev; EvNew(5, ev, 1, pe_signal); ev->base.vtbl = &pe_signal_vtbl; PE_RING_INIT(&ev->sring, ev); ev->signal = 0; pe_watcher_init(&ev->base, stash, temple); WaREPEAT_on(ev); WaINVOKE1_off(ev); return (pe_watcher*) ev; } static void pe_signal_dtor(pe_watcher *ev) { pe_watcher_dtor(ev); EvFree(5, ev); } static char *pe_signal_start(pe_watcher *_ev, int repeat) { pe_signal *ev = (pe_signal*) _ev; int sig = ev->signal; if (!_ev->callback) return "without callback"; if (sig == 0) return "without signal"; if (PE_RING_EMPTY(&Sigring[sig])) rsignal(sig, (Sighandler_t)process_sighandler); PE_RING_UNSHIFT(&ev->sring, &Sigring[sig]); return 0; } static void pe_signal_stop(pe_watcher *_ev) { pe_signal *ev = (pe_signal*) _ev; int sig = ev->signal; PE_RING_DETACH(&ev->sring); if (PE_RING_EMPTY(&Sigring[sig])) { rsignal(sig, (Sighandler_t)SIG_DFL); Sigstat[0].hits[sig] = 0; Sigstat[1].hits[sig] = 0; } } WKEYMETH(_signal_signal) { pe_signal *sg = (pe_signal*) ev; if (nval) { STRLEN n_a; int active = WaPOLLING(ev); int sig = whichsig(SvPV(nval, n_a)); /*warn("whichsig(%s) = %d", SvPV(nval,na), sig); /**/ if (sig == 0) croak("Unrecognized signal '%s'", SvPV(nval, n_a)); if (!PE_SIGVALID(sig)) croak("Signal '%s' cannot be caught", SvPV(nval, n_a)); if (active) pe_watcher_off(ev); sg->signal = sig; if (active) pe_watcher_on(ev, 0); } { dSP; XPUSHs(sg->signal > 0? sv_2mortal(newSVpv(PL_sig_name[sg->signal],0)) : &PL_sv_undef); PUTBACK; } } static void _signal_asynccheck(pe_sig_stat *st) { int xx, got; pe_watcher *wa; for (xx = 1; xx < NSIG; xx++) { if (!st->hits[xx]) continue; got = st->hits[xx]; wa = (pe_watcher*) Sigring[xx].next->self; while (wa) { pe_event *ev = (*wa->vtbl->new_event)(wa); ev->hits += got; queueEvent(ev); wa = (pe_watcher*) ((pe_signal*)wa)->sring.next->self; } st->hits[xx] = 0; } Zero(st, 1, struct pe_sig_stat); } /* This implementation gives no race conditions, assuming no kernel-level threads. */ static void pe_signal_asynccheck() { pe_sig_stat *st; Sigslot = 1; st = &Sigstat[0]; if (st->Hits) _signal_asynccheck(st); Sigslot = 0; st = &Sigstat[1]; if (st->Hits) _signal_asynccheck(st); } static void boot_signal() { int xx; int sig; char **sigp; /* it is crufty to hardcode this list */ static char *nohandle[] = { "KILL", "STOP", "ZERO", 0 }; pe_watcher_vtbl *vt = &pe_signal_vtbl; Zero(&Sigstat[0], 1, pe_sig_stat); Zero(&Sigstat[1], 1, pe_sig_stat); Sigslot = 0; for (xx=0; xx < NSIG; xx++) { PE_RING_INIT(&Sigring[xx], 0); } memset(Sigvalid, ~0, sizeof(Sigvalid)); PE_SIGVALID_off(0); sigp = nohandle; while (*sigp) { sig = whichsig(*sigp); if (sig) PE_SIGVALID_off(sig); ++sigp; } memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl)); vt->dtor = pe_signal_dtor; vt->start = pe_signal_start; vt->stop = pe_signal_stop; pe_register_vtbl(vt, gv_stashpv("Event::signal",1), &event_vtbl); } Event-1.26/c/generic.c0000644000076400007640000000500112357140355013254 0ustar useruserstatic struct pe_watcher_vtbl pe_generic_vtbl; static pe_watcher *pe_generic_allocate(HV *stash, SV *temple) { pe_generic *ev; EvNew(14, ev, 1, pe_generic); ev->base.vtbl = &pe_generic_vtbl; pe_watcher_init(&ev->base, stash, temple); ev->source = &PL_sv_undef; PE_RING_INIT(&ev->active, ev); WaREPEAT_on(ev); WaINVOKE1_off(ev); return (pe_watcher*) ev; } static void pe_generic_dtor(pe_watcher *ev) { pe_generic *gw = (pe_generic *)ev; SvREFCNT_dec(gw->source); pe_watcher_dtor(ev); EvFree(14, ev); } static char *pe_generic_start(pe_watcher *_ev, int repeat) { pe_generic *ev = (pe_generic*) _ev; SV *source = ev->source; pe_genericsrc *src; if (!_ev->callback) return "without callback"; if (!source || !SvOK(source)) return "without source"; src = sv_2genericsrc(source); PE_RING_UNSHIFT(&ev->active, &src->watchers); return 0; } static void pe_generic_stop(pe_watcher *_ev) { pe_generic *ev = (pe_generic*) _ev; PE_RING_DETACH(&ev->active); } WKEYMETH(_generic_source) { pe_generic *gw = (pe_generic*)ev; if (nval) { SV *old = gw->source; int active = WaPOLLING(ev); if(SvOK(nval)) { (void) sv_2genericsrc(nval); /* for type check */ } if (active) pe_watcher_off(ev); gw->source = SvREFCNT_inc(nval); if (active) pe_watcher_on(ev, 0); SvREFCNT_dec(old); } { dSP; XPUSHs(gw->source); PUTBACK; } } static pe_genericsrc *pe_genericsrc_allocate(HV *stash, SV *temple) { pe_genericsrc *src; EvNew(16, src, 1, pe_genericsrc); src->mysv = stash || temple ? wrap_genericsrc(src, stash, temple) : 0; PE_RING_INIT(&src->watchers, 0); return src; } static void pe_genericsrc_dtor(pe_genericsrc *src) { PE_RING_DETACH(&src->watchers); EvFree(16, src); } static HV *pe_genericsrc_stash; static void pe_genericsrc_event(pe_genericsrc *src, SV *data) { pe_generic *wa = src->watchers.next->self; while(wa) { pe_datafulevent *ev = (pe_datafulevent*) (*wa->base.vtbl->new_event)(&wa->base); ++ev->base.hits; ev->data = SvREFCNT_inc(data); queueEvent(&ev->base); wa = wa->active.next->self; } } static void boot_generic() { pe_watcher_vtbl *vt = &pe_generic_vtbl; memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl)); vt->dtor = pe_generic_dtor; vt->start = pe_generic_start; vt->stop = pe_generic_stop; pe_register_vtbl(vt, gv_stashpv("Event::generic",1), &datafulevent_vtbl); pe_genericsrc_stash = gv_stashpv("Event::generic::Source", 1); } Event-1.26/c/timeable.c0000644000076400007640000000527412357140355013436 0ustar useruserstatic pe_timeable Timeables; /*#define D_TIMEABLE(x) x /**/ #define D_TIMEABLE(x) /**/ static void db_show_timeables() { pe_timeable *tm = (pe_timeable*) Timeables.ring.next; warn("timeables at %.2f\n", NVtime() + IntervalEpsilon); while (tm->ring.self) { STRLEN n_a; pe_watcher *wa = (pe_watcher*) tm->ring.self; pe_timeable *next = (pe_timeable*) tm->ring.next; warn(" %.2f '%s'\n", tm->at, SvPV(wa->desc, n_a)); tm = next; } } static void pe_timeables_check() { pe_timeable *tm = (pe_timeable*) Timeables.ring.next; NV now = NVtime() + IntervalEpsilon; /*db_show_timeables();/**/ while (tm->ring.self && now >= tm->at) { pe_watcher *ev = (pe_watcher*) tm->ring.self; pe_timeable *next = (pe_timeable*) tm->ring.next; D_TIMEABLE({ if (WaDEBUGx(ev) >= 4) { STRLEN n_a; warn("Event: timeable expire '%s'\n", SvPV(ev->desc, n_a)); } }) assert(!WaSUSPEND(ev)); assert(WaACTIVE(ev)); PE_RING_DETACH(&tm->ring); (*ev->vtbl->alarm)(ev, tm); tm = next; } } static NV timeTillTimer() { pe_timeable *tm = (pe_timeable*) Timeables.ring.next; if (!tm->ring.self) return 3600; return tm->at - NVtime(); } static void pe_timeable_start(pe_timeable *tm) { /* OPTIMIZE! */ pe_watcher *ev = (pe_watcher*) tm->ring.self; pe_timeable *rg = (pe_timeable*) Timeables.ring.next; assert(!WaSUSPEND(ev)); assert(PE_RING_EMPTY(&tm->ring)); if (WaDEBUGx(ev)) { NV left = tm->at - NVtime(); if (left < 0) { STRLEN n_a; warn("Event: timer for '%s' set to expire immediately (%.2f)", SvPV(ev->desc, n_a), left); } } while (rg->ring.self && rg->at < tm->at) { rg = (pe_timeable*) rg->ring.next; } /*warn("-- adding 0x%x:\n", ev); db_show_timeables();/**/ PE_RING_ADD_BEFORE(&tm->ring, &rg->ring); /*warn("T:\n"); db_show_timeables();/**/ D_TIMEABLE({ if (WaDEBUGx(ev) >= 4) { STRLEN n_a; warn("Event: timeable start '%s'\n", SvPV(ev->desc, n_a)); } }) } static void pe_timeable_stop(pe_timeable *tm) { D_TIMEABLE({ pe_watcher *ev = (pe_watcher*) tm->ring.self; if (WaDEBUGx(ev) >= 4) { STRLEN n_a; warn("Event: timeable stop '%s'\n", SvPV(ev->desc, n_a)); } }) PE_RING_DETACH(&tm->ring); } static void pe_timeable_adjust(NV delta) { pe_timeable *rg = (pe_timeable*) Timeables.ring.next; while (rg != &Timeables) { rg->at += delta; rg = (pe_timeable*) rg->ring.next; } } WKEYMETH(_timeable_hard) { /* applies to all timers in a watcher; is ok? */ if (nval) { if (sv_true(nval)) WaHARD_on(ev); else WaHARD_off(ev); } { dSP; XPUSHs(boolSV(WaHARD(ev))); PUTBACK; } } static void boot_timeable() { PE_RING_INIT(&Timeables.ring, 0); } Event-1.26/c/queue.c0000644000076400007640000001360712357140355012777 0ustar useruserstatic pe_ring NQueue; static int StarvePrio = PE_QUEUES - 2; static void boot_queue() { HV *stash = gv_stashpv("Event", 1); PE_RING_INIT(&NQueue, 0); newCONSTSUB(stash, "QUEUES", newSViv(PE_QUEUES)); newCONSTSUB(stash, "PRIO_NORMAL", newSViv(PE_PRIO_NORMAL)); newCONSTSUB(stash, "PRIO_HIGH", newSViv(PE_PRIO_HIGH)); } /*inline*/ static void dequeEvent(pe_event *ev) { assert(ev); PE_RING_DETACH(&ev->que); --ActiveWatchers; } static void db_show_queue() { pe_event *ev; ev = (pe_event*) NQueue.next->self; while (ev) { warn("0x%x : %d\n", ev, ev->prio); ev = (pe_event*) ev->que.next->self; } } static int prepare_event(pe_event *ev, char *forwhat) { /* AVOID DIEING IN HERE!! */ STRLEN n_a; pe_watcher *wa = ev->up; if (!ev->callback) { if (WaPERLCB(wa)) { ev->callback = SvREFCNT_inc(wa->callback); EvPERLCB_on(ev); } else { ev->callback = wa->callback; ev->ext_data = wa->ext_data; EvPERLCB_off(ev); } assert(ev->callback); } assert(!WaSUSPEND(wa)); assert(WaREENTRANT(wa) || !wa->running); if (!WaACTIVE(wa)) { if (!WaRUNNOW(wa)) warn("Event: event for !ACTIVE watcher '%s'", SvPV(wa->desc,n_a)); } else { if (!WaREPEAT(wa)) pe_watcher_stop(wa, 0); else if (WaINVOKE1(wa)) pe_watcher_off(wa); } WaRUNNOW_off(wa); /* race condition? XXX */ if (WaDEBUGx(wa) >= 3) warn("Event: %s '%s' prio=%d\n", forwhat, SvPV(wa->desc,n_a), ev->prio); return 1; } static void queueEvent(pe_event *ev) { /**INVOKE**/ assert(ev->hits); if (!PE_RING_EMPTY(&ev->que)) return; /* clump'd event already queued */ if (!prepare_event(ev, "queue")) return; if (ev->prio < 0) { /* invoke the event immediately! */ ev->prio = 0; pe_event_invoke(ev); return; } if (ev->prio >= PE_QUEUES) ev->prio = PE_QUEUES-1; { /* queue in reverse direction? XXX */ /* warn("-- adding 0x%x/%d\n", ev, prio); db_show_queue();/**/ pe_ring *rg; rg = NQueue.next; while (rg->self && ((pe_event*)rg->self)->prio <= ev->prio) rg = rg->next; PE_RING_ADD_BEFORE(&ev->que, rg); /* warn("=\n"); db_show_queue();/**/ ++ActiveWatchers; } } static int pe_empty_queue(int maxprio) { /**INVOKE**/ pe_event *ev; ev = (pe_event*) NQueue.next->self; if (ev && ev->prio < maxprio) { dequeEvent(ev); pe_event_invoke(ev); return 1; } return 0; } /*inline*/ static void pe_multiplex(NV tm) { if (SvIVX(DebugLevel) >= 2) { warn("Event: multiplex %.4fs %s%s\n", tm, PE_RING_EMPTY(&NQueue)?"":"QUEUE", PE_RING_EMPTY(&Idle)?"":"IDLE"); } if (!Estat.on) pe_sys_multiplex(tm); else { void *st = Estat.enter(-1, 0); pe_sys_multiplex(tm); Estat.commit(st, 0); } } static NV pe_map_prepare(NV tm) { pe_qcallback *qcb = (pe_qcallback*) Prepare.prev->self; while (qcb) { if (qcb->is_perl) { SV *got; NV when; dSP; PUSHMARK(SP); PUTBACK; perl_call_sv((SV*)qcb->callback, G_SCALAR); SPAGAIN; got = POPs; PUTBACK; when = SvNOK(got) ? SvNVX(got) : SvNV(got); if (when < tm) tm = when; } else { /* !is_perl */ NV got = (* (NV(*)(void*)) qcb->callback)(qcb->ext_data); if (got < tm) tm = got; } qcb = (pe_qcallback*) qcb->ring.prev->self; } return tm; } static void pe_queue_pending() { NV tm = 0; if (!PE_RING_EMPTY(&Prepare)) tm = pe_map_prepare(tm); pe_multiplex(0); pe_timeables_check(); if (!PE_RING_EMPTY(&Check)) pe_map_check(&Check); pe_signal_asynccheck(); if (!PE_RING_EMPTY(&AsyncCheck)) pe_map_check(&AsyncCheck); } static int one_event(NV tm) { /**INVOKE**/ /*if (SvIVX(DebugLevel) >= 4) warn("Event: ActiveWatchers=%d\n", ActiveWatchers); /**/ pe_signal_asynccheck(); if (!PE_RING_EMPTY(&AsyncCheck)) pe_map_check(&AsyncCheck); if (pe_empty_queue(StarvePrio)) return 1; if (!PE_RING_EMPTY(&NQueue) || !PE_RING_EMPTY(&Idle)) { tm = 0; } else { NV t1 = timeTillTimer(); if (t1 < tm) tm = t1; } if (!PE_RING_EMPTY(&Prepare)) tm = pe_map_prepare(tm); pe_multiplex(tm); pe_timeables_check(); if (!PE_RING_EMPTY(&Check)) pe_map_check(&Check); if (tm) { pe_signal_asynccheck(); if (!PE_RING_EMPTY(&AsyncCheck)) pe_map_check(&AsyncCheck); } if (pe_empty_queue(PE_QUEUES)) return 1; while (1) { pe_watcher *wa; pe_event *ev; pe_ring *lk; if (PE_RING_EMPTY(&Idle)) return 0; lk = Idle.prev; PE_RING_DETACH(lk); wa = (pe_watcher*) lk->self; /* idle is not an event so CLUMP is never an option but we still need to create an event to pass info to the callback */ ev = pe_event_allocate(wa); if (!prepare_event(ev, "idle")) continue; /* can't queueEvent because we are already missed that */ pe_event_invoke(ev); return 1; } } static void pe_reentry() { pe_watcher *wa; struct pe_cbframe *frp; ENTER; /* for SAVE*() macro (see below) */ if (CurCBFrame < 0) return; frp = CBFrame + CurCBFrame; wa = frp->ev->up; assert(wa->running == frp->run_id); if (Estat.on) Estat.suspend(frp->stats); /* reversed by pe_event_postCB? */ if (WaREPEAT(wa)) { if (WaREENTRANT(wa)) { if (WaACTIVE(wa) && WaINVOKE1(wa)) pe_watcher_on(wa, 1); } else { if (!WaSUSPEND(wa)) { /* temporarily suspend non-reentrant watcher until callback is finished! */ pe_watcher_suspend(wa); SAVEDESTRUCTOR(_resume_watcher, wa); } } } } static int safe_one_event(NV maxtm) { int got; pe_check_recovery(); pe_reentry(); got = one_event(maxtm); LEAVE; /* reentry */ return got; } static void pe_unloop(SV *why) { SV *rsv = perl_get_sv("Event::Result", 0); assert(rsv); sv_setsv(rsv, why); if (--ExitLevel < 0) { warn("Event::unloop() to %d", ExitLevel); } } static void pe_unloop_all(SV *why) { SV *rsv = perl_get_sv("Event::TopResult", 0); assert(rsv); sv_setsv(rsv, why); ExitLevel = 0; } Event-1.26/c/io.c0000644000076400007640000001253312357142703012256 0ustar useruserstatic struct pe_watcher_vtbl pe_io_vtbl; static pe_ring IOWatch; static int IOWatchCount; static int IOWatch_OK; static void pe_sys_io_add (pe_io *ev); static void pe_sys_io_del (pe_io *ev); static pe_watcher *pe_io_allocate(HV *stash, SV *temple) { pe_io *ev; EvNew(4, ev, 1, pe_io); ev->base.vtbl = &pe_io_vtbl; pe_watcher_init(&ev->base, stash, temple); PE_RING_INIT(&ev->tm.ring, ev); PE_RING_INIT(&ev->ioring, ev); ev->fd = -1; ev->timeout = 0; ev->handle = &PL_sv_undef; ev->poll = PE_R; ev->tm_callback = 0; ev->tm_ext_data = 0; WaINVOKE1_off(ev); WaREPEAT_on(ev); return (pe_watcher*) ev; } static void pe_io_dtor(pe_watcher *_ev) { pe_io *ev = (pe_io*) _ev; if (WaTMPERLCB(ev)) SvREFCNT_dec(ev->tm_callback); PE_RING_DETACH(&ev->ioring); SvREFCNT_dec(ev->handle); pe_watcher_dtor(_ev); EvFree(4, _ev); } static char *pe_io_start(pe_watcher *_ev, int repeat) { STRLEN n_a; int ok=0; pe_io *ev = (pe_io*) _ev; if (SvOK(ev->handle)) ev->fd = pe_sys_fileno(ev->handle, SvPV(ev->base.desc, n_a)); /* On Unix, it is possible to set the 'fd' in C code without assigning anything to the 'handle'. This should be more officially supported but maybe it is too unix specific. */ if (ev->fd >= 0 && (ev->poll & ~PE_T)) { if (!ev->base.callback) return "without io callback"; PE_RING_UNSHIFT(&ev->ioring, &IOWatch); pe_sys_io_add(ev); ++IOWatchCount; IOWatch_OK = 0; ++ok; } if (ev->timeout) { if (!ev->base.callback && !ev->tm_callback) { assert(!ok); return "without timeout callback"; } ev->poll |= PE_T; ev->tm.at = NVtime() + ev->timeout; /* too early okay */ pe_timeable_start(&ev->tm); ++ok; } else { ev->poll &= ~PE_T; } return ok? 0 : "because there is nothing to watch"; } static void pe_io_stop(pe_watcher *_ev) { pe_io *ev = (pe_io*) _ev; pe_timeable_stop(&ev->tm); if (!PE_RING_EMPTY(&ev->ioring)) { pe_sys_io_del(ev); PE_RING_DETACH(&ev->ioring); --IOWatchCount; IOWatch_OK = 0; } } static void pe_io_alarm(pe_watcher *_wa, pe_timeable *hit) { pe_io *wa = (pe_io*) _wa; NV now = NVtime(); NV left = (_wa->cbtime + wa->timeout) - now; if (left < IntervalEpsilon) { pe_ioevent *ev; if (WaREPEAT(wa)) { wa->tm.at = now + wa->timeout; pe_timeable_start(&wa->tm); } else { wa->timeout = 0; /*RESET*/ } ev = (pe_ioevent*) (*_wa->vtbl->new_event)(_wa); ++ev->base.hits; ev->got |= PE_T; if (wa->tm_callback) { if (WaTMPERLCB(wa)) { pe_anyevent_set_perl_cb(&ev->base, wa->tm_callback); } else { pe_anyevent_set_cb(&ev->base, wa->tm_callback, wa->tm_ext_data); } } queueEvent((pe_event*) ev); } else { /* ++TimeoutTooEarly; This branch is normal behavior and does not indicate poor clock accuracy. */ wa->tm.at = now + left; pe_timeable_start(&wa->tm); } } static void _io_restart(pe_watcher *ev) { if (!WaPOLLING(ev)) return; pe_watcher_off(ev); pe_watcher_on(ev, 0); } static void pe_io_reset_handle(pe_watcher *ev) { /* used by unix_io */ pe_io *io = (pe_io*)ev; SvREFCNT_dec(io->handle); io->handle = &PL_sv_undef; io->fd = -1; _io_restart(ev); } WKEYMETH(_io_poll) { pe_io *io = (pe_io*)ev; if (nval) { int nev = sv_2events_mask(nval, PE_R|PE_W|PE_E|PE_T); if (io->timeout) nev |= PE_T; else nev &= ~PE_T; if (io->poll != nev) { io->poll = nev; _io_restart(ev); } } { dSP; XPUSHs(sv_2mortal(events_mask_2sv(io->poll))); PUTBACK; } } WKEYMETH(_io_handle) { pe_io *io = (pe_io*)ev; if (nval) { SV *old = io->handle; io->handle = SvREFCNT_inc(nval); SvREFCNT_dec(old); io->fd = -1; _io_restart(ev); } { dSP; XPUSHs(io->handle); PUTBACK; } } WKEYMETH(_io_timeout) { pe_io *io = (pe_io*)ev; if (nval) { io->timeout = SvOK(nval)? SvNV(nval) : 0; /*undef is ok*/ _io_restart(ev); } { dSP; XPUSHs(sv_2mortal(newSVnv(io->timeout))); PUTBACK; } } WKEYMETH(_io_timeout_cb) { pe_io *io = (pe_io*)ev; if (nval) { AV *av; SV *sv; SV *old=0; if (WaTMPERLCB(ev)) old = (SV*) io->tm_callback; if (!SvOK(nval)) { WaTMPERLCB_off(ev); io->tm_callback = 0; io->tm_ext_data = 0; } else if (SvROK(nval) && (SvTYPE(sv=SvRV(nval)) == SVt_PVCV)) { WaTMPERLCB_on(ev); io->tm_callback = SvREFCNT_inc(nval); } else if (SvROK(nval) && (SvTYPE(av=(AV*)SvRV(nval)) == SVt_PVAV) && av_len(av) == 1 && !SvROK(sv=*av_fetch(av, 1, 0))) { WaTMPERLCB_on(ev); io->tm_callback = SvREFCNT_inc(nval); } else { if (SvIV(DebugLevel) >= 2) sv_dump(sv); croak("Callback must be a code ref or [$object, $method_name]"); } if (old) SvREFCNT_dec(old); } { SV *ret = (WaTMPERLCB(ev)? (SV*) io->tm_callback : (io->tm_callback? sv_2mortal(newSVpvf("", io->tm_callback, io->tm_ext_data)) : &PL_sv_undef)); dSP; XPUSHs(ret); PUTBACK; } } static void boot_io() { pe_watcher_vtbl *vt = &pe_io_vtbl; memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl)); vt->dtor = pe_io_dtor; vt->start = pe_io_start; vt->stop = pe_io_stop; vt->alarm = pe_io_alarm; PE_RING_INIT(&IOWatch, 0); IOWatch_OK = 0; IOWatchCount = 0; pe_register_vtbl(vt, gv_stashpv("Event::io",1), &ioevent_vtbl); } Event-1.26/c/ev.c0000644000076400007640000002101412357140355012254 0ustar useruser/* 100 levels will trigger a manditory warning from perl */ #define MAX_CB_NEST 95 static NV QueueTime[PE_QUEUES]; static pe_cbframe CBFrame[MAX_CB_NEST]; static int CurCBFrame = -1; pe_event_vtbl event_vtbl, ioevent_vtbl, datafulevent_vtbl; static void pe_anyevent_init(pe_event *ev, pe_watcher *wa) { assert(wa); ev->up = wa; ++wa->refcnt; ev->mysv = 0; PE_RING_INIT(&ev->peer, ev); PE_RING_UNSHIFT(&ev->peer, &wa->events); ev->hits = 0; ev->prio = wa->prio; ev->callback = 0; } static void pe_anyevent_dtor(pe_event *ev) { STRLEN n_a; pe_watcher *wa = ev->up; if (WaDEBUGx(wa) >= 3) warn("Event=0x%x '%s' destroyed (SV=0x%x)", ev, SvPV(wa->desc, n_a), ev->mysv? SvRV(ev->mysv) : 0); ev->up = 0; ev->mysv = 0; ev->hits = 0; if (EvPERLCB(ev)) SvREFCNT_dec(ev->callback); ev->callback = 0; PE_RING_DETACH(&ev->peer); PE_RING_DETACH(&ev->que); --wa->refcnt; if (WaCANDESTROY(wa)) /* running */ (*wa->vtbl->dtor)(wa); } static void pe_anyevent_set_cb(pe_event *ev, void *fptr, void *ext) { if (EvPERLCB(ev)) SvREFCNT_dec(ev->callback); EvPERLCB_off(ev); ev->callback = fptr; ev->ext_data = ext; } static void pe_anyevent_set_perl_cb(pe_event *ev, SV *sv) { SV *old = 0; if (EvPERLCB(ev)) old = ev->callback; ev->callback = SvREFCNT_inc(sv); SvREFCNT_dec(old); EvPERLCB_on(ev); } /*****************************************************************/ static pe_event *pe_event_allocate(pe_watcher *wa) { pe_event *ev; assert(wa); if (PE_RING_EMPTY(&event_vtbl.freelist)) { EvNew(0, ev, 1, pe_event); ev->vtbl = &event_vtbl; PE_RING_INIT(&ev->que, ev); } else { pe_ring *lk = event_vtbl.freelist.prev; PE_RING_DETACH(lk); ev = (pe_event*) lk->self; } pe_anyevent_init(ev, wa); return ev; } static void pe_event_dtor(pe_event *ev) { pe_anyevent_dtor(ev); PE_RING_UNSHIFT(&ev->que, &event_vtbl.freelist); } static void pe_event_release(pe_event *ev) { if (!ev->mysv) (*ev->vtbl->dtor)(ev); else { SvREFCNT_dec(ev->mysv); ev->mysv=0; } } EKEYMETH(_event_hits) { if (!nval) { dSP; XPUSHs(sv_2mortal(newSViv(ev->hits))); PUTBACK; } else croak("'e_hits' is read-only"); } EKEYMETH(_event_prio) { if (!nval) { dSP; XPUSHs(sv_2mortal(newSViv(ev->prio))); PUTBACK; } else croak("'e_prio' is read-only"); } /*------------------------------------------------------*/ static pe_event *pe_ioevent_allocate(pe_watcher *wa) { pe_ioevent *ev; assert(wa); if (PE_RING_EMPTY(&ioevent_vtbl.freelist)) { EvNew(1, ev, 1, pe_ioevent); ev->base.vtbl = &ioevent_vtbl; PE_RING_INIT(&ev->base.que, ev); } else { pe_ring *lk = ioevent_vtbl.freelist.prev; PE_RING_DETACH(lk); ev = (pe_ioevent*) lk->self; } pe_anyevent_init(&ev->base, wa); ev->got = 0; return &ev->base; } static void pe_ioevent_dtor(pe_event *ev) { pe_anyevent_dtor(ev); PE_RING_UNSHIFT(&ev->que, &ioevent_vtbl.freelist); } EKEYMETH(_event_got) { pe_ioevent *io = (pe_ioevent *)ev; if (!nval) { dSP; XPUSHs(sv_2mortal(events_mask_2sv(io->got))); PUTBACK; } else croak("'e_got' is read-only"); } /*------------------------------------------------------*/ static pe_event *pe_datafulevent_allocate(pe_watcher *wa) { pe_datafulevent *ev; assert(wa); if (PE_RING_EMPTY(&datafulevent_vtbl.freelist)) { EvNew(15, ev, 1, pe_datafulevent); ev->base.vtbl = &datafulevent_vtbl; PE_RING_INIT(&ev->base.que, ev); } else { pe_ring *lk = datafulevent_vtbl.freelist.prev; PE_RING_DETACH(lk); ev = (pe_datafulevent*) lk->self; } pe_anyevent_init(&ev->base, wa); ev->data = &PL_sv_undef; return &ev->base; } static void pe_datafulevent_dtor(pe_event *ev) { pe_datafulevent *de = (pe_datafulevent *)ev; SvREFCNT_dec(de->data); pe_anyevent_dtor(ev); PE_RING_UNSHIFT(&ev->que, &datafulevent_vtbl.freelist); } EKEYMETH(_event_data) { pe_datafulevent *de = (pe_datafulevent *)ev; if (!nval) { dSP; XPUSHs(de->data); PUTBACK; } else croak("'e_data' is read-only"); } /*------------------------------------------------------*/ static void pe_event_postCB(pe_cbframe *fp) { pe_event *ev = fp->ev; pe_watcher *wa = ev->up; --CurCBFrame; if (WaACTIVE(wa) && WaINVOKE1(wa) && WaREPEAT(wa)) pe_watcher_on(wa, 1); if (Estat.on) { if (fp->stats) { Estat.scrub(fp->stats, wa); fp->stats = 0; } if (CurCBFrame >= 0) { pe_cbframe *pfp = CBFrame + CurCBFrame; if (!pfp->stats) pfp->stats = Estat.enter(CurCBFrame, pfp->ev->up->max_cb_tm); else Estat.resume(pfp->stats); } } /* this must be last because it can destroy the watcher */ pe_event_release(ev); } static void pe_callback_died(pe_cbframe *fp) { dSP; STRLEN n_a; pe_watcher *wa = fp->ev->up; SV *eval = perl_get_sv("Event::DIED", 1); SV *err = (sv_true(ERRSV)? sv_mortalcopy(ERRSV): sv_2mortal(newSVpv("?",0))); if (WaDEBUGx(wa) >= 4) warn("Event: '%s' died with: %s\n", SvPV(wa->desc,n_a), SvPV(ERRSV,n_a)); PUSHMARK(SP); XPUSHs(event_2sv(fp->ev)); XPUSHs(err); PUTBACK; perl_call_sv(eval, G_EVAL|G_DISCARD); if (sv_true(ERRSV)) { warn("Event: '%s' died and then $Event::DIED died with: %s\n", SvPV(wa->desc,n_a), SvPV(ERRSV,n_a)); sv_setpv(ERRSV, ""); } } static void _resume_watcher(void *vp) { pe_watcher *wa = (pe_watcher *)vp; pe_watcher_resume(wa); } static void pe_check_recovery() { /* NO ASSERTIONS HERE! EVAL CONTEXT IS VERY MESSY */ int alert; struct pe_cbframe *fp; if (CurCBFrame < 0) return; alert=0; while (CurCBFrame >= 0) { fp = CBFrame + CurCBFrame; if (fp->ev->up->running == fp->run_id) break; if (!alert) { alert=1; /* exception detected; alert the militia! */ pe_callback_died(fp); } pe_event_postCB(fp); } } static void pe_event_invoke(pe_event *ev) { STRLEN n_a; int Dbg; pe_watcher *wa = ev->up; struct pe_cbframe *frp; pe_check_recovery(); /* SETUP */ ENTER; SAVEINT(wa->running); PE_RING_DETACH(&ev->peer); frp = &CBFrame[++CurCBFrame]; frp->ev = ev; frp->run_id = ++wa->running; if (Estat.on) frp->stats = Estat.enter(CurCBFrame, wa->max_cb_tm); assert(ev->prio >= 0 && ev->prio < PE_QUEUES); QueueTime[ev->prio] = wa->cbtime = NVtime(); /* SETUP */ if (CurCBFrame+1 >= MAX_CB_NEST) { ExitLevel = 0; croak("Deep recursion detected; invoking unloop_all()\n"); } Dbg = WaDEBUGx(wa); if (Dbg) { /* SV *cvb = perl_get_sv("Carp::Verbose", 1); if (!SvIV(cvb)) { SAVEIV(SvIVX(cvb)); SvIVX(cvb) = 1; } */ if (Dbg >= 2) warn("Event: [%d]invoking '%s' (prio %d)\n", CurCBFrame, SvPV(wa->desc,n_a),ev->prio); } if (!PE_RING_EMPTY(&Callback)) pe_map_check(&Callback); if (EvPERLCB(ev)) { SV *cb = SvRV((SV*)ev->callback); int pcflags = G_VOID | (SvIVX(Eval)? G_EVAL : 0); int retcnt; SV *evsv = event_2sv(ev); dSP; PUSHMARK(SP); if (SvTYPE(cb) == SVt_PVCV) { XPUSHs(evsv); PUTBACK; retcnt = perl_call_sv((SV*) ev->callback, pcflags); } else { AV *av = (AV*)cb; assert(SvTYPE(cb) == SVt_PVAV); XPUSHs(*av_fetch(av, 0, 0)); XPUSHs(evsv); PUTBACK; retcnt = perl_call_method(SvPV(*av_fetch(av, 1, 0),n_a), pcflags); } SPAGAIN; SP -= retcnt; PUTBACK; if (SvTRUE(ERRSV)) { if (pcflags & G_EVAL) pe_callback_died(frp); else sv_setsv(ERRSV, &PL_sv_no); } } else { assert(ev->callback); (* (void(*)(pe_event*)) ev->callback)(ev); } LEAVE; if (Estat.on) { if (frp->stats) /* maybe in transition */ Estat.commit(frp->stats, wa); frp->stats=0; } if (Dbg >= 3) warn("Event: completed '%s'\n", SvPV(wa->desc, n_a)); pe_event_postCB(frp); } static void boot_pe_event() { pe_event_vtbl *vt; vt = &event_vtbl; vt->new_event = pe_event_allocate; vt->dtor = pe_event_dtor; vt->stash = gv_stashpv("Event::Event", 1); PE_RING_INIT(&vt->freelist, 0); vt = &ioevent_vtbl; memcpy(vt, &event_vtbl, sizeof(pe_event_vtbl)); vt->stash = gv_stashpv("Event::Event::Io", 1); vt->new_event = pe_ioevent_allocate; vt->dtor = pe_ioevent_dtor; PE_RING_INIT(&vt->freelist, 0); vt = &datafulevent_vtbl; memcpy(vt, &event_vtbl, sizeof(pe_event_vtbl)); vt->stash = gv_stashpv("Event::Event::Dataful", 1); vt->new_event = pe_datafulevent_allocate; vt->dtor = pe_datafulevent_dtor; PE_RING_INIT(&vt->freelist, 0); memset(QueueTime, 0, sizeof(QueueTime)); } Event-1.26/c/idle.c0000644000076400007640000000675112357140355012572 0ustar useruserstatic struct pe_watcher_vtbl pe_idle_vtbl; static pe_ring Idle; /*#define D_IDLE(x) x /**/ #define D_IDLE(x) /**/ static pe_watcher *pe_idle_allocate(HV *stash, SV *temple) { pe_idle *ev; EvNew(3, ev, 1, pe_idle); ev->base.vtbl = &pe_idle_vtbl; pe_watcher_init(&ev->base, stash, temple); PE_RING_INIT(&ev->tm.ring, ev); PE_RING_INIT(&ev->iring, ev); ev->max_interval = &PL_sv_undef; ev->min_interval = newSVnv(.01); return (pe_watcher*) ev; } static void pe_idle_dtor(pe_watcher *ev) { pe_idle *ip = (pe_idle*) ev; SvREFCNT_dec(ip->max_interval); SvREFCNT_dec(ip->min_interval); pe_watcher_dtor(ev); EvFree(3, ev); } static char *pe_idle_start(pe_watcher *ev, int repeating) { NV now; NV min,max; pe_idle *ip = (pe_idle*) ev; if (!ev->callback) return "without callback"; if (!repeating) ev->cbtime = NVtime(); now = WaHARD(ev)? ev->cbtime : NVtime(); if (sv_2interval("min", ip->min_interval, &min)) { ip->tm.at = min + now; pe_timeable_start(&ip->tm); D_IDLE(warn("min %.2f setup '%s'\n", min, SvPV(ev->desc,na))); } else { PE_RING_UNSHIFT(&ip->iring, &Idle); D_IDLE(warn("idle '%s'\n", SvPV(ev->desc,na))); if (sv_2interval("max", ip->max_interval, &max)) { D_IDLE(warn("max %.2f setup '%s'\n", max, SvPV(ev->desc,na))); ip->tm.at = max + now; pe_timeable_start(&ip->tm); } } return 0; } static void pe_idle_alarm(pe_watcher *wa, pe_timeable *_ignore) { NV now = NVtime(); NV min,max,left; pe_idle *ip = (pe_idle*) wa; pe_timeable_stop(&ip->tm); if (sv_2interval("min", ip->min_interval, &min)) { left = wa->cbtime + min - now; if (left > IntervalEpsilon) { ++TimeoutTooEarly; ip->tm.at = now + left; pe_timeable_start(&ip->tm); D_IDLE(warn("min %.2f '%s'\n", left, SvPV(wa->desc,na))); return; } } if (PE_RING_EMPTY(&ip->iring)) { PE_RING_UNSHIFT(&ip->iring, &Idle); D_IDLE(warn("idle '%s'\n", SvPV(wa->desc,na))); } if (sv_2interval("max", ip->max_interval, &max)) { left = wa->cbtime + max - now; if (left < IntervalEpsilon) { pe_event *ev; D_IDLE(warn("max '%s'\n", SvPV(wa->desc,na))); PE_RING_DETACH(&ip->iring); ev = (*wa->vtbl->new_event)(wa); ++ev->hits; queueEvent(ev); return; } else { ++TimeoutTooEarly; ip->tm.at = now + left; D_IDLE(warn("max %.2f '%s'\n", left, SvPV(wa->desc,na))); pe_timeable_start(&ip->tm); } } } static void pe_idle_stop(pe_watcher *ev) { pe_idle *ip = (pe_idle*) ev; PE_RING_DETACH(&ip->iring); pe_timeable_stop(&ip->tm); } WKEYMETH(_idle_max_interval) { pe_idle *ip = (pe_idle*) ev; if (nval) { SV *old = ip->max_interval; ip->max_interval = SvREFCNT_inc(nval); if (old) SvREFCNT_dec(old); VERIFYINTERVAL("max", ip->max_interval); } { dSP; XPUSHs(ip->max_interval); PUTBACK; } } WKEYMETH(_idle_min_interval) { pe_idle *ip = (pe_idle*) ev; if (nval) { SV *old = ip->min_interval; ip->min_interval = SvREFCNT_inc(nval); if (old) SvREFCNT_dec(old); VERIFYINTERVAL("min", ip->min_interval); } { dSP; XPUSHs(ip->min_interval); PUTBACK; } } static void boot_idle() { pe_watcher_vtbl *vt = &pe_idle_vtbl; PE_RING_INIT(&Idle, 0); memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl)); vt->dtor = pe_idle_dtor; vt->start = pe_idle_start; vt->stop = pe_idle_stop; vt->alarm = pe_idle_alarm; pe_register_vtbl(vt, gv_stashpv("Event::idle",1), &event_vtbl); } Event-1.26/c/var.c0000644000076400007640000001023012357140355012430 0ustar useruserstatic struct pe_watcher_vtbl pe_var_vtbl; static pe_watcher *pe_var_allocate(HV *stash, SV *temple) { pe_var *ev; EvNew(10, ev, 1, pe_var); ev->base.vtbl = &pe_var_vtbl; pe_watcher_init(&ev->base, stash, temple); ev->variable = &PL_sv_undef; ev->events = PE_W; WaREPEAT_on(ev); WaINVOKE1_off(ev); return (pe_watcher*) ev; } static void pe_var_dtor(pe_watcher *ev) { pe_var *wv = (pe_var *)ev; SvREFCNT_dec(wv->variable); pe_watcher_dtor(ev); EvFree(10, ev); } static void pe_tracevar(pe_watcher *wa, SV *sv, int got) { /* Adapted from tkGlue.c We are a "magic" set processor. So we are (I think) supposed to look at "private" flags and set the public ones if appropriate. e.g. "chop" sets SvPOKp as a hint but not SvPOK presumably other operators set other private bits. Question are successive "magics" called in correct order? i.e. if we are tracing a tied variable should we call some magic list or be careful how we insert ourselves in the list? */ pe_ioevent *ev; if (SvPOKp(sv)) SvPOK_on(sv); if (SvNOKp(sv)) SvNOK_on(sv); if (SvIOKp(sv)) SvIOK_on(sv); ev = (pe_ioevent*) (*wa->vtbl->new_event)(wa); ++ev->base.hits; ev->got |= got; queueEvent((pe_event*) ev); } static I32 tracevar_r(pTHX_ IV ix, SV *sv) { pe_tracevar(INT2PTR(pe_watcher *, ix), sv, PE_R); return 0; /*ignored*/ } static I32 tracevar_w(pTHX_ IV ix, SV *sv) { pe_tracevar(INT2PTR(pe_watcher *, ix), sv, PE_W); return 0; /*ignored*/ } static char *pe_var_start(pe_watcher *_ev, int repeat) { STRLEN n_a; struct ufuncs *ufp; MAGIC **mgp; MAGIC *mg; pe_var *ev = (pe_var*) _ev; SV *sv = ev->variable; if (!_ev->callback) return "without callback"; if (!sv || !SvOK(sv)) return "watching what?"; if (!ev->events) return "without poll events specified"; sv = SvRV(sv); if (SvREADONLY(sv)) return "cannot trace read-only variable"; (void)SvUPGRADE(sv, SVt_PVMG); mgp = &SvMAGIC(sv); while ((mg = *mgp)) { mgp = &mg->mg_moremagic; } EvNew(11, mg, 1, MAGIC); Zero(mg, 1, MAGIC); mg->mg_type = 'U'; mg->mg_virtual = &PL_vtbl_uvar; *mgp = mg; EvNew(8, ufp, 1, struct ufuncs); ufp->uf_val = ev->events & PE_R? tracevar_r : 0; ufp->uf_set = ev->events & PE_W? tracevar_w : 0; ufp->uf_index = PTR2IV(ev); mg->mg_ptr = (char *) ufp; mg->mg_obj = (SV*) ev; mg_magical(sv); if (!SvMAGICAL(sv)) return "mg_magical didn't"; return 0; } static void pe_var_stop(pe_watcher *_ev) { MAGIC **mgp; MAGIC *mg; pe_var *ev = (pe_var*) _ev; SV *sv = SvRV(ev->variable); if (SvTYPE(sv) < SVt_PVMG || !SvMAGIC(sv)) { warn("Var unmagic'd already?"); return; } mgp = &SvMAGIC(sv); while ((mg = *mgp)) { if (mg->mg_type == 'U' && mg->mg_obj == (SV*)ev) break; mgp = &mg->mg_moremagic; } if(!mg) { warn("Couldn't find var magic"); return; } *mgp = mg->mg_moremagic; EvFree(8, mg->mg_ptr); EvFree(11, mg); } static void _var_restart(pe_watcher *ev) { if (!WaPOLLING(ev)) return; pe_watcher_off(ev); pe_watcher_on(ev, 0); } WKEYMETH(_var_events) { pe_var *vp = (pe_var*)ev; if (nval) { vp->events = sv_2events_mask(nval, PE_R|PE_W); _var_restart(ev); } { dSP; XPUSHs(sv_2mortal(events_mask_2sv(vp->events))); PUTBACK; } } WKEYMETH(_var_variable) { pe_var *vp = (pe_var*)ev; if (nval) { SV *old = vp->variable; int active = WaPOLLING(ev); if (SvOK(nval)) { if (!SvROK(nval)) croak("Expecting a reference"); if (SvTYPE(SvRV(nval)) > SVt_PVMG) croak("Var watchers can only watch plain vanilla scalars"); } if (active) pe_watcher_off(ev); vp->variable = SvREFCNT_inc(nval); if (active) pe_watcher_on(ev, 0); SvREFCNT_dec(old); } { dSP; XPUSHs(vp->variable); PUTBACK; } } static void boot_var() { pe_watcher_vtbl *vt = &pe_var_vtbl; memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl)); vt->dtor = pe_var_dtor; vt->start = pe_var_start; vt->stop = pe_var_stop; pe_register_vtbl(vt, gv_stashpv("Event::var",1), &ioevent_vtbl); } Event-1.26/t/0000755000076400007640000000000012727627261011530 5ustar useruserEvent-1.26/t/group.t0000644000076400007640000000057412357140355013050 0ustar useruser#!./perl -w use Test; plan test => 3; use Event; require Event::group; my $gp = Event->group(timeout => 5, cb => \&die); my $undef; eval { $gp->add(\$undef) }; ok $@, '/not a thing/'; eval { $gp->add(\$gp) }; ok $@, '/not a thing/'; eval { $gp->add($gp) }; ok $@, '/itself/'; for (1..10) { $gp->add(Event->timer(after => 5, cb => \&die)); } # need more tests here! XXX Event-1.26/t/signal.t0000644000076400007640000000102412357140355013160 0ustar useruser# signal -*-perl-*- BEGIN { if ($^O eq 'MSWin32') { print "1..0 # skipped; kill() doesn't send signals on Win32\n"; exit; } } use Test; plan tests => 4; use Event qw(loop unloop); #$Event::DebugLevel = 3; my $count = 3; Event->signal( signal => 'USR1', cb => sub { my $e = shift; ok $e->w->signal, 'USR1'; ok $e->hits > 0; # threads can cause signal clumping unloop; } ); my $idle; $idle = Event->idle( cb => sub { kill 'USR1',$$; kill 'USR1',$$; ok 1; } ); loop; ok 1; Event-1.26/t/eval.t0000644000076400007640000000150212357140355012633 0ustar useruser# stop -*-perl-*- ? use Carp;# 'verbose'; use Test; plan tests => 7; use Event qw(all_running loop unloop sweep); # $Event::DebugLevel = 3; my $die = Event->idle(cb => sub { die "died\n" }, desc => 'killer'); my $status = 'ok'; $Event::DIED = sub { my ($e,$why) = @_; ok $e->w->desc, 'killer'; chop $why; ok $why, 'died'; if ($Event::Eval == 0) { $Event::Eval = 1; $die->again } elsif ($Event::Eval == 1) { unloop $status; $Event::Eval = 0; } }; ok loop(), $status; #----------------------------- { local $Event::DIED = sub { die }; local $SIG{__WARN__} = sub { ok $_[0], '/Event::DIED died/'; }; $die->now; sweep(); } { local $Event::DIED = \&Event::verbose_exception_handler; local $SIG{__WARN__} = sub { ok $_[0], '/died/'; }; $die->now; sweep(); } Event-1.26/t/io.t0000644000076400007640000000427212357140355012322 0ustar useruser# -*-perl-*- i/o use Config; BEGIN { if ($^O eq 'MSWin32') { print "1..0 # skipped; Win32 supports select() only on sockets\n"; exit; } } use Test; plan tests => 8; use Event qw(loop unloop); use Event::Watcher qw(R W); use Symbol; #$Event::DebugLevel = 3; eval { Event->io }; ok $@, "/nothing to watch/"; eval { Event->io(fd => \*STDIN, cb => \&die, poll => 0) }; ok $@, "/nothing to watch/"; my $cannot_detect_bogus_fd; if ($Config{osname} eq 'darwin' or $Config{osname} eq 'gnu' or $Config{archname} =~ m/^armv5tejl/) { # GNU/Hurd's poll returns with -EBADF which is accurate # but we cannot determine which fd is bad. $cannot_detect_bogus_fd = 'Cannot detect bogus file descriptors'; } my $noticed_bogus_fd=0; my $bogus_timeout=0; my $bogus; if (!$cannot_detect_bogus_fd) { $bogus = Event->io(desc => 'oops', poll => 'r', fd => 123, timeout => .1, cb => sub { ++$bogus_timeout; }); } $SIG{__WARN__} = sub { my $is_it = $_[0] =~ m/\'oops\' was unexpectedly/; if ($is_it) { ++$noticed_bogus_fd; } else { warn $_[0] } }; sub new_pipe { my ($cnt) = @_; my ($r,$w) = (gensym, gensym); pipe($r,$w); Event->io(desc => "r", poll => 'r', fd => $r, cb => sub { my $e = shift; my $w=$e->w; if ($e->got & R) { my $buf; my $got = sysread $w->fd, $buf, 1; die "sysread: $!" if !defined $got; die "sysread: pipe closed?" if $got == 0; ++$$cnt; } }); Event->io(desc => 'w', poll => 'w', fd => $w, cb => sub { my $e = shift; my $w=$e->w; if ($e->got & W) { my $got = syswrite $w->fd, '.', 1; die "syswrite: $!" if !defined $got; die "syswrite: pipe closed?" if $got == 0; } }); } my $count = 0; new_pipe(\$count); my $hit=0; my $once = Event->io(timeout => .01, repeat => 0, cb => sub { ++$hit }); Event->io(timeout => 2, repeat => 0, cb => sub { ok $count > 0; ok $hit, 1; ok $once->timeout, 0; unloop; }); loop(); skip $cannot_detect_bogus_fd, $noticed_bogus_fd, 1; skip $cannot_detect_bogus_fd, $bogus && !defined $bogus->fd; skip $cannot_detect_bogus_fd, $bogus_timeout > 0; Event-1.26/t/hook.t0000644000076400007640000000053012357140355012644 0ustar useruser# hook -*-perl-*- use strict; use Test; plan test => 4; use Event qw(sweep sleep); my ($p,$c,$ac,$cb) = (0)x4; Event::add_hooks(prepare => sub { ++$p }, check => sub { ++$c }, asynccheck => sub { ++$ac }, callback => sub { ++$cb }); Event->timer(after => 0, cb => sub {}); sleep .5; sweep(); ok $p,1; ok $c,1; ok $ac,1; ok $cb,1; Event-1.26/t/idle.t0000644000076400007640000000135212357140355012624 0ustar useruser# idle daydreams of -*-perl-*- use Test; plan tests => 4; use Event qw(loop unloop); # $Event::Eval = 1; #$Event::DebugLevel = 0; package myobj; use Test; my $myobj; sub idle { my ($o,$e) = @_; if (!$myobj) { # see if method callbacks work ok $o, 'myobj'; ok $e->w->desc, __PACKAGE__; } ++$myobj; } Event->idle(cb => [__PACKAGE__,'idle'], desc => __PACKAGE__); package main; my $count=0; my $idle = Event->idle(desc => "exit", cb => sub { my $e = shift; ++$count; unloop() if $count > 2 && $myobj; }); ok ref($idle), 'Event::idle'; Event->idle(cb => sub { ok 0; Event->exit })->cancel; Event->idle(cb => sub { $idle->again }, repeat => 1, desc => "again"); ok !defined loop(); Event-1.26/t/leak.t0000644000076400007640000000122212357140355012617 0ustar useruser# leak -*-perl-*- use Test; plan test => 6; use Event qw(all_watchers); my @e = Event::all_watchers(); ok @e, 0; @e = Event::all_idle(); ok @e, 0; sub thrash { Event->idle(parked=>1)->cancel; Event->io(parked => 1)->cancel; Event->signal(parked=>1)->cancel; Event->timer(parked=>1)->cancel; my $var = 1; Event->var(parked=>1)->cancel; } for (1..2) { thrash(); } my $got = join(', ', map { ref } all_watchers()) || 'None'; ok($got, 'None'); { my $io = Event->io(parked => 1); ok !$io->is_cancelled; $io->cancel for 1..3; #shouldn't crash! ok $io->is_cancelled; eval { $io->start }; ok $@, '/cancelled/'; } Event-1.26/t/delete.t0000644000076400007640000000043312357140355013150 0ustar useruser#!./perl -w use strict; use Test; plan tests => 1; use Event 0.40 qw(loop unloop); package Foo; my $foo=0; sub DESTROY { ++$foo } package main; my $e = Event->timer(after => 0, cb => sub { delete shift->w->{foo}; unloop }); $e->{foo} = bless [], 'Foo'; loop(); ok $foo; Event-1.26/t/callback.t0000644000076400007640000000154012357140355013442 0ustar useruser#!./perl -w use strict; use Test; plan tests => 6; use Event 0.65; my $invoked_method=0; sub method { ++$invoked_method; } my $main = bless []; Event->timer(after => 0, cb => \&method); Event->timer(after => 0, cb => ['main', 'method']); Event->timer(after => 0, cb => [$main, 'method']); { local $SIG{__WARN__} = sub { ok $_[0], '/nomethod/'; }; Event->timer(desc => 'nomethod', after => 0, cb => [$main, 'nomethod']); } eval { Event->timer(after => 0, cb => ['main']); }; ok $@, '/Callback/'; { local $Event::DIED = sub { my ($run,$err) = @_; ok $run->w->desc, 'nomethod'; ok $err, '/object method/'; }; local $SIG{__WARN__} = sub {}; Event::loop(); } { my $warn=''; local $SIG{__WARN__} = sub { $warn .= $_[0]; }; Event::loop(); ok $warn, '/loop without active watchers/'; } ok $invoked_method, 3; Event-1.26/t/bored.t0000644000076400007640000000063212357140355013002 0ustar useruser# -*- perl -*- use Test; plan test => 5; use Event; # $Event::DebugLevel = 3; my $really_bored; my $w; $w = Event->timer(after => .5, parked => 1); ok !defined $w->cb; eval { $w->now() }; ok $@ =~ /callback unset/; $w->cb(sub { if (!$really_bored) { $w->again; $really_bored='yes'; } else { ok 1; } }); ok ref $w->cb, 'CODE'; $w->start; ok !defined Event::loop(); Event-1.26/t/reenter.t0000644000076400007640000000155512357140355013360 0ustar useruser# deep -*- perl -*- BEGIN { if ($^O eq 'MSWin32') { print "1..0 # skipped; Win32 supports select() only on sockets\n"; exit; } } use Test; plan test => 7; use Event qw(loop unloop one_event all_running); #$Event::DebugLevel = 4; # deep recursion my $rep; $rep = Event->io(fd => \*STDOUT, poll => 'w', cb => sub { loop() }); do { local $SIG{__WARN__} = sub {}; # COMMENT OUT WHEN DEBUGGING! ok !defined loop(); }; ok $rep->is_running, 0; # simple nested case my $nest=0; $rep->cb(sub { return if ++$nest > 10; one_event(); }); ok one_event(); # a bit more complex nested exception $nest=0; $rep->cb(sub { die 10 if ++$nest > 10; one_event() or die "not recursing"; }); $Event::DIED = sub { my $e = shift; ok $e->w, $rep; ok $e->w, all_running(); my @all = all_running; ok @all, $nest; unloop(); }; loop(); ok 1; Event-1.26/t/now.t0000644000076400007640000000124412357140355012512 0ustar useruser# -*-perl-*- ASAP use Test; plan tests => 13; use Event qw(loop unloop); # $Event::DebugLevel = 3; my $c=0; Event->idle(repeat => 1, cb => sub { ++$c; unloop if $c >= 2; }) ->now; my $tm = Event->timer(after => 10, cb => sub { ok 1 }); ok !$tm->pending; $tm->stop; $tm->now; ok $tm->pending; my @e = $tm->pending; ok @e, 1; ok ref $e[0], 'Event::Event'; ok $e[0]->hits; ok $e[0]->w, $tm; $tm->prio($tm->prio + 1); $tm->now; $tm->prio($tm->prio - 1); $tm->now; $tm->now; @e = $tm->pending; # in order of occurance (FIFO) ok join('', map { $_->prio } @e), join('', $tm->prio, $tm->prio+1, $tm->prio, $tm->prio); loop; ok $c, 2; ok $tm->cbtime; Event-1.26/t/data.t0000644000076400007640000000045312357140355012621 0ustar useruser#!./perl -w use Test; plan tests => 8; use Event; my $w = Event->idle(parked => 1, data => 'data'); ok $w->data, 'data'; ok !$w->private; ok $w->private(1); ok $w->private; package Grapes; use Test; ok $w->data, 'data'; ok !$w->private; ok $w->private(2), 2; package main; ok $w->private, 1; Event-1.26/t/timeout_cb.t0000644000076400007640000000075212357140355014044 0ustar useruser# -*-perl-*- use Test; plan tests => 6; use Event qw(loop); sub step1 { my ($e) = @_; ok $e->got, 't'; $e->w->timeout_cb(undef); } sub step2 { my ($e) = @_; ok $e->got, 't'; $e->w->cancel; } Event->io(timeout => .1, timeout_cb => \&step1, cb => \&step2); sub method { step1($_[1]); } Event->io(timeout => .1, timeout_cb => ['main','method'], cb => \&step2); Event->io(timeout => .1, timeout_cb => [bless([],'main'),'method'], cb => \&step2); loop; Event-1.26/t/unconfigured.t0000644000076400007640000000067612357140355014407 0ustar useruser#!./perl -w use strict; use Test; plan test => 6; use Event; my @p = (cb=>\&die); eval { Event->io(@p) }; ok $@, '/unconfigured/'; eval { Event->signal(@p) }; ok $@, '/without signal/'; eval { Event->timer(@p) }; ok $@, '/unset/'; eval { Event->var(@p) }; ok $@, '/watching what/'; my $var = 1; eval { Event->var(@p, poll => 0, var => \$var) }; ok $@, '/without poll events/'; eval { Event->var(@p, var => \$]) }; ok $@, '/read\-only/'; Event-1.26/t/generic.t0000644000076400007640000000125712357140355013327 0ustar useruser#!./perl -w use Test; plan test => 10; use Event; require Event::generic; my $src = Event::generic::Source->new; ok $src; my $w0 = Event->generic(parked => 1); ok $w0; eval { $w0->source(undef); }; ok $@, ""; eval { $w0->source($src); }; ok $@, ""; eval { $w0->source(123); }; ok $@, qr/not a reference/; eval { $w0->source(\123); }; ok $@, qr/not a thing/; eval { $w0->source($w0); }; ok $@, qr/Can't find event magic/; sub second_cb($) { my($e) = @_; ok $e->data, 456; $e->w->stop; } $w0->cb(sub($) { my($e) = @_; ok $e->data, 123; Event->generic(source => $src, cb => \&second_cb); $e->w->cb(\&second_cb); $src->event(456); }); $w0->start; $src->event(123); Event::loop; Event-1.26/t/fifo.t0000644000076400007640000000114412357140355012631 0ustar useruser#!./perl -w # check FIFO dispatch of equal priority events use Test; plan test => 1; use Event; my @hit; sub cb { my ($e) = @_; push @hit, $e->w->desc; } my $t1 = Event->timer(desc => 1, after => 10, cb => \&cb); my $t2 = Event->timer(desc => 2, after => 10, cb => \&cb); my $t3 = Event->timer(desc => 3, after => 10, cb => \&cb); my $h4 = Event->timer(desc => 4, nice => -1, after => 10, cb => \&cb); my $h5 = Event->timer(desc => 5, nice => -1, after => 10, cb => \&cb); $t2->now; $h4->now; $t1->now; $t1->now; $t3->now; $h5->now; $t2->now; $t1->now; Event::loop(); ok join('', @hit), '45211321'; Event-1.26/t/var.t0000644000076400007640000000144012357140355012475 0ustar useruser# watch -*-perl-*- use strict; use Test; plan test => 6; use Event qw(loop unloop); # $Event::DebugLevel = 2; my $var1 = 1; my $var2 = 3; my $var3 = 0; Event->var(var => \$var1, cb => sub { my $var = shift->w->var; ok $$var, 2; $var2++; }, desc => "var1" ); Event->var(var => \$var1, cb => sub { ok $var1, 2 }); Event->var(var => \$var2, cb => sub { $var3 = 3; ok $var2, 4; unloop; }, desc => "var2"); Event->var(var => \$var3, async => 1, cb => sub { ok $var3, 3; }); Event->idle(cb => sub { ok $var1, 1; $var1++; }); my $var4 = 0; my $e = Event->var(poll => 'r', var => \$var4, cb => sub { my $e = shift; ok $e->hits, 1; }); my $str = "$var4"; #read $var4 = 5; #write loop; Event-1.26/t/hup.t0000644000076400007640000000125612357140355012506 0ustar useruser#!./perl -w BEGIN { if ($^O eq 'MSWin32') { print "1..0 # skipped; Win32 is too strange\n"; exit; } } # contributed by Gisle Aas use Test; plan test => 1; use Event qw(loop unloop); $| = 1; my $pid = open(PIPE, "-|"); die unless defined $pid; unless ($pid) { # child for (1..100) { print "."; } print "\n"; exit; } my $bytes = 0; Event->io(poll => "r", fd => \*PIPE, cb => sub { my $e = shift; my $buf; my $n = sysread(PIPE, $buf, 10); $bytes += $n; #print "Got $n bytes\n"; unloop() unless $n; }); loop(); ok $bytes, 101; Event-1.26/t/loop.t0000644000076400007640000000122312357140355012655 0ustar useruser# -*-perl-*- use strict; use Test; plan tests => 3; use Event qw(loop unloop); # kill 2, $$; # $Event::DebugLevel = 4; my %got; my $sleep = 1; use vars qw($sleeping); $sleeping=0; my $early = Event->idle(desc => 'early', repeat => 1, cb => sub { return if !$sleeping; unloop 'early'; }); Event->idle(desc => "main", repeat => 1, reentrant => 0, cb => sub { my $e = shift; local $sleeping = 1; my $ret = loop($sleep); if (!exists $got{$ret}) { $got{$ret} = 1; if ($ret eq 'early') { $early->cancel; ok 1; } elsif ($ret == $sleep) { ok 1; } } unloop(0) if keys %got == 2; }); ok loop, 0; Event-1.26/t/leak2.t0000644000076400007640000000204612357140355012706 0ustar useruser#!./perl -w # # Test script to check the memory consumption # of an Event loop which installs, handles and # cancels a number of IO watchers (recursively). # # For extra diagnostics, Event.pm can be built with # -DEVENT_MEMORY_DEBUG. # # If the script succeeds, the final memory check # replies something like this: # "1-29509-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0" # (all slots except of the first two ones should # be 0 - the second number may differ). # # J. Stenzel (perl@jochen-stenzel.de) # use Test; plan test => 2; use Event; # $Event::DebugLevel = 3; sub check {warn "[DBG] ", join('-', Event::_memory_counters), "\n";} sub iosub { for (my $l=0; $l<=5; $l++) { Event->io( fh => \*STDIO, timeout => "0.5$l", repeat => 1, cb => \&iosub, prio => 5); } $_[0]->w->cancel; } Event->io(fh => \*STDIO, timeout => 0.5, repeat => 1, cb => \&iosub, prio => 5); Event->timer(prio => 1, after => 3, cb => sub { $_->cancel foreach Event::all_watchers; ok !defined Event::all_watchers; } ); Event::loop(); ok 1; Event-1.26/t/timer.t0000644000076400007640000000212612357140355013027 0ustar useruser# the time for -*-perl-*- use Test; plan tests => 7; use Event qw(loop unloop); # $Event::DebugLevel = 3; #if (0) { my $count = 0; Event->timer(after => 0.5, interval => .1, nice => -1, cb => sub { ++$count }, desc => "counter"); my $when = time + 2; Event->timer(at => $when, cb => sub { ok $when, $_[0]->w->at; }, desc => "at"); my $again; Event->timer(after => .5, cb => sub { my $o=shift; ok 1; if (!$again) { $again=1; $o->w->again; $o->w->again; #should be harmless } }, desc => "after"); my $ok = Event->timer(interval => .5, cb => sub { unloop('ok') if $count > 30 }, desc => "exit"); ok abs($ok->at - time) < 3, 1, "diff was ".($ok->at - time); my $long; for (1..10) { $long = Event->timer(after => 60+rand(60), cb => sub { ok 0; }); } $long->cb(sub { ok 1 }); $long->at(time); ok loop(), 'ok'; $_->cancel for Event::all_watchers(); #} my $depth=0; Event->timer(interval => .01, cb => sub { if (++$depth < 2) { loop(); } else { Event::unloop_all('reentrant'); } }); ok loop(), 'reentrant'; Event-1.26/t/attach_to.t0000644000076400007640000000046212357140355013656 0ustar useruser#!./perl -w use strict; use Test; plan tests => 3; use Event 0.53; # $Event::DebugLevel = 3; my $array = Event->timer(attach_to => [0,1,2], after => 1, cb => \&die); ok $array->[2], 2; ok $array->interval, 1; eval { Event->timer(attach_to => bless([]), after => 1, cb => \&die); }; ok $@, '/blessed/'; Event-1.26/Event.xs0000644000076400007640000004616712725135327012733 0ustar useruser/* -*- C -*- sometimes */ #define MIN_PERL_DEFINE 1 #ifdef __cplusplus extern "C" { #endif #include #include #include #ifdef __cplusplus } #endif #include "ppport.h" /* lexical warnings -- waiting for appropriate magic from paul.marquess@bt.com */ #if 0 static void Event_warn(const char* pat, ...) { dTHX; va_list args; va_start(args, pat); if (!ckWARN_d(WARN_ALL)) return; Perl_vwarner(aTHX_ WARN_ALL, pat, &args); va_end(args); } # undef warn # define warn Event_warn #endif #if 1 #ifdef warn # undef warn #endif #define warn Event_warn static void Event_warn(const char* pat, ...) { STRLEN n_a; dSP; SV *msg; va_list args; /* perl_require_pv("Carp.pm"); Couldn't possibly be unloaded.*/ va_start(args, pat); msg = sv_newmortal(); sv_vsetpvfn(msg, pat, strlen(pat), &args, Null(SV**), 0, 0); va_end(args); SvREADONLY_on(msg); PUSHMARK(SP); XPUSHs(msg); PUTBACK; perl_call_pv("Carp::carp", G_DISCARD); } #endif #ifdef croak # undef croak #endif #define croak Event_croak static void Event_croak(const char* pat, ...) { STRLEN n_a; dSP; SV *msg; va_list args; /* perl_require_pv("Carp.pm"); Couldn't possibly be unloaded.*/ va_start(args, pat); msg = sv_newmortal(); sv_vsetpvfn(msg, pat, strlen(pat), &args, Null(SV**), 0, 0); va_end(args); SvREADONLY_on(msg); PUSHMARK(SP); XPUSHs(msg); PUTBACK; perl_call_pv("Carp::croak", G_DISCARD); PerlIO_puts(PerlIO_stderr(), "panic: Carp::croak failed\n"); (void)PerlIO_flush(PerlIO_stderr()); my_failure_exit(); } #ifdef WIN32 # include #endif #if defined(HAS_POLL) # include /* Many operating systems claim to support poll yet they actually emulate it with select. c/unix.c supports either poll or select but it doesn't know which one to use. Here we try to detect if we have a native poll implementation. If we do, we use it. Otherwise, select is assumed. */ # ifndef POLLOUT # undef HAS_POLL # endif # ifndef POLLWRNORM # undef HAS_POLL # endif # ifndef POLLWRBAND # undef HAS_POLL # endif #endif /* Is time() portable everywhere? Hope so! XXX */ static NV fallback_NVtime() { return time(0); } #include "Event.h" /* The following is for very simplistic memory leak detection. */ #define MAX_MEMORYCOUNT 20 static int MemoryCount[MAX_MEMORYCOUNT]; static void dbg_count_memory(int id, int cnt) { assert(id >= 0 && id < MAX_MEMORYCOUNT); MemoryCount[id] += cnt; } #if EVENT_MEMORY_DEBUG # define EvNew(id, ptr, size, type) dbg_count_memory(id,1); New(0,ptr,size,type) # define EvFree(id, ptr) STMT_START { dbg_count_memory(id,-1); safefree(ptr); } STMT_END #else # define EvNew(x, ptr, size, type) New(0,ptr,size,type) # define EvFree(id, ptr) safefree(ptr) #endif static int LoopLevel, ExitLevel; static int ActiveWatchers=0; /* includes WaACTIVE + queued events */ static int WarnCounter=16; /*XXX nuke */ static SV *DebugLevel; static SV *Eval; static pe_event_stats_vtbl Estat; /* IntervalEpsilon should be equal to the clock's sleep resolution (poll or select) times two. It probably needs to be bigger if you turn on lots of debugging? Can determine this dynamically? XXX */ static NV IntervalEpsilon = 0.0002; static int TimeoutTooEarly=0; static struct EventAPI api; #define NVtime() (*api.NVtime)() static int pe_sys_fileno(SV *sv, char *context); static void queueEvent(pe_event *ev); static void dequeEvent(pe_event *ev); static void pe_watcher_cancel(pe_watcher *ev); static void pe_watcher_suspend(pe_watcher *ev); static void pe_watcher_resume(pe_watcher *ev); static void pe_watcher_now(pe_watcher *ev); static void pe_watcher_start(pe_watcher *ev, int repeat); static void pe_watcher_stop(pe_watcher *ev, int cancel_events); static char*pe_watcher_on(pe_watcher *wa, int repeat); static void pe_watcher_off(pe_watcher *wa); /* The newHVhv in perl seems to mysteriously break in some cases. Here is a simple and safe (but maybe slow) implementation. */ #ifdef newHVhv # undef newHVhv #endif #define newHVhv event_newHVhv static HV *event_newHVhv(HV *ohv) { register HV *hv = newHV(); register HE *entry; hv_iterinit(ohv); /* NOTE: this resets the iterator */ while (entry = hv_iternext(ohv)) { hv_store(hv, HeKEY(entry), HeKLEN(entry), SvREFCNT_inc(HeVAL(entry)), HeHASH(entry)); } return hv; } static void pe_watcher_STORE_FALLBACK(pe_watcher *wa, SV *svkey, SV *nval) { if (!wa->FALLBACK) wa->FALLBACK = newHV(); hv_store_ent(wa->FALLBACK, svkey, SvREFCNT_inc(nval), 0); } /***************** STATS */ static int StatsInstalled=0; static void pe_install_stats(pe_event_stats_vtbl *esvtbl) { ++StatsInstalled; Copy(esvtbl, &Estat, 1, pe_event_stats_vtbl); Estat.on=0; } static void pe_collect_stats(int yes) { if (!StatsInstalled) croak("collect_stats: no event statistics are available"); Estat.on = yes; } #ifdef HAS_GETTIMEOFDAY NV null_loops_per_second(int sec) { /* This should be more realistic. It is used to normalize the benchmark against some theoretical perfect event loop. */ struct timeval start_tm, done_tm; NV elapse; unsigned count=0; int fds[2]; if (pipe(fds) != 0) croak("pipe"); gettimeofday(&start_tm, 0); do { #ifdef HAS_POLL struct pollfd map[2]; Zero(map, 2, struct pollfd); map[0].fd = fds[0]; map[0].events = POLLIN | POLLOUT; map[0].revents = 0; map[1].fd = fds[1]; map[1].events = POLLIN | POLLOUT; map[1].revents = 0; poll(map, 2, 0); #elif defined(HAS_SELECT) struct timeval null; fd_set rfds, wfds, efds; FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); FD_SET(fds[0], &rfds); FD_SET(fds[0], &wfds); FD_SET(fds[1], &rfds); FD_SET(fds[1], &wfds); null.tv_sec = 0; null.tv_usec = 0; select(3,&rfds,&wfds,&efds,&null); #else # error #endif ++count; gettimeofday(&done_tm, 0); elapse = (done_tm.tv_sec - start_tm.tv_sec + (done_tm.tv_usec - start_tm.tv_usec) / 1000000); } while(elapse < sec); close(fds[0]); close(fds[1]); return count/sec; } #else /* !HAS_GETTIMEOFDAY */ NV null_loops_per_second(int sec) { croak("sorry, gettimeofday is not available"); } #endif #include "typemap.c" #include "timeable.c" #include "hook.c" #include "ev.c" #include "watcher.c" #include "idle.c" #include "timer.c" #include "io.c" #include "unix.c" #include "var.c" #include "signal.c" #include "tied.c" #include "group.c" #include "generic.c" #include "queue.c" MODULE = Event PACKAGE = Event PROTOTYPES: DISABLE BOOT: LoopLevel = ExitLevel = 0; DebugLevel = SvREFCNT_inc(perl_get_sv("Event::DebugLevel", 1)); Eval = SvREFCNT_inc(perl_get_sv("Event::Eval", 1)); Estat.on=0; boot_timeable(); boot_hook(); boot_pe_event(); boot_pe_watcher(); boot_idle(); boot_timer(); boot_io(); boot_devpoll(); boot_var(); boot_tied(); boot_signal(); boot_group(); boot_generic(); boot_queue(); { SV *apisv; api.Ver = EventAPI_VERSION; api.start = pe_watcher_start; api.queue = queueEvent; api.now = pe_watcher_now; api.suspend = pe_watcher_suspend; api.resume = pe_watcher_resume; api.stop = pe_watcher_stop; api.cancel = pe_watcher_cancel; api.tstart = pe_timeable_start; api.tstop = pe_timeable_stop; api.NVtime = fallback_NVtime; api.new_idle = (pe_idle* (*)(HV*,SV*)) pe_idle_allocate; api.new_timer = (pe_timer* (*)(HV*,SV*)) pe_timer_allocate; api.new_io = (pe_io* (*)(HV*,SV*)) pe_io_allocate; api.new_var = (pe_var* (*)(HV*,SV*)) pe_var_allocate; api.new_signal = (pe_signal*(*)(HV*,SV*)) pe_signal_allocate; api.add_hook = capi_add_hook; api.cancel_hook = pe_cancel_hook; api.install_stats = pe_install_stats; api.collect_stats = pe_collect_stats; api.AllWatchers = &AllWatchers; api.watcher_2sv = watcher_2sv; api.sv_2watcher = sv_2watcher; api.event_2sv = event_2sv; api.sv_2event = sv_2event; api.unloop = pe_unloop; api.unloop_all = pe_unloop_all; api.sv_2interval = sv_2interval; api.events_mask_2sv = events_mask_2sv; api.sv_2events_mask = sv_2events_mask; apisv = perl_get_sv("Event::API", 1); sv_setiv(apisv, (IV)&api); SvREADONLY_on(apisv); } void _add_hook(type, code) char *type SV *code CODE: pe_add_hook(type, 1, code, 0); /* would be nice to return new pe_qcallback* XXX */ int _timeout_too_early() CODE: RETVAL = TimeoutTooEarly; TimeoutTooEarly=0; OUTPUT: RETVAL void _memory_counters() PPCODE: { #ifdef EVENT_MEMORY_DEBUG int xx; for (xx=0; xx < MAX_MEMORYCOUNT; xx++) XPUSHs(sv_2mortal(newSViv(MemoryCount[xx]))); #endif } void _incr_looplevel() PPCODE: ++LoopLevel; ++ExitLevel; void _decr_looplevel() PPCODE: --LoopLevel; void unloop(...) CODE: pe_unloop(items? ST(0) : &PL_sv_undef); void unloop_all(...) CODE: pe_unloop_all(items? ST(0) : &PL_sv_undef); bool cache_time_api() CODE: SV **svp = hv_fetch(PL_modglobal, "Time::NVtime", 12, 0); if (!svp || !*svp || !SvIOK(*svp)) XSRETURN_NO; api.NVtime = INT2PTR(NV(*)(), SvIV(*svp)); XSRETURN_YES; NV time() PROTOTYPE: CODE: RETVAL = NVtime(); OUTPUT: RETVAL void sleep(tm) NV tm; PROTOTYPE: $ CODE: pe_sys_sleep(tm); NV null_loops_per_second(sec) int sec void all_watchers() PROTOTYPE: PPCODE: pe_watcher *ev; if (!AllWatchers.next) return; ev = (pe_watcher*) AllWatchers.next->self; while (ev) { XPUSHs(watcher_2sv(ev)); ev = (pe_watcher*) ev->all.next->self; } void all_idle() PROTOTYPE: PPCODE: pe_watcher *ev; if (!Idle.prev) return; ev = (pe_watcher*) Idle.prev->self; while (ev) { XPUSHs(watcher_2sv(ev)); ev = (pe_watcher*) ((pe_idle*)ev)->iring.prev->self; } void all_running() PROTOTYPE: PPCODE: int fx; for (fx = CurCBFrame; fx >= 0; fx--) { pe_watcher *ev = (CBFrame + fx)->ev->up; /* XXX */ XPUSHs(watcher_2sv(ev)); if (GIMME_V != G_ARRAY) break; } void queue(...) PROTOTYPE: $;$ PREINIT: pe_watcher *wa; pe_event *ev; PPCODE: wa = (pe_watcher*) sv_2watcher(ST(0)); if (items == 1) { ev = (*wa->vtbl->new_event)(wa); ++ev->hits; } else if (items == 2) { if (SvNIOK(ST(1))) { ev = (*wa->vtbl->new_event)(wa); ev->hits += SvIV(ST(1)); } else { ev = (pe_event*) sv_2event(ST(1)); if (ev->up != wa) croak("queue: event doesn't match watcher"); } } queueEvent(ev); int one_event(...) PROTOTYPE: ;$ CODE: NV maxtm = 60; if (items == 1) maxtm = SvNV(ST(0)); RETVAL = safe_one_event(maxtm); OUTPUT: RETVAL void _loop() CODE: pe_check_recovery(); pe_reentry(); if (!ActiveWatchers) warn("Event: loop without active watchers"); while (ExitLevel >= LoopLevel && ActiveWatchers) { ENTER; SAVETMPS; one_event(60); FREETMPS; LEAVE; } LEAVE; /* reentry */ void queue_pending() CODE: pe_queue_pending(); int _empty_queue(prio) int prio CODE: pe_check_recovery(); pe_reentry(); while (pe_empty_queue(prio)); LEAVE; /* reentry */ void queue_time(prio) int prio PPCODE: NV max=0; int xx; if (prio < 0 || prio >= PE_QUEUES) croak("queue_time(%d) out of domain [0..%d]", prio, PE_QUEUES-1); for (xx=0; xx <= prio; xx++) if (max < QueueTime[xx]) max = QueueTime[xx]; XPUSHs(max? sv_2mortal(newSVnv(max)) : &PL_sv_undef); MODULE = Event PACKAGE = Event::Event::Io void pe_event::got() PPCODE: XPUSHs(sv_2mortal(events_mask_2sv(((pe_ioevent*)THIS)->got))); MODULE = Event PACKAGE = Event::Event::Dataful void pe_event::data() PPCODE: XPUSHs(((pe_datafulevent*)THIS)->data); MODULE = Event PACKAGE = Event::Event void DESTROY(ref) SV *ref; CODE: { pe_event *THIS = (pe_event*) sv_2event(ref); if (WaDEBUGx(THIS) >= 3) { STRLEN n_a; warn("Event=0x%x '%s' DESTROY SV=0x%x", THIS, SvPV(THIS->up->desc, n_a), THIS->mysv? SvRV(THIS->mysv) : 0); } (*THIS->vtbl->dtor)(THIS); } void pe_event::mom() PPCODE: if (--WarnCounter >= 0) warn("'mom' renamed to 'w'"); XPUSHs(watcher_2sv(THIS->up)); void pe_event::w() PPCODE: XPUSHs(watcher_2sv(THIS->up)); void pe_event::hits() PPCODE: XPUSHs(sv_2mortal(newSViv(THIS->hits))); void pe_event::prio() PPCODE: XPUSHs(sv_2mortal(newSViv(THIS->prio))); MODULE = Event PACKAGE = Event::Watcher void DESTROY(ref) SV *ref; CODE: { pe_watcher *THIS = (pe_watcher*) sv_2watcher(ref); assert(THIS); if (THIS->mysv) { THIS->mysv=0; if (WaCANDESTROY(THIS)) /*mysv*/ (*THIS->vtbl->dtor)(THIS); } } void pe_watcher::pending() PPCODE: { if (GIMME_V == G_ARRAY) { pe_event *ev = (pe_event *) THIS->events.prev->self; while (ev) { XPUSHs(event_2sv(ev)); ev = (pe_event*) ev->peer.prev->self; } } else { XPUSHs(THIS->events.next->self? &PL_sv_yes : &PL_sv_no); } } void pe_watcher::again() CODE: pe_watcher_start(THIS, 1); void pe_watcher::start() CODE: pe_watcher_start(THIS, 0); void pe_watcher::suspend(...) CODE: if (items == 2) { if (sv_true(ST(1))) pe_watcher_suspend(THIS); else pe_watcher_resume(THIS); } else { warn("Ambiguous use of suspend"); /*XXX*/ pe_watcher_suspend(THIS); XSRETURN_YES; } void pe_watcher::resume() CODE: warn("Please use $w->suspend(0) instead of resume"); /* DEPRECATED */ pe_watcher_resume(THIS); void pe_watcher::stop() CODE: pe_watcher_stop(THIS, 1); void pe_watcher::cancel() CODE: pe_watcher_cancel(THIS); void pe_watcher::now() CODE: pe_watcher_now(THIS); void pe_watcher::use_keys(...) PREINIT: PPCODE: warn("use_keys is deprecated"); void pe_watcher::is_running(...) PPCODE: XPUSHs(sv_2mortal(newSViv(THIS->running))); void pe_watcher::is_active(...) PPCODE: PUTBACK; XPUSHs(boolSV(WaACTIVE(THIS))); void pe_watcher::is_suspended(...) PPCODE: PUTBACK; XPUSHs(boolSV(WaSUSPEND(THIS))); void pe_watcher::is_cancelled(...) PPCODE: PUTBACK; XPUSHs(boolSV(WaCANCELLED(THIS))); void pe_watcher::cb(...) PPCODE: PUTBACK; _watcher_callback(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::cbtime(...) PPCODE: PUTBACK; _watcher_cbtime(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::desc(...) PPCODE: PUTBACK; _watcher_desc(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::debug(...) PPCODE: PUTBACK; _watcher_debug(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::prio(...) PPCODE: PUTBACK; _watcher_priority(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::reentrant(...) PPCODE: PUTBACK; _watcher_reentrant(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::repeat(...) PPCODE: PUTBACK; _watcher_repeat(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::max_cb_tm(...) PPCODE: PUTBACK; _watcher_max_cb_tm(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; MODULE = Event PACKAGE = Event::Watcher::Tied void allocate(clname, temple) SV *clname SV *temple PPCODE: if (!SvROK(temple)) croak("Bad template"); XPUSHs(watcher_2sv(pe_tied_allocate(gv_stashsv(clname, 1), SvRV(temple)))); void pe_watcher::hard(...) PPCODE: PUTBACK; _timeable_hard(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::at(...) PPCODE: PUTBACK; _tied_at(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::flags(...) PPCODE: PUTBACK; _tied_flags(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; MODULE = Event PACKAGE = Event::idle void allocate(clname, temple) SV *clname; SV *temple; PPCODE: if (!SvROK(temple)) croak("Bad template"); XPUSHs(watcher_2sv(pe_idle_allocate(gv_stashsv(clname, 1), SvRV(temple)))); void pe_watcher::hard(...) PPCODE: PUTBACK; _timeable_hard(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::max(...) PPCODE: PUTBACK; _idle_max_interval(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::min(...) PPCODE: PUTBACK; _idle_min_interval(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; MODULE = Event PACKAGE = Event::timer void allocate(clname, temple) SV *clname; SV *temple; PPCODE: XPUSHs(watcher_2sv(pe_timer_allocate(gv_stashsv(clname, 1), SvRV(temple)))); void pe_watcher::at(...) PPCODE: PUTBACK; _timer_at(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::hard(...) PPCODE: PUTBACK; _timeable_hard(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::interval(...) PPCODE: PUTBACK; _timer_interval(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; MODULE = Event PACKAGE = Event::io void allocate(clname, temple) SV *clname; SV *temple; PPCODE: if (!SvROK(temple)) croak("Bad template"); XPUSHs(watcher_2sv(pe_io_allocate(gv_stashsv(clname, 1), SvRV(temple)))); void pe_watcher::poll(...) PPCODE: PUTBACK; _io_poll(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::fd(...) PPCODE: PUTBACK; _io_handle(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::timeout(...) PPCODE: PUTBACK; _io_timeout(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::timeout_cb(...) PPCODE: PUTBACK; _io_timeout_cb(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; MODULE = Event PACKAGE = Event::var void allocate(clname, temple) SV *clname; SV *temple; PPCODE: XPUSHs(watcher_2sv(pe_var_allocate(gv_stashsv(clname, 1), SvRV(temple)))); void pe_watcher::var(...) PPCODE: PUTBACK; _var_variable(THIS, items == 2? ST(1) : 0); /* don't mortalcopy!! */ SPAGAIN; void pe_watcher::poll(...) PPCODE: PUTBACK; _var_events(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; MODULE = Event PACKAGE = Event::signal void allocate(clname, temple) SV *clname; SV *temple; PPCODE: XPUSHs(watcher_2sv(pe_signal_allocate(gv_stashsv(clname, 1), SvRV(temple)))); void pe_watcher::signal(...) PPCODE: PUTBACK; _signal_signal(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; MODULE = Event PACKAGE = Event::group void allocate(clname, temple) SV *clname; SV *temple; PPCODE: XPUSHs(watcher_2sv(pe_group_allocate(gv_stashsv(clname, 1), SvRV(temple)))); void pe_watcher::timeout(...) PPCODE: PUTBACK; _group_timeout(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::add(...) PPCODE: PUTBACK; _group_add(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; void pe_watcher::del(...) PPCODE: PUTBACK; _group_del(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; MODULE = Event PACKAGE = Event::generic void allocate(clname, temple) SV *clname; SV *temple; PPCODE: XPUSHs(watcher_2sv(pe_generic_allocate(gv_stashsv(clname, 1), SvRV(temple)))); void pe_watcher::source(...) PPCODE: PUTBACK; _generic_source(THIS, items == 2? sv_mortalcopy(ST(1)) : 0); SPAGAIN; MODULE = Event PACKAGE = Event::generic::Source void allocate(clname, temple) SV *clname; SV *temple; PPCODE: if (!SvROK(temple)) croak("Bad template"); XPUSHs(genericsrc_2sv(pe_genericsrc_allocate(gv_stashsv(clname, 1), SvRV(temple)))); void DESTROY(ref) SV *ref; CODE: { pe_genericsrc_dtor(sv_2genericsrc(ref)); } void pe_genericsrc::event(...) PPCODE: pe_genericsrc_event(THIS, items >= 2 ? sv_mortalcopy(ST(1)) : &PL_sv_undef); Event-1.26/util/0000755000076400007640000000000012727627261012242 5ustar useruserEvent-1.26/util/bench.pl0000644000076400007640000001706712357140355013662 0ustar useruser#!./perl -w use strict; use Config; use Event qw(time loop unloop); use vars qw($VERSION $TestTime); $VERSION = '0.08'; $TestTime = 11; #eval q[ use NetServer::ProcessTop; warn '[Top @ '.(7000+$$%1000)."]\n"; ]; #warn if $@; # $Event::DebugLevel = 2; Event->timer(cb => \&unloop, after => $TestTime, nice => -1, desc => "End of benchmark"); #------------------------------ Timer use vars qw($TimerCount $TimerExpect); $TimerCount = 0; $TimerExpect = 0; for (1..20) { my $interval = .2 + .1 * int rand 3; Event->timer(cb => sub { ++$TimerCount }, interval => $interval); $TimerExpect += $TestTime/$interval; } #------------------------------ Signals use vars qw($SignalCount); $SignalCount = 0; Event->signal(signal => 'USR1', cb => sub { ++$SignalCount; }); Event->timer(cb => sub { kill 'USR1', $$; }, interval => .5); #------------------------------ IO use vars qw($IOCount @W); $IOCount = 0; use Symbol; for (1..15) { my ($r,$w) = (gensym,gensym); pipe($r,$w); select $w; $|=1; Event->io(fd => $r, cb => sub { my $buf; ++$IOCount; sysread $r, $buf, 1; }, poll => 'r', desc => "fd ".fileno($r)); push @W, $w; } select STDOUT; #------------------------------ Idle use vars qw($IdleCount); $IdleCount = 0; my $idle; $idle = Event->idle(min => undef, cb => sub { ++$IdleCount; for (0..@W) { my $w = $W[int rand @W]; syswrite $w, '.', 1; } $idle->again; }, desc => "idle"); #------------------------------ Loop sub run { my $start = time; loop(); time - $start; } warn "Running benchmark...\n"; my $elapse = &run; sub pct { my ($got, $expect) = @_; sprintf "%.2f%%", 100*$got/$expect; } warn "Timing a null loop...\n"; my $null = Event::null_loops_per_second(7); my $e_per_sec = ($IdleCount+$TimerCount+$IOCount+$SignalCount)/$elapse; chomp(my $uname = `uname -a`); print " benchmark: $VERSION Event: $Event::VERSION perl $] uname=$uname cc='$Config{cc}', optimize='$Config{optimize}' ccflags='$Config{ccflags}' Elapse Time: ".pct($elapse,$TestTime)." of $TestTime seconds Timer/sec: ".pct($TimerCount,$TimerExpect)." ($TimerCount total) Io/sec: ".sprintf("%.3f", $IOCount/$elapse)." ($IOCount total) Signals/sec ".sprintf("%.2f", $SignalCount/$elapse)." Events/sec ".sprintf("%.3f", $e_per_sec)." Null/sec $null Event/Null ".sprintf("%.2f", 100* $e_per_sec / $null)."\% "; __END__ ------------------------------------- benchmark: 0.08 Event: 0.40 perl 5.00556 uname=SunOS eq1070.wks.na.deuba.com 5.5.1 Generic_103640-24 sun4u sparc SUNW,Ultra-1 cc='cc', optimize='-xO3 -g' ccflags='-DDEBUGGING' Please mail benchmark results to perl-loop@perl.org. Thanks! Elapse Time: 99.37% of 11 seconds Timer/sec: 98.18% (801 total) Io/sec: 4550.053 (49735 total) Signals/sec 1.92 Events/sec 4909.684 Null/sec 93511 Event/Null 5.25% ------------------------------------- benchmark: 0.08 Event: 0.26 perl 5.00554 uname=SunOS eq1062.wks.na.deuba.com 5.5.1 Generic_103640-19 sun4u sparc SUNW,Ultra-1 cc='cc', optimize='-xO3 -g' ccflags='-DDEBUGGING' Please mail benchmark results to perl-loop@perl.org. Thanks! Elapse Time: 99.14% of 11 seconds Timer/sec: 98.18% (810 total) Io/sec: 4957.076 (54057 total) Signals/sec 1.93 Events/sec 5343.137 Null/sec 111410 Event/Null 4.80% ------------------------------------- benchmark: 0.07 Event: 0.24 perl 5.00553 uname=SunOS eq1062.wks.na.deuba.com 5.5.1 Generic_103640-19 sun4u sparc SUNW,Ultra-1 cc='cc', optimize='-xO3 -g' ccflags='-DDEBUGGING -I/usr/local/include' Please mail benchmark results to perl-loop@perl.org. Thanks! Elapse Time: 99.14% of 11 seconds Timer/sec: 98.18% (783 total) Io/sec: 4911.331 (53562 total) Signals/sec 1.93 Events/sec 5292.045 Null/sec 114013 Event/Null 4.64% ------------------------------------- benchmark: 0.06 Event: 0.20 perl 5.00552 uname=Linux furu.g.aas.no 2.0.31 #1 Mon Oct 13 12:20:11 MET DST 1997 i586 cc='cc', optimize='-g' ccflags='-Dbool=char -DHAS_BOOL -DDEBUGGING -I/usr/local/include' Please mail benchmark results to perl-loop@perl.org. Thanks! Elapse Time: 97.61% of 11 seconds Timer/sec: 96.80% (772 total) Io/sec: 1518.486 (16304 total) Signals/sec 1.96 Events/sec 1687.248 Null/sec 50928 ------------------------------------- benchmark: 0.06 Event: 0.18 perl 5.00551 uname=IRIX64 clobber 6.2 03131016 IP25 mips cc='cc -n32', optimize='-O3' ccflags='-D_BSD_TYPES -D_BSD_TIME -woff 1009,1110,1184 -OPT:Olimit=0 -I/usr/local/ include -DLANGUAGE_C' Please mail benchmark results to perl-loop@perl.org. Thanks! Elapse Time: 99.63% of 11 seconds Timer/sec: 98.18% (720 total) Io/sec: 6541.408 (71690 total) Signals/sec 1.92 Events/sec 7017.893 Null/sec 74469 ------------------------------------- benchmark: 0.05 Event: 0.13 perl 5.00502 uname=SunOS eq1062.wks.na.deuba.com 5.5.1 Generic_103640-19 sun4u sparc SUNW,Ultra-1 cc='cc', optimize='-xO3 -g' ccflags='-DDEBUGGING -I/usr/local/include' Please mail benchmark results to perl-loop@perl.org. Thanks! Elapse Time: 99.48% of 11 seconds Timer/sec: 98.18% (765 total) Io/sec: 3742.786 (40955 total) Signals/sec 1.92 Events/sec 4048.570 Null/sec 176565 ------------------------------------- benchmark: 0.04 Time::HiRes: 01.18, Event: 0.10 perl 5.005 uname=IRIX Pandora 6.3 12161207 IP32 cc='cc -n32', optimize='-O3' ccflags='-D_BSD_TYPES -D_BSD_TIME -woff 1009,1110,1184 -OPT:Olimit=0 -I/usr/local/include -DLANGUAGE_C' Please mail benchmark results to perl-loop@perl.org. Thanks! Elapse Time: 99.42% of 11 seconds Timer/sec: 98.18% (846 total) Io/sec: 4729.905 (51725 total) Signals/sec 1.92 Events/sec 5104.823 Null/sec 92255 ------------------------------------- benchmark: 0.04 Time::HiRes: 01.18, Event: 0.10 perl 5.00501 uname=SunOS pluto 5.5.1 Generic_103640-08 sun4m sparc SUNW,SPARCstation-10 cc='gcc', optimize='-O2 -g' ccflags='-DDEBUGGING -I/usr/local/include' Please mail benchmark results to perl-loop@perl.org. Thanks! Elapse Time: 98.83% of 11 seconds Timer/sec: 98.18% (765 total) Io/sec: 2629.475 (28586 total) Signals/sec 1.93 Events/sec 2866.151 Null/sec 150603 ------------------------------------- benchmark: 0.03 IO: 1.20, Time::HiRes: 01.18, Event: 0.07 perl 5.00404 uname=IRIX64 clobber 6.2 03131016 IP25 cc='cc -n32 -mips4 -r10000', optimize='-O3 -TARG:platform=ip25 -OPT:Olimit=0:roundoff=3:div_split=ON:alias=typed' ccflags ='-D_BSD_TYPES -D_BSD_TIME -woff 1009,1110,1184 -OPT:Olimit=0 -I/usr/local/include -I/usr/people7/walker/pub/include -DLANGUAGE_C -DPACK_MALLOC -DTWO_POT_OPTIMIZE -DEMERGENCY_SBRK' Please mail benchmark results to perl-loop@perl.org. Thanks! Elapse Time: 99.66% of 11 seconds Timer/sec: 98.18% (819 total) Io/sec: 817.160 (8958 total) Signals/sec 1.92 Events/sec 944.869 ------------------------------------- benchmark: 0.03 IO: 1.20, Time::HiRes: 01.18, Event: 0.07 perl 5.005 uname=SunOS punch 5.5.1 Generic_103640-08 sun4u sparc SUNW,Ultra-2 cc='gcc', optimize='-O2 -g' ccflags ='-DDEBUGGING -I/usr/local/include' Please mail benchmark results to perl-loop@perl.org. Thanks! Elapse Time: 99.76% of 11 seconds Timer/sec: 98.18% (711 total) Io/sec: 1020.097 (11194 total) Signals/sec 1.91 Events/sec 1150.593 Event-1.26/util/filehandle.txt0000644000076400007640000002713112357140355015073 0ustar useruser---------------------------------------------------------------------------- [Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index][Thread Index][Top&Search][Original] ---------------------------------------------------------------------------- Re: your mail ---------------------------------------------------------------------------- * From: Tom Christiansen * To: Chip Salzenberg * Cc: Byron Brummer , perlbug@perl.com, tchrist@jhereg.perl.com * Date: Tue, 19 May 1998 10:50:27 -0600 * Message-Id: <199805191650.KAA09658@jhereg.perl.com> ---------------------------------------------------------------------------- >You can call the readline() or glob() operators directly, if you like, >or else assign your handle to a scalar and say <$scalar>. Um, not quite. Here's a FMTEYEWTK on Indirect FileHandles that didn't make the cut on the Perl Cookbook. Check out talk about readln, er, readline. --tom You want to use a filehandle like a normal variable so you can pass it to or return it from a function, store it in a data structure, and so on. The solution is to use indirect filehandles by storing strings, typeglobs, typeglob references, or IO objects into scalar variables: $fh = SOME_FH; # bareword is strict-subs hostile $fh = "SOME_FH"; # strict-refs hostile; same package only $fh = *SOME_FH; # typeglob $fh = \*SOME_FH; # ref to typeglob (bless-able) $fh = *SOME_FH{IO}; # blessed IO::Handle from *SOME_FH typeglob Or to use the `new' method from the FileHandle or IO modules to create an anonymous filehandle, store that in a scalar variable, and use it as though it were a normal filehandle. use FileHandle; $fh = FileHandle->new(); use IO::Handle; # 5.004 or higher $fh = IO::Handle->new(); Then use any of these as you would a normal filehandle. Here's how this works: Anywhere that Perl is expecting a filehandle, an indirect filehandle may be used instead. An indirect filehandle is just a scalar variable that contains a filehandle. Functions like `print', `open', `seek', or the functions or the `' diamond operator will accept either a read filehandle or a scalar variable containing one: ($ifh, $ofh, $efh) = (*STDIN, *STDOUT, *STDERR); print $ofh "Type it: "; $got = <$ifh> print $efh "What was that: $got"; In the spirit of there being more than one way to do it, here are seven ways to produce an indirect filehandle. Don't be intimidated: numbers 3, 6 and 7 are the most common (and 6 and 7 are really the same thing): 1. Barewords The first, SOME_FH is rather dubious, because it's not merely a string, but a bareword string. It won't be allowed if `use strict 'subs'' is in effect. Other than that, everything in the next entry also applies. 2. Strings `"SOME_FH"' is still a string, but at least it's quoted. The big problem with this is that it doesn't have package information, so if you used it to call a function compiled in a different package, that function could get confused unless it were one of the ubiquitous handles, like ARGV, STDIN, STDOUT, and STDERR. You could add the package manually, saying perhaps `"main::SOME_FH"'. It won't be allowed if `use strict 'refs'' is in effect. The function in question can fix it up using the `Symbol::qualify' function, which adds in the package. Its cousin, `Symbol::qualify_to_ref', does this and produces a reference, silencing the complaints from `strict refs'. use Symbol; sub function_taking_filehandle_argument { my $fh = shift; # produce typeglob $fh = qualify($fh, scalar caller); # or else this one: # produce typeglob ref $fh = qualify_to_ref($fh, scalar caller); ... } The `Symbol::qualify' function produces something useful for passing to the `readline' function as described below. 3. Typeglobs The `*SOME_FH' notation is a typeglob, an entry in a package symbol table. Typeglobs are often nominated as Perl's deepest and blackest magic. If you see a star in front of an identifier, there are typeglobs involved, and you know you have entered a wizardly realm where even gurus fear to tread. Unlike the string versions of filehandles shown previously, you can do nearly anything with a typeglob you'd like--if not a good bit more. They're extremely convenient and useful, once you get the hang of them. You don't have to fight with packages or any stricture. And although it's not `bless'able because it's not a reference, it can be effectively returned from functions. A reference to a typeglob can't. Here's how typeglobs are typically used for I/O: #!/usr/bin/perl # demoglob - show how to return local filehandles sub ropen { my $path = shift; local *FH; open(FH, $path) || die $!; return *FH; } $f = ropen("/etc/motd"); $g = ropen("/etc/termcap"); print scalar(<$f>), scalar(<$g>); >>> Welcome to www.perl.com, the Perl Homepage >>> ######## TERMINAL TYPE DESCRIPTIONS SOURCE FILE If a typeglob is passed in, it can be assigned to a local filehandle using a typeglob. After that, normal operations like `<>' or any I/O function can be applied to it. sub read_N_lines using local *FH = shift; my $count = shift; my @lines = (); while (--$count > 0) { push @lines, scalar ; last if eof(FH); } return @lines; } open(TCAP, "/etc/termcap") || die $!; @some = read_N_lines(*TCAP, 3); print @some; >>> ######## TERMINAL TYPE DESCRIPTIONS SOURCE FILE >>> # >>> # Version 9.12.0 It turns out that it also works if the caller forgets to star the filehandle or passes it as a string, effectively using techniques 1 and 2 from this list. It works only so long as they're in the same package as the function in question and `strict refs' isn't enabled, though. @some = read_N_lines('TCAP', 5); That's because assigning a string to a typeglob promotes the string to a typeglob of that name, like this: *newname = *oldname; *newname = 'oldname'; # magically same; promote string to typeglob! A careful function would have done either this to qualify its filehandle argument: use Symbol; local *FH = qualify(shift, caller); Or prototyped the function to take a typeglob, which implicitly does the same thing: sub read_N_lines(*$) { # same definition } Once such a prototype is visible, a call like this: @some = read_N_lines(TCAP, 5); is really treated as though it were @some = &read_N_lines(*TCAP, 5); 4. Typeglob references The ` \*SOME_FH' notation produces a reference to a typeglob. It can be used to create an object by blessing the reference; this is what the FileHandle and IO modules use. Don't try passing one of these back from a function, though, because it doesn't work. Instead, if you would like an anonymous one of these, use the Symbol module. use Symbol; sub ropen { my $path = shift; my $fh = gensym(); open($fh, $path) || die $!; return $fh; } 5. IO handles The curious `*SOME_FH{IO}' construct is explained in greater detail in perlref(1). It accesses the internal IO object associated with the handle called SOME_FH. This is a real object; it's already blessed even though it's built-in to Perl. printf "I have %s\n", *STDIN{IO}; >>> I have IO::Handle=IO(0x80784b8) The only issue here is that it can't be used to generate a new filehandle the way `Symbol::gensym' can. But if you've already accessed the symbol as a filehandle, that's ok. This works fine: sub ropen { my $path = shift; local *FH; open(FH, $path) || die $!; return *FH{IO}; } 6. FileHandle The standard FileHandle module can be used to create a new filehandle to use indirectly. It's just a bit expensive to load; as of the 5.004 release, merely saying `use FileHandle' loads fifteen text files plus several shared libraries, plodding through nearly four thousand lines of source code. use FileHandle; sub ropen { my $path = shift; my $fh = FileHandle->new(); open($fh, $path) || die $!; return $fh; } 7. IO::Handle This is works the same as the FileHandle module, except that its name is different. The FileHandle module is really just a front-end to this one. It's still just as crazily expensive. There's a catch with these indirect filehandles. Only a simple scalar variable, not part of an array or hash or larger expression, can be used for things like `print', `printf', or the diamond operator. This is illegal and won't even compile: @fd = (*STDIN, *STDOUT, *STDERR); print $fd[1] "Type it: "; # WRONG $got = <$fd[0]> # WRONG print $fd[2] "What was that: $got"; # WRONG With `print', you can get around this problem by using a block and an expression: print { $fd[1] } "funny stuff\n"; printf { $fd[1] } "Pity the poor %x.\n", 3_735_928_559; >>> Pity the poor deadbeef. or even this, which sends the message out to one of two places: $ok = -x "/bin/cat"; print { $ok ? $fd[1] : $fd[2] } "cat stat $ok\n"; print { $fd[ 1+ ($ok || 0) ] } "cat stat $ok\n"; This kind of thing doesn't work for the diamond operator. In some cases, though, you may be in luck. The angle bracket notation is mostly just an interface to the built-in function named `readline'. You may call it directly--providing that you pass it a typeglob. Not a string. Not a reference to a typeglob. Just a typeglob. Given the initialization of @fd above, this would work: $got = readline($fd[0]); But if those had been typeglob references or strings instead of globs, `readline' wouldn't have worked. All this monkeying around will probably get to you eventually. If so, it may well be time to load the FileHandle module (or its newer alias, IO::Handle), which simplifies much of this. It has a `new' method to provide an anonymous filehandle, as we saw above. And it has `print' and `getline' methods (Yes, that's `getline' as a method, but `readline' when a function. I don't know what I was thinking when I wrote it.): use FileHandle; @fd = ( *STDIN{IO}, *STDOUT{IO}, *STDERR{IO} ); $fd[1]->print("Type it: "); print { $fd[1] } ("Type it: "); # same, but *much* faster $got = $fd[0]->getline(); $fd[2]->print("What was that: $got"); See also the `open' entry in perlfunc(1) (or Camel:3), FileHandle(3) (or Camel:7), the perlref(1) manpage's treatment of the so-called `*foo{THING}' syntax, and the IO modules. ---------------------------------------------------------------------------- Follow-Ups from: Chip Salzenberg Steffen Beyer sb@engelschall.com (Steffen Beyer) References to: Chip Salzenberg ---------------------------------------------------------------------------- [Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index][Thread Index][Top&Search][Original] ----------------------------------------------------------------------------