From 302a99d1f4f3e5cc02e43cfb5130254143882dc9 Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Sun, 12 Jul 2015 17:47:54 +0300 Subject: [PATCH] fixes #54, es6 --- 1-js/10-es-modern/17-generator/anon.png | Bin 0 -> 30427 bytes 1-js/10-es-modern/17-generator/article.md | 233 +++++++++++++++--- .../10-es-modern/17-generator/genYield2-2.png | Bin 36397 -> 31534 bytes .../17-generator/genYield2-2@2x.png | Bin 83382 -> 73441 bytes .../10-es-modern/17-generator/genYield2-3.png | Bin 28523 -> 25158 bytes .../17-generator/genYield2-3@2x.png | Bin 64450 -> 58403 bytes .../solution.view/index.html | 43 ---- figures.sketch | Bin 10821632 -> 10821632 bytes 8 files changed, 196 insertions(+), 80 deletions(-) create mode 100644 1-js/10-es-modern/17-generator/anon.png diff --git a/1-js/10-es-modern/17-generator/anon.png b/1-js/10-es-modern/17-generator/anon.png new file mode 100644 index 0000000000000000000000000000000000000000..a1675d2fee874e14fe4b2d222b1d30b29cec78d8 GIT binary patch literal 30427 zcmXtf1ymc&_crblyv4N;oZ{}q-QA%$1d6*CYm2+IxE6Q!pv56baCoucP$>P<-~W6k zXHQNhGk16H&b_<$d7k;Ksjh&FMUI7lfPkx{D5s5pfQSM=*fG%HEldy7TJSFv2Wd5F z1cZh!*e_P7@ZYpHirQ)j2m$X95W=Dm5Prj(!j2ITK5-);{AY=PAd-cEK<1IxsU-&g z1I=1RK@Q>XzfVz5c`CdG(?ik73w}1`e+MG7q*Eij5#3u!O&)y%nV5{1Atb}q1a7TV zNlseVZ~g3#f0ms=z%ushR?EG_(QwvHUS$VkdKI`d=bUwxbFcBrPylT~V020YnJj10 zu6@%orq}fM;7~O7Ca&8kHhwD5<(&*? zly)Vn(%Wy}hF(wB;^R_zYI+`wE?<}1dZlkS0=khO3&Zh|LIFZZFDxFCu%@^^+&ttE zG(S=H&Awq6Sq#|VeWKJQv4kapn1DG)p|knNlIy3pI~MN~>DbZUSx8Dszrl~1I&R->i9)RcGt6EB+v(hLIep^G5LHO&Vl-UHtBvWpo`ign3im`KbGOyCdmNADOiz|HoQ8Ds!+ZHjb)|ef8QVLvp0vi+DHLQQC z>$q%qt}(L)p!L4*l<8!C(v>Jpzck*N|B-pN86$}J_ifWg{=yfnn(RxI?gg^;Bjb&SBeFFRoAvB+0%7vTg_79@-6@ z#ISAr7hEU{EH3swRX(nkRn=RN|^8mV#| ze@IiZuvC=ly+fC3tk9hh$Y?PF*cuVmnwX$@(C){B*VY#JK8aUw05xtF`CGhZMs3kW zV~*2O&=DPB}J>1Y)Dl)Z@j87SQn(Io4G_lt*7JB|(v^6kgD*(0OWN*uG4v9)tb0F)>wsvh1`V7d}O;*SWVcgD#nNPwgtnm;M` zuX*+XjUXu&A(YJM?#?e2-Bj#y`ZI6PWAkKZ8XFI;2^@-17$HXbGK@#p0m;JXu{9-8 z<5Dx=vIAf#a`L{3K z7V3?`VaL(6xCozENllHTxL(2GS1-IOVi_VNdisb1#ggw#NCa90al|yCPlmQ-DI`gg zvl%Ng4ooQE9x@~d(%0pdfiNC_f#UEeC7Cr4l5tUx?gLM%$3uWT{V%X`R-#hJ%v!A% z23@T5c%(fP3Uy$f{r$O=xx2F+>o4x(^CnA7TJ4gGXz<>}znIh#!wP!iM+K9l+d{-X zNAfM~F?n7OR*o!D%0bb?TGD3H{~VWP9nUisSIJEh4hBV60#o~toQ9X`r;~Ac{2FNG zXxEbwQtVU3ZmgxpH~XfCE%yLw%qY``E4D4R#=6PG+VQ}5s@4UI=5FW9{%>N1)ql+D zJN()2W$w|gO?wm57x6S)=DgB$ejD*~Gm&Mck)hw>17(aK-}Udu04f)Jr@J-1q*Ko# zdW>j*jIJhMvUD++&VbRW2oI0n+R~H(O)6<}MTWmy3J|ktQ5bA`kvwv7+WFkZWLaQM zVv4384zvS(0h%YPZ1R+?3O0S=)%uu7QH=IU(z#3q*FGnmqKIxjigNvI1B=O_JkRU> zO!K}LFZd?*@Q>+To@9Z^;FQe06IpOd3#7f9=D83@2Y-V2|b^TWXD{86Twj%rEZh2RMg zLZL+P@%<}s*4tKQh{hEwM-UT3kHFTC3dMo39|{k@jsIAqS>`NDkXAW2>_^Wxy(}=azQ|)?U0r*$BS={`44sx;*?b*>I_e_*a&qag%tf846N*se+|-7dvl>zJ9K(dU_S5 z_V^9<&FlDo3NL4M4$}lsck9=wGUv@EJNT+gfAN8OLX-M0r9FkO=O$vCeSaEE7hwt? z&=QmAS+UA5*`i4`AWh|6QF1d^2FcxwK8K^Ta896y1$PHEg_bL(g`Ljoyr+=hy6wJV z{b?VFYe-})Tceb}1jrKUkZxAD6DF`8ziXa3Dm!|~-YfL%OoLupOCW8azbxcSEJ0%7 zzKDlse-RiN!8XcRq0mgjL<4sY%?TKsuDPVgT^ALf`qP@0PYx&P$Ys{%F#0fDc$nT! z81^oHn6k_evyGl8J`l#x?~b5hQ-|O@S{f3abI6g#eOYjNXdepRAb&xS$9d)3t%e#(lnFkm6)Pnz4;tGllgQTS zRvIE-o6=4hnFEZ!`~CIBJeN6>6+`K!c=U;pEkYZxY*P; zg*UhJx6LhU6GGz}t2jT#sQa=tWPzhJS|n}v4~{3U$UhuVk+ z$F~Xe(3;{)DgxhJmy7ZU1uNnYqc7sE_eUwJ9qflk#tv99@^Lv5G@+cyoT2$JBqMK! zJ-R{J+WqsQAQO}x77n;cEM0_eYteO3QI*n$1_q0aD@a^78{5_WK8)ETl33V-$d!No@ z4^~@|!PKE&=(fx=Fdt4s4h|@ZiFIK%$zhCi3C9>n^4})#^!kzA;|7P=V1V7A2a0#~AyU4qJ+$50_c~iH zeVC7=-p4O=;s9zEYub?$Z{u%oQDW)rCD>+PPRHn{IB?2-T=talchc@-a4gMnWLwaNa_ZV-U=ybLmqwb`G-aMK^73RJr zDBQv}hKxV6(c#FrKw7aDxG|#W!iA@hes(M2+#_448PVrK??G?eNWPnvqXX&Yj+QM7 z?X1yi*x5c4r|5lFD)11ab^v(}rngxD`wobM`S#dK$f67e-OE%@CBu`S+qb%5_GY`< zAK$5^>0#nV3~EZ-Wm|GE_`JO&6~XB)f9B}&`K{}QcnBoO=JyyCQp#_jWuIvBJ{Ox- zPetJuF1I#%Sh#i(_2vV)X4y-$joB!mxiVOJcB}|#%-15-<^#nk(DRp z8HwyQ=QUH02*KUc!4G%O!F$wRqN{Tlv=qI?*UCK$ubi&A7<4T)&kZ=_$h4EeLfmrbv($@`3+VixQ(1Hgx~7Jq9Z+tf$jyGYDNkrm+A^!}HRquISD>BFEB`Jd z(~oN;4^4TvlnYXJU_uZU+6Tyxg5A`p zZ7*}SM{dXpne){=2p^G3hjeFE=KHkzD8Hi+UPcCvJ-jyrGR^1#2`hAzWg!f99G0X> znUlUZ)3+G|`a~=%x4GfLqmxFzHYnb=vH<zZ$$hU z9TA&Kii~Ooex%_ctB8ufK(canKZ@bz>1hHtSW^y4YACJ88}nA)PgYNg1@0IHwvC{( z7!irDz}Igky=DL)L{LPRX1=&X)=H)U4>XRj0KcPghuU$?-&Z8v)aX7mf8STSWdp1GvYr=%Oo> z`9BxWDM}|~WOm7w2B+B#nj9Nc3&x9Yj&V&X_xR%48mr>*>>p=|HyDMj@#O~)9!xjhfE1WoNn>@&Z(xIXNHNJs9@I76n){BmU8WVW3KZ_Vb%MXsaL^b zH_(k5=^#f^*_S5qC{aNM*}))#f#0ewe*uvO;9j%=DR2g{8SJc?UqnBe?yvr`0fQT< z*bQu*kRt04{_8$RRgM`F)ZR)H#Bcg6?%dRf*1Laqfo<-kv}69m+hBEL%MQVKIe;0R zqpDre0m;gZv?&nr@xzo&8hFMAiD(a)9V6A4-w2Xerd-HAni1N}^$C~~j9XP$a^Ws(l z#q|ZN>$hEp(%2EGb9BXlsAJO4lg=n^X!U=B(*j{HHQ#x;rBx^Rs6`1UymD?3spd}H z#c{vbgt(Q*2H*U`9&GUwT*P1A=mSZf8?)J=I$5t!IZ9Q+comfTg%P_G@^8nc*uya& z)23xhA0Bttpg%S&-m;JkM4WCBTt5R0Fq%(=WX1)Rjr6PEzM2k2f} z)X~x%;pN;{M{!Rl+1$(RKuHI(nfdOnVzMYQcr~{)h3u~2Wu-o}qnY_GQ>Mlm123J; zV1^niDe(xnJRr)V5|dAdklA1O{%NQKW55nEo~4SMNgQSNF(?{cv>)6xsacd(-JYG`#PD z1w9Hw1Kfbg_XBH8wZgn#Sm?mJZpt_tNnF7KO&Ai^*BZ9h&tBPBI=#&pS*N~)Zm)lE zJ<2drBwe#2?tMsyl0JQy!D%qca?!&(74!*A9tqt1p6FO}(byqV6kSrYXk6JV>ul<_rt!e9P1snGQR;unf-31YKM^GX9Bf1PmJ9mNd$3M0r(HK(+s^6k-SA>_= z->-lceU&t;fI8l6nAxU~+Z5q0%E4CNXku7+r1Sgq#_vBMV&jyefr$w!WRv25vnk%! znM8z4{LH?D;{#MiB7}qK09mYG=_*9}Jm~E789)M%g+}Fb+aLG?X50RnYadr~parAI zH|`NaA29tcb(6~zVJiGW>*;mUgSmbJpN6otl=PN)5G7u7Y6dTkbSr=Y%>@qXNH0)O_qfa@t#C4Z<(o+P-fx!jbqY z=!0JuE$t4t3be-TDR@HfrOX#P&We)+U|Nv0UN~-jmU(T?(@!E^ES3sc;e4}*0@c}>J5F6gQ#PQ{2!3m4Q-DDGRGh?kq( zVQ4A$PmCQ3nJbd+oODmL4B8+EDfh)?SE?Dg^KFNhD-OeyAb&jVi(jMSyuW-jb;pI- z&amRYe0WrWNMxAAn*#)H@aMi+NJMaTH3KGd?%w91-Yyfz?!uGtxjghsCp%HEX>+YK zy6Dl)omd?1nf1`y_Vn)_i13Jc8E#D&JPg!D*7L>x(HQYHXiemLQUOY{F`P~Q4~*b_ zMTSvl^#v9Xr$j_1M*jG5j-}&kHF=YULGH)mp5~ zX!lxax{KN7%Sw%YNWfp#Y9^eK9|J8SPC2|R;EKNbJJg!Im+_q}>Mc!7sh0}-m>upe zf)q)58VRxTBuG__XB^-4+3)=$@+h;#z``vdlagb?J7Yf^sRx&<3@e1t^+&OZ zskT>A1u=0t2`eii`7q+7r;*B0hVtJS>LRiz+%5F0Y?gv>$2`_(;`LQDB`tkh27DMd z#0(c022W73^_K6jUQEe2+DW`6Fni=jj<=M_$NREW3KPzo2s3~WRYAPu@e55uBzta#7)D)xEvU0Hv(IP?F63D4D8)1iOomkPZ}4IMCPF zKzW^GBknQyP_$7UfARV@R#DeOQ%_H~&To33AI1;4esEU`kj}dDCzb$woNab8Flp(~ z0|PNor&Nj2Tzu(M`usp1nV7Me!!n0!ewKSxWL` za=QY9%Jd$k!e$>tae4ol^qQ+{DJhkswq;5IG*STw(hX5sA)#Lf3eTP1bQ_b8OJ-g% zw^=q;x;VJ0q|6gvk9m1Ux#6owiFbu=_UO_B@f+v0zneKfcVgroqarGcOi7GC*n)ET zVPR65v?#-eHvK->gTyb1^|Nw?=TCoCV-idYS+WQZd1sfoC{RMC9;aH3Fje9P4g=p{ z&;j^hVH@@bf!7~$jNv&P;e~!t(vUZ3TGOjQ)~Kq|t`mWY%^PntCxx|HJT8emc149H zJF)&_`EF@Ui$ZDHt^fwoQJBLjr?lblqHV+mDx=lXqISli*cgmoc1hB3h|6tqyYB#g zotD)1W*cKy{|TK%h=C7Im@)(6?`zPm#30>6(1rwBmk|`lfxaNBR}2<wvR8DUGW9=WyIc+C)|obZ*{pwXu+=+>!Fd6gytI#BO{rS*svwx5;^}! zSBseA8mxK01bYRRU&%q?+UsXauj}LYYx3DCW>2Llt>)t2K(oq=mF!C3nd?O-W)3n9 zi;|A{v@$XA9@;6`Dqn+^4nK&S4ozOZv2iZItjMUg*p(8)jq5aQTNh-)QmPxoJ8(}QR22uLQT8oC`6Ecd@?WcuQLT8(7%^~x5-1et zHbFKh#m~>itGkk(J)4>Kt-pL|mA`7QXO!Rm7U#`~Y!D3ve+AVC?m(9m2A{UCSMVCTooHi|4x94_Z<#LsgaYv8S z)vWJt`VC6>dAZp61)f*M4Qi~d-HZiXp3mk_^^}XuE*W_~8aVd&Z1y=HL0Wpq<=RYF zgSb|**H{@rbWLL>-8CZ=%!> z*N&PMpI>f&&3|#Igc{XFcj!+v)*k!cUdI7?1=32s8$9p7|A~LAXQDYvi)he#73ABH zkJn2kn4to>Z*%j9BOq9n*rLbpc3uAVK0ks^-&oL~-OD~EYj(2tX=`zFN5MD{H+xV? zzG$!T1c+)nQg*39LeZ}E9z6bVR%w8O2zqD{Ht@-PlFNk^hrI6=+w53Ge+$~TILyvVM;m*Az-7gWcuu<;QqFDoMt0BKO>}sgrLPEnB)9ed%HKu8)&^qr$MHk@lUQI&gEg*x2LE?N5v^F^#eVq)EDI7c21VZ zv6(gZ8$WOw<@^6g3nmxoJzJ;PSq7h06DBE$P*%q=1S~ z9IG$;0_W(x`p2-=*7#Yeu3lXXm)nLKIgA0XuERH*U4PWt-ADq;trf_b$OVU=3{{Py zBJA-=eVu1>WdUx)tOpw}FQl15xvteA!K($vNfc>jF?S|$B%N45#ND70Pg(Nd4her> zydGNbJR|WTr9$?Z&S@QUuE*{Jb&z~VnpNOh?Y=o@E^>YA%DQ7`p#EwQ9w$Gy`fo-D z{aKe&S~sQu>0`yduZDs4Nr&1D%r=Q$6Be3ebx{*8Y9m9rg>_d6l5Hag)14mw!O~4u zL9eAorx!+*j#m3;*7y8n9g82&v-#(_Zb=8>u0ZHT9lW5G2Xfhi;0%lkt2{sBG#IDj*}C3 zLIC6x7COvch@+q`)sc{>P_${&GyU|eZDpH2I;0Pmyhs`PNfI%4pdWRK30c7WZ++@Q zubDE50YJ}#b1fBKB>qEuYI=6y6hPBOXVY1Eg1Q3#FrhCDCl+?DwEm8s@!DIb?bLKC*4BKiE=L9MixQ?yAyOV z{Z~o`i6&l9U%|e`@*9%_`RLj|HH!x#>$N&thE;~0sN+91MS?vbx5uqI1UQVm5D79kAqhtJI>H*XvLwhTG#vf)6@zC~N{OZl z@acik2&p#$66{|(FFnz>Yp_+YDW%uQGjxd;RgY`;?bD5)F+J?vaNW#*)#1uYJgq!J z#*UnhPehZ$Tyl?-qT(C*d-ox!p};MCE5fW0TV>NYEU)5QOAM6a<1=ObBtx|1vs;fg zsz^!OplcFi^nAS{cfbx+af#J-mW)?@8pG!NrIBhUlJmwx&a*dcTw0Q- zVC|&g;*D=zG>n!~#51ldd7Fs|Q&xo{jf7jPLPj^O6^IQ#y{kO*s4G7@lVYT6jrGy2 zn2~kbtBIYUZUku;W8`-=fB=I;kCxs@8CYD75^7x@+v&B@L5id~t*7f=RZ&=TMWT`c zK=f50h>C{1icHr;I+&MzvYdOJVSNPWuCuPH;-39?;b=!0Ed#<**QZp-e;yWo=kU%N zlv+3;01E8;)rXU6k^R$Wg&fFiYDAK5+(w8MH}`qyD`YJt=bSyLq6x2eF?*&aLP3{R zWE(;v*x_FrF^v+BOC*ZTjS-!eS|!cI5#OD0fGhyV%@*_bl1Wj%Oy6##iA{j`*0Sp~ zwFywSi;`zWKlc~%NgQx-p#{wj-ylAW4f=O$gvwL}(Anr3pc(ZLmDHQsc1WTH zENK0eQmmX_)oLx0r~FXmqI$7?Vs%03+f2(6AJFg)kf+0$p29epqoG4fM0Ic_dfw_}xe3eM<3maoiAIX@TpEwI0r(sX#w#j5^>1cThqbt= z0Wv}FQ@D<_vweGZfB%MrL>u(-hB|XczwDS+p_#f;y=iV+>3BT{%=S@QpudR6 z(R_9zCD-7);?qc)z?*6HG6-?TF_$DrVk|F^y(U{+AKIaIB#cZ=bG2o6yINK-LR4%p}!QXboNz!-lC{g1H> zCqSx{YyZ5ZZC;Zwj~ANf<=AUe{9(D|_Mn2MV!Chbq!{k~ixfmCF1LiZ{bDlhrYdByCE^kTiVk#`zT*J@kucXeaO|PRqBeS265z? zS4n$jpFN>vg8ax}*6W_vVdwJlR?|0G6e9B&DwBma_$tNgZfwf!N?=X#{GTfz9qEiZxhzk*Ly?FEs-^syWj{H)v>-bQD5=dHuIM|0PdJl<9&| z*NYOwz`j-ky$)Y5ahU!swI~1wynM=>k)|MAtGK&!l4t=f}OxZ*{ zzd@F!U-&#we_4_jF?};$PxRCVWud_JP9gvDT+?lY2XUPkXvA4z#qOmK`M zk7vpI(cR!?;WjJhu5$swGT*lQNRk#I^KMs~oV!Da$06+D;?~1A!yK@MKaEb#8FUc= zDf^@@EGmi~%~;J}pq+u08Ln}4oshV>!4BKqjDl$36g}b>l*IjRZX!%c<^6nS8T%&a zzg6HzciGE{e-xDkf;sXmbx;O3nd)$3W0OwXR-Vro$|Jj-c!2YQ-Fv6{`0j%XK-&+N zJd|D*KC9N31irX^=-G01B4o_u#=tkALiAsq+!r4_k?fjhCsa1mAY|gD4j>wKgf`?; zUwpE$#2j?zteg&L!muEkJMH2-f*c8Fhik0%t{Mf%1LVM;)H}dsBW!o^T-$+fLmt%e zeUCcC%@pg?WSOX~?CeJF(%0+6h@!Kjxd#$mEj|QM`Voz2gr3sRQOE}cx4E^8)8LYY zYtStNY^HRzk(=Ye{&`;G1Lb4oI|kvB%?m@D{%*5v18fJe;Wr-kS2#;WAoVry=CV!6 z1f53W3ZS~*fkn%`O`^%CqV2K^>Z$xPPHvB*n!hO|JfZC7!t|uwiQ?X!boTuedLPWz zP52(B0efmXq9QTl&=(%dYXYS#p~M2MRWXBu(H?Q#n1_DfmlQL0SoGJt)d1+Io}NXG zFM-m>e(raKk^VJr-K;+&78osTAx%{coNp%q&6KG{Lo{G{Iu}N=)z$Vk8%AJ3C z{7G62>=kSJd7ZiI8Bbe-RU1t?3eLf5LD4o=s{U-z1`tg$Df6W8 zGZ!Az7;x71Z?By!bod{0zyVF4@dt;4JYjCJBA<0u0E%KdisdJ!u1Sh3Vvjs)TrmZI zqLAWeSLXH~lb_t!*!mTKhzbtCyZl2Il@@%2zr;e(@w9TgtkyL}Xbb8eQgz2fLhW~W z`TExTElM9SKHWl+bDtvnx5IheCHII)wz^SQ96IBsF=>n%$jlyxkQ_SuR1Y{N(rG6niqZpUzcwVnKMKh|2BN#bZHL)_8%xdI& zruRVfls^7`MFNd))Q{3h{DPQN8@7Zg&pa zBc=MyXN{IZ>(5MMlq$mfA2~FdZid&KZT0hlvl~hLG20ov-+Dz80=(Sdi!LWFDU8uo zM4->-29ykP<T*|zcsMcEnq%bX#UvTA@?o4 zfDG=jmEE^cdcI4SkJfub&avt1!+h#m8NB}XxVDpcbha{%1aVoeYH0C8SC8t2Ga^l& zLor|4uN;yjtzNYDn9cOJ*owj}$ER6w3K3pKO9}7gl`@m+4b49f^Y1l8GPjx-sgYFe zhu_q7m_6D;mry$lMd{!C}wyiu6iR(#D)G>=DDNe^&iaOd=eO5;KQJta9onH!P>TyYQ7B zr5^pz_sq1jjQt7uZQtx817}2L{qKUem_q1q3{xkD)LT6Osj2&t?VHT;+!YXMy?y zg}f4W-ZCHk#{$JeG8(TX@l9n+NsW1_Q?uYo)H2tj(Vqe!1J zTa!0YX!M#`SQuDvYZwt4^8}ZcmMyBD?ctfHgk&fJcykZXj0BM#V#w$86>{a{Ey0=3Nqel9x5^d2BvB-AHR{FH z+5w5I;oz9*uwi?Cm4~Ml&6Wn z;6FElEBSt7T&9Odr4??WDqIo$N)2{YR>o_=rkVG#i=x=-7m$c z`p{lFC?sY~a^Ol6TpQ>Ysjjwz-KT^)-RvkY@MkIKz9OO1td!io0NK&yu+U0pee|&t-UgM)+cb@#Laf1AqI55%#x&E)@rgRfUD!QH?57Qh|3uJ7yk>?}STe$hn- z*Qwk~8*%bAu1hJl{6`7$kUv=ZsVtHT9djG@a0?BPUd6hXdCtyISx}kbp%@32@1LQV zxea|_xk=p|s~sx}jKXt#79;6kD+1X#AMXUlI*x;UBXKu%)DING9(anN9@2@ zt;>03)r~4&m(Afwbr?ProIGX$S#H?ifvZRLYM^PUd(j{JE0r?R8K+UKSouoNs@)4| zq>Fqps5WDm{Ww)pV67fMUeJ%C%6MbH!!@bOYVVMD?JmPyBE<}q z&=DZQCazRBu%tvTVYIziY_?#d)$@(F?(wEs@nUTb>n7)i$4-RjHrPWip9YfiDATl2 zvmD`9n>gVps2BQ7$6LYDNSoP=IRn*o)&exVVs0#BYv4!5wd6)+R3@Gx)n9Z>B`3Hp zE2H_HB5}Bn31)I|{`i;K2l8GCV(Hb_^HCmHNIZ+_hnjKYp+pWrxpi-*r(3V`p6hBh zmTUhbPa|Ne?%ja3Zt2Kbq7;fwW?Tb1PU>eLFpG3(o3( z=~lGlGcxT_V!Ycu3D#j|dK6H$D=FZB%V}!&#}EcaR?KWy8qA{Jz$*!WidckW62z@- z#}S+x@+?Z-E_QN9HE7}L*G;T;_jbq*Hq3%W8rD;U-uZz8y$iN)#G6Sm)ZQhqaADk% zuOo1f*Ti^~*YWr*p)^*9=4*55Kdo{eQZH7aB*^^XnA$5^tQxH9c|IMHW;|>(W#^`g zomTghc#n-2wq=@^%m=O1Doy#R+eC2UXA^BXdT_DsV#=o2>ZLo?F)hrFS{QmP#%>dG z8}sF|wak~*jsGvv@mr(WiM8x^g6isPoFv&@cCwKj{p$ON*}ImB#D)DJX2LEYsm!!G z=0Kv#W{ac!a`<^#9w?Q zuKAR%kNq4v5$YXnxXD8u-Q;)TQPQt7I}%y0(>~xG;^jjpfBXl@oh!gCsG&(ZqcNl1 zH*!>_Jz<$CdmpJ3wcoY&!Tzfq^GfqLpvPcJ5)&3t0h_m?!@D(IKpI?;;ZzWRDBdIc zV_z;jyoA4Lzo-A9_FWTY2j>qYfHxbYRyH*(#VDr^6c#4nl6&s!^7eo6f`g-wFI$!E zR6#TnZ#5c^ZmFx%!6+`G4j@wH&Cd2x6ljgMc60!^r5&L;#aMOC$$OkdYi;Ba4- zS#9tI|Njigtm5^)%{d~657tr3m-WdtncXFDVFoY2kb>vV?dvq_lnTt4ix&@5zX zKecFg_}7KIZ=Dox6~ON+6=nE~_u+1Kf}HY)f(Vd4C*(_0sqC81Sv7*2M`hQ$(-jsr z2h@YKREA$ek(BK?O+stgjDG6G;tMJkFPFG=KLdx}}uwTjw#B%6z zp0_3p*M18$NRF>lXyJnQI-elLySUYK*MO%&yjLLXO(Lm6;+RdAHKYk6j2^?>m(zR| zUKq=nTE0U&_-zZm9#FmV6SHp?V$H_;>s=lj5D1qy`dpcK{En7OXBBf0)YAc1XK$Pf z*~ZhlXpkJ5q)rk~R+`dezIRkxTJ`ctXPxI_eB=;R8Xk64E~t@b+8oYN;7&pwM6B>vG2z`FS7pkBCx%v6hmo8^(e{U?X> zOS;%a8oaieFO*ggEnbRVHZj_ohbhD&6mzW0%m+CC;Tqb~`VFqCPwuVAGPzx#lD|yXDh>AcnZ(B4tw? z-kI^m=bgJcQ%-I6rMG|ux_hraIYyGa5Cs$y+;YA~3imo^G6H(BGKnX#BQr-#`^$WH-IJW>aj1$ETYlLF&{#z=P#?pss_{`~}z}0D0 z%$(Wekc)xC6!mYjm~$HpF&syx&nW8eqNFt2J4Lig$WT~TXpzQc(pv9ZJ>MtNaxi+5 z9jxEGVE>`;?0S5Fs_5^4%}Jo#R4OCC&5aJ`uQ;w#(a&Jit0F!H`HKm>*6jR4NdIpJ z&tLV(zbA4gDXQDPx3v|?ZI5D3I!>|-qqC19_^(duL$)f&+S?ID=O@nPDOCeR{-00L ztulSIa9PEg-y10@C1+^%N6oYdDF8!4%5{*v;=(Xx27W0kgKhmk>P5zzt)tRx{QsrM z-e0^z^__Z|URK?xGz9irn+`4$R_wD4BQsCfH8`m=P&cxzh;6~^xzMDkY)|?Z-Y>K; zQdp$DNFE^u`NtxutS3CUld%l{K~Qq+4LdrYrB;K^%Z7jzzD}G}D~p4W zMrkOVi^3`4^zb}(ZKUce*?PSnXRF>ixW`(eaLio-nS}CKp0D&_M1jgm6=U$xX zjQNEpvC@193Qzi?cIvgUkI%i(m!A8X7F-B8ZTJL^20yk*z{_g!?(F&Gmz8jTu*oB) zx5q&db)E!E8H+C693c-0#h-Ks@r;MLXMjMHT*o_P0Sh*rUxczGNIJLBTWKm&VU_}^ zM1mW*kk%$GaQ=U<;7hOo=%rSHU3nOdLN_`tHO28O^X1APvWpeng*T)!&1Mr-n2T}Y z=T;6tobcc@*Rg^@%Afc=a*3VJ{Ir^rRjvkBbiFU=S^Jj-g#I(lB zFiceh*5wz?`fMb!tk_cX{#Uo8Isa9)+Sn+g(rR5*xI0LQW*j}p(eLvOe!)>T(JV3c zj%?N};$Mu%g#IJn-_34R0W^b?J1DTW@KB6y#K#|TzC{eN$;U}|6rWr`s&`IQVjfd7 zzb5oFDkdQ7DeIKxJ$; zY|6bi3Lg|cKD2aR_mjYeir zD7;+)RHvig)u|iEQtvC$9|{SSV^bMhO9huH~d!VXJHuE2&?OvhPYJXvVysZ{0P^io~%KqZm>BEj)UuzKO{v`U|C zJ2~dli)(dF;gI0?uC^tmj$(VCv>+q_WkMVsds8)6-^SJ76t$6je*bCR!R=$FG%0 z`=a*cYO%N6@4l-bx($(LSPcJ#5vIV>xWKh)F6B-)<;P~{2;W0vq)d=3shxoqixzvk zu2R4B?Ot&_l5*6FvJq5j4EKGs(_Zm`l}A=8KR)}ou^c;tkCl&&5B9k<<&R;=9S;VV zy@32IIOmgP)dJTNpv8@;JZE3Y=5JkHWto(Mac^aHbd$bf!%F+Y@Fp z6-B?Dlu99|vO=S+@8+l@f1t&Co$ftikr(pIA!xKaT6^Hi7fBL3h-5_MWhr0cF8^SL zB+A!^<}U?|qd$AvLa)&NPEYrij9f@QPw@Smp;Dm8_r zx)$;k8!aLibPdX$Lk!*cDgeJd0uF$|=!YA#)z-b3buyu=uiyw9j|us$3sqC;a432K z3a8C7BT2$QBF7gV8)fHqV3{WfyE#W^UQZ$_b>bWgiT#FS3cXxMpch|w) z-Mv_0aCa^46t^;Haat%)thoCW{`v0PeL64MIXTJBKFQ8nE60`xppKsniIkF(5ej$9 zUsNg^a6JJ;24qZ547JYmuJJ=6vd9-eY2=5qyV~u;0y}A<0SO1%!Cpncs&gu-$QNG9 zY_dE|SCn>QhA#?pb1L6&@4rc-i-`)HPo7SS4s05tizhr|fkZN4AP}|UhX>CfXhUGd zk%EP03MG$eLftdc(7kPoQ5;;52esiDH+CO>hN@?>lD$GkcMi653#-cLmZmX zH|00h14V(xEk_d`I8OqVDT{lct8!hPv4};}AoQe|Dw(P*5$XRrLNBvv#jhgz zvp}v;HnAi6N3rAUiZ-G*jKgjC%MWk2YQ;AX9zm!hEVK`=;cjx@KFO6+At2?!-wfrA zDY~DQC{gNAGSo}yVA4KH*oPAdeHBKPcYZ=TWEhsk(um%{d7-H+Jmk7kOymeA>z2TY zTDc&~_{8iR`az^)lc9dR9n;k-zs=ZA7d*-{lLxjt;g%(uuzte6D&}~vd;Q$Cd)Cvh zc1#XCSpF(P9ZD8EtKo-racCjN5Ni*ZjL=G;7Z5;|)r>U7j=G1Jo1hNZ(iC{@ChhhiH-_bZ%za&8C$i$;l^RI9m_;nD3s4=es+=yXm`|sC;3D{%l}8DnaOG8 zfjEM9#=t%)XT1oOS0<0hnk0ddUyxP{bDEO;VfUNcnpkm=W6BPcVF_IL9=P#e|PJ$sPBqlf)aSR(HnZ}H?itGwVver+irqal$O^$0z>Mghh zSXsYn%ve8YWg)ngv*5@^#utT=ADxGIpljfLEr*}P{dopb^p}g zR+~nV?&;|dH+JDoasW0d_xXJ?g7%V?DMx#2=48AAz^2fm_wIO2rwR2cD_p7IOu@md zSY#AvE3!+oec&?JJ?Mu<(H?olnVN|Fk#$-}q5-#A7ZJxt!{pTDl)L|Zvsy#J!iYsg$FY(9 zN-PIC-U)UlescMNlHoneD@R6LtI{q;4nG@}21}GQ=qUn6 z(i$0ZE3dHF9^3r3ks=NgjP6ekTzT7y=Pw)eio5@b)`Staw3{CAUEnayItPt&0Z0ah zQu=6aKBzNByn2HOetova(?5dpknfsi zXX%l}6%q`>$lY{jBw;{^aMdxy$$B`&J%XQfnqC^f*xskXE9%{|9Ju)SNY)nZ>T2uimtHO%a_*=}s zpV^NN-A)Q#>e9FN)S*=$V^g(6h{>TR#O!C^C?IS~2GGEBze|n&yP#a`YFZ^usI^7aM$cT}%6ioEUO326NLxx@FiAMA@P3 znSciw#ENQkl0_KRWGU$|Ys6sNnpRPjzBWlAL}mb4<_&#Jy*Nmhx1L>DXV~2jE|_`T zoX5gWqIao5g$dj18yVYzl2830nbk+wY@F@bLv!x=QD}G{U9mLCZHT7h`!U7I-{a|d zz8@jg#pB+B98C~S;KKgdhjJb93_mapH{#6&gjL5t^tbTgqfvSF$B`lFMWSap?-g@3wN{?XpjGJ=`DaUob18q}`?5;+RWL}>i} zR=BZDgSlVlvUt7>p19a=hcb~{P-;-_>`i3*h+!|u8vcrqvLP@WMaW12y=1G@N z7f(kThZ~!T^+uPM>;;)>P%(iw`INbW2A6itFokUzMtr|x)@5r&uaGN0ECw++4G-Wb z&FgW>*ZN!wDXF@`pEtPA%{+f^i0bH#?a)Jr1R^5&yqEEHI$BR(_;z8M2$m=cTOP17 zyTe>h_Bs9tOCZTJ4X|d34gs|ixWNzLTuXC2&J?Jz6z}AuI&>IfBL9Xaf{0uC)OfY8mLZ!+431%i94|H39E;PS(`|KckUd<*t{__j(ZE8gEWN_L|jd0&T`u2a3S8)-8 zD3C$yOITum_gzU+Q9m8km6|D4ci$QvS$Tamw#)=u!?+$012tapur3hndpj~SI?xa> zuhu-$!OfyP5N$y1m!K0dRmCzbr};Jg=cG$yb3Tvw2`Uis=f0;s z8A=r(dZOH6#@SZ4M#H%j7#$NTqK8!x($EV$p z#|iJ!^u>AsO3u#?5nl-=rtWfs>|U6xR{Zs59g?*gfPc1lUfCK)oxJ9EAgMwbt9gLGHO zWj7HY3;WdF4E&?$0&tBwI6-Fe(2a7Ga=Ip=JcYv-wlsxBHZbOJKS-#1TaB?KG)-)+ zx7)7R&Bn}g2$b^{FCP1Z z0XFIT)&ak5w6{le#dB4S9R`#22iFY(A*mFM@es}`v+_=ISy`ow`*|Z_FLS{}IDIQ= zIs9O?wzPvhPUTM`8}PdDr^xt=$}!S|q|!mO9X4}%qskPC1V&Y%=Y}i$9v>IrbCY!V5;u%y)1yQb&dA+Ipi~5HvZAv*>g1kUhvcL#bq=7tcm*T#FE{gaeX%uh9S4NfgpMO zDoT?)6IA#QnXM-(WYJ9Mtn-3FlB-&4ukQTKBrW8(wu#umtj*bG$bqipGS@NvSzJz9 z`lP)qq&m2jNwN}@2nDJtUv`F+`u+&50PHc{A8riu{Cvx<$a}YauV0Y-q4Njf>L}tp zKpOow_V1Erf)TJk?P__imJTq8!^tbw5YLq9CYESZdP)Ss2mWJybjuPL*cqpA9VH5P zCTUV4K(0*j5mgGV{Y{{unMRMjNlV=ca~VlsFtF&bo_Iax=@HcPwAK`6u{H_a^&(yW z5}vl$)r`R&k;%aJYKUJ>k5zP7owk5A;QGz#zz;;bW(AcUr)u3S1O;9od;oo)3}WaY zXQ#FSRFol1fGMe?+fW!6Fpbxu@epu1C@WuK2vpl==ZyyQ(eju|o$UP@CV8QE%k`J|GhI($wF+xH@ zN`XoM+loRE$Fl?_xnA+098EqT6e2P!oVVzD;kCw}qtA|PE}6jn6k;FHJ!8CREEO-A zy~Z|~V^yi-)9^=P^?P@_&{AM#*;f3T25Lor#z4A<`g~ftVE}^1hn866c-$R3mTA;h zP9Bb_kB4!$Vp%C3Vug?UyNZhSb&Ns8O_BQa$d}~^_HSXD0GWXoh(6j!Hs0(JcT4Eh zHuzvzu3{!pNQ5_SfhDUJ$}Ec?R9{kEO#yy*F&zphojz@Xn?Q&hrN{|C)jaQ5;hnD( zRBI^OnHp99^JoMi+zEq!J76Xss{a^GAK@kw7}tFX3CUXvHX!*LBeYgYPelyV)_Mq4 z`HTKkU?>F-u@6e+bAVE}Alzo<} z(s3#8`V-~6%wA@d%r`E{Clb)pv3N=rCd+j% za}%2CQuOBG-_;H#41fp~xA-qTyq_3nIDzz6W-k}tp%rK2xVv?E3&5`nSSL*-R$h1& z+5YkcCq&Ikvay-n-3`}5MM=mRH`3WN^y!eRBi!V_;gj_|#b;$@NzqM$b!AHkh?VlP z+ZQsqeyMVX{g!M&_r1Kszc}t0C(`PqWrwqiVFBTTq-%T9``R6xC{pF9=L?JX?tU*- zdQXd&&-}`snuelPl><88DSDd*)Z_Lnzcw_=bTxX;!T*xBP?K!a*x$nA^hX=FTVVef z7-&Y?rle{Y;RX7AXviSw_rBrVTD?@8eUwFdGW5Jwz<&QJj2ozY1H8IH+@&5Om&{}$ zGYR2P$&KYe&m>++|A0!2vwDjQ%~541CP4U`6Uv0y0{y-}pWO-Gv6R-Argsj|Mv%he7C1?l27U~rO>y$p@~C4Z+4f_vIuXW~ zL**f)g+pkA0$o35F{Zq*Yvirb?b#Hd(Cigx`_@Dvp}}|EvSyok)y|BN2L*)f9H5L? z?!dPD`+s?*dyHAGsxiuJW!lrEm=X4uTx8+5B&UVDF1%x$78Ny~k_4~rWyI@gNmcBm zwRvJv(yVw2yY%M}hH#qS-DOw(Sqm^k)E$7>@Lqi_X~KCF4;uXAi0-l!3({&gMH(4m zDx=V;qa++0UR$JRxW9Ae{leAt8;%8)6=5Wp9|@`R6r|;x&o{P0bP@ItdhDb_Hve`r z2sse#55r>>?{6^uT?u6vGszh-{erI-_}CX)r<}6~nqUYSUMea&w}kcQKkPoI{e?DU zvbOIpp^T5e$D`IU-PaDeYkm5WO^5@jEZ!L;eQLt~O?+n&s^NiGer^y`r?()%hM}8m zx0U_?H<(an7NX#(KL5aZD*B9AGPSR#MFP-5rbLwDo0}Pixc|13v%4zxo634xSAJh) zccBc%^Cu)OB6k#Ib23uLw@yk)G0nXzZRjcCP<9GMeyU@C4GIbjY|NI(b;5#0le8R| zW+J2dkdneVA@H@@C}kRIo9I`{zUK0xtiI_7n>zG+rC%jaG2V$&A<@QhkC*{bYZh)? z=qd1Jr@W|$WZV^8@awbT-@q*NWGAkU3ZgZu9G;A3KOZ;7$(u&@e`tg46cCPOXpp^) z%PhoS_UXmv&9z+9_gH1#?b!OUwB)syGusznVYV1QgRKeA$uM@-04=JE<@mJA{%_js zXWZ4lA?m;WLXH1Eze>}|BkImoYPB{P9+aEL!-H<@=zU*K?(Q}%mnCAJcq(C4sOw>k zekCNz#K?P5AKm7D&SoFMdm8Hq+fX(}&bAZ~-}etO$#5*=Kpys#S)Pb$5aD4HC76}I zgH;d}6&{z~0u*pVg{}@^G>ua%u}3QM{zA)-KJR9q9b7F&UYXkOjzz*riXD~U$4Jz0 z=&pSU7?V4_@6uMuDuQ;#ya*7JO`B|?+%-inLc>9J_y_ZMoSjhK|Fh&0aecmv4vvQtA3l5D&Pj_z`@9CKIa?!GVmTxIy z$hFmW)i^-5i}IP-Kk~>rDJeZ*OAaD?kX)X)fH?E^3zZoQau~oMc8@S+sX{InV1rny zaI9ypjbN$3c&`A){rtoI)j*W(EZ!`$1uqF;Ldm?#e(E6 zkU6#WJA%sD%Mac7+?ZyG+PqDEz2oB^K_ZRAeK=6OEVzL6A2l~+YU?-W)wLt^y zH<+0YFC&q`8rA+&>Z+0D99RyH-^#Vu%1^kCY?HZ)b-AjA|j6XLoEY{1~<~ zE)KDhd;+$Ixri^P{iFfLU`ul}3ULy_!I$=h{}T>*`0pQL5ysCyZNdw`$25iw!q>`| z!FXMJ7-b(^m-8>BfM{BXp9ywWx0j~q+Sl_{q*0Z%n)rp;rzCeML1X0X=u8(s5<1IT zJXC4mR~?3KLu7f!(R$I1z6q0n_)o-tvo8TIHdB;gCb< zyVv&3lxjO78Up#k>P--d@sR80bcq9z&4YKb2B2s+xL7O&P3V8bknwhD*)(1I;7lNYo{?^LTo8ktII+q9|13iZe|ouMG15|LX4Wqf%2`@Z zw?HDO@9@6_2D<7IFsNEj7x4OM#1B*IHA>MiRgM*T1?~9tFQh`X41&VLkb>xg6e*{Y zq0}&3Mx#a+{VjHKtq0-LLa|e*n>%U2%lGvd%^$i^jc4(7dniykT-vZhgu$DaHLK#U zJ_~|B$Q*SG>+k?P@$en(upeXU<`8m`QqJ!_J>J~~E2hBS<``+kB&17`I?<+kes@fT z5_TS%f<(hDMx~xInxEFGl*x^$DoXIQaiX-iOUoEkRXrHUHjmrRkB^_z0SH;Wg2s+? z63!0NiHekntRc<`aLK5SPBuCK%GS~6b%*5?}<6~eQ->riHn1w4%PFW)zwGJ ztq6dVLuX*00g7G{;|GbK^v9YBNPMC8(%7Leti>i19VnCvno@XZlFnybpiWk(Y+xsJ zkj&Escdnp3k^E5{9K1^GNR#}7jOiT}T6=Wsn9$FTvzjUs zk}KX?U-D|B2Ahy_)_>M$__xrF!bk(vgN?Y3Sgi7BfoOOzy#fA4E4XOgJ6AI4)>&18 zmSTNi@NH9C57z(lXs?R=Hr?z3q6h(GctJxK=S;KW3VGn*##JV_qyYLfxuGp1%NK%- z#gcsv7+9RXvG~MRw&TyG&|pXmI&3bKZpojfJir5d6-YLES;n0X$o-sZf?%s0OAZTE z)O3_qo--6Y2xmk(J!#FhioAoGL6R7}Iz<-xo(r@w1?@UYWi_?3Z1F*fF<1H&gLE0i z-n3)+gcBVdLjpKE^rHp2xnNJy#=GF>qfxoSX#Nc z%NY-vOXd}Lnvn#kq!=>N83N-Xnq4W;84u;5Gw$oC8F-V`YeQz5a=Zf22ACPP!yIYK zbi@2cXb=wZF~rn!E{}||nS~&Ye=0S@hQ3Df!570~I%*5SkWzr5Qxj9~t(S!${84Hr zgd^BSA(&08i#JPGbLwFNQ<_uI_Vf$X$BpB*Kw!l-TIqIDCMH9@t<|w3s!{paE3ulV zQI7YyfGl5j2bcFet$aLWNe1Lu&rei9wDQZjGR?iuuKwHJz z;yk;XL3LyZ>J7Y}P?|fBrX~VSzXUqfcP8A*w??NnPw!@^(*JckawxR> zb=0qXI=wBkaBaHD?r8RSUOBk-uo>#a{L~SuKN7bJFst%UHx_}%7g*aEuaxdMb@WWQ z2~Z|WHEtS+@p%4#5Hs9VIK&oe(UfQk5;QsVrnB)>P;<0arqUGE9F~QCg#X6AWtCPX zfGZpsWD;vdxqK&xE-Ko^Gz~3Ib_H~0j&q&E;x^-hpdvV4oiGl#JLZ6A@E@4yftILd`AO<|0;KWrG><@RkSvWcZ`R4uXZnC(jwYa+ri0^T(#!J4Mz1+8_-EJX8g+8t&(O z{%5g+5dH7$s5?a(o-!J@7iJDT2bQx*9JvFoK`T{tw1EAxcEn5jK`=q{YU)+y>h&oFHgOUueR39y{W=~!|i zW5L|iV@3Womy=7xv&DY8RP$a7kHuZNU`=4K_}pePR^LWc3Imz?OLqWt2Fp;UNr*kGJCDhJ&~gH;_#7Y&7# z_8U9(;8myXcDel^jX*jNiwlX3jI+ouAYD)5F%}FV%OXh;xs8f->Fwsq>Lc5Ik*n?S zu!LuyF~Ob01N@o121PyBq>s4;AEwMj{>fH{>r(!=28vc>9Mh;0 z#|wgGgD*xJfU!}c(=8_0T57vBslbzdg$h;gI>2Q!c=^&sHz(!_^r1xa30MEH01XPf zl+BY1W4&YR+w7opH@`;`e%o;no@K0zb}%v2ZKRRG+|WN4X~-(x*N^anNrid++b48? zx2b?$fGDO2jewfbmWbVO4cG=Kf(=#^wMyD_JX4HNp2dj!FyRT>Aqs``KK#(=g2+#M z2qdRJqaS>mTOy$~;!j#i0}5aDMMYh54j@alY;vWdahRS39vn8U;p*o2^Mb!5xh|!$}2xCH55j%6?TukeJc)G z3TcSpWnxPD%EHXd%m9y~kWO40YsIR9bHq3uuMVfK$&!FW>)hH@zOdx=j|MFLXgxF! z^N#X_{0DEGshhzYC6g9zJkgw*Q%(hi2VWPw-)`4SZw@e-DK>p+c*efE44EW8kNKYp{lT)!qmM4C~pNU6Sh0zwwxTC#wjV{ac0Wacj zHXd|!RIGv%p|0H!QCw;O9jhXFlMxfH0h;611$@KtfcOc72^!*QRXTd6o1zZUfL^~m z@o!g_U4y?z%qJjL&(&^^r|m~R6}}f^*g3}W^2-UHL^gN)ABN9GNK(? zEqHthBP^l2BEUZAc1~S0x~y_cZ;k!w6&i-PiNTxC=&}f*1h=qb)e%d0PCK}N(i@bA z@JpF#qZ51(`S#H4 zD>|s`ki&zLK~akgpXg#=u0g8=43kzNeFv{hQ*PTy=E#JHL zLKIi@E0=c%7pV9TF)`{&=kX`;IJoF%kwTugxw;T%4i#~!EkUC5CUKW;V>+Xhg)r7F z$E4!j_&>sb$35yny<9P2=nyHpPmpahff}c#qroq@XHacbVVtJ8XUC$Tx$W{0hvLPO zkFgCUrBXSuL-7jA-k$g;*oCIQ8u2^RpnAg`MG3OAa&r%^i3|XEHSglfvP+a7 zUQTUFocG100$arwVuK6+enq$HIg# zn1$FXa>>WaRn86{Yv zN7JveATw4IIz6>dD!xr@e;~-sPPQUww?~ktW1WP2X$@4 zjxt|2S^3-9Q1!{Zwp!2x6s|=9RqE?a-jo!%cpeZ1?NVK7guo)Roj$g9Wp}jf_Y# z@jmFaN|XXJ^pg_t6O|b=u>zpZmGQb7;TDEsH^53&c@^@|OuB#sPJ%RE>AEsbLXW<8 zBQ%IifD-zpHab3!xSd6wCudGDodNl>CFfZ%s{FggGJR}tY0+AA^sx3)@z4VQio^cmg6*HnlCcO;KsS>Zf%!)2fBEIu8eklN`E730E zrI%&P$sK{secf$DVcUek>9v(Ip+aLz08MP9Or%lKg~$NsZH>ScMH(XS&?EXk*;8(f zC4@QuSoP7ug>FNoVT>p~b+v+zJV^lQ2Q>IN$kAsy=_xtX!h-T;+#98sJ&sIq)596N z(agt*deCS{*n$f0cPa+8bc;IVy8Lo!xS!XY zc|*%j$-D@fz+-K-lUvrvx70X(?oJ(;cLFt>}IFj%;_- z5W$7wq}nKTkQPOM`*F@(G>KREoTr0Vyv`2blS~k?C&)5w~ygi^_}QR zXlE90diOKKCSlGX*ZkH}pYD0BfstuCK?RQ@YAp-96uPI2LtUDbmI^0LrA7~`A|sU) zMf4dUnySaiDOvjHTLbb;LsBlqSbY`+H?#HOWV~~Gt?@Q-r2$r7pEaQ@!$UJA0r#Yx zEO~lJTdN?78+f8ZTs`-Ra3kkV-y+03jPLj(TZVr~S@s$qUD)&EswXq!m+8l!YGpFF zxC#@D4Eri`IRH}adOrEd0xK}5e9%sV+#F+2Nrcx-%BX$QdiD`}pXm0@{*Gc3n=h5S zz8y+%JZ|TmaJYG?44VnP@ht+x$`2wy``uD1f#IoNAPjg2z8oB(FM=QdqI#wZ9xr~? z!xxK4h!F6G`I1rPHL6To4OQkw(`;bc=)^G5q&vqEB^pFy!_hG?3kiHTwf?EWf}&(S zZ6D-?bn2La4VA(?X&TifZzA}7aIq)l$Ko@2*3okj#Q!Q5*qO2s7_9fhsk3oVO7XUE z{CeK3Z>)npWZ=a5r+0(+%G%)X@4JcG_!Z*aHS5U`XJ`TO)B_5hOoBQM9Rvn?E?|~_}{!?sCE>D@9AW*QICp%3>PLXlB zM=wQ?h;Y~)b(qos6BE;>tSzd-0uU3a(GK9u?=#A-j5o=m>-iX`I?{T){?xNE*zYfI z(@C?zLi~BFrTzFc*WTpxahnlSL!0hr;39zJqk9%%n^f+;K3_+$XEFTZhZ^P;o- zuuHVCK?Zg2-s9Yv;p5o(FnyOkki6TmPu}dZRc+`LEg~e?T}p}nG3qGDuJ8C zy*afUXF(kB*rbh={+D&oCMk&ZXeUiu?UTD|VYOu*H7E0wi?bI#vz=XEhcvpY*Qq3+ zTlFi_5^R9FuK@mkdK>;9yvRi+tX+#84TT5vS_$4%A9Di8f!lw=%FizTaR6Jq;JZE4 z+HQyZTwh*XK=?1HSLZol=uX8ZQEpLKlUSpBC2Qc%<|a1R3uTyL7aYejR*##my6XD- z)P_kv+6!@y%8femlIZKCp!t~ARt{871X;!-7MU8;dLQE~av5k?y6*L%RGc`tt&p(T z8Y%IfXZ;gtyKOELLuf$CO^F<@@K-Es_q1)Tv1rJ0$)f|YCBT9EV?6Ad+1s}Q>)ZJu zUX^`)_nA=JtaZL;+(A3ry7?4B)FeLDmkpfWHAtl5yAmjs0Ia1{C~ud@eX?zz)$gJ*VRVRD;TUWA7x=8d^wx8G7icNmTptaOrj`~p)B zHOl>I9l3JCl}x|ySCoVkGwPJyeVsCd3PhH9f+=6$w}1CUJNg2BAYH3sM?srGUZ;9m z0Xnp`6--S8(%6|Nl9PHyBsv8Q$tm6?0`}O5$8_<3Wn|j9HG@jdRp`IQBS%t*N#I!_ zdAZhL ziSf|$^s8SqJ~J7u3Z>s>jFus5KUKJKPHz6RjZ+MvQPlXb&mxS#-x^+X?)WI*RG6{8 z%&t}le`~n$O3$$o$yvRrpG%5E2!op~%%;YP>B;2;&7UkFoW$z6P!%PGgW#8hs8ulQ zQprA&^RNw7Yw~@^Xh!rNDpiAlKw}*-SFPqpF2)y)ma;#zb-J>%=<+dTf2CD4bjJ@+ zu@Fl=#H#?zj^=LTA`ly=^at;WFw*E}<)1$K~36 z@42sr8;ON|zB6+qTfTNclakRaBQ2$tGOHElLLXZ$X3Zqb&va=vw77uCtN7-t=2fH5 z#CrXQdKq{b(^69+CazL^=*pf0)EnVnVWsHE)BnB*p?u#pJb&b`ur z5|gJm5Wfub9_I3Ccx(x_Q7X1DYF*x%3F!D@98W0@Y3!G}&+8l4qRRSrZ<-bg;ndXF z6LHl9>SDLfG3eR2o+wpo)ZE2r)I8|!g{rju_^v0{x2BYuxW(@~jyrI_wQcpbXi`6( z7$7{~ymKiJp}j(w>K9X9e4ARRp8xVYA~mEB|I#+V4QAx)KDnR@dta5BU&c<0tnaY7 z8u=My?QrJZac+gYyKc=jXx5*Mk8DGu?^jty>r%BE_uE8Hpd0YENcGlD0NSqw2w__; z<7gLHDX|mJusDovTI+IW+Zks|z_(Dx*7PaviJ2PRjU4Brt)pB)gy5!MmN$L&6LtzQ5EGw;ZrkSa!w2Ruz0IJBzFU3Ws%qd6;blf zDd!s3swj4)78*AqDN{2xmMAU(7cZ%4Jq|GW2&g2!dth>gB+Fly2m~1ko-k|<2R=FZ z3m*81ftM@tO@Cx%-qg@_b#s9vsxHevB%AdD!FAs!8)Mk*SL(j9dQdHY`?+w@k(i1Q zl>N{i>@)S-@66-+;PbkywqJwwgF3f=LBRwB^%F6KWT+{_b%@n7?uQTgz-jCNge>!s zjbc+N^yT}bH~^d>9YC^iFi$Cl+E&l~M0J(%_j$57&NNB8*<(I-!kpwIDoNodkHdRz zZ$jZeCPS#d{5_%$Y#cVx-eU86eq{fKUiHSp(Lu%1P)~YZ(IM2-5JzGeAw@u@SJtd& zFv^0b*T3j*t;$0{R`tDeWJF|BqyW}l<$L51RdVk%#;DC77!LHh6_ISuAs7y1*}66? zFu8^8PEK9p^j!$Wmv1A9l4-YlMJ$qEf`QFDNa&HU%5`f9NEp#$AFvILuQVcIM$4BG z;uYBFCT|`2l}PbS`$Ygg?T$qGMZauqoiWtskt^ol3hHwa;jFY|XvxBiW4yqRO^SGh9ZNNZ0&B#b3~(LsO!A`%5oL z&p*?<{w=?x4hVyV`r=U>){tH7jqsF1y|#^x1fp2-6JkzC@Wj~|x>%e)`tRT;Re{uN zA(cV9x~W0+cn^bDjp+?$yW_VuX>$Ba=K<@}Ckr!J4PA1V7F z(`lTUCkuNiicycBh@XMw$P7e?mFS<@biENbSd0acHB@+Nefl6I7Z}RjOCZTp3ZG^9 z-7(7yaB0fZoR}GjjTu8l_3L4-rG-&1K|~k7iLF?uLoYz!kgi7tF}c$9w`P@WB|-4P zQ7CesWrvk4_7hNlb515%a51`WY7x^ zizA;2k7meokAlak-Jj165I$!|q?TI0`=ST^+97KwU=?{;Ecf0%ix*pXM0K6)Y;tMy zx3=`rI`$R%`IVs2k|4Ho%&N0_5wD7m*4DDqr3PPf)b{q%-Z2roYgGCWo|7%cZ=oM? zxh$jgaAhBMEt4WJ^MKZ%-GOztve)0db-^Ij3{mIM<)Xdow`|&mv!jq-<-aA4fUp@YeG^agiw(C;y@y|&@ z{qbu3kl`5Zj)T_qWQF;=`qb3mId#aMeX(FK$t2;^5E$tr_HWft;8Vi^LuHUXgKVr7 ze}(d$9kw_egxBQX{)!FtVCs{#|KU2fJHg&%xUl8jy24}=nce*&6YI^M`=2qC3**hn zn;u~2Gs2x+ps|TjbKBtP$qkr6!;fj}I;BN}aK)c0+ZC1$IDG05j%>2&Y zT(1+=IbAyy8NGfQ+>lQ?wxilfw=OVicrC>;x_p#Y%63A@AOKPfr0DkuK0AguNhr6h zn^$O6evIQ{RY*?-II(m+ugA5TE+-MsB>n3Tv9aPIby!Zu?QW2iWtv1g4^@6uQx2$? zi23oL(D$qFt~&56(&2s+HIPW0^Y9?f?C|Db`ig0Nz~OE^p4rdL@;*~n?)D#cv#KlB zgTrFt`;RNB~f%f*1>q$Gh;e?2cdD<)HM1$Zfv#KblX) z{wXRMEm@b;YknfCa&v>>*IhK{5Ii1w65qFgxNbaqTAnW(^yph`op!$p-cB422@f|M z(8i)7$g)}x{l0}FE%h_DDRaO4%+HJ()NCQ`tYhAf{J3+Gl!wEk@yIOZr^G5q!-@B~ zxwl3lGD6)1xy`Ds5_d@(dgdbiPT_3X`enDeV2j@G*!+BVUh#30UU51!sp8N)@}6y& z(GSvCFDV@#NckCk$0WY)O_Kk;!TbB?_VzaY?`P3N&h46 zp?Iw=4JE%5|LyfWHEsCLy2Jh*qw^icm*2O?|8X2JN__RW4}RtM)IFYy5_Z0DY4!K8 zG(x`(l#7&4Ju9gE?353GS%S^7b9TmpwGNM7gml<6WB4ssv7ervPUUj;D~sxca$o`> zpIP`+Dg8(@!Z6}r!-KX@NQ1+46Z^vnjV|Wa{JviN+i0V1ufwIARE++JMNkO?2tsd4 z|35U8F&J^aZ==>w)=J#H%=T_ySe9`UaX{jG_IoUZ@XТретий `next(9)` передаёт `9` в генератор как результат второго `yield` и возобновляет выполнение, которое завершается окончанием функции, так что `done: true`. -Получается "пинг-понг": каждый `next(value)` передаёт в генератор значение, которое становится результатом текущего `yield`, возобновляет выполнение и получает выражение из следующего `yield`. +Получается "пинг-понг": каждый `next(value)` передаёт в генератор значение, которое становится результатом текущего `yield`, возобновляет выполнение и получает выражение из следующего `yield`. Исключением является первый вызов `next`, который не может передать значение в генератор, т.к. ещё не было ни одного `yield`. + +На рисунке ниже изображены шаги 3-4 из примера: -Исключением является первый вызов `next`, который не может передать значение в генератор, т.к. ещё не было ни одного `yield`. ## generator.throw @@ -366,8 +368,6 @@ alert( generator.next(9).done ); // true ...Но "вернуть" можно не только результат, но и ошибку! -Как и любая операция, `yield` может завершиться со значением, либо сгенерировать исключение. И то и то -- разновидность результата. - Для того, чтобы передать в `yield` ошибку, используется вызов `generator.throw(err)`. При этом на строке с `yield` возникает исключение. Например, в коде ниже обращение к внешнему коду `yield "Сколько будет 2 + 2"` завершится с ошибкой: @@ -380,9 +380,9 @@ alert( generator.next(9).done ); // true function* gen() { try { // в этой строке возникнет ошибка - let result = yield "Сколько будет 2 + 2?"; + let result = yield "Сколько будет 2 + 2?"; // (**) - alert("не сработает, так как ошибка выпадет в try..catch"); + alert("выше будет исключение ^^^"); } catch(e) { alert(e); // выведет ошибку } @@ -397,9 +397,9 @@ generator.throw(new Error("ответ не найден в моей базе д */!* ``` -"Вброшенная" в строке `(*)` ошибка возникает в строке с `yield` и обрабатывается как обычно. В примере выше она перехватывается `try..catch` и выводится. +"Вброшенная" в строке `(*)` ошибка возникает в строке с `yield` `(**)`. Далее она обрабатывается как обычно. В примере выше она перехватывается `try..catch` и выводится. -Если её не перехватить, то она "выпадет" из генератора. По стеку ближайший вызов, который инициировал выполнение -- это строка с `.throw`. Можно перехватить её там, как и продемонстрировано в примере ниже: +Если ошибку не перехватить, то она "выпадет" из генератора. По стеку ближайший вызов, который инициировал выполнение -- это строка с `.throw`. Можно перехватить её там, как и продемонстрировано в примере ниже: ```js @@ -426,7 +426,7 @@ try { Если же ошибка и там не перехвачена, то дальше -- как обычно, либо `try..catch` снаружи, либо она "повалит" скрипт. -# Плоский асинхронный код +## Плоский асинхронный код Одна из основных областей применения генераторов -- написание "плоского" асинхронного кода. @@ -493,9 +493,13 @@ execute( showUserAvatar() ); Вместе с тем, это -- всего лишь набросок, чтобы было понятно, как такая функция в принципе работает. Есть уже готовые реализации, обладающие большим количеством возможностей. -Одна из самых известных -- это библиотека [co](https://github.com/tj/co). +Одна из самых известных -- это библиотека [co](https://github.com/tj/co), которую мы рассмотрим далее. -Её нужно подключить (через `npm` или https://cdnjs.cloudflare.com/ajax/libs/co/4.1.0/index.min.js), после чего запускаем её с функцией-генератором, вот так: +## Библиотека "co" + +Библиотека `co`, как и `execute` в примере выше, получает генератор и выполняет его. + +Начнём сразу с примера, а потом -- детали и полезные возможности: ```js //+ run @@ -513,7 +517,8 @@ co(function*() { }) ``` -Библиотека `co`, как и `executor` выше, выполняет генератор, получает из него промисы и возвращает обратно их результаты. В примере выше `function*()` делает `yield` промиса с `setTimeout`, который через секунду возвращает `1`. + +Предполагается, что библиотека `co` подключена к странице , например, отсюда: [](http://cdnjs.com/libraries/co/). В примере выше `function*()` делает `yield` промиса с `setTimeout`, который через секунду возвращает `1`. Вызов `co(…)` возвращает промис с результатом генератора. Если в примере выше `function*()` что-то возвратит, то это можно будет получить через `.then` в результате `co`: @@ -561,19 +566,17 @@ co(function*() { [/warn] -**Библиотека `co` может работать не только с генераторами.** - -Есть несколько видов значений, которые умеет обрабатывать `co`: +Библиотека `co` умеет выполнять не только промисы. Есть несколько видов значений, которые можно `yield`, и их обработает `co`:
    -
  • Объект-генератор -- выполняется описанным выше способом.
  • +
  • Промис.
  • +
  • Объект-генератор.
  • Функция-генератор `function*()` -- `co` её выполнит, затем выполнит полученный генератор.
  • -
  • Промис -- `co` вернёт его (на самом деле новый промис, но он вернёт этот).
  • -
  • Функция с единственным аргументом вида `function(callback)` -- библиотека `co` её запустит со своей функцией-`callback` и будет ожидать, что при ошибке она вызовет `callback(err)`, а при успешном выполнении -- `callback(null, result)`, то есть в первом аргументе -- будет ошибка (если есть), а втором -- результат (если нет ошибки). После чего результат будет передан в генератор.
  • +
  • Функция с единственным аргументом вида `function(callback)` -- библиотека `co` её запустит со своей функцией-`callback` и будет ожидать, что при ошибке она вызовет `callback(err)`, а при успешном выполнении -- `callback(null, result)`. То есть, в первом аргументе -- будет ошибка (если есть), а втором -- результат (если нет ошибки). После чего результат будет передан в генератор.
  • Массив или объект из вышеперечисленного. При этом все задачи будут выполнены параллельно, и результат, в той же структуре, будет выдан наружу.
