You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(13) |
Aug
(151) |
Sep
(21) |
Oct
(6) |
Nov
(70) |
Dec
(8) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
(47) |
Feb
(66) |
Mar
(23) |
Apr
(115) |
May
(24) |
Jun
(53) |
Jul
(10) |
Aug
(279) |
Sep
(84) |
Oct
(149) |
Nov
(138) |
Dec
(52) |
2003 |
Jan
(22) |
Feb
(20) |
Mar
(29) |
Apr
(106) |
May
(170) |
Jun
(122) |
Jul
(70) |
Aug
(64) |
Sep
(27) |
Oct
(71) |
Nov
(49) |
Dec
(9) |
2004 |
Jan
(7) |
Feb
(38) |
Mar
(3) |
Apr
(9) |
May
(22) |
Jun
(4) |
Jul
(1) |
Aug
(2) |
Sep
(2) |
Oct
|
Nov
(15) |
Dec
(2) |
2005 |
Jan
(1) |
Feb
(1) |
Mar
|
Apr
(1) |
May
(28) |
Jun
(3) |
Jul
(11) |
Aug
(5) |
Sep
(1) |
Oct
(5) |
Nov
(2) |
Dec
(3) |
2006 |
Jan
(8) |
Feb
(3) |
Mar
(8) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Steve F. <sm...@us...> - 2002-08-04 11:12:54
|
Update of /cvsroot/mockobjects/no-stone-unturned/lib In directory usw-pr-cvs1:/tmp/cvs-serv17430/lib Added Files: saxon651.jar Log Message: Added extension support --- NEW FILE: saxon651.jar --- PK èûbÉÜ©VKîW±ò¶lTý¸$M4èèag¥UvHÁ¤ûÒ0@dvnyt\ÁÈÿG2Ò¬ x¤à±"æÿ°y,(XÔðKlR»É±½(«/¬Jp@ÕKôÓü§v°&ÐÛn¾+ÜcÕßqèK mg8<*ÎìIé¿ïÏ#îO·ÓËõîÙQp«fyͺéùÅ¿ÔP8Þnû«F8K?]ÙIéÃÑuPÃw·Ét¾`]|ßòC t\G/ÇGIUrðíqI"e^ôÇÑc N uDÆÎc(Ê&9ÓìY×pgãm!c8ïâÒD#ÍY¿PK¹ÈH R($ïÃríÂp¶;_(ä¶ÉG»Ät ]¯Wvüꦷ°ÒSx{Û«%oÍÚ~ùPa¨Xâ¢ðÈ÷ÝCï]ºù&O²H³÷D7#2ͼ·xáûbçÀ/ÕVs¢"9ð_5ïùµÇZè@6wT)6Õfeay> êP!#ñé³e6¢zµä¯ ¾Ý*ÏËe=X´a£ÃÆ%tÚè¨ çɳ1 b¦0¡ÐÕ®A¡ïo)¯_¢ùtä¹ þ·(\ CNô¼®}W+ïÖ>ɹôÒö1;fÝ¢w¾B9:AB"SåKmVj£Rë7Yü¤÷õÓ:¼ñn7ÒÜzÕ^`ÃÅ%bWùá2'o6¯é èHØ* _CGÂ8¡#ál² 7rFz[3?|î|9û©÷Xah1¼pËl&`LÒÿ$z,Ñ8] S£q&ì餳H9K²,%8¸[¸Ãß]<Á bkxWx VDèxäÐ-n¡/¹gWe¬%Ê¥G°H'ññDRz¡Ýh-TòÅÄÍFx=<¶ÚÁ±à©X°Ñ~¾¦§®ÿPKa<Jtu uì½èJ_§Ò}U/áB^n@ÜèùHRêIUêËi~ÞÝtËRTÁU²ô÷Ð9ò5÷+»> ^ÃÝ)àì$¸<|oªìܤìÊ0ÇýÔÖi» -Ðë'%ðßPKÃ(oP Ò|YDòk2¨ù&Ì×u¥ù&Íz@ëBóM;_æÛî;/ËM~L¿×àZ¶×qô}¸àåwaéä²RyYÚ¸J]Á]7ï!x´ë-=ßÚðëº[t%Ä®7ìÙìH$׳AVA¡¼ÎËf!sÂù(@5ÑÉhÂ48VQÈó)ÆÇxbAÜÓ» 'ÚcEAêÚSá]¦§â»MOópç'qsF¬¬9\!29/ð(ûtíÅß÷~äðëïZàªpOvD^*=aÏATz]¾N¼ö|Øù´ÝÕî0>Mw#´Ûw¸DgôX¶«"ÐËÃÙ¡@æX0ì9vvõØslhiQ8Xú <ÝÙñ]uajvt~A7 ½ìu£¨cv$gÄXÁÞãwwbQjÃÉ ú%X¬ýú$ä{£»¨.Xc\¯Æ¶×ÂOUZÉ£yÓ,£ðiÆgPÛ1E >Gæ½p'±ß/âJü+}ùKôV* »h¼/sÇ¿a/îÂÎ?{ðîÅë¸B§Åç¥ßRüq«3¦ëqönÁ4ìhÉÃm4 %20VäJ¡D²ÈÛítéxÜÝJw wÈãVøÈß3ø®úÉYy¾Ùt½òµÕDÆ äÿv|ðu¢WHÕÇûXèBÎ.ä²uor|¨è°§ÒíªðVx;eoPwãÓT)û3ºÕ9{pmïxBr÷ òÜ |Ú묰ۢÑÎ&RÀÄNv![½§ÎáG¯ÒsÁ;áÝÇpLygåöà='_pòè 'ïÅÓ³ÖTzÂþnLê >þ_ÿhï9¾GÊþéÔ=¹:Ì »CQÔíðJÈ[X´iïUÂÜþö¹ýÝth0P<xðñ94ÓÝÐÝÀÙø6óéZ'éâG±OÁ&<?ÃóÏ}~Dþ àyø9~ð{Ã_ñ2þ×Ä_¿ÑøµßÐÝ'UxKªñ¦Äð|¯àÏrþ"ûð<÷äàoò,>ð¡ 2NÙÇn_Rdo§ íí2áQH _æªò¨ ÆË#&(¼IM#R¶|s;)aG~§ö,s- NËòë4E{¿£Ê+s«ÎîÄJŨüÉÄxzñ}©eô9Æð!-røÁ ù"Ã,³27õbþTì&gML2ReËs·.R·½\sëÒ¿ÃÂ{:Ê ¬Ò-©ôÝùSbjõéwçOë7=-3Íüõ$ÃüéDÔ]ÁÞÓ³T¶*[Ø{43¥£C½6ì=J«ÂïªÈÿy;üò{îÍlcùºq®¦1·Â Y ÁÇ^v'r*º³ªgç¼]ÇïÒÓÁÇö`{yML^AW Õ¡á`H×BÖZ¾\Mÿ±½Çß Ýxï\¡rT9ÜïÄôPvE°Å&n¬µÖ!Ö02E0¿vGPBÁPàÞã¯t¢j°mÌfº¯E®"j÷;è÷]¨tìÞ 2Úc¼ôðl·%S0J¦ÒîÓQ.3P)³Q+çb½ÌÅÌGTà*Y6FC\À·ýb\/Kp£\rn&q,Ã.Y½²÷ÉJ|CV¡KVã°ÔáQîÿ®¬Ã3²/ʼ*að®\Éè©,i¡bË(iü'[d£$¤]¶_Ü¡êG½qÕaR¦,ÓËÔ^¹)ÌM ãLcqú±%[p?{^J N|þßãøOøYr}¯³M½o´³uÑ>Ò«sðïÓ?Pôòo²}ã©×mì#þhÐìN4h¢ú#Ö$*¬çW«£ÆfV7ìB0Ó;ï2VÆêù}0¯E´# ×°@¹Yõz#þÞP,ÀFü>ýwǹò §åÚÌRR_¸ °hmiAÙû ùÖUúÍwMe¶ù^VÈ¿íÍ«ìÆåwa|ØërÝX«ÎȽ©ë<¸½ëwbFÆöCÂÞü Ø iÝ;1½f¯·ùaw8?Ý+X«<SºqåÞãënÃn¶ø0fT¹=Zv-çöiycr.ùµü}&Ù§¶OcüÓåG+Ï`!Kù1VÉs¨âJùâò<êxP^Æy OòÌsò^7ñ6é½+oõÕãx¯×Bï9ÊÁ+ Fà¾$2Iú)ü?7&ríãlÓYS?mq.+ô³-äîóÓ%¯cá'0®âËõö¨ãg 0öÙÞóå àádBþæýØúýXÎÇ]¹Òï±'λT&ò 0Ky0W,!û5Ã¥d~èR:kW³ØOjÊ> ¾[³þPKÀ¼zbÙ ¥A£+PhÁVÍnvsv7-Õ}Ðê£þz¦çè9þþQï,, èËÙ{ï|÷oîÌþýÏ!Kp³Èc%°Êæ.{i¬eÑu6sÂ}6Ø|ÁæK6 6&ÉfMÍVVÛI/دnC·L[÷×ÑåNÓÓç=£ÞN°bØ-9-¥ÔrÃ é ÆV¸ Ù ô0NÙ}Ñ·]×ç6ô 0H½×-Ç n\+Äòæ\'ð\Û&¼#&VRsnM ¬Z\h56¤·llØä9]uMÃ^1<¿Cg*زüÝ-8 Ûß*6ìm!kFÎu''¯Ë`Qú-;Xö¤ÜNàBaâ?)knaRU¢.¬ÏU*¼«v'±>G~`x)*th¶thUyÇÍÀr?´*uÊöR¼l ôK§vË5[w²À¨YòmÙq¥ ª:¬ù¦çÒ÷-§^qüÀk\Aàb¡ºm<2tÛpêúRàQ|ú°G±ô¢«A1_»¼ø>[¨º^]ßi(ôЯ ÓönRþ¹9´SB,û¦Ñ¤:¼5µ-yÄZ'g!êÊÑx»Åê¥ßqt²Vv+xB¶<K CUÏRa0ÔÅrõKí}âQ:ɽcÑÔwt$ç{ H¼V ýéõN_dÈEªuK¦<>¿iR55NÚñM·ÅU²KnË3å¼Åb`_ß_f¾qEü¨á,^ÒpCcǵ2/³54àh¸)6o0ÔU¼©ám\ÓpïiÁ¬[(kgߨh¨rÞ'X>êbánO@w°£$ <Ãñ7]¯¡/ïΤ]#¥4ÝëwìÐe=zxè<@Ïwµ£YåS#)Hã }¥¯§äOÒ8U|Q¿#Á&É&Uü=÷&¡½Åßh#ͱÅ~¥5 ';>²3sùÞÅ f)vEÌA'Ç(c¬Sjö .1³Í_Åk!/FõpÝ_¢b½Êù±Ô: ! àã¦,^¼JdR4öÓâääðH}{|³4Ѹ¨`ÔW?&È'Ôl%ÝO?Ãñ¿¬tÝÔå2ñr«4Þýå^?TZ8,÷V(Mk#¯ui<اP_Xk?Ý mF^a´¡6úãp&ÔÜNbD=CTJ¶îW\¥ ðg*¥6´8ò6!<Ü×Ù9w¨MÓ,q ]ß°Kl#/áùfò7ð¾RrFÁ<Oq¸Á=êwzý ô¸táy2üÝ/óï.í@ïZ÷í±Ò~pHZz»P>/ñQþ¾åè2åj·¦=GûöÇcæÍ¤kßCcNTéR>ÕÆ`ò'úYA^í$GsaãòìSÜVÙ9zV9,Q4u ô²Â¾ó/PK¹+ö¬ t9Q+ÏIoÚ³¥ìæ-{ÆòJn2#~±Tè¬:]-6 ¹^Ùò³m»5¢Nh¨à tX´Æ9IF*9îzæâ@Þ§Q[¥ã§VËPDé lYU>ìÉX rÔÁtzþTÅrv_zͯÔ|s´\ò}é «àÃ_ص¾ ó^¥E6!×$G|ßXéÃ÷¤4ÕUi®æË¬kÛ2ï\FâªxÔÌK&04K;ñÑ¥¼¬¨kr4éÌ7ßXR9-Ó)0üÁ\_åJ¨0ã³)IGùe£;ÖÖbjZ U¥×,\4_´¼ U4ð/ü[-Jøç\ÀGF1fà?ÊÆÇ¸h`cìµf[CÝÀ%üj»îkÝ÷¾ëzLÃeà Ãúo[`Óµ;Ã,ñ±}¿2d¨ÂÜ188h>:5ÞÔè]Cf©èÙ^á¤jU£hU[EàËO^?RÆôÛÄö&¶Ú@ÙÔÞ2Áä뢩É`~4è©ñRà ÁDlÌ%µý<²äS5æ2·à¸Ì²)zÖÉ.*ËyKE5¸JTá¤8[v7øD[óóm<ý5}mÝõ®7¾&ÜÍ7¬>[¹ ª×©píYVgs¹`¤q\¶Ä#É·}qÆy ú%øl[QÞk_8eZ ìFf1fU*t$°C ÖxÙ4µÖ¾Õ}w¹9:}7Ë©:âyÖYGJÍÖ-¿HDjâZyfH} ³ÙFìíMv¶êKÎép v¼ ¸yK¤][xª£o(Ö½ 'ÊC¬ÝCZ:SÇLVôÞ:¾¡·G×þnK$ëH] ÃCÂ4B¹×G ð$:q¡Í2e§É½bQzL`ZE<3A¨ßi bV©0lçKËU dÊæ¬· `ÓôØí-׬ùLÎsLk~Hjiã´mçtév!cêù«-ÚVñ¡9ûÜÂ%ê¡éSÐz íå)hIõ0ܸ/)ê©KCL_ÐM'"©éálVDbJÓÃ<¸æà¼añÆÈ¢n=Ó¶Ü®òC,ÂqúyÁx«aÍ´õ/f<DQ67|Q0%½Èø¼$®Ë¨²ë9%]xP°;µ6êµI° ¶¦Ælg>³XEÊTäòv$¿l¬kä8âêZES2£*Q¦|ñj_mäéU$ÆìåÞ«$£ä ¢ÔL:&Yg{V24í/ñËu[VÁ:YûÇå¹JîöTvU '<4SòwhÚ¯nL«HJ#c1RÌÅ-jº![]±\Ýï² ¢CG¹áYJÖ³ãV ÚæìájåI,C õ¯Q,gÝ5Å´¯éô>ÁDèc6ÓAm#ÄD{[°5|°@Ò8Ùqtà!æ)ÛëOHÅ8^©ô§«s³·òxt/x^ñp&S.ûÊûûUýó¹±Ì¨í4f°³ù*ØVó<¼bÉËTÕ)Ê¢,çh;GìÌÙåáTNAGÃ57¼UIËþç1¢e{ýn`=¡åK,Í®:h=kEèæ ®ñ °'Ø~¸¬ÄáJÆ8Ó Æ!qÇ¥¹Ð RHÒË Hµ) ¥¶ÒRn¢nÓtq³7Z¼ßï7¼ãq|àÍ 3â8¾xß|õÝÿÀ}qüÎ&©H/v4|çû¾óï÷ÝÎüôçWß .\T°Ã2F"Ø»9"Ȩ1d\p\A'dë)AîqZ¬÷FÈâ>AîÑ+Ã1¡ I \Á*ädäeL ÖqFÆÂ¥¥ ºµô1ãØ: CF8Õ7×ó\Múdb!4àLreÓæCåÂwÇ è¬a®)ä2äM%>´=mX¥©ú~Ç-Þj¸e9eÒ Û"ÖE%·E¿ A.rD®C dhÊùk.úæä]öeO,Çݾ¹¡Õ£é*®«Y2¬_Ü£®YØ- o¸Ü`f7¯OïÈêd;hñ·ÅvÐ."åw3Ƨjê* ¼(Cë÷< êÆô<s]le8ųéØäX±él©hd9õ$p¦«¤ßê}¦`ÑaÃ.êcu»3Y^¬»uÊnï7Ewcó5±[xSé=Ä É"è|ã7ô'c+@ÿA ^FO²¶ÒûH4 ÔWôi(¼p²SÈ]BH¾ì»¸ è&Èâ $lFÚÑLÐ-¶6T`¶Å* äTø"'®BÑ+P£¡ ´«`Yª!þR,,ðK4üáÏðs°Gb)9ôµfùdhY¡iZ³¶²ht «NÕU¬NÉ1YзEÕh'XÇ">TE«`Í%÷ óÖÿã¨f¹VÅHLvT°®#*ÅäX¬'¶ BÛv dcã%4¥¤/p³¶¹öËTµÖÂZ©Õå#ºªºÔzÑE]ØNõï¡:ï£JÀn¢® ãN£{áb ~4â=c ÑÂ!ñìWð "#Æ0µ£BaGÇCT02N*XC8Âi¡j!´0,f@bT1aÂq&G`S`Á1!㬥`Y{D?¨MJz%¨CÆÕWBueØc[EÒg´sZÒÔ¬±dÆuk¬CBÕÃ2ܽZãé¬KY3×&m+ÉAÓûmÛì½²·w°þ@ÃKX6,½¯ÖmØÔE2;«G4Çã1ày u^&«¨ùñJ²ÛÉiîá2Ü.Í4íKtAK¤°vl;êí//ïÚåðÚ¬É %£^ìJP ³6Zp' n²;g¸®îtÌ7 GlXqÜѧ G g§²®?,7 9º&!¶±d±5¡o·©çtKLûBNB¸×´6¬³A³ü¬2,QOét]Bº}s®£ëI1e\½Ë6M=ë¶Å°Å¥ù -«³'¾!Ò'×oÐÅÚ1lÂküdr2g2fåE-SîtOfõ©x»àdõC´:6WGD4q8*îÄ[±ETlC¼ çPT1ó2.¨x©x;U<f Æ]w"LŦbk¨WK{{{òX&]áWtñ¤§ð´m+ n*©0-ô,!ü!ÔÐÊGuD,,-aYü¦ë¨I b¡HÿHd XXÂÑìùkt^ÿÓþV5DåX(ö°:p3RbÓþhàt`äÒá(6ÚR®(aX¼ö2ÂîtÝe,IÉW±!²±Ú+,ÈFü?±¾ÒsÔà¬%Ú vc%RXzÞÃòß˲w²¼÷qfÿÝ8b?Æp?_`ðq 1÷ÒO"nAÉÿ fA{ܱõ¨fzÀlX±Ìd+6ÙPTª²Èä?òIN÷ÆdEé¹}çûè¿þùãO*Ò%Z¯Ew¦!ßP³B÷Mɸ×ñ¤±6£ò Ozê&£¢}qÕv£9íq?îmð!ßö¡9Ú \îoòÐÓ÷Ti©®ó7è9ò9÷£®ñ½@::¾ÄRµzR"l0* "Ñ´?°¤àPu»<ä.Ü [M\"ÅCá©MI|µµç¾òU¨ `é m)ÃoWurç^àÆº[ËÉŲM)É{"©»ÖWD'wÛ2RaìjlFìÎSþ;>»Î aojL5n×¶®8lhÃîª BF§ìNî:{=_wÐIõ²âjú F ¶"÷GõÈ%2 {øÜ·Aà3:ky®µ5%ñýð\îw²ITz!Å¡AÃò}èa¬¥ ô'Q$åç©y~ØÊhÖ|r3æÍîÝ~¯wº¼+5¶õ©òL ös®4êsW]Ã>Vd4د ]±îém¯ /õeMz*45C%*3Zø-53VýX9ÙÖ{© ¹~Âóp 0[xZ«¶×Ù!ÍAÓ¸µ¨ ( þJ#i_hq>·©ÓïVtnV'S 8esEÝÔémîÁ¦ÓéÓ=~}ÏMJ)ýs~ç×=çÜsν¿Ý?òl=8_-Å\/à_p£õnÜ$ßÜâÂxpÛK©w]èÚ.ÜåA¾. BÙ(`Ðz\øHßíA%¾)à[îÐ+à^÷¹ñmîÇfßð]¸ñ=7l[lr.l÷ >ð°ïxDÀÑTÀNñ¸[Àc¢ù¸»ð én<!¹ñc7~"¤ºñ¤O¹°Û §*HÚjíf 'Z F80Ó ñH&cf¸4óL FW)kº0²:ÌZ±xPê<ñXÂm_a¦T:±t¦Ï*IKÉEÈòæõãÄJê§c4àèlÓLW{²%ÏrWGG¬ÅjS(Í©H:b%Ób5Ùl6Ó¤UçI±DÌ£p¿)lÆ¢ñ`&ÒL +ÇÍtý *TBb²)Ò>ýpù5ÃCȤ,kà"#ç¬` 1mv4ä¹¶TRÒMfå¤J-³=U8i»¼BÝvÌÀ2¢[öe1Æc¥M38¬Ø¬e6H´Q+LPÃE·æj%g¤Ï¡¸¤\-$$6vkMÇêH<˯-Q)6[cLHcgÔLÑϰÈ[éöÕÔ¯Jí~£(kL5H^,}h)Vé¸)^ìl×!S¿,pO¤HR8êpÂ82©HÔÔ§#uÈâµeLFRYK-d]wÙEåRl§±RÍtK·5y s´ê`bÕ?;mJ<5¶ú âðÎÁDóÔ²î¢ñBËÙü:àæd6¥ªôÁÈC«bôùxÖÀ)h0p* Ó |N°&42ûc °y8.¢}42~»ð¥Xfày¼ 0ãÓ¦_àEbò%üÒÀËØc`/~¥0ñÈJÕÀ¹X"ýÚÀoðüß ö{À+ pa? çOxU Ö5 gÓ)ÙÖV3màmüMÀ;þw{ÏÀ?Díø+p¥8öoÞ7ðÙü°À+¤Fò´|Zz¦%¶ÚÀÂ×fY©P0ØÑÑ1cú4)ÜãfÍ<·¹)xn ÃÈèJQ'A#H5$Skl¿ÄÜ©ÆJGiÛàÂ>ÌLÛZáÄO7óuÕ¦Ö⣠gTÖ ×5Ä×ã3¥0Â?©ß]2Å ¬ê4yÅÅa®í©l3g¢ÿP Am885Zý?çö2£¸ñaçÌè9 ÖÌWgÌ`·³ÌR^¨Ç®ØâüäuÕWwÅ@E*Ä-fçüV¹Å³+2j¥?<ø6Nó¢,+Cü$7Þ´´T8ߨÿE²S*Ù1+å2¤p}SÛî$sÛ#äæüèvFR)Þ SqìÐóý̸«K{ë¶}ù<¸Êy«ö7|¾3^Á)Ϲ «7Þ©þ#z±ü¯K¯ê°%¦0é9è9ölRãøR=@)ìrs³Ëå¡¿¼?øÕMÏÔ_»\)úÛTøU ÏÓò.(Îų ?ÏÕ;ü9pñ» 0yÊv¨Úmlì÷68Împ¼®mp±4°%ÛQ&vª!]¤ª"å£Fé´ZsPNx2ÌäÃ<cÅÆÐ· ô4óq. g9ãÐó#J[ÐLí3ò^b![s`¼¸`¹Mc»]c½Cc¿:¼6)Ïèm ®½Úv+lÝðKØ/er0juì¶:GM³WÝ:ÙçQáÙ¤.õ96Pt+TÙm>GC)RHLÈÕñdäP¾!·sç0,oK°áçäù#ºöï²ûëJ,/`p+½ø°ÊÕgTÌøv¡2TºK¨8r; ylue½¸·ªÔWCUÈÈ#£êäêÐÐ<R*Ï#µ¡ ïèа*£"à 8ºÊ°9Fae_Ã8¤xGwáxnYÚEw ïxºñ!tcT0Ø1ZÖÙËÀ=Uê*hnhUyÖ)_YUi{ö/,&Bü+ÀÃ$IR>]7eëEyÿ|s*³¦vyÏDZÁä@ > á*VB;;%jd0Æ#IXãq1+óV奬Ê+Ù!k©w+r.ÄÕ|w%÷|×â\ÛqîÁzܰ7c'©»q#g/îÀ>þ³¾n>HîÄG¸K)lPeبFa ànµ÷ª(îWiܦ.ÇêvlU=X¯6c»zYõv¨'ñ¨z;ÕËx\÷À.Zíëbç±kÆ.`½hìºÆªíì¤óÙãÕVÝOLT²«YóóÕRöV{ê`p3·ØN>ÑZ±3g7mÄ<x/"FÝ2F×ÅÅ}¸mÄFúeÄIÊx/cÃìøÙ± Æ~3Æ0¤ôµ]^²ù.T¸rÓ5f{GÏ«¶oĤÃÞºjARݺ6×d©¾)Õ9LÍaÚ¼^TÈ59I"T~¥=û_-p C»@¡«{Ys¬§©R1Ç-bY'·gÿ[Ö 9 ê,ð~É{µ|ÏÀ,Ïÿõ2ÜÃÚË"Úëù,¾¯èã²8ºô ç5ÄÒ±¬Z\OÍ0/¿>\;4A£_ò¼ÙóÉÓ£L_ua t£¬0zdÄa¦¼Ü÷ê¸çùñ×9ßЮUæM]«ÖçªÚñÂwÓQ ezÖ§w£f*ª§LõÙ·cFÈ¡»Ö¡\a¬ÑL6ôWFiï²ÜÞÃH>ÙÇá}LÄlÄûekzÑ¥é»_ÔOgK^ªþtüír±ã Rã¿@þºSv³NÙ»pMqÂlABwf'Î w´wñ:{a #/Vg9ûVçÊÏCwMíF µ5>²¯ÆçØòs#Jk|®M,ìͶÍÅLè3T9\ªÍ2µÊj}hV#qªÅjÎÌ|Å̬-d¦1¯Õc Í}^ëtff²®®ÖuÔz|IfLeã6ò8Ýl×u2ïI[Ù[P/Ǧ´³CuºgÓÌgéölnvä:Ìå×£ÝC^ÉPKÐ( &nHç{r{RÙbOS1ÕÏ5mqÄôL*¹ÉªÜ#T´Jíg[ë®[¯T×ìNeËêCÁ»:ÛmJ¬\·B!Z7EçÉ:îb¦;Çug¦;Sâ=kêK%VÛÞ*ðv ËZ²tæs¼«/O:OW*]Ê8©ø$<1Jk¢µùBoª´¦?mõ2ùÍ.AxÝÚl>Uâ~-mÂP°¬Î.Î:¨µæs%«¿´¤]Õ<îMWè±ó"ÍîT¡-ÕKmúîaÅÎ!·úû M[üäð®¢B0{ÚõÙ¬ÕÊ®*t{ÜYæÃb¦Ë}ùl¹7g¿WîM:¥Êñõ¶þ¦þÞlS©Ê»gÓ¡U*êÜU.οý¼@V±³/¼C¹A;ïô~¡Ôu²lÆ vX0³åÚBª[!7Dj(÷òµ0Ö%Ãg¤Ôsô`{>L>6çPù.]\Ó)ÄÙc£²ZG:s¨Ô-råÞʾzñ{DÇm¯öàôÝ/¥²i{ª ÂIÛÎÀÑS;CG:G5é|9Ç÷Y³§¸¼gBÌ"'ôÈbرæ$:_º<lÏÜóÙsu_gªdX¤/Mg¤ftäË ´µ6£^½a'¥Fea¬MlÅ54*ÃÌ<'M\ vÅûkÿwHîUËÿ⬷C_Z %5ô¸AéïøoüÿÅoÎÅuu¹«Ë*ø?¼§÷M¦1E`úRWܦÔo3)&rùR"ÈÙK'ÊE«3ÉKVª³Ñ+^StñbHI ~Á®Oäò{r !Çp )!tòj³½6%"ã¼2Þ¨_û `üÕ¹N«e¥31Z&6¡Y÷â çØâS.b«XÎK{ûè=è'®]y[p5}çÔÇFÛkö3aÑW;jKP÷a³ q¡¨5ñ»¸Í+LÉD¯ÄM$ À #ÏD¦2U¦2¦$dѬ7e&ºø4d`Ú7X3 FFªÙmÙniäëPèÏáQIæðÂöVl4Ö*$J=©\¶>a[ßÈ4ða¢FÝn®W.2¥Næ æ'1ßC¢ZöP½ú³¼«vî²Ò%Uëתïê+sÑ<ºW(Ý7vKɹBÉ LÊùùÖTaU¡Ú«èæ©"ï+w(ÛjÉÍêë³r|â Õú1[°%ßäºÖ8ÕKù¡¯«ª×èK_ÎÓÓ¬=ÛнJ&W^aèôu|S;Kd±R½KRÛÙÛ̺}jÍGõX7SªÕVqÎ<ö®nÕ]ÎvZÍQF2lk¥µc§JE&7´1óìë*çÒvÑ´¦¿dåB·TgÈÇ*Xóÿé> Çx¾3U½CVÕÅF´ªÝSêÎUvVõx¾³J?Ø6\Û§svuv®õ£m笾¬zö3ÆPK¹¦¡"©kÓv·V*´>+¦£ª-gY¼ÿ*&Ù uë«ÇÑdøùã!<ªVÎn ÂÕ¼êÀ÷W¹ ²kJ×·w¸òÍv]ÙR°¬¡ìÎ<9ü*MfðÇ`ªàÌP%Ìþ²|Ù_'~í>_D5¯åj1¿¢øëOBçDÃvIã¸n ¿Îf¶p=>n¯nðJª¿Ï¶í$\'à>w¤æ4<Ûûÿ$ôAø®Q{³wÇxÔæOÂ?´ÙÞ;û¡uÙÙ3ZRdädôö8µm:ʱi_q3êÀ4¢$mD£x|XÜCc|ØcÒjsÒC0&÷Æ@!( nB¡Zò@db§¾ NG^£#ÀxËñØ{Ö(^·¯Ou ^íZîÖR\£{i$º1m«Äwms+éq%½f³îJúhüóððqwÔ{IhþAø+³£gxV£-Ýçlzãî§ÁçNz°®r~ù£C<Á¤Ê¬ñ B¤©zkÀÔÓHÇ+vÉ &bÊÆ¨çþ÷4ÂÔæÌh1cú(âHÉ1Ãl®cA$:`o¾`³§ÅÏcæãÅ8{£>PÜÄ5ópÜ«é»èrÅ>¹{¾¨ï(Ñ;¯ãôwí/`6Ç>®nä3.ÐsEPBeÇnÄØÎMB?¦â&ÌÂÍßA_Ǹkq6`?_Îôɤú}RÜ Oãnäx_¤¦{ñîÃwq?^¼¯â5<7ðÒâÅ! ã°Ç amFhÃíìÃ>>!ûæZ¢0pç?Ë6ÖB3£ýò6BKû4l»ObiKMC¼fËÔ°<éQ-ÞÚf=êyÒÓâ«m6ìI+iàé¸7j.jñÇýXDÐ÷»¢A¬n ÆýÑ{û%ªð ÇôXxg³÷EÍXxÓ )°ÂtJ¬- VÐf°Á J4Xµ,³ Ç¥RH© WAiHÒÓX¿mAÜ÷ÄG[ü q¿zØ®<Ö¦ÀÙ@p1LÊ̹w3ð}.·Ë=²ZÕZ©g¶lO!2#.ÂtY9r)$ÅÒ¤0e VÈR¬å¸RV`³¬ÂvJØ!Ø%W ,Á-²·ËzÜ-W2G·á¨\ ÓÒ3Òe¾/[ñCù^mxK®Å¯åzþòý¸¸e¹$'QÉóçw²Þ(MR¤e¥ä:Ù-í½òI¹Inå¹Epõ×ÏËò=¹M^áÉd¿¼!wÈÛr§üF>#ïËÝZ|V'Ór¶ëËäÚjù¶NîÕ¶Ê}Úuòe--_Ñzå~íN9 ÝdzGå ö<¬ Ê!íYyDû1×oÊö®ÑÞ£.·|Óåc*MÉP§ÒÎPúål?k«ËÀï±âihïÐw1×~ÏÐnL×^Çgñ9&íì¢ÚY k/ãó¬¶^$µXUZª½/±>ú°B{52Çt½F{_æ^-ÖiOâ+äUÿn9ÎêÙ?}û]ˬ|=x{A¾ëYW;DoáþW)%Ì[L±«ZI®]éÂxÕe"å(É~ÖÒvÍð=ÌrNW"ÎúCHne¯ÐÝâ¥$ä .¨qtµvtµ^GGDû£#¨ ::BÚ³°ö.?áw©nOq;4Üd¯³Ûq`JhÛѳë;îE®{¤ßD?ÝK ËP·VªµÌ=Á#vúèoPKxꫦ êcã ýNJ(Ø0dÚb8î1iQÒ<ä$ kÜpM¹. Þ´SÐ:t2qû¢aå¦ã9cαãcbÎ;¬`½´sOz¦cûAÎ)Ø1æûÛ3L{Ld²á>'5¯ )ë¬á^ÏsÍɼ'è<¶¹ AìvÕª+Q/Å?kzÓÕm«O ¯²V°+¶¶};kuôzÞ ï¯<ôæ>tßóòªÅ^ÈȲS zïbñÒ.ì9åc5=7VÉæsÈT.6Ái*Zåp¹ÐWýû+Yj²ãÊâÖr¸G7[b57üÃ_Þ*ÝXRÚ~ÿ#e\tMOøÊQcçû¥eÃJo¼e;òò Fç ¼ -''°í|-Ë_¼ÓøÜÉÕ~ Ç`×;ÔáQ>5À^°q¦ð8vqTðb%=%uÛë/9ReYW±ì|Ëã5-»ºÎ·á(ñ5w5×P?Ôý;"þ4°A3±#*µ×aM8ã{Ý\´,yUi·d7W{øW"-ÓS@p5=48WjWODßò7eë¸óWw¡EäÃ]»PhÂp"¨$Bw %BèK¨r}úÄÖ77°!䣯FG"üÊ ÍU ´Ü¹ÑP°YºjªKØ75âç`"RP[ÞÔoÒ FÃÑH['jßü÷O4\@Û"¶'Ôª ÿ"\ ¬q¾v1_;¯U;xä¡ _ ñ¿îëÿt~#¼ªÐ ìdQé©=UðKÅn¬&Jÿ PW«ÞNÙô¥.à;#Þò9ÚÎÈ$JM8|;TÀ-µáêÑ{J+hø_âêÒjTÑÂeî¼" u¬Òò À/F̬Ð^Ûñ>¡ò_ýåù+1ó¼eßJëxÆèsF_ÐßÍñFí®òçL¯ázNúFÎîæOPKxh%µÒ ´i×ìº0Jmt]@<KO»@ädëT." (D.âD@·VºAP/wD xCôýONÚ´MWðq}ò_¿ÿû¿ëûg½wï}ð`±ý8×jØéG®Õqê¯WÍ ~|7úñ%ܤáæ"Ü[u|ÙÛð»4|µm¸]5_ÓqêïTÍ]:¾îgÿ ?vc~:¾©ãn:öêØçÇ=¸WÃ"ûoû± ¿Pt¿Ôñ+¿Öñ¿Õñ¼ßùÑ4üÞãð¢ñ% ðc-^VÍ+:^Õð×FW¢ÝÞ³R[-ËÈ&ÖèLÇÒ)ξíÑN{« (eõIÓN$3Ìmf8fÆ»Ãív2ï^!(±X"m§Ú-;ÝËy§Õe¦cvc"îó¦î¤Ù»5I3¿)ÙiS3k5ûzWc ¼%è Ç·±ÔÖpÊìKÄÃkÉÓv)xqáÊh<j7<Uoc¢ÓLkƶtÏ+¹ÞÜ³Ô Øa&£jî.zíQjzÀøk:¬äÓö¬PÒYvö`U¥CÄ\ÊÆDܶúìãRÏPZ$C/=#Òl3mfoÓ· _<w¹Õ×w±´ÅE¤Ë\!(°Irîî÷õÄÂvÒ§ºh·ðúìÈJ6õE¬^;ó´'jòHE¸Í±ÕmÆV'»Ó=VÜÎ%¤GìëÜ9w"«(xâ]d¿ }ædƹ¼§Ä ÅnÙ<¡©óX¢~oWR©´»N§`{H,XrMÒìV6vE,ÒÔµm©²h|`)ÝiÚ4CÄ:µvU¦lZ´5űD÷Ò%#r,sÉ%:%~QÉ=%Ã{ÎEªuD,ò#t´¹JxlXÆëÐ6â¥->.vbÃMNJ;%²ssrvr<q2ÔHgFí¶´Õ^fê Àw²ÂÓ&ÑxÊJÚ#\Ï0.Éîðöåp§RZh¨ÿO´IËLõZ,[Á¬ü×ÑÌ#°`¼ñ\=rÜ¿2s1ÌßH'#Ö¨Jøâ,ÕªÄ1ðaÎKÇBÊ1é®.uTø#Þ0ð'¼©áÏþ¿jxËÀÛxSPù~Ñ@Ã;þ¿f'ÓÇåYª/×ðÿÄ¿`:LNB»õh§åNFu8Pg+EZkÜÑfo5`¡Kûþ÷ó'ÁAUE~FåÑTy<aå½úrÁѤîÛvpEå|Çg¦Ëyg¥_ÑÚ¤â»Wkï襺þcPyák6z8*h& C ÄcW|¢nHèø "&ÅLi ÷»,)Ñdº!Ág ',Ê ]ç³ Ê¯;7©f³¢[êVµnq+ʼù]¥ìÆYÂG=»ÎHéXÂÚ^§¼;nð`ÅSNÄÌ·¹¹6¥AK*öKOà&(S\ìsS^z¦Sq{.µ) µ©Ë*&!É'HÙØ3£Uã9f3Çèr0y" ]xÏQ¸81ñz:%rO©ð? d*ÚÙ¤9C&Ö±FpÂñ62'l9ÃPÁB³·×w j*ßOaAaæv"[ͬÌ[ 7eCÒêÖ6©*¹¦Rpî§D3Ño3SY¡sLѾ#e[´Ç)ÅK3×Eáu¤´Ioª:gl¯Åm¥ùìÇ¢pzÎãA}ºUÈëÔÕ¬,ï±æÑò¹"Zg¥éÖ1g2\QµIUzVoÌÜA`kJjÖ¶ÃÙ·XÉUËbóIÁ+§0muÐÅÃßÇV±óuÅê (Íë$¾âüzhÌ)ÐÊ*ÇziT6g¢½ÌwHÛp7oÑ%\k¾°q¯ÙÏÁææñvߤìR6>+½;R wóòOZVöUãk2N̼Eó±ã<#ÓxƯ4;B.ÿ`l3§æïïC±é4æ¦É¾_ó`eþB²ªøñ~ó~U59#TN¿ÞíYR9ý)îþw}£»¾Éí7»ë|~Øk¬ßXP²ýgËÙ³¤/´²qÛ ðÙ"ètf,Õ\¯ÁBö§K«´ P°q/<ï |Õü ¢p´ÖAèmw×{ûáÏL!(Þ]ïÛß.òbÿ~5¦º¢Ì`+gQîÄPZ/N^4°¬Z5·52¢¢ôpFQÚÅ-sÎtîØLTjVS+«q 俣YX¦e i<äñI} P>g 9ÃÀ¼AÈ+÷Pô¹T»³ÑÎl×<Ç íNªqt\bÜé¸3p3OÜÊ·Ñ,·óÔ<u ²ªöÓ`wãlâBìuL"*ën sLWA.)RðtvT4¶¹f:·<quõßÚò!, rÛjbuÞRÆ´[ yw¡£:_©÷â}8h&f8k%Ï)¹öLUý>T^áÔé¡ATÕª§áª7þR_©Þ@?fìEMý ãijïn£}µ4gÍnXKøWä«Óؾ@O¿Èµi¨W0¯2¦^Çb¼ÁxIñóçm¦À;8ïâ|~¯\Âì¸u¾2ÔG3êÇØÕØ>ÞäÃØÁÝrÝNÓÃè)£ÏevzÉ}3>Æw´àãø#uà<®é¼/Ä{. LãòBºÁÏó.ÂÅBùÕ/N~~UGeï9î§V¢qZ<«< %Kë¼:_ ¸¾°då ê®8±Þ ùõE9Áz5¨çDk]Áádp¦sTì½U¡Àû§h(Û3B#]*Ê ÔO+rZ¶F ´r´@JÇ!¬ÚXÝ%ýXÚeNx4à¨]¸iÞN\ =°Î;ßêÑüJÔyCcrNøvaá¨c$PU @SnBÓÆê`a©·Ôç³ÆgúSráx.ìa¬c<lfZ?Ï|³e)+ÙwÊN÷3*èR ¿ÔÀZH ´´¢LC¹Ô¡BG¥9°^_:9 r4F¬&lã°]Ò²7ËvÜ/'ãéÀã²OË&<'§áy9¯)ºDÄ.9R ¤R&d¥%$%§ÊvJ»Câr¶\*çÊår\#çËurÜ(ÉÝr<$W8Yt!±ëf.CNÔuºò½+ f{ñi<Ôo ´Bbæ$@)0¶ÝØ7ÎçÞìÚ&éÐ6lkÙK»klÀºÑ¤HS§â 1MÚ¤Riöa_&Möaûö=ç^;I!hrÎïüÎï<ç9¿·ë?þ÷7¿CIüBCÆëÇKr8%Ór8#¯j8¯Éáë¾Cò!ø;å*§Â[*ò*¦TXb8§a#Îk¢ él f"ø¦Ýr.É¡¬ñ¢ÌF0ÁËÒþ¯jh0íxMÃE\Òe¯«xCÅë¬i#of#gæÄéfа RòVÑÌ9ã2fK©´ÔôrkÖʦx(M9gÎH9üe[¥ýMqÿ@Á°ó©ÑkÙùÞ®Ê!'G¸ Ë6ËÓ¦;fL¨e¬Q8i¸\WJiÊ* lËdé=kS©¢1çØ>´-V¶H:ªÏÛP\MkZµ10%e˱¹°\Mþ¦å¤úʦkæôË}¥@¶urÊXÓVI 7Kãþûxº.Ðsæ¤Q.Ô´Ò ßwJm§ºÌnÑìsæÈ9븶éò3ÒY§l<Pä°ÅçS.Y ê+Æó¦m½âQò£tb&gÈlSüáð¤å_ô¦ó¤nÙÎdÁÈó*ÁÅËÕiå§xS¨º¡:e7kZÒõy¸G^ ãÌëØn9Ï¡)_Â;±CÅß·u|o©x[G®ªø®ïáû:~wÖwqU ymÿ3µ ɬ¦ÔW+%¯]rø¡~¤ãÇxïê<Ú?Tñïã¾/uÈufèøÖ3:>Ä5ºá¬ë¸!W?Õñ"vÑ÷mtMëÀÑÑÁ$ó´³³1ÉÑû<·¯UÇÏ0/°ù±¡Ñq喝¥ã¶Äý9>hýÙËòZqËÈÄ93˨´,GÔµfd¢hºäûqYNÑe£1Ç)¹ÑK</áuñ®Ìý~¦ýúîX«^ùúÏkÚVeÞ<{ee¬zÜØËø ¬Ï]×´Kµõ2ÁUV²Å¦9#Kì|mù®&íÆxfuxÍ¥aEW]©H°WÁ¿f¹7DÖ1W%Ã-Ç-Y±k63ÖV]±<Q¬hbX[µì972ùº§9^ûh([p²ïØæ\ÉË0>{Åùcæe*ø %-;Çú)£8並g]ô²ä4Úøaè@òÃâõ>;ÉêÌöfV±ÿ9òæíYS¡"ÄD"x9âDàBr'îBÝ^AD*p¨ {èºm¼ëîbý¡Õ5y<ÿ ×ÑÀ)¸õà/ÃïKõ5üYáhn·rÑS÷°ÿ±SÛаÆ%4 uWÐ<¼£ÉØ*Øt /.`ïåA2¶Ù[>j|q8ÛRAË lH}±ÃäîV<&å&2ÉÏ|ºLÆôö&c´¿ÔÚ=ä6OKF7HäG@Tü}¡}¡îûÐ©Þæ->æ=8~Ô³ìÏ¢^ôD×ì¦ó+. ¡«Ã6êÛÑlB'¶2qn·Aëg¸¸:Æ@¥®½x½üÖ?Ëxó8Àw·p´üñk¶º{8? ?áþþ!ü#ø7mþc"QQ1¡ãhÂIÑqÑDN.îñ6±èEÌs¢ù pÿµ;øæ(m¾ÂüP¶!Wß÷Kjq´µD\¸ -¡°5£»Õ&õRz¡à¢²âÊ'èDðç@ÞáÞåï£0µ?ÄLÖå4â#kÛ)^)¥£$ð¤cE)ÉãI² <iRÈë1FIåéÿPKäSÖ ¢¤Zû#* Á Ò¶v7ap2g&j[íûÝÐ?Я¶]]u®~îè/èOèZm÷<~ÈÌ}ì{Î>û{2üóëoá8¾×pc*.k¨ÃXWä{\>&4$1©á*ÞPqS⺼Å[*nD1«á önb%ÃMÙx Ñ¥ }ëlBÎÏV^×@\ñ:èÞÀZ!^ÈZqß5l/í¸Ùøty$ÜÑBJä|Ó±y:d<r¤Àea¸|VØ~5¸É~>W¥©m&ÌTc¾zsSMkDd§dFd=ÏD°H\?}Û¦CÛ »k6¦ÃkuJçíäìÅG¾°=9¤±DÉÙLFÿO#Ü¢Kµn¶GoW&]%ÅÔç,¯ª§ -Ew¦¿J¤O¼0²4»»Æ2;kNÎ,QK-ýfÖ:*ù»y¦hÝbFzø7ÔRS;øÏ¨êíÝëXÓZ7Û+þ%+£cµ½ãtÔÜlqpVÆqEÎ2VØ-סܹ¼/· æßîl*N8¹J÷j!÷kÁEv (_=Þ QÔh³8ÄÏÝA÷£zÙ)ÐÅçÎ^ä[«½ üÄAò)?Mäf§p#½Âóèfl%ñ'Â÷meBIö>AÝGÅ«¨ïãoÇP'úWM8þZÒø² =¶ãá`ýV»$&ë.4ï<W¢z+@³óܹv\bcÄ\aS'2[Â.REú`t¤_Vq¼ø¸\ñü$¡§ðÃ×d¯+>A´iWolçc4÷Åv"öv?Uñ9 ª$ÐDÂâ¡äOð*NLÿMW*ß}¿£y"<Üû-½«Ø3n£°{ëÄÑ'h½Ñn£f»¡m0ÒßF¡öÉÇþaùlèøáß?ûÇ:(bÿCo¤R :+$EÀ¤»E:´¸ëZ.öÃ#É%Ò[fÌåÚîñô}Æþ æ¢fEÏIZ¢z\¦zgéEe6íÄkxz¶?sDõ!F{çj4P;êìÊ *骴#Ár?/ýPKxm¦[ h;JÜhHHŤI*äu|Âàô yüþظð¸ô3qá ?Ãxß´VRJBÅ}wî»çÜóÎùðûÝ{¤°9òÈÂÑaAë:,ê°År7òÛ7D9|,X a`+ùõ¦1ÃD5vÜÃFàÆüÐ]ëîÜÑïsO7[ÍmËØR1dÔ®Ï-3ÌW½°áÊÄ»$î#yñýª/Æë _)]¾ö\ª]¡|Àw}é«U{ÅS¡+'©ÜªTJfûxCÍF]Dy= ÊH5ôx°É#_¿w¦Î0\S<Rëh©*òIÈ`W¤Q9àq¬Ï|û4âæzi謹[Gݶ:íz9°#ÔF*ÈêAªNK'_Õ`à/µY,éë²t¹Vn±ja3òÄ}_[0~üK{ü·16qÖFØ6qÆÆ¬,n1¬ü'䶦w.wÜõ=á©ä tw³§àC¾è4ú!iÉJêu(©hñ OjiÊFqâ½½ tÖóÌYhÁp¦[H9-ΤÙBÚK·yM=ÎSJú?ÒÌO4å3q}Á$¾bß0N;«m>LàB2¯Ð®³iÒc$ÙERJ²KÄb&Ùíju\î¨siÕÈ´ó©] ¤ø=g·:ã®`¶Ø|ÕþÑ<ù>àt/øg_ðÕ¾²3½²õ¸Ä"¹rþ"ñPKçr¿°_ B!E! j Ã!<Âç#x_ù3aZú¢lã#¾$/G0G#ø ñóB¾*ÛäàE!Ç4¼Áb¼,ä!_r\È^ÅkB¾.ä¤×CøFoÈñQ1rJÈ!¼%¾á³ÞV¨ípÛÙ5LËIY=9=eY¦Ý5 ³ÀY>¤bº_avûAã°(:lµ(ÆaÓ;ôäv=R¨+ëe «zvÆê¥b`¨Ï=Ô{rÎpÖ,ô¦£ öÒF6cõo6óN÷)±ÙÉ{ûÚ>g Ûº6L;OS¼2{hº,±:xI!äØÃ½FÆ¢lCÆÊ8cíéÜ@"Î& ÆPÎJ´å,ÇÎe³¦Ý2åmƹ#˶ìmØàoËu ³Ú3¹8ÐeÚ;®¬)AæÒFv·agdï ýN_y»Çµj ÙBgx5hyZé/lÈ8?IWQX0³Ëò¼RXø?\fzª°4jÏÙ½¡W=Ñê°]EÇ,´ìK¥$@×r9ÈQ9U?Ó=êÉBÞH^Õ>VL³ é\Q>8K20¥4 eu̼¿ Kaýí$jÅTÒ_ÁÌÐ-CiÂ$³ ÞáÞ´º+¡ûcn|~ Ja*Û4'¢j<§ÅPc¶ºU8+Å4Kó\l«¯hÓ`Þ6{2CÜÆèÐtÖô"Ò+ÚiskFP2ozÒ1:ÚpNÇøõBhѱéØ(äa!iM ³³¦´¤Ø`~ÁN24×ñM|KG3t´ãQÙéø6¾£ðÀ¤^Çwñ=pQÃ÷u|OêxïéxÛ°]¾ÿK¸¬°òöR.W®è(a\ÇüPÈ×pUÇÄáãëÄ\¦uêø)~¦ãç¸¨ãø¥_á¢Â²>ÇÉ'ÁÁÁÆÁûÈëOt´'¶æìÃÑñ Í èN å·"¦ÕËWcR¡!·Û° =t ±ó&gÚ+4ÝÙ Eg<V¸«×tþ«%WŦOèéT¹¸øò9ÎÖ9±IZÛ»²~2l§§í©~|ÑIL̼j:³2rØ)/3Ý¡ùbOÁÊØô¯ßÒ¡ p¹Oã3G8>üp¥Ý0TõOhsõÅ/cöÂêÖêäµ3Ð]&t~ßú`}p+âðð42Ê/#<â)1¢u$.Jç1,g£°ã~IO%3>KjcXKª>vs!òõÑP sKGÞ'üü=Q¼5£#ýnó¢Ú¤KU7Ýã¿=ªWâjPì.\³¶Þ_«Ów7ãXÔÜÛÜ(H¢¤ûazãIÄp |
From: Steve F. <sm...@us...> - 2002-08-04 11:12:34
|
Update of /cvsroot/mockobjects/no-stone-unturned/doc/xdocs In directory usw-pr-cvs1:/tmp/cvs-serv17366/doc/xdocs Modified Files: htmlbook.xsl Log Message: Added extension support Index: htmlbook.xsl =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/htmlbook.xsl,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- htmlbook.xsl 2 Aug 2002 22:10:23 -0000 1.2 +++ htmlbook.xsl 4 Aug 2002 11:12:31 -0000 1.3 @@ -2,8 +2,10 @@ <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> -<xsl:import href="file:///@xslpath@/html/docbook.xsl"/> - -<xsl:param name="html.stylesheet" select="'htmlbook.css'"/> + <xsl:import href="file:///@xslpath@/html/docbook.xsl"/> + <xsl:param name="use.extensions" select="'1'"/> + <xsl:param name="html.stylesheet" select="'htmlbook.css'"/> + <xsl:param name="callouts.extension" select="'1'"/> + <xsl:param name="callout.defaultcolumn" select="'78'"/> </xsl:stylesheet> |
From: Steve F. <sm...@us...> - 2002-08-04 11:12:12
|
Update of /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/images In directory usw-pr-cvs1:/tmp/cvs-serv17269/doc/xdocs/images Modified Files: gui_example3.gif gui_example2.gif gui_example1.gif Log Message: Made GUI examples consistent Index: gui_example3.gif =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/images/gui_example3.gif,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 Binary files /tmp/cvsFkAncH and /tmp/cvsEczR5d differ Index: gui_example2.gif =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/images/gui_example2.gif,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 Binary files /tmp/cvs5mEeLI and /tmp/cvsMuBtoh differ Index: gui_example1.gif =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/images/gui_example1.gif,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 Binary files /tmp/cvsKMcVsK and /tmp/cvsmQAsGk differ |
From: Steve F. <sm...@us...> - 2002-08-04 01:41:51
|
Update of /cvsroot/mockobjects/no-stone-unturned/src/nostone/tests In directory usw-pr-cvs1:/tmp/cvs-serv30310/src/nostone/tests Modified Files: SearcherTest.java Log Message: More on GUI testing Index: SearcherTest.java =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/src/nostone/tests/SearcherTest.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- SearcherTest.java 3 Aug 2002 22:22:59 -0000 1.2 +++ SearcherTest.java 4 Aug 2002 01:41:48 -0000 1.3 @@ -14,7 +14,11 @@ } public void testNoMatchesFound() { - Searcher searcher = new Searcher(new Directory() {}); + Searcher searcher = new Searcher(new Directory() { + public String lookFor(String searchString) { + return null; + } + }); assertEquals("Should be status", "", @@ -29,9 +33,11 @@ public void testOneMatchFound() { - Searcher searcher = new Searcher(new Directory() {}); - - // addSearchResult("One Result"); + Searcher searcher = new Searcher(new Directory() { + public String lookFor(String searchString) { + return "One Result"; + } + }); ((JButton)findNamedComponent(searcher, "search button")).doClick(); @@ -40,7 +46,7 @@ ((JTextArea)findNamedComponent(searcher, "results")).getText()); assertEquals("Should be status", "", - ((JLabel)findNamedComponent(searcher, "status")).getText()); + ((JLabel)findNamedComponent(searcher, "status")).getText().trim()); } |
From: Steve F. <sm...@us...> - 2002-08-04 01:41:51
|
Update of /cvsroot/mockobjects/no-stone-unturned/doc/xdocs In directory usw-pr-cvs1:/tmp/cvs-serv30310/doc/xdocs Modified Files: testing_guis_1.xml Log Message: More on GUI testing Index: testing_guis_1.xml =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/testing_guis_1.xml,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- testing_guis_1.xml 3 Aug 2002 22:23:10 -0000 1.2 +++ testing_guis_1.xml 4 Aug 2002 01:41:47 -0000 1.3 @@ -18,7 +18,7 @@ <chapter> <title>A Search Dialogue</title> - <section> + <sect1> <title>Requirements</title> <para> Our customer has asked us to write our favourite demonstration application, a search dialogue that takes @@ -83,9 +83,9 @@ we can see that we're always moving forward. What we don't do is write the whole user interface and model seperately and then try to glue them to together at the end. </para> - </section> + </sect1> - <section> + <sect1> <title>First test: a search with no results.</title> <para> Sometimes the hardest thing in test-driven development is getting started (a bit like writing this book). @@ -194,9 +194,9 @@ application. It's not (yet) great software, but it shows some progress and helps to organise our thoughts. It's also executable, so we have very early, repeatable feedback. </para> - </section> + </sect1> - <section> + <sect1> <title>Finishing the first test</title> <para> Now we've assembled some core infrastructure, we can finish off the test with some meaningful behaviour. @@ -309,9 +309,9 @@ <screenshot><mediaobject> <imageobject><imagedata fileref="images/gui_example2.gif" format="gif" /></imageobject> </mediaobject></screenshot> - </section> + </sect1> - <section> + <sect1> <title>What have we learned</title> <para> User interface testing is messy, but not impossible. Graphical frameworks are made up of code, just like @@ -328,22 +328,24 @@ a system is in development—they might even be worked on by different people—and most likely you don't want your test suite to collapse because someone has reworked the way it looks. </para> - </section> - </chapter> + </sect1> + </chapter> <!-- A Search Dialogue --> <chapter> <title>Second test: search with one result.</title> - <para> - Now we'll extend our application a little. In most situations, the interesting cases are <emphasis>0</emphasis>, - <emphasis>1</emphasis>, and <emphasis>multiple</emphasis> results. - We've covered no results in our first test, so now we'll look at a single result. This means that we can - concentrate on how the mechanisms for searching and displaying fit together, without worrying (for the moment) - about things like which collection to use or how to manage scrollbars. Our test needs to setup the single - result to return, check that the result has been passed through to the output component, and check that the - status field is empty, something like this: - </para> + <sect1> + <title>Introducing a Directory</title> + <para> + Now we'll extend our application a little. In most situations, the interesting cases are <emphasis>0</emphasis>, + <emphasis>1</emphasis>, and <emphasis>multiple</emphasis> results. + We've covered no results in our first test, so now we'll look at a single result. This means that we can + concentrate on how the mechanisms for searching and displaying fit together, without worrying (for the moment) + about things like which collection to use or how to manage scrollbars. Our test needs to setup the single + result to return, check that the result has been passed through to the output component, and check that the + status field is empty, something like this: + </para> - <programlisting> + <programlisting> public void testOneMatchFound() { Searcher searcher = new Searcher(); @@ -359,20 +361,141 @@ ((JLabel)findNamedComponent(searcher, "status")).getText()); }</programlisting> - <para> - Unfortunately, we don't have a <function>addSearchResult()</function> method. We don't yet know where the - results for our <classname>Searcher</classname> come from. Perhaps the directory service isn't ready yet, - or the customer is locked in contract negotiations with its owner. We'll just have to invent something to be - going on with. What we really need is to understand how the <classname>Searcher</classname> will talk to the - directory when it eventually arrives, so we'll introduce an interface <classname>Directory</classname>; we - can pass a directory object through to the <classname>Searcher</classname> when we construct it. For now, - we'll just have the <classname>Directory</classname> return the result when asked, or <varname>null</varname> - if there is none. - </para> - </chapter> + <para> + Unfortunately, we don't have a <function>addSearchResult()</function> method. We don't yet know where the + results for our <classname>Searcher</classname> come from. Perhaps the directory service isn't ready yet, + or the customer is locked in contract negotiations with its owner. We'll have to invent something to be + going on with. Actually, we don't really care yet. What we really need is to understand how the + <classname>Searcher</classname> will talk to the directory when it eventually arrives, so we'll + introduce an interface <classname>Directory</classname>; we can pass a directory object through to + the <classname>Searcher</classname> in the constructor. For now, we'll just have the + <classname>Directory</classname> return a result when asked, or <varname>null</varname> if there is none. + That suggests an interface like the following. + </para> + + <programlisting> +public interface Directory { + String lookFor(String searchString); +}</programlisting> + + <para> + Now we have to create temporary instances of <classname>Directory</classname> when setting up our test cases. + </para> + + <programlisting> +public void testNoMatchesFound() { + Searcher searcher = new Searcher(<emphasis>new Directory() { + public String lookFor(String searchString) { + return null; + } + }</emphasis>); + <emphasis>[...]</emphasis> + +public void testOneMatchFound() { + Searcher searcher = new Searcher(<emphasis>new Directory() { + public String lookFor(String searchString) { + return "One Result"; + } + }</emphasis>); + ((JButton)findNamedComponent(searcher, "search button")).doClick(); + + assertEquals("Should be result", + "One Result", + ((JTextArea)findNamedComponent(searcher, "results")).getText()); + assertEquals("Should be status", + "", + ((JLabel)findNamedComponent(searcher, "status")).getText().trim()); +}</programlisting> + + <para> + The first implementation of <classname>Directory</classname> returns <varname>null</varname>, because that + test represents there being no results. The second implementation returns the string + <constant>"One Result"</constant>, which is what we expect to see loaded into the output component. Let's see + what fails first (I'll fix the missing <classname>JTextArea</classname> first just to speed things up a bit + here). + </para> + + <screen> +There was 1 failure: +1) testOneMatchFound(nostone.tests.SearcherTest)junit.framework.AssertionFailedError: + Should be result expected:<One Result> but was:<> + at nostone.tests.SearcherTest.testOneMatchFound(SearcherTest.java:44) +FAILURES!!!</screen> + &redbar; + + <para> + Of course, we haven't implemented the code to make the search and check the result. Let's do so now and + add the behaviour to the <classname>ActionListener</classname>. + </para> + + <programlisting> +public Searcher(final Directory directory) throws HeadlessException { + super("Searcher"); + + JButton searchButton = new JButton("Search"); + searchButton.setName("search button"); + + final JLabel statusBar = new JLabel(" "); + statusBar.setName("status"); + + final JTextArea results = new JTextArea(); + results.setName("results"); + + searchButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + <emphasis>String result = directory.lookFor(""); + if (null == result) { + statusBar.setText("No entries found"); + } else { + results.setText(result); + } + } + }</emphasis>); + + getContentPane().add(searchButton, BorderLayout.NORTH); + getContentPane().add(results, BorderLayout.CENTER); + getContentPane().add(statusBar, BorderLayout.SOUTH); + pack(); +}</programlisting> + + &greenbar; + + <para>Once again, let's see the application in action:</para> + <screenshot><mediaobject> + <imageobject><imagedata fileref="images/gui_example3.gif" format="gif" /></imageobject> + </mediaobject></screenshot> + + </sect1> <!-- Introducing a Directory --> + + <sect1> + <title>Expecting the search string</title> + <para> + We're missing an important part of the behaviour, there's no way for users to specify what they're looking + for. The <classname>ActionListener</classname> simply passes an empty string to the + <classname>Directory</classname>. Looking again, the requirements say nothing about a user typing in a + search string, everybody just assumed it. Clearly this is a contrived example, but these things do happen in + the Real World. The nice thing about the early feedback from incremental development is that you discover + problems when you still have time to do something about them, rather than after all the time (and money) has + been spent. We confirm our suspicions with our customer that they actually wanted to be able to enter search + strings and go back to work on the tests. + </para> + </sect1> <!-- Expecting the search string --> + + <sect1> + <title>What have we learned?</title> + </sect1> <!-- What have we learned? --> + + </chapter> <!-- Second test --> <appendix id="findNamedComponent" status="todo"> <title>Finding GUI components</title> + </appendix> + + <appendix status="todo"> + <title>To do.</title> + <simplelist type="vert"> + <member>redo GUI images on the same platform.</member> + </simplelist> </appendix> </part> |
From: Steve F. <sm...@us...> - 2002-08-04 01:41:51
|
Update of /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/images In directory usw-pr-cvs1:/tmp/cvs-serv30310/doc/xdocs/images Added Files: gui_example3.gif Log Message: More on GUI testing --- NEW FILE: gui_example3.gif --- GIF87a ZðÌ_1ÈÁzð ¡£¿ðt(L¡ WÈÂÂÍ¡ùþ°¼!/(ÃãpÔ!ÿ!(Ä!J°¦ù¡s¸D ±D¢NÅ>W¬¢Ì¤(*jÑ\:ÔÀ,jõðâØ2ÊÌ5£ÌÌXE4ªqs㠴ǽÑàc 0È9âñv¤á!Ù(È?:d!éG2Ò\d H7¤#yÉ&fR|!(ÅHIB²$d)xJT®å$ÉøJÆò¶<@-QÙFIòÇdIÊ` $T$19Êj&³¿lf0©ÉYâÐCäæ"Á CrîP4gÕYCtâÑ ð§éNgÚ³Ðá=÷ÿG; ³~ Ѩqô£ ©|0*ÒT¢$PCQ$Q |
From: Steve F. <sm...@us...> - 2002-08-04 01:41:51
|
Update of /cvsroot/mockobjects/no-stone-unturned/src/nostone/gui In directory usw-pr-cvs1:/tmp/cvs-serv30310/src/nostone/gui Modified Files: Searcher.java Directory.java Log Message: More on GUI testing Index: Searcher.java =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/src/nostone/gui/Searcher.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- Searcher.java 3 Aug 2002 22:22:59 -0000 1.2 +++ Searcher.java 4 Aug 2002 01:41:47 -0000 1.3 @@ -7,7 +7,7 @@ import java.awt.event.*; public class Searcher extends JFrame { - public Searcher(Directory directory) throws HeadlessException { + public Searcher(final Directory directory) throws HeadlessException { super("Searcher"); JButton searchButton = new JButton("Search"); @@ -16,19 +16,32 @@ final JLabel statusBar = new JLabel(" "); statusBar.setName("status"); + final JTextArea results = new JTextArea(); + results.setName("results"); + searchButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - statusBar.setText("No entries found"); + String result = directory.lookFor(""); + if (null == result) { + statusBar.setText("No entries found"); + } else { + results.setText(result); + } } }); getContentPane().add(searchButton, BorderLayout.NORTH); + getContentPane().add(results, BorderLayout.CENTER); getContentPane().add(statusBar, BorderLayout.SOUTH); pack(); } static public void main(String[] args) { - Searcher searcher = new Searcher(new Directory() {}); + Searcher searcher = new Searcher(new Directory() { + public String lookFor(String searchString) { + return "One Result"; + } + }); searcher.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { Window w = e.getWindow(); Index: Directory.java =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/src/nostone/gui/Directory.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- Directory.java 3 Aug 2002 22:22:59 -0000 1.1 +++ Directory.java 4 Aug 2002 01:41:47 -0000 1.2 @@ -1,4 +1,5 @@ package nostone.gui; public interface Directory { + String lookFor(String searchString); } |
From: Steve F. <sm...@us...> - 2002-08-03 22:23:53
|
Update of /cvsroot/mockobjects/no-stone-unturned In directory usw-pr-cvs1:/tmp/cvs-serv24800 Modified Files: .project Log Message: Index: .project =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/.project,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- .project 2 Aug 2002 21:58:26 -0000 1.1 +++ .project 3 Aug 2002 22:23:51 -0000 1.2 @@ -3,10 +3,16 @@ <name>no-stone-unturned</name> <comment></comment> <projects> - <project>junit</project> </projects> <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> </buildSpec> <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + <nature>org.eclipse.team.cvs.core.cvsnature</nature> </natures> </projectDescription> |
From: Steve F. <sm...@us...> - 2002-08-03 22:23:12
|
Update of /cvsroot/mockobjects/no-stone-unturned/doc/xdocs In directory usw-pr-cvs1:/tmp/cvs-serv24698/doc/xdocs Modified Files: testing_guis_1.xml htmlbook.css Log Message: Index: testing_guis_1.xml =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/testing_guis_1.xml,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- testing_guis_1.xml 2 Aug 2002 21:56:03 -0000 1.1 +++ testing_guis_1.xml 3 Aug 2002 22:23:10 -0000 1.2 @@ -18,78 +18,75 @@ <chapter> <title>A Search Dialogue</title> - <para> - Our customer has asked us to write our favourite demonstration application, a search dialogue that takes - a search string and shows multiple lines of results. After some discussion, the story breaks down into - the following tasks: - </para> - <procedure> - <step> - <para> - The user clicks the <guibutton>Search</guibutton> button. - There are no matches and the status bar shows <emphasis>No entries found</emphasis>. - </para> - </step> - <step> - <para> - The user clicks the <guibutton>Search</guibutton> button, show one matching line. - </para> - </step> - <step> - <para> - Run a search when the user hits <keysym>Return</keysym> in the search string field. - </para> - </step> - <step> - <para> - The user clicks the <guibutton>Search</guibutton> button, there are no matches and any - previous output is cleared. - </para> - </step> - <step> - <para> - At the start of a search, clear the status bar. Also, set the cursor to the hourglass during the search. - </para> - </step> - <step> - <para> - The user clicks the <guibutton>Search</guibutton> button, there are too many results - to show in the available space, so show scrollbars. - </para> - </step> - <step> - <para> - The user clicks the <guibutton>Search</guibutton> button, there are too many results - to show in the available space, stop when there's a pageful before the scrollbars - appear. - </para> - </step> - <step> - <para> - There are too many results, as with the last task. Add a <guibutton>More</guibutton> - button that will show all the results after the first page has been shown. - </para> - </step> - <step> - <para> - Disable the <guibutton>More</guibutton> button unless there is more than a page ofresults to show. - </para> - </step> - </procedure> - <para> - As always, the trick is to find a way to add little bits of functionality to the application so that - we can see that we're always moving forward. What we don't do is write the whole user interface and - model seperately and then try to glue them to together at the end. - </para> - </chapter> + <section> + <title>Requirements</title> + <para> + Our customer has asked us to write our favourite demonstration application, a search dialogue that takes + a search string and shows multiple lines of results; let's say entries in a phonebook. + After some discussion, the story breaks down into the following tasks: + </para> + <procedure> + <step> + <para> + The user clicks the <guibutton>Search</guibutton> button. + There are no matches and the status bar shows <emphasis>No entries found</emphasis>. + </para> + </step> + <step> + <para> + The user clicks the <guibutton>Search</guibutton> button, show one matching line. + </para> + </step> + <step> + <para> + Run a search when the user hits <keysym>Return</keysym> in the search string field. + </para> + </step> + <step> + <para> + The user clicks the <guibutton>Search</guibutton> button, there are no matches and any + previous output is cleared. + </para> + </step> + <step> + <para> + At the start of a search, clear the status bar. Also, set the cursor to the hourglass during the search. + </para> + </step> + <step> + <para> + The user clicks the <guibutton>Search</guibutton> button, there are too many results + to show in the available space, so show scrollbars. + </para> + </step> + <step> + <para> + The user clicks the <guibutton>Search</guibutton> button, there are too many results + to show in the available space, stop when there's a pageful before the scrollbars + appear. + </para> + </step> + <step> + <para> + There are too many results, as with the last task. Add a <guibutton>More</guibutton> + button that will show all the results after the first page has been shown. + </para> + </step> + <step> + <para> + Disable the <guibutton>More</guibutton> button unless there is more than a page of results to show. + </para> + </step> + </procedure> + <para> + As always, the trick is to find a way to add little bits of functionality to the application so that + we can see that we're always moving forward. What we don't do is write the whole user interface and + model seperately and then try to glue them to together at the end. + </para> + </section> - <chapter> - <title>The first test</title> - <sidebar> - <para>A search with no results.</para> - </sidebar> <section> - <title>Basic scaffolding</title> + <title>First test: a search with no results.</title> <para> Sometimes the hardest thing in test-driven development is getting started (a bit like writing this book). What is the simplest first test for a graphical user interface that we can implement without taking too @@ -156,7 +153,7 @@ <para> I'm prepared to believe this unit test, but I'd really like to <emphasis>see</emphasis> something—we - also believe in early integration testing. I'll tack on a <function>main</function> method and a call to + also believe in early integration testing. I'll tack on a <function>main()</function> method and a call to <function>pack()</function>so that we can run our magnificent first application. (I've also sneaked in a <classname>WindowListener</classname> to catch the window closing event and shut things down cleanly. It's boilerplate to help me get through this demonstration, if you like you can treat it as an exercise for @@ -190,12 +187,17 @@ <para>Which looks like this:</para> <screenshot><mediaobject> <imageobject><imagedata fileref="images/gui_example1.gif" format="gif" /></imageobject> - <caption><para>The first screen</para></caption> </mediaobject></screenshot> + + <para> + What we've done is lay down some basic scaffolding for the rest of our tests and the beginnings of our new + application. It's not (yet) great software, but it shows some progress and helps to organise our thoughts. + It's also executable, so we have very early, repeatable feedback. + </para> </section> <section> - <title>Finishing the test</title> + <title>Finishing the first test</title> <para> Now we've assembled some core infrastructure, we can finish off the test with some meaningful behaviour. What exactly does this test have to prove to fulfill our first requirement? That the status bar shows an @@ -210,7 +212,9 @@ "No entries found", ((JLabel)findNamedComponent(searcher, "status")).getText()); }</programlisting> + <para>Of course this fails:</para> + <screen> There was 1 error: 1) testNoMatchesFound(nostone.gui.SearcherTest) @@ -219,23 +223,65 @@ FAILURES!!! Tests run: 1, Failures: 0, Errors: 1</screen> + &redbar; <para> - because we don't have a status bar. I'll add a suitable <classname>javax.swing.JLabel</classname>. Now it fails - for a more interesting reason. + because we don't have a status bar. I'll add a suitable <classname>JLabel</classname> and make it pass. While + we're at it, let's make sure that the status field has the appropriate contents. + </para> + <programlisting> +public Searcher() throws HeadlessException { + super("Searcher"); + + JButton searchButton = new JButton("Search"); + searchButton.setName("search button"); + + final JLabel statusBar = new JLabel("No entries found"); + statusBar.setName("status"); + + getContentPane().add(searchButton, BorderLayout.NORTH); + getContentPane().add(statusBar, BorderLayout.SOUTH); + pack(); +}</programlisting> + &greenbar; + <para> + This now passes, so it's helped us to sort out a couple of our interface components, but there's no behaviour + yet. We can force the issue by extending the test. The status field should start empty, as nothing has happened + yet, let's test its contents before the click. + </para> + + <programlisting> +public void testNoMatchesFound() { + Searcher searcher = new Searcher(); + + assertEquals("Should be initial status", + "", + ((JLabel)findNamedComponent(searcher, "status")).getText().trim()); + + ((JButton)findNamedComponent(searcher, "search button")).doClick(); + assertEquals("Should be status", + "No entries found", + ((JLabel)findNamedComponent(searcher, "status")).getText()); +}</programlisting> + + <para> + Which produces a failure. </para> - <screen> + <screen> There was 1 failure: 1) testNoMatchesFound(nostone.gui.SearcherTest)junit.framework.AssertionFailedError: - Should be status expected:<No entries found> but was:< > + Should be status expected:<> but was: <No entries found> at nostone.gui.SearcherTest.testNoMatchesFound(SearcherTest.java:19) FAILURES!!!</screen> + &redbar; + <para> Now we have to add some behaviour so that the status bar is updated. In Swing, that's done with an <classname>ActionListener</classname>. In this case, the behaviour is simple, just set the contents of the status component. Here's the whole of the reworked constructor. </para> + <programlisting> public Searcher() throws HeadlessException { super("Searcher"); @@ -256,11 +302,12 @@ getContentPane().add(statusBar, BorderLayout.SOUTH); pack(); }</programlisting> - &greenbar; - <para>and here's the evidence that it actually works.</para> + + &greenbar; + + <para>and here's the evidence that it actually works:</para> <screenshot><mediaobject> <imageobject><imagedata fileref="images/gui_example2.gif" format="gif" /></imageobject> - <caption><para>With a status message</para></caption> </mediaobject></screenshot> </section> @@ -269,15 +316,59 @@ <para> User interface testing is messy, but not impossible. Graphical frameworks are made up of code, just like other frameworks and, if they're not completely dysfunctional, it should be possible to exercise that code - in isolation. As always, the skill is in being very clear about what will give you enough confidence to carry - on adding to and changing your code, without letting mistakes through or slowing yourself down with - brittle tests. In this case, we've decided that we don't care about layout, just that various components are - present <emphasis>somewhere</emphasis> in the application. Obviously, the look of the application must be + in isolation. As always, the skill in test-driven development is to be very clear about what will give + you enough confidence to carry on adding to and changing your code, without letting mistakes through or + slowing yourself down with brittle tests. There's no single definition for this, every team tends to develop + its own "house style". + </para> + <para> + In this case, we've decided that layout doesn't matter for our purposes, just that various + components are <emphasis>somewhere</emphasis> in the application. Obviously, the look of the application must be right (or good enough) before it can ship, but layout and behaviour often change at different rates while - a system is in development—they might even be worked on by different people—and you might not want - your implementation test suite to break because someone's reworked a data panel. + a system is in development—they might even be worked on by different people—and most likely you + don't want your test suite to collapse because someone has reworked the way it looks. </para> </section> + </chapter> + + <chapter> + <title>Second test: search with one result.</title> + <para> + Now we'll extend our application a little. In most situations, the interesting cases are <emphasis>0</emphasis>, + <emphasis>1</emphasis>, and <emphasis>multiple</emphasis> results. + We've covered no results in our first test, so now we'll look at a single result. This means that we can + concentrate on how the mechanisms for searching and displaying fit together, without worrying (for the moment) + about things like which collection to use or how to manage scrollbars. Our test needs to setup the single + result to return, check that the result has been passed through to the output component, and check that the + status field is empty, something like this: + </para> + + <programlisting> +public void testOneMatchFound() { + Searcher searcher = new Searcher(); + + <emphasis>addSearchResult("One Result");</emphasis> + + ((JButton)findNamedComponent(searcher, "search button")).doClick(); + + assertEquals("Should be result", + "One Result", + ((JTextArea)findNamedComponent(searcher, "results")).getText()); + assertEquals("Should be status", + "", + ((JLabel)findNamedComponent(searcher, "status")).getText()); +}</programlisting> + + <para> + Unfortunately, we don't have a <function>addSearchResult()</function> method. We don't yet know where the + results for our <classname>Searcher</classname> come from. Perhaps the directory service isn't ready yet, + or the customer is locked in contract negotiations with its owner. We'll just have to invent something to be + going on with. What we really need is to understand how the <classname>Searcher</classname> will talk to the + directory when it eventually arrives, so we'll introduce an interface <classname>Directory</classname>; we + can pass a directory object through to the <classname>Searcher</classname> when we construct it. For now, + we'll just have the <classname>Directory</classname> return the result when asked, or <varname>null</varname> + if there is none. + </para> </chapter> <appendix id="findNamedComponent" Index: htmlbook.css =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/htmlbook.css,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- htmlbook.css 2 Aug 2002 22:09:45 -0000 1.2 +++ htmlbook.css 3 Aug 2002 22:23:10 -0000 1.3 @@ -5,5 +5,9 @@ h3 { font-family: Arial, Helvetica, sans-serif; font-style: italic; font-weight: bold} p { font-family: Arial, Helvetica, sans-serif} li { font-family: Arial, Helvetica, sans-serif } -pre { margin-left: 5%; } - +.programlisting { margin-left: 5%; } +.screen { margin-left: 5%; } +.sidebar { border: double black 1px; font-size: 80%; padding: 4px; text-align: center; + margin-left: 80%; } +.screenshot { text-align: center; } +.caption { font-size: 80%; font-style: italic; } |
From: Steve F. <sm...@us...> - 2002-08-03 22:23:01
|
Update of /cvsroot/mockobjects/no-stone-unturned/src/nostone/tests In directory usw-pr-cvs1:/tmp/cvs-serv24636/src/nostone/tests Modified Files: SearcherTest.java Log Message: Index: SearcherTest.java =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/src/nostone/tests/SearcherTest.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- SearcherTest.java 2 Aug 2002 21:57:09 -0000 1.1 +++ SearcherTest.java 3 Aug 2002 22:22:59 -0000 1.2 @@ -3,6 +3,7 @@ import junit.framework.TestCase; import nostone.tests.TestHelper; import nostone.gui.Searcher; +import nostone.gui.Directory; import javax.swing.*; import java.awt.*; @@ -13,7 +14,11 @@ } public void testNoMatchesFound() { - Searcher searcher = new Searcher(); + Searcher searcher = new Searcher(new Directory() {}); + + assertEquals("Should be status", + "", + ((JLabel)findNamedComponent(searcher, "status")).getText().trim()); ((JButton)findNamedComponent(searcher, "search button")).doClick(); @@ -21,6 +26,23 @@ "No entries found", ((JLabel)findNamedComponent(searcher, "status")).getText()); } + + + public void testOneMatchFound() { + Searcher searcher = new Searcher(new Directory() {}); + + // addSearchResult("One Result"); + + ((JButton)findNamedComponent(searcher, "search button")).doClick(); + + assertEquals("Should be result", + "One Result", + ((JTextArea)findNamedComponent(searcher, "results")).getText()); + assertEquals("Should be status", + "", + ((JLabel)findNamedComponent(searcher, "status")).getText()); + } + private Component findNamedComponent(final Container container, final String name) { return new TestHelper().depthFirst(container, new TestHelper.ComponentVisitor() { |
From: Steve F. <sm...@us...> - 2002-08-03 22:23:01
|
Update of /cvsroot/mockobjects/no-stone-unturned/src/nostone/gui In directory usw-pr-cvs1:/tmp/cvs-serv24636/src/nostone/gui Modified Files: Searcher.java Added Files: Directory.java Log Message: --- NEW FILE: Directory.java --- package nostone.gui; public interface Directory { } Index: Searcher.java =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/src/nostone/gui/Searcher.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- Searcher.java 2 Aug 2002 21:57:09 -0000 1.1 +++ Searcher.java 3 Aug 2002 22:22:59 -0000 1.2 @@ -7,7 +7,7 @@ import java.awt.event.*; public class Searcher extends JFrame { - public Searcher() throws HeadlessException { + public Searcher(Directory directory) throws HeadlessException { super("Searcher"); JButton searchButton = new JButton("Search"); @@ -28,7 +28,7 @@ } static public void main(String[] args) { - Searcher searcher = new Searcher(); + Searcher searcher = new Searcher(new Directory() {}); searcher.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { Window w = e.getWindow(); |
From: Steve F. <sm...@us...> - 2002-08-03 22:22:45
|
Update of /cvsroot/mockobjects/no-stone-unturned In directory usw-pr-cvs1:/tmp/cvs-serv24584 Modified Files: readme.txt Log Message: Index: readme.txt =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/readme.txt,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- readme.txt 2 Aug 2002 21:58:26 -0000 1.1 +++ readme.txt 3 Aug 2002 22:22:41 -0000 1.2 @@ -1,6 +1,8 @@ This is a build environment for a book on test-driven development that is due for publication as soon as we can finish the thing. -Requires ANT 1.5 +Ant needs the jars in the lib directory for the doc-book conversions. + +Requires Java 1.4, ANT 1.5, JUnit 3.7 Copyright 2002. Steve Freeman. |
From: Steve F. <sm...@us...> - 2002-08-02 22:59:16
|
Update of /cvsroot/mockobjects/no-stone-unturned/lib In directory usw-pr-cvs1:/tmp/cvs-serv12576/lib Added Files: saxon-jdom.jar saxon.jar saxon-fop.jar Log Message: --- NEW FILE: saxon-jdom.jar --- PK ½C&jëNC®>È $»P5ÇØÅÀ¯ºÇ¯TÝjpUÀ4ó_±7˼¾è[Ò ²»od ļ2©æ«®,4·Ö¥ß#;ÒA¡Ïë¹1 3RÙ23û6hÈ,¹EÛ!r4sîíº-·snY¾8;ÈGwשH?Ëì1qÕÜWsûA"¨Æª[wü,ßtj°-p:´UéE¯éäRUúðùN½.ýyuÁ@ KBÊ«£[âGËÈø· ÃqyÜÑP0pS&0)pd°úæÆô5Ü3p±" NªU±fàx§éoó¢zl)$µ¯~Bj×:¿`¨ \Ø9¶»ëF6¿?(wËDÍÝ»AԷųí:ÏEs/{¥>©°ÝbbO%³&E°(7fmúÇyÆ.¯û©3?à¸BwËüâÍÜn twÄÚ³ß%¨~z"ðºÊ^tÚU&l|ÑzéÃöó= ùSè)̧dé5§pö'¾ÒÛÖ¾°Þ#òø¢-Ĭ¬±áâÖleµ°þú[^ø6í$aÇd£,â/ÍÓ,1Ï,Abé^Á4ÿ°#ôq¿GïD§1êå§èýõ7ô7ýôx'hÓÂé^ê$½Á¼K´Ó`·À¬*ö#ìÕiã6$GÛ;Î6X-6×Fò"o8.±Ë[d`õ Õø1Qļ-ÛAÙfwKà¯ø|ÐD ÑÄøì2~S4Vã$sγçòof?}~÷¸Ãf²È¢dDÙJ¾Ù[9d0g¡jaÞkêC¾ö:½¶j©Î®ØHE±ÆÅ /8hø^§¹Gnì·yÜÚêYèv»*\HÇ{~TYȶu¼§bߣó¯ýø¾À£ê ¾oÏ?H®Ò#0²ákµÙ;ØQáw§Cå¶]íÑUñ£VƪÝwp´m)²tYâ¡©5Ý;P¡û°×µVájÇ" 4«ó U. ¹VÐ=õØ7F]Üw]chØÅa#l\²±d¬+¸jcMÂØ µ6¶má$ó¦ë jÇP4V#sWPá¡¥bÉÉK%Ò|Û¯z«£Ou\A»´êhC»g:&1Eð¢³q#aKILkHéÁs\ÖÑfu¤Ñãætd0¯VíÃ5ÒÒ±ÖJ²ºì?U¦×úÿ²`Hýï{½wþE³´=D7íÄÂÚÈIEÃ'¥Ñ<#4ÏSg,W«-õV ùmUgþÈE+±nÓt³bWª¤<ÕòÛ½:pÁ|wZÀËèELÞ¥kñ¢tÕê/=Mô 8päÀâã4T"¬Õg<3ß|cï×>ÃÆvâpq3(nÅh7¢`|E#J.¶\]T%F!C¶îù½ôºÍG¾ªtZdîù-ñ"àý¾î2D¶Թ;±Æ¡ Û"9ïI%Ãûùy Ï m©ºTboÐkàov§Íõc?Õ®è j;_xÉ0íMëùÂÊ£¦^ùÔ¢Ë[C®<1Î6pß?¤â¹U5èÒWÉR"ØíraíÌÔî>7UÀR"¬sîûZT%ÐCTê¢E!R?ChñËz_ÀÍÕ¹S××öx®ñ?<ñHY.ÿv^îð!Ob )#.$D"¸kÆÌ`ÕÅ6Cùÿè)\éruPyÒìϼ¡«y0ú¬ì<68YzÀQ]Ã@ÚÐ"ß"ÌÓ &{¬dYÆ[<U,}ýfô+$#¤a}£}«øMÒäÅbñ/p7pì·S)ßiç')%Ò"aRêÅ#,Þ&,Ñi¾z¶-Á¤/â ¯à*Ö' .O°-g ÐÌöø÷¸%Ú_;Ë"¯Ïæb§IfgKÏÄÉlS!m³bélv¤'Wa!7T×\Ew×IÓú PKÖ8XE &;%ö²¦Ðl£$W¥ö9¤¢·©¸w©¸U®jQ§Bâv¹ÕÑÏPýÏU¤V!paµeÌöX)ªÅtT`P¡bGTÔàªeÕ¤ £b¦ ÛTde9[°¡bi:3¾_PMnodts ÏdÄI:º#ZÇR";Ë^u·)Ʋºé¨p£Ý·§£-êØBÈ£Ua#'³Ò1uä+ÂrlÑe7ZiÑÿÛ})eÀÿÐ5[dÏ3?XºgÎ%n¶¨QJ +·]ãÙÙMRgnsW$Éîè)G6á[,ÓqWPðåÃJ²åêçÌ)f¨ºÉiɯûë7²&1F±ÖÎ;/¯JÔsí.ÀgÐÍÓW"\»tlÃp¹)ÖÌÓÅÐ]{s´bw/6Uª§Ó£5BìÏ.,£Å.¾®Õô <r,iåóèj WÓ̺&ÖÕ«+ä@S5@þ|´¢f$£Þzþ2JH{´z6 ¦ÕàÑx\k(À«E ðiao% JGÖ0ÿ´Ó&¡L! ¼ÜL¢têVCCåylX|Âêù±1ì=ò¨$@ù9T0ôh½àÞC²×¶áøóxFkÄZ2½hàÛ}y½÷±°¶üÔ_#äQ÷·ÀóÀ´L5 ðYÈQÛLr¿R~!~ aþ:ªøò7QÃOSö·°AùYØ|£ÄÙ³|Ïñ÷ð"?i}Óü"ÎðLòK¸@ú2ÿWøG¸Ê?ÆÏ¤¯óOð;ÿ1þe§ïÛì½àütÀ+TkÉ:È@óÂiõ°n«Î£²·bý46\L{ê%Ýîáú\¦PUÀ-ytkÌÕm³6. ùWÁÒKùÝ`¤íDö9þÖð/á_Y_£_A.~ø·âßá(ÿÈúü'à¿P{°mîàÒL¶©<øÛáK¤_#yï´jêñ®ÄýFr;îÃmµbýyT÷Ê3Ñã¥ÇM1Mï®ð¾NÌïtç§ ÷¹y8M^ õÁ¦ãL+4®í»Á¦+ç× ®(dÆk¥©e__øPY¥Ð²ä¸zegë¶ö>°oXcØù]ÛÍñ*:. ¿Vô\r½ã¯jíq\q{C,ؾ>6 3ëºÚ[,ؾ¯¹±ñ5T àQÅÖ;^Nßt¤¦Öc¾Swí]ÛÄ }ÿ^e°1 Ùeß8âÁþ/ÕKÍ é1 'µV«¼kbï)Lý·¹x_ÿFÎÏ 7j=fǦí/=)è-¾¸«÷ÊV!yLYw£È< ñVhâ0áÄÄAOÉlmû'RÇïè ëòëÙ<ú²DÕæNõtºsLó_¤Wá_(}¡d²·"¡lÆòüû!_¯C¼»Ãº:i+¥CY©"*!*@V´:ë\ õV²ÃJP Ö#4>\è0ãY4C"h¥(d âè'~Ô1E-ìÍo¢T}6Õk==ŨS8@§UÞÄ~YBÓr!}¯DT?)¯Ë~K©Gh>À"ë0`ýxIEEó[k:Äw/tÌÈ=âÏgb¸ãâRk·-iÃaK}¨üWuG>Kbkéã<maQURµóÙCû%¬6!YÐü"¦qr»| vÔêÄ0%x²] nLSæ©YJbúpúQ A4Ïi_Ò¾&ßR ?Ð$~¤)<¡4~§<£YüAð']Ä_t Ïi^tYuÑUÕCý,Æ*4I²TB©ùû£ÒêEIÆñ#×îk$ZíeÀ¹ßtY3ÿÜô/³¨ÜÊýªÓËLÉÕSH±ñ{0`~&®2ÏÛX.°ÇMüý PKúé_î "o©¯<gõr^4±"ÅNëyFú¿¬Ò:4æÂ>îI=O¥><ãλ6úñ¦^ôÙØ6Öã5¯c£¹x;mlÂfÇm|mbÈFÙ(ʪ$0!sÀÖ(6`5ÑuÏ9ëÈÊu×?WþdrF×døVîè=£5ür6зz«ÙÎצåÉéKÏÙÓµ`ö¼]+Zü?±¾Õ5Ø¡n¾4X*´AI .F iT)ȪhÁ¤ÙW\Ïp<É]N RÚ5Öl+½T$qÊ.YÇX^ÎfXáz¶µVÊgj<HȬ®<á¶E>1×/ÖBÕ%VnAXŪñM79ÀÍU,oQxfæez#£©zÕ;ïaࣤ`84iZbj¥</ic¾DÅ(®ÊzÂ)iØhº9ÛñDÑWä)Ó½,C{¹B Wì*ú1aYÂ-®+\ÁTw5Ô5g¯81nÊâ»lûUCC.i8cÚp\à IÚ%9c²N¼Ì®ÛI»å %k°nØKk&ñÇ\¹û"ï¿=½@Br[éWH.±ÏO¼ÝçåÓH|{&è~¦w>LüÞöÁôMt¶°$\½wý>¹Þð6é°wÑo|´ä°ôMòCÙ%§ @ ðüÆm eõªPG¿BSÐuõû³9ô&@oþ»Gy¡-Aáo¡ pä6º¹îb{ä+á«°ø\þ<þ.õë&nñ÷ð _òð5ÿwùGø ߯oücüÎ?¥O +6â²!þíNìÔðϦöÛ kí>'ÚÞÀ.îÛÅï#ñ°ÔÈ6Üñú&·Ïß~ôø3¡ICç!ºÝ8¢¯üÇñY´§ OäWÓç/PKËøÅ ~|ëC½èÄ) øHwZ,Îñ¡#^´à¬¨^|äC v@øV¦dÑCÓhÝ!o¡[ÆÛÊèAHF tSÎHWͨYU·d¨XÆ Ë2V .!'#k2XÀ*C zABɪf^I©2®ã53ÿ»¡2nà&ùo-K|¯dÜÂm wdÁQbgQôt8iq_˸oÄódìñ:¬ÚæZjá¥ÿ ÷À0úS¯ûX%ùt;ùñ¦_VSåV*sVÊ£½Þ'pvõ©ÚíEøS9ÝR4ÝW)J-Á½ÏæùåÉ»5ðµ$&#ð©r¤"¼àe'j Á÷íÔ7LíF¥Ü¨Mx´íÞQ1½fO ìÕ ªkÖnWT9JK°¶ßªáÐ"ÝWL_Ì XÐrª¯L24\_ML&'G¢£¢ïÕ{E-&Uz£i¤¢Í º9-äÑZªe?«¬¼È(µ"W'Mcõ½ÒY/1H¿. ÃÕæ*Ã_üêRiÚq·¹7±áGDŬ!"=B´&-ê^CÈ?<Ö_FóZ4¶:zn `ààïxMÀBbUFÛ&ÚJèxÑ1I΢àsðóËhåWÐÁtòytñ4zù¸¾IÁ4ÏBá:yYG_Ãnà{ZÿÌWñ¿Ç¼§üþâ7é cª8z¥\ ÄIÍù!"¹méëqA±·Cdõàëè#! fÖáuÎË8\Âà 1_Ð7p2¿6~Gø]Dù=ñû8ÛÚid"îÎ_«gÝBÃ|'·qA;Æ'èD ¼ùÛ®SßQ½oçQïÙ÷sʸ¼ëtPîµà eÖôýPKQ%´ tjx20NРLú4*%¸§Øði ý!DqBólÐpZ ÈõLÇhHe'Û¬T¦Í5g³vÛ 4Ù´:ëSSÊIè¦R®uúìéIÛ<Hèµ\>TéYY|®5±ìó¾K8ܲӾ±ìTf:ºó°®(ö&,7Ö.P³½ åY)RvZ¶åèm*h¡ó±æ3²4å§'Ç3bgH£é®S ØÄ%Ì:Jçå)åD*;5G'MWm*úÔoÛÊéÉ®«¨¦¦æ)ŶAPßBÉì´R§,Î)²É¶õ9cê8!û±GÇØ«£I=X· ·@ÐîM·¹{Õ.ZÓ1çÚ öLXôÄÈvÃ%5èxgt<& gu¼ !ÙZ `r£ÉGîÈ;»ziÖ(F×¼}9^çõyNH¼Wîô î_Øæù;]l{n¼çƪôµôeqHh+ð"ô!Rãd%þ-@ ñÓïOPK¡ùJ ö±}¬fU³¿ªÙßÔÝ'ø_×ñ©Kñ-8¢<háÆ¢éçA¸tÉ÷ ]tè¢{°DâB]<¬"]Öá3·á1¤H ¹I©êÆzð)ãIåµõ8·wË*V&ê2ÉKiâ-ce2u+Ç©ÙËT ð©Ù45®f3T7SuÇ«n[NàRA¥Èl©Ô¥Jj]j¡i ú£Q3*×1»Í@¨·%4ÐgFü±@8DðÒp0Þ ßlF»ÍP?Ë6m{2wh÷÷Ñ~· nÅ"±Lð1¡n3GÒ º((Yâf]ÆÌHÌ ÷²¶-þmþÚ ?Ô[»rã³;Ö p+ÜêýÄK§ ß1C1¯;ÜWèÖFýáPí~¶v]ÄßßoF¸ÔÓîv¾3sÑ7»)F(ZõäÕJ^¡@l ®b¤d£±o½k²VÒí}ÍÈjÿÆ !E}þfR¶5ÿ¯ýGWÞkÆÚ- ÆUÌÎ¥Ü"ÀÖo^ÅljØvòîíuåY\¡MáÙëí:wDcf_kO6NJ¨W±¦¯I£åáVÊ\Ö¬¢îÇð#¥5K6B £`e¤G?_:Ò+é,kýÁg¬9ØïõdÀªyb`m[ JÝgË·d`Ó&jTIi©ú±oV1XJ3ÒO:¥¡äwûFPÈOºè¦ yâi¹N qN=f³?j)u¦¨eë- ©Ê¬\Ýáþ#lb Ö?«]i 1ç=-Ýf¿:yTZJ¥gXÅ8{]2:gºýzkÿÎð@¤Ûd¬ãV¥i^y¢RoÊßÀ®ÂÕþÿÂGz3ÃÂ5\D´Í>ËJÊ?ß÷É ó¾ã/òѼrÅ4u ü;®3°×rÌÕådCNS Ü{È?µ}û@0ئ2·¤¶®vòÅ"¦ésB¯Æg üA#ÔÉi"·Ï¸ ·272_uõªkÀ éM»p.Y(tYlÈéØiH£,I'o ű«ÌM©#ôÓ£=§ |MÈYfÏ´&dË&Ò,-öP4Ü©XjÈ2Yn`7n1¤UI|êÎT]êV(ªvCVJ`ÎçÓÌ{î(KrÔÊèÏRÝ*ÁÉ£-ÏQe¨¥âÔ²>»QkWNeÙQʣѤÍ]l¶*W¥ËCÖâzÁñ#"b'ÍX8u®u£³:J¸&´5Þòù|!+Ñú±mH¬7°OÎ1ä\9Íód!_¡¡á ²|W̲Åóq#xîüÓÚHAîÅ.~C6âàACº1¬K!¦l2ð01¤WÍnUö¹Yl¡ûËVÕ¥O0±1ð%5giÊC¥ßdSFp³+÷¨)ä(Ú;Ipâ($#ªÜ %Â`í`_°6ñ¢ÂÆÕÄ,#D11aøÑ¬êÈ)ÔT®>zùÊoc¢~*Ë{U ÕfôS±»,Q«¥êVÛ±p"¸IìäBUGÚIAÍý1?ÓCæZÒbêøa1!cëVÎíËFBUõom] Îb"¯ÎU$£H, ÚÜ!FG8LÎQC9ÈÖ\éöÓ»ý*IÎÿBÕOa[Ò;YÜöGØóüÔ²ÞD]X´.¯³hM³ÇÞeÚ[úúc;2N¦*ûú|ArUÙ¨æìfÄCb4¼UñD¿ì6ÙNM?²ª%צ/-¼Ú¥åË«ÀÒAùçKL«èóǺ7«:òó.Ükr®ú9iôFºÍ0Üätõ WÖç2ê9÷1éohê1d»Nî§KÊít>9ýÑÉè³íoĬ§ ¹¨ 5¢cì£CÜGG¸°Æ}?ÎÀ0Vð!ÒAtq¾?¡©<><~ηáqìÀ¸O2f{ñêijúïO¨õgq7~ÊÕÏãx?ÃKø%ûWI#ê âÜJm@Å¡ß(Þë÷²uPf¯²X1ñå´ö[9þ2õGGyÛ!LíoEUõAL£»L²z3Úd½«Æë"ÚëJáâ9t¤"h8F±bRÇñCe³E%qàLKã¨p¦³ã¨T4É;Y±ì_gðø=:ñÎÁ8 ¾M½¾Cþ_ûÔéõ? ý~H~ñ15ü ÃΧxEïÜÛ¸²ÂÊP%X±]Õ ZÐ^cô±5ö«xÎÝXXcÇ*B8jÖ1ÈÖXç*S u*:Ðw)¬í*3á®s×¹5åÃuê$ºÀ#:Ƥ³Ä)Â|1pºÁJ)ÆZ)Áù¤HWïNz°Ò«ûnT6pm lyÌTÞíºí¸p2=÷¶SÙêâ8moZ §dâÛkâW&ñiWá hæP"K=-)q¬ZW@q&b6 >ÍÚ±8Q&mÚT¬"ìmWìg!4Òײ|]S/ª8³³Mz¾Cº -4Õ¥EÁrÇsíM!à+ºk7\y{óöfé¯ÎÃtõÚb&¡é$±d2Ó±&ÛÜϧIùÙ©bÖ6¡¹m´Á| t;$[+ojËáÑZQ¥ U?HVªT»Ö¾2)JeB)@*na{íUh,dÀÇÊð¿WB%2ãØÄ¢¥×+`-¾YçuÚ§²ô¢ª)q7U<ÉÖÊüÔªzêÔëJ[§>¬ ï¦ï®jòRUf§èòtjëà¾*Å/õÁI81é·&uöÇû¬WgDyjªÚFSv6kë±F;gkç¢c¶!ͨ¶Ú&\¢mÁ5ÚV|Sâ·k`¿Á°ÅãÕñ¢¶/iá5íb¼®]·µËðv9>оµ+qD»J ]#í[8d%?Á÷ÙJ\UêÑ<IRPëÑ¥]GOرøaõöâ«h*w叿 W¬,uDÔQ{£vë¢úü/Ëî ª#×X]AÕx.HÞÈó)!f)OÐn§¼íLÖö \»sX®ݥüîÐîKP##åKñq>Ø=ä»QýÖq¼qlçx1ý§ã%ü^Åñkünåx)Ç¥/C)ßn|Ý¥ñÅãÆåÐþPKýàåV --- NEW FILE: saxon.jar --- PK 1 £ 'Cx\Ö'D?#;3FÌÂܲ"Â0:1+fvgÃ<zRD& Át&7kf ¶;k.389{ÖJ¹4è³Å²ÓÓj®zRCÛé M[REDZ²nR¬FsÁÒÐì¹?eÊ_×r§{,[°S¹ËÎx ¸¹¼-¡¡ÎÌdr)Óµæ4Ô{~y3E¯aѯýÙrµÝ#¼Ù·wssÔ6ÙYk¼¸0k9ælF4kî¯e¬÷%äFû5Oããëîì»T¹ÚZ,TßÓÐÕ¨ºwÔÎÎÙÙô¡½,b[e´IÓ±=twUÇZ»S¥¶òÎÀ¤)Z Q°Ü%+Uti+¡7ñ2-Æá¥wí\ÉÕÛ Eúñê»c³¹qrcRvÞmÌåleR\ÁªÔ´°2ʼ¢0-iËÖõ°§HVzåR×ÊÕ Ñ²Ðp`Sä·r»i¹o&̸*ÁÄâ[BS(Øél[8+:)kÔ?øµå}2/p§àQôØ~KõPØ ^»q»>ì5ÅH9y<¨a×@=eºgJm&·Ë.®Ãçç¥îaÛI3¦Q¶Å<,úyD<Ç@DQ1Å ~m` Ëö ¤Ù|:4ô#'2+mfîsÒžðúÍì×`EÔTEÔs±k!ï2èoð´íµÇÀÏ1d`C¶o.À¥Ú§jzxÌä\ïÙàËbæÉsv:Ö7V]GÒkãÒ%M^ãjÚúÖÓ0äæ¼=1mbòÿ8\.¸Ö¼c.§ry&í[ÿ'6P©.d¼gGqwûù¨C»áZIRµîñõ¤ZÉ[µÆü5î¯ûÔÚM8N¹ÿ¢^ãÚ½-ÚÜv 5«D)ôh`µ"¶þV)oCÒf4`+ZÑlC7ÚÑ ÕÜåûã5ÀõÎh8êºÐ*ê¢]ï髯 -z uÝZK¸;0ñbÖÝuáoÊÑzUþ=¨eÜìd¬¿»({y¹ÜNËâ ±ÕpÝí_E}ÙOXicô§ænüÌ·'>ëDPÿjo˦ë2ñøÚߺػhÐOêoüµÓÈç:±øù¿Hó÷}ïõ³oýÊG,Y é~,AÍ!:¨Q× H zWtÇA©OÏóØ}SWÑ4uÍ-ÑJ¸¹¶+ØvCê+«]`¢ºq£,å#lÔã8`àÁ¸|/ù;{ý$b~AÛÊIÞDP_(c¢MùRó÷ù7»x5øBB "5ªâ8lp-R{_©_²¼rú§èÔ%èúÌ´0òj/@¨RË_àú_}í²öh±(ÞA{4&4°úâ\ó'N:â´V!ÁWÐ];ôÌ:ýIÔ®uÂIÙ^¿ð÷eðC<ÃÞÿ ý§ïYm|-}%~%ý=rx =§ñ2OÎáø=-Mà0ÓÒíö<Ì_ÔV`Tb«®ÜÉ WHøW©.zgBÍý*Á÷±Ý'r\H=¤ àñYéÔúúfzÜ~î_ç¿Áé~oÍ[<=F¢xa²µ¢½æDa´1 s± êßéëôuÚÑÒ|óçCÚØñ®¢sªuÇt ;ú}#Óªã:)|/Ù|>äÉqVÜó8MB¹A^îÖp¬}=ÅñMÅå¥×.Veÿ 'ûSNõgñ9»õ ðã<á¿n'Ð=8¿øfvpj1пè+úûà¿´x EõzõÈ}K9Vªèa¿¢k¸hì2n[á£+Õ¥ü£Çý÷Ø®ÉÉ õ©ÿPKéHÊúª @H¨,X°s¹rìÈvP¹À¡?Q$À?çkæûëûãCã(Á2Á!a¢Ãq¹4ájýBX*>K¯enÔFVp¼Z?låFÚRdÑk[^NÿÞòò5;±Ë¹'ÌÙΦÊ'ÌXßÈ(ÞkÎÎ(-'õw®º0"ȳBíj/:»R®BÐ¥mËÓÌ5¾àÖV¤×Ú¾rÿE»#áäLo¿_xÌ·ªcaö$#Þ#¹qÇû=§=gH;ÎÛyN8à{ÅPK²Ròö _£1/5"ÞwÌÓI¦,Û¡½þé¤uR®7ZöXe«'ޥܬÔLݬ޳ÆSÓ»Íl6eOh¸=8j7ãiÓïwrdn¿#êKh|rK e5¥þ´å:úðMÙ¨ÁICæhÁ±ònZ'Ü´ºuºç-tJs0®²«·|] %'ÍdáY*=r¨w`@ØËRv&'Ýs`2å¸MÇÔes6_ÊvÞÉRcê±=\WãéB~R:âX*µÆúm'åÐPïvEPúAÝ{ ÷R;½}=C=Tå÷hØÇ}V}Ù\°³f._²â2ºÕºÕNÏþL!´îKÉ-ëÍØÃô&ehØ ^ïÇlÇ÷b§âCzäé.Üm`î4pºu1°="L«fqr¦Ïä¦âC¥'+W"NÈü®ÚßóhyKì¿fà°8@¯× ¼7u5ð¾i`Øoé1ðm|ÇÀw s Õ*vAäLôÙ<"ý¹|°8ðæ_H°·+XãWXê[XÑ¿2¿couÞT·ÅBù¿SþäÞØ&o,ö/Ò±²õ°Ú!öoRëÆbÿ!/ÇV»VLÓI'0éèU%2ØÕ-£ÞðstÉr·kè^BdD~áà:ÙÑn=ÌÛ ÖA [ÝE±0Á¡K'¨'è6NäY¶b3ak'¡ª{µåði-i+Ñ¢BDc«¶wjmèÑÚ±[[[Õ½)¿£ÿPKÏ'n¹^ .² &S»£WbP«5§Ç»C©È Añ. v*4ùÏ^ô¦S¨×dQ´ÙOEB= ¬Ì¥¶H²-OµÛbkIÑN¼Êa»¿:¶#¤Ð!ì ïÄXÔJcÉñÄw8»2 m¤»mG:¢-µÅcÑÝm7×I> Béºì,ÙüM$£æ$È7Ñ75,éþyÁäÆxÂðE 9x23³¥0ÓÖ"§GAVÄz,-È(é ØFL-Íç©õorà¼Î¥s¤oìÁdÆBæâ0~(í|ôÊS¥W:OM0iÕ°¶fQ pÆÍrð½s3NàOÁÕ(ÃÉüz4®ÁZþ¶z+6aéSèõ¤»è ¤{ è^Ò¾ú4Ò§Ðgî+ ßFúí´ôƺô@=Èv&s°0£7Y]ÎÄly&f31ûÙÊLÌ^gb¿G-{eÍÕÄì¯Ä.i±Äô ýpÔåü®OuÏ@¹Ë¦Q& ܦQ!«JYU ÐîDõaÔíGÍÈ\w¡ÚMÆ4jÝîièw?gcË¡ö¢nÔÀz¬@ ÏÁIXUhgx;ÖååÉå:P[EèPq×;äönïæ9Áyû!ÇÈ/cÔÆqµíÊÍmwîGÝûnÔÎ Þïá¢a §Ñ(¸iMÅ3ÁåtN°N77O£YpË4Z·N£Upý\É#xä©Ó§ÐM0É2ªZäùLñb&yS¼I^Ë÷2É~¦vi=5Ó¡ D.víVìªÌÈäâ2¹ ² I¤,ùÄüJ9pÞ*¹óÒm³D«Et/fÙ¥/#ä`u>Ê.}án\ääv³ÝíëèöÇÉy.vp»ÙnúÂKðn'ÓMvÓ7Óô-ä¼:n²þáex¯%ºÂmѽµÈÕÌRyÍzÕåÂ=hƽä^÷87ÅdwîA:÷9|i88W6isîQÂ÷çL{,ÓµbºÜvG2>=EûOs¯gÈý [...2312 lines suppressed...] d f0 Ì ¨¢ Ç --- NEW FILE: saxon-fop.jar --- PK oò'Û¬QÊD}ÈEAÀt'§±I¾ öÙ`EÀÕ7¥ =«åʦZÏfUËBiÝ:%{öØ([Ų¥¬ºEó@Õ3yfnFå<Ǭ³.ûüvóbÉÃ9àòkáþOÃϸ£ EfZ#ö½äÕ¾²¥åÖ ù»ØIOýN~{ÊôïõGêïônÝ%f%NIuø6ù#î&½\O¾Þ F¢Í·éë¹´Î6jëú5*M,ù:;û/$Okj8ûh¨=|ÇÎY3=ÐVêqÉb :)-.ow`ã²;ت?#;·Ý]òÈ4¾äÎ> ¸»<µü1áÏwÚïßÍ¿GÓ~7è7ââ#V.>(èÛÅ}{ ðG2@»Kô¸6PðæIöÚÊaô?ª7L»º¿;g7K. àvQ^ú> +UC÷p~£h Þ ï!Vá-þ>~@'®póåbÒüop@NÑþB×WC$\È1æøgè'\Ü?Ápê#©1G £5xC=/Ðê9Áxj¬§_óULRy^RPÁ35Ò_à ¢gú[ð>ºW`ö«QÒ¾kßìõ |
From: Steve F. <sm...@us...> - 2002-08-02 22:57:59
|
Update of /cvsroot/mockobjects/no-stone-unturned/lib In directory usw-pr-cvs1:/tmp/cvs-serv12270/lib Log Message: Directory /cvsroot/mockobjects/no-stone-unturned/lib added to the repository |
From: Steve F. <sm...@us...> - 2002-08-02 22:10:26
|
Update of /cvsroot/mockobjects/no-stone-unturned/doc/xdocs In directory usw-pr-cvs1:/tmp/cvs-serv32008/doc/xdocs Modified Files: htmlbook.xsl Log Message: *** keyword substitution change *** Index: htmlbook.xsl =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/htmlbook.xsl,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- htmlbook.xsl 2 Aug 2002 21:56:03 -0000 1.1 +++ htmlbook.xsl 2 Aug 2002 22:10:23 -0000 1.2 @@ -1,9 +1,9 @@ -<?xml version="1.0" encoding="utf-8"?> -<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" - version="1.0"> - -<xsl:import href="file:///@xslpath@/html/docbook.xsl"/> - -<xsl:param name="html.stylesheet" select="'htmlbook.css'"/> - -</xsl:stylesheet> +<?xml version="1.0" encoding="utf-8"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + version="1.0"> + +<xsl:import href="file:///@xslpath@/html/docbook.xsl"/> + +<xsl:param name="html.stylesheet" select="'htmlbook.css'"/> + +</xsl:stylesheet> |
From: Steve F. <sm...@us...> - 2002-08-02 22:09:47
|
Update of /cvsroot/mockobjects/no-stone-unturned/doc/xdocs In directory usw-pr-cvs1:/tmp/cvs-serv31759/doc/xdocs Modified Files: htmlbook.css Log Message: *** keyword substitution change *** Index: htmlbook.css =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/htmlbook.css,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 |
From: Steve F. <sm...@us...> - 2002-08-02 21:58:30
|
Update of /cvsroot/mockobjects/no-stone-unturned In directory usw-pr-cvs1:/tmp/cvs-serv27987 Added Files: readme.txt build.xml .project Log Message: --- NEW FILE: readme.txt --- This is a build environment for a book on test-driven development that is due for publication as soon as we can finish the thing. Requires ANT 1.5 Copyright 2002. Steve Freeman. --- NEW FILE: build.xml --- <?xml version="1.0"?> <project name="no-stone-unturned" default="html-book" basedir="."> <property file="${user.home}/build.properties"/> <property file="build.properties"/> <target name="project-properties"> <property name="project.fullname" value="No Stone Unturned"/> <property name="project.version" value="0.001"/> <property name="project.name" value="no-stone-unturned"/> <property name="year" value="2002"/> </target> <target name="source-locations"> <property name="doc.dir" value="doc"/> <property name="xdoc.dir" value="${doc.dir}/xdocs"/> <property name="doc.lib.dir" value="${doc.dir}/lib"/> <property name="xsl.library" value="docbook-xsl-1.53.0" /> <property name="xsl.dir" value="${doc.dir}/${xsl.library}" /> </target> <target name="dest-locations"> <property name="out.dir" value="out"/> <property name="out.doc.dir" value="${out.dir}/doc"/> <property name="out.xdoc.dir" value="${out.dir}/xdocs"/> </target> <target name="CallMeFirst" depends="project-properties, source-locations, dest-locations"> <tstamp/> <echo message="---- ${project.fullname} ${project.version} ----"/> <echo message=""/> <echo message="base dir = ${basedir}"/> <echo message="java.home = ${java.home}"/> <echo message="user.home = ${user.home}"/> <echo message="ant.home = ${ant.home}"/> <echo message=""/> <filter token="version" value="${project.version}"/> <filter token="year" value="${year}"/> </target> <target name="CheckXslLibrary" depends="CallMeFirst"> <available property="xsl.library.available" file="${xsl.dir}" /> </target> <target name="unpack-xsl" depends="CallMeFirst, CheckXslLibrary" unless="xsl.library.available" description="Unpack the stylesheets needed to build the book."> <unzip src="${doc.lib.dir}/${xsl.library}.zip" dest="${doc.dir}" /> </target> <target name="_CheckDtd" depends="CallMeFirst"> <!-- requires xdoc.dtd.dir --> <available property="dtd.available" file="${xdoc.dtd.dir}" /> </target> <target name="_UnpackDtd" depends="_CheckDtd" unless="dtd.available" > <!-- requires xdoc.dtd.dir --> <mkdir dir="${xdoc.dtd.dir}"/> <unzip src="${doc.lib.dir}/docbook-xml-4.2.zip" dest="${xdoc.dtd.dir}" /> </target> <target name="_prepare-xdoc" depends="CallMeFirst"> <!-- requires prepare.xdoc.dir, book.xml.file --> <mkdir dir="${prepare.xdoc.dir}"/> <!-- Copy files with filtering --> <filter token="docpath" value="${basedir}/${prepare.xdoc.dir}"/> <filter token="xslpath" value="${basedir}/${xsl.dir}"/> <copy file="${xdoc.dir}/${book.xml.file}" filtering="on" overwrite="true" tofile="${prepare.xdoc.dir}/book.xml"/> <copy file="${xdoc.dir}/htmlbook.xsl" filtering="on" overwrite="true" todir="${prepare.xdoc.dir}"/> <!-- Copy all remaining files from ${xdoc.dir} to ${out.xdoc.dir} --> <copy todir="${prepare.xdoc.dir}"> <fileset dir="${xdoc.dir}"> <exclude name="*-book.xml"/> <include name="*.xml"/> </fileset> </copy> <antcall target="_UnpackDtd"> <param name="xdoc.dtd.dir" value="${prepare.xdoc.dir}/dtd" /> </antcall> </target> <target name="prepare-book" depends="CallMeFirst, unpack-xsl"> <mkdir dir="${out.doc.dir}"/> <mkdir dir="${out.doc.dir}/images"/> <antcall target="_prepare-xdoc"> <param name="prepare.xdoc.dir" value="${out.xdoc.dir}"/> <param name="book.xml.file" value="doc-book.xml"/> </antcall> <!-- Copy the images --> <copy todir="${out.doc.dir}/images"> <fileset dir="${xdoc.dir}/images"/> </copy> <!-- Copy other files (non XML) --> <copy todir="${out.doc.dir}"> <fileset dir="${xdoc.dir}"> <include name="*.pdf"/> <include name="*.css"/> </fileset> </copy> </target> <target name="html-book" depends="prepare-book" description="Generate book as a single HTML file."> <delete file="${out.doc.dir}/book.html" /> <xslt basedir="${out.xdoc.dir}" in="${out.xdoc.dir}/book.xml" out="${out.doc.dir}/book.html" style="${out.xdoc.dir}/htmlbook.xsl" processor="trax" /> </target> <target name="clean" depends="CallMeFirst" description="Remove all generated files"> <delete dir="${xsl.dir}" /> <delete dir="${out.dir}" /> </target> </project> --- NEW FILE: .project --- <?xml version="1.0" encoding="UTF-8"?> <projectDescription> <name>no-stone-unturned</name> <comment></comment> <projects> <project>junit</project> </projects> <buildSpec> </buildSpec> <natures> </natures> </projectDescription> |
From: Steve F. <sm...@us...> - 2002-08-02 21:57:13
|
Update of /cvsroot/mockobjects/no-stone-unturned/src/nostone/tests In directory usw-pr-cvs1:/tmp/cvs-serv27702/src/nostone/tests Added Files: TestHelper.java SearcherTest.java Log Message: --- NEW FILE: TestHelper.java --- package nostone.tests; import java.awt.*; public class TestHelper { public Component depthFirst(Container container, ComponentVisitor visitor) { Component[] components = container.getComponents(); for (int i = 0; i < components.length; i++) { Component component = components[i]; Component applied = visitor.apply(component); if (null != applied) { return applied; } if (component instanceof Container) { applied = depthFirst((Container) component, visitor); if (null != applied) { return applied; } } } return null; } public interface ComponentVisitor { public Component apply(Component aComponent); } } --- NEW FILE: SearcherTest.java --- package nostone.tests; import junit.framework.TestCase; import nostone.tests.TestHelper; import nostone.gui.Searcher; import javax.swing.*; import java.awt.*; public class SearcherTest extends TestCase { public SearcherTest(String name) { super(name); } public void testNoMatchesFound() { Searcher searcher = new Searcher(); ((JButton)findNamedComponent(searcher, "search button")).doClick(); assertEquals("Should be status", "No entries found", ((JLabel)findNamedComponent(searcher, "status")).getText()); } private Component findNamedComponent(final Container container, final String name) { return new TestHelper().depthFirst(container, new TestHelper.ComponentVisitor() { public Component apply(Component aComponent) { return name.equals(aComponent.getName()) ? aComponent : null; } }); } } |
From: Steve F. <sm...@us...> - 2002-08-02 21:57:13
|
Update of /cvsroot/mockobjects/no-stone-unturned/src/nostone/gui In directory usw-pr-cvs1:/tmp/cvs-serv27702/src/nostone/gui Added Files: Searcher.java Log Message: --- NEW FILE: Searcher.java --- /* */ package nostone.gui; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class Searcher extends JFrame { public Searcher() throws HeadlessException { super("Searcher"); JButton searchButton = new JButton("Search"); searchButton.setName("search button"); final JLabel statusBar = new JLabel(" "); statusBar.setName("status"); searchButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { statusBar.setText("No entries found"); } }); getContentPane().add(searchButton, BorderLayout.NORTH); getContentPane().add(statusBar, BorderLayout.SOUTH); pack(); } static public void main(String[] args) { Searcher searcher = new Searcher(); searcher.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { Window w = e.getWindow(); w.setVisible(false); w.dispose(); System.exit(0); } }); searcher.setVisible(true); } } |
From: Steve F. <sm...@us...> - 2002-08-02 21:56:51
|
Update of /cvsroot/mockobjects/no-stone-unturned/src/nostone/gui In directory usw-pr-cvs1:/tmp/cvs-serv27565/src/nostone/gui Log Message: Directory /cvsroot/mockobjects/no-stone-unturned/src/nostone/gui added to the repository |
From: Steve F. <sm...@us...> - 2002-08-02 21:56:51
|
Update of /cvsroot/mockobjects/no-stone-unturned/src/nostone/tests In directory usw-pr-cvs1:/tmp/cvs-serv27565/src/nostone/tests Log Message: Directory /cvsroot/mockobjects/no-stone-unturned/src/nostone/tests added to the repository |
From: Steve F. <sm...@us...> - 2002-08-02 21:56:50
|
Update of /cvsroot/mockobjects/no-stone-unturned/src/nostone In directory usw-pr-cvs1:/tmp/cvs-serv27565/src/nostone Log Message: Directory /cvsroot/mockobjects/no-stone-unturned/src/nostone added to the repository |
Update of /cvsroot/mockobjects/no-stone-unturned/doc/xdocs In directory usw-pr-cvs1:/tmp/cvs-serv27388/doc/xdocs Added Files: htmlbook.xsl doc-book.xml testing_guis_1.xml notes.xml htmlbook.css extra_entities.xml brief_introduction.xml Log Message: --- NEW FILE: htmlbook.xsl --- <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:import href="file:///@xslpath@/html/docbook.xsl"/> <xsl:param name="html.stylesheet" select="'htmlbook.css'"/> </xsl:stylesheet> --- NEW FILE: doc-book.xml --- <?xml version="1.0"?> <!DOCTYPE book [ <!ENTITY % docbook SYSTEM "file:///@docpath@/dtd/docbookx.dtd"> <!ENTITY % extra_entities SYSTEM "file:///@docpath@/extra_entities.xml"> <!ENTITY chp_brief_intro SYSTEM "file:///@docpath@/brief_introduction.xml"> <!ENTITY testing_guis1 SYSTEM "file:///@docpath@/testing_guis_1.xml"> <!ENTITY notes SYSTEM "file:///@docpath@/notes.xml"> %docbook; %extra_entities; ]> <book> <title>No Stone Unturned</title> <bookinfo> <author> <firstname>Steve</firstname> <surname>Freeman</surname> <email>st...@m3...</email> </author> <author> <firstname>Nat</firstname> <surname>Pryce</surname> <email>nat...@b1...</email> </author> <copyright> <year>@year@</year> <holder>Steve Freeman</holder> </copyright> </bookinfo> &testing_guis1; ¬es; </book> --- NEW FILE: testing_guis_1.xml --- <part status="first cut"> <title>Developing Graphical Applications</title> <partintro> <para> It <emphasis>is</emphasis> possible to develop graphical applications test-first. It's not easy, because graphical user interfaces have to respond to people (who are less predictable and linear than we'd like) and so tend to have lots of global state that's hard to test in isolation. That, and the variable quality of some popular graphical toolkits, means that we have to think a bit harder we do for non-graphical applications. It took a while for the test-driven development community to figure out what to do, for a long time the answer was to make the presentation layer as thin as possible and to defer everything down to a business layer. That's probably why there are no tests for the graphical test runners for <application>JUnit</application>. This is still good advice but it doesn't feel good enough, given how much we say we believe in the benefits of writing the tests first. Now we have a better handle on how to work with graphical environments (or at least some of them). Let's see something working. </para> </partintro> <chapter> <title>A Search Dialogue</title> <para> Our customer has asked us to write our favourite demonstration application, a search dialogue that takes a search string and shows multiple lines of results. After some discussion, the story breaks down into the following tasks: </para> <procedure> <step> <para> The user clicks the <guibutton>Search</guibutton> button. There are no matches and the status bar shows <emphasis>No entries found</emphasis>. </para> </step> <step> <para> The user clicks the <guibutton>Search</guibutton> button, show one matching line. </para> </step> <step> <para> Run a search when the user hits <keysym>Return</keysym> in the search string field. </para> </step> <step> <para> The user clicks the <guibutton>Search</guibutton> button, there are no matches and any previous output is cleared. </para> </step> <step> <para> At the start of a search, clear the status bar. Also, set the cursor to the hourglass during the search. </para> </step> <step> <para> The user clicks the <guibutton>Search</guibutton> button, there are too many results to show in the available space, so show scrollbars. </para> </step> <step> <para> The user clicks the <guibutton>Search</guibutton> button, there are too many results to show in the available space, stop when there's a pageful before the scrollbars appear. </para> </step> <step> <para> There are too many results, as with the last task. Add a <guibutton>More</guibutton> button that will show all the results after the first page has been shown. </para> </step> <step> <para> Disable the <guibutton>More</guibutton> button unless there is more than a page ofresults to show. </para> </step> </procedure> <para> As always, the trick is to find a way to add little bits of functionality to the application so that we can see that we're always moving forward. What we don't do is write the whole user interface and model seperately and then try to glue them to together at the end. </para> </chapter> <chapter> <title>The first test</title> <sidebar> <para>A search with no results.</para> </sidebar> <section> <title>Basic scaffolding</title> <para> Sometimes the hardest thing in test-driven development is getting started (a bit like writing this book). What is the simplest first test for a graphical user interface that we can implement without taking too large a step; we don't want to let more than a few minutes go by before we see that test bar turn green again. As always, the trick is to be very clear about what we want to test. </para> <para> While we're waiting for a flash of genius, let's do something simple enough to understand. Let's start the first test and make sure that we can create an application object. </para> <programlisting> public class SearcherTest extends TestCase { public SearcherTest(String name) { super(name); } public void testNoMatchesFound() { Searcher searcher = new Searcher(); } } public class Searcher { }</programlisting> &redbar; <para> This doesn't do much, but it does at least force us to come up with <classname>Searcher</classname>, a name for our application, and names are always important. What else can we assert? We know that we'll need some components in our user interface to complete the first task, so let's check that they're present. We'll start with just one. </para> <programlisting> public void testNoMatchesFound() { Searcher searcher = new Searcher(); assertNotNull("Should be search button", findNamedComponent(searcher, "search button")); }</programlisting> <sidebar> <function>findNamedComponent()</function> is a helper method that searches the user interface structure for a component that has the given name, see <xref linkend="findNamedComponent" /> </sidebar> <para> Now our test won't compile because <classname>Searcher</classname> is not a <classname>java.awt.Container</classname>. We will need a top-level window component somewhere, so let's fix both problems by making <classname>Searcher</classname> extend <classname>javax.swing.JFrame</classname>. We'll also create a button for starting the search so that the test will pass. We can do all of this in the constructor. One day, as the application grows, we can extract it into something cleaner, but this will do for now. </para> <programlisting> public class Searcher extends JFrame { public Searcher() throws HeadlessException { super(); JButton searchButton = new JButton("Search"); searchButton.setName("search button"); getContentPane().add(searchButton); } }</programlisting> &greenbar; <para> I'm prepared to believe this unit test, but I'd really like to <emphasis>see</emphasis> something—we also believe in early integration testing. I'll tack on a <function>main</function> method and a call to <function>pack()</function>so that we can run our magnificent first application. (I've also sneaked in a <classname>WindowListener</classname> to catch the window closing event and shut things down cleanly. It's boilerplate to help me get through this demonstration, if you like you can treat it as an exercise for the reader.) </para> <programlisting> public class Searcher extends JFrame { public Searcher() throws HeadlessException { super("Searcher"); JButton searchButton = new JButton("Search"); searchButton.setName("search button"); getContentPane().add(searchButton); pack(); } static public void main(String[] args) { Searcher searcher = new Searcher(); searcher.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { Window w = e.getWindow(); w.setVisible(false); w.dispose(); System.exit(0); } }); searcher.setVisible(true); } }</programlisting> <para>Which looks like this:</para> <screenshot><mediaobject> <imageobject><imagedata fileref="images/gui_example1.gif" format="gif" /></imageobject> <caption><para>The first screen</para></caption> </mediaobject></screenshot> </section> <section> <title>Finishing the test</title> <para> Now we've assembled some core infrastructure, we can finish off the test with some meaningful behaviour. What exactly does this test have to prove to fulfill our first requirement? That the status bar shows an appropriate message after the user clicks <guibutton>Search</guibutton>. For example, </para> <programlisting> public void testNoMatchesFound() { Searcher searcher = new Searcher(); ((JButton)findNamedComponent(searcher, "search button")).doClick(); assertEquals("Should be status", "No entries found", ((JLabel)findNamedComponent(searcher, "status")).getText()); }</programlisting> <para>Of course this fails:</para> <screen> There was 1 error: 1) testNoMatchesFound(nostone.gui.SearcherTest) java.lang.NullPointerException at nostone.gui.SearcherTest.testNoMatchesFound(SearcherTest.java:19) FAILURES!!! Tests run: 1, Failures: 0, Errors: 1</screen> &redbar; <para> because we don't have a status bar. I'll add a suitable <classname>javax.swing.JLabel</classname>. Now it fails for a more interesting reason. </para> <screen> There was 1 failure: 1) testNoMatchesFound(nostone.gui.SearcherTest)junit.framework.AssertionFailedError: Should be status expected:<No entries found> but was:< > at nostone.gui.SearcherTest.testNoMatchesFound(SearcherTest.java:19) FAILURES!!!</screen> &redbar; <para> Now we have to add some behaviour so that the status bar is updated. In Swing, that's done with an <classname>ActionListener</classname>. In this case, the behaviour is simple, just set the contents of the status component. Here's the whole of the reworked constructor. </para> <programlisting> public Searcher() throws HeadlessException { super("Searcher"); JButton searchButton = new JButton("Search"); searchButton.setName("search button"); final JLabel statusBar = new JLabel(" "); statusBar.setName("status"); searchButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { statusBar.setText("No entries found"); } }); getContentPane().add(searchButton, BorderLayout.NORTH); getContentPane().add(statusBar, BorderLayout.SOUTH); pack(); }</programlisting> &greenbar; <para>and here's the evidence that it actually works.</para> <screenshot><mediaobject> <imageobject><imagedata fileref="images/gui_example2.gif" format="gif" /></imageobject> <caption><para>With a status message</para></caption> </mediaobject></screenshot> </section> <section> <title>What have we learned</title> <para> User interface testing is messy, but not impossible. Graphical frameworks are made up of code, just like other frameworks and, if they're not completely dysfunctional, it should be possible to exercise that code in isolation. As always, the skill is in being very clear about what will give you enough confidence to carry on adding to and changing your code, without letting mistakes through or slowing yourself down with brittle tests. In this case, we've decided that we don't care about layout, just that various components are present <emphasis>somewhere</emphasis> in the application. Obviously, the look of the application must be right (or good enough) before it can ship, but layout and behaviour often change at different rates while a system is in development—they might even be worked on by different people—and you might not want your implementation test suite to break because someone's reworked a data panel. </para> </section> </chapter> <appendix id="findNamedComponent" status="todo"> <title>Finding GUI components</title> </appendix> </part> --- NEW FILE: notes.xml --- <part status="first cut"> <title>To Do</title> <itemizedlist> <listitem><para>Tests in Ant</para></listitem> <listitem><para>bash mocks</para></listitem> <listitem><para><emphasis>DocBook</emphasis>Fix keysym, guibutton, co</para></listitem> </itemizedlist> </part> --- NEW FILE: htmlbook.css --- /* htmlbook.css, a stylesheet for htmlbook */ h1 { text-align: center; font-family: Arial, Helvetica, sans-serif; font-weight: bold} h2 { font-family: Arial, Helvetica, sans-serif; margin-top: 3%} h3 { font-family: Arial, Helvetica, sans-serif; font-style: italic; font-weight: bold} p { font-family: Arial, Helvetica, sans-serif} li { font-family: Arial, Helvetica, sans-serif } pre { margin-left: 5%; } --- NEW FILE: extra_entities.xml --- <!ENTITY redbar "<emphasis>Red Bar</emphasis>" > <!ENTITY greenbar "<emphasis>Green Bar</emphasis>" > --- NEW FILE: brief_introduction.xml --- <chapter> <title>How Mock Objects Happened</title> <section><title>Introduction</title> <para>Mock Objects is a development technique that lets you unit test classes that you didn't think you could <emphasis>and</emphasis> helps you write better code whilst doing so. This article uses a simple example to show a compressed history of how Mock Objects was discovered by refactoring from conventional unit tests and what its advantages are.</para> <para>Mock Objects is based on two key concepts: replace everything except the code under test with mock implementations that emulate the rest of the environement, and put the test assertions <emphasis>inside</emphasis> those mock implementations so that you can validate the interactions between the objects in your test case as they occur.</para> <para>This article assumes that you are familiar with java and unit testing using JUnit.</para> </section> <section><title>Simple Unit Tests</title> <remark>Perhaps we should change from "I" to "we" in these examples to show that we are pair programming!</remark> <para>Let's dive straight into a worked example. I am writing a component to automatically direct robots through a warehouse. Given a starting point on a grid, it will find a route through the stacks to a given destination. How can I test this? The standard approach is to write some unit tests that create a robot, call some methods on it, and then check that the resulting state is what we expect. My tests will have to tell me, for example, that the robot arrives where it was directed to go and does not hit anything on the way. A easy test to start with is to check that a robot does not move if it is told to go to its current location: </para> <example><title>the first test for our robot</title> <programlisting>public class TestRobot { [...] public void setUp() { robot = new Robot(); } public void testGotoSamePlace() { final Position POSITION = new Position(1, 1); robot.setCurrentPosition(POSITION); robot.goTo(POSITION); assertEquals("Should be same", POSITION, robot.getPosition()); } }</programlisting> </example> <para>This tells me that the robot thinks has arrived where it should be, but it doesn't tell me anything about how it got there. It might have trundled all the way round the warehouse before returning to its original location. I would like to know that the Robot didn't move in this test. One option would be to store and retrieve the route it took after each <methodname>goto()</methodname>. For example:</para> <example><title>Testing our robot more rigorously</title> <programlisting>public void testGotoSamePlace() { final Position POSITION = new Position(0, 0); robot.setCurrentPosition(POSITION); robot.goTo(POSITION); assertEquals("Should be empty", 0, robot.getRecentMoveRequests().size()); assertEquals("Should be same", POSITION, robot.getPosition()); }</programlisting> </example> <para>My next test might be to move one point on the grid:</para> <example><title>Testing movement</title> <programlisting>public void testMoveOnePoint() { final Position DESTINATION = new Position(1, 0); robot.setCurrentPosition(new Position(0, 0)); robot.goto(DESTINATION); assertEquals("Should be destination", DESTINATION, robot.getPosition()); List moves = robot.getRecentMoveRequests(); assertEquals("Should be one move", 1, moves.size()); assertEquals("Should be same move", new MoveRequest(1, MoveRequest.SOUTH), moves.get(1)); }</programlisting> </example> <para>As the tests become more complex, I would pull out some of the detail into helper methods to make the code more legible:</para> <example><title>Helper methods make tests more readable</title> <programlisting>public void testMoveALongWay() { final Position DESTINATION = new Position(34, 71); robot.setCurrentPosition(new Position(0, 0)); robot.goto(DESTINATION); assertEquals("Should be destination", DESTINATION, robot.getPosition()); assertEquals("Should be same moves", makeExpectedLongWayMoves(), robot.getRecentMoves()); }</programlisting> </example> <para>Where <methodname>makeExpectedLongWayMoves()</methodname> returns another list of the moves I expect the robot to take for this test.</para> <para>There are problems with this approach to testing. First, tests like this are effectively small-scale integration tests, they set up pre-conditions and test post-conditions but they have no access to the code while it is running. If one of these tests fail, I will have to step through the code to find the problem because the assertions have been made <emphasis>after</emphasis> the call has finished.</para> <para>Second, to test this behaviour at all, I had to add some functionality to the production class, namely retaining all the <classname>MoveRequest</classname>s since the last <methodname>goto()</methodname>. I don't have any other immediate need for <methodname>getRecentMovesRequests()</methodname>. </para> <para>Third, although it's not the case here, test suites based on extracting history from objects tend to need lots of utilities for constructing and comparing collections of values. The need to write external code to manipulate an object is often a warning that its class is incomplete and that some behaviour should be moved from the utility to the class.</para> <para>Is there a better way? Can I find a style that will give me better error reporting and put the behaviour in the right place?</para> </section> <section><title>Factoring Out The Motor</title> <para>My robot is actually doing two things when moving through the warehouse: it chooses a route from where it currently to where it has to arrive, and it actually moves along the route it has chosen. If I separate these responsibilities into two objects, I can test that the object planning the route makes the correct requests to the object moving the robot, and, separately, test that the object moving the robot responds correctly to the requests set to it. </para> <para>Now I need to define an object model that gives me the separation of concerns I need for testing, but also makes sense in terms of my application domain. Aha! Robots have <emphasis>Motors</emphasis>. The Robot plans its route and passes control requests to its Motor; the Motor moves the robot in response to those requests. By intercepting the requests between the Robot and its Motor I can track what's happening inside the Robot. </para> <para> The first step is to define the interface that the Robot will use to control the Motor:</para> <example><title>The Motor interface</title> <programlisting>public interface Motor { void move(MoveRequest request); }</programlisting> </example> <para>Now I need to initialise a Robot with a Motor when I create it. Because I want to intercept the interaction between the Robot and its Motor I cannot let the Robot instantiate its own Motor; there would be no way to then intercept the Robot's movement requests. That leads me to pass a Motor instance to the Robot's constructor.</para> <para>I can now write my tests to create a Robot with an implementation of the <interfacename>Motor</interfacename> interface, that watches what's happening in the Robot, and complains as soon as something goes wrong. In fact, I will do this right now, before I start thinking about writing a real implementation of the Motor interface, so that I know my Robot implementation still works despite the extensive refactorings I have performed. The first test is now:</para> <example><title>Testing using a mock motor</title> <programlisting>public void testGotoSamePlace() { final Position POSITION = new Position(0, 0); robot.setCurrentPosition(POSITION); Motor mockMotor = new Motor() { public void move(MoveRequest request) { fail("There should be no moves in this test"); } }; robot.setMotor(mockMotor); robot.goTo(POSITION); assertEquals("Should be same", POSITION, robot.getPosition()); }</programlisting> </example> <para>In this test, if there is a bug in the Robot code and the Motor gets requested to move, the mock implementation of <methodname>move()</methodname> will fail immediately and stop the test; I no longer need to ask the Robot where it's been.</para> <para>Now I know that my Robot class works I can write a real implementation of the Motor interface:</para> <example><title>A real implementation of the Motor interface</title> <programlisting> public class OneSpeedMotor implements Motor { public void move(MoveRequest request) { turnBy(request.getTurn()); advance(request.getDistance()); } [...] } </programlisting> </example> <para>As my tests grow, I can refactor the various mock implementations into a single, more sophisticated MockMotor and use it throughout all the Robot tests; for example:</para> <example><title>Creating a mock motor class</title> <programlisting>public void MockMotor implements Motor { private ArrayList expectedRequests = new ArrayList(); public void move(MoveRequest request) { assert("Too many requests", this.expectedRequests.size() > 0); assertEquals("Should be next request", this.expectedRequests.remove(0), request); } public void addExpectedRequest(MoveRequest request) { this.expectedRequests.add(request); } public void verify() { assertEquals("Too few requests", 0, this.expectedRequests.size()); } }</programlisting> </example> <para>Which makes our tests look like:</para> <example><title>Testing our robot with mock motors</title> <programlisting>public class TestRobot { [...] static final Position ORIGIN = new Position(0, 0); public void setUp() { mockMotor = new MockMotor(); robot = new Robot(mockMotor); robot.setCurrentPosition(ORIGIN); } public void testGotoSamePlace() { robot.goTo(ORIGIN); assertEquals("Should be same", ORIGIN, robot.getPosition()); mockMotor.verify(); } public void testMoveOnePoint() { final Position DESTINATION = new Position(1, 0); mockRobot.addExpectedRequest(new MoveRequest(1, MoveRequest.SOUTH)); robot.goto(DESTINATION); assertEquals("Should be destination", DESTINATION, robot.getPosition()); mockMotor.verify(); } public void testMoveALongWay() { final Position DESTINATION = new Position(34, 71); mockMotor.addExpectedRequests(makeExpectedLongWayMoveRequests()); robot.goto(DESTINATION); assertEquals("Should be destination", DESTINATION, robot.getPosition()); mockMotor.verify(); } } </programlisting> </example> </section> <section><title>What does this mean?</title> <para>My code moved in this direction because I was committed to unit testing but didn't want to record and expose unnecessary details about the state of my Robot (the <methodname>getRecentMoveRequests()</methodname> method). As a result, I have better unit tests and a cleaner interface to the Robot class. But even better than that, by following the needs of my tests I have actually ended up improving the object model of the Robot by separating the Robot from its Motor and defining the an abstract interface between the two. I now have the flexibility to subtitute a different Motor implementation, perhaps one that accelerates. Similarly, if I want to track the total distance a Robot travels, I can do so without changing the implementation of either the robot or its motor:</para> <example><title>Tracking distance with the decorator pattern</title> <programlisting> /** A decorator that accumulates distances, then passes the request * on to a real Motor. */ public class MotorTracker implements Motor { private Motor realMotor; private long totalDistance = 0; public MotorTracker(Motor aRealMotor) { realMotor = aRealMotor; } public void move(MoveRequest request) { totalDistance += request.getDistance(); realMotor.move(request); } public long getTotalDistance() { return totalDistance; } } // When constructing the Robot, wrap the implementation of a // Motor that does the work in a MotorTracker. OneSpeedMotor realMotor = new OneSpeedMotor(); MotorTracker motorTracker = new MotorTracker(realMotor); Robot = new Robot(motorTracker); // do some travelling here [...] println("Total distance was: " + motorTracker.getTotalDistance()); </programlisting> </example> <para>Neither changing the Motor implementation nor adding tracking functionality would have been so easy if I had stuck with a testing strategy based on stashing the intermediate route. The next step might be to introduce a <classname>Navigator</classname> object to work out the route, and the Robot would link the two together.</para> <para>Tests based on Mock Objects usually conform to a pattern: setup any state, set expectations for the test, run the target code, and verify that your expectations have been met. This style makes tests easy to work with because they look similar and because all the interactions with an object are local to a test fixture; I have found myself contributing usefully to someone else's code base after only a few minutes with the tests. More importantly, however, I constantly find that the process of deciding what to verify in a test drives me to clarify the relationships between an object and its collaborators. The flex points I add to my code to provide support for testing turn out to be the flex points I need as the use of the code evolves. </para> </section> <section><title>Conclusions</title> <para>This simple example shows how refactoring tests with some design principles in mind led to the discovery of an unusually fruitful development technique. Using Mock Objects in practice is slightly different. First, the process of writing a test usually involves defining which mock objects are involved, rather than extracting them afterwards. Second, in Java at least, there are the beginnings of a Mock Object library for common classes and APIs. Third, there are now several tools and libraries to help with the construction of Mock Objects. In particular, the <ulink url="http://www.mockobjects.com">www.mockobjects.com</ulink> site includes a library of expectation objects. </para> <para> The rest of this book will show you how to use Mock Objects and Test Driven Design in your development process. We will work through some real-world examples to show how Mock Objects can be used to test Java APIs, drive refactoring and eliminate dependencies on external components. And along the way we will annotate our examples with tips and warnings to help you improve your technique and avoid pitfalls. </para> <para> Mock Objects and Test Driven Design have changed the way we develop code, and changed it noticeably for the better. We hope that you can benefit from these techniques as well and that this book helps you to do so. </para> </section> </chapter> |
From: Steve F. <sm...@us...> - 2002-08-02 21:56:06
|
Update of /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/images In directory usw-pr-cvs1:/tmp/cvs-serv27388/doc/xdocs/images Added Files: green_bar.gif red_bar.gif gui_example2.gif gui_example1.gif Log Message: --- NEW FILE: green_bar.gif --- GIF87a --- NEW FILE: red_bar.gif --- GIF87a --- NEW FILE: gui_example2.gif --- GIF87a J´¨Ñ£H Ä)°ç¥§ÿäÙ»·OEÒ«X³jÝtéɦ;/ýU^E³V¹ªÕ*@Ûox©³Xyí¢î;û/íÚ¿HsÞtÛÐ$Ü UpLøiw¨wç&ÛÔxË-5ÎB§úÝ~ö§§¦\5è^ \iHnwP_µ8Ë?:ÿâÆ«éxݪÔÝ`§ñº\«Í©1) Â* ¶Þ XI4ëì³Îºí´ÑÂE-µÊ±¨³ÜÒí,ÝZ¬²jî¹è¶Sº§: ¬z*Ä+ï¼ãkï½Diï¾üÆ¢M æN¡GHB°H(ÔÛ Sȳ° 0¬ÚcHÃͰ8¤Ù sÈC±(y;åæ\vº ñm?|ßÏx3&ÚÌeK"ø¦8ÄÛ!ïßkßúÖǾ̽/|É"ؤxÅÄõîzX_õ´XFëånu«+cCÄÍ©qÔËã»§GÞOp¼£åVÇâ}lô벨9.*2T¢ yÆ(/>R|lciÉLBR ¤#%JOr¡äåÉ4:®h¬b#÷¨FEînzT+Ñh½ºí°À<Ù/IÌ9 ³Áü×ÀÉLf²¦Ð&M`rjZóØÌ¦6·ÉÍnf]à§8ÇIÎró§ --- NEW FILE: gui_example1.gif --- GIF87a J´¨Ñ£H*í)0§@¢þgïÞ>K³jÝʵëЦ'ò¼ô/ÞTyÑbõʶH .ÿÖ¥þÙ©#nÌÑßõ ^aâ wbTÒ*£fa誡¯ÐþÉ´ÔV[-\ÖfK-Új[ltÒ92Ë-ãÎ2®E¼BÚ«ì¶Ë.Oî::+¸c©`ï½ø¦«î¾üUe¿ Zð¬àÞÚã'yð áG°ð$D¡ W8të 0¡gHÃÚð8V¼vÈÃúð@¢y |
From: Steve F. <sm...@us...> - 2002-08-02 21:54:05
|
Update of /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/images In directory usw-pr-cvs1:/tmp/cvs-serv26791/doc/xdocs/images Log Message: Directory /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/images added to the repository |