<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;C0UMRXs-cSp7ImA9WxNWF04.&quot;"><id>tag:blogger.com,1999:blog-36201586</id><updated>2009-10-16T23:14:44.559+01:00</updated><title>Derek says:</title><subtitle type="html">Real-world technobabble</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://derek-says.blogspot.com/" /><link rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>54</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><link rel="self" href="http://feeds.feedburner.com/DerekSays" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry gd:etag="W/&quot;D0UHQ34_fip7ImA9WxNSEEk.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-7617445232883911144</id><published>2009-08-22T20:36:00.007+01:00</published><updated>2009-08-23T17:33:52.046+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-23T17:33:52.046+01:00</app:edited><title>HTC Hero</title><content type="html">&lt;p&gt;A week and a bit ago I upgraded my phone (a Nokia 6120 - read the saga that led to me getting that one &lt;a href="http://derek-says.blogspot.com/2007/07/mobile-madness.html"&gt;here&lt;/a&gt;) to the HTC Hero and thought I'd share my experiences thus far. I'd been following the progress of Google's Android OS for a while and really quite like the T-Mobile G1 but I'm on Orange with no plans to switch network so was pretty excited when I heard Orange were introducing the HTC Hero just in time for my contract expiring. The big screen, WiFi and GPS were plus points and, whilst I would have preferred a real qwerty keyboard like that of the G1, this being effectively the third version of that phone it should hopefully have a fair few bug fixes and refinements.&lt;/p&gt;

&lt;p&gt;&lt;img style="float: right;" src="http://lh6.ggpht.com/_EuFsZMY5ZNU/SpFoWs1eSGI/AAAAAAAAAhk/LJQluDvKQx0/s144/htc-hero-sml.jpg" border="0" alt="HTC Hero" /&gt;First off it comes in a pretty nice Apple-esque white box and after you've phoned the connections people and turned it on you're presented with a detailed and bright screen. Setup is straight forward and you're up and running in no time.&lt;/p&gt;

&lt;p&gt;I should mention that I'm a pretty big user of Google services; Mail, Calendar, Docs, Reader are apps I use every day. I've &lt;a href="http://derek-says.blogspot.com/2007/05/why-dont-google-support-syncml.html"&gt;blogged in the past&lt;/a&gt; about syncing my phone contacts with those held in Google Mail and it was great to not have to do the usual chore of copying all my contacts over from my old phone. Once I set up my Google account details in the Hero my contacts were all synced down - brilliant! What's better is that my calendar was now synced too which didn't work with SyncML on the old phone. My only criticism of this being that "My Calendar" in the phone is not the same as my "Derek Fowler" Google calendar - this isn't immediately apparent, in fact the two calendars even share the same colour coding, but if you add an event to "My Calendar" it's not synced up to Google. Once you realise this and pick the [your name] calendar that option remains selected and you can even hide "My Calendar" on the phone to make things clearer.&lt;/p&gt;

&lt;p&gt;A really nice extension to the contact list added by HTC themselves is the ability to link phone contacts to their Facebook and Flickr accounts so that whilst browsing contacts you also get their Facebook updates, their Facebook profile picture appears in the contact list and Photo Albums on the phone will also browser your contacts Facebook and Flickr photos in addition to any you have stored on the phone. All in all some brilliantly functional Web 2.0 integration.&lt;/p&gt;

&lt;p&gt;Google Mail on the phone is pretty similar to the app you can get for other handsets and, oddly, is separate to the actual "Mail" app. Admittedly GMail has features like Labels that you don't get with normal e-mail but still. Text messaging is presented nicely with messages between you and a particular contact appearing as a never ending conversation - something that really does make a lot of sense and I'm surprised it's taken handset vendors this long to think of it.&lt;/p&gt;

&lt;p&gt;The browser on the Hero is excellent. It renders pages well and has multi-touch for zooming which is invaluable when you're browsing normal pages rather than those tailored for a small screen. A double-tap zooms in until the object tapped on fills the screen, double-tap again returns to the full page view - very similar to the iPhone browser.&lt;/p&gt;

&lt;p&gt;One of the things that I've found to really let the Hero down is the onscreen qwerty keyboard. Whilst it's quite usable in landscape mode it just isn't big enough in portrait mode and, comparing it to the one on the iPhone you can instantly see it's considerably smaller. Thankfully there's the compact qwerty and phone keypad modes you can switch to which are usable, I've stuck with phone keypad.&lt;/p&gt;

&lt;p&gt;Other let downs are battery life and the odd bit of lag. Initially battery life was pretty poor, being less than a day between changes however after a few full changes it's now up to about two days. Whilst it's not the two weeks I was used to with the Nokia it's okay considering the big screen and multitude of devices inside the handset. Lag wise it's most noticeable when switching from portrait to landscape mode however in general the phone is very responsive and what lag there is generally isn't enough for you to start getting impatient so that's good.&lt;/p&gt;

&lt;p&gt;The Google Market is already full of a wide variety of apps and what's brilliant is that most are free. Highlights I've come across so far are:
&lt;ul&gt;
&lt;li&gt;AndNav - a SatNav app that uses &lt;a href="http://www.openstreetmap.org/"&gt;OpenStreetMap&lt;/a&gt; maps, no 3D view but promising&lt;/li&gt;
&lt;li&gt;beebPlayer - an unofficial BBC iPlayer app that supports both on-demand replay of old TV and radio shows but also live TV and radio!&lt;/li&gt;
&lt;li&gt;Last.fm - streams your recommendations, friends, neighbourhood etc radio&lt;/li&gt;
&lt;li&gt;Layar - augmented reality browser, shows you a view through the phone camera with markers pointing you in the direction of particular things&lt;/li&gt;
&lt;li&gt;Google Maps - excellent use of the built in compass in Street View to allow you to look around as if you're in the place&lt;/li&gt;
&lt;li&gt;Google Sky Map - similar to normal Maps it makes use of the compass to allow you to look around the sky, the app telling you what stars/constellations you're looking at and it even has a search function that will guide you to looking at the correct point in the sky for a particular object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally I have to mention one aspect that had me pleasantly surprised about the Hero. If you read other articles on this blog you'll gather that I'm a pretty big hi-fi nerd so I was very impressed when I plugged my headphones in to the Hero (via the 3.5mm jack) and had a listen. Sound quality is really excellent with an airy detailed delivery - I'd be willing to bet it would give most portable music players a good run for their money.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-7617445232883911144?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/EclWc_6ndsw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/7617445232883911144/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=7617445232883911144" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/7617445232883911144?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/7617445232883911144?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/EclWc_6ndsw/htc-hero.html" title="HTC Hero" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/_EuFsZMY5ZNU/SpFoWs1eSGI/AAAAAAAAAhk/LJQluDvKQx0/s72-c/htc-hero-sml.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2009/08/htc-hero.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUYGRXo6fip7ImA9WxJRFk0.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-9141065463149015567</id><published>2009-05-16T19:55:00.008+01:00</published><updated>2009-05-18T00:32:04.416+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-18T00:32:04.416+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DDD" /><category scheme="http://www.blogger.com/atom/ns#" term="OO" /><title>The always-valid entity anti-pattern</title><content type="html">&lt;p&gt;Jeffrey Palermo wrote an article about &lt;a href="http://jeffreypalermo.com/blog/the-fallacy-of-the-always-valid-entity/"&gt;the fallacy of the always-valid entity&lt;/a&gt; recently in which he highlighted that guarding against an entity becoming invalid by having validation logic in the setters of properties raises more issues than it solves.&lt;/p&gt;

&lt;p&gt;Another way of enforcing an always-valid entity is, what I have &lt;a href="http://usrportage.de/archives/897-Antipattern-the-verbose-constructor.html"&gt;found elsewhere&lt;/a&gt; termed, the "verbose constructor". Having a constructor which requires a value for every property, or every valid combination of properties.&lt;p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;public Car(string make, string model, string serialNumber, 
           decimal engineLitres, int maxPower, decimal urbanMpg, 
           decimal extraUrbanMpg, decimal combinedMpg, 
           int fuelTankCapacity) { ... }

Car myCar = new Car("Audi", "A4", "12345ABCD", 1.8, 120, 
                    28.5, 51.4, 39.8, 65);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The "verbose constructor" is itself a good candidate for an anti-pattern for the following reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modifying the entity means modifying every instantiation of it also&lt;/li&gt;