-В примере ниже происходит `yield` всех этих видов значений: +В примере ниже происходит `yield` всех этих видов значений. Библиотека `co` обеспечивает их выполнение и возврат результата в генератор: ```js //+ run @@ -596,7 +599,7 @@ co(function*() { result = yield Promise.resolve(3); // промис result = yield function(callback) { // function(callback) - callback(null, 4); + setTimeout(() => callback(null, 4), 1000); }; @@ -613,18 +616,28 @@ co(function*() { }); ``` -Библиотека `co` обрабатывает результаты рекурсивно. То есть, если в результате `yield` получается генератор, то он тоже выполняется библиотекой `co`, и так далее. +[smart header="Устаревший `yield function(callback)`"] +Отдельно заметим вариант с `yield function(callback)`. Такие функции (с единственным-аргументом callback'ом) называют "thunk". -Звучит это сложнее, чем на самом деле. Практическое следствие простое -- мы можем использовать `yield` во вложенных вызовах функций. +Функция обязана выполниться и вызвать (асинхронно) либо `callback(err)` с ошибкой, либо `callback(null, result)` с результатом. -Например: +Этот способ использования является устаревшим, так как там, где можно использовать `yield function(callback)`, можно использовать и промисы. При этом промисы мощнее. Но в старом коде его ещё можно встретить. +[/smart] + + +Посмотрим пример посложнее, с композицией генераторов: ```js //+ run 'use strict'; +co(function*() { + let result = yield* gen(); + alert(result); // hello +}); + function* gen() { - return yield gen2(); + return yield* gen2(); } function* gen2() { @@ -633,17 +646,25 @@ function* gen2() { ); return result; } +``` + +Это -- отличный вариант для библиотеки `co`. Композиция `yield* gen()` вызывает `gen()` в потоке внешнего генератора. Аналогично делает и `yield* gen()`. + +Поэтому `yield new Promise` из `gen2()` попадает напрямую в библиотеку `co`, как еслы бы он был сделан так: + +```js +//+ run +'use strict'; co(function*() { - let result = yield gen(); + // gen() и затем gen2 встраиваются во внешний генератор + let result = yield new Promise( + resolve => setTimeout(resolve, 1000, 'hello') + ); alert(result); // hello }); ``` -В примере выше: первый `yield` возвращет генератор `gen()`, при его выполнении `yield'ится` генератор `gen2()`, внутри которого `yield'ится` промис, который завершается с `"hello"`. - -Библиотека `co` при этом -- только на самом верхнем уровне. - Пример `showUserAvatar()` можно переписать с использованием `co` вот так: ```js @@ -687,13 +708,11 @@ function* showUserAvatar() { let avatarUrl; -*!* try { avatarUrl = yield* fetchAvatar('/article/generator/user.json'); } catch(e) { avatarUrl = '/article/generator/anon.png'; } -*/!* let img = new Image(); img.src = avatarUrl; @@ -710,15 +729,155 @@ function* showUserAvatar() { co(showUserAvatar); ``` -Заметим, что для перехвата ошибок при получении аватара используется `try..catch` вокруг `yield* fetchAvatar`. Несмотря на то, что операции -- асинхронные, мы можем использовать обычный `try..catch`. И это очень удобно! +Заметим, что для перехвата ошибок при получении аватара используется `try..catch` вокруг `yield* fetchAvatar`: -TODO +```js +try { + avatarUrl = yield* fetchAvatar('/article/generator/user.json'); +} catch(e) { + avatarUrl = '/article/generator/anon.png'; +} +``` +Это -- одно из главных удобств использования генераторов. Несмотря на то, что операции `fetch` -- асинхронные, мы можем использовать обычный `try..catch` для обработки ошибок в них. +## Для генераторов -- только yield* +Библиотека `co` технически позволяет писать код так: +```js +let user = yield fetchUser(url); +// вместо +// let user = yield* fetchUser(url); +``` +То есть, можно сделать `yield` генератора, `co()` его выполнит и передаст значение обратно. Как мы видели выше, библиотека `co` -- довольно всеядна, поэтому будет работать и так и эдак. +Однако, рекомендуется использовать для вызова функций-генераторов именно `yield*`. +Причин для этого несколько: +
    +
  1. Делегирование генераторов `yield*` -- это встроенный механизм JavaScript. Вместо возвращения значения обратно в `co`, выполнения кода библиотеки... Мы просто используем возможности языка. Это правильнее.
  2. +
  3. Поскольку не происходит лишних вызовов, это быстрее по производительности.
  4. +
  5. И, наконец, пожалуй, самое приятное -- делегирование генераторов не портит стек.
  6. +
+Проиллюстрируем последнее на примере: + +```js +//+ run +'use strict'; + +co(function*() { + +*!* + // при запуске в стеке не будет видно этой строки + yield g(); // (*) +*/!* + +}).catch(function(err) { + alert(err.stack); +}); + +function* g() { + throw new Error("my error"); +} +``` + +При запуске этого кода стек может выглядеть примерно так: +```js +*!* +at g (eval at runJS …, :13:9) +*/!* + at GeneratorFunctionPrototype.next (native) + at onFulfilled (…/co/…/index.min.js:1:1136) + at …/co/…/index.min.js:1:1076 + at co (…/co/…/index.min.js:1:1039) + at toPromise (…/co/…/index.min.js:1:1740) + at next (…/co/…/index.min.js:1:1351) + at onFulfilled (…/co/…/index.min.js:1:1172) + at …/co/…/index.min.js:1:1076 + at co (…/co/…/index.min.js:1:1039) +``` + +Детали здесь не имеют значения, самое важное -- почти весь стек находится внутри библиотеки `co`. + +Из оригинального скрипта там только одна строка (первая): +```js +at g (eval at runJS …, :13:9) +``` + +То есть, стек говорит, что ошибка возникла в строке `13`: +```js +// строка 13 из кода выше +throw new Error("my error"); +``` + +Что ж, спасибо. Но как мы оказались на этой строке? Об этом в стеке нет ни слова! + +Заменим в строке `(*)` вызов `yield` на `yield*`: + +```js +//+ run +'use strict'; + +co(function*() { + +*!* + // заменили yield на yield* + yield* g(); // (*) +*/!* + +}).catch(function(err) { + alert(err.stack); +}); + +function* g() { + throw new Error("my error"); +} +``` + +Пример стека теперь: +```js +*!* +at g (eval at runJS …, :13:9) +*/!* + at GeneratorFunctionPrototype.next (native) +*!* + at eval (eval at runJS …, :6:10) +*/!* + at GeneratorFunctionPrototype.next (native) + at onFulfilled (…/co/…/index.min.js:1:1136) + at …/co/…/index.min.js:1:1076 + at co (…/co/…/index.min.js:1:1039) +*!* + at eval (eval at runJS …, :3:1) +*/!* + at eval (native) + at runJS (…) +``` + +Если очистить от вспомогательных вызовов, то эти строки -- как раз то, что нам надо: +```js +at g (eval at runJS …, :13:9) + at eval (eval at runJS …, :6:10) + at eval (eval at runJS …, :3:1) +``` + +Теперь видно, что (читаем снизу) исходный вызов был в строке `3`, далее -- вложенный в строке `6`, и затем произошла ошибка была в строке `13`. + +Почему вариант с простым `yield` не работает -- достаточно очевидно, если внимательно посмотреть на код и воспроизвести в уме, как он работает. Оставляем это упражнение вдумчивому читателю. + +Итого, рекомендация уже достаточно обоснована -- при запуске вложенных генераторов используем `yield*`. + +## Итого + +
    +
  • Генераторы создаются при помощи функций-генераторов `function*(…) {…}`.
  • +
  • Внутри генераторов и только них разрешён оператор `yield`. Это иногда создаёт недобства, поскольку в коллбэках `.map/.forEach` сделать `yield` нельзя. Впрочем, можно сделать `yield` массива (при использовании `co`).
  • +
  • Внешний код и генератор обмениваются промежуточными результатами посредством вызовов `next/yield`.
  • +
  • Генераторы позволяют писать плоский асинхронный код, при помощи библиотки `co`.
  • +
+ +Что касается кросс-браузерной поддержки -- она стремительно приближается. Пока же можно использовать генераторы вместе с [Babel](https://babeljs.io). [head]