pax_global_header00006660000000000000000000000064134054701760014521gustar00rootroot0000000000000052 comment=9f6521b4a97664b2270b01de1f44a371a425e298 terkelg-globrex-47e816f/000077500000000000000000000000001340547017600151645ustar00rootroot00000000000000terkelg-globrex-47e816f/.gitignore000066400000000000000000000000271340547017600171530ustar00rootroot00000000000000node_modules .DS_Store terkelg-globrex-47e816f/.travis.yml000066400000000000000000000000411340547017600172700ustar00rootroot00000000000000language: node_js node_js: - 8 terkelg-globrex-47e816f/appveyor.yml000066400000000000000000000003361340547017600175560ustar00rootroot00000000000000environment: nodejs_version: "8" install: - ps: Install-Product node $env:nodejs_version - npm install --global npm@latest - npm install test_script: - node --version - npm --version - npm test build: off terkelg-globrex-47e816f/globrex.png000066400000000000000000000541261340547017600173440ustar00rootroot00000000000000‰PNG  IHDRè�=MJa IDATxœìÝyümÕüÇñ×mt+š…QD"Z*¢2TæRI$Mj—’-i`ÑDƒÕ¤hŠ„¨¤I£²Š"¥AŠŠæyîþþØ»Ÿo·ïp†½÷g�sÞÏÇã>pï÷ìõö½÷{ÎþìµÖg�ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÈ`™f`̘1Ã:‚ˆˆ  àâ"ÀÆÀÀòÀÂÀ¬Õ?Üü¸øp%ð'ŸŠGÚO+""ÃnÚ4•�MÓw¸*ÐGOpñ•À�…€ùªß~x’ò¦úñê×ýÀ>ÿ±È)"y .N¾ ìLïòåÏW¿ÎÎñ©x°Ö€""2’T 7Oßá¨@ ÁÅ¥€M�õ€×tùò§€;�7RΆÝ@y“}£O…þ‰Œ�àâqÀgjºÜ3À%À/€ŸùTÜRÓuEDdĨ@ož¾Ã-P�>Ü‚‹ ûS.C�uŠ/ïŃ@.Î.ò©x¼�qD$ÁÅM€câJàà§>768Žˆˆ èÍÓw¸*ЇWpñ�À™À+Zö à"à§”³awµ8¶ˆ4(¸8p+°HKCþ8ø¡ÞKDDd**Л§ïp T §àâ¢ÀŸ(÷™[y’r&ìÛ>Wæ‘×N6úiÊ%ðѧâ|ƒñEDd¨@ož¾Ã-P�>œ‚‹'Zçã$`{Í‚‰ ®àâÑÀç�cüÀ)>Ïg‘Œ¨@oÞ,ÖDQpq>`]ë3ùpupq%ë "Ò³7X–~\_Í苈ˆHKô¤šA>ÁÅÕ€ó¬sLàA`%ŸŠë¬ƒÈp .¾Xø à€¥�¹�À-”� ONó©xÔ(æ@ .^¬b�c&›ûT\oDDDli½yšAéMÎ?;/ް!Ã+¸¸Ppq_àvÊ›ËSçP>ü}å�·¿\\Ð"Ô:À8V® .naDDDdØå\dˆäì çÁw_eB†Kpq¶àâ—)gÇwæïð¥ó;7?ÕP¼aqå „ÜLެ̈ˆˆHC´F¡Zâ>œ‚‹G9Ï(­åSq†uˆ\§oÖV§<·þ Êc­®Î’OųV9s\\ø1åRö~låSñd ×:ÁÅÀ/Xç˜ÄÎ>û[‡‘öi‰{óôn� ôá\\žò˜µ\½GÇ%Apq:°%°-ðê^r p4p¨OÅý FÁÅ�'óÔxÙK€�êÔ�ªšPþx…u– < ,ëSq“ui— ôæi‰»H�|*þ Ül�c3(�JiÁÅ �€é¬8XøpKpq·ªÚÈ .îœJ½Å9À;�ß«ùº¯z0´¥uŽIÌ|Ü:„ˆˆÈ0R�.ÒŸÛ¬LàrŸŠ»­CX .Î\üåÙð‹öx™y)Ï‚þKpqÕÚ �àâÞÀwhî³âuÀ%ÁÅ¥ºþÀò©8ø•uŽIÌj@DDd©@N§Y°\|#å~òºfø–..†àâÈ%Áů»·0ÔâÀYšI×7­LâVë"""ÃHºÈpú‰u ÁÅÕ�‹€WÖ|éiÀn”…ä5_;;ÁÅ�¯¶8äRÀùÁÅ—µ8æ ¸Ü:À$η ""2ŒT ‹ Ÿ‹|*þa¢mÁÅgPžß”Õ�Kƒ‹�îg8ÁÅO ½pvpq^ƒ±³”ñiWùTÜnBDDd©@>'Xh[pq5à§Àì- ÷Zà²j)ýP .¾ 8Ö0ÂrÀ¯G½1ß8Ú:€ˆˆÈ°R�.2\žN¶Ѧà⛀_ÐNqþœ…�s‡©H.. ü ˜neeà„êÜzÉÏÔGˆHT ‹ —4Jgw§ùeíYˆ²H_Î`ìZUÍï~ äÒ¨m]`_ë2®|*´!""2¬T ‹ —s¬´%¸8å²öWÆX83¸ø*à uØx¯uˆ™ì\ÜÄ:„¼Àw­ˆˆˆ 3è"Ãå"ë-:x›uÊsÖÏÔîîÁÅw{Yç˜À÷‚‹«X‡�ÿwžOÅ߬Cˆˆˆ 3è"Ãå ëm.~ø‚uŽ1–~YÍêŒàâ\Àñ@®ç»Ïœª3Ò³q¼u‘a§]dxüÓ§â¿Ö!š\|p¸uŽq¬ f¢Kß–¶1……�Ûl(/ô8å–i� t‘áq•u€¦ç¦ìR?—u– |>¸¸­uˆNW¶³ÎÑ¡•�oY‡qçûTë#ì,ë"""£@ºÈð¸Æ:@“ªâl ë˜ 8¹:WÓÄ…ƒ‹ [4qí ]a@DDD¤.*ÐE$'�.ûÎз‚‹/nàº_Z=ÎÍÈãÀiÖ!DDDDê¢]Dròzë-{9°[� .ÎlUç53v„O…–¸‹ˆˆÈÐP�."9y¹u;TÇ¡Õe;`Þ¯—«‡€`BDDD¤N*ÐE$'£ÐÔlfsß®ãBÕòÛÕq­°¿OÅÝÖ!DDDDê4›u‘1îµ`ä£ÁÅ÷úTœÛçu¶¬#Pæî´!õ ..,Lyorp»OÅ3¶©DDDÚ¥]Drr³uCßâSñt//.Nv¬9S®¾áSñ°uéOpqà£Àê” "gn˜øDpñZà÷À}*žh7¥ˆ šà⬔ï'Oë³B‘ tiMÕ¼ji`àIànà6ŸŠÇLƒIN.¶`h9Ê£Ñëñõ›/«-M¾n¾gBz\œ ØøðŽ)¾|Nà-Õ¯/O¢OEj4¨¡ê{4e/‰iÀ ààqŸŠÇ-³M¦:‘âÃÀâÀ#À-Àe>wYæ’Ñ\\XŸò�ß�Y«ß¿88xÐWäçV¦l¨»TõkÊÉ�Ë€ßùTÜf—Pê2Í:À(˜1c†uSÁÅ¥€ƒ€µÿßÜmÀµ”o.—𩸿½„½ .ž¼Û:°—OÅžÖ!ú\œ¸ƒÑX¦=ž{�¥}*îëæEÁÅ9€)oŒ‡Ýú>'[‡hKp1—�ùûy_®ŠÎÏ»SÏ¿ÓK(ß÷~[õÌç¤ülü 僈¥™¼Éã“”Ÿ™ÿ¬~ý¸¸Ê§âöfÓN,¸ø^àDÆoôùàÇÀqݾ·‰L¦úìû4eï•å§øòƒ|*vh>U½Æ¼wn¼•©û‡ý8ƒògî>µ†L›¦ò±iú·`” ôàâ²ÀÀB]¼lpp.ð[àŸŠGˆ×7èõ .lk�ÃÐw}*ºjô\Ü8¦™8YIÀŠMÜpäj ôàâšÀ!Àëê�ÀùÀ>jàÚ� .N6ö¢¾•/ÿ® üì<¸¦�Ÿ•àâ‡�Ÿ2u“ÏG�ã€}|*nm:— ¯ª0ß Ø•ÎøÍ–󩸶±`5 .Îüx�—¸ø p’OÅ_êÊ¥½yú· ÷=¸¸ð1þ÷~àvʛ៧÷²/¶zêw%åR£~< \Hù&õkŸŠëû¼^mT ×/¸øzௌîûÓ3À›:½‰¨>À¯§œyv«úT\d¢Mƒ\ ¾K¹ì´IÏRn{ØÅ§âÁ†Çê[õÙx°^ÃCÝœ œ ü¦‰ídÁÅwR> xQ/{8ØÛ§bTƒJª[ßz9žô'>Ô›ª9ÁÅ5(†ëpp$å÷ ¯}ù*Л§ïp r,ЫkQîyý“÷#¸‰òÍðÄn õàâÆÀñýäœÀ_€“�S|*®kàúS�ÞŒàâ±Àg­sú­OEGÕ‹?j8O~æS±®uˆ¶ j�\\8œîVOõë6`³Ü—½#°MËÃ>BùÀýGÀ™>Ïö{Áàâ+€«€—öx‰û€¯GúÞà‰T©Þ ¼–r¿ð‚À|ÀÜ”cï­~ÝÜ\ÜPÇßϰ .¾�r»äT½+&3P³èÁÅ(—ð×éaÊ÷�#{í塽yú· §½êô¼ðe`‰._þG`ãN‹âàâ%ô÷FÚ‰çŠõ|*nix¬P�ÞŒàâ«)ÿn§[g1ôŸŠ_NöÕlŸé•Jîž^çS1r]þ­@.ÎEÙ�i³æ#Mè@`WŸŠ' 3Œ+¸øVàrlï¿n¡ü;:²×Yõê!ÿ¹À»jÈóGàó>W×p-SÕ÷åÝ”«ß¼¦‡ËOuú"èÍ›ªÑ€ ‰àâlÁÅ/P6”9„î‹s(Ÿÿ)¸8åþààâki¾8‡²óõÞÀÍÁųƒ‹­–üÊ« ±Ý¬sûvµÏn2aø‹s€CF±84ÕûþØç;—Vúróì'G–¤¼)¿>¸øÑ¯±+õçPÞ[¤àâÞU£Ð�\|ypqOʇç½çPή¯ |�²yGß3j÷7ÁÅ )·pÕùs³Qpqþš®Õ¤OÐlq°"åv›w�ïËH©ôQ\|7p5åñM‹ôy¹9�C‚‹'çžäë6ésœnMÖ \Âw}pq“jŸŸ ®C(gFÕÒÀöS|ÍWÚbìÊ-6’±ªQØ�e­³TV ,ú>ld&°0ÆâÀσ‹U«q:\|3𵚳ÌFÙáÿ²ªÉ@..\<ˆ²×Àb ³ åvÄs�¿S­ÄZÁÅ¥‚‹¿¥,û½o�ÙtÊïgî6iq¬E�}€Û‚‹1¸ØË$žÔÈú)îH°Zâ\œ‡ò)yS³>æSqÃLãÎÜJùoéÊesW45€–¸7+¸ø2Êf…¯°Îbä!à5>ÿ™ù‚‹ïÎl?Rë ŸŠC­CX„%îÁÅ]�o’ï=Åž” ÉL¿—Õ~äÿZf˜ÄN>LõEÕîË)€4åq`kŸŠlO¦¨¾[Qþ»‰QŒ?‡?ö©xÜ(C­ªûÇí(¿¯Mnq{x­OE–?�ÁÅ%)úX½§>|ŸòÞòΙÿPKÜ›§ô!\\‰roj“K ßü1¸ø¡™~ ì‹s(—þ^ÔÇ>1V}0|‚òÃb½˜òFe<£0{~e×YÉPpqŽª¡ã·È·8‡²@?®ƒ-#M[ÀxüÉtz´ã¶4[œCÙþÁÅc«¾9Y©¶N\DìŠs(·C9«îƒ‹ófé[µEæʉ¥¦ÿÞç¥ÜB�«ý±}O��òÔ ÁÅÝuëÉ S�>„‚‹[Q~x´±ÿî%À/ª‡çÞL>Ó¸�š8!¸Øk—Y1æSq°!åQJ£èsÁE7ö7‚‹«�ÇÊ�¦}©—#¥yÁÅ—¿bpN[Ø8­jbgå ñ§²øÛÖ..J»ÛM> \\|y‹cN*¸øIÊÉ�6zìtjAÊ¿—Û‚‹ßÄB=¸¸%å‰+µ8ìæÕv�¬×r9±d W—³3JT ‘àâ¬ÁÅÃ(�¶iói×4ʇ“«Ò�·8v'æv±!½ó©ø°¥u#Ó€ƒgÚ#úU«0-úµOÅÖ!ä…ª¥Úï³ÎÒ¥§[éÕI#]�%ߢgª_“ù6e³6­\\ìµáZ-‚‹Ó‚‹_~ByO‘£yÜ\Ü1ƒ#S .Î\ü9pÍ7D›Ù4Ê^7Ù¨Þ[³Î1Žå(ûC¼×:ȨP�>$ªŽÓ(;]ZY¸–<�ÆÚ<Ç¥rÒ9ŸŠ£Ý-+T³é�‘>Àždêyb ¸¸p�ÝÌS‡ÞœjX¼\e4îT®žlsÕlvýóŒµp‰Õ ^µßü8çÁè‚ÀÀÕÁÅ5¬ÃL$¸¸p%`¹ qÕà¢Õ¿ëñ,dbsS¾wÎkd¨@Uq~:°Žu ×¥U/V·!ýñ©Ø�¼÷�5i¿êg}wë -8ЧâFëò|ÁÅ¥�K�×ZgéÓû)÷8[ìñü“Á˜�øíDP5î:°Å,ãY8³jžÕšêAÎO)·H še€³ƒ‹'´3Vpq]Ê}KG�ò³Õ|'³¥í™—²÷�4Lú€Sœ¿Ç:ËЛÊð©øö7‹Žr;6ªn·Sîy“¼, œO3ÇHY؈òX¬¶å:ƒ>Ù‰ŸÞÒV�I, œ\œ³�Áª™óã±�á­ÃF”³ék[.~8…|V[.ìl ã¥íãÉ¡ ôÐS�>ÀÆ<ÙUqÞ™\g÷¥{;GY‡0°!ywË®Ã.>Y‡�8ƒá»1ÛÃàœô ô{)˾@uŸ‘Óª¥·ÒÞ ‡b·¬¿n¯ ì¿°pq6«ÁÅÏ‘g!ºKpqqÃñs^Ú>³{­Œèƒíhʦ7Ò™œ;èJªóŒ¿œd�Eju)ðCë2®A¹yìÖñ-ߘ_G~ŸE¿ò©˜¨AÜÖä± y¬�ªS\Ü‘álLúeà¼àâ"m\|ù›9ØÏbàYÚ>Ö_­Œè*¸¸ƒ¹'ÊRŽ3Ò£ê†rÊ£ždðͶ­¾ˆ´e^Ê3Ò[¹ªŽ ¼¦�±ºpÚx¿Y5ƒÊ±1Ú\@c˵ƒ‹kaT¬µdàÁÅe[w+Ú=a¨[TG˜¶fÀ–¶\ãSñë£@ú .®ƒöhvëʽú2D|*ž¢|ò|®uéÛÑ>É:„Œ¤÷Û´8^N�âΚàÏv¢ìž£FŽ] ..œÈðß¿’²3þj-ŽùëÇêÕ!m=¬« ÒÒv€oYÃþ4t‚‹¯N°Î1€öõ©xØ:„ÔϧâIÊ&>´Î"=»ØÍ:„Œ´o´¸ì7§Õ\gùT<6óo_|É O§jß&\œ�òœóùë¾v¦æ~ÓÖÙÖ>gßic¬>¼Ø´��piûYÀ�­CŒ èḋ‡š�uçà»Ö!¤9US±µ€ë­³HOvó©¸Û:„Œ´—ÐÞ²æœ ôq—·{‘O—íñœ×À5=ðö®›³é”ÍãÚZÚýàâ–ÆêUhú¬ï\Úþw`cmAk� ôÁ²':*¬;ûT@ÞÓ· .¾¶‰ ØÒöß«úTüË:ȨQ�>‚‹sR©¦¿¯î©™Þˆñ©øðÊæG’·ïùT¨w€ää£Õ rÓîlaŒ®UK�?f�cw_¤œÉ{ æko¼¹æk¢ÍÚȧâFÊí¹nK›8°î‹ØÒö�øTèÜs*øîÀ¬C  ›�3¬CHû|*.AÇæîÔN:ó4es¢¶}n×Ò8Y .Nö·Î1“Ç(÷ÿڧâ�IÎkïIÕ oÏ:¯9ÀVnó|ôjVvE ×UŽk?Xó5aiûÀg}*¾T÷Ï›tNzæ‚‹¯BKÛ{õ5´]>?v±Î!ÚEOæe O‡¯ò©Ø�rïv>\Åf¬ë‘W“´Ÿ¯÷©Ø³ÁSXö^ÜеÍ4Ê-b­©¼nD{?ÛÝ:°jÐÜ·YÚ~;ð.ŸŠã­ƒŒ:èù;x‘uˆqûQî-”¼\üÀ:„dí$`iŸŠ/ŽÙÿxcKcÏEY¬ŽŒªAXNgâSñqŸŠ65@pqy´Òjf«·= OÅS”ËësìE² Pô{‘YÚ~ðÖº0JoF¹!Föª³)?b�c&ÏRîëÞϧâáàâj”˜_cšj|ÿ± ÿ\œ¼x=°$°(e·ÔE�…�y(»ÉÎÌ=ÓËž¤\êzÿ˜_÷Mò¿ŸûïßV£l‚#öž¥l §Õ-2ž¿ÛøTŒ÷€µÍ¦RGµ8žµm€W[‡¨üƒò8®¦íG9k,ÿ³†Å >Wv° {èSñß>®‘ûÒöc€/øTŒy€ÿ= ¹‹ò!Ý¿�ÿj/]öžööžä&±îæ`“yWpq±Qè^\-çoúX©n|Þ§âÑ&¨&Þ×ä=ºŽ²)ð À§ Æ_,¸¸¨O…E‡õÝ).i0ödæ¾lÙË‹3_Ú>ØÞ§âë ò|*Ðóµà¬CÌd×±Åùs|*î .n\޶MŒ¼êHÀ­€OPΊ‹tkŽê×sèóz3‚‹·Qv þp%p¶OÅí}^Wêq3°�OÅS|]›³;Ó€µ�#[ÓÊW�ù­CTó©8¯…qölaŒn}‡²7ÇÓÁÅ¥°)С¼÷l½@÷©x$¸¸pfÛcw`óàâá>êæE°´ý[*Îó¤b*CÁÅYÉïÃã<à€‰þЧ"'¶Gr\\!¸xp)ðYTœK>¦KP®æØ8øwpñ²àâ[,ƒ ?Vè 8‡vgÐêîàœ�ªí¶Ö9*·ÑBSÜàâ{€w7=N—¾âS±£OÅÓ>7QnÓ²ðV£qñ©8‹<ï%§Q6¬ìVÎKÛ/ö°!ãS�ž§�)÷éæâ `ËöŒÑFÉKpq–àâž”+(ÞkG¤+çßhd= lçS±AçZ·Ý·`õàâ°¯4 <µŠ¥Íª®ÞMó-ŒÑ�ƒ}*öç÷om=IÉzõæÀÝÆƳjpqýN¿8ó¥í÷P®ZzÚ:ˆŒOzf‚‹³ÐNs”nìëSqCŸ\µ IDAT_wesÕj�Q>…�Õ8ŽH/æÎ..md„ܼϧâ»ÖA¦0ðfë ÛÐ:@åhŸŠß6=Hpñ­t*ŸÄùÀ—'ø3«“rL tŸŠ»É³YÀ~U�I ÀÒö�G¡¿Æ S�žŸ�¯µ1Æ=Àþ�|a5Ãþ‹fãHf>iB¤O‹¿ .ªaó®£<ʧ—}Æs:|XÝÎÄEjÝvjiœNÜ |z’Y̶·tT$¯N«Îƒ–f\¼Ó§â–_ÿâ³tê�cŽš-ºØæÐ³à⢔“ ¹ØzŠnéÝÜ{ÕmyñŸ³%ðˆuˆqì\\b¢? .~Œ|—¶_F~[Oöy�ùêÓ¥eF Qœ•ÿ;¶1Ppqv`ó6ÆêÀ£äÓ9"o²Pù.ÐÉ m[?¸¸ê8¿å–©}֧ªñ tIz&‚‹/>f�cŒÇé½ÁÅMu‘,iÙ§ ³Ãƒ‹¯³1$ö¶ò©x¦†k½¨†ktkv@ ›±•OÅ=-�µ6ùN{@¡”E�^½o|žòÔ‡Ü\5v ¸øQìήŸÊA>¿²!�S�ž�Ï‘ÏÒ+€ã}*zí zc­I$G+ZiÐtà„jÖMz·§OÅ.ÑÙ)«&~95n?ò©8­Åñ>ßâX“ùesÕÜeóPʧâ`_ëãx Õ¿«ji{®G _Ag�í$#*Ð3\œlj�c&ýì¡ÉýɰôO³‹2ìÞ ìfb€}ŧb¯š¯i5º¸Ñ¸ÃênZÜÒ\|)ð�¶Æ›Â.>OX‡èÀtëNî3ùðwëãÁÅyÉwiûý”ûÎûÝ^$-S�ž‡·“ÑÓJà ŸŠ?õñú{kK"¹z�u‘ì\Ôìi÷v󩨧�ëZ[¤½^[÷±B¯ë‘Ç ÅË|*N±Ñ…¥¬<ǧâqòé!0ÖÂÀoÈwiûç}*þaBº§=Ÿ¶0“#û|½ ôá§VsÐ{/ŽQµ¯OÅ·º¶ ôÁwªA‘šKñô•.¿Þz‹Í«ŒÇŸŠßS6œÌM®=yõ©8Õ:„ôFº±à⬔Owsñðã>¯¡}ˆ§sYçiÉêÁÅu¬C ˆC|*vmðúVºÕÞ÷as/°M›_¼£Í1'p®OÅù]¾fî&‚t!«½²3p‡uˆp%-�� ÍP�noÊ%2¹8Õ§â‘>¯ñp-I$WºY•Q³ÏØn½2®Û7uñêÁàüM] Ç» £í|*îlyÌÓZs<»÷ðšyjOÑ�W�ÿ>ÐòCžô ðÉéu Ð ‡½OX˜É‰5\Co Ã-‡½|"mzðIë;‡òŒÝººµ�Çr6ÏêÁÀ09ݧâ‡ã~Ô`Ì™]äSqI¯³8Vp¬,ÆûTüø¹uŽŒmáS¡ãŽœ t{´0ÆÀ¹Ö!DD2´Kuâ†<ßuÀ'Zè¼dÃןŒfÐûó°UÛƒçVk{ÜqôÚ0ñŵ¦èžÕ–’NlCùïJžïHŸŠŸX‡�þ©@7\|%yuoÿ¡Oų5\çÑ®!"’“7kX‡ÈÌ}À‡«e§M[²…1&2§áØÃ`{ŸŠŒ»öw×Rvùî…õ vŽÇ†àSqå~tùŸ?Óà6#i— t[kZ˜I]OÝž©é:""9i}0c3€ |*nhi¼%[Gêõ[ŸŠc�ÆÎáìóÃúØúa] [�?•£€ß[‡ÈÄÃÀzÕqt2T ÛzŸu€1nRMײ^–%ÍzÐ:€ˆ‘_j"ßô©øm‹ãYîA·Þ <¨Âöìê÷Ž eÑtB//¬–ç[ÿ»›n<þ¤ª›£¾G_hña©´@º‘ª#°õ‡ÇX§5ÜàG†ÇýÖDŒÌF^ÇbZ¹Ø£å1—jy¼±¬—Iª}*nµ8¸¸°¬ÅØcüȧ¢×Ú9tPŸ×:ÀT|*þìm�ÃØ÷}*êhð,Q�nç äµ|èÔ¯¥.ßC¬êS ³îeTm`ÀØcÀ&>­meªh¿®­ñÆ¡fTÝ;8Úpüwa¼Úñ}¼vɺBŒ€ý�k¬Cù °­u©Ÿ t;+Zã~à¯g}v§4ï_ÖDŒ¼3¸8ÊÇníe°”rI2_n+Ïó°©ñª¼wŽ p pq¯_²žý .Îm�a*>O›u49$�Rî;Ì:ˆÔOº�œ ôßÕ<2k�×’<ýÓ:€ˆ‘Y€÷X‡0rp�Á¸ËŒ9–/ugŸŠgXÉxüŸôù€ÂrÅÈX³[è„OÅåÀ!Ö9Z¶�OÅuÖ!¤*Ðí¼Õ:ÀgÕ|½—Ô|=É�>d”åÔ?¤M»ûTX4d²ÞK¬½s‡[.Î 8Ë Ài}¾~…ZRŒ–Ý�Ƀã OG�¨@7\œx“uŽ1êîÄ›}céÛ_­ˆz›u7§�m] ?m<þ xŒri»õR㥱Ýj÷àò^_œÉ†�ãSñ0£qæµÀ6Ö!¤Y*Ðm¼˜Ã:D冺¬ÎWóõ$?´ bhùêAë(¹Æ§ÂªPµ~ ­¦˜�ñ™õ´¼ñøgöù�âä³ñQëÝð©8æŽæ�ëûTOZgèÁ—€»­C4d[ŸŠ¿X‡�æ©@·‘Ó�]?]F'¢}ÈUMëìü/2h^c`D¼ûg*Ð'÷-½7ëI�ó{}apq!ÊŽä9ÈYZŸŠ»(‹ôaóCŸ Ë£ ¥E*Ðm {�®=è£¡îæ‚"ƒä•ÖFD{qU OnÏ̺I/c8ö>·ôòÂjïùÁ@.G› ì¿{ŸŠ®{”ë�ýõRQ�n#—™—û(èë¶H×”üüÂ:€ˆ¡—Y9èú\¶ 8À:Äsª"wiÃWõò¢àâ«(gÞ?Ukšþ l�^ÙŠ]0“'€ ª&x2"T ÛÈ¥@ÿsŸçtNdá®)™©š ^a�CÄÈBÖFDóï´�©')—¶çÔå~ lÏîþS7_\|Ipñ”�¹Wi&RÏúß}µ’awë5ØÞ§¢«W2øf³0j‚‹ó Xç¨ü¹¡ëª@Ç+Z‡1ð"ëÃ.¸8ûýÄ0:g+w+dذÊzëÉß:ù¢àâÒÀ–Àæä»-ðë58Ø�Á½Où‰OÅÖ!¤}*ÐÛ—Ó²ÈÚŸÈg¬ûº’­ûsYi™ ôæ-Ìj¨û(Òaðgà[Ö!Ʊ¤ñø7�÷›ÕÒû€5���ÇÊ�©Üb _>Ï7£ÜŠ1h5ÏM”pd Ú?Öa�Ó²Èk¸fNÿÿ¤a>÷�¾`�E¤eÖ�ÅGÁÊÖ**ПïiÊ¥íOYÇ¢ÆãÏ\\ƒr¢âUÀ«�7Rý6h²›èQÔ:ŸŠ«ƒ‹û»Ygé“”ç�?dDl¨@o_NË¿Ç}ÒÛ§œþÿI;¾lA3]"myÐ:ÀXÕ:p¿n’_`ߌ÷ÄZ¯Rü�ñøuJÖjôuÊóå_k¤C;úT Ó÷_º¤&qí{©u€Êý>÷5pÝW4pMɘOÅ�ÀñÖ9DZ–Sc¬¡\œF3è·XÈÌ_)‹�\i_=î­ÁŸŠÇ)'ÁÏ|*¢u±¥½}¹|xÜÔÐuk躒·¯2Ç™ˆtJGo5kòø¼ì¨é׈x†riûÖA&¡8õ¸À:@Ý|*.¾g�£‡[{*ÐÛ—Ã 4·§N3è#ȧâvàÖ9DZt—u€!÷.ë•ë¬dä@ŸŠ?Z‡˜‚¶ÙÕã ë „£a .ª éˆS�Þ>Ëó9ÇjêæÒºA‹Ø9€æŽîÉÍ¿¬ ¹öŸC¹¤[ʆaƒp¦´ ôþ= üÚ:DÝ‚‹/öµÎÑ�e€}¬Cˆ-èí{±u€JSË3µÄ}DùT< |Èyù£H]ô0ªY¹èšA‡”KÛ·Ò�\V)²3«UqÃæ0`ëÚ.¸¸šu±£}tý§¡ëj}„ùT\ |É:‡HÃîþnbX—^i�ƒrϵþžáŸŠË¬CL¥:k|NëCàëu .®|Ì:G¦Çs™Ô“–©@o_.?lM¤=è#Χâ0àë" ú±OųÖ!†ØšÖ*×fzÖw›ndpÎ�Îåþj�ý8Ý:D�‚‹ RΞš%)�±•¤½}¹œ]ûÍepqnò9FNlmœoB¤Ï‡Z‡rkX¨äÞ­ Ÿ÷©xÔ:„´âY`ŸŠÖAjvƒ»õa³àâÚÖ!¤}*ÐGW3èK7pM@>OEûteøìãSq­uˆaU�žK�>Ÿ›t˜OÅï­CtaënOŸŠK­CÔ)¸ø!àSÖ9útTµ @FÈlÖd¨¨@—ÿçSñ@pqMà\`¹_öà—”³ï×RÏÙê ‹Ôp-©Ç‡€‹ú¼Æ,ÀKÆüïS®Pš�ò½h9`y`Eêû»?øZM×’ñ-O>³]£<ƒ~ °‹uˆ.éž¶;OP~>ŸüÒ§b¨N¦.ÎÇpì§9� ­ƒH{ôf&uz�uÉ‹OÅ]ÁÅU€#�õ'ø²Û�“€}*j�q.Îüç¹9XÞ§âá>¯sï¿ÿ¼Â*¸¸8°e±¾"àx~q?•[€½}*Ô[¡y¹ì?¸Ú:„¡Íjøùl[.ÇØæì_ÀÙÀ¯€³ðï¸ßfxú"m\<Õ§âë Òèí{Æ:@ƒT Ë øT<@ùár(° åÌæS”EÔ/€ l¸u°ZC×–Þ½šòïf«6ó©¸ ¸ ø)üÿ2ê¥(ÿ-.KÙŒg `>àE”+7î¥Ü¢qpŽšÂµ&—ýjŸŠQ=2òhŸŠs¬Cô`nëz8øð;ŸŠë�ó´"¸ø>`Së5;"¸x¡OÅ�ÖA¤y*ÐÛ÷�u€Ê \SKÜeB>R.5oEpqcà‹m�']Û²šømÛWM�n¬~�Ööø2¾àâ‹€U¬sTZ{¯ÊÌmÀŽÖ!¤gwPnº¸úu•OÅ0O ½@pqà{Ö9°på1r*ÐÛ—Ë,Ì\u^¬š‘Z¾ÎkŠô*¸èÎèastpq9ŸŠ¦Ž}”Áò.`ºuˆÊùÖŒl©ŸÇ�ñ0pUõëÀÅ>ÿ´�”…}�WZ‡hÈ:ÁÅÏi»ÕðS�Þ¾¬4di`^ë"ÁÅ…�S)—*KÞ§Ü'¸¹uÉÂ:ÖƸØ:€�ã|*ΰчaÝOý,ðÊÆ©×pã‰Ö—àâªÀÖÖ9vppñŸŠ[­ƒHsT ·ï~ë qÖDª¦p'Sî'–Á°Ypñ‹¥î’�\ ô¿úTÜe¢e·Û[‡èÓÓÖúðpkõëÊ‚ü:àzàúî‡Ð±àâ\À¬s´àÅÀ±ÁÅÕõ€fx©@o_.3èÝt0î„ tÉ�šÂ &-uqÁÅׯ²ÎQ¤³¿ë²�OÅ O ñÿV¿î¤Ü÷»QömoF§Ò{€ø®ui† ôöåòXëtàm5_O¤+ÁÅÍQS¸Aµ8°?°¥u1³¶u€1γв“|*†¡Yâ£Ö€û€…G­1›µàâÛ�¬s´lßàâY>·"õ›Å:Àú¯u€JmÇ‘TËŠW¨ëz"Ý .¾8Ô:‡ôe‹àâjÖ!ÄL.ËÛŸ¥<’j”ìm &9¬P|PÅy»‚‹sG3z5Ítàøàâ¬ÖA¤~£ö�9·[¨¼¸Æk­ÌSãõD:\\†ò|ëÙ­³HߎªŽÚ’\œ�|ŽW»Ô§â>ë-ŠýÍÕ~ÜǬsHë¾¼Á:„‘•€]¬CHý´Ä½}wX¨ÔY ¯QãµD:\\ø%0¿u©ÅÒÀ^è†cÔ¼ÈeèLëÒ—{�E­CX.~ؘrÏûM”ÝÞ/Îñ©¸×2[S‚‹ov¶Îal�àâ¯}*þlDê£ô–ùTü‡²[§µÚ–¸£] ç œ9­u©ÕŽÁEm™-µ0† ôÁv·ñøsX Z-óþ4åq·‹ï¦ìÉr2pWpñÂàâÎÁÅ¡™i®¶W‹&玫î‰dH¨@·ñoëÀu\¤:Öâu\K¤K‡Rv2�£°·qVàûÕÍ— ¹ª°XË:Gå.àJëÒë½î¼�Z ˜o‚?›…r ɾÀ_‚‹WWÅúb­¥kÆ.ÀòÖ!2±<°‡u©� t7Xªé:ïF{¥eÁÅ/›YçhÙ¶À1Ö!Zòf`'ëÒŠÕ©ÿØÏ^ýZG] ¼;�Ç·êdzQ_ûFÊbýÖàâ¹ÁÅϧ7”«ÕJ€¯YçÈÌ.U7{*Ðm\oX¤¦ëä2ó!#"¸¸åÍÅ(ù‘OÅ€¯“Ç™6ì\Ôö…á÷ ëcœj@úö/ãñg .¶Z¤WÅu/ÇN£\…v,ðïàâÁÅ¥êÌÖ„ªkù÷1ÚN�±Y�c«•­2àT ÛÈá̾gЃ‹³�×Í• ¹àâ¢ÀqŒÖ{×MTçƒûTÜ üÀ6NkæŽ.N³"ͨn´?l�£òp¶u#¹4è«C['ZjÞ”µ€~O¿˜Ø¸!¸ø›àâûú�Õ˜(»—Ë -|Ó:„ôo”nrsr�u`Žàb¿Ë W^^G‘©T„N¤¦þ âI`}ŸŠ‡ÆüÞÞÀãFyÚ¶*Õà J料íVý:ݧbT~®fVç©.Ön±@û]ä?^㵦Î .^–[¡\| åg Lì‹ÁÅQêÏ3”T Û¸Ú:@åe}¾þ“µ¤éÌÎÀjÖ!Z¶«OEû>·Gå±°ß43’ñ}Ì:À§Y�ZÜh€þï­:V5Óìey{'V¢,ÔÏÎa»QµšêûÀ@í—7rL “pbHº�ꨵۭs‹÷úÂê�2§£qdˆUg�~Ý:GËNšàÏöetfÑ_ fBêU}†äR ?Aùó&ƒïf`†q†%Zë�”G«5i àêàâöÆ[޶¦\U•›?‹_ hBz§ÝNšúK÷Ê>^ûNʳ6E\œ�Ñ;ëôßÀç|*ƽÑô©¸8¤ÝH¦>\ÜÀ:„ÔjUÚ_ <‘ßøT¼ûsãÙ4¸ØÔê i˜ t;´,ÙÇk7­+„È<£uÖé3À>S�ç»?ec«QqHpqAëR›O[ãxëR+ëm„mèhq,€Í)›Éµ¦šµ? ˜»Íq;tˆOÅ¥”ß—}_Ÿ›ƒIº�K¬Ðã zµ¯E³YÒ¸àâë�ݬs´ì«>MõEUÿÝòäba´do(çÖ³ÎQ¹øµu©Õ5Æã¿®�A‚‹ `óðz‹–Çû°fËcvâv`ŸŠß‘ç +‹ -bIº�‹)÷½Yêu‰û§�³(m8˜Ý:D‹Î¤»e|û4”%G·²!}[‹ö�¢šÈI>OY‡�ZýÙxü¥ƒ‹ý{Ö‰wQv]o[kµCu´êwÚ¯KÛÏtÂÊŽÀVa&ñÉàâúÖ!¤;*Ð�øT<\f£×§¼¹.å‘!\ü0JG…üØx¢}çãñ©¸Ÿ‰É «Ãƒ‹Gç°"=Óòvi’õ½Õ,Àë[Çêóñ-Žu8Í7ÁëÅÙ>§Œý�êóxk£?omøúÄî3òÔ¦..L¾'•ìçSqÃ$^÷¶¦ k?oB:£ÝÖÀ�Æ–íô ƒ‹‹£æpÒ°jVt”Ã� |³ÏkDÊfW£æmÀÉÁÅY­ƒHǶ´PyŒòøFNç�¿RÃ×ßµáëOäRŸŠ¿µ0Îa”³¾¹¹™)>¯}*îvh'N׬ެ“Ì©@7äSñ,ð+ãÝÌ oÏh5ì[ó[‡hÉÀ§«÷‚žUg8�â,:ÀÚÀ—¬CÈÔ‚‹+ÒðÒß.œ\­>‘ád] ¿1¸8O.~X¥‰kwàˆ¦.~ X·éqzTøT<>ÕùTü®…<Ýz1plut�dLº½ÓŒÇ_±“/ .ÎO>32¤ªÆ_Û[çhɳÀ†>ÿ­ézû9Vöì¶Ÿ†˜È©�Ò‘Ö¤9>×ÿ2Œ0+ ÑUwx«Æ ÿNjr€êÌîÛ£§úTt³5u+Ê•:¹Y ØÎ:„LNº½³�^CÕå-Õ™´SÙ˜»é02òֵђ¯úT\P×Ū“!Fu}.àãÖ!dbÕCÞ\Žúù³OÅ¥Ö!¤q¿4Õ®¹ðê®Û‰}}*žnxŒïPžÝ�›GèròÀ§â&`ïfâôí[ÁÅ^Or’¨@7V�¿ÚèÉ)ÌÎ]Ù«eZ£2«)¶6²Ð’3i¦Ký‘ØÎYZÌ:€Lê³Àtë•\›OI½¬·¾¯Î‹×¶­óš]ø' w.® |¦É1ú°—OÅm=¼îàêºÃÔ`:åR÷Ù¬ƒÈøT çá8ãñß1ÅŸ X¨� 2ºªåí¹¿Ô¤Û€�º9ï¼SÕ,z¨ûº¢Í³y¥ Õ‘PãKdà¿À­CH+Îî3ßk¹wªºš[ǵzôUŸŠ'›ºxÕ6×¥í¥ÇmÕŠƒÍ)·´åf%`ë2>è𩸸Æ0ÂÊýAõáòå³ÈèzÐÉv‹Aö°¾OE“G°ü€ò!À¨9Û:€LèãÀÒÖ!*‡ùTÖp�¯9~FÍ×a/*i‘ ô|ü»fqóoŸù7ƒ‹K�W×]n/·аŸ·4ÖqÀM-�•uäÎTpñtxZH N¬ñÔ çc»ýe­àbϽ‚‹›c{v²OÅyM]¼êqôƒ¦®ß§û��ê¸�OŃä{6ú›€=¬CÈó©@ÏDµwÔò&óýãüÞ7€9Ú"#k˜Ïå¼ø\ûÎÇSí{ûFceà~ìgÉdÕY»ß²ÎQy†f3öj¢UkR£jæ÷(Ãséå…US¸Ãê�Ó•Gi~‹ã7€%£W_©ó�žOÅÉä»k—àâ &êÄŽ ô¼Jù†ha­±ÿ#¸¸ði£,2šþi !OëúT<Ðò¸'kyL ßô©xÄ:„Œk —ý�?ò©¸Ñ:Ä X!ß§|¶ò¹n_Pí þ)`Ùe;ôع¼³‹»¸ ùžÇ}9ð½®» ¶ÿ'2 p|pq^ë RR�žŸŠ;€ï ï‚‹KÂÿwÜ=„ážÑ”ü ë¹ÄÛûT\Õö Õ,z®g°Öå6 Z‡� .Îìo�£2ƒ|fò©z¾X�e=ž¡î3SÍ‚oaÍnΜ.¾‘r¦õ%ÍEšÒ_iðç7¸ø"àhò¼Ï|غ‰}÷>7PžeŸ£×¿©Þ»Å˜ ôüXÍmXý禔µEZãSñàzë5û¡OņãŸÌpÏ¢oWm’ü|XÔ:DådŸŠk­CŒ±,ð"ëcŒÂrûoS>¨±0 ص“/¬–Ÿ‡íѶ3€-úé\>™jëË À2M\¿‡ûT¤¯ÿMÊmo9z'pjuì­R�žŸŠ»éñ¼Ål\|)ù>Ý“á7L³¡×[Y¨f¼e†�äSqšuˆ²T§3+ÁÅU�mÎÓ©ä·’dMë£Æ§âzÊ–V6.ºÉ¾ ¸øà\`Áv"M蟊K¼þ·�u¼~?þKß™>�_lrŒ>½øÑ$§;I T çé[À¿ Æ}p0¿ÁØ"Pî†3¼¥Üwþ°uÊŸé?Y‡¨Ù?ɧËg'-‚‹/£,„r¹¿8.³Ùs€u¬Œ¨Ý)›Z˜8a¼=¾ÁÅAtWŽIDAT—DyúFÏßkòoà+M]<¸¸ùv3øRýb|*NÎlzœ>|œrOºŠt#¹|€ÊUã¦;gNäFãŠÇY‡«Z ~™uŽšlÕðþÀldzc´$papqÿ±KÞƒ‹+R6z\Î*Ø8b“]¨{´ù5ÆšÇ:@‹¾ ´}¢ÆXËgQöù°ùô#8̧â·M\8¸¸)eóá\=m… ÿ¿í"çï ”§9éŒt*Ð3U½Il¨’Œ¢ÍÌc×þL¾K¯·Ã®IR]¾îSq¬uˆåzäÍ,”«¼þ\<2¸ø{Êc‰–²�õ<÷Q6cÊÍ&ÖÆay”W«ªŽî*8^èF`—&.\\Û³è;ñm£­0{Sî{ÏÙÁEmËi™ ôŒùTüØÍ:‡HÛ|*îÖ´ÎÒ…‡�õrí*îSqp¤uŽ>ü€Ñ»±Îefm"K[«ZÇnÕûH6‚‹o£\望—[hYþ`"#Ï›4Ñ3%¸øaÊŽí9×·_·اâAã>ÿðàâPǘ›œ`¤tp‘uÉ^î7ò]«öpo@yó0>WíqÌÙnÀ]Ö!zð Êc}@·¬»9ª|Ï:Ä8rí\½Šu€6ùT<|xÒ:K&ö𩸸î‹ßü˜½îk×l;ŸŠG Ç?¸ÆpüN,F¾«‡’ ôÌUÇ$mÜc�EÆ•ËÒÀe­4Á§â à3ä_¤GŸŠŸZ‡˜J5£¸“uŽ.�DÙΪû²¥\š­ ’À6Õggn>d`kGê~°z3¢Å9Àk­  £|*²[¾\\x�uŽ , ¼Ý:„�ï¿¶aè?ÀÆu?Ì .Îü˜ü›>FÙ›Å\5qŽuŽ),;¶1¨4Kú€ð©8‹²™„d¢:ÏôUÖ9*/6¶Ñ”ªHß‚üfÒïÖ÷©˜¥’Õ2ñÍ(�+ËÙ‘ŒvqeÇgéÜmä;+úëSøˆu€¶Uï…QvT5ÏŸò©¸³�kxs×­[ð©ø‡uˆ1v&ÿ‰¸Üó èƒeoàgÖ!HÓ7ö[’Ïw€=ƒ‹s[‡hŠOÅQ”{8sjÂöÙÌ>à;âSq°»uŽIìéS±Õ(çÕ,ÔÚÖ9ÌfUÓ¥Íi` #W Tg~¯Å`žÒ�/ûTœÛе·jèºuºØß:ÄX>W'[ç˜Äßsm‚;ŒT �jÒÆÀ%ÖY¦�Kª‡šºppq àkM]¿G¯¾h¢I>?Ö¤œ¹¶¶ŸOů¬CôáÛä×€òiÊ"k/ë ø4ecéÌÑM�á\“[­La™àbî³ü�𩸅²QÞ_�£´å8ŸŠ›¸põ`ñ-M\»f;eºòmoò�¥>Ü:À(Q�>`ª§Wrí}2p–uˆlä8[=O®ûRu›]ÛŸ�‹o8~ߪ~›’ÏŠ„û€÷ûT|ß:ˆµàâÀžÖ9È�À—¬CLƧâfà&ëSÙ>ÿÞÁð¯R¼œrõ_Sf�ßV´™=E¦û½«³ØsœE¿8Ô:Ä(Q�>€|*îÞK~ö·PîÎå¬Ä& �\—Þ.\\Ä:DÓ|*þ¼ 8Ó`ø»€OúTgÈ·)‹ÎÂb{ŸŠ?Y‡èÐQÀ¥Ö!&ñÎQ;nm<>‡o`¸:¼ß|À§â¿-Œõ5òžE¿Ð:ÀdªYôS¬sTVnéß�Œ1òoă¬*Ò×n¶Î|ͧ"·�&\D¹¬2G9î«j„OÅ3>»îoaȳ2ßçÚµª“ñçi�ì `/Ê�z d!¸¸ðzëã¸Û9ã9Û§âë�ªVÝ|œ|¬Ïì%èh? <ÞÖ§bàÀ5Öyúô0å h+÷,Õ6´œûáä>Ãðãñÿ¬îS±µÃÙP�>àªæ&ï Übå`ÃñÇsOUx4¢Ú¿›ëq>9?¹nDÕ0¸Kax€{â¡>™ä.M_p‚XkѲÔðØžc›¾~EÊýæÜ¹'“yîy«Öôõ¹)…._•å;’tã¹'°lš¾¾¢éëÓ’”ä÷“Lšì®Âÿ&yð\‰VÓ×oKr—$Ÿ#þ|q�Ô«H’WNëÒ”UûÛ4}ýWΛÏO‚¾N4}ý‹”ó¸Söu¼,¥XÖ·ùúÕ'œÃŽüd¢8ONò¯ÅÚçÏ=�95}}iÓ×ÏNI ½�ï”%|µPÃÕXÕé/Æ>rHPؾe^Ýyl’4}ýo)«Šs&È_múzÙ[—íPÓ×7}ý´$÷Hòٹ糕e¸/¥!QgÓ×wOÙéò)‰Í2úy’£æ^múúœ¦¯ï“äaYŽ£ka{ûïNùÿ8¦K“¼>%1?Éq³å!A_G†ää9)g¦¾?AÈ›¾Þ^rº 7ø)þû3TC=6ËÓ›~C'è[4}ý©”â5YÌ ÕW³·Ó¯_’rÝéK)UÚ_2Tùe†­�'Í=�¸ç–^ÙC7‘&yaæ9V3G‡…v®–ä˜,ÇË™óæžÀZÐôõg›¾~T’[¤tÂX¦êç&9bø]²š¾>#åøÄ ™÷Z-Ó‚ÊN Ï—ÿ4Òð['æO^Ë/;×+ ú:4œ™ºC’—f¼·»§4}ý†üÙ5Fйßž*ÐP¹þ¨,GÿÔe(¸š¾¾ é맦¬tœ¹ÊáNZï«çÛ¨Sª·®Ö…IžŸäk¨Òöì†mäGgúÂ}»ã~[þaXQ(¥õçë2þªçÎ|)¥+ÆÒý¾múú²¦¯ß’äà”…¤É´G<.Î’ö?߉Eÿž“˜¯{Í=��`óæùŽ˜µUwË$ÏLò¤,neû”¦¯_¸“˜g¥œ;šÓSæ¨îÛVÝCSV”™:öà¥M_?o¦ØKkhô„”þ¢+=cù�¦¯�^ü¬–_[u/Ji™³'ÎHy±ñ_ œÒ†ÒVÝ5RZ®=+ÉõfžÎ¯lúúÛ~±­º›¦Á>Úôõ}'ˆ3›¶ê®™äáI™äÈ$W� ì{š¾>n‚8ëÚð÷öa)÷œÃ3ݳöI¿–êдUw@’ÇŸ›ŒîM_?rä ÕVÝÞIþ;Éþ«êò$oMròP\zUöÚKú86Wxs&è[´UwÝ$�äq)gÞöÄÅIþ¸éë·î"Öw’üÆÆX”ûÏÙ«­ºÃ’<5å&}µ CÿápŽ˜íh«nß”—UÏÍî%ê'9xªö4˨­º‡'ySv¿xÙÇ“<¯éëÏ�7«�eHÖ�ò;åà™§óò¡ÎÕ´UwÕ$/Nép1Ö½ Rvd¬ÅŠÚ{¤­ºý“<$å8Õý2Î.µs’lªÌ³ mÕÝ"É£†Ï�G sIÊËÐ5Ûe¤­º«¤´ >!ÉC3ÎÏø¦¡ÜšÒVÝÉ) ?{bKbþâE>ÇHÐÇç O`ô­µUw“$÷Oò»IîšäNI®²‹oûH’§7}½Ë³CmÕý0óW‚½eÓ×ß›yi«n¿$ǧ¬„•ñ�•Üt;EûØF[uWOùÿòø”¿;ú]øü¦¯—­…àä†�8§¦´bÛžËRzd¿|™Î=®GmÕšò¢õYýªÊž8aئºCmÕÝ-¥%á¢[Æ]šäø¦¯ß·àq׌¶ê®–rfý>I6¥l«¾æ*†¼<ÉÛ’<£é멊«nHmÕÝ:Éq) è=³˜ç�OòĦ¯¿¸€±–B[u×J©oq|JñãÕü|oñÞ¦¯º€q&7ìÈø|’Wðm§tzÙÐáf¡$èãs…'°l ú¶†þo&¹yÊ£ýR¶Ó]#¥`Ì'š¾Þíê›mÕý,ÉuF˜êî:¿éë̻ڪ»aÊÍùØ”‡«EÓ;«éë».xÌu¯­º›¥$éG$¹cÊJñeI¾œ²cdYz>Ï®­ºƒ“<&Éo'¹vJ1¢$9½éë©Ï ohÊӽSö�Kr³ Âþ"å%ànµ)j«î˜$ÏKI(WëëIþ¤éëO/`¬ucø9¸cJ °“Ü:É­’Üpøl»óåü$?Hò•”óæïnúúSÍ—bØÕxŸ”÷›RJVòLþ‹$/Hòªõ\xsØõö ”dýAÙ³gËs“Ü}-ïi«îæ)÷Ú]í :?ÉR~.F[¬‘ �ÏžÀŽôáÆzÏ”›ê¾Ã—/JÙÂ÷Ý”‚_ç6}½ÜþVÚªÛ+å�üœ?[iúú¨ãïÒðFô¾)o‡�NrÓ û䦯_¿€q€5dø½{hJ¢~LÊÃþ^ÒôõŠÛð +ê'¤Ìï–+øÖ “|8É[RVÀ¼,ÛCmÕíµ–ž%6ša·ÝÝS^´Ü9¿Z4¹aÊËФtKøVJƒ—m´v•ÚCSž�ŽJyQ¼«Ú g§ô‚ÿæÈÓ][uû¤szR’ÛmõGW¤t€xcÊ9û_Ž= úø\á l› ·Uwç”þÙ»³EñÂ$g¥loù|’�5}½´mPÚª»~¦¯æ»­—5}ýÜ™ç°Û†‡ë;§œ-¼_JQ™}V8Ì÷’ܾéë‹<=`�v…µÕg;о™änM_¯ªºx[u·K©ƒrPJ­’k¦ì&úi’Ÿ¤Ü?ÎN¹ï�½žWawyÁreÃVøC“T)/%HÙz•”E®÷'ù›õø\ÔVÝ�S’ô_OrfÓ×?š2¾}|®ð¶$èÃ_¨SSª²®Æ—S΄¿'Ég–©ýS[uwHÙŠ8§cš¾~ÿÌsØcÖ®ÃS¶¿‘róÙ{'ßrQJQ¼OM0=` ^’òûä·R¶›¯t;üw“¹‘‹%PHÐÇç O`óæÍi«îN)[õ±•ykßOrz’75}ýµ�½bmÕmJ2g¢xy’ý×R›‘]¶Ãšò`}ðð¹MJuøO¥ToýÂ|3Ö’á<ãa)[jLY}ºE®\,ôçINKò¢¦¯ÏŸt’,% úø\á úRVBÇô¡”*Ê9εU÷°$ïœ+~’Ï6}½èÊÁëÚPåÆ)[D÷NÙ™ó-[ÌØš}|»*®À çÇNΓá s[uMrbÓ×gOs[7š!æÖfë}°V ‰ø¹Ã˜ÉØ=™)F¯¨¸�#“œÕVÝc&Ž›üÿÊ’sx×Ìñöˆ}ÃÙ½oOvß$§µU÷§ǽÃÄñ¶ö�¦¯ÿcÆø{L‚>�ÓfŠûŠ¶êŽœ0Þœ+è§Ï`U$èÓyE’Iû~-ÉémÕÝjì@mÕíŸÒ×v›“¼y¦Ø«&AŸÈÐöë1IæèY¾’÷ íºÆtXæë 𾦯¿3Sl€U“ O¨éë%yêLáï’äMmÕ�™@ß{ıwåU3ÆX5 úÄš¾~]’g ÿÈ$ÏqüŒ8öΜ•ä£3ÅX�æ'°yóæ+}­­º§$yÍô³ÉI8¬æ/L[u‡$ùâ"Ç\�5}ýÁ™bÀ†°×^ÒDZYAŸIÓׯÍ<+é¿–äímÕ°àqç蹞$Ÿ‘œë�}FC’þÌB_7É{Ûª»Ö"ÆyÂ"ÆZ¡ÍIž5C\€…“ Ï¬éëS“t3„>(ÉimÕ-âgà9I®³€qVêÕM_v†¸ 'A_OOòÏ3Ä=.É©«©ìÞVÝ�) úÔÎMÒÌ`ô%ÐôõåI‘yЬ=-É_·U·÷J¿±­ºý’œ‘dŸ…Ïjç®HòØ¡·<Àº A_M__�äÁI¾;Cø'&ùD[u·ÝÝoh«îæI>žäö£ÍjÇNnúZ[5`]Q'Ûk³¶#mÕÝ1ɧ“ì?Ú„vìÒ$oLÒ5}ýµíý mÕ]=É%9%Éõ'œÛHrLÓ×WÌ6,mÖÆç O`% z’´UwX’�$Ùw” ížo$ù\ÊŠþÿ$¹^Êjù‘Iö›iN_Jò;¶¶Àô$èãs…'°Ò=IÚª{H’Œc[œ“ä^M_Ÿ7÷D`#’ �Oò·¤š¾~o’R ¢mtg'¹·äXÏ$èK¬éë¿ORÏ=�™�™dSÓ×ߟ{"c’ /¹¦¯_›äĹç1“w¤¬œÿxÍ!‚ ìÉômµU÷è$—�ñRå’$ÏlúúÕsO(œAŸ+<�E$èIÒVÝ“¼+É52àrúJ’Ç5}ÝÏ=àW$èãÛ«±ëFÓ×Lr¯”ÖgëÍ/“üY’»I΀�È+� ,j}‹¶ên�ä´$XèÀóØœämIþ¼éëÿœ{2ÀöYAŸ+<�E'èIÒVÝ^Iž–ä/’ì»ðãÛœä½I^ÐôõWæž °sôñ¹Â#Aߢ­ºÛ&yM’ûŽd±~žäÍIº¦¯Ï™{2Àî‘ �ÏžÀ˜ úmÕ—²š~ûу­Üæ$ŸL©Bÿ®¦¯1ó|€’ �ÏžÀ z’´UwÕ$Ç'9)É=& ºsŸKrF’w4}½ ÛÀ†!AŸ+<�©ô­µU·)É“’›äÚ…½ ÉÇ’|0Éû›¾þÞDq€‘IÐÇç O`Ž}‹¶êöIr¿$¿—dS’Û,pøó“œ™äSÃçóM__²Àñ€%!AŸ+<�9ômµUw£”^ê&9`øÜ<É~)Õà·®a’Ÿ%9/É�’œ3|¾‘䬦¯Ï�næÀœ$è,™ÿ¢± m( 8<IEND®B`‚terkelg-globrex-47e816f/index.js000066400000000000000000000173351340547017600166420ustar00rootroot00000000000000const isWin = process.platform === 'win32'; const SEP = isWin ? `\\\\+` : `\\/`; const SEP_ESC = isWin ? `\\\\` : `/`; const GLOBSTAR = `((?:[^/]*(?:/|$))*)`; const WILDCARD = `([^/]*)`; const GLOBSTAR_SEGMENT = `((?:[^${SEP_ESC}]*(?:${SEP_ESC}|$))*)`; const WILDCARD_SEGMENT = `([^${SEP_ESC}]*)`; /** * Convert any glob pattern to a JavaScript Regexp object * @param {String} glob Glob pattern to convert * @param {Object} opts Configuration object * @param {Boolean} [opts.extended=false] Support advanced ext globbing * @param {Boolean} [opts.globstar=false] Support globstar * @param {Boolean} [opts.strict=true] be laissez faire about mutiple slashes * @param {Boolean} [opts.filepath=''] Parse as filepath for extra path related features * @param {String} [opts.flags=''] RegExp globs * @returns {Object} converted object with string, segments and RegExp object */ function globrex(glob, {extended = false, globstar = false, strict = false, filepath = false, flags = ''} = {}) { let regex = ''; let segment = ''; let path = { regex: '', segments: [] }; // If we are doing extended matching, this boolean is true when we are inside // a group (eg {*.html,*.js}), and false otherwise. let inGroup = false; let inRange = false; // extglob stack. Keep track of scope const ext = []; // Helper function to build string and segments function add(str, {split, last, only}={}) { if (only !== 'path') regex += str; if (filepath && only !== 'regex') { path.regex += (str === '\\/' ? SEP : str); if (split) { if (last) segment += str; if (segment !== '') { if (!flags.includes('g')) segment = `^${segment}$`; // change it 'includes' path.segments.push(new RegExp(segment, flags)); } segment = ''; } else { segment += str; } } } let c, n; for (let i = 0; i < glob.length; i++) { c = glob[i]; n = glob[i + 1]; if (['\\', '$', '^', '.', '='].includes(c)) { add(`\\${c}`); continue; } if (c === '/') { add(`\\${c}`, {split: true}); if (n === '/' && !strict) regex += '?'; continue; } if (c === '(') { if (ext.length) { add(c); continue; } add(`\\${c}`); continue; } if (c === ')') { if (ext.length) { add(c); let type = ext.pop(); if (type === '@') { add('{1}'); } else if (type === '!') { add('([^\/]*)'); } else { add(type); } continue; } add(`\\${c}`); continue; } if (c === '|') { if (ext.length) { add(c); continue; } add(`\\${c}`); continue; } if (c === '+') { if (n === '(' && extended) { ext.push(c); continue; } add(`\\${c}`); continue; } if (c === '@' && extended) { if (n === '(') { ext.push(c); continue; } } if (c === '!') { if (extended) { if (inRange) { add('^'); continue } if (n === '(') { ext.push(c); add('(?!'); i++; continue; } add(`\\${c}`); continue; } add(`\\${c}`); continue; } if (c === '?') { if (extended) { if (n === '(') { ext.push(c); } else { add('.'); } continue; } add(`\\${c}`); continue; } if (c === '[') { if (inRange && n === ':') { i++; // skip [ let value = ''; while(glob[++i] !== ':') value += glob[i]; if (value === 'alnum') add('(\\w|\\d)'); else if (value === 'space') add('\\s'); else if (value === 'digit') add('\\d'); i++; // skip last ] continue; } if (extended) { inRange = true; add(c); continue; } add(`\\${c}`); continue; } if (c === ']') { if (extended) { inRange = false; add(c); continue; } add(`\\${c}`); continue; } if (c === '{') { if (extended) { inGroup = true; add('('); continue; } add(`\\${c}`); continue; } if (c === '}') { if (extended) { inGroup = false; add(')'); continue; } add(`\\${c}`); continue; } if (c === ',') { if (inGroup) { add('|'); continue; } add(`\\${c}`); continue; } if (c === '*') { if (n === '(' && extended) { ext.push(c); continue; } // Move over all consecutive "*"'s. // Also store the previous and next characters let prevChar = glob[i - 1]; let starCount = 1; while (glob[i + 1] === '*') { starCount++; i++; } let nextChar = glob[i + 1]; if (!globstar) { // globstar is disabled, so treat any number of "*" as one add('.*'); } else { // globstar is enabled, so determine if this is a globstar segment let isGlobstar = starCount > 1 && // multiple "*"'s (prevChar === '/' || prevChar === undefined) && // from the start of the segment (nextChar === '/' || nextChar === undefined); // to the end of the segment if (isGlobstar) { // it's a globstar, so match zero or more path segments add(GLOBSTAR, {only:'regex'}); add(GLOBSTAR_SEGMENT, {only:'path', last:true, split:true}); i++; // move over the "/" } else { // it's not a globstar, so only match one path segment add(WILDCARD, {only:'regex'}); add(WILDCARD_SEGMENT, {only:'path'}); } } continue; } add(c); } // When regexp 'g' flag is specified don't // constrain the regular expression with ^ & $ if (!flags.includes('g')) { regex = `^${regex}$`; segment = `^${segment}$`; if (filepath) path.regex = `^${path.regex}$`; } const result = {regex: new RegExp(regex, flags)}; // Push the last segment if (filepath) { path.segments.push(new RegExp(segment, flags)); path.regex = new RegExp(path.regex, flags); path.globstar = new RegExp(!flags.includes('g') ? `^${GLOBSTAR_SEGMENT}$` : GLOBSTAR_SEGMENT, flags); result.path = path; } return result; } module.exports = globrex; terkelg-globrex-47e816f/license000066400000000000000000000020671340547017600165360ustar00rootroot00000000000000MIT License Copyright (c) 2018 Terkel Gjervig Nielsen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. terkelg-globrex-47e816f/package.json000066400000000000000000000010611340547017600174500ustar00rootroot00000000000000{ "name": "globrex", "version": "0.1.2", "description": "Glob to regular expression with support for extended globs", "main": "index.js", "author": "Terkel Gjervig", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/terkelg/globrex" }, "files": [ "index.js" ], "keywords": [ "glob", "regex", "regexp", "parser", "glob2regx", "compiler" ], "scripts": { "test": "tape test/*.js | tap-spec" }, "devDependencies": { "tap-spec": "^4.1.1", "tape": "^4.8.0" } } terkelg-globrex-47e816f/readme.md000066400000000000000000000110171340547017600167430ustar00rootroot00000000000000
globrex

