tag:blogger.com,1999:blog-60822422024-03-08T09:14:22.097+00:00JBlogsA .Net Developer's DumpsterUnknownnoreply@blogger.comBlogger140125tag:blogger.com,1999:blog-6082242.post-17643014612375889042008-01-26T00:09:00.000+00:002008-01-26T00:10:45.254+00:00Almost missed the flight to Hong KongIt was the big day yesterday. The family, Ryan (5 months) Danni my wife and me was on a long haul fight from London to Hong Kong then en-route to China to see the family there. To get to the Gatwick airport, we need to take express train from home station.<br /><br />Once a few years back, I have some bad experience on rail travel to this airport. The distance is so long, it involves at least one connection, maybe two or three if need to going to central London first. In that incident, the delayed railway work had many train services cancelled, and we had been delayed at the start of the trip – then a chain of delays had we missed the fight when were finally at the airport although we leave a plenty of time for the travel.<br /><br />The Deja Vu was back this time. We almost miss the flight yesterday.<br /><br />We arrived at train station at 18 minutes before it arrived. Two huge luggage, three pieces hand carried bags, Ryan and his buggy were unloaded from the taxi. Did I say three? Wait, ‘honey, do you see my laptop bag?’ <br /><br />The bag with laptop and other important things was left at home. Without them I have to cut short my hols, and buy another ticket home in two weeks time. Panic, in a very desperate attempt, Danni, Ryan and a suitcase were left at the platform, put one rucksack back, and I was drove home with the taxi to get the bag.<br /><br />It 9s about 10-15 minute one way drive from home to the station in a clear traffic. This time it was very busy, the lunch hour. A lorry and a wagon joined up in front, every traffic light turned into red when we up to it. Radio reported midday, 12 minutes before the train arrives on half way to my home.<br /><br />I didn't know how Danni would handle things neither: buggy, a huge suitcase (38KG) and Ryan. Some passed-by help her to move the suitcase into the station concourse. But then and she needs to draw some cash from outside station and collect tickets from fast ticket machine. I thought I am going to miss them.<br /><br />Taxi pulled stop at a near exit it may make it a minute or two quicker than if drove up. I ran the shortcut uphill to collect the bag, locked the door. The heart was beating so fast, and the hand is so shaky I dropped the key when locking the door. Ran the short cut to meet the taxi, and we back. <br /><br />When I daring enough to look at the time. The dashboard display was showing an airbag warning so the time is not showing. Maybe that was not a bad news after all.<br /><br />The train arrived just when the taxi waiting for oncoming traffic so to turn right on the road and got into station. Then I found I have no money to pay the additional taxi fare. I have got only got a fiver, which paid to the driver already - with additional round trip - I have got no money. That is why I need Danni to get some cash. <br /><br />On Phone asked Danni to get onboard first. With so many things, it was just nightmare to move things on its own. Danni asked a staff member to hold the train for 1 minute. Replied 'Sorry madam, I can’t hold a train'. It was a virgin west coast fast train. i think probably he could if it was a slower local train. They went onboard without waiting<br /><br />I told the driver the embarrassing truth before she pulled stop and I slam the door open. She let me off although not very happy - I won't blame her. I thanked her very much and promised will pay back once I am back. <br /><br />Got the laptop bag, and cuddling the other huge rucksack from the boot, desperately run to the platform. Luckily it was at platform 1, so no need to jump down rail track or run through the passenger bridge. <br /><br />The train was still there, first class door was still open, right in front. Before I dove into the coach, I asked the staff 'Are they on?' he smiled and nodded, ‘Yes, they have’.<br /><br />The train was 2 minutes late, and probably been hold for 15 or 30 sec. <br /><br />Danni was very cool in the situation, and Ryan was very helpful, no crying whatsoever. When they were on, Danni found him had already napped away.Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-6082242.post-22978476478057947292007-12-21T21:28:00.001+00:002007-12-21T21:30:18.495+00:00using slide duplicator to 'scan' slide<div style="float: right; margin-left: 10px; margin-bottom: 10px;"> <a href="http://www.flickr.com/photos/i-fotos/2125297217/" title="photo sharing"><img src="http://farm3.static.flickr.com/2130/2125297217_f5d8eaf09b_m.jpg" alt="" style="border: solid 2px #000000;" /></a> <br /> <span style="font-size: 0.9em; margin-top: 0px;"> <a href="http://www.flickr.com/photos/i-fotos/2125297217/">using slide duplicator to 'scan' slide</a> <br /> Originally uploaded by <a href="http://www.flickr.com/people/i-fotos/">Jingye</a> </span></div>At old school, slide duplicator is used to copy and make additional slide set from existing ones. <br />At new age, digitalise slides are done by using film scanner. <br />This is an attempt to do poor man's scanning: use a full frame DSLR to copy slides to raw then process to jpg etc. I am very pleased with the result.<br />It offers more control, dust control, and much faster.<br /><br />This one is done by using slide duplicator:<br /><a href="http://www.flickr.com/photos/i-fotos/2127692128/" title="Morning bath by Jingye, on Flickr"><img src="http://farm3.static.flickr.com/2361/2127692128_7f04fa1887.jpg" width="333" height="500" alt="Morning bath" /></a><br /><br />This one is done by scanner:<br /><a href="http://www.flickr.com/photos/i-fotos/451402373/" title="Sikh Golden Temple by Jingye, on Flickr"><img src="http://farm1.static.flickr.com/183/451402373_b57731b43e.jpg" width="335" height="500" alt="Sikh Golden Temple" /></a><br clear="all" />Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-6082242.post-23244577645791201442007-08-19T17:15:00.000+01:002007-08-19T17:32:15.305+01:00Cleanig DSLR CMOS SensorThere is one practical issue Digital Single Lenses Reflection Camera (DSLR) lost to ‘Analogue’ (Film) SLR is dust control. DSLR attracts and accumulates dust to its CCD/CMOS sensor. A dirty sensor casts greyish dots on the photo. <span style=""> </span>Film camera doesn’t have a CCD sensor. When shutter opens, it exposes light-sensitive film. If there is no film loaded, no film to collect dust. So even if the maybe speck fells on the film, it will 1) washed away in developing; and 2) it wouldn’t be a lasting problem. <p class="MsoNormal">I have been suffering from this ‘dirty’ problem since I converted to DSLR. I use a few zoom lenses and swap them on times. In a sun-scorched, dusty tropical countryside mounting lenses is the best thing you could do to damage your DSLR,, which was assembled in a static-free lab.</p> <p class="MsoNormal"><o:p></o:p>I was getting-by with an incompetence bush blower in the past. Let camera camber face down while blowing air into it. I have even tried household vacuum cleaner – not to the extent stick it into the camber though. They just never went away. In fact I see more and more dots shown on the shoots. </p> <p class="MsoNormal">Using Photoshop stamp tool to copy some pixels from neighbourhood is one way to get around the problem. Until there are just too many of them!</p> <p class="MsoNormal">This photo was taken last Sunday with F-stop to F13, focus to more than 10 meters. It is just too dusty and too moral busty to be manually fixed (although I still did it). It made me decide to splash out on a proper cleaning kit.</p> <p class="MsoNormal"><o:p><a href="http://www.flickr.com/photos/i-fotos/1171593612/" title="Photo Sharing"><img src="http://farm2.static.flickr.com/1023/1171593612_42cef7e77f.jpg" width="500" height="333" alt="Lots of Dust" /></a> <br> link to a <a href="http://www.flickr.com/photo_zoom.gne?id=1171593612&size=o">larger one</a></o:p></p> <p class="MsoNormal">Here is the major steps:</p> <ol style="margin-top: 0cm;" start="1" type="1"><li class="MsoNormal" style="">Blow off loose dust from the camber</li><li class="MsoNormal" style="">grab speck directly from the CCD sensor</li><li class="MsoNormal" style="">Use Pec Pad with ‘Eclipse 2’ solvent to wipe the sensor surface.</li></ol> <p class="MsoNormal"><o:p> </o:p><br />Here is tool list:</p> <ul><li>New Giottos Q Ball Air Dust Blower Puffer with Adj tube</li><li>Speck Grabber Pro cleaning tool for CCD's, optics etc</li><li>Eclipse E2 Cleaning Fluid for camera CCD Sensor</li><li>PEC PAD 10x10cm (100) Cleaning Wipes for Lens & Filters</li><li>Sensor Swab Type 3 (12Pk) For Canon, Kodak CCD Cleaning<o:p> </o:p><br /></li></ul> <p class="MsoNormal">In total it costs near £70 from eBay. Almost a third of a Canon DSLR 400D!</p> <p class="MsoNormal"><o:p></o:p><a href="http://www.flickr.com/photos/i-fotos/1171594516/" title="Photo Sharing"><img src="http://farm2.static.flickr.com/1332/1171594516_f6c5c5089f.jpg" width="457" height="500" alt="DSLR Sensor cleaning" /></a><br><br /></p><p class="MsoNormal">Giottos Q Ball Air Dust Blower is very powerful but no as powerful as canned air, which spreads strong current may actually leaves an un-removable marks on the surface. There is an air inlet valve prevents backflow and dust coming to blower.</p> <p class="MsoNormal"><a href="http://www.flickr.com/photos/i-fotos/1171595430/" title="Photo Sharing"><img src="http://farm2.static.flickr.com/1201/1171595430_f69ee1075e.jpg" width="500" height="370" alt="DSLR Sensor cleaning" /></a><br><br /></p><p class="MsoNormal">Speck Grabber is use to grab visible speck directly from delicate surface, such like reflection mirror, focus screen or CMOS sensor. It is an interesting tool. It has a tacky tip (the blue tip in the picture) made of copolymer plastic. Although it has tacky adhesion property, it doesn’t leave residue on the surface it touches. </p> <p class="MsoNormal">For grabbing speck directly there are other competing products, such like a ‘Dust-Aid’. Very expensive though – around 35 pounds of 12 sticky pads. </p> <p class="MsoNormal"><o:p><a href="http://www.flickr.com/photos/i-fotos/1171596316/" title="Photo Sharing"><img src="http://farm2.static.flickr.com/1002/1171596316_bafcd82fab.jpg" width="500" height="384" alt="DSLR Sensor cleaning" /></a><br></o:p><br />Sensor Swab is the most expensive one, costs £33. Any if you wonder what is in it – A sensor swab is a plastic wand wrapped with a Pec Pad tissue (1/3 sheet of it to be precise). <span style=""> </span>Pec Pad is secured to the wand by a tiny elastic band. 12 units of Sensor Swab in the package, in individual seal package. So it works out to be around £2.75 a pot! IMO, this can only be justified by the made to size wand. it fits just right to the size of sensor surface, so one wipe stroke will be enough hence reduce the need of repeat wiping – which may let small speck to scratch & grind the ultra sensitive sensor. </p> <p class="MsoNormal"><o:p><a href="http://www.flickr.com/photos/i-fotos/1171597254/" title="Photo Sharing"><img src="http://farm2.static.flickr.com/1358/1171597254_d60a27a7e8.jpg" width="500" height="422" alt="DSLR Sensor cleaning" /></a></o:p><br />And finally lint –free Pec Pad and Eclipse 2 Optic Cleaning Fluid for Tin Oxide Coated Sensor.</p><p class="MsoNormal">Now here is how to do it, reference to <a href="http://www.pbase.com/copperhill/image/71784128">http://www.pbase.com/copperhill/image/71784128</a> on how to prepare a home made sensor swab and how to apply it in great detail. Read it for definitive guide and tips.</p><p class="MsoNormal">Before apply Sensor swab I have few more steps:</p><p class="MsoNormal">1. Cleaning mirror and focus screen. Though cleaning this has no effect on shots, it helps to a cleaner view finder and reduces the risk of loose dust move to sensor later.</p> <ol><li>Un-mounted lenses but don’t switch on ‘cleaning sensor’ function or lifting up mirror. </li><li>Camera face down, blow off loose dust from the camber. Be careful don’t let nozzle touch any element in the camber.</li><li>Use SpeckGrabber to catch each visible dust particle. Must follow it’s user guide. </li></ol> <p class="MsoNormal"><o:p> </o:p>2. Cleaning CMOS sensor.</p> <ol><li>Lifting up mirror by B-stop or ‘cleaning sensor’ function of the camera.</li><li>Camera face down, use blower to blow off any loose dust speck.</li><li>Use SpeckGrabber to catch visible dust particle.</li><li>Use Sensor Swab to wipe clean the sensor, carefully.</li><li>Mount the lenses and release the locked-up mirror.</li></ol> <p class="MsoNormal"><o:p></o:p>This cleaning process may need to repeat to get the best result due to lenses mounting, locked-up mirror release could bring in ‘new’ specks. </p><p class="MsoNormal">If this is the case, in second run, you don’t need to clean mirror and focus screen again. So you should:</p> <ol><li><!--[if !supportLists]--><span style=""><span style=""><span style="font-family: "Times New Roman"; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"></span></span></span><!--[endif]-->Have every tool ready to use.</li><li><!--[if !supportLists]--><span style=""><span style=""><span style="font-family: "Times New Roman"; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"></span></span></span><!--[endif]-->While lenses is mounted, locked-up mirror or switch on ‘cleaning function’.</li><li><!--[if !supportLists]--><span style=""><span style=""></span></span>Detached lenses</li><li><!--[if !supportLists]--><span style=""><span style=""><span style="font-family: "Times New Roman"; font-style: normal; font-variant: normal; font-weight: normal; font-size: 7pt; line-height: normal; font-size-adjust: none; font-stretch: normal;"></span></span></span><!--[endif]-->Clean with SpeckGrabber if the new dust isn’t as serious as prevous.</li><li><!--[if !supportLists]--><span style=""><span style=""></span></span>Use Swab</li></ol> <p class="MsoNormal">This is a photo I took (F22) after first run, there is a new speck introduced while ‘old’ ones had gone.</p><p class="MsoNormal"><a href="http://www.flickr.com/photos/i-fotos/1170728649/" title="Photo Sharing"><img src="http://farm2.static.flickr.com/1075/1170728649_a781117234.jpg" width="500" height="333" alt="still one to go" /></a><br>Link to a <a href="http://www.flickr.com/photo_zoom.gne?id=1170728649&size=o">large size</a><br /></p> <p class="MsoNormal"><o:p></o:p>This is a photo I took after second run. No speck or greyish dust anymore.<br /><o:p> </o:p></p><p class="MsoNormal"><o:p><a href="http://www.flickr.com/photos/i-fotos/1171587904/" title="Photo Sharing"><img src="http://farm2.static.flickr.com/1305/1171587904_b8b9fac0ea.jpg" width="500" height="333" alt="no dust == world peace!" /></a><br>Link to a <a href="http://www.flickr.com/photo_zoom.gne?id=1171587904&size=o">large size</a></o:p><br />World peace!</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6082242.post-43064122853048979282007-08-07T08:14:00.001+01:002007-08-07T08:20:35.815+01:00Ely Cathedral<div style="float: right; margin-left: 10px; margin-bottom: 10px;"> <a href="http://www.flickr.com/photos/i-fotos/1031896127/" title="photo sharing"><img src="http://farm2.static.flickr.com/1176/1031896127_1cc106a3cb_m.jpg" alt="" style="border: 2px solid rgb(0, 0, 0);" /></a><br /><span style="margin-top: 0px;font-size:0;" > <a href="http://www.flickr.com/photos/i-fotos/1031896127/">Ely Cathedral</a> <br /> Originally uploaded by <a href="http://www.flickr.com/people/i-fotos/">Jingye</a> </span></div>Lady's Chapel Ely Cathedral. Dedicated to Virgin Mary. The largest of its kind in Europe. All four walls are engraved with delicate statues, unfortunately, all have been defaced in 16th century.<br /><br />I like the mysterious air set in this photo.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6082242.post-41414000591882207892007-05-18T08:26:00.000+01:002007-05-18T08:30:27.043+01:00Sikh Golden Temple<div><a title="photo sharing" href="http://www.flickr.com/photos/i-fotos/451402373/"><img style="border: 2px solid rgb(0, 0, 0);" alt="" src="http://farm1.static.flickr.com/183/451402373_b57731b43e_m.jpg" /></a><br /><span style="font-size:0;"><a href="http://www.flickr.com/photos/i-fotos/451402373/">Sikh Golden Temple</a><br /></span></div><br /><p>This photo has recently been selected as the winner of the theme <a href="http://www.flickr.com/groups/the_world_through_my_eyes/discuss/72157600202319995/">‘Tourist attractions from your travels’</a><br />by flickr group <a href="http://www.flickr.com/groups/the_world_through_my_eyes/">‘The world though my eyes’</a> and blogged <a href="http://theworldthroughmyeyesgroup.blogspot.com/">here</a>.<br /></p><p><i>‘This photo from the "tourist attraction" travel thread made a real impression on me. The tranquility, elegance and reverence of this shot is something to behold.’</i><br /></p><p>I am thrilled and very happy.<br /><br />You can see more photos of Sikh Golden Temple <a href="http://www.flickr.com/photos/i-fotos/sets/72157600059760055/">here</a> </p>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-6082242.post-19645932881809821242007-05-04T22:20:00.000+01:002007-05-04T23:12:21.095+01:00Jetty 6.1.2 (rc2) don't do multi core processor<p class="MsoNormal">Recently we upgraded our work laptop to Intel dual core processor.<br /><br />After moving my local working code branch to new pc, I start to see some very strange things happened. In some tests where the web server issues an httpClient call to itself hangs indefinitely. No time out; no response, the thread is just suspended.<br /><br />In comparison, the very same code runs merrily on my old pc (single core), I can see the httpClient request invokes a new thread on itself.<br /><br />Adding the mystery, the problem on dual core pc is intermittent- in about 20% occasion it starts a new thread.</p> <p class="MsoNormal">Jetty doesn't spawn a new thread on multi core CPU. Looking back I can come to this conclusion but the process to get to here wasn’t easy. Then I google out this <a href="http://jira.codehaus.org/browse/JETTY-305">bug report</a><br /></p> <p class="MsoNormal">I quickly upgrading to Jetty 1.6.3 - the stable build just released, the problem've gone away.<br /></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6082242.post-38669177057870889162007-04-22T10:22:00.000+01:002007-04-23T21:22:34.074+01:00Macro Photography<a title="photo sharing" href="http://www.flickr.com/photos/i-fotos/467575566/"><img style="BORDER-RIGHT: #000000 2px solid; BORDER-TOP: #000000 2px solid; BORDER-LEFT: #000000 2px solid; BORDER-BOTTOM: #000000 2px solid" alt="" src="http://farm1.static.flickr.com/223/467575566_27599c339c.jpg" /></a><br /><span style="font-size:85%;">0.005sec (1/200); f/13; Focal Length:105 mm; ISO Speed:640;Exposure Bias:0 EV;Flash fired; using 12 and 20mm extension tube<br /></span><br />Received Kenko extension tube set this week. Today I have a play with it.<br /><br /><br /><p>My favourite subject is ladybird. Though very small, it is a very beautiful beetle with bright red shell doted. The size–about 5-7mm-presents a serious challenge for macro photography.</p><p>Back earlier April, I used Macro function comes with the lenses for close up shooting, which can be manually focus (with moving camera back and forth) at around 0.45m distance. The finished shoots after crop and interpolation(up size of the digital image by calculated and filling the pixels) become blur at edges. This is understandable-the finished photo I used as desktop is actually 4 times the life size by digital up scaling, counting the actual projection size of the beetle on the CCD sensor(or film emersion) it is much smaller. Later I will show you image magnification ratio chart.</p><a title="photo sharing" href="http://www.flickr.com/photos/i-fotos/444868958/"><img style="BORDER-RIGHT: #000000 2px solid; BORDER-TOP: #000000 2px solid; BORDER-LEFT: #000000 2px solid; BORDER-BOTTOM: #000000 2px solid" alt="" src="http://farm1.static.flickr.com/254/444868958_f888fedf20.jpg" /></a><br /><span style="font-size:85%;">0.005sec (1/200); f/9; Focal Length:105 mm; ISO Speed:100;Exposure Bias:0 EV;Flash No; Using Macro function<br /></span><br />It must be optical magnification to solve the problem properly rather than resize the digital image. There are few solutions around, such like use reverse ring to mount a 50mm lenses reversely. Use a bellow or an extension tube. Each solution has its pros and corns.<br /><br /><br /><p>Reverse ring is the cheapest solution. you can pick up one from eBay for around £5 including postage from China. It exposed the lenses inside out, without proection to the lenses element it could be a hazardous. And of course you lost TTL metering and auto focus.</p><p>Bellow is the most flexible but quite bulky. It takes a platform with ruler and guiding rails. I feel it is not the best choose for field shooting. I saw one on eBay going for £160 with a compliment 50mm FD lenses. A new one without lenses shipped from China costs about 30 pounds includes p&p.</p><p>That leaves candidate extension tube. By mounting it ( or combine a few and) to camera body, then mount lenses to it, you have the balance of flexibility, portable and lenses protection.<br />There are two types of extension tubes around. The economical one costs around £10 pounds, it doesn’t come with electronic contact points, so the camera and your AF, TTL lenses are disconnected. The one I brought made by Kenko comes with build-in contact points, it relays the communication between lenses and camera body. So it retains TTL metering and auto focusing. Costs £55 pounds from HK. About the price I paid for a 50mm 1.8F prime lenses. Consider there is no lenses, no motor and no circuit board but just 3 aluminium rings, it is quite expensive.<br /><a title="photo sharing" href="http://www.flickr.com/photos/i-fotos/467588788/"><img style="BORDER-RIGHT: #000000 2px solid; BORDER-TOP: #000000 2px solid; BORDER-LEFT: #000000 2px solid; BORDER-BOTTOM: #000000 2px solid" alt="" src="http://farm1.static.flickr.com/168/467588788_836f82d8f8_m.jpg" /></a><br /><span style="font-size:85%;">shown with 12, 20 and 36mm extension tubes mounted (See the red dots behind the lenses?)<br /></span><br />Anyway I am quite excited to have a new gadget under my belt.<br /><br />Global warming speeds up this Spring. Back three weeks ago there are a lot of ladybirds around our garden, now they all seemed gone away. So it is very lucky I found a fella basking sun in the grass.<br /><br />First I mounted a 25mm tube and set our little friend to a tulip leave. Didn’t use flash as the sunlight was still strong. Auto-focus is usable, but not very useful as the field of depth is very shallow regardless aperture: a little motion from the subject will mean refocusing. And the auto focusing is just not fast enough to cope. The strong wind didn’t help neither. With the magnifying effect from the tube, it renders subject violent movement.<br /><br />After a few attempts, I retreated. Took my little model with the stem he is resting on and set the shooting studio over dinning table.<br /><br />I use flash mounted with diffuser. First I try 25mm, then 25mm plus 12mm and finally 25mm plus 12mm plus 36mm. At the beginning I didn’t bother to set up tripod, thinking with speed at 1/200 and image stabiliser, it should be alright without – I was wrong, later I checked the photos and found there are compromised on quality. </p><p>With all three tubes mounted, the Maginification ratio increased to 6.1 for a 50mm lenses. I zoomed to around 100mm so the shake from the hands were even apparent. So a tripod is a must. In fact I use release cable and set the custom function to enable mirror lockup.<br /><br /><a title="photo sharing" href="http://www.flickr.com/photos/i-fotos/467586861/"><img style="BORDER-RIGHT: #000000 2px solid; BORDER-TOP: #000000 2px solid; BORDER-LEFT: #000000 2px solid; BORDER-BOTTOM: #000000 2px solid" alt="" src="http://farm1.static.flickr.com/203/467586861_4c48ad54a6.jpg" /></a><br /><span style="font-size:85%;">0.005sec (1/320); f/9; Focal Length:105 mm; ISO Speed:400; Exposure Bias:-1EV;Flash No; Using 20mm extension tube</span> </p><a title="photo sharing" href="http://www.flickr.com/photos/i-fotos/467588415/"><img style="BORDER-RIGHT: #000000 2px solid; BORDER-TOP: #000000 2px solid; BORDER-LEFT: #000000 2px solid; BORDER-BOTTOM: #000000 2px solid" alt="" src="http://farm1.static.flickr.com/215/467588415_9a899ff631.jpg" /></a><br /><span style="font-size:85%;">0.005sec (1/320); f/9; Focal Length:105 mm; ISO Speed:400; Exposure Bias:-1EV;Flash fired; Using 12, 20 and 36mm extension tube </span><br /><p><span style="font-size:85%;">After shooting, I resize the photo to be the same as the CCD size - for Canon 5D it is 23.84 x 35.8mm then measure the beetle’s size then compares to it is actual size: 6mm. Here is the actual magnification ratio chart:<br />(Setup) (CCD Projection size) (Mag. ratio)</span></p><p><span style="font-size:85%;">macro: 2.8mm 0.467 </span></p><p><span style="font-size:85%;">12,20 36mm ex.tube: 8.5mm 1.417 (approx.)</span></p><p><span style="font-size:85%;">12 and 20mm ex.tube: 7.6mm 1.267</span></p><p><span style="font-size:85%;">20mm ex.tube: 3.75mm 0.625 (approx.) </span></p><p><span style="font-size:85%;">P.S. Also found Cannon 5D handles high ISO noise quite well. With noise reduction switch on, it only becomes visibly grainy at 1000 or above. </span></p><p><a href="http://www.flickr.com/photos/i-fotos/sets/72157600041367303/">My close up shooting album.</a></p>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6082242.post-51167908877722845422007-01-29T00:25:00.000+00:002007-01-29T14:07:41.954+00:00Custom configuration with nested collections in .Net 2.0I am writing this as a brain dump.<br /><br />Has been played around with .NET 2.0 strong type configuration this weekend (a bit late, I know). After some uneven drive-thanks to the lack of documentation- I finally produce a custom configuration file like the one below.<br /><br />(For my work colleagues at Talis, yeah you - I know you will check my blog – If you are wondering why I am not using the time on our project for <a href="http://www.w3.org/RDF/">RDF</a> Java configuration. Honestly, I do. I mean you absorb and learn from a competing technology, getting ideas from patterns, even the naming convention it uses – particularly there is Reflector for sneaking around.)<br /><br />Here is the custom configuration setting with nested collection:<br /><span style="font-family:courier new;font-size:85%;"><section name="workflowConfig" type="Jingye.Workflow.Exe.WorkflowConfigSectionHandler,Workflow" /><br />…<br /><br /><workflowConfig seperateProcesses="true" processWaitTime="50000"><br /><setup workingPath="c:\temp\" /><br /><workflow name="WorkflowOne" interval="15" dailyRun="true" startTime="09"><br /><task name="task1" onError="Abort"/><br /><task name="task2" onError="Log" /><br /></workflow><br /><workflow name="WorkflowTwo" interval="9999" dailyRun="true" startTime="08"><br /><task name="anotherTask1" onError="Abort"/><br /><task name="anotherTask2" onError="Log" /><br /></workflow><br /></workflowConfig><br /></span><br /><strong>Some well-known bits and bobs<br /></strong>1. Where is my config file?<br />For web app, this setting is in web.config. It will be picked up by <span style="font-family:courier new;">ConfigutationManager</span> as the default config file.<br />For console app or win service, you need to tell the Configuration about this file.<br />1) The short form. You app.exe.config file should be side by side with app.exe. Framework will ‘intelligently’ figure out the path and suffix ‘.config’ to the exe.<br /><span style="font-family:courier new;font-size:85%;">Configuration config = ConfigurationManager.OpenExeConfiguration("Workflow.exe");<br />WorkflowConfigSectionHandler scheduler = (WorkflowConfigSectionHandler)config.GetSection("workflowConfig");<br /></span><br />2) The long form. The short form wraps this long form for convenient sake, but if you want to load a config from a different location or even pass in as command line argument, these are the lines to use<br /><br /><span style="font-family:courier new;font-size:85%;">ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();<br />// relative path names possible<br />fileMap.ExeConfigFilename = @"c:\temp\exe\ConfigTest.exe.config";<br />// Open another config file<br />Configuration config =<br />ConfigurationManager.OpenMappedExeConfiguration(fileMap,<br />ConfigurationUserLevel.None);<br /><br />//read/write from it as usual<br />ConfigurationSection mySection = config.GetSection("workflowConfig");<br /></span><br />2. Your configuration section - the root derives from <span style="font-family:courier new;font-size:85%;">System.Configuration.ConfigurationSection</span>. Back in .Net 1.x era, this is traditionally called XXXXHandler as it implements IConfigurationSectionHandler interface.<br /><br />3. Each configuration element is declared as class derives from ConfigurationElement. Configuration element can have child elements, again derives from ConfigurationElement.<br /><br />4. Configration elements take attributes/properties - decorates class properties with ConfigurationProperty. However configuration element doesn’t take CDATA text as body.<br /><br /><span style="font-family:courier new;font-size:85%;">[ConfigurationProperty("seperateProcesses", DefaultValue = "true", IsRequired = false, IsDefaultCollection = true)]<br /></span><br />5. Assign a key property in ConfigurationPropertyAttribute decoration. Such like ‘name’. You will need this to locate your configuration element in a MAP.<br /><br />6. If a config element is a collection such like this, you also need to implement a façade to manage access to each member, this MyConfigElementCollection class is derived from ConfigurationElementCollection class.<br /><br /><strong>Less well-known bits about MyConfigElementCollection class</strong><br /><br />1. By default, MyConfigElementCollection uses AddRemoveClearMap as its merging semantics – meaning how machine.config and your web.config or app.exe.config should merge together.<br />You can override this to be BasicMap or AddRemoveClearMapAlternate or BasicMapAlternate. Mark Gabarra discusses each of this merging semantic in his blog “<a href="http://blogs.msdn.com/markgabarra/archive/2006/06/27/648742.aspx">.Net Configuration Default Behaviour</a>”, worth a read if you are wondering ‘how could I stop downstream config changes my setting?’<br /><br /><span style="font-family:courier new;font-size:85%;">public override ConfigurationElementCollectionType CollectionType<br />{<br />get{ return ConfigurationElementCollectionType.BasicMap;}<br />}</span><br /><br />2. Override ElementName, if you are not using AddRemoveClearMap or just find another <span style="font-family:courier new;font-size:85%;">‘<add>’</span> being confusing to the guy actually uses your app.<br />By default, ElementName is “” (String.Empty), because in AddRemoveClearMapAlternate semantic, elements should be view as ‘operation instructions’ – add, remove or clear an element. The real name of the element is passed in the strong typing context, hence anonymous is acceptable. Nevertheless, it is less self-describing to the user.<br /><span style="font-family:courier new;font-size:85%;">protected override string ElementName<br />{ get { return "workflow"; } }<br /></span><br />3. In the parent element, where an instance of this element or a collection of this elements is declared, give the default name – “” as the name in ConfigurationProperty.<br /><span style="font-family:courier new;font-size:85%;">[ConfigurationProperty("", IsRequired = false, IsDefaultCollection = true)]<br />public WorkflowConfigElementCollection Workflows<br />{<br />get<br />{ return (WorkflowConfigElementCollection)base[""]; }<br />set<br />{ base[""] = value; }<br />}<br /></span><br />I find this is confusing at the beginning, but if link back to point 2, it all make sense on how reflection and serialization works.<br /><br /><strong>Reference:<br /></strong>Mark Gabarra, blog “<a href="http://blogs.msdn.com/markgabarra/archive/2006/06/27/648742.aspx">.Net Configuration Default Behaviour</a>”<br />Jason Diamond blogs on using call back custom validator: <a href="http://jason.diamond.name/weblog/2006/05/25/custom-configuration-section-validator-weirdness">Custom Configuration Validator Weirdness</a><br />Alois Kraus: <a href="http://www.codeproject.com/useritems/SystemConfiguration.asp">Read/Write App.Config with NET 2.0</a>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6082242.post-87832602317660458312007-01-11T18:06:00.000+00:002007-01-12T11:59:27.785+00:00Five things<p>Five Things about you and five firends of yours<br /><br />Admit that it is hard for me to come with five friends who blogg, this is difficult. And my Talisian colleagues are moving fast – I would say although your colleagues are your friends (at least in theory), you are not meant to tag them as this spirals into a workspace dead loop.<br />Now I am pulling my hair for the five coz <a href="http://www.dynamicorange.com/blog/archives/five_things.html">Rob</a> exhausts (almost) all work-bloggers I know, thanks also goes to <a href="http://iandavis.com/blog/2007/01/five-things">Ian (internet alchemy) D</a> too. No, nil, zero, no one (<a href="http://pragmaticintegration.blogspot.com/">Andy</a>, I leave <a href="http://trafficlightmusings.blogspot.com/index.html">Sarah</a> to your account).</p><p>So if you wonder who this quietly Jingye is, here is the five of him: </p><ol><li>I got to gym at least five times a week, do a 5km/30mins run before finishing the day.</li><li>I consume around 500 minutes podcast each week, mostly IT and digital photography related. My most favourite is <a href="http://downloads.bbc.co.uk/rmhttp/downloadtrial/worldservice/documentaryarchive/rss.xml">BBC documentary archives </a>and the least favourite is <a href="www.ibm.com/services/us/igs/rss/ibm_bcs_podcast.xml">IBM Institute for Business Value</a>.</li><li>Danni, my wife and I have recently completed a 25 km charity walk for<a href="http://www.bhf.org.uk/"> British Heart Foundation</a> at the Peak District.</li><li>My latest gadget is a Canon 5D digital camera. Here is one (more are in my <a href="http://www.flickr.com/photos/i-fotos/sets">flickr</a>). </li><li>I organise outdoor activities for the alike Chinese expats in Britain. Our next call is ‘Winter Farm Experience’ at Lake District. </li></ol><p><a title="Photo Sharing" href="http://www.flickr.com/photos/i-fotos/340788937/"><img height="248" alt="Stafford - Baswich" src="http://farm1.static.flickr.com/132/340788937_934947aaa1.jpg" width="500" /></a></p><p>And here are five friends of mine: <a href="http://mumucoffee.spaces.live.com/Blog">mumu</a>, <a href="http://xmaspanda.spaces.live.com/Blog">xp</a>, <a href="http://flywhc.spaces.live.com/Blog">flywhc</a>, <a href="http://thetime.spaces.live.com/Blog/">TheTime</a>, <a href="http://wisherxu.spaces.live.com/blog">Sisyphus</a></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6082242.post-73174616448096808732006-12-08T09:29:00.000+00:002006-12-08T09:40:09.122+00:00Effective Writing<p>Found <a href="mailto:jeremystellsmith@gmail.com">Jeremy Stell-Smith</a>'s <a href="http://work.onemanswalk.com/articles/2006/12/08/effective-writing">Effective Writing</a> a very useful guide from a TDD developer’s point of view on getting things done – without being distracted or going deviation in the writing.<br /><br />I still got a few travel essays pending – ‘todo’ since July - seem very daunting task, considering it is a part-time hobbits thing. In the running up to the New Year, I am going to try to apply these principles.<br /><br /><li>Work top down – do outline first<br /><li>Question Driven Writing – compare that to test driven development to stay on topic.<br /><li>Work in Sprints - cutting off the distraction and shut yourself down to external.<br /><p></p></li>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6082242.post-62568812504833495572006-11-11T20:49:00.000+00:002006-11-11T20:52:30.362+00:00AppDomain, process and components...This is a fundamental concept in .Net. In this short retrospective I try to offload following points:<br />1. What is AppDomain? Aslo a derived question: what is the difference between Appdomain and process?<br />2. Why we need AppDomain?<br />3. What is the design implication of Appdomain has on software?<br /><br /><span style="font-weight:bold;">So what is AppDomain? What is the difference between Appdomain and process?<br /></span>From <a href="http://www.gotdotnet.com/team/clr/AppdomainFAQ.aspx#_Toc514058484">gotnotnet</a> <br />“Application Domain is a construct in the CLR that is the unit of isolation for an application.” In non-.NET CLR environment, each running application is hosted by a process. There can be numerous processes launched of the same application and each process can only host ONE application. In contrast, .NET CLR introduces a light-way unit to load an application – AppDomain. Each AppDomain hosts one application, (or indeed assembly, component). Each process can have multiple AppDomains.<br /><br /><span style="font-weight:bold;">Why we need AppDomain?</span><br />AppDomain provides isolation around applications without the heavy cost associated with running an application within a process (address space, context, security...). In another word when addressing security context for example, it is wrapped around process unit. It relives each resident in an AppDomain from handling it themselves. <br /><br />The isolation means: <br />• An application can be independently stopped.<br />• An application cannot directly access code or resources in another application.<br />• A fault in an application cannot affect other applications.<br />• Configuration information is scoped by application. This means that an application controls the location from which code is loaded and the version of the code that is loaded.<br /><br /><span style="font-weight:bold;">What is the design implication of AppDomain has on software?</span><br />AppDomain promotes a loose-coupled component-oriented programming mode.<br /><br />The term component is probably one of the most overloaded terms in morden software engineering. From <a href="http://en.wikipedia.org/wiki/Component">Wikipedia</a> I found quite a few entries, which defines ‘component’ in different domain. Where it is related to computer science, it reads ‘<span style="font-style:italic;">A piece that makes up a whole, a part of an assembly</span>’. Very abstract. In electronic component, it says ‘<span style="font-style:italic;">An electronic component is a basic electronic element usually packaged in a discrete form with two or more connecting leads or metallic pads. Components are intended to be connected together…</span>’ This definition is more vivid to use as a metaphor here.<br /> <br />In .net a class *IS* a component. In the extreme form, one can compile a .net class into a binary assembly. Then CLR can load it into an AppDomain of a process. <br />From runtime process’ point of view, ‘traditional’ programming model/application is packaged to a monolithic binary block, regardless how it maps class diagram for business logic. Monolithic binary means they are tightly coupled. A change to one class can trigger a massive relinking of the entire application and necessitate retesting and redeployment of all other classes.<br /><br />In contrast, a .net component based application is a collection of binary building blocks grouped by functionality. Each block contains one or more classes. At run time, each block is loaded to an AppDomain, together, they make up a process. If one of the component needs to be update, changes are contained to that component only. No existing client of the component requires recompilation or redeployment. An updated component can even be updated while a client application is running, as long as the component isn’t currently being used.Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6082242.post-82441143609632712252006-11-02T18:06:00.000+00:002006-11-02T18:31:09.503+00:00Create your custom xAnt task<p class="MsoNormal">Here are some notes on how to extend ant task to provide your custom ant task. </p> <p class="MsoNormal">Both ant build (for Java) and nAnt build (for .net) are discussed.</p><p class="MsoNormal"> </p>1. nAnt<br /><br />In nAnt for .net build you embedded c# code as script though semantically it is a derived class from Nant.Core.Task. (You don’t need to include Nant.Core assembly. It is loaded by default). A scripting block is a top level block, meaning side by side with <target> block.<br /><br />In following sample script., the first static c# function is a - function - to work out number of running processes by given name.<br />The secnd task class is to kick off an external batch file - if you want the batch running in a separate process there isn't better way that this cumbersome one.<br />The third task class is to kill a process.<br /><br /><span style="font-size:78%;"> <script language="C#" prefix="custom"><br /> <code><br /> <![CDATA[<br /> [Function("NumberOfRunningProcess")]<br /> public static int NumberOfRunningProcess(string name)<br /> {<br /> System.Diagnostics.Process[] procList = System.Diagnostics.Process.GetProcessesByName(name);<br /> return procList.Length;<br /> }<br /><br /> [TaskName("WriteRunXspBatchScript")]<br /> public class WriteRunXspBatchScript: Task<br /> {<br /> private string _batchFilePath;<br /> private string _httpRootPath;<br /> private int _port;<br /> <br /> [TaskAttribute("XspRunScript", Required=true)]<br /> public string BatchFilePath<br /> {<br /> get{return _batchFilePath;}<br /> set{_batchFilePath=value;}<br /> }<br /><br /> [TaskAttribute("HttpRootPath", Required=true)]<br /> public string HttpRootPath<br /> {<br /> get{return _httpRootPath;}<br /> set{_httpRootPath=value;}<br /> }<br /><br /> [TaskAttribute("Port", Required=true)]<br /> public int HttpPort<br /> {<br /> get{return _port;}<br /> set{_port=value;}<br /> }<br /><br /> protected override void ExecuteTask()<br /> {<br /> string cmd = string.Format("start /MIN xsp --root \"{0}\" --port {1}", _httpRootPath, _port);<br /> using (StreamWriter wr = new StreamWriter(_batchFilePath,false))<br /> {<br /> wr.WriteLine("@echo off");<br /> wr.WriteLine(cmd);<br /> }<br /> }<br /> } <br /> [TaskName("StopXsp")]<br /> public class StopXsp : Task{<br /> private bool _deleteXsp;<br /> private string _xspRunScript;<br /> <br /> [TaskAttribute("DeleteXspRunScript", Required=false)]<br /> public bool DeleteXspRunScript<br /> {<br /> get{return _deleteXsp;}<br /> set{_deleteXsp=value;}<br /> }<br /><br /> [TaskAttribute("XspRunScript", Required=false)]<br /> public string XspRunScript<br /> {<br /> get{return _xspRunScript;}<br /> set{_xspRunScript=value;}<br /> }<br /> <br /> protected override void ExecuteTask() {<br /> System.Diagnostics.Process[] procList = System.Diagnostics.Process.GetProcessesByName("mono");<br /> if (procList==null )<br /> {<br /> throw new Exception("No Mono process found. Expect to kill one and only one mono xsp process");<br /> }<br /> if (procList.Length>1)<br /> {<br /> throw new Exception("More than one Mono processes is running. Expect to kill one and only one mono xsp process");<br /> }<br /> try<br /> {<br /> procList[0].Kill();<br /> }<br /> catch(Exception){;}<br /> <br /> if (_deleteXsp)<br /> {<br /> File.Delete(_xspRunScript);<br /> }<br /> }<br /> }<br /> ]]><br /> </code><br /></script></span><br /><br /><span style="font-size:100%;"><span style="font-weight: bold;">Usage:</span><br /><span style="font-size:78%;"><echo message="process devenv ${custom::NumberOfRunningProcess('devenv')}" /><br /><WriteRunXspBatchScript Port="80" HttpRootPath="${webcontrolsUnitTest.src.dir}" XspRunScript="${build.dir}\${MonoXspRun}" /><br /></span></span><span style="font-size:78%;"><</span><span style="font-size:78%;">StopXsp DeleteXspRunScript="true" XspRunScript="${build.dir}\${MonoXspRun}"/</span><span style="font-size:78%;">></span><br /><span style="font-size:100%;"><br />2. ant<br />Reference to <a href="http://www-128.ibm.com/developerworks/java/library/j-antbuild/">Extending Ant to support interactive builds</a>, to archive this you need to write external java classes, expose package via classpath by system envronment variable or via <path> in the build script.<br /><br />The only change to the sample code given in </span><span style="font-size:100%;"><a href="http://www-128.ibm.com/developerworks/java/library/j-antbuild/">Extending Ant to support interactive builds</a> is instead of using classpath, it uses </span><span style="font-size:100%;"><span style="font-weight: bold;"><path></span> :<br /><span style="color: rgb(51, 51, 153);font-size:78%;" ><?xml version="1.0"?><br /><project name="PropertyPromptExample" default="main" basedir="."><br /> <property name="promptTimeout" value="5"/><br /> <path id="extendedTask"><br /><span style="font-weight: bold;"> <fileset dir="c:\playpit\"></span><br /><span style="font-weight: bold;"> <include name="monkeyNuts.jar"/></span><br /><span style="font-weight: bold;"> </fileset></span><br /><span style="font-weight: bold;"> </path></span><br /><span style="font-weight: bold;"> <taskdef name="propertyprompt" classname="com.ibm.samples.apache.tools.ant.taskdefs.optional.PropertyPrompt" classpathref="extendedTask"/></span><br /><br /> <target name="main"><br /><!-- <javac srcdir="." destdir="." verbose="on"/> --><br /> <property name="propA" value="oldValA"/><br /> <property name="propA" value="oldValA1"/><br /> <echo>value of propA: ${propA}</echo><br /> <echo>value of propB: ${propB}</echo><br /> <propertyprompt propertyname="propA" promptcharacter=":">Enter value for propA</propertyprompt><br /> <propertyprompt propertyname="propB" defaultvalue="defvalB">What is the value for propB</propertyprompt><br /> <echo>value of propA: ${propA}</echo><br /> <echo>value of propB: ${propB}</echo><br /> </target><br /></project><br /></span></span>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6082242.post-3600846435468088872006-10-27T17:48:00.000+01:002006-10-27T18:00:40.674+01:00Export & Import Goodie from/to Photoshop<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/3778/742/1600/screenshot.gif"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger2/3778/742/400/screenshot.gif" alt="" border="0" /></a><br />Just finished my retrospective notes on <a href="http://jingyeluo.blogspot.com/2006/10/photoshop-action-and-batch-to-watermark.html#links">Photoshop Action and Batch to watermark images</a> then I think 'wait a minute, I have all these - custom shape custom action in one pc, how do I port it to another? I don't want to repeat the manual creation work again.<br /><br />It is a very simple task, a quick search found that IM Photography's tips: <a href="http://www.imphotography.com/downloads/installactions.htm">Installing and exporting Photoshop actions</a> Likewise you can export and import custom shape by first select the shape, then click on the little play trangle at the top right corner to bring up the context menu, then select 'save shapes...'Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6082242.post-77218081513225703462006-10-27T16:45:00.000+01:002006-10-27T22:12:28.606+01:00Photoshop Action and Batch to watermark images<span style="font-weight: bold;font-size:78%;" >Jingye says: 'I am scratching my head on Photoshop tasks'. I am not a pro (digital) photographer. With busy life, </span><span style="font-weight: bold;font-size:78%;" > I just want to get some reasonable quality picture from my digital cameras</span><span style="font-weight: bold;font-size:85%;" ><span style="font-size:78%;">. I took many many photos during holidays (easliy over 5Gb for two weeks in a exotic country). I only have time to tidy them up a little bit, mostly an auto-leveling and an auto-curving. Then I will print some, upload a small size to <a href="http://www.flickr.com/photos/i-fotos">flickr</a>; archive a large version.<br /><br />Many ps tasks I have done in the pass were forgotten fast. So here I steal/rewrite from other people’s Photoshop tips/how to do something. I claim not rights of them unless stated. This is just my web notepad for myself and everyone else.’<br /><br /><span style="font-size:130%;">Photoshop Action and Batch to watermark images<br /></span></span></span><br />Rewrite and proved based on Chris Kitchener's <a href="http://www.ephotozine.com/techniques/viewtechnique.cfm?recid=339">Watermarking your photos in Photoshop 7 and CS technique</a> ) and <a href="http://photoshop911.typepad.com/help/2004/04/watermarking_ph.html">Watermarking Photos (batch)</a><br /><br /><span style="font-weight: bold;">Objective</span>:<br />1) Create a reusable watermark.<br />2) Create a custom action and use Photoshop’s batch command to process a group of images to apply watermark.<br /><span style="font-weight: bold;"><br />Applicable versions</span>:<br />Photoshop CS (v8) and Photoshop v7<br /><span style="font-weight: bold;"><br />Prep work</span>:<br />I used transparent watermark for protecting IP rights yet showing off pictures. I would try to make all images looked consistent when viewed as a collection-the size, effect, position etc. For this reason, I will resize all images to a certain size (see <a href="http://jingyeluo.blogspot.com/2006/10/photoshop-action-and-batch-to-resize.html#links">Using Photoshop Actions and batch command to resize images</a> <span style="font-weight: bold;font-size:130%;" ></span>. Then group landscape and portrait photos in two source folder (i.e. source_landscape, source_portrait) 2) create two actions: e.g. ‘watermark Landscape’ ‘watermark portrait’.<br />Create an ‘output’ folder as well.<br /><br /><span style="font-weight: bold;">Task 1: Create an custom shape, which will be used as watermark later.</span><br />At this stage there is no need to tweak the shape yet for special effect yet, just create a new document with plain text/logo. For example a square logo can be of <span style="font-style: italic;">Width: 3 inches x Height: 3 inches, Resolution: 300 pixels per inch (ppi) and the Colour Mode: Greyscale, Contents: White</span>, Type the text with desired font and size it to fill all canvas.<br />(<span style="font-weight: bold;">important</span>) Go to the 'Layer' menu, highlight 'Type' and select 'Create Work Path'. This action converts the text to an outline vector path. To add the shape the library, choose 'Define Custom Shape' from the "Edit' menu and name the item 'watermark'. Click 'OK'.<br /><br /><span style="font-weight: bold;">Task 2: Create Watermark</span><br />1) Open a test image, ideally this should be in similar size to those will be in batch process later, pick an image that it is not too dark around watermark application area. Also consider an watermark for lanscape and portrait images each. Here I will only give lanscape images as example.<br />2) In the 'Preferences', check that the 'Units and Rulers' are set to 'Inches'. 'Units' set to 'Pixels' or 'Percent' create a watermark that changes size based on the files resolution and will prove unreliable.<br />3) Add a new layer(shift+ctrl+n), nae it 'watermark'.<br />3) From Toolbox, select <b></b>'Custom Shape Tool' (U), found under the 'Rectangle Tool'. Select 'watermark' shape from the listed icons.<br />4) Hold '<span style="font-weight: bold;">shift</span>' key and draw watermark on new layer to fill the entire width.<br />5) (Layer menu) <span style="font-weight: bold;">Rasterize</span>-><span style="font-weight: bold;">shape<br /></span>6) (Filter menu) <span style="font-weight: bold;">Stylize</span>-><span style="font-weight: bold;">Emboss,</span> angle 135<br />7) (Layer menu), '<span style="font-weight: bold;">Layer Style</span>' ->'<span style="font-weight: bold;">Blending Options</span>'. Set the layer blending mode to "Hard Light" to let the image show through<br />8) Sets up the file and its attributes. (File menu)->File Info (Alt+Ctrl+i). Key in the information you want attached to the file.<br /><span style="font-size:78%;">copyright info: Some rights reserve. Attribution-NoDerivs 2.0 UK: England & Wales <strong style="font-weight: normal;">You are free: </strong>to copy, distribute, display, and perform the work to make commercial use of the work(http://creativecommons.org/licenses/by-nd/2.0/uk/)<br /></span>9) Flatten the file.<br />Watermark is done.<br /><br /><span style="font-weight: bold;">Task 3: Record Task 2 as a custom action<br /><br /></span>Close all working files. Now we ready to create an watermark action. Most of the steps in this task is repeat from task 2.<br /><br />1) Open an new image to be worked on.<br />2) Create a new action. Click the “create new action” icon in the Actions panel.<br />3) Name this Action “watermark lanscape image”. As soon as you create a new Action, your<br />action starts recording.<br />4) Repeat task 2 all steps<br />5) stop recording<br />5) Save image use 'save as' from File menu. Remember(<span style="font-weight: bold;">very important</span>): DO NOT rename the file; and save it to the target output folder that batch process is output to. (the reason for this two points are explained here: <a href="http://jingyeluo.blogspot.com/2006/10/photoshop-action-and-batch-to-resize.html#links">Using Photoshop Actions and batch command to resize images</a>)<br />5) Stop recording.<br />6) Close working image,<br />7) Open the original image. Test& re-recording “watermark lanscape image” action to satifaction.<br /><br /><span style="font-weight: bold;">Task 4: Batch process all images</span><br />1) In Photoshop, go to FILE --> AUTOMATE --> BATCH.<br />In the Play section pull down "Action" and select "<span style="font-weight: bold;">watermark lanscape image</span>" action you created earlier.<br />3) The “Source” Section. Since we did not create an “Open” Command in our Action, we need to make sure the “Override Action “Open” Commands” is NOT checked. The “Suppress file Open Options Dialog” should be checked. And the “Suppress Color Profile Warnings” should be checked.<br />4) Click the “Choose” button and select the folder "<span style="font-weight: bold;">source_landscape</span>" you created in prep-work.<br />5) The “Destination” Section. The “Destination” should be set to “Folder”. Click on the “Choose” button and select the folder you created called “<span style="font-weight: bold;">output</span>”. Make sure the “Override Action “Save As” command” is checked. Otherwise batch will create two identical files for each image – one named after original name (this is what action records in ‘save for web’) and the other name after the following pattern.<br />6) In the “File Naming” Section. I prefer to prefix original image file name with something like ‘forWeb_’ just to differential it from original file. To do this Set the first box to ‘forWeb_’ second box to “Document Name” and the third box to “Extension”.<br />7) uncheck 'Override Action "Save as" commands'<br />8) Now, to process your images, just click “Ok”.<br />And that’s it. (repeat this for protrait images)Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6082242.post-82601990348882174712006-10-27T00:15:00.000+01:002006-10-27T17:43:25.303+01:00Photoshop Action and Batch to resize images<span style="font-weight: bold;font-size:78%;" >Jingye says: 'I am scratching my head on Photoshop tasks'. I am not a pro (digital) photographer. With busy life, </span><span style="font-weight: bold;font-size:78%;" > I just want to get some reasonable quality picture from my digital cameras</span><span style="font-weight: bold;font-size:85%;" ><span style="font-size:78%;">. I took many many photos during holidays (easliy over 5Gb for two weeks in a exotic country). I only have time to tidy them up a little bit, mostly an auto-leveling and an auto-curving. Then I will print some, upload a small size to <a href="http://www.flickr.com/photos/i-fotos">flickr</a>; archive a large version.<br /><br />Many ps tasks I have done in the pass were forgotten fast. So here I steal/rewrite from other people’s Photoshop tips/how to do something. I claim not rights of them unless stated. This is just my web notepad for myself and everyone else.’</span><br /></span><br /><span style="font-weight: bold;font-size:130%;" ><span style="font-family:verdana;">Using Photoshop Actions and batch command to resize images.</span></span><br /><br />Rewrite and proved based on tsion (<a href="http://www.sitepoint.com/forums/showthread.php?t=252128">http://www.sitepoint.com/forums/showthread.php?t=252128</a> Apr 10, 2005, 10:38’s tutorial)<br /><br /><span style="font-weight: bold;">Objective</span>: Create a custom action and use Photoshop’s batch command to process a group of images to a certain size.<br /><span style="font-weight: bold;">Applicable versions</span>: Photoshop CS (v8) and Photoshop v7<br /><span style="font-weight: bold;">Prep work</span>: Resize will based on a certain axis, i.e. width/height. To maintain a consistent size of a collection of photos, it is better to 1) group landscape and portrait photos in two source folder (i.e. source_landscape, source_portrait) 2) create two actions: e.g. ‘resize to width 800’ ‘resize to height 800’.<br />Create an ‘output’ folder as well.<br /><br />In the following walk though we will do ‘resize to width 800’ only, same principle apples to ‘resize to height 800’.<br /><br />1) Copy all landscape images you want to resize to the “source_landscape” folder.<br />When you copy your images, I recommend you copy them all to the root directory in the “original” folder, don’t use any subfolders. This you’ll ensure that you have no duplicate images, or images with the same filename.<br /><br />Now we record custom automation action.<br /><br />2) In Photoshop, open an arbitrary image.<br />3) Now, create a new action set. To do this, we click on the folder icon in the Actions panel. Let’s name this set “Custom”. I like to keep my custom actions in their own set, so I can find them easier later on.<br />4) Next create a new action. Click the “create new action” icon in the Actions panel.<br />5) Name this Action “resize to width 800” As soon as you create a new Action, your action starts recording.<br />6) To resize the image: Go to IMAGE --> RESIZE IMAGE. This will open the “Image Size” dialog box. Now let’s change the width of our image to 800 pixels wide. Then click “OK”.<br />7) Now immediately after you click “OK”. Go to FILE --> SAVE FOR WEB. Set your jpg parameters how you normally would and click save.<br />Due to a bug in cs, there are two things described here must be follow:<br />7.1 Make sure you save this file in the “output” folder that we created in prep work.<br />7.2 DO NOT rename the file, just save it as it is. Otherwise you will get ‘Replace Files’ message window in batch process later for each image. (more below)<br /><br />8) Click the “Stop recording” icon in the Actions panel. Our new Action is complete, and ready to use.<br />Now we are ready to process our images.<br /><br />9) Go to “output” folder and delete the image you saved there when you created your action. This is just so it doesn’t get mixed in with the images you’re processing.<br /><br />10) In Photoshop, go to FILE --> AUTOMATE --> BATCH.<br /><br />11) The “Play” section. Change your set to “Custom”. And your Action to ““resize to width 800” this sets the Action you created earlier.<br /><br />12) The “Source” Section. Since we did not create an “Open” Command in our Action, we need to make sure the “Override Action “Open” Commands” is NOT checked. The “Include Subfolders” option doesn’t matter. The “Suppress file Open Options Dialog” should be checked. And the “Suppress Color Profile Warnings” should be checked.<br /><br />13) Click the “Choose” button and select the folder "<span style="font-weight: bold;">source_landscape</span>" you created in prep-work.<br /><br />14) The “Destination” Section. The “Destination” should be set to “Folder”. Click on the “Choose” button and select the folder you created called “<span style="font-weight: bold;">output</span>”. Make sure the “Override Action “Save As” command” is checked. Otherwise batch will create two identical files for each image – one named after original name (this is what action records in ‘save for web’) and the other name after the following pattern.<br /><br />15) In the “File Naming” Section. I prefer to prefix original image file name with something like ‘forWeb_’ just to differential it from original file. To do this Set the first box to ‘forWeb_’ second box to “Document Name” and the third box to “Extension”.<br /><br />Now, to process your images, just click “Ok”.<br />And that’s it.<br /><br />Question 1: When I run the batch command, PCS brings up the replace image dialogue asking me is I want to replace the previously saved image, which obviously I don't.<br />What am I missing?<br /><br />Answer: First, the output folder in ‘resize to width 800’ action must be identical to what it is set in batch process output folder.<br />Second, Do not rename the file in recording the action, this seemed like confused the batch process.<br /><br />Question 2: 'm trying to batch process ..alot of images...but everytime i run the batch, the picture quality appears after each image, asking me to save at what size. This is alot to go thorugh when i have thousands of pics, is there a way around this? So far from what i've seen, the answer is no.<br /><br />Answer: use ‘Save for web’, not ‘save as’Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6082242.post-22170174860482492442006-10-23T16:11:00.000+01:002006-10-24T08:48:11.749+01:00Strong Typing vs. Strong Testing[Blog on Blog]<br /><br /><span style=";font-family:Verdana;color:black;" >... without a full set of unit tests (at the very least), you can't guarantee the correctness of a program. To claim that the strong, static type checking constraints in C++, Java, or C# will prevent you from writing broken programs is clearly an illusion (you know this from personal experience). In fact, what we need is <o:p></o:p></span> <p class="MsoNormal"><b><span style=";font-family:Verdana;color:black;" >Strong testing, not strong typing. </span></b><span style=";font-family:Verdana;color:black;" ><o:p></o:p></span></p> points to note:<br /><br /><ol style="margin-top: 0cm;" start="1" type="1"><li class="MsoNormal" style="">A very concise code sample comparing strong type and weak type language, where weak type loose the semantic on checking variable type – it works as long as it implements the method expected.</li><li class="MsoNormal" style="">unit test is an extension to complier</li></ol>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6082242.post-86514112556261105132006-10-03T11:23:00.000+01:002006-10-03T11:29:43.003+01:00mono XslTransform vs .net XslTransform observationAlthough by and large mono is the reincarnation of .net for the poor, there are subtle differences between them. Here is what I found on Xsl Transformation. Mono XML interprets xsl:last() function in a significant different way to native .net. XML.<br /><div id="mb_0"><br />Using the same xml style sheet with a few debug trace: p – xsl:position(); l – xsl:last; c-xsl:count()<br />Mono rendering:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/3778/742/1600/xslt_lastFunc_mono.gif"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger2/3778/742/400/xslt_lastFunc_mono.png" alt="" border="0" /></a><br />Native .Net rendering:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/3778/742/1600/xslt_lastFunc_net.gif"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger2/3778/742/400/xslt_lastFunc_net.png" alt="" border="0" /></a><br />And the source code:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/3778/742/1600/xslt_lastFunc_source.gif"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger2/3778/742/400/xslt_lastFunc_source.gif" alt="" border="0" /></a>We also found the insignificant whitespaces in the two versions are placed differently.<br /><br />We are able to spot these difference in a consistent, repeatable and fully automated way by writing <a onclick="return top.js.OpenExtLink(window,event,this)" href="http://jingyeluo.blogspot.com/2006/08/tdd-web-controls-dev-life-cycle.html" target="_blank">Ruby+Watier</a> scripts before writing any code. The test script fully emulates an IE browser object. It instantiates an browser window and issues http request. We can then either assert the html source character by character or more semantically and interactively, do things like @ie(:id, "myLink").click<br /></div>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6082242.post-83504688820918907422006-09-15T08:45:00.000+01:002006-09-15T08:47:57.553+01:00update/delete/insert nodes to an xml document<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger2/3778/742/1600/sample.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger2/3778/742/400/sample.jpg" alt="" border="0" /></a><br /><div>Load an xml document to memory. Nevigate the DOM object, using xpath to query nodes. To update the node: create an new one, and replace the existing one.</div> <div>Default namespace in xml doc still needs to declare in namespace mamager- and use in the xpath query. Although it is not present in the xml data:</div> <div> </div> <div>Sample Data<br /><br /></div> <div> </div> <div>C# Code to do this:<br /><span style="font-size:85%;"><span style="font-family: courier new;"> private void SetTestData(int index, int itemsPerPage, int totalResults)</span><br /><span style="font-family: courier new;"> {</span><br /><span style="font-family: courier new;"> XmlTextReader reader = new XmlTextReader("..\\TestData_V1.xml");</span><br /><span style="font-family: courier new;"> XmlDocument doc = new XmlDocument(); </span><br /><span style="font-family: courier new;"> doc.Load(reader);</span><br /><span style="font-family: courier new;"> reader.Close();</span><br /><br /><span style="font-family: courier new;"> string osUri = "http://a9.com/-/spec/opensearch/1.1/";</span><br /><br /><span style="font-family: courier new;"> XmlNamespaceManager nsMgr = new XmlNamespaceManager(doc.NameTable);</span><br /><span style="font-family: courier new;"> nsMgr.AddNamespace("os", osUri);</span><br /><span style="font-family: courier new;"> nsMgr.AddNamespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");</span><br /><span style="font-family: courier new;"> nsMgr.AddNamespace("dc", "http://purl.org/dc/elements/1.1/");</span><br /><span style="font-family: courier new;"> nsMgr.AddNamespace("rss", "http://purl.org/rss/1.0/");</span><br /><br /><span style="font-family: courier new;"> XmlNode oStartIndex, oItermsPerPage, oTotalResults;</span><br /><span style="font-family: courier new;"> XmlElement root = doc.DocumentElement;</span><br /><br /><span style="font-family: courier new;"> oStartIndex = root.SelectSingleNode("/rdf:RDF/rss:channel/os:totalResults", nsMgr);</span><br /><span style="font-family: courier new;"> oItermsPerPage = root.SelectSingleNode("/rdf:RDF/rss:channel/os:itemsPerPage", nsMgr);</span><br /><span style="font-family: courier new;"> oTotalResults = root.SelectSingleNode("/rdf:RDF/rss:channel/os:startIndex", nsMgr);</span><br /><br /><span style="font-family: courier new;"> XmlElement nStartIndex = doc.CreateElement("os", "startIndex", osUri);</span><br /><span style="font-family: courier new;"> XmlElement nItermsPerPage = doc.CreateElement("os", "itemsPerPage", osUri);</span><br /><span style="font-family: courier new;"> XmlElement nTotalResults = doc.CreateElement("os", "totalResults", osUri);</span><br /><br /><span style="font-family: courier new;"> nStartIndex.InnerXml = index.ToString();</span><br /><span style="font-family: courier new;"> nItermsPerPage.InnerXml = itemsPerPage.ToString();</span><br /><span style="font-family: courier new;"> nTotalResults.InnerXml = totalResults.ToString();</span><br /><br /><span style="font-family: courier new;"> root.SelectSingleNode("/rdf:RDF/rss:channel", nsMgr).ReplaceChild(nStartIndex, oStartIndex);</span><br /><span style="font-family: courier new;"> root.SelectSingleNode("/rdf:RDF/rss:channel", nsMgr).ReplaceChild(nItermsPerPage, oItermsPerPage);</span><br /><span style="font-family: courier new;"> root.SelectSingleNode("/rdf:RDF/rss:channel", nsMgr).ReplaceChild(nTotalResults, oTotalResults);</span><br /><br /><span style="font-family: courier new;"> doc.Save("..\\tempTestData.xml");</span><br /><span style="font-family: courier new;"> }</span></span><br /></div>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6082242.post-18578862589386730602006-09-02T11:16:00.000+01:002006-09-02T11:17:03.941+01:00The ASP.NET Page Object Model<p>Revisit and take away from Dino Esposito's classic article <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/aspnet-pageobjectmodel.asp">The ASP.NET Page Object Model</a></p><p style="font-weight: bold;">Code Behind</p><p><span style="font-style: italic;">The code of a page is <span style="font-weight: bold;">the set of event handlers and helper methods</span> that actually create the behavior of the page. This code can be defined inline using the </span><span style="font-style: italic;"> tag or placed in an external class—the code-behind class.</span></p><ol><li>Think it this way make it easier to break away sequnential mentally on reading/writing code.</li><li>Code behind is totally optional.<br /></li><ol><li>You can have 'orphan' aspx page derived from web.UI.Page directly. In situations, say that you are testing good and feel of a web control</li><li>You can have all aspx derived from a common code-behind class<br /></li></ol></ol><p><span style="font-weight: bold;">AutoEventWireup</span></p><p>VSNET IDE wizard generates boiler-plate aspx contains @page like this</p><p style="font-family:courier new;"><span style="font-size:85%;"><%@ Page language="c#" Codebehind="MyPage.aspx.cs" AutoEventWireup="false" Inherits="MyNameSpace.MyPage" %></span></p><p>For backward compatibility with the earlier VB programming style, ASP.NET also supports a form of implicit event hooking. By default, the page tries to match special method names with events; if a match is found, the method is considered a handler for the event. ASP.NET provides special recognition of six method names. They are <b>Page_Init</b> <b>Page_Load</b>, <b>Page_DataBind</b>, <b>Page_PreRender</b>, and <b>Page_Unload</b>. These methods are treated as handlers for the corresponding events exposed by the <b>Page</b> class. The HTTP run time will automatically bind these methods to page events saving developers from having to write the necessary glue code. For example, the method named <b>Page_Load</b> is wired to the page's <b>Load</b> event as if the following code was written.</p> <pre class="code">this.Load += new EventHandler(this.Page_Load);<br /></pre> <p>The automatic recognition of special names is a behavior under the control of the <b>AutoEventWireup</b> attribute of the <b>@Page</b> directive. If the attribute is set to false, any applications that wish to handle an event need to connect explicitly to the page event. Pages that don't use automatic event wire-up will get a slight performance boost by not having to do the extra work of matching names and events. Although VSNET creates aspx with the <b>AutoEventWireup</b> attribute disabled, the default setting for the attribute is <span style="font-weight: bold;">true</span>, meaning that methods such as <b>Page_Load </b>are recognized and bound to the associated event.<br /></p><p>You should always explicitly register an appropriate handler instead of relying on AutoEventWireup.</p><p>Another interesting experitment. set AutoEventWireup="true" and also keep the following line in the InitializeComponent of code-behind. Put a Response.Write to it. It is called twice!</p><p><span style="font-size:85%;"><span style="font-family:courier new;"> this.Load += new System.EventHandler(this.Page_Load);</span></span><br /></p><span style="font-weight: bold;">The Page Lifecycle<br /><br /></span><table class="data"><tbody><tr valign="top"><th class="data" align="left" width="34%">Stage</th> <th class="data" align="left" width="18%">Page Event</th> <th class="data" align="left" width="48%">Overridable method</th> </tr> <tr valign="top"> <td class="data" width="34%"><ul><li><span style="font-size:85%;">Page initialization</span></li></ul></td> <td class="data" width="18%"><span style="font-size:85%;"><b>Init<br /><br /></b></span></td> <td class="data" width="48%"><span style="font-size:85%;"><br /></span></td> </tr> <tr valign="top"> <td class="data" width="34%"><ul><li><span style="font-size:85%;">View state loading</span></li></ul></td> <td class="data" width="18%"><span style="font-size:85%;"><br /></span></td> <td class="data" width="48%"><span style="font-size:85%;"><b>LoadViewState</b> Restores view-state information from a previous page request that was saved by the SaveViewState method<br /><br /></span></td> </tr> <tr valign="top"> <td class="data" width="34%"><ul><li><span style="font-size:85%;">Postback data processing</span></li></ul></td> <td class="data" width="18%"><span style="font-size:85%;">(implicitly by Page base class -ProcessPostData (private))<br /></span></td> <td class="data" width="48%"><span style="font-size:85%;">Call to <b>LoadPostData</b> methods in the controls tree that implements the <b>System.Web.UI.IPostBackDataHandler</b><br /><br /></span> interface (e.g. TextBox)</td> </tr> <tr valign="top"> <td class="data" width="34%"><ul><li><span style="font-size:85%;">Page loading</span></li></ul></td> <td class="data" width="18%"><span style="font-size:85%;"><b>Load</b></span></td> <td class="data" width="48%"><span style="font-size:85%;"><br /><br /></span></td> </tr> <tr valign="top"> <td class="data" width="34%"><ul><li><span style="font-size:85%;">Postback change notification</span></li></ul></td> <td class="data" width="18%"><span style="font-size:85%;"><br /></span></td> <td class="data" width="48%"><span style="font-size:85%;"><b>RaisePostDataChangedEvent</b> method in any control that implements the <b>IPostBackDataHandler</b> interface<br /><br /></span></td> </tr> <tr valign="top"> <td class="data" width="34%"><ul><li><span style="font-size:85%;">Postback event handling</span></li></ul></td> <td class="data" width="18%"><span style="font-size:85%;">Any postback event defined by controls</span></td> <td class="data" width="48%"><span style="font-size:85%;"><b>RaisePostBackEvent</b> method in any control that implements the <b>IPostBackEventHandler</b> interface<br /><br /></span> </td> </tr> <tr valign="top"> <td class="data" width="34%"><ul><li><span style="font-size:85%;">Page pre-rendering phase</span></li></ul></td> <td class="data" width="18%"><span style="font-size:85%;"><b>PreRender</b></span></td> <td class="data" width="48%"><span style="font-size:85%;"><br /><br /><br /></span></td> </tr> <tr valign="top"> <td class="data" width="34%"><ul><li><span style="font-size:85%;">View state saving</span></li></ul></td> <td class="data" width="18%"><span style="font-size:85%;"><br /></span></td> <td class="data" width="48%"><span style="font-size:85%;"><b>SaveViewState<br /><br /></b></span></td> </tr> <tr valign="top"> <td class="data" width="34%"><ul><li><span style="font-size:85%;">Page rendering</span></li></ul></td> <td class="data" width="18%"><span style="font-size:85%;"><br /></span></td> <td class="data" width="48%"><span style="font-size:85%;"><b>Render<br /><br /></b></span></td> </tr> <tr valign="top"> <td class="data" width="34%"><ul><li><span style="font-size:85%;">Page unloading</span></li></ul></td> <td class="data" width="18%"><span style="font-size:85%;"><b>Unload</b></span></td> <td class="data" width="48%"><br /></td></tr></tbody></table><p>The ProcessPostData is a private method implemeted at Page class which contains code like this:</p><p><span style="font-size:85%;"><span style="font-family:courier new;">IPostBackDataHandler handler1 = (IPostBackDataHandler) control1;</span><br /><span style="font-family:courier new;">if (handler1.LoadPostData(text1, this._requestValueCollection))</span><br /><span style="font-family:courier new;">{</span><br /><span style="font-family:courier new;"> this._changedPostDataConsumers.Add(handler1);</span><br /><span style="font-family:courier new;">}</span><br /><span style="font-family:courier new;">if (this._controlsRequiringPostBack != null)</span><br /><span style="font-family:courier new;">{</span><br /><span style="font-family:courier new;"> this._controlsRequiringPostBack.Remove(text1);</span><br /><span style="font-family:courier new;">}</span><br /></span><br />A simple page to demo this cycle: <a href="http://beta.blogger.com/comingup.nemonova.com/PageLifeCycle.zip">PageLifeCycle.zip</a> (contains PageLifeCycle.cs and .aspx, unzip and add them to a web proj. to see it in action)<br /></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6082242.post-13732722995223288132006-08-31T21:26:00.000+01:002006-08-31T21:32:44.742+01:00TDD web controls dev life cycle<span style="font-style: italic;">An entire upside down experience to help coder focus on deliver 'good enough' requirements</span><br /><br />In <span style="font-weight: bold;">summary</span> this dev pattern is<br /><br />1. decide deliverables - the rendered html as browser user sees. (step 1, 2)<br />2. write ruby script to test the html (in fact it is reversed test the test script) (step 3)<br />3. act as web designer to use the web control to build a test page (of course, the web control is not existed yet) (step 4)<br />4. Implment web control (step 5)<br />5. test the web control (step 6-7)<br />6. change loop<br /><br />A well designed website should be broken into three domains:<br />1) Reusable Web controls which render plain html<br />2) bare bone website composed of web controls. Pages are served as control containers and responsible for managing navigation, user experience. It should contains no inline css but class/id/name that allows UI designer change the 'skin' without touching the website, not even a downtime.<br />3) CSS<br /><br />Here is the <span style="font-weight: bold;">Test Driven Development Cycle</span><br />1. Agree with UI designer on html template. the static html prototype is the 'contract'.<br /><br />2. break down the template into componentised controls that will be generated with user/custom controls. Save the html corresponding to the control to a new html e.g. ~\gallery\searchbox.html<br /><span style="font-size:85%;"><span style="font-family:courier new;"><html></span><br /><span style="font-family:courier new;"> <body></span><br /><span style="font-family:courier new;"> <!--search box--></span><br /><span style="font-family:courier new;"> <div id="PARENTDIV" name="PARENTDIV" class="TestGlobalStyleClass"></span><br /><span style="font-family:courier new;"> <label id="PARENTDIV.MessageLabel" name="PARENTDIV.MessageLabel">TestMessageLabelText</label><br></span><br /><span style="font-family:courier new;"> <input type="text" id="PARENTDIV.SearchTerm" name="PARENTDIV.SearchTerm" class="SearchTermClass" size="100" maxlength="100"></span><br /><span style="font-family:courier new;"> <a href="http://test.webcontrols.com" id="PARENTDIV.AdvLink" name="PARENTDIV.AdvLink"</span><br /><span style="font-family:courier new;"> title="Test ToolTip" class="AdvLinkClass">Test Link Text</a> </span><br /><span style="font-family:courier new;"> <!--search box close--></div></span><br /><span style="font-family:courier new;"> </body></span><br /><span style="font-family:courier new;"></html></span><br /></span><br />3. Write an Ruby script 'SearchBoxTestFixture.rb' to test this template. This is to validate our test case is sounds.<br /><br /><span style="font-size:85%;"><span style="font-family:courier new;">require 'watir'</span><br /><span style="font-family:courier new;">require 'test/unit'</span><br /><span style="font-family:courier new;">require 'test/unit/assertions'</span><br /><span style="font-family:courier new;">include Watir</span><br /><br /><span style="font-family:courier new;">class SearchBoxTestFixture <><br /><span style="font-family:courier new;"> def setup</span><br /><span style="font-family:courier new;"> localHostXSP = "http://127.0.0.1"</span><br /><span style="font-family:courier new;"> localHostIIS = "http://localhost/Talis.Web.Cenote.WebControls.Test" </span><br /><span style="font-family:courier new;"> @staticTemplate = 'http://localhost/Talis.Web.Cenote.WebControls.Test/static/searchbox.html'</span><br /><span style="font-family:courier new;"> remoteHost = "http://talis.com";</span><br /><span style="font-family:courier new;"> @testSite = localHostIIS</span><br /><span style="font-family:courier new;"> @ie = IE.new</span><br /><span style="font-family:courier new;"> end</span><br /><span style="font-family:courier new;"> </span><br /><span style="font-family:courier new;"> def teardown</span><br /><span style="font-family:courier new;"> @ie.close</span><br /><span style="font-family:courier new;"> end</span><br /><span style="font-family:courier new;"> </span><br /><span style="font-family:courier new;"> def test_allHtmlElementsExist</span><br /><span style="font-family:courier new;"> # page = "SearchBoxTest.aspx"</span><br /><span style="font-family:courier new;"> # @ie.goto(@testSite+'/'+page)</span><br /><span style="font-family:courier new;"> </span><br /><span style="font-family:courier new;"> # test static html template</span><br /><span style="font-family:courier new;"> @ie.goto(@staticTemplate)</span><br /><span style="font-family:courier new;"> </span><br /><span style="font-family:courier new;"> assert_equal(1, @ie.divs.length, 'Expecting only one div')</span><br /><span style="font-family:courier new;"> assert(@ie.div(:id, /PARENTDIV/).exists?, "Expecting div id 'PARENTDIV'")</span><br /><span style="font-family:courier new;"> assert(@ie.div(:name, /PARENTDIV/).exists?, "Expecting div name 'PARENTDIV'")</span><br /><span style="font-family:courier new;"> </span><br /><span style="font-family:courier new;"> #assert message label</span><br /><span style="font-family:courier new;"> assert_equal(1, @ie.labels.length, 'Expecting only one lable box')</span><br /><span style="font-family:courier new;"> assert(@ie.label(:id, /PARENTDIV.MessageLabel/).exists?, "Expecting label id 'PARENTDIV.MessageLabel'")</span><br /><span style="font-family:courier new;"> assert(@ie.label(:name, /PARENTDIV.MessageLabel/).exists?, "Expecting label name 'PARENTDIV.MessageLabel'" )</span><br /><span style="font-family:courier new;"> assert('TestMessageLabelText', @ie.label(:id, "PARENTDIV.MessageLabel").innerText)</span><br /><span style="font-family:courier new;"> </span><br /><span style="font-family:courier new;"> #assert input box</span><br /><span style="font-family:courier new;"> assert_equal(1, @ie.text_fields.length, 'Expecting only one input box')</span><br /><span style="font-family:courier new;"> assert(@ie.div(:id, /PARENTDIV/).text_field(:id, 'PARENTDIV.SearchTerm').enabled?, "Expecting textbox id 'PARENTDIV.SearchTerm'" )</span><br /><span style="font-family:courier new;"> assert(@ie.text_field(:name, 'PARENTDIV.SearchTerm').exists?, "Expecting textbox name'PARENTDIV.SearchTerm' textbox element")</span><br /><span style="font-family:courier new;"> assert_equal(100, @ie.text_field(:id, 'PARENTDIV.SearchTerm').size(), "Expecting textbox size 100")</span><br /><span style="font-family:courier new;"> assert_equal(100, @ie.text_field(:id, 'PARENTDIV.SearchTerm').maxLength(), "Expecting textbox maxLength 100")</span><br /><span style="font-family:courier new;"> </span><br /><span style="font-family:courier new;"> #assert link</span><br /><span style="font-family:courier new;"> assert_equal(1, @ie.links.length, 'Expecting only one link')</span><br /><span style="font-family:courier new;"> assert(@ie.link(:id, 'PARENTDIV.AdvLink').exists?, "Expecting link id 'PARENTDIV.AdvLink'" )</span><br /><span style="font-family:courier new;"> assert(@ie.link(:name, /PARENTDIV.AdvLink/).exists?, "Expecting link name 'PARENTDIV.AdvLink'" )</span><br /><span style="font-family:courier new;"> assert_equal('http://test.webcontrols.com/', @ie.link(:name, /PARENTDIV.AdvLink/).href, "Expecting link url 'http://test.webcontrols.com'" )</span><br /><span style="font-family:courier new;"> assert(@ie.link(:title, 'Test ToolTip').exists?, "Expecting link title (tool tip) 'Test ToolTip'" )</span><br /><span style="font-family:courier new;"> assert_equal('Test Link Text', @ie.link(:id, 'PARENTDIV.AdvLink').innerText, "Expecting link text 'Test Link Text'" )</span><br /><br /><span style="font-family:courier new;"> end</span><br /><span style="font-family:courier new;">end</span><br /><br /></span>4. write SearchBoxTest.aspx that intend to render as to searchbox.html. Ours contains this:<br /><span style="font-size:85%;"><span style="font-family:courier new;"> <My:SearchBox </span><br /><span style="font-family:courier new;"> ID="PARENTDIV"</span><br /><span style="font-family:courier new;"> Class="TestGlobalStyleClass"</span><br /><span style="font-family:courier new;"> MessageLabel_Text="TestMessageLabelText"</span><br /><span style="font-family:courier new;"> MessageLabel_Class="TestMessageLabelClass"</span><br /><span style="font-family:courier new;"> SearchTerm_Class="SearchTermClass"</span><br /><span style="font-family:courier new;"> SearchTerm_Size="100"</span><br /><span style="font-family:courier new;"> AdvLink_Class="AdvLinkClass"</span><br /><span style="font-family:courier new;"> AdvLink_Tooltip="Test ToolTip"</span><br /><span style="font-family:courier new;"> AdvLink_InnerText="Test Link Text"</span><br /><span style="font-family:courier new;"> Runat="server"</span><br /><span style="font-family:courier new;"> /></span><br /></span><br />5. Implement the custom web control: SearchBox.cs<br /><br />6. If haven't done so, write nUnit Testfixture to hook* ruby script into your test dll. So all tests will feedback as red/green light<br /><br />7. Modify SearchBoxTestFixture.rb to target SearchBoxTest.rb.<br /><br />Contract changed, start from 1. again<br /><br /><span style="font-weight: bold;">Notes:</span><br />1. You need to install<span style="font-size:85%;"><span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;"> </span></span><span style="font-size:85%;"><a href="http://rubyforge.org/projects/rubyinstaller/">Ruby</a></span> <span style="font-size:85%;"><span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;"> </span></span><span style="font-size:85%;"><a href="http://rubyforge.org/frs/?group_id=104">WATIR</a> </span><br />2. Travis <span style="font-size:85%;">Illig has this fatastic</span> RubyTestExecutor integrates ruby and watir test scripts into nUnit test framework. Check his paper <span style="font-size:85%;"></span><a href="http://www.codeproject.com/cpnet/RubyTestExecutor.asp">Integrated ASP.NET Web Application Testing with NUnit, Ruby, and Watir</a> on code project.</span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6082242.post-1156978775995954082006-08-30T23:59:00.000+01:002006-08-31T00:06:17.440+01:00Mono is not an adaptive asp.net web rendering engine<div>Scott Mitchell writes in <a href="http://aspnet.4guysfromrolla.com/articles/050504-1.aspx">ASP.NET.4GuysFromRolla.com: A Look at ASP.NET's Adaptive Rendering</a>: IIS <a href="http://asp.net/">ASP.NET</a> renders web controls by first detect the user-agnet type, for this reason, <a href="http://asp.net/">ASP.NET</a> Web controls are called <strong>adaptive</strong>. By default it renders HTML 3.2-compliant markup using <span style="font-family:Courier New;"><strong>tagwriter=System.Web.UI.Html32TextWriter.</strong> </span><span style="font-family:Arial;">For<br />HTML 4.0-compliant agents (Mozilla/4.0 and above, e.g. MSIE6) it uses </span><span style="font-family:courier new,monospace;"><strong>tagwriter=System.Web.UI.HtmlTextWriter. </strong></span>IIS does so by having a regex check for browser User-Agent. However, the default implementation doesn't address FireFox 0.8 and above, which is Mozilla/5.0 and HTML 4.0-compliant.</div> <div> </div> <div>Here we will check the adaptive rendering issue around Mono1.x ASPNET instead of IIS.</div> <div> <p>Default behaviour<br />1. Test rendering by Mono XSP web server.<br />On MSIE 6.0: <span style="font-family:courier new,monospace;">tagwriter=System.Web.UI.<strong>HtmlTextWriter</strong></span><br />evidence: System.Web.UI.WebControls.WebControl is rendered as <div><br />On FireFox 1.5: <span style="font-family:courier new,monospace;">tagwriter=System.Web.UI.<strong>HtmlTextWriter</strong><br /></span> evidence: System.Web.UI.WebControls.WebControl is rendered as <table ><br />Mono1.1 doesn't address adaptive Rendering - there is no <browserCaps> in its machine.config</p> <p>2. Test rendering by IIS6<br />On MSIE 6.0: <span style="font-family:courier new,monospace;">tagwriter=System.Web.UI.<strong>HtmlTextWriter</strong></span><br />evidence: System.Web.UI.WebControls.WebControl is rendered as <div><br />On FireFox 1.5: <span style="font-family:courier new,monospace;">tagwriter=System.Web.UI.<strong>Html32TextWriter</strong></span><br />evidence: System.Web.UI.WebControls.WebControl is rendered as <table ><tr><td></p> <p>It seemed that Mono team get around the problem luckily because it was born at a time HTML 4.0-compliant browsers prevails. (At least it was what they thought?). But maybe we can still add <browserCaps> for backward adaptive? At least it looks straightforward enough to add Add <browserCaps> to web.config to enable mono becomes aptive.<br />Not quite though.<br />Checking native .net1.x machine.config, in <configuration><configSections> there is:<br /><span style="font-family:courier new,monospace;"><span style="background-color: rgb(204, 204, 204);"> <section name="browserCaps" type="System.Web.Configuration.HttpCapabilitiesSectionHandler, System.Web, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/></span><br /></span>HttpCapabilitiesSectionHandler handles <browserCaps>. However, mono1.x build System.Web does NOT contain type HttpCapabilitiesSectionHandler implementation.</p> <p>Conclusion: Mono1.X is not an adaptive ASPNET rendering engine.</p> <p>Ideally we could add this to Web.config (affect single web app) or machine.config (affect all web apps on the machine)</p> <p><configuration><br />...<br /><configSections><br />...<br /><sectionGroup name="system.web"><br /> <section name="browserCaps" type="System.Web.Configuration.HttpCapabilitiesSectionHandler , System.Web, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/><br />...<br /></sectionGroup><br /></configSections><br /><System.Web><br />...<br /><browserCaps><br /><!-- if (working on web.config) { copy all <browserCaps> section from machine.config} --><br /><!-- copy Rob Eberhardt's <browserCaps> (<a href="http://slingfive.com/pages/code/browserCaps/browserCaps_spaces.txt">http://slingfive.com/pages/code/browserCaps/browserCaps_spaces.txt </a>) --><br /></browserCaps><br />...<br /></System.Web></p><p>Technorati Tags: <a href="http://technorati.com/tag/MONO+ASPNET" rel="MONO ASPNET">MONO ASPNET</a></p></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6082242.post-1156668101981228542006-08-27T09:41:00.000+01:002006-08-31T00:09:34.436+01:00Intellisense Nant Build Script on VSNET<p><span style="font-family:verdana;">From <a onclick="return top.js.OpenExtLink(window,event,this)" href="http://weblogs.asp.net/soever/archive/2005/02/01/364883.aspx" target="_blank">Serge van den Oever</a></span> <span style="font-family:verdana;"><br />1. Edit and save following build script to NAntGenerateSchema.build. This<br />script is used to generate the nant.xsd for the Intellisense trick</span>. <span style="background-color: rgb(204, 204, 204);font-family:courier new,monospace;" ><br /><?xml version="1.0" encoding="utf-8" ?> <project<br />name="GenerateNAntSchemaForVS.NET" default="genschema"> <property<br />name="myVsNetRoot" value="C:\Program Files\Microsoft Visual Studio .NET 2003"<br />/> <property name="nantSchema"<br />value="${myVsnetRoot}\Common7\Packages\schemas\xml\NAnt.xsd"/> <target<br />name="genschema"> <nantschema output="${nantSchema}" target-ns=" <a onclick="return top.js.OpenExtLink(window,event,this)" href="http://nant.sf.net/schemas/nant.xsd" target="_blank">http://nant.sf.net/schemas/nant.xsd</a>"/><br /></target> </project></span></p>1) update property <span style="font-family:courier new,monospace;">myVsNetRoot</span> to <span style="font-family:verdana;">your VSNET install path.</span><br /><p><span style="font-family:verdana;">2) save this script as NAntGenerateSchema.build </span><br /></p>3) run "nant NAntGenerateSchema.build ' . This will download the latest nant schema from Source Forge to VSNET schema dir. Note: this script should be run when <span style="font-family:verdana;">refreshing nant releases.</span><br /><p><span style="font-family:verdana;">2. Suppose you are working on HelloWorld.sln with VSNET, create a HelloWorld.build, which is your nant build script. Open HelloWorld.build in the IDE ((RC) by open with - HTML/XML Editor (set to default unless you need encoding).</span><br /></p><p><span style="font-family:verdana;">3. Open the properties window for HelloWorld.build, Select "<a onclick="return top.js.OpenExtLink(window,event,this)" href="http://nant.sf.net/schemas/nant.xsd" target="_blank"> http://nant.sf.net/schemas/nant.xsd</a>" as TargetSchema.<br /><br />Job done.</span><br /></p><span style="font-size:85%;">Technorati Tags: <a href="http://technorati.com/tag/NANT+VSNET" rel="NANT VSNET">NANT VSNET</a></span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6082242.post-1156553412281420632006-08-26T01:50:00.000+01:002006-08-28T23:58:39.033+01:00nAnt build script to test mono web app with Ruby and Watir<p style="font-weight: bold;">Download the build script template: <a href="http://comingup.nemonova.com/myWebsite.build">myWebsite.build</a></p><strong>1. Prove nant task <csc>, <nunit2> works/doesn't work with mono<br /> build</strong><br /><ol><li> Prove test assembly is fine use vsnet (.net 1.1) build, reference *.net1.1*<br /> nunit.framework.dll , not the mono build.<br /> <ul><br /> <li>build asm<br /> </li><li>tested with nUnit2.2.0 GUI exe<br /> </li><li>tested with nUnit-2.2.0-mono console exe.</li></ul><br /> Both work as expected<br /></li><br /><li>nAnt build. nant target mono-1.0; reference lib (nunit.framework.dll) set to NUnit-2.2.0-mono<br /> <ul><br /> <li>test assembly with nUnit2.2.0 GUI exe. On loading asm it throws exception<br /> 'This assembly was not built with the NUNIT framework and contains no tests'<br /> cases' on the popout message window</li><li>test assembly with nUnit-2.2.0-mono<br /> console exe. This returns:<br /> <div style="font-family: courier new; background-color: rgb(204, 204, 204);">OS Version: Microsoft Windows NT 5.1.2600.0 .NET Version: 1.1.4322.2032 Tests run:<br /> 0, Failures: 0, Not run: 0, Time: 0 seconds Open the assembly by .net<br /> reflector, surprise, surpise there is nothing in the dll<br /></div></li></ul></li></ol><strong>2. Use mono mcs compiler</strong><br /><ol><li> compiles the source<br /> <div style="font-family: courier new; background-color: rgb(204, 204, 204);">mcs -r:system.dll -r:\sslocal\Cenote.root\dependencies\NUnit-<br /> 2.2.0-mono\bin\nunit.framework.dll -t:library SampleRubyTestFixture.cs</div><br /></li><li> test - test assembly with nUnit2.2.0 GUI exe. - test assembly with<br /> nUnit-2.2.0-mono console exe. - test assembly with nUnit2.2.8 GUI exe. All work<br /> as expected<br /></li><br /><li>Open the assembly by .net reflector, it confirms that our test case is in there This confirms that nUnit2.2.* GUI exe doesn't discriminate mono build, as long as nunit.framework.dll is the .net1.1 compliance version This also confirms that the problem is not with nant task <nUnit2>, regardless which nunit build version it points to.<br /></li></ol><strong>3. Questioning nant task <csc></strong><br />Before setting off to use task <exec> and mcs for the build, I have a few more go on task <csc>. Eventually it confirms that it was a bug in the <csc> task causes the problem.<br />nAnt doesn't support multiple filesets or its derived types like assemblyfileset etc, which means you cann't resuse reference assemblyfileset. For building multiple projects in a build that each project has an inter-set to others, each <csc> needs to have a full list of <reference><include> dlls. A bit of pain. Using <module> is a hack. Though it solves the resuse problem on the surface, if you poke the assembly with Reflector, you will find there are modules should really be references. this is NOT the right way to reference <assemblyfileset>.<br /><div style="font-family: courier new,monospace; background-color: rgb(204, 204, 204);"><csc> ... <references refid="sys.assemblies " /> <modules><br /><include name="${webcontrols.output.Mono}\${webcontrolsNamespace}.dll" /><br /><include name="${cenote.output.Mono}\${cenoteNamespace}.dll" /><br /></modules> </csc></div><br />By the way, if declare <fileset>and its derived types like<br /><assemblyfileset> at project level(doc root) it can take an id attribue<br />and can be referenced from everywhere.<br /><strong>4. <nunit2> and nUnit2.2.x GUI</strong><br />Leaving the bug in <csc> behind, I move into nant <target> unit<br />test with <nunit2>. nunit2 used nunit-version="<a href="http://2.2.8.0/"> 2.2.8.0</a>"<br />clr-version="2.0.50727.42" for the test. Passed. However, now the mono-target<br />assemble is not loaded with nUnit2.2.X GUI, not even nUnit-2.2.0-mono console<br />exe. An System.IO.FileNotFoundException is thrown, complaining test dll or its<br />dependencies dlls are not found. [to-do] I will look into it later. This is not<br />an issue for next step. (We only use nUnit gui for vsnet build)<br /><strong>5. Serve web test using ruby+watir</strong><br />prerequisite: install <a href="http://rubyforge.org/projects/rubyinstaller/">Ruby</a><br />engine and <a href="http://rubyforge.org/frs/?group_id=104">Watir</a> library<br />Watir offers a clean, well define, automated and scripting (in opposite to<br />recording) base Web app test. <a href="http://www.codeproject.com/cpnet/RubyTestExecutor.asp"><br />Travis</a> made a nice hook to integrate ruby script into nUnit test<br />framework. It is not absolutely necessary to integrate ruby script into nUnit.<br />*.rb script can run from cmd line. However, the integration leverage the<br />reporting function comes with nUnit.<br /><ol><li>compile RubyTestExecutor-1.1.3.0 to target nunit_2.2.0_mono<br /></li><li>Write a 'Hello World' test case as well as ruby script. In Nant task<br /> <csc>include them as embeded resource. <resources<br /> dynamicprefix="true"> <include name="...\*.rb" /> </resources><br /></li><li>VSNET .net1.1 build and nUnit GUI test<br /> <ul><br /> <li>in vsnet reference RubyTestExecutor-1.1.3.0_target_nunit_2.2.0<br /> </li><li>make sure the Web_Control_test_project is set to default web sharing. It<br /> contains test pages as well as test cases.<br /> </li><li>Postbuild action to copy test.dll and referenced dlls (except<br /> nUnit.framework.dll) from ~\bin\Debug to ~\bin<br /> </li><li>run tests</li></ul></li><br /><li>VSNET mono1.0 build and nAnt build (test with <nunit2>, on my pc it picks<br /> the lastest nunit2.2.8 engine)<br /> <ul><br /> <li>in nAnt build reference RubyTestExecutor-1.1.3.0_target_nunit_2.2.0_mono<br /> </li><li>compile, delpoy as usual<br /> </li><li>start XSP at Web_Control_test_project where pages live.<br /> </li><li>Both use port 80 for http request. This means we don't need to change ruby<br /> scripts for native 1.1 (which runs on IIS) or mono runtime (which runs XSP).<br /> Just need to stop/start IIS before XSP kicks start. (I argue it is more<br /> pragmatic then dynamic decide which port to use depends on runtime env)</li></ul></li></ol><strong>5 Conclusion</strong><br />With this build script, we archieve:<br /><ul><li> Implement, build and test ASP.Net Web Controls and Website in VSNET2003 IDE to<br /> target .Net 1.1 framework.<br /></li><li> Use nAnt build script to link, compile, deploy the same code base to target<br /> Mono1.0. This build process needs to know nothing about the IDE build.<br /></li><li> Use Ruby+Watir scripts to test web app in 'nearest' real way.The script test<br /> suite is seamlessly integrate into nUnit framework.</li></ul><strong>6 What's more can be done?</strong><br />Automated XSP web server start/stop. The build process requires manually start<br />mono XSP web server before <nunit2> tests. XSP must run in an isolated<br />AppDomain/process from where nAnt is running from, so use <exec> task is<br />not prossible. It is also not possible to use <a href="http://www.gotdotnet.com/team/clr/AppdomainFAQ.aspx"><br /><span class="pageTitle"><span id="ctl01_PageTitleLabel">Application Domain<br /> ExecuteAssembly</span></span></a> to create and load XSP into an<br />isolated AppDomain because on Windows OS XSP requires mono runtime environment,<br />which is unmanaged code. (Though XSP.exe is managed code.)<br /><p>Download the build script template: <a style="font-weight: bold;" href="http://comingup.nemonova.com/myWebsite.build">myWebsite.build</a><br /></p>Technorati Tags: <a href="http://technorati.com/tag/Nant" rel="nAnt">nAnt</a><br /><div><a href="http://technorati.com/tag/RUBY+WATIR" rel="RUBY"> RUBY WATIR</a> <a href="http://technorati.com/tag/MONO+ASPNET" rel="MONO ASPNET"><br /> MONO ASPNET</a><br /></div>Unknownnoreply@blogger.comtag:blogger.com,1999:blog-6082242.post-1156072790814632802006-08-20T12:19:00.000+01:002006-08-20T12:27:58.940+01:00TDD Mono asp.net web application on<div class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;">Note: (This is a dump as I play with the new tools on doing familiar TDD aka. Test Driven Development), <em>work in progress</em>.</span></div> <div class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><strong></strong> </span></div> <div class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><strong><br />The application: </strong>An <a href="http://asp.net/">asp.net</a> web application run on Linux Mono<br /><br /></span></div> <div class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"> </span></div> <div class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><strong>Requirement: Unit test web application UI.</strong></span></div> <p class="MsoNormal" style="margin: 0cm 0cm 0pt 36pt; text-indent: -18pt;font-family:verdana;"><span style="font-size:85%;">–<span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;"> </span></span><span style="font-size:85%;"><i style="">This is hard. </i>NUNIT is designed for API (exe, lib) test</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt 36pt; text-indent: -18pt;font-family:verdana;"><span style="font-size:85%;">–<span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;"> </span></span><span style="font-size:85%;">Unit test server controls</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt 36pt; text-indent: -18pt;font-family:verdana;"><span style="font-size:85%;">–<span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;"> </span></span><span style="font-size:85%;">Support Continuous integration </span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"> </span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><strong><br /></strong></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><strong>Tools for the trade:</strong></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt 36pt; text-indent: -18pt;font-family:verdana;"><span style="font-size:85%;">-<span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;"> </span></span><span style="font-size:85%;">VS.net IDE</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt 36pt; text-indent: -18pt;font-family:verdana;"><span style="font-size:85%;">-<span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;"> </span></span><span style="font-size:85%;"><a href="http://www.nunit.org/index.php?p=download">NUnit</a> (For this project we targeting <a href="http://asp.net/">asp.net</a> 1.1, so pick NUnit 2.2 from the list)</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt 36pt; text-indent: -18pt;font-family:verdana;"><span style="font-size:85%;">-<span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;"> </span></span><span style="font-size:85%;">Nant</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt 36pt; text-indent: -18pt;font-family:verdana;"><span style="font-size:85%;">-<span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;"> </span></span><span style="font-size:85%;"><a href="http://rubyforge.org/projects/rubyinstaller/">Ruby</a></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt 36pt; text-indent: -18pt;font-family:verdana;"><span style="font-size:85%;">-<span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;"> </span></span><span style="font-size:85%;"><a href="http://rubyforge.org/frs/?group_id=104">WATIR</a> (I use <a href="http://rubyforge.org/frs/download.php/5677/watir-1.4.1.exe"> watir-1.4.1.exe</a> as at the time of writing)</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt 36pt; text-indent: -18pt;font-family:verdana;"><span style="font-size:85%;">-<span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;"> </span></span><span style="font-size:85%;">Mono gtk,</span><span style="font-size:85%;"> </span><span style="font-size:85%;">XSP web server</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt 18pt;font-family:verdana;"><span style="font-size:85%;"> </span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><strong><br /></strong></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><strong>Internal Resource:</strong></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt 36pt; text-indent: -18pt;font-family:verdana;"><span style="font-size:85%;">-<span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;"> </span></span><span style="font-size:85%;">Ruby test code template for <a href="http://vs.net/">vs.net</a></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt 36pt; text-indent: -18pt;font-family:verdana;"><span style="font-size:85%;">-<span style="font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; font-size-adjust: none; font-stretch: normal;"> </span></span><span style="font-size:85%;">Water code template for <a href="http://vs.net/">vs.net</a></span><span style="font-size:85%;"> </span><span style="font-size:85%;">(because I am lazy)</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"> </span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><strong><br /></strong></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><strong>Reference:</strong></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><a href="http://secretgeek.net/watir_3mins.asp"><span style="color: rgb(128, 0, 128);">Babysteps in WATIR</span></a> A Jumpstart to Ruby/Watir </span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"> </span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><a href="http://www.codeproject.com/cpnet/RubyTestExecutor.asp">Integrated ASP.NET Web Application Testing with NUnit, Ruby, and Watir </a> </span><span style="font-size:85%;">Travis Illig creates a RubyTestExecutor to integrate Ruby/Watir Testscripts into nUnit framework. So test cases can be run from GUI like other nUnit test cases. However this is more of convenience that necessary. You still write Ruby/Watir scripts. You can still invoke them from command line. </span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"> </span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><a href="http://www.codeproject.com/cpnet/introtomono1.asp">Introduction to Mono - Your first Mono app</a> </span><span style="font-size:85%;"> </span><span style="font-size:85%;">Happened to find this Primer</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"> </span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><strong><br /></strong></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><strong>Development pattern:</strong></span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"><br /></span></p><p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;">Assumption: Coding in <a href="http://vs.net/">vs.net</a> 2003, OS: winXP</span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;"> </span></p> <p class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;">(One off task) Create web project</span></p> <ol style="margin-top: 0cm;font-family:verdana;" type="1"> <li class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size:85%;">create project directory: {root}\My.Hello.World</span></li> <li class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size:85%;">Web share this folder</span></li> <li class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size:85%;">create a new web project in <a href="http://vs.net/">vs.net</a>, map it to My.Hello.World</span> </li> <li class="MsoNormal" style="margin: 0cm 0cm 0pt;"><span style="font-size:85%;">Execute Mono run time test. Bring up command line console and do nAnt build.<br />a. Start Mono XSP web server<br />b. nAnt target doesn't natively require nUnit, although it could leverage point 1-3.<br />c. However, this is redundant. We can just load up Ruby and Watir script engines and call test scripts</span></li></ol><span style=";font-family:Times New Roman;font-size:85%;" > </span><span style=";font-family:Times New Roman;font-size:85%;" > </span> <div class="MsoNormal" style="margin: 0cm 0cm 0pt;font-family:verdana;"><span style="font-size:85%;">Technorati Tags: <a href="http://technorati.com/tag/TDD" rel="TDD">TDD</a> <a href="http://technorati.com/tag/RUBY+WATIR" rel="RUBY">RUBY WATIR</a> <a href="http://technorati.com/tag/NUNIT+ASPNET" rel="NUNIT ASPNET">NUNIT ASPNET </a></span></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6082242.post-1155656232045380572006-08-15T16:37:00.000+01:002006-08-15T16:37:14.173+01:00svn external steps<div>This quick note gives a step by stop guide to make svn external reference.</div> <div> </div> <div>svn external means that local copy is a references to repository rather than a working copy. So if later checking in would not check-in the local copy, but mark the reference only.</div> <div> </div> <div>1. {local path}mkdir dependencies. dependencies contains a collections of external denpendencise (references) we will import next.</div> <div>2. svn add dependencies {repository url}, and </div> <div>3. svn ci -m"..." dependencies. 2. 3. source controls 'dependencies'</div> <div>4. (use windows file browser), go to 'dependencies' |(right click)|Properties|Subverion tab| (requires Tortoise, the svn windows client) </div> <div>5. from the Subverion tab, select 'svn externals' from middle dropdown box, then in the text area below, type '3rdAPILib url_to_3rdAPILib' (no*'*, 3rdAPILib is the dir name you give to the external reference, url_to_3rdAPILib is its location in the repository) </div> <div>6. click 'set' button, then 'ok' it.</div> <div>7. right click 'dependencies'|'SVN Update'. This should get a copy of '3rdAPILib' to your {local path}\dependencies .</div> <div> </div> <div>Technorati Tags: <a href="<a href="http://technorati.com/tag/Subversion">http://technorati.com/tag/Subversion</a>" rel="tag">Subversion</a> <a href=" <a href="http://technorati.com/tag/SVN"> http://technorati.com/tag/SVN</a>" rel="tag">SVN</a></div>Unknownnoreply@blogger.com0