&lt;li&gt;Forcing a programmer to set these values when they may not be available will result in garbage data which is useless anyway&lt;/li&gt;
&lt;li&gt;Derived classes must call this verbose constructor either replicating every parameter in their own constructors or hardcoding values for some parameters (&lt;a href="http://en.wikipedia.org/wiki/Hard_code"&gt;another anti-pattern&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Unreadable code, without help from the IDE it's difficult to identify each parameter&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The method Jeffrey highlighted in his post has to use exceptions to catch validation errors, which forces a programmer to use another anti-pattern; &lt;a href="http://en.wikipedia.org/wiki/Expection_handling"&gt;exception handling&lt;/a&gt;. Where programming logic is implemented by the throwing and catching of exceptions. Any call to a property setter of the entity must be wrapped in a try...catch... block.&lt;/p&gt;

&lt;p&gt;The always-valid entity, however it's implemented, seems to lead to a minefield of bad code. The thinking behind the need for this blurs the line between two important distinctions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;not setting a value vs. setting it to something incorrect&lt;/li&gt;
&lt;li&gt;what makes an object a valid type vs. what makes an object valid for a particular use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I touched on the first of these before; where it may be the case that a programmer doesn't yet have a value for a particular property available yet. So long as we ensure the entity doesn't leak out in this invalid state we're okay.&lt;/p&gt;
&lt;p&gt;Which leads on to the second item; we should guard against a value being set where that value violates the type e.g. setting Day to 32 for a DateTime, something bad has occurred and this is a real exception case. However, this is a much lower-level problem than enforcing business rules, for example where a credit card applicant's date of birth must be at least 18 years earlier than the date of the application. It could be the case that one company actually requires applicants to be 21 so hardcoding that type of validation into the class is not only restrictive but enforcing this by throwing exceptions is very inefficient.&lt;/p&gt;

&lt;p&gt;The always-valid entity just serves to be very restrictive and limits the entity's uses in its current form. Validating from outside means that its easy to skip validation or make it more stringent when needed. Also, if implemented along the lines Jeffrey describes in his post, it means mechanisms have a common way of validating objects without needing specific knowledge of the particular object or the current validation being applied which makes for more robust code.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-9141065463149015567?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/vjV2Y9Ac8K8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/9141065463149015567/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=9141065463149015567" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/9141065463149015567?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/9141065463149015567?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/vjV2Y9Ac8K8/always-valid-entity-anti-pattern.html" title="The always-valid entity anti-pattern" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2009/05/always-valid-entity-anti-pattern.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MDRn0-eip7ImA9WxVXFkg.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-6951811146778265114</id><published>2009-02-14T23:50:00.000Z</published><updated>2009-02-14T23:51:17.352Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-14T23:51:17.352Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="NHibernate" /><title>OpenSession with connection disables second-level cache in NHibernate</title><content type="html">&lt;p&gt;I've has this post in my drafts for nearly a year now so I decided I'd finish it off.&lt;/p&gt;

&lt;p&gt;I came across an issue when using the second-level cache in NHibernate where none of my objects were being cached and NHibernate was always going to the database for them. What was more odd was the NHibernate debug output suggested the items were being retrieved from the datbase and added to cache but on the next request the items couldn't be resolved in the cache.&lt;/p&gt;

&lt;p&gt;Attatching a debugger and stepping through shows a timestamp passed into Cache's Put() method is equal to MinValue which makes it skip the Cache.Add at the last minute (whilst outputting debug messages to the contrary).&lt;/p&gt;

&lt;p&gt;Tracking this timestamp back revealed it was created when the session is first openned and was due to my passing in my own connection string rather than letting NHibernate provide one. I assume this is a safeguard because IDs aren't necessarily unique between databases so in that case the cache would perform oddly.&lt;/p&gt;

&lt;p&gt;If in your case they are however then you can work around this by casting your ISessionFactory as an ISessionFactoryImplementor. This has an extra overload of OpenSession which takes a IConnection and a ConnectionReleaseMode but doesn't disable the second-level cache.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-6951811146778265114?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/r82e0oXU2Ck" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/6951811146778265114/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=6951811146778265114" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/6951811146778265114?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/6951811146778265114?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/r82e0oXU2Ck/opensession-with-connection-disables.html" title="OpenSession with connection disables second-level cache in NHibernate" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/03/opensession-with-connection-disables.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkEASHs8eyp7ImA9WxVSE0o.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-1367572755376716315</id><published>2009-01-07T21:56:00.003Z</published><updated>2009-01-08T00:30:49.573Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-08T00:30:49.573Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server" /><title>ISNULL vs COALESCE</title><content type="html">&lt;p&gt;Consider this SQL Server statement:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT ISNULL(2, 2.0), COALESCE(2, 2.0)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You might assume, as I did, that they're equivalent and will produce the same result, however this is not the case.&lt;/p&gt;

&lt;p&gt;They differ in the way they determine what data type to return. ISNULL always returns the data type of the first argument and the second argument must implicitly cast to that type. COALESCE on the other hand returns the data type of the argument with highest &lt;a href="http://msdn.microsoft.com/en-us/library/ms190309.aspx"&gt;data type precedence&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a result what you get out of the example above is:&lt;/p&gt;
&lt;table border="1" cellspacing="2"&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;2.0&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;The reason being that the constant "2" is treated as an integer while "2.0" is treated as a decimal. Therefore ISNULL will return an integer because the first argument is an integer but COALESCE returns a decimal because decimal has higher precedence.&lt;/p&gt;

&lt;p&gt;One possible issue I can envisage here is if you were to inadvertently COALESCE a float column in with your decimals and then try to do some arithmetic. You'd end up doing dodgy float arithmetic where you thought you were doing safe decimal arithmetic.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-1367572755376716315?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/bEjXYzdsH_E" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/1367572755376716315/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=1367572755376716315" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/1367572755376716315?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/1367572755376716315?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/bEjXYzdsH_E/isnull-vs-coalesce.html" title="ISNULL vs COALESCE" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2009/01/isnull-vs-coalesce.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkICSX05cSp7ImA9WxRSFkU.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-1946047148698042301</id><published>2008-09-17T20:46:00.003+01:00</published><updated>2008-09-17T22:56:08.329+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-09-17T22:56:08.329+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="XSL" /><title>Column layouts with XSL</title><content type="html">&lt;p&gt;Marking up a set of items so that they are laid out in a fixed number of columns from left to right can be tricky if the items vary in height. You need markup something like the example below to achieve this...&lt;/p&gt;

&lt;pre&gt;&lt;code class="html"&gt;&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;
 &amp;lt;div&amp;gt; class=&amp;quot;item&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
 &amp;lt;div&amp;gt; class=&amp;quot;item&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
 &amp;lt;div&amp;gt; class=&amp;quot;item&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;
 &amp;lt;div&amp;gt; class=&amp;quot;item&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
 &amp;lt;div&amp;gt; class=&amp;quot;item&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;...with CSS like this...&lt;/p&gt;

&lt;pre&gt;&lt;code class="css"&gt;.item { float: left; width: 250px; }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Outputting this from XSL is fairly straight forward and requires relatively little "code" by juggling some XSL and XPath. Here is some example XML:&lt;/p&gt;

&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;
&amp;lt;items&amp;gt;
 &amp;lt;item title=&amp;quot;Item 1&amp;quot;/&amp;gt;
 &amp;lt;item title=&amp;quot;Item 2&amp;quot;/&amp;gt;
 &amp;lt;item title=&amp;quot;Item 3&amp;quot;/&amp;gt;
 &amp;lt;item title=&amp;quot;Item 4&amp;quot;/&amp;gt;
 &amp;lt;item title=&amp;quot;Item 5&amp;quot;/&amp;gt;
&amp;lt;/items&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The XSL to transform this into HTML of the format shown earlier looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
&amp;lt;xsl:stylesheet version=&amp;quot;1.0&amp;quot; xmlns:xsl=&amp;quot;http://www.w3.org/1999/XSL/Transform&amp;quot;&amp;gt;
 &amp;lt;xsl:variable name=&amp;quot;cols&amp;quot; select=&amp;quot;3&amp;quot;/&amp;gt;
 &amp;lt;xsl:template match=&amp;quot;/items&amp;quot;&amp;gt;
  &amp;lt;xsl:apply-templates select=&amp;quot;item[position() mod $cols = 1]&amp;quot; mode=&amp;quot;row&amp;quot;/&amp;gt;
 &amp;lt;/xsl:template&amp;gt;
 &amp;lt;xsl:template match=&amp;quot;item&amp;quot; mode=&amp;quot;row&amp;quot;&amp;gt;
  &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;
   &amp;lt;xsl:apply-templates select=&amp;quot;.|./following-sibling::item[position() &amp;amp;lt; $cols]&amp;quot;/&amp;gt;
  &amp;lt;/div&amp;gt;
 &amp;lt;/xsl:template&amp;gt;
 &amp;lt;xsl:template match=&amp;quot;item&amp;quot;&amp;gt;
  &amp;lt;div class=&amp;quot;item&amp;quot;&amp;gt;
   &amp;lt;xsl:value-of select=&amp;quot;@title&amp;quot;/&amp;gt;
  &amp;lt;/div&amp;gt;
 &amp;lt;/xsl:template&amp;gt;
&amp;lt;/xsl:stylesheet&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;First off, we've got a variable named "cols" for setting the number of columns to output. Next, inside the first template matching our root element, we have an apply-templates which selects all the item element with a position that when divided by the number of columns leaves a remainder of one. This should give us items 1, 4, 7, 10 etc and these are then passed to a template in mode "row".&lt;/p&gt;

&lt;p&gt;This apply-templates will match the next template whose job is to output the div element with class row. Within this div there is another apply-templates, this time matching the current item element and a number of its following siblings. That being one less than then number of columns required so in this example we get the context item plus its two following siblings. The template that matches this apply is that last one, without the mode specified.&lt;/p&gt;

&lt;p&gt;The last "item" matching template simply writes out the div with class item surrounding the content of the item itself.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-1946047148698042301?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/yyvyIUSmwMA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/1946047148698042301/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=1946047148698042301" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/1946047148698042301?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/1946047148698042301?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/yyvyIUSmwMA/column-layouts-with-xsl.html" title="Column layouts with XSL" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/09/column-layouts-with-xsl.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcGSH48eyp7ImA9WxdaE0s.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-3566699272108348495</id><published>2008-08-21T23:52:00.003+01:00</published><updated>2008-08-22T00:57:09.073+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-08-22T00:57:09.073+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><title>Function overloading in JavaScript</title><content type="html">&lt;p&gt;Trying to write a function so that it will handle different numbers and types of argument always seems to take a lot more code that it should. Today I ended up with some nightmarish &lt;var&gt;if...else...&lt;/var&gt; because I wanted to support:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;var&gt;Object, Object&lt;/var&gt;&lt;/li&gt;
&lt;li&gt;&lt;var&gt;Object, String&lt;/var&gt;&lt;/li&gt;
&lt;li&gt;&lt;var&gt;Object, Object, String&lt;/var&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I remembered a &lt;a href="http://ejohn.org/blog/javascript-method-overloading"&gt;post by John Resig&lt;/a&gt; from a while back on this, however his method doesn't handle different types. A quick Google found &lt;a href="http://snippets.dzone.com/posts/show/842"&gt;this snippet&lt;/a&gt; which does the job but seems a bit clunky, converting constructors to strings and the like. Satisfied that it could probably be improved upon here is &lt;a href="http://dfowler.geeksbox.co.uk/demos/method-overload.htm"&gt;my go at it&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Implementation&lt;/h3&gt;

&lt;p&gt;Here an &lt;var&gt;Impl&lt;/var&gt; class holds the different method implementations against their signatures, defined as an array of constructors. The &lt;var&gt;add&lt;/var&gt; method maps a new signature to an implementation, the &lt;var&gt;exec&lt;/var&gt; method identifies the correct implementation for the current arguments and executes it and the &lt;var&gt;compile&lt;/var&gt; method returns a function that can be used to overwrite the "daddy" function.&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;function Impl(){
 var _impl = {};
 return {
  add: function(aSignature, fImpl){
   _impl[aSignature] = fImpl;
  },
  exec: function(args, scope){
   var aArgs = Array.prototype.slice.call(args);
   var aCtors = [];
   for(var i in aArgs) aCtors.push(aArgs[i].constructor);
   return (_impl[aCtors] || function(){}).apply(scope, aArgs);
  },
  compile: function(){
   var impl = this;
   return function(){
    return impl.exec(arguments, this);
   };
  }
 };
}&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Usage&lt;/h3&gt;

&lt;p&gt;Here's an example setup of a function &lt;var&gt;stringify&lt;/var&gt; that will take two strings, two numbers or an array and do different things depending on what arguments are passed.&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;function stringify(){
 var someVar = 'Items: ';
 var impl = new Impl();
 
 impl.add([String, String], function(sLeft, sRight){
  return sLeft + ': ' + sRight;
 });
 impl.add([Number, Number], function(iLeft, iRight){
  return 'Sum: ' + (iLeft + iRight).toString();
 });
 impl.add([Array], function(aIn){
  return someVar + aIn.join(', ');
 });
 
 stringify = impl.compile();
 return stringify.apply(this, arguments);
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each implementation is added with an array of constructors e.g. &lt;var&gt;[Number, Number]&lt;/var&gt; representing the arguments signature to match and the implementation function. Notice that we don't need to do any type checking of the variables in the implementation function, as we have to have matched the signature to get that far, and we can give then relevant names.&lt;/p&gt;

&lt;p&gt;Notice the last two lines are:&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;stringify = impl.compile();
return stringify.apply(this, arguments);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So on the first execution of the function it is overwritten with a "compiled" version and then that version is called on the next line. Subsequent calls to the function will go straight to the "compiled" version thus speeding things up. This could also be done without the compilation and overwriting bit by just calling &lt;var&gt;exec&lt;/var&gt; directly thus:&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;return impl.exec(arguments, this);&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Calling our function&lt;/h3&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;stringify('foo', 'bar'); // =&gt; 'foo: bar'
stringify(26, 5); // =&gt; 'Sum: 31'
stringify( [ 1, 2, 3 ] ); // =&gt; 'Items: 1, 2, 3'&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Our different numbers and types of argument are giving us the output we'd expect.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-3566699272108348495?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/J0fjU_U8kBQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/3566699272108348495/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=3566699272108348495" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/3566699272108348495?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/3566699272108348495?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/J0fjU_U8kBQ/function-overloading-in-javascript.html" title="Function overloading in JavaScript" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/08/function-overloading-in-javascript.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEYARngycCp7ImA9WxdaEko.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-7263656476761987485</id><published>2008-08-21T00:07:00.003+01:00</published><updated>2008-08-21T00:49:07.698+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-08-21T00:49:07.698+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="NHibernate" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Excluding particular derived types in NHibernate queries</title><content type="html">&lt;p&gt;Today I came across an NHibernate problem where I needed to select every instance of a particular base type and all its derived types from a database, apart from one particular derived type. Here is a trivial example:&lt;/p&gt;
&lt;pre&gt;&lt;code class="c#"&gt;public class Mammal {}
public class Dog : Mammal {}
public class Cat : Mammal {}
public class DomesticCat : Cat {}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case the problem was equivalent to selecting every mammal that isn't a domestic cat.&lt;/p&gt;
&lt;p&gt;We're using the &lt;em&gt;table per class hierarchy&lt;/em&gt; inheritance model in NHibernate which uses values in a discriminator column to determine which type is held in a particular row of the table.&lt;/p&gt;
&lt;p&gt;Selecting the whole hierarchy is done like this:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;In HQL:&lt;/dt&gt;
&lt;dd&gt;&lt;pre&gt;&lt;code class="c#"&gt;IQuery q = sess.CreateQuery("from Mammal");
IList mammals = q.List();&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;
&lt;dt&gt;In Criteria:&lt;/dt&gt;
&lt;dd&gt;&lt;pre&gt;&lt;code class="c#"&gt;ICriteria crit = sess.CreateCriteria(typeof(Mammal));
List mammals = crit.List();&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;I then needed to be able to effectively add a &lt;var&gt;WHERE discriminator &amp;lt;&amp;gt; 'DomesticCat'&lt;/var&gt; to the end of the query. I had a quick search for this special discriminator property and for a Criteria Expression for excluding a particular type but couldn't find either.&lt;/p&gt;
&lt;h3&gt;The Solution&lt;/h3&gt;
&lt;p&gt;I finally found the solution on the &lt;var&gt;WHERE&lt;/var&gt; clause page of the HQL chapter in the NHibernate reference. There is a special property called &lt;var&gt;class&lt;/var&gt; which you can test against a type name in HQL or an actual type in Criteria queries e.g.&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;In HQL:&lt;/dt&gt;
&lt;dd&gt;&lt;pre&gt;&lt;code class="c#"&gt;IQuery q = sess.CreateQuery("from Mammal m where m.class != 'DomesticCat'");
IList mammals = q.List();&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;
&lt;dt&gt;In Criteria:&lt;/dt&gt;
&lt;dd&gt;&lt;pre&gt;&lt;code class="c#"&gt;ICriteria crit = sess.CreateCriteria(typeof(Mammal));
crit.Add( Expression.Not( Expression.Eq("class", typeof(DomesticCat)) ) );
List mammals = crit.List();&lt;/code&gt;&lt;/pre&gt;&lt;/dd&gt;
&lt;/dl&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-7263656476761987485?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/IcnOJsjzgQI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/7263656476761987485/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=7263656476761987485" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/7263656476761987485?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/7263656476761987485?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/IcnOJsjzgQI/excluding-particular-derived-types-in.html" title="Excluding particular derived types in NHibernate queries" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/08/excluding-particular-derived-types-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMBRXc_eip7ImA9WxdUGEQ.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-5100110944141112474</id><published>2008-08-04T19:44:00.004+01:00</published><updated>2008-08-05T01:34:14.942+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-08-05T01:34:14.942+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Generic collections and inheritance</title><content type="html">&lt;p&gt;I stumbled upon a small annoyance today when trying to use a generic collection of type B where a generic collection of type A is expected where B inherits from A. With arrays this works fine and the elements are implicitly cast to the base type.&lt;/p&gt;

&lt;p&gt;Here's a &lt;a href="http://www.sliver.com/dotnet/SnippetCompiler/"&gt;snippet compiler&lt;/a&gt; script which illustrates the problem - &lt;a href="http://dfowler.geeksbox.co.uk/files/snippets/list-converter.txt"&gt;list-converter.txt&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the script I'm using &lt;var&gt;BaseType&lt;/var&gt; and &lt;var&gt;InheritingType&lt;/var&gt; for A and B. The script initially shows the implicit cast taking place for an array of B objects on line 19. The ArrayTest method expects an array of A but is quite happy being called with an array of B.&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;public static void ArrayTest(BaseType[] bar) { ... }

InheritingType[] myArray = new InheritingType[]{ it1, it2 };
ArrayTest(myArray);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we now look at the ListTest method and try running this section of code...&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;public static void ListTest(List&amp;lt;BaseType&amp;gt; bar) { ... }

List&amp;lt;InheritingType&amp;gt; myList = new List&amp;lt;InheritingType&amp;gt;();
myList.Add(it1);
myList.Add(it2);
  
ListTest(myList);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;...we get an error...&lt;/p&gt;

&lt;pre&gt;Argument '1': cannot convert from 
'System.Collections.Generic.List&amp;lt;InheritingType&amp;gt;' to 
'System.Collections.Generic.List&amp;lt;BaseType&amp;gt;'&lt;/pre&gt;

&lt;p&gt;We get the same result if we try an explicit cast&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;ListTest((List&amp;lt;BaseType&amp;gt;)myList);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Obviously allowing an implicit conversion for generics in general doesn't make a lot of sense but for lists I think it does and it's a pain to have to convert from one generic collection type to another.&lt;/p&gt;

&lt;h3&gt;Solution&lt;/h3&gt;

&lt;p&gt;Thankfully, with the help of some generics (of all things) and the &lt;var&gt;ConvertAll&lt;/var&gt; method of &lt;var&gt;List&lt;/var&gt; there's quite an elegant solution to this problem, we can create ourselves a nice generic list converter, here's an example:&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;public class ListConverter&amp;lt;TFrom, TTo&amp;gt; where TFrom : TTo
{
 public static IEnumerable&amp;lt;TTo&amp;gt; Convert(IEnumerable&amp;lt;TFrom&amp;gt; from)
 {
  return Convert(new List&amp;lt;TFrom&amp;gt;(from));
 }
 
 public static List&amp;lt;TTo&amp;gt; Convert(List&amp;lt;TFrom&amp;gt; from)
 {
  return from.ConvertAll&amp;lt;TTo&amp;gt;(new Converter&amp;lt;TFrom, TTo&amp;gt;(Convert));
 }

 public static TTo Convert(TFrom from)
 {
  return (TTo)from;
 }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We use two type arguments, the type we're converting from, which will be B from the example above, and the type we're converting to, A. Notice also the &lt;var&gt;where TFrom : TTo&lt;/var&gt; which enforces that B must inherit from A.&lt;/p&gt;

&lt;p&gt;As we need the &lt;var&gt;ConvertAll&lt;/var&gt; method of &lt;var&gt;List&lt;/var&gt; we have a method that takes an &lt;var&gt;IEnumerable&lt;/var&gt; and creates a new &lt;var&gt;List&lt;/var&gt;. We also have the method that does the main &lt;var&gt;ConvertAll&lt;/var&gt; on the &lt;var&gt;List&lt;/var&gt; and the delegate which is passed to &lt;var&gt;ConvertAll&lt;/var&gt;.&lt;/p&gt;

&lt;p&gt;This allows us to create a type converter as we code without needing to mess about e.g.&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;ListTest(ListConverter&amp;lt;InheritingType, BaseType&amp;gt;.Convert(myList));&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-5100110944141112474?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/i0h4YCAS7Zk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/5100110944141112474/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=5100110944141112474" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/5100110944141112474?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/5100110944141112474?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/i0h4YCAS7Zk/generic-collections-and-inheritance.html" title="Generic collections and inheritance" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/08/generic-collections-and-inheritance.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkADQ3Y9fCp7ImA9WxdVEUo.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-496319417435839087</id><published>2008-07-16T01:46:00.006+01:00</published><updated>2008-07-16T02:12:52.864+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-07-16T02:12:52.864+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="CSS" /><title>A quick go at CSS preprocessing in JavaScript</title><content type="html">&lt;p&gt;Chris Heilmann's &lt;a title="CSS preprocessor for variables, nested selectors and other goodies" href="http://www.wait-till-i.com/2008/07/14/css-preprocessor/"&gt;post&lt;/a&gt; today about &lt;a href="http://wiki.framwurk.org/Main/CSSPP"&gt;CSSPP&lt;/a&gt;, a PHP preprocessor for CSS, set the old brain going so I decided to knock up a quick &lt;a href="http://dfowler.geeksbox.co.uk/demos/csspp-js/"&gt;proof of concept (FF only)&lt;/a&gt; in JavaScript doing some of the same stuff. Namely, it has very quickly hacked nested rule parsing and a form of the replacement variables feature.&lt;/p&gt;

&lt;p&gt;Currently you have to specify your CSS for processing in a script tag with a particular type...&lt;/p&gt;

&lt;pre&gt;&lt;code class="html"&gt;
&amp;lt;script type="text/csspp"&amp;gt;
.red {
 
 border: 2px solid red;
 
 h2 {
  background: #933;
 }
 
 p {
  background: $derek$;
 }
}
   
.blue {

 border: 2px solid blue;
 background: $other$;
        
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;...and the variables are retrieved from a JavaScript object by name...&lt;/p&gt;

&lt;pre&gt;&lt;code class="html"&gt;
&amp;lt;script type="text/javascript"&amp;gt;
var cssVars = {
 derek: '#FCC',
 other: '#CCF'
}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Obviously a JavaScript implementation like this would slow down the user experience and wouldn't have any of the snazzy caching features of a server-side version but it might be useful if you're hacking a bit of CSS and don't have a PHP server handy.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-496319417435839087?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/JLOJIAWI2Qg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/496319417435839087/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=496319417435839087" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/496319417435839087?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/496319417435839087?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/JLOJIAWI2Qg/quick-go-at-css-preprocessing-in.html" title="A quick go at CSS preprocessing in JavaScript" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/07/quick-go-at-css-preprocessing-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEADRnk6eSp7ImA9WxRbGU0.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-557815242514819791</id><published>2008-06-19T23:06:00.004+01:00</published><updated>2008-12-10T10:59:37.711Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-10T10:59:37.711Z</app:edited><title>Comparison of "netbook" screen resolutions</title><content type="html">&lt;p&gt;I'm thinking about pushing the boat out and getting myself a "netbook" and was wondering whether I'd actually find the relatively low resolutions they offer usable so I knocked up this quick comparison. To make them as usable a possible you'd probably have your browser in full screen mode so that's what I've depicted here.&lt;/p&gt;

&lt;img src="http://4.bp.blogspot.com/_EuFsZMY5ZNU/SFrhY55o7SI/AAAAAAAAAYU/U081-RaFYB8/s1600/netbooks.jpg"/&gt;

&lt;p&gt;As you can see both the greater resolutions would be very usable for browsing and the Mini-Note's resolution is brilliant for a 9" screen; being the same as that you usually see on much larger machines.&lt;/p&gt;

&lt;p&gt;The 7" EEE PC's 800 x 480 resolution isn't quite enough. You can see in the screen shot the horizontal scroll bar at the bottom and I think that would be a common problem as lots of sites are designed for 1024 pixels as minimum width rather than 800 pixels these days.&lt;/p&gt;

&lt;p&gt;To sum up the HP would almost be a viable alternative to a full size laptop if it were more powerful. For now though, it looks like the Acer Aspire One with its good resolution, 1.6GHz Intel Atom processor and excellent price of £199, would be the best one to go for.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-557815242514819791?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/mUlkQIZHRlo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/557815242514819791/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=557815242514819791" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/557815242514819791?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/557815242514819791?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/mUlkQIZHRlo/comparison-of-netbook-screen.html" title="Comparison of &quot;netbook&quot; screen resolutions" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_EuFsZMY5ZNU/SFrhY55o7SI/AAAAAAAAAYU/U081-RaFYB8/s72-c/netbooks.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/06/comparison-of-netbook-screen.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cHRXoyeCp7ImA9WxdRFk8.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-589961607313625376</id><published>2008-06-02T11:50:00.013+01:00</published><updated>2008-06-05T00:10:34.490+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-06-05T00:10:34.490+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="NHibernate" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>"duplicate association path" bug in NHibernate Criteria API</title><content type="html">&lt;p&gt;This problem exists in Hibernate itself as well and, contrary to some comments I've seen in the bug tracker, I believe it is a bug in the Criteria API and not in HQL.&lt;/p&gt;

&lt;h3&gt;A trivial example&lt;/h3&gt;

&lt;p&gt;I have a Store type representing a shop which has a collection, Products, containing Product types the shop stocks e.g. "Golf Balls", "Bananas", "Hats" etc. I want to get all the stores who stock both Golf Balls and Hats.&lt;/p&gt;

&lt;p&gt;In HQL this would be :&lt;/p&gt;

&lt;pre&gt;&lt;code class="sql"&gt;SELECT s 
FROM Store AS s 
INNER JOIN s.Products AS prod1
INNER JOIN s.Products AS prod2
WHERE prod1.Type = 'Golf Balls' 
   AND prod2.Type = 'Hats'&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;...pretty straight forward and works fine.&lt;/p&gt;

&lt;p&gt;In Criteria API this would be:&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;IList stores = sess.CreateCriteria(typeof(Store))
   .CreateAlias("Products", "prod1")
   .CreateAlias("Products", "prod2")
   .Add( Expression.EqProperty("prod1.Type", "Golf Balls") )
   .Add( Expression.EqProperty("prod2.Type", "Hats") )
   .List();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;...again straight forward and seems logical but this produces an error...&lt;/p&gt;

&lt;pre&gt;NHibernate.QueryException: duplicate association path Products&lt;/pre&gt;

&lt;p&gt;As I said, it seems like a pretty solid candidate for a bug and it's odd considering surely the meaning of &lt;var&gt;CreateAlias&lt;/var&gt; is that I want to use the same association more than once so need to alias it to different labels.&lt;/p&gt;

&lt;p&gt;Unfortunately there's no way to get around this issue if you need distinct association joins like the above example and looking at the NHibernate code it doesn't seem like an easy fix. If, however, you can apply your criterion or sorts to the same alias then there is a workaround.&lt;/p&gt;

&lt;h3&gt;Workaround&lt;/h3&gt;

&lt;fieldset&gt;&lt;legend&gt;Note&lt;/legend&gt;This only applies where you don't require distinct association joins.&lt;/fieldset&gt;

&lt;p&gt;If we take a look at this handy &lt;a href="http://www.surcombe.com/nhibernate-1.2/api/Index.html"&gt;NHibernate API reference&lt;/a&gt; we see that the two implementing classes for ICriteria are &lt;var&gt;NHibernate.Impl.CriteriaImpl&lt;/var&gt; and &lt;var&gt;NHibernate.Impl.CriteriaImpl.Subcriteria&lt;/var&gt;.&lt;/p&gt;

&lt;p&gt;&lt;var&gt;CriteriaImpl&lt;/var&gt; is the root criteria you get calling &lt;var&gt;CreateCriteria&lt;/var&gt; on &lt;var&gt;ISession&lt;/var&gt; and &lt;var&gt;Subcriteria&lt;/var&gt; you get with every call to &lt;var&gt;CreateCrteria&lt;/var&gt; or &lt;var&gt;CreateAlias&lt;/var&gt; on &lt;var&gt;ICriteria&lt;/var&gt;.&lt;/p&gt;

&lt;p&gt;First you need to retrieve the root &lt;var&gt;CriteriaImpl&lt;/var&gt; for your working &lt;var&gt;ICriteria&lt;/var&gt;. Your working &lt;var&gt;ICriteria&lt;/var&gt; may be the root but if it isn't you need to recurse up through the &lt;var&gt;Parent&lt;/var&gt; property until you reach the &lt;var&gt;CriteriaImpl&lt;/var&gt; object.&lt;/p&gt;

&lt;p&gt;&lt;var&gt;CriteriaImpl&lt;/var&gt; has an &lt;var&gt;IterateSubcriteria&lt;/var&gt; method which returns an &lt;var&gt;IList&lt;/var&gt; of all its &lt;var&gt;Subcriteria&lt;/var&gt; descendants. You can loop through this list checking the &lt;var&gt;Parent&lt;/var&gt; and &lt;var&gt;Path&lt;/var&gt; properties of each item. The &lt;var&gt;Parent&lt;/var&gt; because the value of &lt;var&gt;Path&lt;/var&gt; is relative and you're only interested in what will be sibling &lt;var&gt;Subcriteria&lt;/var&gt; to the one you're about to add.&lt;/p&gt;

&lt;p&gt;If you find a match you can retrieve its alias from the &lt;var&gt;Alias&lt;/var&gt; property, otherwise you can add a new alias to your working &lt;var&gt;ICriteria&lt;/var&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-589961607313625376?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/GaeemYCIgq4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/589961607313625376/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=589961607313625376" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/589961607313625376?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/589961607313625376?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/GaeemYCIgq4/duplicate-association-path-bug-in.html" title="&quot;duplicate association path&quot; bug in NHibernate Criteria API" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/06/duplicate-association-path-bug-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkIBSHc_eyp7ImA9WxdSFEw.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-459126862035466637</id><published>2008-05-21T23:52:00.000+01:00</published><updated>2008-05-21T23:55:59.943+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-21T23:55:59.943+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Implementation of the Visitor pattern using .NET Generics</title><content type="html">&lt;p&gt;In &lt;a href="http://derek-says.blogspot.com/2008/05/implicit-polymorphism-and-lazy.html"&gt;a recent post&lt;/a&gt; I discussed using the Visitor pattern to solve a lazy initialization problem in NHibernate. The example Visitor class in that post is tied to the base class of the class hierarchy it is dealing with so everywhere you need to use a Visitor class you'd need to define at least one of these Visitor classes and then possibly inherit from it to implement alternative functionality.&lt;/p&gt;

&lt;p&gt;A better solution is to use .NET Generics to create the Visitor e.g.:&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;// Visitor for base type TBase
public class Visitor&amp;lt;TBase&amp;gt;
{

 // Delegate for type TSub which can be any subclass of TBase
 // that takes a parameter of type TSub
 public delegate void VisitDelegate&amp;lt;TSub&amp;gt;(TSub u) where TSub : TBase;
 
 // Dictionary to contain our delegates
 Dictionary&amp;lt;Type, object&amp;gt; vDels = new Dictionary&amp;lt;Type, object&amp;gt;();
 
 // Method to add a delegate for type TSub which can be any subclass of TBase
 public void AddDelegate&amp;lt;TSub&amp;gt;(VisitDelegate&amp;lt;TSub&amp;gt; del) where TSub : TBase
 {
  vDels.Add(typeof(TSub), del);
 }
 
 // Visit method for type TSub which can be any subclass of TBase
 // takes one parameter of type TSub, picks the right delegate
 // and executes it passing the parameter to it
 public void Visit&amp;lt;TSub&amp;gt;(TSub x) where TSub : TBase
 {
  if(vDels.ContainsKey(typeof(TSub)))
  {
   ((VisitDelegate&amp;lt;TSub&amp;gt;)vDels[typeof(TSub)])(x);
  }
 }
 
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I've knocked up a quick &lt;a href="http://www.sliver.com/dotnet/SnippetCompiler/"&gt;Snippet Compiler&lt;/a&gt; demo &lt;a href="http://dfowler.geeksbox.co.uk/files/snippets/generic-visitor.txt"&gt;here&lt;/a&gt;. The key parts are the &lt;var&gt;Accept&lt;/var&gt; methods in the classes of the hierarchy...&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;public class Cat : Mammal
{
 ...
 public override void Accept(Visitor&amp;lt;Mammal&amp;gt; visitor)
 {
  visitor.Visit&amp;lt;Cat&amp;gt;(this);
 }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;...and adding the actual work to be done by creating delegate for each of the types you want to "capture"...&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;// Our visitor on our base class which will do our type specific work
Visitor&amp;lt;Mammal&amp;gt; visitor = new Visitor&amp;lt;Mammal&amp;gt;();
string outerVar = &amp;quot;A variable from outside delegate&amp;quot;;

// Add the work to be done for DomesticCat
visitor.AddDelegate&amp;lt;DomesticCat&amp;gt;(delegate(DomesticCat a){
 WL(&amp;quot;Doing some DomesticCat specific work&amp;quot;);
 WL(a.Age + &amp;quot;, &amp;quot; + a.Color + &amp;quot;, &amp;quot; + a.Name);
 WL(outerVar);
});

// Add the work to be done for Dog
visitor.AddDelegate&amp;lt;Dog&amp;gt;(delegate(Dog b){
 WL(&amp;quot;Doing some Dog specific work&amp;quot;);
 WL(b.Age + &amp;quot;, &amp;quot; + b.Color);
});&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The visitor pattern is quite widely applicable in OO environments however, while this solution may not be ideal where you need the visitor class to have a lot more information about the task it is to perform, it is certainly preferable to a large &lt;var&gt;if...else if...else...&lt;/var&gt; type construct you might otherwise use for small tasks.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-459126862035466637?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/-z9UzssWxWA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/459126862035466637/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=459126862035466637" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/459126862035466637?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/459126862035466637?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/-z9UzssWxWA/implementation-of-visitor-pattern-using.html" title="Implementation of the Visitor pattern using .NET Generics" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/05/implementation-of-visitor-pattern-using.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cMRXw8eip7ImA9WxdSE08.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-7559266028350128788</id><published>2008-05-20T23:24:00.002+01:00</published><updated>2008-05-21T00:11:24.272+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-21T00:11:24.272+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="jQuery" /><title>dp.SyntaxHighlighter jQuery plugin</title><content type="html">&lt;p&gt;I've just added syntax highlighing to the code samples on my blog using the excellent &lt;a href="http://code.google.com/p/syntaxhighlighter/"&gt;dp.SyntaxHighlighter&lt;/a&gt;. Adding a class name e.g. "c#" or "xml" to your &lt;var&gt;pre&lt;/var&gt; or &lt;var&gt;textarea&lt;/var&gt; elements and calling &lt;var&gt;HighlightAll&lt;/var&gt; magically highlights the content and turns the surrounding element into a fancy box complete with toolbar.&lt;/p&gt;

&lt;p&gt;I tend to wrap my samples in a &lt;var&gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;...&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;/var&gt; so applying the highlight on the &lt;var&gt;pre&lt;/var&gt; tag would have broken because of the additional &lt;var&gt;code&lt;/var&gt; inside. A quick gander at the code, bit of refactoring in shCore.js and a jQuery one-liner later and I've got a nice(ish) plugin that will apply highlighting to the elements selected through jQuery thusly:&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;$(document).ready(function(){
   $("code").syntaxHighlight({showGutter: false, firstLine: 5});
});&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The settings are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;showGutter &amp;lt; bool &amp;gt;&lt;/li&gt;
&lt;li&gt;showControls &amp;lt; bool &amp;gt;&lt;/li&gt;
&lt;li&gt;collapseAll &amp;lt; bool &amp;gt;&lt;/li&gt;
&lt;li&gt;firstLine &amp;lt; int &amp;gt;&lt;/li&gt;
&lt;li&gt;showColumns &amp;lt; bool &amp;gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can grab the files from here:&lt;/p&gt;

&lt;ul&gt;
   &lt;li&gt;&lt;a href="http://dfowler.geeksbox.co.uk/files/dp.SyntaxHighlighter/Scripts/shCore.js"&gt;Modified shCore.js&lt;/a&gt;&lt;/li&gt;
   &lt;li&gt;&lt;a href="http://dfowler.geeksbox.co.uk/files/dp.SyntaxHighlighter/Scripts/jQuery.syntaxHighlight.js"&gt;jQuery.syntaxHighlight.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This mod is using the latest stable release (1.5.1) of dp.SyntaxHighlighter. It looks like version 1.6 is in the pipeline with some major changes so I'll keep an eye on that and maybe revisit this when it comes out.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-7559266028350128788?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/3JYCBJvr2q4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/7559266028350128788/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=7559266028350128788" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/7559266028350128788?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/7559266028350128788?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/3JYCBJvr2q4/dpsyntaxhighlighter-jquery-plugin.html" title="dp.SyntaxHighlighter jQuery plugin" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/05/dpsyntaxhighlighter-jquery-plugin.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck8FR3s7eCp7ImA9WxdSE08.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-3652972974965105385</id><published>2008-05-16T21:16:00.004+01:00</published><updated>2008-05-20T23:00:16.500+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-20T23:00:16.500+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="NHibernate" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Implicit polymorphism and lazy collections in NHibernate</title><content type="html">&lt;p&gt;If you create a lazy loaded property or collection in NHibernate which can contain any type from a class hierarchy, for example by having mappings like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
&amp;lt;hibernate-mapping xmlns=&amp;quot;urn:nhibernate-mapping-2.2&amp;quot;&amp;gt;
  &amp;lt;class name=&amp;quot;Mammal&amp;quot; table=&amp;quot;Mammal&amp;quot;&amp;gt;
    &amp;lt;discriminator column=&amp;quot;mammal_type&amp;quot; type=&amp;quot;String&amp;quot;/&amp;gt;
    ...
    &amp;lt;subclass name=&amp;quot;Cat&amp;quot; discriminator-value=&amp;quot;CAT&amp;quot;&amp;gt;
      ...
      &amp;lt;subclass name=&amp;quot;DomesticCat&amp;quot; discriminator-value=&amp;quot;CAT-DOMESTIC&amp;quot;&amp;gt;
        ...
      &amp;lt;/subclass&amp;gt;
    &amp;lt;/subclass&amp;gt;
    &amp;lt;subclass name=&amp;quot;Dog&amp;quot; discriminator-value=&amp;quot;DOG&amp;quot;&amp;gt;
      ...
    &amp;lt;/subclass&amp;gt;
  &amp;lt;/class&amp;gt;
  &amp;lt;class name=&amp;quot;Zoo&amp;quot; table=&amp;quot;Zoo&amp;quot;&amp;gt;
    ...
    &amp;lt;bag name=&amp;quot;Animals&amp;quot;&amp;gt;
      &amp;lt;key column=&amp;quot;zoo_fkey&amp;quot;/&amp;gt;
      &amp;lt;one-to-many class=&amp;quot;Mammal&amp;quot;/&amp;gt;
    &amp;lt;/bag&amp;gt;
  &amp;lt;/class&amp;gt;
&amp;lt;/hibernate-mapping&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You'll find that on requesting your objects from your collection they will be of a special new type NHibernate has created, derived from your base class which in this case is "Mammal".&lt;/p&gt;

&lt;p&gt;This is a real problem because it means that you can't perform &lt;var&gt;is&lt;/var&gt; or &lt;var&gt;as&lt;/var&gt; operations on it to determine which actual type it is and you can't cast it to access properties and methods of your derived types.&lt;/p&gt;

&lt;p&gt;The solution is to use the Visitor pattern which is described in detail on &lt;a href="http://sourcemaking.com/design_patterns/visitor"&gt;this site&lt;/a&gt; with a couple of examples in C# &lt;a href="http://www.dofactory.com/Patterns/PatternVisitor.aspx"&gt;on this site&lt;/a&gt;. Essentially it involves creating a class with a method which is overloaded for each of the types in your class hierarchy.&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;class MammalVisitor
{
  public void Visit(Cat c) { ... Cat operations ... }
  public void Visit(DomesticCat dc) { ... DomesticCat operations ... }
  public void Visit(Dog d) { ... Dog operations ... }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This "visitor" object is then passed to a method defined on the base class of your hierarchy and then subsequently overridden on each derived type.&lt;/p&gt;


&lt;pre&gt;&lt;code class="c#"&gt;class Mammal
{
  public virtual void Accept(MammalVisitor mv) { mv.Visit(this); }
  ...
}

class Cat : Mammal
{
  public override void Accept(MammalVisitor mv) { mv.Visit(this); }
  ...  
}

class Dog : Mammal
{
  public override void Accept(MammalVisitor mv) { mv.Visit(this); }
  ...  
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These methods simply call the visitor's method passing &lt;var&gt;this&lt;/var&gt; to it which in turn will automatically execute the correct overload.&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;Mammal m; // some unknown derived type of mammal
MammalVisitor mv = new MammalVisitor();
m.Accept(mv);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These overloaded methods can then perform your type specific functions. In the example above you have no knowledge of the type of Mammal that you have however when you call Accept the relevant code is automatically executed. If Mammal happens to be a Cat type then the Cat overloaded Visit method is called.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-3652972974965105385?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/nwgOD03mNoc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/3652972974965105385/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=3652972974965105385" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/3652972974965105385?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/3652972974965105385?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/nwgOD03mNoc/implicit-polymorphism-and-lazy.html" title="Implicit polymorphism and lazy collections in NHibernate" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">8</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/05/implicit-polymorphism-and-lazy.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MMRHg_eCp7ImA9WxdSE08.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-2113068026619053841</id><published>2008-05-13T01:24:00.005+01:00</published><updated>2008-05-21T00:18:05.640+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-21T00:18:05.640+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="MVC" /><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="XSL" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>Creating Views using XSL in ASP.NET MVC</title><content type="html">&lt;p&gt;There's something about Web Forms that never felt quite right to me; it all seemed a bit too much like a bodge that created more problems than it solved. I've been having a tinker with &lt;a href="http://www.asp.net/mvc/"&gt;ASP.NET MVC&lt;/a&gt; for the past few days now and I'm really liking the way it all fits together; giving you clean separation between the layers and a means of passing data between them.&lt;/p&gt;

&lt;p&gt;The View layer in MVC uses a very Classic ASP-esque markup for mixing code and HTML. Seems rather dirty but by this point any major processing should have been done and all that you'll need to do is render HTML with maybe some looping.&lt;/p&gt;

&lt;p&gt;That being said if all we'll need to do by this point is some looping at the most then why not use an XSL transform instead?&lt;/p&gt;

&lt;p&gt;XSL is well defined and established now with a load of tools out there for giving you a WYSIWYG view of your tranform as you build it. Plus as it is purely XML based it will likely be a lot easier for designers  (the folk who we really want to build Views) to get to grips with.&lt;/p&gt;

&lt;h3&gt;A quick proof of concept&lt;/h3&gt;

&lt;h4&gt;Step 1 - Create a model class for your XSL ViewData&lt;/h4&gt;

&lt;p&gt;This has simply an XmlDocument which will contain our serialized object and a string which will contain a path to our XSL file.&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;public class XslViewData
{
 private System.Xml.XmlDocument _doc;
 private string _xslPath;

 public XslViewData(System.Xml.XmlDocument doc, string xslPath)
 {
  _doc = doc;
  _xslPath = xslPath;
 }
  
 public System.Xml.XmlDocument Doc
 {
  get 
  {
   return _doc;
  }
 }

 public string XslPath
 {
  get
  {
   return _xslPath;
  }
 }
}&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Step 2 - Serialize your object to XML in your Controller&lt;/h4&gt;

&lt;p&gt;First make sure the type you want to render is ready for XML serialization. This involves adding some attributes to classes and properties so read up on that first before you carry on. It's important to get your type serializing out in a nice way as it will be easier to work with in the XSL.&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;using System.Xml;
using System.Xml.Serialization;
...
Product prod = ProductRepository.GetProduct(id);
XmlSerializer ser = new XmlSerializer(typeof(Product));  
XmlDocument doc = new XmlDocument();
System.IO.MemoryStream ms = new System.IO.MemoryStream();
XmlWriter xw = XmlWriter.Create(ms);
ser.Serialize(xw, prod);
ms.Position = 0;
doc.Load(XmlReader.Create(ms));
RenderView("Xsl", new XslViewData(doc, "/Content/prodDetail.xsl"));&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Step 3 - Create a ViewPage or ViewUserControl to host your XSL&lt;/h4&gt;

&lt;p&gt;All you need in the aspx/ascx file is an Xml ASP.NET control...&lt;/p&gt;

&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;asp:Xml ID=&amp;quot;Xml1&amp;quot; runat=&amp;quot;server&amp;quot; onload=&amp;quot;Xml1_Load&amp;quot;&amp;gt;&amp;lt;/asp:Xml&amp;gt;&lt;/pre&gt;&lt;/code&gt;

&lt;p&gt;...and in the code behind...&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;public partial class Xsl : ViewPage&amp;lt;XslViewData&amp;gt;
{
 protected void Xml1_Load(object sender, EventArgs e)
 {
  Xml1.Document = ViewData.Doc;
  Xml1.TransformSource = ViewData.XslPath;
 }
}&lt;/pre&gt;&lt;/code&gt;

&lt;h4&gt;Step 4 - Create an XSL file&lt;/h4&gt;

&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
&amp;lt;xsl:stylesheet version=&amp;quot;1.0&amp;quot; xmlns:xsl=&amp;quot;http://www.w3.org/1999/XSL/Transform&amp;quot;&amp;gt;
    &amp;lt;xsl:output method=&amp;quot;xml&amp;quot; indent=&amp;quot;yes&amp;quot; omit-xml-declaration=&amp;quot;yes&amp;quot;/&amp;gt;
 
 &amp;lt;xsl:template match=&amp;quot;/Product&amp;quot;&amp;gt;
  &amp;lt;h2&amp;gt;&amp;lt;xsl:value-of select=&amp;quot;Name&amp;quot;/&amp;gt;&amp;lt;/h2&amp;gt;
  &amp;lt;xsl:apply-templates select=&amp;quot;Image&amp;quot;/&amp;gt;
    &amp;lt;/xsl:template&amp;gt;

 &amp;lt;xsl:template match=&amp;quot;Image&amp;quot;&amp;gt;
  &amp;lt;img&amp;gt;
   &amp;lt;xsl:attribute name=&amp;quot;src&amp;quot;&amp;gt;
    &amp;lt;xsl:value-of select=&amp;quot;ImageUrl&amp;quot;/&amp;gt;
   &amp;lt;/xsl:attribute&amp;gt;
  &amp;lt;/img&amp;gt;
 &amp;lt;/xsl:template&amp;gt;
 
 &amp;lt;xsl:template match=&amp;quot;*&amp;quot;&amp;gt;
 &amp;lt;/xsl:template&amp;gt;
 
&amp;lt;/xsl:stylesheet&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Done&lt;/h4&gt;

&lt;p&gt;Not only is this simple to implement it has a lot of scope for improvment; compiling transforms, adding caching and configuation etc. This method also has the advantage that it requires no recompile to alter the template.&lt;/p&gt;

&lt;h3&gt;Links&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.asp.net/mvc/"&gt;Official ASP.NET MVC page&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.w3schools.com/xsl/default.asp"&gt;XSL @ W3Schools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.w3schools.com/xpath/default.asp"&gt;XPath @ W3Schools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.wmhelp.com/xmlpad3.htm"&gt;XmlPad - a free XML/XSL editor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-2113068026619053841?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/BNcSfm9CfAE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/2113068026619053841/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=2113068026619053841" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/2113068026619053841?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/2113068026619053841?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/BNcSfm9CfAE/creating-views-using-xsl-in-aspnet-mvc.html" title="Creating Views using XSL in ASP.NET MVC" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/05/creating-views-using-xsl-in-aspnet-mvc.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0EFQXoyeCp7ImA9WxdSE08.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-5842342137326068661</id><published>2008-04-24T00:51:00.001+01:00</published><updated>2008-05-21T00:20:10.490+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-21T00:20:10.490+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><category scheme="http://www.blogger.com/atom/ns#" term="jQuery" /><title>Cross-browser data binding with jQuery</title><content type="html">&lt;p&gt;From version 4.0 Internet Explorer has had the ability to bind certain HTML elements to a client-side data source. Pretty much any data you can access with ADO you can use as a data source but the one we've used most commonly at work is XML. By adding some attributes to your HTML elements e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;input type="text" datasrc="#dsoComposers" datafld="compsr_last"/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;you can get them to render out the data from the data source and, in the case of inputs, persist any changes back to the source. Additionally, if you have a multi-row data source and you bind it to a table the contents of the &lt;var&gt;tbody&lt;/var&gt; tag are duplicated for each row.&lt;/p&gt;

&lt;p&gt;This is very useful for making web applications because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you only send the raw data along with a small amount of rendering HTML to the client&lt;/li&gt;
&lt;li&gt;the client edits the data, adding/deleting rows without postbacks&lt;/li&gt;
&lt;li&gt;the client posts back structured data rather than a ton of awkwardly named querystring variables&lt;/li&gt;
&lt;li&gt;you need no presentation code for translating your data to or from HTML&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All this considered I thought I'd have a go at creating a simple cross-browser version of this databinding functionality in jQuery with a limited feature set.&lt;/p&gt;

&lt;h3&gt;Features to implement&lt;/h3&gt;

&lt;p&gt;For this proof of concept I decided the features I would try and implement were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support for JSON as a data source&lt;/li&gt;
&lt;li&gt;Repeat rendering of a table's tbody section for each item in an array of objects&lt;/li&gt;
&lt;li&gt;CSS class name based way of tying properties of the objects to HTML elements&lt;/li&gt;
&lt;li&gt;Rendering of property values within HTML elements innerHTML or value&lt;/li&gt;
&lt;li&gt;Attaching of event handlers to persist data changes on inputs back to the array data source&lt;/li&gt;
&lt;li&gt;Some ability to reflect programmatic changes to the underlying data source in the bound HTML elements&lt;/li&gt;
&lt;li&gt;Doing the above without needing to fully refresh the HTML every time&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Use&lt;/h3&gt;

&lt;p&gt;Some &amp;quot;template&amp;quot; HTML...&lt;/p&gt;

&lt;pre&gt;&lt;code class="xml"&gt;    &amp;lt;table id="info"&amp;gt;
      &amp;lt;thead&amp;gt;
        &amp;lt;tr&amp;gt;
          &amp;lt;th&amp;gt;Common name&amp;lt;/th&amp;gt;  
          &amp;lt;th&amp;gt;Origin&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;First developed&amp;lt;/th&amp;gt;
          &amp;lt;th&amp;gt;Use&amp;lt;/th&amp;gt;
        &amp;lt;/tr&amp;gt;
      &amp;lt;/thead&amp;gt;
      &amp;lt;tbody&amp;gt;
        &amp;lt;tr&amp;gt;
          &amp;lt;td class="field[name]"&amp;gt;&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;&amp;lt;input type="text" class="field[origin]"/&amp;gt;&amp;lt;/td&amp;gt;
          &amp;lt;td class="field[developed]"&amp;gt;&amp;lt;/td&amp;gt;
          &amp;lt;td class="field[use]"&amp;gt;&amp;lt;/td&amp;gt;
          &amp;lt;td&amp;gt;&amp;lt;button class="field[delete]"&amp;gt;Delete Row&amp;lt;/button&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
        &amp;lt;tr&amp;gt;
          &amp;lt;td colspan="4" style="border-bottom: 2px solid #888;"&amp;gt;&amp;lt;textarea class="field[comments]" style="width: 100%;"&amp;gt;&amp;lt;/textarea&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
      &amp;lt;/tbody&amp;gt;
      &amp;lt;tfoot&amp;gt;
        &amp;lt;tr&amp;gt;
          &amp;lt;td colspan="4"&amp;gt;&amp;lt;button id="add"&amp;gt;Add Item&amp;lt;/button&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;/tr&amp;gt;
      &amp;lt;/tfoot&amp;gt;
    &amp;lt;/table&amp;gt;&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;...some data...&lt;/p&gt;


&lt;pre&gt;&lt;code class="javascript"&gt;var data = [
   { name: 'Braeburn', origin: 'New Zealand', developed: '1950s, United States', comments: '', use: 'Eating' },
   { name: 'Bramley', origin: 'Southwell, Nottinghamshire, England', developed: 'about 1809', comments: '', use: 'Cooking' },
   { name: 'Cox\'s Orange Pippin', origin: 'Great Britain, New Zealand', developed: 'c. 1829', comments: '', use: 'Eating' },
   { name: 'Empire', origin: 'New York', developed: '1966', comments: 'Lovely white subacid flesh. Tangy taste.', use: 'Eating' },
   { name: 'Granny Smith', origin: 'Australia', developed: '1868, Australia', comments: 'This is the apple once used to represent Apple Records. Also noted as common pie apple.', use: 'Eating or cooking' }
];&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;...and a small amount of JavaScript...&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;$(document).ready(function(){
   $('#info').databind(data);
});&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The add button handler looks like this...&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;data.push({ name: '', origin: '', developed: '', comments: '', use: '' });
$('#info').databind(data);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;...any code making programmatic changes to the data must recall databind to refresh the bound HTML elements.&lt;/p&gt;

&lt;h3&gt;Demo&lt;/h3&gt;

&lt;p&gt;I've set up this quick proof of concept &lt;a href="http://dfowler.geeksbox.co.uk/demos/jquery-databind/index.htm"&gt;here&lt;/a&gt;. I haven't looked at how it performs with large arrays of data but I expect the answer would be badly.&lt;/p&gt;

&lt;p&gt;Going forward there may be scope for turning this into a proper jQuery plugin with support for other types of data source and the ability to bind an arbitrary group of elements to some data rather than just a table.&lt;/p&gt;

&lt;h3&gt;Links&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms531388(vs.85).aspx"&gt;IE data binding @ MSDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.json.org/json2.js"&gt;I used the stringify function from this JSON library for the debug output&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-5842342137326068661?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/t3Ex5o3PdmQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/5842342137326068661/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=5842342137326068661" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/5842342137326068661?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/5842342137326068661?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/t3Ex5o3PdmQ/cross-browser-data-binding-with-jquery.html" title="Cross-browser data binding with jQuery" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/04/cross-browser-data-binding-with-jquery.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YNRn0-fSp7ImA9WxZWFUU.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-37992249443997063</id><published>2008-03-14T23:32:00.003Z</published><updated>2008-03-15T11:39:57.355Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-15T11:39:57.355Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Mapstraction" /><title>JSLinted and namespaced Mapstraction</title><content type="html">&lt;p&gt;I've been using &lt;a href="http://www.mapstraction.com/"&gt;Mapstraction&lt;/a&gt; in work over the past few months and now my current project has come to an end I've generated a few &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; patches of my changes, which include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSLinting the source&lt;/li&gt;
&lt;li&gt;Adding simple namespacing (read "hacking in") with backward compatibity "pollute" mode&lt;/li&gt;
&lt;li&gt;Adding ability to execute event handlers in a particular scope along with a general rework of the event implementation to allow easier extensibility&lt;/li&gt;
&lt;li&gt;Fixing several bugs with the Multimap implementation&lt;/li&gt;
&lt;li&gt;Adding new and refining existing JSDoc comments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Files&lt;/h3&gt;

&lt;p&gt;Should probably point out that I'm not part of the team that maintain Mapstraction and these aren't "official" patches. Hopefully the bug fixes at least &lt;em&gt;will&lt;/em&gt; make it back into the repository though.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://dfowler.geeksbox.co.uk/files/mapstraction/rev174 (all changes).patch"&gt;Patch for revision 174 to add all changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://dfowler.geeksbox.co.uk/files/mapstraction/rev174 (no namespacing).patch"&gt;Patch to revision 174 to add all except namespacing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://dfowler.geeksbox.co.uk/files/mapstraction/mapstraction.js"&gt;mapstraction.js  rev174 with patches applied&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Notes&lt;/h3&gt;

&lt;p&gt;The namespacing is on by default so to get it to work with an old page you do need to call mxn.activatePolluteMode() first. Additionally there are a few loose utility functions in the mapstraction file that are also within the namespacing. You can get to three of them (metresToLon, lonToMetres and loadScript) from the mxn.fn namespace so if you have been making use of those you'd have to change your code to mxn.fn.metresToLon() for example. I'm not sure which of the other functions in there people would be likely to make use of so I left it at those three to try and minimise surface area but it wouldn't be a problem to add them all to fn.&lt;/p&gt;

&lt;p&gt;There is also some backward compatibility stuff in the events implementation. I modified events so that they pass an eventArgs object rather than the arguments individually, that way the signature of all handlers is the same. This is only activated when you pass the third "scope" argument to addEventListener so old implementations should work as before either being passed no argument for move or a LatLonPoint for click.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-37992249443997063?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/fHYbJdH7y_E" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/37992249443997063/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=37992249443997063" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/37992249443997063?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/37992249443997063?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/fHYbJdH7y_E/jslinted-and-namespaced-mapstraction.html" title="JSLinted and namespaced Mapstraction" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/03/jslinted-and-namespaced-mapstraction.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkYGQXs_eip7ImA9WxZQEkQ.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-4205264373176308147</id><published>2008-02-18T01:23:00.001Z</published><updated>2008-02-18T01:28:40.542Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-18T01:28:40.542Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="PMP" /><title>Large capacity PMP roundup</title><content type="html">&lt;p&gt;After my considerable disappointment at no news of a 160GB iPod Touch from Apple at this year's Macworld I decided to have a look at what the competition is doing in the way of large capacity portable media players.&lt;/p&gt;

&lt;h3&gt;My criteria&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;40GB or greater disk&lt;/li&gt;
&lt;li&gt;3" or larger screen (preferably 16:9)&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;The contenders&lt;/h3&gt;

&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Capacity (GB)&lt;/th&gt;
&lt;th&gt;Screen (Inches)&lt;/th&gt;
&lt;th&gt;Formats&lt;/th&gt;
&lt;th&gt;Battery A/V (Hours)&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;

&lt;tr&gt;
&lt;th colspan="7"&gt;Archos&lt;/th&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;504&lt;/td&gt;
&lt;td&gt;40, 80, 160&lt;/td&gt;
&lt;td&gt;4.3"&lt;/td&gt;
&lt;td&gt;Video: MPEG-4&lt;br/&gt;Audio: MP3, WMA, WAV&lt;/td&gt;
&lt;td&gt;17/5.5&lt;/td&gt;
&lt;td&gt;£172.21, £258.99, £394.95&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;704 WiFi&lt;/td&gt;
&lt;td&gt;40, 80&lt;/td&gt;
&lt;td&gt;7"&lt;/td&gt;
&lt;td&gt;Video: MPEG-4, WMV&lt;br/&gt;
Audio: MP3, WMA, WAV&lt;/td&gt;
&lt;td&gt;25/5.5&lt;/td&gt;
&lt;td&gt;£269.99, £368.23&lt;/td&gt;
&lt;/tr&gt;


&lt;tr&gt;
&lt;td&gt;605 WiFi&lt;/td&gt;
&lt;td&gt;80, 160&lt;/td&gt;
&lt;td&gt;4.3"&lt;/td&gt;
&lt;td&gt;Video: MPEG-4, WMV&lt;br/&gt;
Audio: MP3, WMA, WAV&lt;/td&gt;
&lt;td&gt;17/5.5&lt;/td&gt;
&lt;td&gt;£214.99, £254.64&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;705 WiFi&lt;/td&gt;
&lt;td&gt;80, 160&lt;/td&gt;
&lt;td&gt;7"&lt;/td&gt;
&lt;td&gt;Video: MPEG-4, WMV&lt;br/&gt;
Audio: MP3, WMA, WAV&lt;/td&gt;
&lt;td&gt;25/5.5&lt;/td&gt;
&lt;td&gt;£269.99, £368.23&lt;/td&gt;
&lt;/tr&gt;


&lt;tr&gt;
&lt;th colspan="7"&gt;Cowon&lt;/th&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;A3&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Video: DivX, XviD, MPEG 1/2/4, WMV, H.264&lt;br/&gt;
Audio: MP3, WMA, FLAC, OGG, AAC, AC3, BSAC, True Audio, WavPack, G.726, CM&lt;/td&gt;
&lt;td&gt;25/5.5&lt;/td&gt;
&lt;td&gt;£315.95&lt;/td&gt;
&lt;/tr&gt;


&lt;tr&gt;
&lt;td&gt;Q5&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Video: DivX, XviD, MPEG4, WMV&lt;br/&gt;
Audio: MP3, WMA, ASF, OGG, WAV, FLAC, APE, MPC&lt;/td&gt;
&lt;td&gt;13/7&lt;/td&gt;
&lt;td&gt;£409.95&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;th colspan="7"&gt;iRiver&lt;/th&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;PMC-140&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;td&gt;Video: WMV&lt;br/&gt;
Audio: MP3, WMA&lt;/td&gt;
&lt;td&gt;12/5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;PMP-140&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;3.5&lt;/td&gt;
&lt;td&gt;Video: AVI, XviD, MPEG-4, MPEG-1&lt;br/&gt;
Audio: MP3, WMA, WAV, ASF&lt;/td&gt;
&lt;td&gt;10/5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Archos have the most players meeting the criteria with large disk versions up to 160GB however they are let down by poor codec support although you can add support for more by downloading them from their website (at extra cost).&lt;/p&gt;

&lt;p&gt;The two Cowon players offer an impressive list of codecs out-of-the-box but they only come in a maximum 60 gigabyte version and are a lot more expensive than in particular the Archos players.&lt;/p&gt;

&lt;p&gt;The iRiver players have small disks, small screens and poor codec support but I couldn't find anywhere stocking them anyway so it looks like I couldn't buy one even if I were interested.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;The Archos players definitely seem to be the best deal if you're not bothered about having support for a large number of codecs. One big criticism of them however is that, looking at the overview of for example the 605 WiFi on the &lt;a href="http://www.archos.com/products/gen_5/archos_605wifi/index.html"&gt;Archos site&lt;/a&gt;, it seems like you're getting loads of features for your money. Reading the small print, however, will tell you that to use some of them you need to buy optional add-ons and they're not cheap. The DVR dock for recording TV is an extra £60, the web browser is £20, the Video podcast plug-in (read iPod compatibility pack featuring H.264 and AAC codecs) is £15! I'm surprised they are allowed to sell the product based on features it doesn't have out of the box and it certainly puts a sting in the tail of the good deal.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-4205264373176308147?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/P1i8z8txC9I" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/4205264373176308147/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=4205264373176308147" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/4205264373176308147?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/4205264373176308147?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/P1i8z8txC9I/large-capacity-pmp-roundup.html" title="Large capacity PMP roundup" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/01/large-capacity-pmp-roundup.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0ADQ3w4fyp7ImA9WxdSE08.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-3998373714692186399</id><published>2008-02-16T15:43:00.003Z</published><updated>2008-05-21T00:22:52.237+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-21T00:22:52.237+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Visual Web Developer" /><category scheme="http://www.blogger.com/atom/ns#" term="NHibernate" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>NHibernate in Visual Web Developer Express</title><content type="html">&lt;p&gt;If you fancy using &lt;a href="http://www.nhibernate.org"&gt;NHibernate&lt;/a&gt; in &lt;acronym title="Visual Web Developer"&gt;VWD&lt;/acronym&gt; you'll have trouble because you can't compile your mapping files into the same assembly as your classes. As a result you can't add mappings to your session factory by assembly name or class name.&lt;/p&gt;

&lt;p&gt;Thankfully there is a simple solution to this, which I'll demonstrate with the aid of the &lt;a href="http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/quickstart.html"&gt;quickstart example&lt;/a&gt; in the NHibernate documentation.&lt;/p&gt;

&lt;p&gt;Start by creating all your persistance class files in your App_Code folder with your mapping files (.hbm.xml) alongside. Next, make the alterations to your &lt;var&gt;web.config&lt;/var&gt; as outlined in section 1.1 of the quickstart but leave out this line:&lt;/p&gt;

&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;mapping assembly="QuickStart" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In your mapping files, change the &lt;var&gt;assembly&lt;/var&gt; attribute of the root &lt;var&gt;hibernate-mapping&lt;/var&gt; element to "App_Code" and remove the &lt;var&gt;namespace&lt;/var&gt; attribute if you're not using a namespace (the default behaviour of &lt;acronym title="Visual Web Developer"&gt;VWD&lt;/acronym&gt;) e.g:&lt;/p&gt;

&lt;pre&gt;&lt;code class="xml"&gt;&amp;lt;hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="App_Code"&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, copy the code for the NHibernateHelper class from &lt;a href="http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/quickstart.html#quickstart-playingwithcats"&gt;section 1.4&lt;/a&gt; and change its constructor from this:&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;static NHibernateHelper()
{
   sessionFactory = new Configuration().Configure().BuildSessionFactory();
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to this:&lt;/p&gt;

&lt;pre&gt;&lt;code class="c#"&gt;static NHibernateHelper()
{
   Configuration cfg = new Configuration().Configure();
   cfg.AddDirectory(new System.IO.DirectoryInfo(HttpContext.Current.Server.MapPath(@"~/App_Code/")));
   sessionFactory = cfg.BuildSessionFactory();
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The original constructor used the &lt;var&gt;mapping&lt;/var&gt; element in the web.config to find out which mappings to load, here we're telling it to load all the mapping files it finds in the App_Code folder. You can also use the &lt;var&gt;AddFile&lt;/var&gt; method to add individual mapping files.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-3998373714692186399?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/SmMr6uSSmbM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/3998373714692186399/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=3998373714692186399" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/3998373714692186399?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/3998373714692186399?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/SmMr6uSSmbM/nhibernate-in-visual-web-developer.html" title="NHibernate in Visual Web Developer Express" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/02/nhibernate-in-visual-web-developer.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEADRnc8cCp7ImA9WxRbGU0.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-5399825658159256145</id><published>2008-02-09T23:03:00.000Z</published><updated>2008-12-10T10:59:37.978Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-12-10T10:59:37.978Z</app:edited><title>Merge with "How to Code"</title><content type="html">&lt;p&gt;Initially I thought it was a good idea to write separate blogs because people interested in gadgets and codecs aren't necessarily interested in code and databases.&lt;/p&gt;

&lt;p&gt;I've since realised three things; that the target audiences were pretty much the same, that dividing my traffic was a bad idea and that I don't really have enough to say or the time to fill two blogs.&lt;/p&gt;

&lt;p&gt;So, having just finished copying all the posts over from Derek's How to Code, I'll be deleting it and maintaining just the one from now on.&lt;/p&gt;

&lt;p&gt;What a shame I never got to use this snazzy bit of artwork...&lt;/p&gt;

&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://1.bp.blogspot.com/_EuFsZMY5ZNU/R640undmJWI/AAAAAAAAAVc/FpOtcLWyyrM/s400/how-to-code.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5165123798112281954" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-5399825658159256145?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/ZbmKGYsu_Mg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/5399825658159256145/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=5399825658159256145" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/5399825658159256145?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/5399825658159256145?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/ZbmKGYsu_Mg/merge-with-how-to-code.html" title="Merge with &quot;How to Code&quot;" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_EuFsZMY5ZNU/R640undmJWI/AAAAAAAAAVc/FpOtcLWyyrM/s72-c/how-to-code.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/02/merge-with-how-to-code.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkcBRXw8fSp7ImA9WxZRFUU.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-7430083771597466295</id><published>2008-01-18T00:32:00.000Z</published><updated>2008-02-09T19:07:34.275Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-09T19:07:34.275Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="VBScript" /><category scheme="http://www.blogger.com/atom/ns#" term="XML" /><category scheme="http://www.blogger.com/atom/ns#" term="MSXML" /><title>Processing instructions and Microsoft XML DOM</title><content type="html">&lt;p&gt;If you're using Microsoft's XML DOM you'll find it strips out the encoding attribute from your processing instruction (the &amp;lt;?xml ... ?&amp;gt; bit) when you get the value of the &lt;var&gt;Xml&lt;/var&gt; property. This is because it always returns unicode regardless of what the input encoding was. As unicode is the default for the XML specification, no encoding attribute is required.&lt;/p&gt;

&lt;p&gt;The &lt;var&gt;Save&lt;/var&gt; method, which writes the contents of the DOM document to a file, maintains the original encoding. If you need your XML in the original encoding after some manipulation in the DOM then you can do this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;xmldoc.Save(&amp;quot;c:\blah.xml&amp;quot;)
Set fs = Server.CreateObject(&amp;quot;Scripting.FileSystemObject&amp;quot;)
Set ts = fs.OpenTextFile(&amp;quot;c:\blah.xml&amp;quot;)
strXml = ts.ReadAll&lt;/code&gt;&lt;/pre&gt;


&lt;h3&gt;Programmatically changing a processing instruction&lt;/h3&gt;

&lt;p&gt;Looks a bit dodgy but this is the way to do it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Set pi = xmldoc.createProcessingInstruction(&amp;quot;xml&amp;quot;, &amp;quot;version=&amp;quot;&amp;quot;1.0&amp;quot;&amp;quot; encoding=&amp;quot;&amp;quot;UTF-16&amp;quot;&amp;quot;&amp;quot;)
xmldoc.replaceChild pi, xmldoc.childNodes.Item(0)&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-7430083771597466295?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/DepPfUzzjeQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/7430083771597466295/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=7430083771597466295" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/7430083771597466295?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/7430083771597466295?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/DepPfUzzjeQ/processing-instructions-and-microsoft.html" title="Processing instructions and Microsoft XML DOM" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/01/processing-instructions-and-microsoft.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkcFSH46eCp7ImA9WxZRFUU.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-1012032915800659322</id><published>2008-01-12T20:16:00.000Z</published><updated>2008-02-09T19:06:59.010Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-09T19:06:59.010Z</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Mapstraction" /><title>Mapstraction "to do" list</title><content type="html">&lt;p&gt;I've been using &lt;a href="http://mapstraction.com"&gt;Mapstraction&lt;/a&gt; to implement draggy maps in our platforms at work for the past month or so and thought I'd share some of the problems I came across so, should you decide to do the same, you know what to watch out for. The issues I've come across below I've fixed for the APIs with which I was working and I'll be submitting the changes back to the project in the near future.&lt;/p&gt;

&lt;p&gt;I should say first that Mapstraction is an awesome piece of work that frees you from having to commit to one mapping provider. When clients don't want to pay for maps so you give them Google and then change their mind when Google start inserting advertisements, all you have to do is change one line of code.&lt;/p&gt;

&lt;h3&gt;The List&lt;/h3&gt;

&lt;h4&gt;1. Patchy implementations&lt;/h4&gt;

&lt;p&gt;Mapstraction abstracts the lowest common denominator set of functionality for its supported APIs. I've been working primarily with Multimap and have discovered that, for this API at least, some &lt;a href="http://mapstraction.com/doc/"&gt;API classes&lt;/a&gt; are missing methods or have non-working implementations.&lt;/p&gt;

&lt;p&gt;In the Multimap case this is just a few methods here and there but the thing I found annoying was that, rather than the method just being empty or throwing a "not implemented" exception, the method was populated with the code for one of the other APIs.&lt;/p&gt;


&lt;h4&gt;2. Incomplete events&lt;/h4&gt;

&lt;p&gt;The only events catered for by Mapstraction are "move end" and "click" which is severely limiting considering the vast array of events available through the native APIs. Events like "zoom", "open bubble", "change map type" etc aren't there.&lt;/p&gt;

&lt;p&gt;Arguably, abstracting events is probably the most difficult part of the process as you have to take into account differences in when similar events fire, orders that they fire and event arguments that are passed back to the handler.&lt;/p&gt;

&lt;p&gt;The event implementation for the two events also doesn't cater for overriding the scope in which the handler function is to be executed via the &lt;var&gt;call&lt;/var&gt; method which is essential if you're working with methods of JavaScript objects.&lt;/p&gt;


&lt;h4&gt;3. No namespacing or prefixing&lt;/h4&gt;

&lt;p&gt;The Mapstraction code is not namespaced, scoped or prefixed in any way so is dangerous when used with a lot of JavaScript code from different sources as you'll likely end up with name clashes and global variables being overwritten.&lt;/p&gt;

&lt;h4&gt;4. No standards enforced on the source code&lt;/h4&gt;

&lt;p&gt;There appear to be no coding standards enforced on the source. It's full of undelared variables, dodgy constructs and some bits that just aren't formatted well, making the code difficult to follow.&lt;/p&gt;

&lt;p&gt;The likes of Yahoo! run all their code through JSLint before it goes anywhere near deployment and with a library of this type I think at least a loose Linting is a must.&lt;/p&gt;


&lt;h3&gt;To sum up&lt;/h3&gt;

&lt;p&gt;If your integration is complex and requires a lot of event handling and dynamic manipulation of the map artifacts then Mapstraction isn't quite there yet but for most other things it's worth filling in any holes yourself for that freedom of API.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-1012032915800659322?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/hMe9v9kFLF4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/1012032915800659322/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=1012032915800659322" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/1012032915800659322?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/1012032915800659322?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/hMe9v9kFLF4/mapstraction-to-do-list.html" title="Mapstraction &quot;to do&quot; list" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2008/01/mapstraction-to-do-list.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UERH04cSp7ImA9WxdSE08.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-4121607270808266822</id><published>2007-12-24T00:36:00.000Z</published><updated>2008-05-21T00:13:25.339+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-21T00:13:25.339+01:00</app:edited><title>What Hi-Fi disappoint on Lossless</title><content type="html">&lt;p&gt;In the Sound Advice section of the Jan 2008 issue of What Hi-Fi a reader asks what the best portable player and file format is for maximising digital audio quality. The response is essentially buy an iPod and use Apple Lossless. Whilst I agree the iPod's audio hardware is very good, I don't think its virtually proprietary encoding algorithm is something What Hi-Fi should be encouraging people to use.&lt;/p&gt;

&lt;p&gt;They later go on to say that you could buy a device from Creative and use "one of the other lossless formats" but they don't give any examples of other formats or mention that the only lossless formats the current Creative products support are WMA (Microsoft Lossless) and AAC (Apple Lossless).&lt;/p&gt;

&lt;p&gt;All in all I'm disappointed that a magazine that professes to be unbiased and impervious to the corporates is so casual about recommending proprietary formats which facilitate consumer lock-in. In my opinion they should be promoting the open source formats and marking the products they review down for only supporting propretary technologies. Decreasing consumer choice is, after all, a negative factor and the corporates shouldn't be allowed to get away with it.&lt;/p&gt;

&lt;p&gt;On the plus side, from 31st Dec, 7 Digital will be offering Radiohead's In Rainbows in FLAC format &lt;a href="http://www.7digital.com/in-rainbows"&gt;click here for more&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-4121607270808266822?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/jJBYQfp9XjM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/4121607270808266822/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=4121607270808266822" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/4121607270808266822?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/4121607270808266822?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/jJBYQfp9XjM/what-hi-fi-disappoint-on-lossless.html" title="What Hi-Fi disappoint on Lossless" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2007/12/what-hi-fi-disappoint-on-lossless.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UCQ3g-eip7ImA9WxdSE08.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-3725132541341370725</id><published>2007-12-10T19:39:00.000Z</published><updated>2008-05-21T00:14:22.652+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-21T00:14:22.652+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript" /><title>Reference types in prototype declaration - JavaScript gotcha</title><content type="html">&lt;p&gt;I've recently started doing some heavy duty JavaScript, including messing around with constructors, prototypes, lamdas, closures etc. I started off creating a few classes by creating a constructor function and then defining its prototype using object-literal notation as it means your code looks quite like class declarations in other OO languages.&lt;/p&gt;

&lt;p&gt;Here is a simple example without any methods, just with two member variables:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function MyClass(){}
MyClass.prototype = {
 iNum: 0,
 sStr: 'Derek'
};

var oA = new MyClass();
var oB = new MyClass();

// oA: iNum -&gt; 0, sStr -&gt; Derek
// oB: iNum -&gt; 0, sStr -&gt; Derek

oA.iNum++;
oA.sStr += ' Fowler';

// oA: iNum -&gt; 1, sStr -&gt; Derek Fowler
// oB: iNum -&gt; 0, sStr -&gt; Derek&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All seems well, however, upon adding some reference types to the prototype things get a bit strange:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;//...

MyClass.prototype = {
 iNum: 0,
 sStr: 'Derek',
 aAry: []
};

//...

// oA: aAry.length -&gt; 0
// oB: aAry.length -&gt; 0

oA.aAry.push('test');

// oA: aAry.length -&gt; 1
// oB: aAry.length -&gt; 1&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Adding an element to aAry of oA has added it to oB's aAry too. "Odd", I thought, so I did a little more investigation:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// MyClass.prototype.aAry.length -&gt; 1&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The array property of the instances is pointing back to the property of the prototype. In other OO languages all member variables within the class declaration are copied into the instances, it is only static variables and method implementations that are shared between them. These JavaScript variables seem to be neither member nor static, they are member if value types and static if reference types. Next I tried looping though the properties and testing hasOwnProperty:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;for(var sProp in oA){
 // oA.hasOwnProperty(sProp)
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Before the assignments all the properties return false, that they are not member properties but reside within the prototype. Following the assignment however iNum and sStr return member and only aAry still claims to be prototype.&lt;/p&gt;

&lt;p&gt;This behaviour isn't a bug in an implementation either, it is consistant in all the browsers but after having a quick look in the ECMA-262 doc i'm still none the wiser about why this is the case. Anyone who can shed light on this please comment below.&lt;/p&gt; 

&lt;h3&gt;The solution&lt;/h3&gt;

&lt;p&gt;The solution to this is to create all member variables using the &lt;var&gt;this&lt;/var&gt; keyword in the class constructor thus:&lt;/p&gt; 

&lt;pre&gt;&lt;code&gt;function MyClass(){
 this.aAry = [];
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This ensures that the variable is created upon the new instance and you don't get any sharing problems.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-3725132541341370725?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/NEH--kc3vjs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/3725132541341370725/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=3725132541341370725" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/3725132541341370725?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/3725132541341370725?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/NEH--kc3vjs/reference-types-in-prototype.html" title="Reference types in prototype declaration - JavaScript gotcha" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2007/12/reference-types-in-prototype.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkIBRXoyfip7ImA9WxZRFk0.&quot;"><id>tag:blogger.com,1999:blog-36201586.post-961002090907119433</id><published>2007-10-27T01:30:00.000+01:00</published><updated>2008-02-09T23:42:34.496Z</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-02-09T23:42:34.496Z</app:edited><title>ALA Web Design Survey 2007 Results</title><content type="html">&lt;p&gt;The results from this year's A List Apart Survey of Web Design Professionals are in.&lt;/p&gt;

&lt;p&gt;The findings are in an &lt;a href="http://www.alistapart.com/d/2007surveyresults/2007surveyresults.pdf"&gt;82 page PDF&lt;/a&gt; which makes some interesting reading. You can also get an anonymised version of  &lt;a href="http://www.alistapart.com/d/2007surveyresults/2007webdesignsurvey.csv.zip"&gt;the 33,000 raw responses&lt;/a&gt; if you want to do some number crunching of your own.&lt;/p&gt;

&lt;h3&gt;Links&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://alistapart.com/articles/webdesignsurvey"&gt;ALA Web Design Survey 2007&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.alistapart.com/articles/2007surveyresults"&gt;ALA Web Design Survey 2007 Results&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36201586-961002090907119433?l=derek-says.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/DerekSays/~4/JSEmne0LXcU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://derek-says.blogspot.com/feeds/961002090907119433/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=36201586&amp;postID=961002090907119433" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/961002090907119433?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36201586/posts/default/961002090907119433?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/DerekSays/~3/JSEmne0LXcU/ala-web-design-survey-2007-results.html" title="ALA Web Design Survey 2007 Results" /><author><name>Derek Fowler</name><uri>http://www.blogger.com/profile/09963865123124577525</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="01005108689222898985" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://derek-says.blogspot.com/2007/10/ala-web-design-survey-2007-results.html</feedburner:origLink></entry></feed>