globrex

Simple but powerful glob to regular expression compiler.

## Install ``` npm install globrex --save ``` ## Core Features - 💪 **extended globbing:** transform advance `ExtGlob` features - 📦 **simple**: no dependencies - 🛣� **paths**: split paths into multiple `RegExp` segments ## Usage ```js const globrex = require('globrex'); const result = globrex('p*uck') // => { regex: /^p.*uck$/, string: '^p.*uck$', segments: [ /^p.*uck$/ ] } result.regex.test('pluck'); // true ``` ## API ### globrex(glob, options) Type: `function`
Returns: `Object` Transform globs intp regular expressions. Returns object with the following properties: #### regex Type: `RegExp` JavaScript `RegExp` instance. > **Note**: Read more about how to use [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) on MDN. #### path This property only exists if the option `filepath` is true. > **Note:** `filepath` is `false` by default #### path.segments Type: `Array` Array of `RegExp` instances seperated by `/`. This can be usable when working with file paths or urls. Example array could be: ```js [ /^foo$/, /^bar$/, /^([^\/]*)$/, '^baz\\.(md|js|txt)$' ] ``` #### path.regex Type: `RegExp` JavaScript `RegExp` instance build for testign against paths. The regex have different path seperators depending on host OS. ### glob Type: `String` Glob string to transform. ### options.extended Type: `Boolean`
Default: `false` Enable all advanced features from `extglob`. Matching so called "extended" globs pattern like single character matching, matching ranges of characters, group matching, etc. > **Note**: Interprets `[a-d]` as `[abcd]`. To match a literal `-`, include it as first or last character. ### options.globstar Type: `Boolean`
Default: `false` When globstar is `false` globs like `'/foo/*'` are transformed to the following `'^\/foo\/.*$'` which will match any string beginning with `'/foo/'`. When the globstar option is `true`, the same `'/foo/*'` glob is transformed to `'^\/foo\/[^/]*$'` which will match any string beginning with `'/foo/'` that **does not have** a `'/'` to the right of it. `'/foo/*'` will match: `'/foo/bar'`, `'/foo/bar.txt'` but not `'/foo/bar/baz'` or `'/foo/bar/baz.txt'`. > **Note**: When globstar is `true`, `'/foo/**'` is equivelant to `'/foo/*'` when globstar is `false`. ### options.strict Type: `Boolean`
Default: `false` Be forgiving about mutiple slashes, like `///` and make everything after the first `/` optional. This is how bash glob works. ### options.flags Type: `String`
Default: `''` RegExp flags (e.g. `'i'` ) to pass to the RegExp constructor. ### options.filepath Type: `Boolean`
Default: `false` Parse input strings as it was a file path for special path related features. This feature only makes sense if the input is a POSIX path like `/foo/bar/hello.js` or URLs. When `true` the returned object will have an additional `path` object. - `segment`: Array containing a `RegExp` object for each path segment. - `regex`: OS specific file path `RegExp`. Path seperator used is based on the operating system. - `globstar`: Regex string used to test for globstars. > **Note: Please only use forward-slashes in file path glob expressions** > Though windows uses either `/` or `\` as its path separator, only `/` > characters are used by this glob implementation. You must use > forward-slashes **only** in glob expressions. Back-slashes will always > be interpreted as escape characters, not path separators. ## References Learn more about advanced globbing here - [mywiki.wooledge.org/glob](http://mywiki.wooledge.org/glob) - [linuxjournal](http://www.linuxjournal.com/content/bash-extended-globbing) ## License MIT © [Terkel Gjervig](https://terkel.com) terkelg-globrex-47e816f/test/000077500000000000000000000000001340547017600161435ustar00rootroot00000000000000terkelg-globrex-47e816f/test/helpers/000077500000000000000000000000001340547017600176055ustar00rootroot00000000000000terkelg-globrex-47e816f/test/helpers/index.js000066400000000000000000000015411340547017600212530ustar00rootroot00000000000000const globrex = require('../../'); const isWin = process.platform === 'win32'; function match(glob, strUnix, strWin, opts = {}) { if (typeof strWin === 'object') { opts = strWin; strWin = false; } let res = globrex(glob, opts); return res.regex.test(isWin && strWin ? strWin : strUnix); } function matchRegex(t, pattern, ifUnix, ifWin, opts) { const res = globrex(pattern, opts); const {regex} = (opts.filepath ? res.path : res); t.is(regex.toString(), isWin ? ifWin : ifUnix, '~> regex matches expectant'); return res; } function matchSegments(t, pattern, ifUnix, ifWin, opts) { const res = globrex(pattern, {filepath:true, ...opts}); const str = res.path.segments.join(' '); const exp = (isWin ? ifWin : ifUnix).join(' '); t.is(str, exp); return res; } module.exports = { match, matchRegex, matchSegments }; terkelg-globrex-47e816f/test/index.js000066400000000000000000000502031340547017600176100ustar00rootroot00000000000000const fs = require('fs'); const test = require('tape'); const globrex = require('../'); const {match, matchRegex, matchSegments} = require('./helpers'); test('globrex: standard', t => { t.plan(3); let res = globrex('*.js'); t.equal(typeof globrex, 'function', 'consturctor is a typeof function'); t.equal(res instanceof Object, true, 'returns object'); t.equal(res.regex.toString(), '/^.*\\.js$/', 'returns regex object'); }); test('globrex: Standard * matching', t => { t.plan(12); t.equal(match('*', 'foo'), true, 'match everything'); t.equal(match('*', 'foo', { flags:'g' }), true, 'match everything'); t.equal(match('f*', 'foo'), true, 'match the end'); t.equal(match('f*', 'foo', { flags:'g' }), true, 'match the end'); t.equal(match('*o', 'foo'), true, 'match the start'); t.equal(match('*o', 'foo', { flags:'g' }), true, 'match the start'); t.equal(match('f*uck', 'firetruck'), true, 'match the middle'); t.equal(match('f*uck', 'firetruck', { flags:'g' }), true, 'match the middle'); t.equal(match('uc', 'firetruck'), false, 'do not match without g'); t.equal(match('uc', 'firetruck', { flags:'g' }), true, 'match anywhere with RegExp "g"'); t.equal(match('f*uck', 'fuck'), true, 'match zero characters'); t.equal(match('f*uck', 'fuck', { flags:'g' }), true, 'match zero characters'); }); test('globrex: advance * matching', t => { t.plan(21); t.equal(match('*.min.js', 'http://example.com/jquery.min.js', { globstar:false }), true, 'complex match'); t.equal(match('*.min.*', 'http://example.com/jquery.min.js', { globstar:false }), true, 'complex match'); t.equal(match('*/js/*.js', 'http://example.com/js/jquery.min.js', { globstar:false }), true, 'complex match'); t.equal(match('*.min.*', 'http://example.com/jquery.min.js', { flags:'g' }), true, 'complex match global'); t.equal(match('*.min.js', 'http://example.com/jquery.min.js', { flags:'g' }), true, 'complex match global'); t.equal(match('*/js/*.js', 'http://example.com/js/jquery.min.js', { flags:'g' }), true, 'complex match global'); const str = '\\/$^+?.()=!|{},[].*'; t.equal(match(str, str), true, 'battle test complex string - strict'); t.equal(match(str, str, { flags:'g' }), true, 'battle test complex string - strict'); t.equal(match('.min.', 'http://example.com/jquery.min.js'), false, 'matches without/with using RegExp "g"'); t.equal(match('*.min.*', 'http://example.com/jquery.min.js'), true, 'matches without/with using RegExp "g"'); t.equal(match('.min.', 'http://example.com/jquery.min.js', { flags:'g' }), true, 'matches without/with using RegExp "g"'); t.equal(match('http:', 'http://example.com/jquery.min.js'), false, 'matches without/with using RegExp "g"'); t.equal(match('http:*', 'http://example.com/jquery.min.js'), true, 'matches without/with using RegExp "g"'); t.equal(match('http:', 'http://example.com/jquery.min.js', { flags:'g' }), true, 'matches without/with using RegExp "g"'); t.equal(match('min.js', 'http://example.com/jquery.min.js'), false, 'matches without/with using RegExp "g"'); t.equal(match('*.min.js', 'http://example.com/jquery.min.js'), true, 'matches without/with using RegExp "g"'); t.equal(match('min.js', 'http://example.com/jquery.min.js', { flags:'g' }), true, 'matches without/with using RegExp "g"'); t.equal(match('min', 'http://example.com/jquery.min.js', { flags:'g' }), true, 'match anywhere (globally) using RegExp "g"'); t.equal(match('/js/', 'http://example.com/js/jquery.min.js', { flags:'g' }), true, 'match anywhere (globally) using RegExp "g"'); t.equal(match('/js*jq*.js', 'http://example.com/js/jquery.min.js'), false); t.equal(match('/js*jq*.js', 'http://example.com/js/jquery.min.js', { flags:'g' }), true); }); test('globrex: ? match one character, no more and no less', t => { t.plan(15); t.equal(match('f?o', 'foo', { extended:true }), true) t.equal(match('f?o', 'fooo', { extended:true }), false) t.equal(match('f?oo', 'foo', { extended:true }), false) const tester = globstar => { t.equal(match('f?o', 'foo', { extended:true, globstar, flags:'g' }), true) t.equal(match('f?o', 'fooo', { extended:true, globstar, flags:'g' }), true) t.equal(match('f?o?', 'fooo', { extended:true, globstar, flags:'g' }), true) t.equal(match('?fo', 'fooo', { extended:true, globstar, flags:'g' }), false) t.equal(match('f?oo', 'foo', { extended:true, globstar, flags:'g' }), false) t.equal(match('foo?', 'foo', { extended:true, globstar, flags:'g' }), false) } tester(true); tester(false); }); test('globrex: [] match a character range', t => { t.plan(13); t.equal(match('fo[oz]', 'foo', { extended:true }), true); t.equal(match('fo[oz]', 'foz', { extended:true }), true); t.equal(match('fo[oz]', 'fog', { extended:true }), false); t.equal(match('fo[a-z]', 'fob', { extended:true }), true); t.equal(match('fo[a-d]', 'fot', { extended:true }), false); t.equal(match('fo[!tz]', 'fot', { extended:true }), false); t.equal(match('fo[!tz]', 'fob', { extended:true }), true); const tester = globstar => { t.equal(match('fo[oz]', 'foo', { extended:true, globstar, flags:'g' }), true); t.equal(match('fo[oz]', 'foz', { extended:true, globstar, flags:'g' }), true); t.equal(match('fo[oz]', 'fog', { extended:true, globstar, flags:'g' }), false); } tester(true); tester(false); }) test('globrex: [] extended character ranges', t => { t.plan(13); t.equal(match('[[:alnum:]]/bar.txt', 'a/bar.txt', { extended:true }), true); t.equal(match('@([[:alnum:]abc]|11)/bar.txt', '11/bar.txt', { extended:true }), true); t.equal(match('@([[:alnum:]abc]|11)/bar.txt', 'a/bar.txt', { extended:true }), true); t.equal(match('@([[:alnum:]abc]|11)/bar.txt', 'b/bar.txt', { extended:true }), true); t.equal(match('@([[:alnum:]abc]|11)/bar.txt', 'c/bar.txt', { extended:true }), true); t.equal(match('@([[:alnum:]abc]|11)/bar.txt', 'abc/bar.txt', { extended:true }), false); t.equal(match('@([[:alnum:]abc]|11)/bar.txt', '3/bar.txt', { extended:true }), true); t.equal(match('[[:digit:]]/bar.txt', '1/bar.txt', { extended:true }), true); t.equal(match('[[:digit:]b]/bar.txt', 'b/bar.txt', { extended:true }), true); t.equal(match('[![:digit:]b]/bar.txt', 'a/bar.txt', { extended:true }), true); t.equal(match('[[:alnum:]]/bar.txt', '!/bar.txt', { extended:true }), false); t.equal(match('[[:digit:]]/bar.txt', 'a/bar.txt', { extended:true }), false); t.equal(match('[[:digit:]b]/bar.txt', 'a/bar.txt', { extended:true }), false); }); test('globrex: {} match a choice of different substrings', t => { t.plan(12); t.equal(match('foo{bar,baaz}', 'foobaaz', { extended:true }), true); t.equal(match('foo{bar,baaz}', 'foobar', { extended:true }), true); t.equal(match('foo{bar,baaz}', 'foobuzz', { extended:true }), false); t.equal(match('foo{bar,b*z}', 'foobuzz', { extended:true }), true); const tester = globstar => { t.equal(match('foo{bar,baaz}', 'foobaaz', { extended:true, globstar, flag:'g' }), true); t.equal(match('foo{bar,baaz}', 'foobar', { extended:true, globstar, flag:'g' }), true); t.equal(match('foo{bar,baaz}', 'foobuzz', { extended:true, globstar, flag:'g' }), false); t.equal(match('foo{bar,b*z}', 'foobuzz', { extended:true, globstar, flag:'g'}), true); } tester(true); tester(false); }); test('globrex: complex extended matches', t => { t.plan(15) t.equal(match('http://?o[oz].b*z.com/{*.js,*.html}', 'http://foo.baaz.com/jquery.min.js', { extended:true }), true); t.equal(match('http://?o[oz].b*z.com/{*.js,*.html}', 'http://moz.buzz.com/index.html', { extended:true }), true); t.equal(match('http://?o[oz].b*z.com/{*.js,*.html}', 'http://moz.buzz.com/index.htm', { extended:true }), false); t.equal(match('http://?o[oz].b*z.com/{*.js,*.html}', 'http://moz.bar.com/index.html', { extended:true }), false); t.equal(match('http://?o[oz].b*z.com/{*.js,*.html}', 'http://flozz.buzz.com/index.html', { extended:true }), false); const tester = globstar => { t.equal(match('http://?o[oz].b*z.com/{*.js,*.html}', 'http://foo.baaz.com/jquery.min.js', { extended:true, globstar, flags:'g' }), true); t.equal(match('http://?o[oz].b*z.com/{*.js,*.html}', 'http://moz.buzz.com/index.html', { extended:true, globstar, flags:'g' }), true); t.equal(match('http://?o[oz].b*z.com/{*.js,*.html}', 'http://moz.buzz.com/index.htm', { extended:true, globstar, flags:'g' }), false); t.equal(match('http://?o[oz].b*z.com/{*.js,*.html}', 'http://moz.bar.com/index.html', { extended:true, globstar, flags:'g' }), false); t.equal(match('http://?o[oz].b*z.com/{*.js,*.html}', 'http://flozz.buzz.com/index.html', { extended:true, globstar, flags:'g' }), false); } tester(true); tester(false); }); test('globrex: standard globstar', t => { t.plan(6); const tester = globstar => { t.equal(match('http://foo.com/**/{*.js,*.html}', 'http://foo.com/bar/jquery.min.js', { extended: true, globstar, flags: 'g' }), true); t.equal(match('http://foo.com/**/{*.js,*.html}', 'http://foo.com/bar/baz/jquery.min.js', { extended: true, globstar, flags: 'g' }), true); t.equal(match('http://foo.com/**', 'http://foo.com/bar/baz/jquery.min.js', { extended: true, globstar, flags: 'g' }), true); } tester(true); tester(false); }); test('globrex: remaining chars should match themself', t => { t.plan(4); const tester = globstar => { const testExtStr = '\\/$^+.()=!|,.*'; t.equal(match(testExtStr, testExtStr, { extended:true }), true); t.equal(match(testExtStr, testExtStr, { extended:true, globstar, flags: 'g' }), true); } tester(true); tester(false); }); test('globrex: globstar advance testing', t => { t.plan(36); t.equal(match('/foo/*', '/foo/bar.txt', { globstar:true }), true); t.equal(match('/foo/**', '/foo/bar.txt', { globstar:true }), true); t.equal(match('/foo/**', '/foo/bar/baz.txt', { globstar:true }), true); t.equal(match('/foo/**', '/foo/bar/baz.txt', { globstar:true }), true); t.equal(match('/foo/*/*.txt', '/foo/bar/baz.txt', { globstar:true }), true); t.equal(match('/foo/**/*.txt', '/foo/bar/baz.txt', { globstar:true }), true); t.equal(match('/foo/**/*.txt', '/foo/bar/baz/qux.txt', { globstar:true }), true); t.equal(match('/foo/**/bar.txt', '/foo/bar.txt', { globstar:true }), true); t.equal(match('/foo/**/**/bar.txt', '/foo/bar.txt', { globstar:true }), true); t.equal(match('/foo/**/*/baz.txt', '/foo/bar/baz.txt', { globstar:true }), true); t.equal(match('/foo/**/*.txt', '/foo/bar.txt', { globstar:true }), true); t.equal(match('/foo/**/**/*.txt', '/foo/bar.txt', { globstar:true }), true); t.equal(match('/foo/**/*/*.txt', '/foo/bar/baz.txt', { globstar:true }), true); t.equal(match('**/*.txt', '/foo/bar/baz/qux.txt', { globstar:true }), true); t.equal(match('**/foo.txt', 'foo.txt', { globstar:true }), true); t.equal(match('**/*.txt', 'foo.txt', { globstar:true }), true); t.equal(match('/foo/*', '/foo/bar/baz.txt', { globstar:true }), false); t.equal(match('/foo/*.txt', '/foo/bar/baz.txt', { globstar:true }), false); t.equal(match('/foo/*/*.txt', '/foo/bar/baz/qux.txt', { globstar:true }), false); t.equal(match('/foo/*/bar.txt', '/foo/bar.txt', { globstar:true }), false); t.equal(match('/foo/*/*/baz.txt', '/foo/bar/baz.txt', { globstar:true }), false); t.equal(match('/foo/**.txt', '/foo/bar/baz/qux.txt', { globstar:true }), false); t.equal(match('/foo/bar**/*.txt', '/foo/bar/baz/qux.txt', { globstar:true }), false); t.equal(match('/foo/bar**', '/foo/bar/baz.txt', { globstar:true }), false); t.equal(match('**/.txt', '/foo/bar/baz/qux.txt', { globstar:true }), false); t.equal(match('*/*.txt', '/foo/bar/baz/qux.txt', { globstar:true }), false); t.equal(match('*/*.txt', 'foo.txt', { globstar:true }), false); t.equal(match('http://foo.com/*', 'http://foo.com/bar/baz/jquery.min.js', { extended: true, globstar: true }), false); t.equal(match('http://foo.com/*', 'http://foo.com/bar/baz/jquery.min.js', { globstar: true }), false); t.equal(match('http://foo.com/*', 'http://foo.com/bar/baz/jquery.min.js', { globstar: false }), true); t.equal(match('http://foo.com/**', 'http://foo.com/bar/baz/jquery.min.js', { globstar: true }), true); t.equal(match("http://foo.com/*/*/jquery.min.js", "http://foo.com/bar/baz/jquery.min.js", { globstar: true }), true); t.equal(match("http://foo.com/**/jquery.min.js", "http://foo.com/bar/baz/jquery.min.js", { globstar: true }), true); t.equal(match("http://foo.com/*/*/jquery.min.js", "http://foo.com/bar/baz/jquery.min.js", { globstar: false }), true); t.equal(match("http://foo.com/*/jquery.min.js", "http://foo.com/bar/baz/jquery.min.js", { globstar: false }), true); t.equal(match("http://foo.com/*/jquery.min.js", "http://foo.com/bar/baz/jquery.min.js", { globstar: true }), false); }); test('globrex: extended extglob ?', t => { t.plan(17); t.equal(match('(foo).txt', '(foo).txt', { extended:true }), true); t.equal(match('?(foo).txt', 'foo.txt', { extended:true }), true); t.equal(match('?(foo).txt', '.txt', { extended:true }), true); t.equal(match('?(foo|bar)baz.txt', 'foobaz.txt', { extended:true }), true); t.equal(match('?(ba[zr]|qux)baz.txt', 'bazbaz.txt', { extended:true }), true); t.equal(match('?(ba[zr]|qux)baz.txt', 'barbaz.txt', { extended:true }), true); t.equal(match('?(ba[zr]|qux)baz.txt', 'quxbaz.txt', { extended:true }), true); t.equal(match('?(ba[!zr]|qux)baz.txt', 'batbaz.txt', { extended:true }), true); t.equal(match('?(ba*|qux)baz.txt', 'batbaz.txt', { extended:true }), true); t.equal(match('?(ba*|qux)baz.txt', 'batttbaz.txt', { extended:true }), true); t.equal(match('?(ba*|qux)baz.txt', 'quxbaz.txt', { extended:true }), true); t.equal(match('?(ba?(z|r)|qux)baz.txt', 'bazbaz.txt', { extended:true }), true); t.equal(match('?(ba?(z|?(r))|qux)baz.txt', 'bazbaz.txt', { extended:true }), true); t.equal(match('?(foo).txt', 'foo.txt', { extended:false }), false); t.equal(match('?(foo|bar)baz.txt', 'foobarbaz.txt', { extended:true }), false); t.equal(match('?(ba[zr]|qux)baz.txt', 'bazquxbaz.txt', { extended:true }), false); t.equal(match('?(ba[!zr]|qux)baz.txt', 'bazbaz.txt', { extended:true }), false); }); test('globrex: extended extglob *', t => { t.plan(16); t.equal(match('*(foo).txt', 'foo.txt', { extended:true }), true); t.equal(match('*foo.txt', 'bofoo.txt', { extended:true }), true); t.equal(match('*(foo).txt', 'foofoo.txt', { extended:true }), true); t.equal(match('*(foo).txt', '.txt', { extended:true }), true); t.equal(match('*(fooo).txt', '.txt', { extended:true }), true); t.equal(match('*(fooo).txt', 'foo.txt', { extended:true }), false); t.equal(match('*(foo|bar).txt', 'foobar.txt', { extended:true }), true); t.equal(match('*(foo|bar).txt', 'barbar.txt', { extended:true }), true); t.equal(match('*(foo|bar).txt', 'barfoobar.txt', { extended:true }), true); t.equal(match('*(foo|bar).txt', '.txt', { extended:true }), true); t.equal(match('*(foo|ba[rt]).txt', 'bat.txt', { extended:true }), true); t.equal(match('*(foo|b*[rt]).txt', 'blat.txt', { extended:true }), true); t.equal(match('*(foo|b*[rt]).txt', 'tlat.txt', { extended:true }), false); t.equal(match('*(*).txt', 'whatever.txt', { extended:true, globstar:true }), true); t.equal(match('*(foo|bar)/**/*.txt', 'foo/hello/world/bar.txt', { extended:true, globstar:true }), true); t.equal(match('*(foo|bar)/**/*.txt', 'foo/world/bar.txt', { extended:true, globstar: true }), true); }); test('globrex: extended extglob +', t => { t.plan(4); t.equal(match('+(foo).txt', 'foo.txt', { extended:true }), true); t.equal(match('+foo.txt', '+foo.txt', { extended:true }), true); t.equal(match('+(foo).txt', '.txt', { extended:true }), false); t.equal(match('+(foo|bar).txt', 'foobar.txt', { extended:true }), true); }); test('globrex: extended extglob @', t => { t.plan(6); t.equal(match('@(foo).txt', 'foo.txt', { extended:true }), true); t.equal(match('@foo.txt', '@foo.txt', { extended:true }), true); t.equal(match('@(foo|baz)bar.txt', 'foobar.txt', { extended:true }), true); t.equal(match('@(foo|baz)bar.txt', 'foobazbar.txt', { extended:true }), false); t.equal(match('@(foo|baz)bar.txt', 'foofoobar.txt', { extended:true }), false); t.equal(match('@(foo|baz)bar.txt', 'toofoobar.txt', { extended:true }), false); }); test('globrex: extended extglob !', t => { t.plan(5); t.equal(match('!(boo).txt', 'foo.txt', { extended: true }), true); t.equal(match('!(foo|baz)bar.txt', 'buzbar.txt', { extended: true }), true); t.equal(match('!bar.txt', '!bar.txt', { extended: true }), true); t.equal(match('!({foo,bar})baz.txt', 'notbaz.txt', { extended: true }), true); t.equal(match('!({foo,bar})baz.txt', 'foobaz.txt', { extended: true }), false); }); test('globrex: strict', t => { t.plan(3); t.equal(match('foo//bar.txt', 'foo/bar.txt'), true); t.equal(match('foo///bar.txt', 'foo/bar.txt'), true); t.equal(match('foo///bar.txt', 'foo/bar.txt', { strict:true }), false); }); test('globrex: filepath path-regex', t => { let opts = { extended:true, filepath:true }, res, pattern; res = globrex('', opts); t.is(res.hasOwnProperty('path'), true); t.is(res.path.hasOwnProperty('regex'), true); t.is(res.path.hasOwnProperty('segments'), true); t.is(Array.isArray(res.path.segments), true); pattern = 'foo/bar/baz.js'; res = matchRegex(t, pattern, '/^foo\\/bar\\/baz\\.js$/', '/^foo\\\\+bar\\\\+baz\\.js$/', opts); t.is(res.path.segments.length, 3); res = matchRegex(t, '../foo/bar.js', '/^\\.\\.\\/foo\\/bar\\.js$/', '/^\\.\\.\\\\+foo\\\\+bar\\.js$/', opts); t.is(res.path.segments.length, 3); res = matchRegex(t, '*/bar.js', '/^.*\\/bar\\.js$/', '/^.*\\\\+bar\\.js$/', opts); t.is(res.path.segments.length, 2); opts.globstar = true; res = matchRegex(t, '**/bar.js', '/^((?:[^\\/]*(?:\\/|$))*)bar\\.js$/', '/^((?:[^\\\\]*(?:\\\\|$))*)bar\\.js$/', opts); t.is(res.path.segments.length, 2); t.end(); }) test('globrex: filepath path segments', t => { let opts = { extended:true }, res, win, unix; unix = [/^foo$/, /^bar$/, /^([^\/]*)$/, /^baz\.(md|js|txt)$/]; win = [/^foo$/, /^bar$/, /^([^\\]*)$/, /^baz\.(md|js|txt)$/]; matchSegments(t, 'foo/bar/*/baz.{md,js,txt}', unix, win, {...opts, globstar:true}); unix = [/^foo$/, /^.*$/, /^baz\.md$/]; win = [/^foo$/, /^.*$/, /^baz\.md$/]; matchSegments(t, 'foo/*/baz.md', unix, win, opts); unix = [/^foo$/, /^.*$/, /^baz\.md$/]; win = [/^foo$/, /^.*$/, /^baz\.md$/]; matchSegments(t, 'foo/**/baz.md', unix, win, opts); unix = [/^foo$/, /^((?:[^\/]*(?:\/|$))*)$/, /^baz\.md$/]; win = [/^foo$/, /^((?:[^\\]*(?:\\|$))*)$/, /^baz\.md$/]; matchSegments(t, 'foo/**/baz.md', unix, win, {...opts, globstar:true}); unix = [/^foo$/, /^.*$/, /^.*\.md$/]; win = [/^foo$/, /^.*$/, /^.*\.md$/]; matchSegments(t, 'foo/**/*.md', unix, win, opts); unix = [/^foo$/, /^((?:[^\/]*(?:\/|$))*)$/, /^([^\/]*)\.md$/]; win = [/^foo$/, /^((?:[^\\]*(?:\\|$))*)$/, /^([^\\]*)\.md$/]; matchSegments(t, 'foo/**/*.md', unix, win, {...opts, globstar:true}); unix = [/^foo$/, /^:$/, /^b:az$/]; win = [/^foo$/, /^:$/, /^b:az$/]; matchSegments(t, 'foo/:/b:az', unix, win, opts); unix = [/^foo$/, /^baz\.md$/]; win = [/^foo$/, /^baz\.md$/]; matchSegments(t, 'foo///baz.md', unix, win, {...opts, strict:true}); unix = [/^foo$/, /^baz\.md$/]; win = [/^foo$/, /^baz\.md$/]; matchSegments(t, 'foo///baz.md', unix, win, {...opts, strict:false}); t.end(); }); test('globrex: stress testing', t => { t.plan(8); t.equal(match('**/*/?yfile.{md,js,txt}', 'foo/bar/baz/myfile.md', { extended:true }), true); t.equal(match('**/*/?yfile.{md,js,txt}', 'foo/baz/myfile.md', { extended:true }), true); t.equal(match('**/*/?yfile.{md,js,txt}', 'foo/baz/tyfile.js', { extended:true }), true); t.equal(match('[[:digit:]_.]/file.js', '1/file.js', { extended:true }), true); t.equal(match('[[:digit:]_.]/file.js', '2/file.js', { extended:true }), true); t.equal(match('[[:digit:]_.]/file.js', '_/file.js', { extended:true }), true); t.equal(match('[[:digit:]_.]/file.js', './file.js', { extended:true }), true); t.equal(match('[[:digit:]_.]/file.js', 'z/file.js', { extended:true }), false); });