<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-28989665</id><updated>2011-09-28T17:34:53.764Z</updated><category term='developing for mobile devices'/><category term='xaml'/><category term='user account'/><category term='SQL'/><category term='Tillison'/><category term='bug fix'/><category term='uber code'/><category term='MSDeploy'/><category term='insert'/><category term='draggable'/><category term='query'/><category term='stateful web'/><category term='WF'/><category term='Charity'/><category term='IQueryable'/><category term='Approach'/><category term='Linq to SQL'/><category term='Compsoft'/><category term='Joel'/><category term='Oredev'/><category term='Marketing'/><category term='PDF Sharp'/><category term='interactivity'/><category term='windows mobile'/><category term='sql ce'/><category term='dictionary attack'/><category term='.NET 2.0'/><category term='.NET 3.5'/><category term='IE7'/><category term='LINQ'/><category term='MSSQL'/><category term='jQuery'/><category term='MySQL'/><category term='multiuser'/><category term='google maps'/><category term='PDF'/><category term='security'/><category term='TechEd 2007'/><category term='IEnumerable'/><category term='Code Contracts'/><category term='SQL Server 2005'/><category term='.NET 3.0'/><category term='IE Bug'/><category term='Digital Natives'/><category term='IIS'/><category term='C#.NET'/><category term='CardSpace'/><category term='microformats'/><category term='Orcas'/><category term='Neil Bostrom'/><category term='Jeanes'/><category term='iPhone'/><category term='Firefox'/><category term='JSONP'/><category term='TSFS'/><category term='UNIX TIME'/><category term='TechEd 2006'/><category term='Cross site'/><category term='Richard Thomason'/><category term='Sync Framework'/><category term='xelement'/><category term='asp.net'/><category term='pear'/><category term='IIS7'/><category term='Methodology'/><category term='Entity Framework'/><category term='.NET'/><category term='UNIX EPOCH'/><category term='Vista'/><category term='Browzar'/><category term='Team Foundation Server'/><category term='Microsoft'/><category term='MVC'/><category term='Bostrom'/><category term='javascript'/><category term='BLINQ'/><category term='Tim Jeanes'/><category term='W3C'/><category term='AJAX'/><category term='SOA'/><category term='concurrent'/><category term='Workflow foundation'/><category term='TechEd 2008'/><category term='plugin'/><category term='displaying error message'/><category term='Equinox'/><category term='Kanban'/><category term='WPF/E'/><category term='Silverlight 3'/><category term='Visual C#'/><category term='business objects'/><category term='new id'/><category term='Tubby'/><category term='.net implementation'/><category term='debug'/><category term='hack'/><category term='Ross'/><category term='RenderMode'/><category term='SQL Server 2008'/><category term='login'/><category term='php'/><category term='Rich Internet Applications'/><category term='Carter'/><category term='website'/><category term='Lenton'/><category term='web services'/><category term='ADO.NET'/><category term='xdocument'/><category term='geocode'/><category term='TechED 2009'/><category term='Work Culture'/><category term='Webservice'/><category term='website development'/><category term='Burfield'/><category term='SEO'/><category term='WCF'/><category term='.NET 4.0'/><category term='MIGRATIING'/><category term='data access'/><category term='log'/><category term='Tristan Smith'/><category term='viewstate'/><category term='Archetecting Silverlight'/><category term='iPad'/><category term='DLINQ'/><category term='WPF'/><category term='password'/><category term='UpdatePanels'/><category term='WiFi'/><category term='Silverlight'/><title type='text'>The blog of the software development team at Compsoft</title><subtitle type='html'>In creating bespoke software solutions, websites and custom solutions, our developers come across problems. In this blog they discuss issues experienced and how they got around them. As Microsoft Gold Certified Partners our developers go to the TechEd and other conferences - read about their experiences and thoughts on emerging technologies!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default?start-index=101&amp;max-results=100'/><author><name>Phil Lenton</name><uri>http://www.blogger.com/profile/03854036326283622134</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>128</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-28989665.post-2265044769879963547</id><published>2010-11-13T10:43:00.003Z</published><updated>2010-11-13T10:50:52.896Z</updated><title type='text'>Øredev 2010 - Day 5 - Tristan Smith</title><content type='html'>&lt;h3&gt;Ten Big Holes - Software for the Next 20 years - Nolan Bushell (Founder of Atari)&lt;/h3&gt;Nolan covered some really interesting futures such as Auto Cars, a future without credentials, nanobots, augmented realities and swarms.&lt;br /&gt;&lt;h3&gt;My last 30 failures and what I've learned so far - Ted Valentin&lt;/h3&gt;Ted Valentin gave us a decent talk covering his path into software development and covering some of the lessons he'd learned.&lt;br /&gt;He talked about how success and failure are both parts of the same coin.&lt;br /&gt;He cited some indy successes with Plenty of Fish, Million dollar homepage and Chat Roulette.&lt;br /&gt;The success criteria he covered:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It should be quick and easy to build, &lt;/li&gt;&lt;/ul&gt;Make use of Facebook login, Twitter integration, Flickr images, RSS, APIs and open data to make it easy to buiild.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Simple to maintain &lt;/li&gt;&lt;li&gt;Easy to make money &lt;/li&gt;&lt;/ul&gt;Using Google Adsense, Affiliates (Plenty of Fish, Tradedoubler), Freemium, Selling (other peoples) things, Partners, Sell the site.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Easy to get visitors &lt;/li&gt;&lt;/ul&gt;Use Google, make your site good link bait, use good keywords, give it a long tail, prefer low keyword competition, aim for low bounce rates. Make use of Google Trends to find the right keywords, Social networks, Piggybacking on popular services, Returning visitors (email), Blog widgets, iPhone, Referrals, PR&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Fills a need &lt;/li&gt;&lt;/ul&gt;He gave some examples where not following these resulted in fails:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Making a site focussed on an unsearched for keyword. &lt;/li&gt;&lt;li&gt;Making it too hard for visitors (making them work when they reach your site) leads to high bounce rate. &lt;/li&gt;&lt;li&gt;Not making the site monetisable leads to less investment. Geographic site for used books, not needed. &lt;/li&gt;&lt;li&gt;Not having a deadline, either GTD throw it out or set a launch party to get social pressure to make you do it. &lt;/li&gt;&lt;/ul&gt;The bottom line was that It's fine to fail, it's better to fail fast and cheap.&lt;br /&gt;&lt;h3&gt;97 Things Every Programmer Should Know - Kevlin Henley&lt;/h3&gt;An open source crowd sourced compilation of collective wisdom from the Experts. Why 97? Strong prime? nope, because it's not quite 100, it's not trying too hard. &lt;br /&gt;Deliberate practice to master the task, not complete the task(Katas) - Jon Jagger&lt;br /&gt;Estimates negotiated to Targets which is made into a commitment - a promise to deliver specific functionality to a certain level of quality by a certain date.&lt;br /&gt;Kevlin only managed to cover a few of the points in the book, well worth getting.&lt;br /&gt;&lt;h3&gt;Social Media and Personal Branding as Project Leadership Tools - Dave Prior&lt;/h3&gt;In 15 words or less, describe your brand.&lt;br /&gt;What does this say about your promise of value?&lt;br /&gt;Think about your persona - the mask you wear to portray a definite impression and conceal your true nature.&lt;br /&gt;Putin is a good example of this, holiday photos all show a beefy masculine character, showing strength.&lt;br /&gt;Define your brand that will enable you to stand out and make sure that you can live up to it. Be consistent with it or people will lose trust in it.&lt;br /&gt;&lt;strong&gt;Sender Receiver Model&lt;/strong&gt;&lt;br /&gt;Sender &amp;gt; Encoding &amp;gt; Message - Noise - (Encoding can be a bad mood making your message change)&lt;br /&gt;How are you encoding the message of your brand?&lt;br /&gt;Be interested and be interesting, this is key to social media.&lt;br /&gt;&lt;strong&gt;4 types of social media users&lt;/strong&gt;&lt;br /&gt;1. Carefree / Careless (detracts from your brand if you say inane things)&lt;br /&gt;2. Noise Makers (Look at me)&lt;br /&gt;3. Barkers (Associative or braggers - Not engaging)&lt;br /&gt;4. Strategic / Tactical users &lt;br /&gt;Your digital footprint is your new permanent record. You have to consider this when you're posting online. Would I want anyone to be able to see this in 10 years? Make sure it's something you can wear, use and maintain without being excessively protective about it.&lt;br /&gt;Social Tokens - The Fawn Liebowitz Experiment - Using core references to find people on the same wavelength to skip straight to trust. Something people have an emotional tie to. Eases communication flow, establishing more than just a common interest, forms a deeper bond by finding joined ownership to tribes.&lt;br /&gt;There's no award for volume, in fact too much can dull your message.&lt;br /&gt;&lt;h3&gt;The 9 Reasons you're not apprenticing anyone - Dave Hoover&lt;/h3&gt;"Today we have more developers than needed, but we have a shortage of good developers". Pete McBreen&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Your company won't let you&lt;/strong&gt;&amp;nbsp;Your company can't stop you, it doesn't have to be a full apprenticeship 'program'. It could just be grabbing lunch together. &lt;/li&gt;&lt;li&gt;&lt;strong&gt;You don't like your job&lt;/strong&gt;&amp;nbsp;Change your job or change jobs, work on it, introduce change, challenge people. &lt;/li&gt;&lt;li&gt;&lt;strong&gt;You're too busy&lt;/strong&gt;&amp;nbsp;You've got things to take care of before you can build in time for apprenticeship. Take control! &lt;/li&gt;&lt;li&gt;&lt;strong&gt;You're a road warrior&lt;/strong&gt;&amp;nbsp;Leave assignments, just because it's not ideal doesn't stop it being possible. &lt;/li&gt;&lt;li&gt;&lt;strong&gt;You're independent&lt;/strong&gt;&amp;nbsp;Feels like way too much responsibility. Contract with options to hire and defined milestones makes it easier in this case. Leave a legacy. &lt;/li&gt;&lt;li&gt;&lt;strong&gt;You're not good enough&lt;/strong&gt; Yes you are, you don't need to be the ultimate master of a subject to get started down the path. &lt;/li&gt;&lt;li&gt;&lt;strong&gt;You can't find any apprentices&lt;/strong&gt;&amp;nbsp;Keep looking! Check the user groups they're full of passionate people. &lt;/li&gt;&lt;li&gt;&lt;strong&gt;You don't like to mentor&amp;nbsp;&lt;/strong&gt;&amp;nbsp;Even if you don't want to do it yourself, try to be gentle, don't stop others from trying. &lt;/li&gt;&lt;li&gt;&lt;strong&gt;You don't believe in it. &lt;/strong&gt;(Gave some examples where it really worked) &lt;/li&gt;&lt;/ol&gt;&lt;strong&gt;Tips&lt;/strong&gt;&lt;br /&gt;Start small, incrementally, do retrospectives.&lt;br /&gt;Pair programming, pet projects with milestones and code reviews&lt;br /&gt;&lt;h3&gt;True Tales of the App Store Making iPhone Apps for profit - Jack Nutting&lt;/h3&gt;Some points form his talk:&lt;br /&gt;Cheaper apps attract more haters.&lt;br /&gt;Reducing price can often decrease ratings.&lt;br /&gt;The structure of the App store means it's a hit driven economy, you can see flocking behaviour as a result.&lt;br /&gt;Apple has a number of methods of raising the focus on an app (Staff Picks, Themes etc).&lt;br /&gt;&lt;strong&gt;Ways of making money&lt;/strong&gt;&lt;br /&gt;In app purchases, lite versions, iAds + competitors.&lt;br /&gt;Build free apps that help people use your own business.&lt;br /&gt;Gameify dull activities.&lt;br /&gt;&lt;br /&gt;If you're going to be a copy cat, add something extra.&lt;br /&gt;People love stories, no matter how stupid, work them into your games.&lt;br /&gt;Updates can increase popularity and increase value (Doodle Bug, Pocket God)&lt;br /&gt;Eliminate Choice - Make your app as simple as possible but not simpler - modified Einstein quote.&lt;br /&gt;&lt;br /&gt;Market while coding, find enthusiasts and give them sneak peaks.&lt;br /&gt;Work your social networks.&lt;br /&gt;Issue a press release.&lt;br /&gt;&lt;h3&gt;Øredev Conclusions&lt;/h3&gt;Having attended Tech Ed in previous years due to our focus on .NET technologies, we've changed our focus more towards mobile development in general. This means we've hit Android, BlackBerry, iPhone and Windows Phone 7.&lt;br /&gt;Øredev has up to 8 tracks going on simultaneously with tracks from below:&lt;br /&gt;Java | .NET | Smart Phones | Patterns | Social Media | Agile | Software Craftmanship | Xtra (non coding related extras) | Architecture | Cloud &amp;amp; Nosql | Realizing Business Ideas&lt;br /&gt;The sheer amount of options is quite daunting at first but it really does expose you toa lot of useful content that you just wouldn't find at a domain / technology focussed conference.&lt;br /&gt;One of the biggest takeaways for us has been around process.&lt;br /&gt;Working across so many different technologies and projects at the same time has an overhead in management, one that we've managed so far using Scrum. Scrum's a great methodology but it isn't quite as flexible as we sometimes need it to be, in Scrum you'd choose a number of tasks from the backlog for a sprint and not deviate from it. We do sometimes have emergency work and rush jobs that can't wait until the next sprint. This can be a real pain when you have to keep half heartedly adopting a methodology.&lt;br /&gt;Kanban is a more flexible methodology that both Tim and I have mentioned in the blog so far, we saw a lot of sessions on it. We're both convinced it has the right managerial qualities as well as psychological benefits to suit us really well.&lt;br /&gt;I really hope you've enjoyed hearing about the sessions we've been to, Øredev is a great conference one I can wholeheartedly recommend. Bring on Øredev 2011!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-2265044769879963547?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/2265044769879963547/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=2265044769879963547' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/2265044769879963547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/2265044769879963547'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/11/redev-2010-day-5-tristan-smith.html' title='Øredev 2010 - Day 5 - Tristan Smith'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_gPRWTjkTHUU/SRY7HZpOTSI/AAAAAAAAAAM/OAQvr_kigYM/S220/tree-thumb.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7165693684200685120</id><published>2010-11-13T10:41:00.002Z</published><updated>2010-11-13T10:42:19.552Z</updated><title type='text'>Øredev 2010 - Day 4 - Tristan Smith</title><content type='html'>&lt;h3&gt;Patterns of Parallel Programming - Ade Miller (MS Patterns and Programming)&lt;/h3&gt;We've reached the end of the free lunch, processing power and other computing metrics have stopped following Moores law, more cores are being added but they're not actually faster, there are just more of them.&lt;br /&gt;This makes parallel programming all the more important, as we add more cores that serial programming just leaves unused. This makes the work Microsoft have done to make parallel programming easier with the Task Parallel Library (TPL) in .NET 4.&lt;br /&gt;Ade illustrated the problem with a Stock market analysis program.&lt;br /&gt;He pointed out that there are a number of things that block parallelism in your code.&lt;br /&gt;You have to consider IO read/write constraints, actions that have fixed dependencies that impose a required order, that you're targetting items that take most time.&lt;br /&gt;The TPL gives you Factory.StartNew, ContinueWith (To pass data from another task), ContinueWhenAll lets you specify a number of other tasks, ParallelFor lets you iterate in parallel (though you lose the index).&lt;br /&gt;&lt;strong&gt;Ramblings&lt;/strong&gt;&lt;br /&gt;Think about Tasks vs Data, Control Flow, Control and Data Flow&lt;br /&gt;When dividing up parallelisable tasks the size of the data chunks has issues where if you make it too big you underutilise whereas too small you thrash.&lt;br /&gt;Using the ThreadPool is making use of the scheduler that focuses on making use of the available resources, the TPL uses a scheduler itself as seen with ContueWhen.&lt;br /&gt;It's important to check that the tasks taking the time are the ones you're targeting to parallelise. Making sure there's business value that's focussed on, don't do it for the sake of it.&lt;br /&gt;With Parallel.For because you can't do index incrementing parallel code, you have to factor that into the code you run.&lt;br /&gt;Calculating totals for example requires an overloaded Parallel.For where each method calculates a subtotal and the grand total is calculated afterwards with a lock on the value being added to.&lt;br /&gt;Parallel tasks can't really use shared state, you get locking issues so when shariing state, if possible don't share at all, use read only data, synchronise afterwards.&lt;br /&gt;You can consider running parallel tasks to see which the fastest result to come back, then using Cancel and Task.WaitAll to cancel the other running tasks.&lt;br /&gt;BlockingCollection - Reading in a file line by line, adding the lines to the blocking collection such that the processing of each item can be parallel where the collection can't be.&lt;br /&gt;Don't just rewrite your loops, figure out what your users want and what's actually taking the time.&lt;br /&gt;Architect for Parallelism.&lt;br /&gt;&lt;h3&gt;In the clouds with the RX framework - Glenn Block&lt;/h3&gt;We're increasingly designing our systems to accommodate latency which is an increasing trend now our code is running in the cloud. RX is a handy tool for this..&lt;br /&gt;RX is a library for composing asynchronous and event-based programs using observable collections. Systems where data is constantly coming in and it needs to be reacted to.&lt;br /&gt;You can do this already, but this is currently really hard. We tend to work with collections in a pull based model, iterating - give me the next, which is blocking. This can mean locked programs that become non responsive.&lt;br /&gt;The key interfaces to make use of it are IObservable + IObserver which give you Subscribe and OnNext, OnError, OnComplete meaning you're reacting to, not controlling the flow.&lt;br /&gt;It's reactive rather than interactive.&lt;br /&gt;Perception is reality, users faced with hangs and slow updating data, believe that's what the app is.&lt;br /&gt;You need to be aware that if you're not using a true observable , you're not going to see the asynchronous behaviour. For example Enumerable.Range(0, 3).ToObservable() would be running synchronously.&lt;br /&gt;RX is available in WPF, Silverlight Toolkit and WP7.&lt;br /&gt;You can choose what thread to observe on, for example observing a textbox keyup event.&lt;br /&gt;Throttling by time, filtering of which events to observe. Google Translate example.&lt;br /&gt;They're working on new Async features that work with the RX framework and interestingly LINQ to Objects in JavaScript..&lt;br /&gt;&lt;h3&gt;ASP.NET MVC 3 - Brad Wilson&lt;/h3&gt;A whistle stop tour of the new features of MVC3. New pluggable view engines like Razor, HTML 5 default templates, integration with jQuery validate, Nuget (automatic installation and dependency filling), DI and IOC injection hooks, global filters and more granular request validation (so individual properties can be marked as ValidateInput(false) to allow HTML content through) and a bunch more.&lt;br /&gt;A search for MVC 3 will give the same info as I would, so I won't enumerate the features in any detail here. There will certainly be some useful additions to our processes though. &lt;br /&gt;&lt;h3&gt;Twitter's Real-Time Architecture&lt;/h3&gt;An unfortunate choice for me, the speaker Kyle Maxwell was fighting his nerves the whole way through which made it quite excruciating to watch (and frankly dull). &lt;br /&gt;He talked about briefly and somewhat incoherently about various sub systems they use, a queuing system, daemons used to spray messages to data shards. The different parts seem to be composed of entirely different languages (scala, ruby and some others I'd never heard of).&lt;br /&gt;All together a disappointing session, I'd hoped to get some takeaways from it and didn't take anything away.&lt;br /&gt;&lt;h3&gt;Kanban and Scrum - making the most of both&lt;/h3&gt;Henrik made a bunch of points which are covered in the free book he released [Insert url for PDF] (It requires registration but nothing more). As a result, I'll just describe one example he used to show how limiting work in progress is a productivity win.&lt;br /&gt;After getting a volunteer from the audience, time how long it took to write a name (4 seconds), he asked for 4 more people to come up on stage.&lt;br /&gt;He then asked for a time estimate for writing the 4 names, (20 seconds).&lt;br /&gt;With that he put the obstacle of not limiting work in progress, all the names had to be written one letter at a time. It took almost 2 minutes! As a German being told Swedish names this added to the time taken.&lt;br /&gt;This was a somewhat contrived example but still illustrates that context switching and working with unlimited work in progress can be a real issue.&lt;br /&gt;Scale that up to normal jobs where in a single day you have to context switch 3/4 times a day and you can see that this example bears out in real life.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-7165693684200685120?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7165693684200685120/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=7165693684200685120' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7165693684200685120'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7165693684200685120'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/11/redev-2010-day-4-tristan-smith.html' title='Øredev 2010 - Day 4 - Tristan Smith'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_gPRWTjkTHUU/SRY7HZpOTSI/AAAAAAAAAAM/OAQvr_kigYM/S220/tree-thumb.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-2324828917589964111</id><published>2010-11-13T04:47:00.002Z</published><updated>2010-11-13T04:48:47.948Z</updated><title type='text'>Øredev 2010 - Day 5 - Tim Jeanes</title><content type='html'>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_zsifaW4TiJo/TN4YUF67hXI/AAAAAAAAAEA/yWqbNo28YZY/s1600-h/Photo_0C2AE2A3-299B-92EF-50AF-F4AC10522926%5B5%5D.jpg" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Photo_0C2AE2A3-299B-92EF-50AF-F4AC10522926" border="0" alt="Photo_0C2AE2A3-299B-92EF-50AF-F4AC10522926" src="http://lh5.ggpht.com/_zsifaW4TiJo/TN4YU5vDvoI/AAAAAAAAAEE/RUAXp5PwTpI/Photo_0C2AE2A3-299B-92EF-50AF-F4AC10522926_thumb%5B3%5D.jpg?imgmax=800" width="364" height="274" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Omg omg omg! It's Nolan Bushnell, the founder of Atari!&lt;/p&gt;  &lt;h4&gt;Session 1 - The Technical Debt Trap - Michael "Doc" Norton&lt;/h4&gt;  &lt;p&gt;The term technical debt refers to problems or bad code that you decide you'll fix later but never really do. A little debt early on speeds development. It's fine so long as you pay the debt back soon, but left unattended is like accumulating interest on that debt as the bad code compounds.&lt;/p&gt;  &lt;p&gt;Though developers generally hate technical debt in any form, it can be a good thing provided it's managed correctly. It allows for rapid delivery to elicit quick feedback and correct the design.&lt;/p&gt;  &lt;p&gt;This isn't an excuse to write code poorly now: if it's debt, you intend to pay it back. You can only do this if you write the code in a way that you can refactor it into a better shape later on. Dirty code is to technical debt as the pawn broker is to financial debt.&lt;/p&gt;  &lt;p&gt;If you don't have a plan to get out of the debt you're in, you don't have technical debt, you just have a mess; cruft.&lt;/p&gt;  &lt;p&gt;Much technical debt can be avoided; however, much is unintentional. When you look back at your old code you find it full of cruft that needs cleaning up. Unfortunately, how you got into debt doesn't excuse you paying it back.&lt;/p&gt;  &lt;p&gt;A lot of handling technical debt comes down to handling expectations. We know we're going to incur it, so we need to balance that against the pressure for speed over quality. Technical debt then compounds as mess is added to mess in order to maintain velocity. Adding clean-up sprints to the dev cycle generally doesn't work. Studies show that the cruft just re-accumulates rapidly afterwards. A better pattern is to clean continuously: try to leave the code cleaner than you found it.&lt;/p&gt;  &lt;h4&gt;Session 2 - C#'s Greatest Mistakes - Jon Skeet&lt;/h4&gt;  &lt;p&gt;We love C#, so it's great to hear such an expert on the subject (and someone who loves it even more passionately) talking about what's wrong with it.&lt;/p&gt;  &lt;p&gt;This was almost entirely a code-based session, so it's hard to write about without duplicating reams of code.&lt;/p&gt;  &lt;p&gt;Ah well.&lt;/p&gt;  &lt;h4&gt;Session 3 - Fostering Software Craftsmanship - Cory Foy&lt;/h4&gt;  &lt;p&gt;We saw a few case studies of people who have opted out of the traditional software development career structure to follow instead a more journeyman-type model whereby they spend their time travelling and pairing with people and exchanging ideas.&lt;/p&gt;  &lt;p&gt;Historically, software development became increasingly prescriptive from the 1960s onwards. The Agile Manifesto was a massive backlash against this that reoriented programmers' values much more towards being flexible and adaptive. Though the older models were more heavyweight, they did lead to stricter practices.&lt;/p&gt;  &lt;p&gt;Empowerment can be defined as sharing information with everyone, creating autonomy through boundaries, and replacing the old hierarchy with self-managed teams.Agile practices often fail when management still works from a carrot-and-stick way of rewarding goals or punishing failures. If we're to work as a team, individual rewards and bonuses are always counter-productive.&lt;/p&gt;  &lt;h4&gt;Session 4 - Real Options - Olav Maassen&lt;/h4&gt;  &lt;p&gt;Similar to buying stock options - by purchasing an option now to buy later at a price set now - almost everything can be considered an option by weighing up the benefit against the loss incurred by choosing against the option, whether than cost/ benefit is financial, emotional or moral.&lt;/p&gt;  &lt;p&gt;Options have value; options expire; never commit early unless you know why.&lt;/p&gt;  &lt;p&gt;Similarly, buying a plane ticket far in advance is much cheaper than buying it at the last moment. The earlier ticket is non-refundable, but the flight is not mandatory: all you've bought is the option to fly then. If you choose not to take the option, you've not lost much.&lt;/p&gt;  &lt;p&gt;Being uncertain can often be better than being wrong.&lt;/p&gt;  &lt;p&gt;In agile practices, pair programming provides options: two people think of different ways of tackling the same problem.&lt;/p&gt;  &lt;p&gt;Scrum backlog provides options: every idea is there. Action is postponed until the time the priority decision needs to be made.&lt;/p&gt;  &lt;h4&gt;Session 5 - True Tales of the App Store - Making iPhone Apps for (Fun and) Profit - Jack Nutting&lt;/h4&gt;  &lt;p&gt;Developing apps for any platform's app store let's you skip most of the hard work of selling software - you have no inventory management, payment handling or shipping. However, this has led to a crowded market, so marketing becomes a bigger priority. You can basically run your own software firm from your desk, but marketing isn't something developers normally do that well.&lt;/p&gt;  &lt;p&gt;The app store has changed the public's relationship to software - they buy and discard software much more freely now, many of them for the first time.&lt;/p&gt;  &lt;p&gt;The lower the price of your app, the more downloads you'll get, but also the more haters you'll get - more low ratings and more negative comments.&lt;/p&gt;  &lt;p&gt;The app store is a hit-driven economy: the better you're doing, the better you continue to do. If you're outside the top fifty or so, you can sink without trace. If there were ever a bug in the app store that showed a non-entity app as number one, within a day it would probably actually be number one.&lt;/p&gt;  &lt;p&gt;Releasing a "lite" version of your app can help to gain publicity, but Apple have strict rules against non-functional buttons that only tell the user to buy the full version to activate that feature.&lt;/p&gt;  &lt;p&gt;Other than making money directly through the app store, advertising can be a revenue stream, but it's generally a slow one. For games, in-game purchasing of additional levels can a;also work.&lt;/p&gt;  &lt;p&gt;An alternative is to build free apps that help people use your business: the app doesn't make any money in itself, but acts as direct or indirect advertising to the existing business model.&lt;/p&gt;  &lt;p&gt;Before you even write a line of code, be smart: don't reinvent the wheel. Or if you must, at least add something new.&lt;/p&gt;  &lt;p&gt;Making an app that people will keep using, then even if they don't spend any more money in it, it lengthens its word-of-mouth viral capacity. People love stories - even (or perhaps especially) stupid ones. This gives you the excuse to continue to add new content. You can add variety by adding mini games (even in games).&lt;/p&gt;  &lt;p&gt;Make your app as simple as possible, but not simpler. Unless it's a game or a book, people will want to be in and out of your app as quickly as possible. Eliminate settings wherever possible; if you can make a choice on behalf of your users, do so.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-2324828917589964111?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/2324828917589964111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=2324828917589964111' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/2324828917589964111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/2324828917589964111'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/11/redev-2010-day-5-tim-jeanes.html' title='&amp;Oslash;redev 2010 - Day 5 - Tim Jeanes'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_zsifaW4TiJo/TN4YU5vDvoI/AAAAAAAAAEE/RUAXp5PwTpI/s72-c/Photo_0C2AE2A3-299B-92EF-50AF-F4AC10522926_thumb%5B3%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-6527352489195443893</id><published>2010-11-11T19:13:00.002Z</published><updated>2010-11-11T19:14:18.409Z</updated><title type='text'>Øredev 2010 - Day 4 - Tim Jeanes</title><content type='html'>&lt;h4&gt;Session 1 - Patterns of Parallel Programming - Ade Miller&lt;/h4&gt;  &lt;p&gt;[The source code from this session is available at: &lt;a href="http://parallelpatterns.codeplex.com/"&gt;http://parallelpatterns.codeplex.com/&lt;/a&gt;]&lt;/p&gt;  &lt;p&gt;With massively multi-processor PCs becoming increasingly mainstream, it's important to utilise the full scope of processing power available wherever possible. .NET 4 implements a bunch of features to make this relatively painless. Unless we take advantage of parallelism, our software may actually run more slowly as newer machines have more, slower cores, rather than a faster single one.&lt;/p&gt;  &lt;p&gt;We saw the Visual Studio 2010 profiler. This is baked into VS2010 and shows clearly where the CPU is being used, together with disk access, etc, on a timeline. This looks really handy for identifying where the bottlenecks really lie. Using profiling is critical - understanding the application and where the problems are first is vital, rather than just wildly parallelising unnecessarily.&lt;/p&gt;  &lt;p&gt;There are a couple of models for parallelism: one is task-based parallelism where we consider what tasks need to be done and run them in parallel. The other is data parallelism: for example in image processing you could split the image into pieces, process them in parallel and then stitch them together in the end.&lt;/p&gt;  &lt;p&gt;In data parallelism, it's important to get the data chunk size right: too big and you're under-utilised; too small and you waste too much time thrashing.&lt;/p&gt;  &lt;p&gt;You also have to take into account at runtime what degree of parallelism is appropriate: your software may end up running on a machine in a few years that has far more processors than were available when you wrote the software.&lt;/p&gt;  &lt;p&gt;Rather than counting processors yourself and manually creating threads, it's better if we can hand this responsibility to the .NET framework and allow it to take care of the degree of parallelism itself. Ideally we just express where parallelism can take place.&lt;/p&gt;  &lt;p&gt;In .NET we can do this using the Task&amp;lt;&amp;gt; class. We specify a task that needs to be performed, but we don't say when it starts. We only request a result from it. You can specify dependencies between tasks.&lt;/p&gt;  &lt;p&gt;There are a couple of standard patterns that are addressed for data parallelism: loops where items can be handled independently; and loops were the required result is some kind of aggregation of all items in the set.&lt;/p&gt;  &lt;p&gt;The first of these is trivial: replace for() with Parallel.For() and you're done. Bear in mind though that you can never assume that the items will be processed in any kind of order at all. Parallel.ForEach can even be used on collections where you don't know the collection size up front.&lt;/p&gt;  &lt;p&gt;There's also an overload of Parallel.For that allows for data aggregation between threads. The only gotcha is to ensure you do your own locking in the step that combined the sub-aggregations from each parallel section. Locks are pretty bad in terms of performance though, so if you find you're getting a lot of them in your parallel tasks, it's a good idea to consider whether or not this is the right way to go.&lt;/p&gt;  &lt;p&gt;this isn't a silver bullet: parallelism is still hell if your tasks need to share data or need to do a lot of synchronisation.&lt;/p&gt;  &lt;p&gt;Task.WaitAll allows you to wait until all parallel tasks have completed; Task.WaitAny allows you to continue after just one has finished. Tasks can be cancelled if they're no longer needed. These last two can be combined if you're doing a parallel search for a single item in a large set.&lt;/p&gt;  &lt;p&gt;The Pipeline pattern can be used where many tasks have to be performed on data items that are idenpendent of one another. I.e. once Task A has finished with a data item, it can immediately be passed to Task B. Buffers exist between the tasks that can have size limits on them to ensure that processing capacity is used most where you need it. This can prevent thrashing and memory overflows.&lt;/p&gt;  &lt;p&gt;In some cases it's appropriate to combine parallel strategies: if you pipeline has a bottleneck, that stage can itself be parallelised (much like adding more worker to the slow step of a production line).&lt;/p&gt;  &lt;h4&gt;Session 2 - Run!&lt;/h4&gt;  &lt;p&gt;Billed as a 5km run, it was mercifully &lt;a href="http://runkeeper.com/user/teedyay/activity/19834938" target="_blank"&gt;a little shorter than that&lt;/a&gt;. Man, running along the Swedish coast in November is cold!&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_zsifaW4TiJo/TNxAZ9RcQwI/AAAAAAAAAD4/0a6TDxAh1bY/s1600-h/IMG_20101111_112232%5B3%5D.jpg" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="IMG_20101111_112232" border="0" alt="IMG_20101111_112232" src="http://lh6.ggpht.com/_zsifaW4TiJo/TNxAbkVjRlI/AAAAAAAAAD8/ghjSB-kW2B0/IMG_20101111_112232_thumb%5B1%5D.jpg?imgmax=800" width="184" height="244" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;What was I thinking?&lt;/p&gt;  &lt;h4&gt;Session 3 - Personal Kanban - Jim Benson&lt;/h4&gt;  &lt;p&gt;Building a personal kanban board for your own work (or even for your own dreams) can build a lot of clarity in your own mind. It removes the brain clutter than creates stress and dissatisfaction, giving clarity to your current position and how well you're doing at whatever it is you do.&lt;/p&gt;  &lt;p&gt;Even in a work-related personal kanban, it's worth including non-work items. The fact that you're worried about a sick relative is a distraction to you today, so it belongs in your WIP column as it's a distraction to you that's impacting on your performance.&lt;/p&gt;  &lt;p&gt;We tend to want to take on way more work than we can deal with, because we want to be productive - or at least be seen to be. We often don't recognise that we have our own WIP limit, that when exceeded, dramatically impacts on our productiveness.&lt;/p&gt;  &lt;p&gt;Kanban can also be used for meetings: It makes for a more flexible, dynamic agenda that contains things the attendee actually want to talk about. it also helps to keep the conversation focussed. I'm not totally convinced on this though - it's hard to say for sure when a discussion on a topic is definitely "done".&lt;/p&gt;  &lt;h4&gt;Session 4 - MongoDB - Mathias Stearn&lt;/h4&gt;  &lt;p&gt;MongoDB is a document-orientated noSQL database. A document is essentially a JSON object, which gives a few advantages over a traditional SQL-based database.&lt;/p&gt;  &lt;p&gt;As the data isn't stored in defined tables, all objects can be expanded dynamically. Also, as relationships aren't used except where needed, parent and child objects can be held as a single object.&lt;/p&gt;  &lt;p&gt;For example, if you're storing a blog in a database, you'd hold each post as a document. That would include all tags and comments as array properties on the blog post object. Physically, these are all held in a single location on disk (effectively as a binary representation of the JSON string) making object retrieval very fast. Data writes are also fast. This makes MongoDB appropriate for high-traffic web apps, realtime analytics or high-speed data logging.&lt;/p&gt;  &lt;p&gt;Querying the data is function-based rather than SQL based, but this really only leads to a syntax difference: db.places.find({zip:10011, tags:"business"}).limit(10); is an example query equivalent. Pretty self-explanatory, and a little shorter than SQL. Critically though, there's been no join between a Business table and a Tag table that you'd get with SQL.&lt;/p&gt;  &lt;p&gt;More complex queries are also possible, such as {latlog:{$near:[40,70]}}.&lt;/p&gt;  &lt;p&gt;Data can be indexed by property to improve performance.&lt;/p&gt;  &lt;p&gt;Updates to records are achieved by combining criteria to find the relevant document, with a $push command that adds or updates properties on the document.&lt;/p&gt;  &lt;p&gt;Where appropriate, objects needed be combined into single documents. Joins can be achieved by adding ObjectId references as properties on documents. There's no such thing as referential integrity in this case though.&lt;/p&gt;  &lt;p&gt;Actions on a single document can be chained together and will be treated atomically, giving you a rough equivalent to SQL transactions. There's no such thing as atomic operations across multiple collections.&lt;/p&gt;  &lt;p&gt;MongoDB is impressively mature in terms of deployment features such as replication and database sharding.&lt;/p&gt;  &lt;h4&gt;Session 5 - Challenging Requirements - Gojko Adzic&lt;/h4&gt;  &lt;p&gt;Customers often ask you to implement their solution to a problem. This often leads to nightmare projects that are way bigger than they need to be. It's generally better to understand what the real problem is and solve that. The implementation of the true solution can well be better than implementing the solution the customer initially identified.&lt;/p&gt;  &lt;p&gt;Similarly refuse to use the technology the customer specifies unless you first confirm that the technology actually matches their need. Often they'll think they know the best way to implement a solution, but another option may be far simpler and more appropriate.&lt;/p&gt;  &lt;p&gt;Don't rush into solving the first problem they give you; keep asking "why" until you get to the money: that'll be their real requirement.&lt;/p&gt;  &lt;p&gt;Know your stakeholders: who is going to use this and why?&lt;/p&gt;  &lt;p&gt;Don't start with stories. Start with a very high level example of how people will use the system and push back to the business goals. The story you're presented with may well not be a realistic one.&lt;/p&gt;  &lt;p&gt;Great products come not from following the spec; they come from understanding the real problem and whose problem it is.&lt;/p&gt;  &lt;p&gt;Effect maps can be used to trace the purpose of all features. They ask why the feature is needed, who the people are that want the feature, then what the target group want to do and how the product should be designed to fulfil that.&lt;/p&gt;  &lt;h4&gt;Session 6 - Kanban and Scrum - making the most of both&lt;/h4&gt;  &lt;p&gt;OK, I think it's fair to say I'm officially totally in love with Kanban now. However, I'm also fairly fond of Scrum. Short of a Harry Hill solution to this dilemma, I attended this session to see how we could take the best of both worlds.&lt;/p&gt;  &lt;p&gt;The key features of kanban is to limit the WIP at any stage, and to measure the flow (typically by measuring the lead time - the time it takes for a task to cross the board).&lt;/p&gt;  &lt;p&gt;Having a lot of parallel tasks or projects running simultaneously leads to more task switching, which leads to more downtime and delays, which leads to all the projects being completed later.&lt;/p&gt;  &lt;p&gt;Doing tasks in series, perhaps with a background task to work on while the main project is blocked, keeps everyone focused and more productive, completing projects sooner: leading to happier customers and happier developers.&lt;/p&gt;  &lt;p&gt;There's and example of the evolution of a kanban board at &lt;a href="http://www.crisp.se/kanban/example"&gt;http://www.crisp.se/kanban/example&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Scrum prescribes rules more than kanban does, such as planning and committing to sprints, regular releases and retrospectives. Some of these items can be useful to add to the basic kanban model, depending on what's appropriate for the company.&lt;/p&gt;  &lt;p&gt;Kanban doesn't prescribe sprints (though they are allowed). I think we may well go without sprints, just because at Compsoft we need to be able to react much more quickly - it's often too hard to commit to a period of time during which our workload can't be altered.&lt;/p&gt;  &lt;p&gt;Kanban focuses on having multi-ability teams, where team members frequently help out on tasks outside of their normal primary area of expertise. It's not that everyone has to do everything though (just as well - my Photoshop skills are pretty lacking.).&lt;/p&gt;  &lt;p&gt;Estimation is flexible in kanban. Some don't estimate at all - just count; some estimate in t-shirt sizes (S, M, L), some in story points, some in man-hours.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-6527352489195443893?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/6527352489195443893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=6527352489195443893' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6527352489195443893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6527352489195443893'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/11/redev-2010-day-4-tim-jeanes.html' title='&amp;Oslash;redev 2010 - Day 4 - Tim Jeanes'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_zsifaW4TiJo/TNxAbkVjRlI/AAAAAAAAAD8/ghjSB-kW2B0/s72-c/IMG_20101111_112232_thumb%5B1%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-4385540850330842333</id><published>2010-11-11T18:48:00.005Z</published><updated>2010-11-17T15:29:57.941Z</updated><title type='text'>Øredev 2010 - Day 3 - Tristan Smith</title><content type='html'>&lt;h3&gt;Keynote - Dr Jeffrey Norris - Mission Critical Agility&lt;/h3&gt;Having shared a naked leap into the ocean after a sauna with Jeff, then chatting to him over dinner we felt a special connection with him. He gave a fantastic keynote, covering three key parts of Agility.&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;Vision, Risk &lt;/b&gt;and&lt;b&gt; Commitment&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;He illustrated vision by talking about Alexander Graham Bell, inventor of the telephone. The environment of the time was one of a total monopoly by Western Union with the Telegraphs. The problem with the technology was that it was single message only, WU had snapped up all the available inventors to work on a multiple message telegraph.&lt;br /&gt;Into this came a wealthy benefactor wanting to break that monopoly by inventing the multi-message telegraph first, without access to a big pool of inventors he snapped up Bell. Bell, whose father had invented a method of teaching deaf people to speak wanted him to take up the family business. The benefactor had a deaf daughter who Alexander taught to speak (and got romantically involved with). &lt;br /&gt;Despite the pressures he faced, he kept working on his vision with&amp;nbsp; it eventually resulting in huge success. Interestingly, Bell's research into the telephone was based on a mistranslated document, he had read that someone had successfully changed sound to electricity and based on that belief managed to find a solution. It turned out that no-one had done anything of the sort.&lt;br /&gt;RISK was illustrated with the Moon landings, NASA were working on a couple of methods of getting to the moon. The popular option was just to have a huge rocket that flew there and flew back, simple! The alternative option was raised which involved building a 4 part rocket which would involve space walks and multiple separations in space. A much more complicated solution, a much riskier one and yet it was the one they went for, and successful too. Vision and Risk.&lt;br /&gt;Factoid: While the rocket was on the ground, it was the largest building in Florida, then they launched it into space!&lt;br /&gt;COMMITMENT While we're constantly reminded of the risk of change, there's also the risk of failing to change as shown by the Western Union example. Holding back critical investment until after evaluating multiple routes and holding back as long as possible can increase agility.&lt;br /&gt;Failure on a followed route can lead to other routes that may be successful.&lt;br /&gt;"Leave the beaten track occasionally and dive into the woods - Graham Bell.&lt;br /&gt;I have not failed. I've just found 10,000 ways that won't work. - Thomas Edison.&lt;br /&gt;&lt;h3&gt;Take Control of Your Development Career - Michael Norton&lt;/h3&gt;The key to Doc's talk was, figure out what you really love and take control!&lt;br /&gt;If you follow the points below:&lt;br /&gt;Get noticed, Get together, Get your Mojo on, Get Naked, Get schooled&lt;br /&gt;&lt;b&gt;Get Noticed&lt;/b&gt;&lt;br /&gt;Learn your business so you're better able to solve problems, you can get better insights into other problems that can improve efficiencies too.&lt;br /&gt;When you're looking to move on up, don't forget to DO your job. You need to be recognised as a good worker in your current role before being elevated to another you're focussed on getting.&lt;br /&gt;Make yourself expendable (so you can be replaced in order to move up and out of your role).&lt;br /&gt;&lt;b&gt;Get Involved&lt;/b&gt;&lt;br /&gt;Join a user group, they're a great place to encounter new ideas. If you help out with a user group or even start / run one you get much better visibility. You can then contact the types of people you'd never get a chance to other wise in sourcing speakers for your user group.&lt;br /&gt;&lt;b&gt;Get your mojo on&lt;/b&gt;&lt;br /&gt;Improve yourself, get your Koans and Katas on, hone your craft. Build something non critical but important to you as a great way to learn in a non contrived way.&lt;br /&gt;&lt;b&gt;Get Naked&lt;/b&gt;&lt;br /&gt;Run with people who are better than you, it's much easier to improve when you're the lowest in a group than the highest, otherwise it can lead to laxity.&lt;br /&gt;Use something different for you (set up a CI box, learn a new language).&lt;br /&gt;Admit when you don't know.&lt;br /&gt;&lt;b&gt;Get Schooled&lt;/b&gt;&lt;br /&gt;Find a mentor, attend conferences, teach a new language or subject (your commitment is a great motivator to learn that new subject).&lt;br /&gt;Finally, Get Started!&lt;br /&gt;&lt;h3&gt;Tightening the feedback loop - Patrick Kua&lt;/h3&gt;Where as with software development TDD and Continuous Integration gives us instant feedback, feedback with people tends to be done on a longer timescale.&lt;br /&gt;Personal reviews tend to be yearly. Yearly feedback makes it somewhat irrelevant, it needs to be done after significant events so that it can help avoid paths that shouldn't be taken and fix issues early.&lt;br /&gt;Giving effective feedback should strengthen confidence or improve effectiveness feedback shouldn't be about you as a person and you shouldn't be thinking 'How does this help me at all?'&lt;br /&gt;It's important to create a feeling of safety so the person is open minded to it. Give feedback in private, ask if it's the right time. Can I give you some feedback? Is now a good time?&lt;br /&gt;A good feedback formula is - Specific time, observed behaviour, perceived impact, "Let's discuss", suggested solution. For example "Yesterday when pairing, you laughed at my solution, I felt belittled and upset."&lt;br /&gt;&lt;b&gt;Giving Feedback&lt;/b&gt;&lt;br /&gt;Give feedback earlier, create safety, focus on behaviours, not too much, make it a conversation&lt;br /&gt;&lt;b&gt;Receiving feedback&lt;/b&gt;&lt;br /&gt;Rule #1 Ask for Feedback&lt;br /&gt;Rule #2 Don't be defensive&lt;br /&gt;Rule #3 Seek clarifications&lt;br /&gt;Rule #4 Say thanks (Positive reinforcement loop - drive culture of feedback)&lt;br /&gt;Rule '#5 Take action (Not acting on feedback will lead to a lapsing of confidence in giving feedback at all)&lt;br /&gt;&lt;h3&gt;Clarity means Completion: The Psychology of Kanban - Jim Benson&lt;/h3&gt;Kanban column headings called Value streams they're the steps you take to provide value.&lt;br /&gt;Existential overflow - The capacity to work while stress increases.&lt;br /&gt;Tasks that are left uncompleted leaves your brain spinning. This is called the&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: arial,sans-serif; font-size: small; line-height: 15px;"&gt;&lt;i style="font-style: normal; font-weight: bold;"&gt;Zeigarnik&lt;/i&gt;&lt;/span&gt;&amp;nbsp;effect.&lt;br /&gt;The less control you have over the flow of tasks, the greater this effect.&lt;br /&gt;Seeing tasks flow across the board helps lessen the effect.&lt;br /&gt;Metacognitiion is the layer which analyses how you learn and what impact that has..&lt;br /&gt;Connect and Clarity&lt;br /&gt;Pulling a backlog task onto the limited WIP makes that a valued task to the person pulling it. This can lead to thoughtful pulling where the impact of a given task is evaluated and prioritised. The investment can make that person's task's progress&amp;nbsp; more important and the fixing of issues that hold it up along the way more important.&lt;br /&gt;In this way Kanban depersonalises the workflow, if there's a problem, it's not just Bill's fault it's personal investment in the processing of a task. The relationship to work changes this way.&lt;br /&gt;The morning stand up which is scrum is often zombie like, where if you're lucky you tell everyone something they didn't know this can be transformed into a task based one where the focus is less on what you did and didn't do and more on where tasks are blocked.&lt;br /&gt;Kanban works on a number of levels, one of which is that it rewards the brain in a number of ways.&lt;br /&gt;The brain loves it when there's no blame, it loves collaboration and it loves pattern matching.&lt;br /&gt;The context of work Todo / Done makes a value map. You can see the things that were valued by those done, people can take pride in the tasks done and it can increase respect.&lt;br /&gt;Developers range from people with ADHD to Asbergers. Kanban changes from individual focus to flow. It makes it easier to spot a task taking a long time so where the Aspergers type is focussed on perfection you can see that immovable task.&lt;br /&gt;The goal is to get tasks done and off the board.&lt;br /&gt;There's a clear definition of done, if the post it is on the right and hasn't moved in a while.&lt;br /&gt;Tasks with happy faces show nice tasks vs bad ones which can show the subjective mood at any time. Retrospectives - why did this suck, can we fix it?&lt;br /&gt;There's a Kaizen impact (continuous improvement) due to the real time fixing of issues (sorting of problems found).&lt;br /&gt;There's some Kinesthetic feedback too with the tactile feedback of moving post-its.&lt;br /&gt;The moving of post-its has a parallel with child raising where picking a task and moving it through the different stages is like birth, growth, pain and release where each task is a plot point.&lt;br /&gt;&lt;h3&gt;The developer who played with XAML - Jeff Wilcox&lt;/h3&gt;A pretty average session, added a few notes below but I mostly wrote up other notes in this session.&lt;br /&gt;Silverlight 4 gets inline properties&lt;br /&gt;&amp;lt;Button&amp;gt;&amp;lt;Button.Content&amp;gt;Hello!&amp;lt;/Button.Content&amp;gt;&amp;lt;/Button&amp;gt;&lt;br /&gt;Suggestion of dropping attributes onto new lines to make Source Control changes more obvious.&lt;br /&gt;Avoid triggers (designers can't figure out triggers, VSM is a replacement for this)&lt;br /&gt;Always do Static Resources over inline styling.&lt;br /&gt;Putting curlies in strings requires "{}Hello {user}a".&lt;br /&gt;Really bad error messages are as a result of a transition between managed and unmanaged code.&lt;br /&gt;Dictionary improvements to xaml in SL 4 make it possible to create objects dictionary style in xaml.&lt;br /&gt;obj &amp;gt; debug generated files are in there which can make it easier to debug issues.&lt;br /&gt;Attached properties - Canvas.Left, Grid.Row where they only apply if relevant.&lt;br /&gt;&lt;h3&gt;Agile Release Planning - James Shore&lt;/h3&gt;If you're not paying attention to the business success factors as well as the technological ones, you're going to fail.&lt;br /&gt;Reality on the ground compared to the beautiful plan can be very different. &lt;br /&gt;He used a real pre-planned holiday that went wrong for him with a partially planned holiday with flexible activities. There's a win for adaptability with late defined plans.&lt;br /&gt;&lt;b&gt;Minimum marketable features&lt;/b&gt;&lt;br /&gt;The minimum deliverable marketable value.&lt;br /&gt;Deliver value not technology, deliver the most valuable features first.&lt;br /&gt;Releasing these features means you can start making money sooner.&lt;br /&gt;Build an entire vertical slice at a time to allow the MMF to be built, not a 3 tier method of writing Data Layer, then Business Layer then UI.&lt;br /&gt;Avoiding "The Grand Plan" and just working on feature incremental design and architecture means as you go you can change the direction for better paths, it makes you more agile. The idea being that you avoid "The Grand Plan" being twisted over time with new features and changes.&lt;br /&gt;Working this way can also reduce waste.&lt;br /&gt;Dividing the tasks into Vision, MMFs, Stories and Tasks gives you a range of time and ordering to the level of detail required at each point. This lets you plan in a more general way further out but more specifically closer in.&lt;br /&gt;&lt;h3&gt;The Burning Man - David Prior&lt;/h3&gt;A session covering a number of the failed or dysfunctional projects David had worked on in his career.&lt;br /&gt;As a reader of &lt;a href="http://thedailywtf.com/"&gt;The Daily WTF&lt;/a&gt; I'd read stories about similar situations to the examples he gave, it's always useful to learn from mistakes so this was an interesting if somewhat incredulous talk at times.&lt;br /&gt;&lt;br /&gt;He gave examples with multiple project owners fighting, half hearted scrum, PMs not passing on accurate progress reports such that the client believes everything is still on track. Teams of unqualified developers without any action being taken to rectify it. Backend systems handled by unreliable people with no progress updates and monitoring. Alcoholic employees who were geniuses when sober. &lt;br /&gt;The cause he had found in almost all of these cases was fear. Fear of repercussion, fear of failure, fear of being fired.&lt;br /&gt;&lt;br /&gt;The titular Burning man example was a disaster because the backend system his company was due to integrate with was being handled by the client's CTO. The CTO had just sold his stock for millions and taken his developers to the Burning Man festival 4600 miles away two weeks from the test date (and they wouldn't be coming back for 5 weeks). When David asked for the code, he found that for that entire year the CTO and his devs had 0 lines of code.&lt;br /&gt;&lt;br /&gt;His solutions included daily introspectives and failure focussed brainstorming.&lt;br /&gt;The failure excuse model can be identified by things such as "So. I can't [do this thing] because [obstacle] won't let me." and "I want to [do this thing] because [reasons] and I can't because [reason]".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-4385540850330842333?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/4385540850330842333/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=4385540850330842333' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4385540850330842333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4385540850330842333'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/11/redev-2010-day-3-tristan-smith.html' title='Øredev 2010 - Day 3 - Tristan Smith'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_gPRWTjkTHUU/SRY7HZpOTSI/AAAAAAAAAAM/OAQvr_kigYM/S220/tree-thumb.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-9179278361907286104</id><published>2010-11-10T22:07:00.002Z</published><updated>2010-11-10T22:09:03.324Z</updated><title type='text'>Øredev 2010 - Day 3 - Tim Jeanes</title><content type='html'>&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_zsifaW4TiJo/TNsXuNB0fwI/AAAAAAAAADw/BCCFkin48Mc/s1600-h/IMG_20101109_190949%5B4%5D.jpg" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Elk burger" border="0" alt="Elk burger" src="http://lh4.ggpht.com/_zsifaW4TiJo/TNsXu3JBf2I/AAAAAAAAAD0/4sOq9Y7TMwE/IMG_20101109_190949_thumb%5B2%5D.jpg?imgmax=800" width="364" height="274" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Elk burger: this is made of win. And elk.&lt;/p&gt;  &lt;h4&gt;Session 1 - Keynote - Mission Critical Agility - Jeff Norris&lt;/h4&gt;  &lt;p&gt;The definition of mission criticality is when everything is on the line. For Jeff at NASA this may be the fate of a spacecraft; for more run-of-the-mill programmers it may be keeping a customer, preserving the life of the company, or keeping your own job. this makes it no less mission-critical.&lt;/p&gt;  &lt;p&gt;Taking examples from sources as disparate as Alexander Graham Bell to the 1969 moon landings, Jeff outlined key elements of success in agility.&lt;/p&gt;  &lt;p&gt;A key factor of agility is vision: the ability to see what's possible even when it isn't on the well-trodden path. Vision normally involves a lot of risk.&lt;/p&gt;  &lt;p&gt;Though commitment seems a virtue, it can be best to remain as uncommitted as possible for as long as possible. Agile methodologies can allow you to remain flexible until remarkably late in the project lifecycle: by developing only as little as is necessary for each iteration of development, hard commitments to certain technologies or avenues can be postponed until absolutely necessary. Early commitment to a single decision is the antithesis of agility.&lt;/p&gt;  &lt;h4&gt;Session 2 - Deep Dive Into HTML5 - Giorgio Sardo&lt;/h4&gt;  &lt;p&gt;HTML5 is undoubtedly going to change the way we develop for the web, so although we won't be able to count on all our users having a browser that supports it for quite some time yet, it's critical for us to ensure we're right on top of it from the outset.&lt;/p&gt;  &lt;p&gt;Giorgio's a Microsoft evangelist, and it's encouraging to see Microsoft on board with web standards.&lt;/p&gt;  &lt;p&gt;Even though the HTML5 spec isn't totally complete yet, it's already becoming supported by some browsers - or at least the parts that are stably defined.&lt;/p&gt;  &lt;p&gt;HTML makes for much cleaner markup. The DOCTYPE tag can be stripped right down to just &amp;lt;!DOCTYPE html&amp;gt;. It's no longer necessary even to have separate &amp;lt;head&amp;gt; and &amp;lt;body&amp;gt; elements (though they can still be used if you find it helps with clarity).&lt;/p&gt;  &lt;p&gt;HTML5 adds a bunch of new tags that though they don't render any differently to &amp;lt;div&amp;gt;s, can help with the semantics of the page, which in turn helps with accessibility.&lt;/p&gt;  &lt;p&gt;The new &amp;lt;video&amp;gt; tag makes embedding video a whole lot easier. The only required attribute is src. Defining the video file to display is literally all you need to do to put a video on your page. There are plenty of other attributes though, such as the image to show before playback begins or if it plays automatically. You can alter the playback speed of the video. You can specify numerous &amp;lt;source&amp;gt; child tags to offer various source files in different formats, in case the client's browser doesn't support the codec of your original file. The browser will play the first &amp;lt;source&amp;gt; that it can support. For fallback, you can specify an &amp;lt;object&amp;gt; tag for Flash or Silverlight after the last &amp;lt;source&amp;gt; tag: a browser that doesn't recognise &amp;lt;video&amp;gt; or &amp;lt;source&amp;gt; will ignore those tags but still pick up on the &amp;lt;object&amp;gt; tag (or some static apology that the user can't see the video). Adding an onerror attribute to the last &amp;lt;source&amp;gt; tag ensures that HTML5-enabled browsers will also use the &amp;lt;object&amp;gt; if none of the video sources are supported. Disappointingly there's no fullscreen mode, for security reasons. All attributes are accessible and alterable via javascript, including the position of the video playback. It's also possible in javascript to detect whether or not the browser supports the &amp;lt;video&amp;gt; tag at all, or if it supports certain video codecs (though the HTML5 spec says these functions return such values as "maybe" or "probably").&lt;/p&gt;  &lt;p&gt;The &amp;lt;canvas&amp;gt; tag is another major addition to HTML. This allows you to draw vector graphics on the page. &amp;lt;canvas&amp;gt; support can easily be detected in javascript. The canvas.toDataUrl method can be used to export the content of the canvas to a single static image. It's important to ensure the canvas has loaded before you attempt to draw on it dynamically in javascript: draw instructions made before that will be ignored. For animations you have access to the refresh frame rate of the browser. These vary between browsers and how busy the machine is, so time-based animations are generally the better way to go (though also syncing with the browser refresh makes for smooth animations with less CPU overhead). You can also draw videos on the canvas, and add matrix transformations to how the video is displayed.&lt;/p&gt;  &lt;p&gt;HTML5 supports svg both as inline &amp;lt;svg&amp;gt; tags in the browser, and also as a source file for an image. This means you can use svg graphics for background images, etc., resulting in much lower bandwidth than you would have using a large jpeg image. SVG images can also be created dynamically in javascript and then serialized and used as source to image tags.&lt;/p&gt;  &lt;p&gt;We touched briefly on some new features of CSS3. An interesting one was the ability to define different styles based on the size of a screen - enabling you to swap image when the browser is small, or changing the layout altogether for mobile browsers.&lt;/p&gt;  &lt;h4&gt;Session 3 - HTML5 APIs - Robert Nyman&lt;/h4&gt;  &lt;p&gt;We recapped some features of video from the previous session. Another nice feature that the BBC are experimenting with is the implementation of subtitles. These can be held in &amp;lt;div&amp;gt;s on the page (and are thus indexable by search engines; then they are shown accordingly in javascript by polling the playback position of the video.&lt;/p&gt;  &lt;p&gt;The Raphael Javascript library is a handy tool that makes building SVG graphics dynamically a whole lot easier.&lt;/p&gt;  &lt;p&gt;There's a tension between using SVG or canvas as on the surface they offer similar functionality. The key difference is that SVG is always vector graphics whilst canvas is always bitmap-based. SVG is often more appropriate for generating dynamic images, whilst canvas is faster and more responsive for animations and games.&lt;/p&gt;  &lt;p&gt;Web storage goes way beyond the capabilities of cookies. Cookies are extremely limited on size (around 4KB), whilst web storage give you 5-10MB, depending on the browser. The two types are sessionstorage that disappears when the browser is closed, and localstorage.that persists between sessions. These work as key-value pairs of strings, but JSON is a handy way of serialising objects.&lt;/p&gt;  &lt;p&gt;There's currently a fight between WebSQL and IndexedDB. WebSQL is backed by Apple, so will probably be in Safari only. IndexedDB will probably be available in all other browsers (and hopefully in Safari too).&lt;/p&gt;  &lt;p&gt;The Worker javascript object allows multithreading. It's initialised with a javascript file and can be communicated with from the main UI thread.&lt;/p&gt;  &lt;p&gt;New javascript property navigation.online is available to check if the browser is currently online, allowing you to alter the behaviour of your web application accordingly.&lt;/p&gt;  &lt;p&gt;There's a drag and drop module in the HTML5 specification, but it looks like it's not going too well. If they can get it sorted out, it could be pretty useful - elements can be marked as draggable or as drop targets by use of attributes. It'll be interesting to see if and how this will be implemented on touch screen devices where&amp;#160; a drag action needs to be distinguished from a scroll - parts of flickr are already unusable on my phone.&lt;/p&gt;  &lt;p&gt;The drag and drop API can be combined with the file API that allows you to drag files from the client file system to the browser, and provide you with metadata about the file as well as access to the byte contents of the file. This can be inspected in javascript, and then the file contents posted to the server asynchronously. Streamed upload, multipart upload and upload progress are all available in HTML5.&lt;/p&gt;  &lt;p&gt;The window.history object allows you to push URLs into the browser history.&lt;/p&gt;  &lt;p&gt;Data push from the server to the browser can now be achieved with the WebSocket object. Connections can be specifically opened and closed in javascript, and events are raised when data is received from the server. web-socket-js and SocketIO allow similar functionality in non-HTML5 browsers, if you need backwards compatibility.&lt;/p&gt;  &lt;p&gt;More at &lt;a href="http://robertnyman.com/html5"&gt;http://robertnyman.com/html5&lt;/a&gt;&lt;/p&gt;  &lt;h4&gt;Session 4 - Clarity Means Completion: The Psychology of Kanban - Jim Benson&lt;/h4&gt;  &lt;p&gt;&lt;strong&gt;Existential overhead&lt;/strong&gt; - the things that stress your team out: all the things that take up brain space and prevent you from working. We find we get this when there's a lot of work backed up that needs doing, or that is work is progress. Being able to push things to a place called "done" frees up space in your brain to focus on the things you should be working on now. Typically developers love to start new things and often don't finish them and flush them from their minds. Kanban keeps the loop tight, ensuring you're only thinking about the things that matter right now.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Flow&lt;/strong&gt;- being able to see the whole flow of work in the project. Though you know what you have to be caring about right now, all other tasks are visible, making it easy to push back on panic rush jobs: though you can still take them on, the fact that another task (that up till now was the most important task on the board) will be pushed down to lower priority.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Depersonalisation&lt;/strong&gt; - The goal of everyone in kanban is to get a task off the right hand side of the board; not just to move it out of your column. It encourages co-operation between developers and testers, as developers can see when the test work queue is backing up. The fault probably isn't with the tester: with dev help they can most likely catch up with their workload. The whole team is focused on removing blockages.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Pattern recognition&lt;/strong&gt; - Human brains (especially those in the IT industry) just love pattern matching. Kanban makes spotting problems and issues with your workflow a case of pattern matching: the visibility of the workflow leaves problems with nowhere to hide.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Learning styles&lt;/strong&gt; - People with different learning styles tend to work in different ways: in the extreme, some will flit from the exciting part of one task to the exciting part of another; others will focus intently on one task until it's beyond perfect. Kanban keeps the balance: the goal is always to move tasks to "done" and never see them again.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Subjective well-being&lt;/strong&gt; - It can be useful to flag tasks as being tasks you like and tasks you hate. In retrospectives, discussing what it is that makes tasks suck can lead you to realise what's causing pain in your overall processes and thus what it is you can do about it.&lt;/p&gt;  &lt;h4&gt;Session 5 - The Counterintuitive Web - Ian Robinson&lt;/h4&gt;  &lt;p&gt;This session wasn't quite what I expected: it turned out to be part of a series on RESTful practices that I wasn't all that interested in. Ah well, a few things were slightly interesting.&lt;/p&gt;  &lt;p&gt;In a traditional web application or service oriented architecture, the server would keep track of the state of the interaction with the client - for example the position in the state machine that a customer has reached (requested order, ordered goods, paid, cancelled, etc).&lt;/p&gt;  &lt;p&gt;In a RESTful application, we break the process into resources (quote, order, item) with verbs (GET, PUT, POST, DELETE), then specify operations (CreateQuote, SearchOrders, ReserveItem, etc) that are executed on the server in response to these verbs. Each resource then maintains its own mini state machine.&lt;/p&gt;  &lt;p&gt;For an application to be able to evolve, we need at least one degree of freedom in our architecture: either we can continually add new verbs (as we would in an SOA), or new resources (as we would in a RESTful application.&lt;/p&gt;  &lt;h4&gt;Session 6 - Introduction to Core Animation - Marcus Zarra&lt;/h4&gt;  &lt;p&gt;Core Animation is one of the core technologies for iPhone and iPad development. It allows for animating 2D planes (or layers) in 3D space. It almost (but not quite) achieves the same as OpenGL. For most animation requirements, however, it performs slightly better than you could manage using raw OpenGL yourself.&lt;/p&gt;  &lt;p&gt;It supports basic animation (to change a value from A to B, and keyframe animation to allow for many points which are animated between&lt;/p&gt;  &lt;p&gt;The following can be animated: opacity, colour (including alpha), size and position. You can also animate matrix transforms. The API allows easier access to matrix transforms by exposing methods to animate rotation, translation and scaling on any axis.&lt;/p&gt;  &lt;p&gt;Animation is best used to indicate user interaction, to give feedback to the user (for example to let them know something can be interacted with). It's also handy for simpler games. It's also very useful for highlighting alerts.&lt;/p&gt;  &lt;p&gt;Several animations are provided for free, such as flipping the screen around on the y-axis, sliding on screen on top of another, etc. Custom animations can be created as well.&lt;/p&gt;  &lt;p&gt;Unless you specify otherwise, the built-in animations take 250ms - long enough for the user to notice, but without them feeling like they're being held up at all.&lt;/p&gt;  &lt;p&gt;Animations can be expensive, particularly if you're animating complex structures, or if you have layers with alpha transparency. The key is to measure performance with instrumentation rather than judging it by eye. Sometimes when you have bad performance you just have to experiment by removing features one by one to see what's actually causing the performance hit. Rounded corners, for example, are surprisingly heavy-duty.&lt;/p&gt;  &lt;p&gt;Core Animation does most of its hard work (preparing the animation and working through the maths) on a background thread - only the actual drawing takes place on the UI thread. In later versions of iOS, even some of the drawing takes place on the background thread.&lt;/p&gt;  &lt;h4&gt;Session 7 - CSS3: Now and the Future - Jonathan Snook&lt;/h4&gt;  &lt;p&gt;The CSS3 spec is at the Candidate Recommendation stage, where it's unlikely to change much but isn't actually finalised yet. However, many browsers already support many of the features - often even features that aren't at the CR stage yet.&lt;/p&gt;  &lt;p&gt;Some of the hotter new features are the new selectors (such as :nth-child), multiple backgrounds, border-radius, gradients, shadows, rgba colour definitions (allowing alpha on different part of an element such as the border and background), 2D and 3D transforms, transitions, multi-column support, and animations.&lt;/p&gt;  &lt;p&gt;Safari, Firefox, Opera and IE9 support most of these features.&lt;/p&gt;  &lt;p&gt;Multiple backgrounds look awesome and we've needed them for a long time. You get to specify as many as you like and they get layered one on top of each other. The unfortunate drawback is that there's no way to override just a single layer (for example in the rollover class for a button).&lt;/p&gt;  &lt;p&gt;Many of the features now becoming available in CSS3 have been available for some time in various forms in older browsers. It makes the CSS pretty messy, having to include the correct CSS3 definition, along with the definitions for Mozilla, webkit and IE's proprietary legacy implementations.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://caniuse.com"&gt;http://caniuse.com&lt;/a&gt; is a handy resource to check which features are currently supported in various browsers.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.modernizr.com"&gt;http://www.modernizr.com&lt;/a&gt; detects browser support for various features and substitutes workarounds where they're not available.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-9179278361907286104?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/9179278361907286104/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=9179278361907286104' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/9179278361907286104'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/9179278361907286104'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/11/redev-2010-day-3-tim-jeanes.html' title='&amp;Oslash;redev 2010 - Day 3 - Tim Jeanes'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_zsifaW4TiJo/TNsXu3JBf2I/AAAAAAAAAD0/4sOq9Y7TMwE/s72-c/IMG_20101109_190949_thumb%5B2%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-3701052511079600248</id><published>2010-11-09T17:40:00.002Z</published><updated>2010-11-09T17:41:43.389Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Kanban'/><category scheme='http://www.blogger.com/atom/ns#' term='Approach'/><category scheme='http://www.blogger.com/atom/ns#' term='Methodology'/><title type='text'>Øredev 2010 - Day 2 - Tristan Smith</title><content type='html'>&lt;strong&gt;Koana, Katas, oh my!&lt;/strong&gt;&lt;br /&gt;(Corey Foy)&lt;br /&gt;Corey started with a discussion of the differences between professional Software Development and other professional careers, pointing out that other critical jobs such as Doctors and Firemen don't do their learning on the job.&lt;br /&gt;His point, while acknowledging that not all software is life critical, but certainly the cost to a developer of major failure with a new technology implementation on a project for example could be the loss of their job, a pretty critical issue for them.&lt;br /&gt;The differences between Koans (a focussed learning exercise) and Katas (honing skills to problems with known solutions) were expounded with illustrations from martial arts. Shu Ha Ri learning was also talked about where Shu is learning by example, following steps thoughtlessly to learn a new thing. Ha learning is where analysis of the subject, why am I doing this, what if I do it an alternate way and Ri learning where the subject is instinctive. In martial arts, this would be where you know the katas and karate moves so innately that you could automatically defend yourself for example.&lt;br /&gt;Other than the knowledge drop, the majority of the time was spent working on some katas where we in pairs solved solutions such as Fizzbuzz and Conway's Game of Life using Test Driven Development. Deleting our code after each iteration and starting again from scratch each time.&lt;br /&gt;Interesting too was that the room had maybe 15 people in it from all language backgrounds and yet everyone managed to work together and storm through the problems.&lt;br /&gt;&lt;strong&gt;A practical introduction to Kanban&lt;/strong&gt;&lt;br /&gt;Kanban is a Japanese methodology for process improvement and control.&lt;br /&gt;It originated in the Toyota Manufacturing Factories after research into the Supermarket model of demand controlling the rate of production.&lt;br /&gt;Kanban has some key principles:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Limit the work in progress.&lt;/li&gt;&lt;li&gt;Stop starting (new work), start finishing. (Using a queue where only one task is taken when the previous task is done.&lt;/li&gt;&lt;li&gt;Visualise the flow of work so that bottlenecks and other issues are easy to see.&lt;/li&gt;&lt;/ul&gt;After a brief overview, came the guys initiated a dot game where 8 people were divided up by job role. A post it note on the table had a dot based design and different coloured dots were given to the different roles. Business Analyst, Designer, Developers, Tester, Project manager and Customer.&lt;br /&gt;http://&lt;a href="http://www.netobjectives.com/the-dot-game"&gt;www.netobjectives.com/the-dot-game&lt;/a&gt;&lt;br /&gt;In the first iteration the process was defined, each person would do a batch of 6 instances of their job (putting their coloured dot on the post it) before passing the batch to the next person.&lt;br /&gt;What quickly became clear was that there were bottle necks and dependencies that led to undue pressure felt by people, some people were kicking their heels while others were slaving away. When the first batch was complete, the customer rejected all the work.&lt;br /&gt;None of the team ever asked for feedback from the customer, everyone had their own interpretation of the spec and the feedback loop was too long as there was no feedback until the entire batch was complete.&lt;br /&gt;Two more iterations of the exercise allowed changes to be discussed which brought customer feedback into the process and more individual informed involvement.'&lt;br /&gt;It was a good way of highlighting some of the key strengths of Kanban, the problems experienced in the first instance where caused by too many items being processed, inefficiencies due to lack of visibility and slow response to those inefficiencies.&lt;br /&gt;Some of the other points made along the way:&lt;br /&gt;Context switching (limited by the 1 item at a time flow) tends to result in about a 20% loss in time per item, this has a major impact if you're repeatedly having to context switch. Some research they pointed at showed that context switching equates to a 10 point drop in IQ.&lt;br /&gt;Work in progress also includes items that are complete but have not been released yet, or not been taken up by the next department (Dev &amp;gt; Testing &amp;gt; Customer Acceptance).&lt;br /&gt;The higher visibility of problems means that bugs for example have a number of extra costs, there's the delay downstream for the time Testing takes, then the context switching tax of going back to a previous problem domain (and possibly project).&lt;br /&gt;Catching issues earlier leads to a lower cost to change in requirements, making it easier for customer change requests to be processed.&lt;br /&gt;Shorter lead times mean greater motivation, the higher perceived (and actual) productivity leading to a positive feedback loop.&lt;br /&gt;Moving on to the Kanban board, tasks are added and prioritised with colours showing the task type or scope (bug, feature, maintenance).&lt;br /&gt;Avatars appended to the bugs as the tasks move across the board through departments make it obvious who is working on each task. Tasks are pulled from the list, and pushed to the done / next stage by that person.&lt;br /&gt;As each task gets moved, date entered can be added to make it easier to see the lag times between work coming in and being done. Deadlines can be added as well as extra data such as TFS Item Ids.&lt;br /&gt;Each department has a specific Work in Progress max task number so that teams are limited to their capacity.&lt;br /&gt;&lt;a href="http://www.kanban101.com/"&gt;http://www.kanban101.com&lt;/a&gt;&lt;br /&gt;Image from mountain goat software&lt;br /&gt;Some really useful information given, the slides of which we'll put up when we get them. We'll certainly be looking to implement a lot of the key features of Kanban in our current Scrum methodology, it fixes some of the issues we sometimes find where inflexibility of times / tasks can be an issue.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-3701052511079600248?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/3701052511079600248/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=3701052511079600248' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3701052511079600248'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3701052511079600248'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/11/redev-2010-day-2-tristan-smith.html' title='Øredev 2010 - Day 2 - Tristan Smith'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_gPRWTjkTHUU/SRY7HZpOTSI/AAAAAAAAAAM/OAQvr_kigYM/S220/tree-thumb.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-498308897515591460</id><published>2010-11-09T16:39:00.005Z</published><updated>2010-11-09T16:45:26.639Z</updated><title type='text'>Øredev 2010 - Day 2 - Tim Jeanes</title><content type='html'>&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_zsifaW4TiJo/TNl5PSZrSDI/AAAAAAAAADQ/Ku0NnP7_cEQ/s1600-h/IMG_20101108_214233%5B2%5D.jpg" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Ribersborg Kallbadhus" border="0" alt="Ribersborg Kallbadhus" src="http://lh5.ggpht.com/_zsifaW4TiJo/TNl5QFpzSZI/AAAAAAAAADU/XMvc5r75d-g/IMG_20101108_214233_thumb%5B1%5D.jpg?imgmax=800" width="364" height="274" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Here's the post-sauna sea pool at Ribersborg Kallbadhus last night. This somehow seemed a good idea despite an air temperature of only 3&amp;deg;C. Exhilarating, but we all shrieked like girls. We also noticed that scarcely any locals were joining in...&lt;/p&gt;  &lt;h4&gt;Session 1 - Koans and Katas, oh my! - Cory Foy&lt;/h4&gt;  &lt;p&gt;This was a largely hands-on session where we spent most of the time writing actually code, so there's not too much to blog about beyond the basic principles of katas and koans.&lt;/p&gt;  &lt;p&gt;Both are exercises whereby you hone your coding skills outside of the normal flow of day-to-day work.&lt;/p&gt;  &lt;p&gt;Katas are essentially simpler exercises where you already know the solution: we worked on the FizzBuzz problem and Conway's Game of Life. The point of the exercise is either to experiment with different ways of reaching the solution (such as implementing TDD or BDD, or using a novel coding pattern), rather than focusing on working out the solution to the problem itself.&lt;/p&gt;  &lt;p&gt;Koans, on the other hand, are longer exercises that are more clearly defined by an instructor. These focus on guiding you through the principles of a language or a coding practise, leading you to pick up the concepts by writing simple pieces of code.&lt;/p&gt;  &lt;p&gt;Katas are something you'd expect to do many times over to hone your skills in various areas, whereas a koan is something you'd work through once in order to pick up particular knowledge.&lt;/p&gt;  &lt;h4&gt;Session 2 - A Practical Introduction to Kanban - Joakim Sund&amp;eacute;n, Marcus Hammarberg&lt;/h4&gt;  &lt;p&gt;I selected this session as I thought it could be particularly relevant to us at the moment. Kanban is a practice we've been considering taking up at Compsoft, if suitably modified to fit our particular needs.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;We started with a hands-on exercise where people simulated the various departments of software development. In this task we were just sticking different coloured dots onto post-it notes, and the point was to experiment with different ways of working to ensure there aren't bottlenecks, that people aren't idle, that the customer is happy with the final result, and that no one feels too pressured.&lt;/p&gt;  &lt;p&gt;The two main principles of kanban are to work to an agreed capacity, and only to pull work from the queue when it is required.&lt;/p&gt;  &lt;p&gt;Limiting work in progress minimises risk: the shorter your lead times between starting work and getting feedback, the less unconfirmed work there is in the system. The more unchecked work there is, the more potential there is for that work to be wrong - either buggy or just not what the customer requires any more. Work in progress should be limited to the capacity of the team. Working with smaller units of work can help to keep the process time streamlined. Where possible, having a cross-functional team can minimise bottlenecks.&lt;/p&gt;  &lt;p&gt;The amount of WIP in a software context is difficult to track as it's not visible: there are no stacks of half-built physical goods sitting around. Thus visualisation is critical. Post-it notes of the wall to track the volume of tasks and where they are in the system helps everyone to see where the work's building up, where the bottlenecks are and hence where the waste is.&lt;/p&gt;  &lt;p&gt;Though SCRUM incorporates many kanban principles, it allows for more flexibility than strict SCRUM. Often it can be impractical to set a fixed sprint time-box for a portion of work, especially where (as we often find) we're juggling many different customers simultaneously.&lt;/p&gt;  &lt;p&gt;A general principle (though not a hard rule) is to focus on finishing work rather than starting new work. Even though it all has to be done sooner or later, it's generally beneficial to help get items that are already started finished, rather than bringing more unstarted items into WIP. The customer appreciates this as it means the higher priority tasks get delivered sooner, rather than there being more lower priority tasks in the pipeline.&lt;/p&gt;  &lt;p&gt;Moving post-it notes representing tasks between columns identifies bottlenecks early and can prompt appropriate reaction. Different coloured notes can represent whatever you want - be it different priorities, different customers, bugs versus features versus change requests, etc.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_zsifaW4TiJo/TNl5Q3w1USI/AAAAAAAAADg/OZxVV38L58I/s1600-h/IMG_20101109_162026%5B1%5D.jpg" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Joakim Sund&amp;eacute;n with example kanban board" border="0" alt="Joakim Sund&amp;eacute;n with example kanban board" src="http://lh5.ggpht.com/_zsifaW4TiJo/TNl5RjBpNnI/AAAAAAAAADk/K3IKGT-jQzc/IMG_20101109_162026_thumb.jpg?imgmax=800" width="364" height="274" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Each department's columns has a WIP limit. Those these can occasionally be broken, this should always at least prompt a conversation about what the underlying problem actually is. It's also worth including the customer's acceptance as a column, so they can be prompted to keep up with their involvement in the task.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-498308897515591460?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/498308897515591460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=498308897515591460' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/498308897515591460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/498308897515591460'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/11/redev-2010-day-2-tim-jeanes.html' title='&amp;Oslash;redev 2010 - Day 2 - Tim Jeanes'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_zsifaW4TiJo/TNl5QFpzSZI/AAAAAAAAADU/XMvc5r75d-g/s72-c/IMG_20101108_214233_thumb%5B1%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-6632335606534389296</id><published>2010-11-08T17:07:00.003Z</published><updated>2010-11-10T22:07:02.424Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Oredev'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight'/><title type='text'>Øredev 2010 - Day 1 - Tristan Smith</title><content type='html'>&lt;strong&gt;&lt;span style="font-size: x-small;"&gt;Silverlight Bootcamp&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;Originally due to be given by Shawn Wildermuth (Silverlight MVP) and then by Tim Heuer (Silverlight Program Manager), it ended up being given by Einar Ingebrigtsen Norwegian Silverlight MVP and developer of the Baldur 3D Silverlight engine. He gave a decent comprehensive overview and exploration of Silverlight.&lt;br /&gt;The talk itself was interspersed with loud exclamations from the REST talk next door 'BOOM, BOOM, BOOM HEADSHOT!' and 'What the **** is this application' were heard by the clearly passionate Thoughtworks guys next door.&lt;br /&gt;Starting with a comprehensive overview of what Silverlight is, Einar talked us through the breakdown of the plugin, how the CLR, DLR and rendering engine fit into it.&lt;br /&gt;He covered topics such as Dependency Properties, RoutedEvents, Storyboards, ContentControls, Animations, DataBinding and a lot more. The aim of the talk was to get a 99% coverage of Silverlight so I'll just cover some details, I thought might be of interest, in this post.&lt;br /&gt;&lt;b&gt;RoutedEvents&lt;/b&gt; follow a similar path to html DOM events except for some key differences&lt;br /&gt;- Bubbling only goes up the tree (focus, lostfocus)&lt;br /&gt;- EventArgs Handled property can be set to true to handle the event (this doesn't exist for all events)&lt;br /&gt;&lt;b&gt;Storyboards&lt;/b&gt;&lt;br /&gt;- Anything can be animated (made to change over time, not just visual properties) &lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;ContentControl&lt;/b&gt;&lt;br /&gt;- Custom controls you can attribute up which property to use as the Content property&lt;br /&gt;He gave us a Xaml centric walk around Blend covering:&lt;br /&gt;&lt;b&gt;Animations&lt;/b&gt;&lt;br /&gt;- Animate colors, values, over time, with easing etc.&lt;br /&gt;&lt;b&gt;Triggers&lt;/b&gt;&lt;br /&gt;- EventTrigger is the only option, which has a single RoutedEvent (Loaded) with a single action, BeginStoryboard&lt;br /&gt;&lt;b&gt;Sample data&lt;/b&gt;&lt;br /&gt;- Lets you create sample data that's easily bound in Blend, makes it easier to design when you can visualise the final result.&lt;br /&gt;- Basic types only&lt;br /&gt;- Creates sample data schema, xaml etc in the project and an associated resource file with the items in it&lt;br /&gt;&lt;b&gt;Dependency Properties&lt;/b&gt;&lt;br /&gt;Used to add bindable properties.&lt;br /&gt;&lt;b&gt;Resources&lt;/b&gt;&lt;br /&gt;All UIElements can have an associated resource, these resources apply to the whole hierarchy of that UIElement.&lt;br /&gt;Resources are stored as dictionaries so they have a key to get access to them and can store anything (a Class instance for example).&lt;br /&gt;MergedResourceDictionary allows you to pull in dictionaries from elsewhere&lt;br /&gt;&lt;b&gt;Styles&lt;/b&gt;&lt;br /&gt;Styling doesn't mean just visual styles, you specify TargetType but can change any property at all.&lt;br /&gt;Styles are inheritable making base styles with overridable style parts possible.&lt;br /&gt;&lt;b&gt;VisualStateManager&lt;/b&gt;&lt;br /&gt;Controls can have states and transition between them, Focused, MouseOver etc.&lt;br /&gt;&lt;b&gt;Validation&lt;/b&gt;&lt;br /&gt;Binding has Validation hooks - ValidatesOnException, ValidatesOnNotifyDataErrors if the object being bound implements IDataErrorInfo + INotifyDataErrorInfo&lt;br /&gt;&lt;b&gt;Control value default&lt;/b&gt;&lt;br /&gt;On controls you can set properties of TargetNullValue='None' and FallbackValue='Data Context not set' so that you can have default values for when nothing is specified and when data has not been bound.&lt;br /&gt;&lt;b&gt;TypeConverters&lt;/b&gt;&lt;br /&gt;Exposed properties on your object model can declare the TypeConverter to use (To allow scenarios such as converting a selected product code into a product instance).&lt;br /&gt;You point to a TypeConverter by attaching an attribute&lt;br /&gt;&lt;b&gt;Templates&lt;/b&gt;&lt;br /&gt;Blend makes it easy to edit templates based on existing controls, this is often a handy starting point. In order to get your bound property content to appear, you need to ensure you add a ContentPresenter control&lt;br /&gt;&lt;b&gt;Timers&lt;/b&gt;&lt;br /&gt;You get access to two, DispatchTimer and the CompositionTarget Rendering event (which is fired as many times as you have MaxFramesPerSecond configured).&lt;br /&gt;The DispatchTimer runs on its own thread.&lt;br /&gt;To work against the UI, you need to go via the Dispatcher&lt;br /&gt;&lt;b&gt;LocalConnection API&lt;/b&gt;&lt;br /&gt;- Used to communicate between SL instances on a page��&lt;br /&gt;&lt;b&gt;Fonts&lt;/b&gt;&lt;br /&gt;Silverlight uses its own font engine, you get 9 fonts by default but you can embed your own fonts.&lt;br /&gt;&lt;b&gt;WriteableBitmap&lt;/b&gt;&lt;br /&gt;Introduced in Silverlight 3, it's surprising fast, Einar's 3D engine project makes a lot of use of it.&lt;br /&gt;&lt;b&gt;Localization&lt;/b&gt;&lt;br /&gt;Tooling is a bit rubbish at the moment, you have to manually change the access modifier in the Resource file but then because the tooling doesn't modify the constructor to be public, you have to derive the resource class to add a public constructor.&lt;br /&gt;&lt;b&gt;Serialization&lt;/b&gt;&lt;br /&gt;- DataContractSerializer and JsonSerializer only&lt;br /&gt;- References are maintained (circular references sorted for you)&lt;br /&gt;- IgnoreDataMember to skip serialization of properties&lt;br /&gt;&lt;b&gt;Printing&lt;/b&gt;&lt;br /&gt;Is still lame, no paging support, pixel not DPI based. If your image is bigger than the available print area, it won't intelligently continue, it'll lose the excess.&lt;br /&gt;- The cool feature, is that you can pass specific UIElements to be printed.&lt;br /&gt;&lt;b&gt;WCF&lt;/b&gt;&lt;br /&gt;- Add service reference handy proxy generation&lt;br /&gt;- Validation for databinding is a pain because you lose IDataErrorInfo in transit.&lt;br /&gt;&lt;b&gt;MVVM&lt;/b&gt;&lt;br /&gt;ViewModel contains State and Behaviour&lt;br /&gt;Built in Commands mechanism - requires a new class for each one.&lt;br /&gt;MVVM Light give you some time saving Behavioural additions.&lt;br /&gt;You create your commands as methods on your ViewModel and call delegates passing your method.&lt;br /&gt;Event aggregation - a contract (message type) that view models can subscribe to / publish. MVVM Light has this called Messager.&lt;br /&gt;Einar showed us a convention he uses where he creates a directory per feature, in this case it was a Customer folder with a View, ViewModel and CustomerDataSource.&lt;br /&gt;The ViewModel encapsulates the state and behaviour. It uses a generic DelegateCommand to wire up to a local method (Load for example) rather than implement the full ICommand.&lt;br /&gt;MVVM Light has an implementation of the delegate calling code.&lt;br /&gt;Jeff Wilcox pointed us at the &lt;b&gt;SilverlightToolkit&lt;/b&gt;&lt;br /&gt;Is a library on CodePlex (silverlight.codeplex.com) that has a bunch of handy controls such as DockPanel, ViewBox and BusyIndicator.&lt;br /&gt;Also has a comprehensive samples app which lists the controls included but includes examples of styling, templating, selection, events, databinding etc for each control. Pretty handy!&lt;br /&gt;Jeff showed us a really nice styled, templated app called Bugaholic he wrote that looks a lot like the Zune client.&lt;br /&gt;&lt;a href="http://www.jeff.wilcox.name/2010/05/my-childwindow-design/"&gt;http://www.jeff.wilcox.name/2010/05/my-childwindow-design/&lt;/a&gt;&lt;br /&gt;Einar covered some unit testing, Jeff wrote the Silverlight Unit Testing framework so we saw a bit of that to end with.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-6632335606534389296?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/6632335606534389296/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=6632335606534389296' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6632335606534389296'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6632335606534389296'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/11/redev-day-1-tristan-smith.html' title='Øredev 2010 - Day 1 - Tristan Smith'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_gPRWTjkTHUU/SRY7HZpOTSI/AAAAAAAAAAM/OAQvr_kigYM/S220/tree-thumb.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-5216514877183068344</id><published>2010-11-08T15:56:00.003Z</published><updated>2010-11-09T16:37:14.259Z</updated><title type='text'>Øredev 2010 - Day 1 - Tim Jeanes</title><content type='html'>&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_zsifaW4TiJo/TNl4huHGhtI/AAAAAAAAAC0/P4Hl5KU4wKA/s1600-h/IMG_20101108_120810%5B1%5D.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="?redev - not the plushest conference venue" border="0" alt="&amp;Oslash;redev - not the plushest conference venue" src="http://lh6.ggpht.com/_zsifaW4TiJo/TNgdw-K-n4I/AAAAAAAAAC4/k0xMFOBOchQ/IMG_20101108_120810_thumb.jpg?imgmax=800" width="364" height="274" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&amp;Oslash;redev - the only conference I've known to be held in a converted slaughterhouse.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;h4&gt;&lt;strong&gt;A bootcamp in Silverlight - Jeff Wilcox, &lt;strike&gt;Tim Heuer&lt;/strike&gt; &lt;/strong&gt;Einar Ingebrigtsen&lt;/h4&gt;  &lt;p&gt;I've tinkered a little with Silverlight at a basic level in the past, but not really used it in anger. This intensive session took us from the very basics through to cover around 99% of Silverlight within a single day, so I've only blogged the points that stood our for me.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;RoutedEvents&lt;/strong&gt; - events that a parent can also receive (Focus, LostFocus, etc.) - these bubble all the way to the root of the VisualTree. Can set the Handled property of EventArgs to stop bubbling, though this isn't available on all such events.. OriginalSource holds information about the source of the event.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;ContentControl&lt;/strong&gt; - the base class for classes that have content (e.g. Button, TextBlock).&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;ItemsControl&lt;/strong&gt; - the base class for controls that have items (just as lists, etc.)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;HierarchicalDataTemplate&lt;/strong&gt; - the base class for hierarchical structures such as TreeView.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Animation&lt;/strong&gt; - all done through storyboards. Any property can be animated - not just visual things (e.g. you can animate the value of a string). In all animations you specify keyframes and Silverlight interpolates between them using the specified easing. nimation storyboards can be started in code, or via triggers in the xaml.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Sample Data&lt;/strong&gt; - This is a powerful feature of Blend. You can easily specify a data structure (Customer has FirstName, LastName, Photo, etc.) and mock data will be generated for you - lots of lorem ipsum-like text and arbitrary images in our case. This makes it really easy to get started with a data-driven app that you can even show to a customer right away.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;DependencyObject&lt;/strong&gt; and &lt;strong&gt;DependencyProperty&lt;/strong&gt; - When making your own controls, can define DependencyProperties. This enables properties to be animated; it also provides two-way dependency, so the view is updated with changes made in code as well as the code being notified of changes made to the value via changes made in the view.. This points to the actual property whose value is to be changed. You can also specify metadata such as the default value and a callback method that will be called whenever the value is changed by some action in the view.&lt;/p&gt;  &lt;p&gt;This makes for quite a bit of extra typing and non-refactorable code (the actual property name is specified as a string in the DependencyProperty definition, for example). It's worth using a generic wrapper that will register the DependencyProperty for you. Einar's set up some sample code of how to do this, available here: [.]&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Resources&lt;/strong&gt; - As well and application-wide resources, all UIElements can have resources available for their scope. Though resources are usually used for styling, resources can be any objects. Only static resources are available in Silverlight - WPF's dynamic resources can't be used here.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Styling&lt;/strong&gt; - this goes way beyond the powers of CSS: any property can be styled - including ones that aren't visual. Styles can be inherited from one another using the BasedOn keyword.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Visual States&lt;/strong&gt; - Controls can have different states (e.g. MouseOver, Focused, etc.). Using the VisualStateManager you can set styles for different states and the animations between them.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Markup extensions&lt;/strong&gt; - These allow you to use pseudo-values for properties, such as {Binding}, {StaticResource}, etc.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;DataContext&lt;/strong&gt; - All UIElements have a DataContext, which is inherited from its parent by default.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Binding data&lt;/strong&gt; - Different modes are available: OneWay (the default, which only takes data from the object to the view), TwoWay (which sends data back), OneTime (which reads the data once at start-up and never updates).&lt;/p&gt;  &lt;p&gt;IValueConverter can convert string values in the model to a different value that is used on the view. This can also work both ways.&lt;/p&gt;  &lt;p&gt;String formats, null and fallback values can also be defined.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Attached Dependency Properties&lt;/strong&gt; - these allow you add your own properties to the existing properties on a DependencyObject. You can see these in action in the Grid control: it adds the Grid.Row and Grid.Column properties to child elements that appear within the Grid.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Element-to-element binding&lt;/strong&gt; - One element can bind to the properties of another element. This can be useful, for example, in list/ detail binding.&lt;/p&gt;  &lt;p&gt;Silverlight promotes using an asynchronous model, so INotifyPropertyChanging and INotifyPropertyChanged interfaces are used to mark the beginning and end of the async operation.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;TypeConverter&lt;/strong&gt; - Everything in xaml is a string, so these are used to convert between objects and strings between the view and the model. They are defined through attributes on types or on DependencyProperties.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Offline support &lt;/strong&gt;- Isolated storage is available for storing data locally. Silverlight can also be run out-of-browser. The API provides methods to detect network availability and events are raised when the network availability changes.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;ChildWindow&lt;/strong&gt; - an easy way to create modal controls. Watch out though - it's easy to tab from this control back to the parent. It's a bit tricky to work around this bug.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;DispatchTimer&lt;/strong&gt; - a timer for running code at a predefined point in time. This runs on its own thread so you need to use the Dispatcher to execute operations on the UI thread.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Local file access&lt;/strong&gt; - you can't access any old file on the hard drive; however OpenFileDialog and SaveFileDialog are available to ask the user to access files.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Local Connection API &lt;/strong&gt;- enables you to communicate between multiple Silverlight instances on a single HTML page.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Fonts&lt;/strong&gt; - Silverlight has its own font engine to break the dependency on the OS, thus ensuring it will render the same everywhere. Nine fonts are included in the runtime, but you can embed your own or access certain ones that you can (hopefully) assume exist in the OS. TrueType fonts are supported.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;WriteableBitmap&lt;/strong&gt; - this enables you to create your own bitmaps dynamically at runtime. It's surprisingly performant.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Printing&lt;/strong&gt; - Any UIElement can be sent to the printer. However, it's pretty limited. It doesn't always look great as it's pixel-based. There's no paging support - anything you print will come out on a single page.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;WCF Services&lt;/strong&gt; - Adding a Silverlight-enabled web service to your server application really adds a regular WCF service - but it also sets everything up for Silverlight consumption in the web.config.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;MVVM&lt;/strong&gt; - the Model - View - View Model model works really well with Silverlight. The View Model is where you spend most of your development time in Silverlight. It should contain business logic relevant to the frontend, but not view-aware. It typically connects to the server through services. In terms of state, it contains as much model-like information that the view needs, with the application logic state.&lt;/p&gt;  &lt;p&gt;Though MVVM costs a bit in terms of the initial learning curve and early development time (though it's less uncomfortable if you're already used to ASP.NET MVC), it's worth it for the separation of concerns and code testability and maintainability. It also makes it a lot easier to make drastic changes to the UI without breaking the application.&lt;/p&gt;  &lt;p&gt;Silverlight toolkit - Available at silverlight.codeplex.com, this is an open source library of useful Silverlight components that may one day make their way into the core Silverlight library. It includes tools for WP7 development.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-5216514877183068344?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/5216514877183068344/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=5216514877183068344' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5216514877183068344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5216514877183068344'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/11/redev-2010-day-1-tim-jeanes.html' title='&amp;Oslash;redev 2010 - Day 1 - Tim Jeanes'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_zsifaW4TiJo/TNgdw-K-n4I/AAAAAAAAAC4/k0xMFOBOchQ/s72-c/IMG_20101108_120810_thumb.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-5825875523736075901</id><published>2010-04-08T15:40:00.009Z</published><updated>2010-07-05T12:34:50.811Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='iPhone'/><category scheme='http://www.blogger.com/atom/ns#' term='iPad'/><category scheme='http://www.blogger.com/atom/ns#' term='Compsoft'/><title type='text'>iPad, Glorious iPad</title><content type='html'>&lt;p  style="font-family:verdana;"&gt;Shipped from the USA, our &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;iPad&lt;/span&gt; has been in the office for 27 hours or so... well, nearly. The MD took it to a meeting yesterday afternoon and then home and played in to the small hours with it. And now it has gone to another meeting. Interestingly, the meeting yesterday was about the development of an Android phone app, but that quickly got &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_0"&gt;forgotten&lt;/span&gt; as the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;iPad&lt;/span&gt;&lt;/span&gt; stole the limelight.&lt;br /&gt;&lt;br /&gt;I had the pleasure of spending some time with it this morning, looking over it with colleagues and have received a variety of opinions:&lt;br /&gt;&lt;br /&gt;The Sales Team: they loved it. It is a tactile thing that wants to be used, to be touched, to be seen. They can see that putting it &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_2"&gt;in front&lt;/span&gt; of customers with their iPhone / &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;iPad&lt;/span&gt;&lt;/span&gt; app on will blow them away. I guess the telling sign is that all bar none have expressed their desire to get hold of an &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;iPad&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The Support Team: the only comment required is that as I left the Head of Support was on the phone to his wife, currently on business in the USA, asking her to get to an Apple Store! (Update: she is on a waiting list!) (Update #2: Wife was able to pick up 64GB &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;iPad&lt;/span&gt;; Head of Support uncontrollably happy!).&lt;br /&gt;&lt;br /&gt;Design Team: in spite of expressed concerns our Senior Designer 'loves it'. The slickness of the interface has impressed him, and he too sees how clients will &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;love&lt;/span&gt; seeing their imagery in a fresh crisp view. He was exploring how he could justify to his wife the purchase!&lt;br /&gt;&lt;br /&gt;Development Team: it shouldn't surprise that their view focused on its gaming potential - the additional control that the larger surface offers over the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;much&lt;/span&gt; smaller iPhone was evident as a Senior Developer demolished a tower in 'Angry Birds'. When questioned, the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;dev&lt;/span&gt;&lt;/span&gt; team confirmed that they would rather build for iPhone / &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;iPad&lt;/span&gt;&lt;/span&gt; (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;iPad&lt;/span&gt;&lt;/span&gt; using a similar development framework to iPhone) than  for other mobile platforms.&lt;br /&gt;&lt;br /&gt;The client: I took the liberty of introducing a long-standing client to the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;iPad&lt;/span&gt;&lt;/span&gt;; his reaction used colourful language to illustrate his surprise at its ease of use and its capabilities.&lt;br /&gt;&lt;br /&gt;The girls next door: It's a gadget, a boy thing... really? They were the first to want to touch the screen and flick through pages on the book reader. Mind you the guys from next door were impressed with the comic book reader.&lt;br /&gt;&lt;br /&gt;My considered opinion:&lt;br /&gt;&lt;br /&gt;This is a great gadget. For viewing websites, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;ebooks&lt;/span&gt;&lt;/span&gt;, documents, videos (the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;on board&lt;/span&gt; speaker is pretty good, not great but adequate) and photographs, it is revolutionary. It doesn't have a Flash player, which means media on the BBC website is not viewable (yet?), but the experience of viewing the news pages is great. Really great. In educational situations, I think this may well transform revision - one app that looks at the Periodic Table is &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;phenominal&lt;/span&gt;. It is a delight to look at and to use!&lt;br /&gt;&lt;br /&gt;Do I see this becoming a business tool? Absolutely. We previously built an iPhone app that presents a host of videos; our &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;dev&lt;/span&gt;&lt;/span&gt; team converted this for use on the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;iPad&lt;/span&gt;&lt;/span&gt; and, wow, it is very impressive. OK, so this app is an instructional tool for a golf tutor, however, the stunning presentation can be applied for use by sales teams, project management ... anyone! For example, in my marketing capacity I can see already how easy potential customers will be able to view a range of documents and supporting videos.&lt;br /&gt;&lt;br /&gt;We have an internal app that has an interface on the iPhone. We currently can edit info from the iPhone, however, the touch screen keyboard is not a &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_14"&gt;practical&lt;/span&gt; size, comments added, therefore, consist of only a few words. With the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;iPad&lt;/span&gt;&lt;/span&gt; and its more capable screen size, it is much easier to type meaning that greater amounts of information will be included. Actually, the word processing app works well; it enables one to add text naturally unlike with the iPhone, and certainly unlike other &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;smartphone&lt;/span&gt;&lt;/span&gt; devices.&lt;br /&gt;&lt;br /&gt;It is because of the combination of these that I think it will become a valuable business tool; it works as a presentation medium, as a document viewer and as a means to capture textual information. And it is fun.&lt;br /&gt;So, perhaps the caveat is that the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;iPad&lt;/span&gt;&lt;/span&gt; is going to work well for businesses, provided the right apps exist.&lt;br /&gt;&lt;br /&gt;My challenge is now to convince the wife that it is a good idea of hers for us to get one...&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-5825875523736075901?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.compsoft.co.uk/News/iPad' title='iPad, Glorious iPad'/><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/5825875523736075901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=5825875523736075901' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5825875523736075901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5825875523736075901'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/04/ipad-glorious-ipad.html' title='iPad, Glorious iPad'/><author><name>palcra</name><uri>http://www.blogger.com/profile/05815952916518755145</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-6996335741547060535</id><published>2010-03-05T10:22:00.001Z</published><updated>2010-03-05T10:22:29.356Z</updated><title type='text'>Using Team Foundation Server (TFS) with Xcode on a Mac</title><content type='html'>&lt;p&gt;We live and breathe TFS here as I genuinely feel its the best source control product on the market. The Visual Studio integration is spot on. The web access add on give nice access for all none developers to create / edit bugs etc.&lt;/p&gt;  &lt;p&gt;We recently have been ramping up our iPhone development and as you may be aware its Mac only using Xcode. Currently there are no TFS plugins for Xcode as it as limited (no?) support for source control plugins.&lt;/p&gt;  &lt;p&gt;After some googling, I stumbled upon &lt;a href="http://svnbridge.codeplex.com"&gt;SvnBridge&lt;/a&gt;. This is a small module you pop on to your application tier and BOOM, you have SVN access to your existing TFS library. No mods, no hassle, just works.&lt;/p&gt;  &lt;p&gt;Getting used to Xcode and svn can be hard work. The intergration isn't the smoothest in the world. So watch out for issues adding / removing items or moving existing items around.&lt;/p&gt;  &lt;p&gt;Overall we are pleased with the support SvnBridge provides, day to day use works well, just a few Xcode / Svn / SvnBridge /TFS fringe issues.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-6996335741547060535?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/6996335741547060535/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=6996335741547060535' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6996335741547060535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6996335741547060535'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/03/using-team-foundation-server-tfs-with.html' title='Using Team Foundation Server (TFS) with Xcode on a Mac'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-1033288566730247122</id><published>2010-02-25T11:00:00.002Z</published><updated>2010-02-25T11:05:16.191Z</updated><title type='text'>MySQL and the warm blankets of Replace and On Duplicate</title><content type='html'>&lt;p&gt;Two very useful features MySQL has that MSSQL doesn't  are the 'REPLACE' and the 'ON DUPLICATE'. &lt;/p&gt;  &lt;p&gt;I've found these are most helpful when updating existing records, although it is best to understand how they differ and how best to combine them with 'INSERT' statements.&lt;/p&gt;  &lt;p&gt;Just for reference a normal 'INSERT' might look like this:&lt;/p&gt;  &lt;pre style="border: 1px solid rgb(206, 206, 206); padding: 5px; overflow: auto; background-color: rgb(251, 251, 251); min-height: 40px; width: 400px;"&gt;&lt;pre   style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;  1: &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=INSERT&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;INSERT&lt;/a&gt; &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=INTO&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;INTO&lt;/a&gt; TABLENAME (productName, productCost, productId)&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; background-color: rgb(255, 255, 255); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;  2:   &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=VALUES&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;VALUES&lt;/a&gt; ('&lt;span style="color: rgb(139, 0, 0);"&gt;new product name&lt;/span&gt;', '&lt;span style="color: rgb(139, 0, 0);"&gt;new product cost&lt;/span&gt;', '&lt;span style="color: rgb(139, 0, 0);"&gt;new product id&lt;/span&gt;')&lt;/pre&gt;&lt;/pre&gt;And an 'UPDATE' statement might look like this:&lt;pre style="border: 1px solid rgb(206, 206, 206); padding: 5px; overflow: auto; background-color: rgb(251, 251, 251); min-height: 40px; width: 400px;"&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%;"&gt;  1: &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=UPDATE&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;UPDATE&lt;/a&gt; TABLENAME &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=SET&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;SET&lt;/a&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; background-color: rgb(255, 255, 255); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;  2:   productName = '&lt;span style="color: rgb(139, 0, 0);"&gt;new product name&lt;/span&gt;',&lt;br /&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%;"&gt;  3:   productCost = '&lt;span style="color: rgb(139, 0, 0);"&gt;new product cost&lt;/span&gt;'&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; background-color: rgb(255, 255, 255); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;  4:   &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=WHERE&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;WHERE&lt;/a&gt; productId = '&lt;span style="color: rgb(139, 0, 0);"&gt;existing product id&lt;/span&gt;'&lt;/pre&gt;&lt;/pre&gt;'REPLACE' is great if you want to insert new records or update records that have matching unique keys. This is because if a record is not found that has a matching key, the record is just inserted. However, if an existing record is found, the record is first deleted, and then inserted.&lt;br /&gt;&lt;p&gt;An equivalent 'REPLACE' statement looks like this:&lt;/p&gt;&lt;pre style="border: 1px solid rgb(206, 206, 206); padding: 5px; overflow: auto; background-color: rgb(251, 251, 251); min-height: 40px; width: 400px;"&gt;&lt;pre style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;  1: REPLACE &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=INTO&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;INTO&lt;/a&gt; TABLENAME &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=SET&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;SET&lt;/a&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" style="margin: 0em; background-color: rgb(255, 255, 255); width: 100%;"&gt;  2:   productName = '&lt;span style="color: rgb(139, 0, 0);"&gt;new product name&lt;/span&gt;',&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;  3:   productCost = '&lt;span style="color: rgb(139, 0, 0);"&gt;new product cost&lt;/span&gt;',&lt;br /&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" style="margin: 0em; background-color: rgb(255, 255, 255); width: 100%;"&gt;  4:   productId = '&lt;span style="color: rgb(139, 0, 0);"&gt;new or existing product id&lt;/span&gt;'&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;This makes 'REPLACE' handy as you don't need to worry about finding or deleting records when there is data that just needs to be added or renewed, and you can do it all in one statement that takes care of it for you.&lt;/p&gt;&lt;p&gt;Caution is needed with 'REPLACE' because it DELETES RECORDS if they exist, before inserting them. So if you have data that has information in that you don't want to loose then you need..&lt;/p&gt;&lt;p&gt;'ON DUPLICATE'!&lt;/p&gt;&lt;p&gt;Combining an 'INSERT' statement with 'ON DUPLICATE' functions similarly to 'REPLACE' except that it doesn't delete existing records, but gives you the power to decide what fields are replaced with what values.&lt;/p&gt;&lt;p&gt;An 'INSERT' with 'ON DUPLICATE' statement looks like this:&lt;/p&gt;&lt;pre style="border: 1px solid rgb(206, 206, 206); padding: 5px; overflow: auto; background-color: rgb(251, 251, 251); min-height: 40px; width: 400px;"&gt;&lt;pre style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;  1: &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=INSERT&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;INSERT&lt;/a&gt; &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=INTO&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;INTO&lt;/a&gt; TABLENAME &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=SET&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;SET&lt;/a&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; background-color: rgb(255, 255, 255); width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;  2:   productName = '&lt;span style="color: rgb(139, 0, 0);"&gt;new product name&lt;/span&gt;',&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;  3:   productCost = '&lt;span style="color: rgb(139, 0, 0);"&gt;new product cost&lt;/span&gt;',&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; background-color: rgb(255, 255, 255); width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;  4:   productId = '&lt;span style="color: rgb(139, 0, 0);"&gt;existing or new product id&lt;/span&gt;'&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;  5:   &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=ON&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;ON&lt;/a&gt; DUPLICATE &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=KEY&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;KEY&lt;/a&gt; &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=UPDATE&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;UPDATE&lt;/a&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; background-color: rgb(255, 255, 255); width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;  6:   productName = &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=Values&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;Values&lt;/a&gt;(productName),&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; background-color: rgb(251, 251, 251); width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;  7:   productCost = &lt;a style="color: rgb(0, 0, 255);" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=Values&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;Values&lt;/a&gt;(productCost)&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;Notice how the new value for the updated field is chosen from the 'Values' collection passed into the 'INSERT' statement. The new field value can be updated to any value that SQL can accept for the field type being update, and you don't have to update them all.&lt;/p&gt;&lt;p&gt;It can also be used with clauses that you would use with a plain 'INSERT' statement.&lt;/p&gt;&lt;p&gt;To find out more, hop on over to &lt;a href="http://dev.mysql.com/doc/refman/5.1/en/insert-on-duplicate.html"&gt;http://dev.mysql.com/doc/refman/5.1/en/insert-on-duplicate.html&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/28989665-1033288566730247122?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/1033288566730247122/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=1033288566730247122' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1033288566730247122'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1033288566730247122'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/02/mysql-and-warm-blankets-of-replace-and.html' title='MySQL and the warm blankets of Replace and On Duplicate'/><author><name>John Green</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-8862042025451117730</id><published>2010-01-27T09:28:00.001Z</published><updated>2010-01-27T09:28:54.875Z</updated><title type='text'>Using javascript to put the cursor at the end of a textbox</title><content type='html'>&lt;p&gt;All too often with software development it's the feature that seems the simplest that takes the most time to implement.&lt;/p&gt; &lt;p&gt;We had a &amp;lt;textarea&amp;gt; on a page that typically contained a lot of text. The customer wanted that textarea to have the focus when they arrived at the page, with the cursor at the end of the text ready for them to type some more. If there's enough text in the box for the vertical scrollbar to appear, we'd need that to be scrolled to the bottom too.&lt;/p&gt; &lt;p&gt;"Sure, no problem!" I said, thinking this would take about five minutes to implement. It was more like two hours of research and wrestling with browser compatibility.&lt;/p&gt; &lt;p&gt;Let me save you two hours. Skip to the end and use my code, or stick around and share my pain.&lt;/p&gt; &lt;p&gt;The nicest way to position a cursor within a text input or textarea is to use the setSelectionRange function. This can also be used to select portions of text:&lt;/p&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;document&lt;/span&gt;.getElementById('myTextBox')&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    .setSelectionRange(startPos, endPos);&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Setting startPos and endPos to be the length of the text puts the cursor at the end. So far so good. Unfortunately, this is a non-standard javascript function, and some browsers doesn't support it - most notably IE.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Another method to put the cursor at the end is to replace the contents of the textbox with itself. Easy peasy with jQuery:&lt;/p&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;$(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).val($(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).val());&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Unfortunately this doesn't work so well in Google Chrome: though it scrolls the textarea to the bottom, it leaves the cursor at the beginning of the text.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;OK, so we use a combination of the two - use setSelectionRange if it's available, replace the text if not.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Now, though, we find that Firefox and Google Chrome won't have scrolled the textbox. That's OK - we can set the scrollTop property to a large value (a little dirty, but hey - it works):&lt;/p&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.scrollTop = 999999;&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Phew! Job done, right?&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Well no - there's still one little "unique browser feature" we have to account for, and not one you'd ever know about until you met it doing this sort of thing.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This bit of code should just work in all browsers that support setSelectionRange:&lt;/p&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; len = $(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).val().&lt;span style="color: #0000ff"&gt;length&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.setSelectionRange(len, len);&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;If you're already saying "Ha! That'll never work in Opera!" then you're clearly too much of a cross-browser javascript-character-encoding genius to be reading this blog.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This will work fine if the textarea contains no carriage returns.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;It turns out that when Opera measures strings (using .length), carriage returns count as one character. However, when it comes to setSelectionRange, they count as two.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This means that in Opera, the cursor will be positioned &lt;em&gt;near&lt;/em&gt; the end, just not quite &lt;em&gt;at&lt;/em&gt; the end - it'll be back by as many letters as there are carriage returns in total.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Ironically, Opera's perfectly capable of handling unicode characters just fine. You can mix Roman, Greek and Chinese characters in your textbox to your heart's content and Opera will count them consistently, no matter how many bytes each one takes to be stored. Press Enter though and all is lost.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This cross-culture check was an important one to make. If Opera had been counting characters for .length and counting bytes for setSelectionRange, things would have got a little complicated - you never know quite how many bytes will be needed to encode the most exotic character a user might one day need. As it's only carriage returns that mess us up, we know we can only ever be out by at most a factor of two. Thus we can just say this:&lt;/p&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; len = $(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).val().&lt;span style="color: #0000ff"&gt;length&lt;/span&gt; * 2;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.setSelectionRange(len, len);&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;That will handle the worst case where the textbox contains only carriage returns.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;A quick check to ensure that no browser minds us trying to go beyond the end of the string like this, and we really, truly, are all done now.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;My only remaining moral obligation was to ensure that no one else had to reproduce this effort. I've bundled this all up into the &lt;a href="http://plugins.jquery.com/project/PutCursorAtEnd"&gt;PutCursorAtEnd jQuery plugin&lt;/a&gt;. The code for release 1.0 is as follows - tested in IE6, IE7, IE8, Firefox 3.5.5, Google Chrome 3.0, Safari 4.0.4, Opera 10.00, and probably safe in pretty much everything else too:&lt;/p&gt;&lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 400px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #008000"&gt;// jQuery plugin: PutCursorAtEnd 1.0&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #008000"&gt;// http://plugins.jquery.com/project/PutCursorAtEnd&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #008000"&gt;// by teedyay&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #008000"&gt;//&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #008000"&gt;// Puts the cursor at the end of a textbox/ textarea&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #008000"&gt;// codesnippet: 691e18b1-f4f9-41b4-8fe8-bc8ee51b48d4&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;($)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;{&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    jQuery.fn.putCursorAtEnd = &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.each(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;        {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            $(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).&lt;span style="color: #0000ff"&gt;focus&lt;/span&gt;()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            &lt;span style="color: #008000"&gt;// If this function exists...&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.setSelectionRange)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                &lt;span style="color: #008000"&gt;// ... then use it&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                &lt;span style="color: #008000"&gt;// (Doesn't work in IE)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                &lt;span style="color: #008000"&gt;// Double the length because Opera is inconsistent about whether a carriage return is one character or two. Sigh.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; len = $(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).val().&lt;span style="color: #0000ff"&gt;length&lt;/span&gt; * 2;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.setSelectionRange(len, len);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                &lt;span style="color: #008000"&gt;// ... otherwise replace the contents with itself&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                &lt;span style="color: #008000"&gt;// (Doesn't work in Google Chrome)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                $(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).val($(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).val());&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            &lt;span style="color: #008000"&gt;// Scroll to the bottom, in case we're in a tall textarea&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            &lt;span style="color: #008000"&gt;// (Necessary for Firefox and Google Chrome)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.scrollTop = 999999;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;        });&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    };&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;})(jQuery);&lt;/pre&gt;&lt;/pre&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-8862042025451117730?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/8862042025451117730/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=8862042025451117730' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8862042025451117730'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8862042025451117730'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/01/using-javascript-to-put-cursor-at-end.html' title='Using javascript to put the cursor at the end of a textbox'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-2287260397225899241</id><published>2010-01-11T16:04:00.004Z</published><updated>2010-01-11T16:07:56.029Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Marketing'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET 4.0'/><category scheme='http://www.blogger.com/atom/ns#' term='SEO'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><title type='text'>ASP.NET 4.0 now 50% more SEO friendly</title><content type='html'>&lt;p&gt;Okay, so I made that statistic up, but this post will cover some of the extra SEO related goodness Microsoft is including in the .NET framework.&lt;/p&gt;  &lt;p&gt;I previously mentioned the Microsoft SEO Toolkit which helps find SEO issues with your site &lt;a title="Article on SEO Toolkit" href="http://compsoftplc.blogspot.com/2009/06/microsoft-release-seo-optimisation.html"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Why is Microsoft including &lt;acronym title="Search Engine Optimisation"&gt;SEO&lt;/acronym&gt; features anyway?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;For public facing web sites and web applications, visitors are the lifeblood that keeps their businesses flowing. Every visitor is a potential customer, and who doesn't love customers?&lt;/p&gt;  &lt;p&gt;For most web sites, a high proportion of new traffic comes from search engines, so improving the relevancy of your site will lead to higher rankings in search results. This in turn leads to greater visibility and higher traffic.&lt;/p&gt;  &lt;p&gt;SEO can be the difference between success and failure, and that importance is reflected in the changes made in ASP.NET 4.0.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;So what's new?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;em&gt;1. Page.Keywords and Page.Description.&lt;/em&gt; &lt;/p&gt;  &lt;p&gt;The Keywords and Description meta tags have traditionally been the first place to optimise your pages, in keywords you can offer a list of words relevant to the current page. Description is used as a short description of the page, search engines often show this as part of the listing in the results, so it's very important.&lt;/p&gt;  &lt;p&gt;Whereas before you had to manually inject keywords and description into a page, you can now manipulate these directly via the Page class.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;2. Permanent Redirects&lt;/em&gt; &lt;/p&gt;  &lt;p&gt;Renaming links and removing old content that have previously been indexed can lead to an accumulation of stale links. Nothing turns visitors off like a big error page when they click one of your broken links.&lt;/p&gt;  &lt;p&gt;One way to handle these broken URLs is to do a Response.Redirect to a working URL, this means the visitor gets a page which is good, but results in the search engine believing the link is still fine, which it isn't. The best way to deal with this is to use a permanent redirect so search engines know the page has permanently moved, this means it will index the new URL and remove any dead links.&lt;/p&gt;  &lt;p&gt;.NET 4.0 introduces a nicer way with:&lt;/p&gt;  &lt;div   style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; direction: ltr; max-height: 200px; cursor: text;font-family:'Courier New',courier,monospace;font-size:8pt;" id="codeSnippetWrapper"&gt;   &lt;div    style="border-style: none; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;" id="codeSnippet"&gt;     &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum1"&gt; 1:&lt;/span&gt; Response.RedirectPermanent"("PathOfWin.aspx")&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;You can do this manually by returning the 301 status code yourself, but this is certainly a win for speed.&lt;/p&gt;&lt;p&gt;It also introduces the MVC method of:&lt;/p&gt;&lt;div   style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; direction: ltr; max-height: 200px; cursor: text;font-family:'Courier New',courier,monospace;font-size:8pt;" id="codeSnippetWrapper"&gt;&lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum1"&gt; 1:&lt;/span&gt; Response.RedirectToRoutePermanent("SomeRoute");&lt;br /&gt;&lt;!--CRLF--&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I'm sure there'll be lots more info on .NET 4.0 improvements to come in future posts.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-2287260397225899241?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/2287260397225899241/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=2287260397225899241' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/2287260397225899241'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/2287260397225899241'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2010/01/aspnet-40-now-50-more-seo-friendly.html' title='ASP.NET 4.0 now 50% more SEO friendly'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_gPRWTjkTHUU/SRY7HZpOTSI/AAAAAAAAAAM/OAQvr_kigYM/S220/tree-thumb.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-5663049226490866829</id><published>2009-12-21T10:23:00.001Z</published><updated>2009-12-21T10:23:14.498Z</updated><title type='text'>Dodging the browser's autocomplete when capturing the user pressing Enter</title><content type='html'>&lt;p&gt;You often need your web page to catch when the user presses Enter, and most of the time you want to click a button or a link when they do this.&lt;/p&gt; &lt;p&gt;This is nice and easy in javascript, but the browser's autocomplete feature can get in the way a bit: often the user will start typing, see the autocomplete suggestions, tap the down arrow a couple of times to pick one, then press enter to pick it.&lt;/p&gt; &lt;p&gt;If your javascript kicks in at this point, that's probably not what your user meant to happen: they just wanted to select that item from the autocomplete suggestions - they didn't want to click the "Next" link just yet.&lt;/p&gt; &lt;p&gt;I posted a &lt;a href="http://stackoverflow.com/questions/1648993/trap-the-enter-key-but-not-when-choosing-the-browsers-autocomplete-suggestion"&gt;question on stackoverflow&lt;/a&gt; to see if anyone else had found a solution to this that was better than saying "press tab, not enter!" to your users.&lt;/p&gt; &lt;p&gt;No one had an out-of-the-box solution, but one user suggested tracking the user pressing the up and down arrow keys - they'd have to press these to get into the autocomplete suggestions.&lt;/p&gt; &lt;p&gt;Much as this seems like a solution made out of string and sellotape, it totally works! We need a few more tweaks (catching page up/ page down too; not doing anything in Opera because it already does it itself).&lt;/p&gt; &lt;p&gt;I've implemented this in jQuery and made it available on jQuery.com as the &lt;a href="http://plugins.jquery.com/project/SafeEnter"&gt;SafeEnter plugin&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;You can use it like this, to click an element when the user presses enter:&lt;/p&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;$('#myTextbox').clickOnEnter(myElement);&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;. or you can handle the event yourself like this:&lt;/p&gt;&lt;pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;$('#myTextbox')&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    .listenForEnter()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    .bind('pressedEnter', &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #008000"&gt;// Do stuff&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    });&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;To save you going hunting for it, the full code of the plugin's here:&lt;/p&gt;&lt;pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 400px; padding-right: 5px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;span style="color: #008000"&gt;//codesnippet:2e23681e-c3a9-46ce-be93-48cc3aba2c73&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;($)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;{&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    $.fn.listenForEnter = &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.each(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;        {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            $(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).&lt;span style="color: #0000ff"&gt;focus&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                $(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).data('safeEnter_InAutocomplete', &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            });&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            $(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).keypress(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(e)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; key = (e.keyCode ? e.keyCode : e.which);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                &lt;span style="color: #0000ff"&gt;switch&lt;/span&gt; (key)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                    &lt;span style="color: #0000ff"&gt;case&lt;/span&gt; 13:&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        &lt;span style="color: #008000"&gt;// Fire the event if:&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        &lt;span style="color: #008000"&gt;//   - we're not currently in the browser's Autocomplete, or&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        &lt;span style="color: #008000"&gt;//   - this isn't a textbox, or&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        &lt;span style="color: #008000"&gt;//   - this is Opera (which provides its own protection)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!$(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).data('safeEnter_InAutocomplete') || !$(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).is('input[type=text]') || $.browser.opera)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                            $(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).trigger('pressedEnter', e);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        $(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).data('safeEnter_InAutocomplete', &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        &lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                    &lt;span style="color: #0000ff"&gt;case&lt;/span&gt; 40:&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                    &lt;span style="color: #0000ff"&gt;case&lt;/span&gt; 38:&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                    &lt;span style="color: #0000ff"&gt;case&lt;/span&gt; 34:&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                    &lt;span style="color: #0000ff"&gt;case&lt;/span&gt; 33:&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        &lt;span style="color: #008000"&gt;// down=40,up=38,pgdn=34,pgup=33&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        $(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).data('safeEnter_InAutocomplete', &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        &lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                    &lt;span style="color: #0000ff"&gt;default&lt;/span&gt;:&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        $(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;).data('safeEnter_InAutocomplete', &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                        &lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                }&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            });&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;        });&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    };&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    $.fn.clickOnEnter = &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(target)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.each(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;        {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;            $(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                .listenForEnter()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                .bind('pressedEnter', &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                    $(target).click();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;                });&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;        });&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;    };&lt;br /&gt;&lt;/pre&gt;&lt;pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,'Courier New',courier,monospace; font-size: 12px"&gt;})(jQuery);&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-5663049226490866829?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/5663049226490866829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=5663049226490866829' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5663049226490866829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5663049226490866829'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/12/dodging-browser-autocomplete-when.html' title='Dodging the browser&amp;#39;s autocomplete when capturing the user pressing Enter'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-4188110981275891225</id><published>2009-12-07T10:49:00.002Z</published><updated>2009-12-07T16:00:32.908Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server'/><category scheme='http://www.blogger.com/atom/ns#' term='IIS'/><category scheme='http://www.blogger.com/atom/ns#' term='MSDeploy'/><category scheme='http://www.blogger.com/atom/ns#' term='Neil Bostrom'/><title type='text'>Using MSDeploy as a build task in TFS</title><content type='html'>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="color: blue"&gt;&lt;font color="#000000" size="2" face="Verdana"&gt;MSDeploy is a new tool out by Microsoft that allows easy synching of files between servers. This can be used from inside IIS or just run from command line. &lt;/font&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="color: blue"&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&lt;font color="#000000" size="2" face="Verdana"&gt;You can read more on &lt;a href="http://iis.orcsweb.com/expand/WebDeploymentTool"&gt;MSDeploy here&lt;/a&gt;. Read &lt;a href="http://blogs.iis.net/msdeploy/default.aspx"&gt;MSDeploy's team blog&lt;/a&gt;. Nice article on using the &lt;a href="http://raquila.com/software/ms-deploy-basics/"&gt;msdeploy command line&lt;/a&gt;.&lt;/font&gt;&lt;/span&gt; &lt;/p&gt;  &lt;p&gt;&lt;span style="color: blue"&gt;&lt;font color="#000000" size="2" face="Verdana"&gt;I thought I would share an actual use of the MSDeploy in our TFS build scripts. It also uses the XmlUpdate task from the &lt;a href="http://msbuildtasks.tigris.org/"&gt;MSBuild Community Tasks Project.&lt;/a&gt;&lt;/font&gt;&lt;/span&gt; &lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Target &lt;/span&gt;&lt;span style="color: red"&gt;Name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;AfterDropBuild&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;    &lt;br /&gt;&amp;lt;!-- &lt;/span&gt;&lt;span style="color: green"&gt;Update web.config to be in release mode &lt;/span&gt;&lt;span style="color: blue"&gt;--&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;&amp;lt;XmlUpdate &lt;/span&gt;&lt;span style="color: red"&gt;XPath&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;/configuration/system.web/compilation/@debug&lt;/span&gt;&amp;quot; &lt;br /&gt; &lt;span style="color: red"&gt;XmlFileName&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;$(DropLocation)\$(BuildNumber)\Release\_Published&lt;br /&gt;                Websites\Site\web.config&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;Value&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;false&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;BuildStep &lt;/span&gt;&lt;span style="color: red"&gt;TeamFoundationServerUrl&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;$(TeamFoundationServerUrl)&lt;/span&gt;&amp;quot;&lt;br /&gt;   &lt;span style="color: red"&gt;BuildUri&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;$(BuildUri)&lt;/span&gt;&amp;quot;&lt;br /&gt;   &lt;span style="color: red"&gt;Message&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Deploying Website&lt;/span&gt;&amp;quot;&lt;br /&gt;   &lt;span style="color: red"&gt;Condition&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;'$(IsDesktopBuild)'!='true'&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;   &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Output &lt;/span&gt;&lt;span style="color: red"&gt;TaskParameter&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Id&lt;/span&gt;&amp;quot; &lt;span style="color: red"&gt;PropertyName&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;InstallerStepId&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;BuildStep&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;    &lt;br /&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Exec &lt;br /&gt;  &lt;/span&gt;&lt;span style="color: red"&gt;Command&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;'&lt;span style="color: blue"&gt;&amp;quot;C:\Program Files\IIS\Microsoft Web Deploy\msdeploy.exe&amp;quot; &lt;br /&gt;     -verb:sync &lt;br /&gt;     -source:contentpath=&amp;quot;$(DropLocation)\$(BuildNumber)\&lt;br /&gt;                          Release\_PublishedWebsites\Site&amp;quot; &lt;br /&gt;     -dest:contentpath=\\SERVER\Websites\Site&lt;/span&gt;' &lt;br /&gt;  &lt;span style="color: red"&gt;ContinueOnError&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;false&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;BuildStep &lt;/span&gt;&lt;span style="color: red"&gt;TeamFoundationServerUrl&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;$(TeamFoundationServerUrl)&lt;/span&gt;&amp;quot;&lt;br /&gt;   &lt;span style="color: red"&gt;BuildUri&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;$(BuildUri)&lt;/span&gt;&amp;quot;&lt;br /&gt;   &lt;span style="color: red"&gt;Id&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;$(InstallerStepId)&lt;/span&gt;&amp;quot;&lt;br /&gt;   &lt;span style="color: red"&gt;Status&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Succeeded&lt;/span&gt;&amp;quot;&lt;br /&gt;   &lt;span style="color: red"&gt;Condition&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;'$(IsDesktopBuild)'!='true'&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;OnError &lt;/span&gt;&lt;span style="color: red"&gt;ExecuteTargets&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;DeploymentFailed&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;Target&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Target &lt;/span&gt;&lt;span style="color: red"&gt;Name&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;DeploymentFailed&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;&amp;gt;&lt;br /&gt;    &amp;lt;!-- &lt;/span&gt;&lt;span style="color: green"&gt;Called if deployment of the web site fails &lt;/span&gt;&lt;span style="color: blue"&gt;--&amp;gt;&lt;br /&gt;    &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;BuildStep &lt;br /&gt;      &lt;/span&gt;&lt;span style="color: red"&gt;TeamFoundationServerUrl&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;$(TeamFoundationServerUrl)&lt;/span&gt;&amp;quot;&lt;br /&gt;      &lt;span style="color: red"&gt;BuildUri&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;$(BuildUri)&lt;/span&gt;&amp;quot;&lt;br /&gt;      &lt;span style="color: red"&gt;Id&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;$(InstallerStepId)&lt;/span&gt;&amp;quot;&lt;br /&gt;      &lt;span style="color: red"&gt;Status&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;Failed&lt;/span&gt;&amp;quot;&lt;br /&gt;      &lt;span style="color: red"&gt;Condition&lt;/span&gt;&lt;span style="color: blue"&gt;=&lt;/span&gt;&amp;quot;&lt;span style="color: blue"&gt;'$(IsDesktopBuild)'!='true'&lt;/span&gt;&amp;quot; &lt;span style="color: blue"&gt;/&amp;gt;&lt;br /&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;Target&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-4188110981275891225?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/4188110981275891225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=4188110981275891225' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4188110981275891225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4188110981275891225'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/12/using-msdeploy-as-build-task-in-tfs.html' title='Using MSDeploy as a build task in TFS'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7837996996309089023</id><published>2009-11-30T10:19:00.001Z</published><updated>2009-11-30T10:19:58.019Z</updated><title type='text'>Inline Block not quite Inline-blocking in IE8</title><content type='html'>&lt;p&gt;So we have been working on a site that has a good amount of buttons on it, but input buttons aren't that easy to make look nice. &lt;/p&gt;  &lt;p&gt;So i've been round the site fitting snazzy buttons built out of anchors and spans with backgrounds to complete the look.&lt;/p&gt;  &lt;p&gt;We've made use of the 'Inline-block' setting of the display css style. It looks proper nice in Firefox, Safari, Chrome, and Internet Explorer 7.&lt;/p&gt;  &lt;p&gt;But.&lt;/p&gt;  &lt;p&gt;Internet Explorer 8 makes a right meal out of it!&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_nyW099dZ_Zg/SxOcRKtwMOI/AAAAAAAAAA8/I8ZcGAffXME/s1600-h/image%5B19%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_nyW099dZ_Zg/SxOcRqTi1qI/AAAAAAAAABA/1Q9HZQdWS2Y/image_thumb%5B13%5D.png?imgmax=800" width="576" height="113" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;All buttons that are next to each other appear stacked on top. IE8 seems to have a problem coping with 'Inline-block' elements.&lt;/p&gt;  &lt;p&gt;However, there is a quick fix it would seem, to this stacking issue. All that is needed to get Internet Explorer 8 to honour the 'Inline-block' style is add a 'margin-right' of some value, like so:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_nyW099dZ_Zg/SxOcSCeekrI/AAAAAAAAABE/qtOqgcDXJs4/s1600-h/image%5B11%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_nyW099dZ_Zg/SxOcSq4CnDI/AAAAAAAAABI/Z_CoD5OH56I/image_thumb%5B7%5D.png?imgmax=800" width="589" height="118" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;and now all the browsers render the buttons nicely:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_nyW099dZ_Zg/SxOcS561p8I/AAAAAAAAABM/NwVQ-ZTlDPc/s1600-h/image%5B17%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_nyW099dZ_Zg/SxOcTdHvySI/AAAAAAAAABQ/FwJpTEawnss/image_thumb%5B11%5D.png?imgmax=800" width="663" height="100" /&gt;&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/28989665-7837996996309089023?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7837996996309089023/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=7837996996309089023' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7837996996309089023'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7837996996309089023'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/inline-block-not-quite-inline-blocking.html' title='Inline Block not quite Inline-blocking in IE8'/><author><name>John Green</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_nyW099dZ_Zg/SxOcRqTi1qI/AAAAAAAAABA/1Q9HZQdWS2Y/s72-c/image_thumb%5B13%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-2013758797337052618</id><published>2009-11-13T13:13:00.003Z</published><updated>2009-11-17T11:55:13.590Z</updated><title type='text'>Tim Jeanes - TechEd 2009 - Day 5</title><content type='html'>&lt;h4&gt;WIA308 - The Biggest Little-Known Features in Microsoft Silverlight&lt;/h4&gt;  &lt;p&gt;(All samples from this session are available at &lt;a href="http://www.wintellect.com/downloads/techedeurope2009.zip"&gt;http://www.wintellect.com/downloads/techedeurope2009.zip&lt;/a&gt;)&lt;/p&gt;  &lt;p&gt;Typically Silverlight uses the browser's connectivity for all network access. However, Silverlight 3 introduces the "client stack", that uses the operation system's networking APIs. This makes it a lot more stable and reliable - for example you now get full access to headers, and when you hit a SOAP error you'll now get the full error details back, instead of the munged version that the browser returns (the browser stack will only ever return a 200 or a 404). This also gives you access to http PUTs and DELETEs, rather than just GET and POST as supported by the browser stack.&lt;/p&gt;  &lt;p&gt;On the other hand, the client stack will never give you cached results; also you're limited to two concurrent connections.&lt;/p&gt;  &lt;p&gt;You just have to call this:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;HttpWebRequest.RegisterPrefix(&lt;span class="str"&gt;&amp;quot;http://[whatever]&amp;quot;&lt;/span&gt;,&lt;br /&gt;    WebRequestCreator.ClientHttp);&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;p&gt;... and then access connections as usual.&lt;/p&gt;&lt;p&gt;An event called CompositionTarget.Rendering is fired about 60 times per second on the UI thread, and can be used for custom animations. It's mostly used for games, but can be useful elsewhere, for example to work through a long-running queue of changes that need to be made to the UI - running on another thread would be inappropriate as that thread wouldn't be able to update the UI.&lt;/p&gt;&lt;p&gt;There's an enhanced frame-rate counter that monitors the amount of memory used by the GPU.. This is shown when EnableFrameRateCounter and EnableGPUAcceleration are both set to true.&lt;/p&gt;&lt;p&gt;BitmapCache.RenderAtScale can be used to scale up controls using the GPU, without pixelation.&lt;/p&gt;&lt;p&gt;A new class called Analytics allows you to monitor CPU load (both by this process and by all processes), as well as information about any GPUs that might be present.&lt;/p&gt;&lt;p&gt;The AssemblyPart class represents an assembly that's part of a Silverlight application. AssemblyPart.Load enables you to load assemblies at runtime, minimising the initial download time of the application. (NB. this can only be called on the UI thread.) By changing the CopyLocal property of a reference to false, you still get full intellisense when developing the application, but it's not sent down in the initial xap file. So long as you dynamically load the associated dll before you try to use it, your application will still work.&lt;/p&gt;&lt;p&gt;Be careful though! The JIT compiler compiles methods the first time it sees them: if this happens before you've loaded the assembly, you'll get a runtime exception. Also, the JIT compiler may choose to in-line some methods, so you don't know for sure when a method will be compiled. The safest way to avoid this (and retain strong-typing) is to use the [MethodImpl(MethodImplOptions.NoInlining)] attribute on the method that uses the dynamically-loaded reference.&lt;/p&gt;&lt;p&gt;Application Extension Services are services that have the same lifetime as the Silverlight application - they start just before the app, and end just after it ends. Implement IApplicationService (and optionally IApplicationLifetimeAware) on a class to make it such a service. We saw a sample where dynamic assembly loading was handled on-demand by such a service. It's a little complex, so check out the sample code.&lt;/p&gt;&lt;p&gt;The VisualTreeHelper class gives you access to the xaml that's been generated by templates in data-bound controls. This can be handy for programmatically styling items in a list, for example.&lt;/p&gt;&lt;p&gt;Silverlight 3 now has support for xaml-styled modal dialogs, using Child Windows.&lt;/p&gt;&lt;p&gt;VirtualizingStackPanel acts like a StackPanel that handles large numbers of items much better, by deferring templating the items until they scroll into view. ListBox now uses it by default, though ComboBox still doesn't.&lt;/p&gt;&lt;p&gt;RelativeSource can be used to bind a property of an element to the property of a nearby control (such as its parent).&lt;/p&gt;&lt;p&gt;AutomationPeer is usually used for accessibility issues, but can also be used to simulate button clicks.&lt;/p&gt;&lt;p&gt;NetworkInterface.GetIsNetworkAvailable() tells you whether or not a network is available. NetworkChange.NetworkAddressChanged is an event that will let you know when the network drops out or comes back.&lt;/p&gt;&lt;h4&gt;DEV312 - Using and Extending Microsoft Visual Studio 2010 Architecture and Modelling Tools&lt;/h4&gt;&lt;p&gt;A lot of this was typing code, so I won't reproduce it here, but there were a few key points.&lt;/p&gt;&lt;p&gt;Visual Studio uses MEF (Managed Extension Framework) as its extensibility mechanism, so it's now included in VS2010. It gives you extensions for commands, gestures (such as drag-and-drop) and model validators. This does most of the hard work for you, giving you easy points to plug into VS events, so you can just concentrate on the things you want to do.&lt;/p&gt;&lt;p&gt;Model validators can be set to run whenever the model is saved or opened, or run manually from a menu.&lt;/p&gt;&lt;p&gt;VSIX is a packaging technology that uses Office's xml model to package up your extensions and makes them much easier to install.&lt;/p&gt;&lt;p&gt;Whilst developing an extension, pressing F5 launches a new instance of Visual Studio, installs the extension, and enables debugging in the first instance. This instance is entirely separate from a normal one, down to using its own set of registry settings. This is so much easier than it used to be!&lt;/p&gt;&lt;p&gt;There's a whole now (and much, much easier) model for inspecting and altering existing code. This was a third-party library he found, but I'll see if I can dig it out - our code generation tools are a little painful to work with sometimes.&lt;/p&gt;&lt;p&gt;This session focused entirely on extending the class diagram and the UML model diagram, but I believe similar extensions are available for other actions and items in Visual Studio.&lt;/p&gt;&lt;h4&gt;DEV301 - Microsoft Visual Studio Tips and Tricks&lt;/h4&gt;&lt;p&gt;I was going to try to keep up, writing them here as they were explained, but there were too many coming too fast, and in any case there'll all here: &lt;a href="http://scottcate.com/tricks"&gt;scottcate.com/tricks&lt;/a&gt;. Thanks Scott!&lt;/p&gt;&lt;p&gt;(Most of these work in VS2008 as well - you don't have to wait for VS2010.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-2013758797337052618?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/2013758797337052618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=2013758797337052618' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/2013758797337052618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/2013758797337052618'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/tim-jeanes-teched-2009-day-5.html' title='Tim Jeanes - TechEd 2009 - Day 5'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-6856628383766201185</id><published>2009-11-13T07:59:00.003Z</published><updated>2009-11-13T13:36:11.340Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Archetecting Silverlight'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Contracts'/><category scheme='http://www.blogger.com/atom/ns#' term='TechED 2009'/><category scheme='http://www.blogger.com/atom/ns#' term='Neil Bostrom'/><title type='text'>Tech Ed 2009 - Friday - Neil Bostrom</title><content type='html'>&lt;p&gt;&lt;strong&gt;Can you keep a secret? The biggest little-known features in Microsoft Silverlight&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The default networking calls in Silverlight are all made through the browser. This has limitations to do with when web service return server faults. The browser can not interrupt it correctly.&lt;/p&gt;  &lt;p&gt;There are now two networking stacks in Silverlight 3. Browser stack and client stack. The client stack goes direct to the OS network stack. This stack works correctly for web service faults. The browser stack only support 200 and 404 return codes. This is the root of the problem with web service server fault limitation. A limitation with the client stack is that it does not get the content caching built in to the browser.&lt;/p&gt;  &lt;p&gt;To start using the client stack, you call HttpWebRequest.RegisterPrefix("http://", WebRequesterCreater.ClientHttp) and all calls after that will be on the client stack.&lt;/p&gt;  &lt;p&gt;You can check any request object by checking the CreaterContext.&lt;/p&gt;  &lt;p&gt;Silverlight 3 has an updated frame rate counter. To enable that, add ENableFrameRateCounter and EnableGPUAcceleration. &lt;/p&gt;  &lt;p&gt;RenderToScale is part of the BitmapCache that allows you to control the size of the bitmap that gets handed off to the GPU by Silverlight.&lt;/p&gt;  &lt;p&gt;Analytics class allows logging of CPU load and GPU usage.&lt;/p&gt;  &lt;p&gt;AssemblyPart.Load allows you to load up assemblies on the fly. This means you can keep your xap file small and just pulled down the extra parks as and when you need them. To lighten up your xap file, you can change your references to be copy local = false. This means it won't be shipped in your xap. For the dll to be easily downloaded, put a manual copy inside the ClientBin folder. &lt;/p&gt;  &lt;p&gt;This technique does have a big flaw. The CLR will die trying to find that reference. The CLR scans the method before it's run for all its types. MethodImpl(MethodImplOPtions.NoInlining) forces the JIT compiler not to scan that method for types it does not know.&lt;/p&gt;  &lt;p&gt;Application Extension Services is a service model for building services that run with your applications. All you need to do is implement IApplicationService, StartService, StopService. Silverlight will create the service as it starts and close it just before exiting.&lt;/p&gt;  &lt;p&gt;SynchrosationContext.Current has access to the UI dispatcher&lt;/p&gt;  &lt;p&gt;VisualTreeHelper is a handy class to grab controls inside Composite controls.&lt;/p&gt;  &lt;p&gt;RelativeSource allows two way template binding! Awesome!&lt;/p&gt;  &lt;p&gt;AutomationPeer class allows you to click buttons etc. &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Architecting Silverlight Applications with MVVM&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;MVVM is only a solution for large scale applications. It's not really ideal for small projects as it can be very bloated with layers etc.&lt;/p&gt;  &lt;p&gt;MVVM is Model, View, ViewModel. As you start using this concept it is very similar to MVC. You create a Model which is your entity with data access. View is your control XAML on the page and then you create a model for your view that has everything you can bind to. The advantage with this is that ObservableCollection does not need to exist in your model, you can just expose that in your VIewModel. This keeps your model very clean from UI dependant references.&lt;/p&gt;  &lt;p&gt;A cute way to reduce the dependency on the view calling the model in code is to use behaviours that you can just attach to elements in the view. One handy behaviour out of the box is CallDataMethod which can be wired up to to your method on the model. &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Code Contracts and Pex: Power Charge your assertions and Unit Tests&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;CodeContracts does validation on your code and comes up with warnings for certain coding errors.&amp;#160; Code Contracts allows you to make code method call intentions on your methods and code contracts will generate the correct code to run that intention.&lt;/p&gt;  &lt;p&gt;Pex allows you to do unit testings on firing cases of your code that you might not have considered.&lt;/p&gt;  &lt;p&gt;The Code Contracts does make for very bloated code. For interfaces you need to make two more classes to just say something doesn't need to be null.&lt;/p&gt;  &lt;p&gt;Code Contracts has a runtime checker, static checker and documentation output. So that single intention gets used in a bunch of places.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-6856628383766201185?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/6856628383766201185/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=6856628383766201185' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6856628383766201185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6856628383766201185'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/tech-ed-2009-friday-neil-bostrom.html' title='Tech Ed 2009 - Friday - Neil Bostrom'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-6044576005206138914</id><published>2009-11-12T17:03:00.001Z</published><updated>2009-11-12T17:03:47.315Z</updated><title type='text'>Tim Jeanes - TechEd 2009 - Day 4</title><content type='html'>&lt;h4&gt;WIA304 - Building Line-of-Business Applications Fast With Microsoft Silverlight and Microsoft .NET RIS Services&lt;/h4&gt;  &lt;p&gt;Given a data model, RIA services quickly generates the domain service classes for your web layer. The generated classes include skeleton methods to get, insert, update and delete the entities. Business rules (such as required fields) are automatically passed through so that the UI can respond to them.&lt;/p&gt;  &lt;p&gt;The uriMApper xaml element provides a way of routing URL patterns to xaml controls, making your Silverlight application more website-like, and preserving the functionality of the back button. It uses URLs in the pattern mysite.com#/Customers - the # ensures you're really staying on the same page, so the Silverlight control doesn't have to be reloaded.&lt;/p&gt;  &lt;p&gt;A goal of RIA Services is to take away some of the pain of handling asynchronous events, giving you cleaner, more readable code.&lt;/p&gt;  &lt;p&gt;RIA Services provides you with some additional Silverlight controls. One we looked at was the DataPagerControl, that attaches to a datagrid and returns pages of data, all with writing virtually no code.&lt;/p&gt;  &lt;p&gt;The DataControlToolkit adds a few new Silverlight controls to get you going more quickly with editing data. For example, the DataForm control will provide appropriate input controls for each field on your object.&lt;/p&gt;  &lt;p&gt;The ActivityControl can be wrapped round your input form. When its IsBusy property is set to true, it masks itself and shows a Please Wait animation. This property can be bound to your domain service class (that wraps the async calls), thus making it dead easy to give your users a synchronous experience.&lt;/p&gt;  &lt;p&gt;To enforce security, the [RequiresAuthentication] and [RequireRole] can be added to methods, preventing them from running if the user doesn't have sufficient credentials.&lt;/p&gt;  &lt;h4&gt;WIA303 - Microsoft ASP.NET AJAX: Taking AJAX to the Next Level&lt;/h4&gt;  &lt;p&gt;I've never been a big user of Microsoft's AJAX offering - I felt their control toolkit wasn't particularly good-looking and wasn't flexible enough if you didn't want exactly what it did out of the box, and I found jQuery could do at least as much as I wanted - so I was interested to find out what improvements they've made to &amp;quot;take things to the next level".&lt;/p&gt;  &lt;p&gt;First up, Microsoft have launched a Content Delivery Network, hosting many common javascript files, such as jQuery, the Microsoft AJAX.NET javascript library, and the jQuery Validation library (which I really must look into). jQuery.UI's not on there yet, but they're thinking about it.&lt;/p&gt;  &lt;p&gt;In .NET 4.0 webforms, you can say &amp;lt;asp:ScriptManager EnableCdn="true" /&amp;gt;, and it will automatically get all its script files from the CDN.&lt;/p&gt;  &lt;p&gt;The MS Ajax Minifier is a new offering that's available as a command line tool or an MSBuild task that works in two modes: normal minification (that strips whitespace, etc.) or hypercrunching (that goes a lot further - shrinking variable names and removing unreachable code). I think hypercrunching is probably the coolest name Microsoft's come up with for any of its products for quite some time.&lt;/p&gt;  &lt;p&gt;The minifier can also analyse your code and warn you of any problems it can recognise.&lt;/p&gt;  &lt;p&gt;(As an aside, a nice way to edit your project file in Visual Studio is to right-click it and select Unload, then right-click and select Edit. I never knew that - I've always been opening it in a separate text editor.)&lt;/p&gt;  &lt;p&gt;The new AJAX library isn't being shipped with VS2010 or .NET 4.0 - instead it's available as an open source project.&lt;/p&gt;  &lt;p&gt;It's written as a pure js library, so it will work equally well in webforms, MVC, or plain html. It integrates seamlessly with jQuery, and all its controls are exposed as jQuery plugins.&lt;/p&gt;  &lt;p&gt;start.js contains a script loader that will pull in any other scripts you need, and defined by the Sys.require() function. This makes it easy to ensure you get the all libraries you need, exactly once each. It also supports lazy loading, so you can load libraries at the point that you need them.&lt;/p&gt;  &lt;p&gt;Items can be added to the page using Sys.create.dataView. This looks for elements with a class="sys-template", which are treated as templates. The contents of the template are repeated for each item in your data source, and data fields within the template are demarked using {{field-name}}. An itemRendered event is fired for each item to allow you to perform your own custom tasks.&lt;/p&gt;  &lt;p&gt;Sys.bind() gives a really easy way to bind an item list with a detail view. You specify an event that fires when an item in the list is clicked, which you then use to populate your detail view. Using templates for both means you have to write almost no code.&lt;/p&gt;  &lt;p&gt;A major new feature is the client-side datacontext. This works much like the DataContext in LINQ2SQL in that it tracks changes to records in the browser,which can then be batched up into a single AJAX post when the save button is clicked. This also supports two-way binding, so you can have the text in html elements be automatically updated in response to the user changing the text in a textbox.&lt;/p&gt;  &lt;h4&gt;WIA401 - Enhancing the Design-Time Experience for Microsoft Silverlight 3&lt;/h4&gt;  &lt;p&gt;When developing controls to be used in Silverlight, bearing in mind how the designers will experience them in Blend can make a big difference to how ready they are to slap you.&lt;/p&gt;  &lt;p&gt;A new feature in Blend is the ability to add sample data. This makes it much clearer what the control will look like at runtime, without having to access any live data.&lt;/p&gt;  &lt;p&gt;Attributes can improve how the control appears both in Blend and at runtime. For example, giving a property Category and Description attributes puts the property into its own group in the designer, with tooltip text to indicate what its function is. Further attributes can change how the value is entered, how it is validated, where it appears in the list, etc.&lt;/p&gt;  &lt;p&gt;All the design-time code is wasted once you come to deliver your final product, so it makes sense to separate your design-time code into a separate assembly, but putting it into separate projects in Visual Studio. To do this, you must follow a naming convention for the project (and thus dll) names, and put classes in each project with the same names. This will then be respected by the design environment. Your projects should be named&amp;#160; *.Design, *.VisualStudio, *.Design.Editors, *.Expression.Design.&lt;/p&gt;  &lt;p&gt;Behaviours are a powerful tool that allow you to specify a lot of functionality without any code. Some are available out of the box, such as making an item draggable, but you can also make your own, configurable by properties in the property box in Blend.&lt;/p&gt;  &lt;h4&gt;WIA307 - Cool Graphics, Hot Code: Visual Effects in Silverlight&lt;/h4&gt;  &lt;p&gt;(All samples from this session are available at &lt;a href="http://www.wintellect.com/downloads/techedeurope2009.zip"&gt;http://www.wintellect.com/downloads/techedeurope2009.zip&lt;/a&gt;)&lt;/p&gt;  &lt;p&gt;A class called PageTurn.cs is a class that encapsulates the Page-Turn framework. Given pairs of canvases (for the left- and right-hand pages), this provides a clean page-turning animation.&lt;/p&gt;  &lt;p&gt;The WriteableBitmap, new in Silverlight 3, is the root of all sorts of visual goodness. This lets you generate images on the fly, as well as taking a snapshot of controls in the running application. This can be used for anything from drawing Mandelbrot Sets, to capturing frames from a video, producing a draggable magnifying glass or the much over-used Shiny Wet Black Floor effect.&lt;/p&gt;  &lt;p&gt;[Aside: If your xaml contains a large picture, but you're scaling it down, then if you make a WriteableBitmap from this, telling it to scale up, Silverlight is clever enough to use the original large bitmap, rather than the smaller scaled one, thus avoiding pixelated blockiness.]&lt;/p&gt;  &lt;p&gt;We saw a little more of HLSL for building custom pixel shaders too. It was developed by Microsoft and is used by DirectX, so is very high-performance. It's based on C and looks a little crazy, but it's maybe not as scary as I'd thought. We saw how this can also be used to generate the Wet Floor effect. This has the big advantage that it's real time, so if your original xaml changes, so does the reflection.&lt;/p&gt;  &lt;p&gt;However, it's worth noting that (for now) Silverlight only uses the CPU to execute the pixel shaders; if it ever uses the GPU, we can expect much better performance.&lt;/p&gt;  &lt;h4&gt;DEV316 - Model-Based Testing Made Easy with Spec Explorer 2010 for Visual Studio&lt;/h4&gt;  &lt;p&gt;Spec Explorer explores your C# code and draws a state machine graph of the possible routes through it. This gives a different view of the model that can be (possibly) more easily compared with the original requirements. From this, it generates unit tests that will trace each route though the code.&lt;/p&gt;  &lt;p&gt;It's a little bit crazy and I don't think I'll ever use it, and that's all I've got to say about that.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-6044576005206138914?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/6044576005206138914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=6044576005206138914' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6044576005206138914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6044576005206138914'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/tim-jeanes-teched-2009-day-4.html' title='Tim Jeanes - TechEd 2009 - Day 4'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-6080352248098012974</id><published>2009-11-12T13:25:00.003Z</published><updated>2009-11-13T13:45:34.641Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='SQL Server 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='Silverlight 3'/><category scheme='http://www.blogger.com/atom/ns#' term='Team Foundation Server'/><category scheme='http://www.blogger.com/atom/ns#' term='TechED 2009'/><title type='text'>Tech Ed 2009 - Thursday - Neil Bostrom</title><content type='html'>&lt;p&gt;&lt;strong&gt;Building Line-of-Business Applications Fast with Microsoft Silverlight and Microsoft .NET RIA Services&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;RIA services provides a pattern to write application logic that runs on the mid-tier that is projected on the client side. Making producing 3 tier application simpler. It's not just restricted to Silverlight.&lt;/p&gt;  &lt;p&gt;Tim started off by showing the new Silverlight Business application template that comes with Visual Studio 2010 out of the box. This template seems pretty complete with loads of functionality like forms transitions, login, register, navigation, resources and styling. Very sexy, well worth looking through this template.&lt;/p&gt;  &lt;p&gt;Domain service class is the guts of RIA services. When adding that class it prompts to point at your model. It then generates an API using your model, insert, update, delete, etc, methods for all your entities.&lt;/p&gt;  &lt;p&gt;RIA services does its querying with two methods, one is the model collection name (Employees), you would bind to that. After that you would populate that collection using the Load method on the context.&lt;/p&gt;  &lt;p&gt;RIA services also includes some out of the box helper controls. One of them being the data pager control. As this control works on IQueryable in your model, it does true server side paging.&lt;/p&gt;  &lt;p&gt;RIA services takes advantage of the Data annotation syntax, similar to AJAX and MVC. This is a general direction in Microsoft which is great. We can implement this once in our common code and get validation for free on almost any client type. &lt;/p&gt;  &lt;p&gt;RequestAuthenication and RequiresRoles is a nice way to control method calls using forms authentication on your server side.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Successfully Administering and Running Microsoft Visual Studio Team System Team Foundation Server 2008/2010&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Turns out the install success rate for TFS 2008 was quite low. Looks like we were lucky on that front. You can never rename a team project, that's why Microsoft uses codenames for projects!&lt;/p&gt;  &lt;p&gt;TFS performance comes from hard disk speed. Disk read / writes in SQL is where the real hit in TFS is. Try to split the databases out.&lt;/p&gt;  &lt;p&gt;It's recommended that you only use a single team project for your company. Use iterations and areas to break down projects. Microsoft has a single team project for "Office" and all the projects (Word, Excel etc) are all in that project. The main reasons behind this is Work items can't be moved between team projects, the out of box reports work on a single team project.&lt;/p&gt;  &lt;p&gt;Microsoft suggests to run TFS in a virtual environment. Benefits come from snapshot and disaster recovery.&lt;/p&gt;  &lt;p&gt;When splitting the tiers up, it is suggested to have sql and SSRS and web tier on the other.&lt;/p&gt;  &lt;p&gt;Read the online notes, LOADS AND LOADS of tips on performance. Legend!&lt;/p&gt;  &lt;p&gt;TFS 2010 installation has been massively simplified. Project collections now allow moving of everything to different to servers. All the new features in TFS 2010 are only available in VS 2010.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Enhancing the design-time experience for Microsoft Silverlight 3&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This session is talking about creating controls that are blend friendly. That appear in Blend and are easy to design. When creating controls that would call data or webservices, check if in design time and return sample data in place of live data.&lt;/p&gt;  &lt;p&gt;Overide ArrangeOverride and MeasureOverride to run code on resize or move in design time. Use Dependecy Properties to make control properties available in Blend. Standard meta attribute like Description, Category, DisplayName, PropertyOrder, NumberRange, NumberIncrement, NumberFormat, EditorBrowsable will get used by Blend to breakdown the placement of the property.&lt;/p&gt;  &lt;p&gt;With all this extra design time code, you can get a large code base. It is suggested you break out the design time code into a new dll. If you name that DLL *.Design.dll, VS and Blend will go looking for it and use them on the fly. If you name it *.Expression.Design.dll only blend will use it. If you name it *.VisualStudio.Design.dll, visual studio will automatically pick it up. In this new dll, add reference to Microsoft.Windows.Design to get access to the extension support. &lt;/p&gt;  &lt;p&gt;Next topic was Behaviours. Blend has a bunch of behaviours out of the box and there is an option in blend to pull down more. Behaviours is a very easy way to wrap up a small set of functionality you would want to apply to any control.&lt;/p&gt;  &lt;p&gt;To build your own behaviour, inherit from Behaviour in System.Windows.Interactivity. If you want to limit it to a type, then pop that in the generic type. AssicatedObject stores what object the behaviour is being attached to.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Debugging Microsoft ASP.NET and Other Microsoft .NET Production Issues with WinDbg and Microsoft Visual Studio .NET 2010&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This session is a favourite of mine, been to it for a few years and has always been very informative. This year it has been updated to take advantage of the VS 2010 feature that allows easy opening and diagnosing memory dump files. In Visual Studio 2010 the Parallel Stacks window shows a diagram of where every thread is and its stack in a lovely chart, giving you loads of insight into what's going on with your website.&lt;/p&gt;  &lt;p&gt;As always Tess got down and dirty with some WinDb.exe action. WinDb.exe is a low level debugging tool that is not aware of .NET. So to give it some knowledge of .NET you need to first load sos.dll. You do this by running the following command:&lt;/p&gt;  &lt;p&gt;.loadby sos mscorwks&lt;/p&gt;  &lt;p&gt;Once you have done this you can walk through some of the CLR using an array of commands. Some of the interesting things you can do is say:&lt;/p&gt;  &lt;p&gt;!dumpheap -stat&lt;/p&gt;  &lt;p&gt;This will list all of the objects on the heap. From here you can drill into the objects for more information by using&lt;/p&gt;  &lt;p&gt;!do (memoryaddress)&lt;/p&gt;  &lt;p&gt;Once you find something that you believe should have been GC'ed, you can run the following command:&lt;/p&gt;  &lt;p&gt;!gcroot (memoryaddress)&lt;/p&gt;  &lt;p&gt;To give you a tree of what the GC is holding on to! This is so immense!&lt;/p&gt;  &lt;p&gt;If you forget what the commands are, you can easily load up a command file that gives a handy context menu on the right using:&lt;/p&gt;  &lt;p&gt;.cmdtree c:\debuggers\cmdtree.txt&lt;/p&gt;  &lt;p&gt;You can get the cmdtree.txt from Tess's website.&lt;/p&gt;  &lt;p&gt;Debug Diag Tool can capture memory dumps on the fly or look for requests holding. Its produced by the IIS team and can be easily downloaded and installed.&lt;/p&gt;  &lt;p&gt;Tinyget is another handy little tool to stress test websites. Means you can prep your website before taking a memory dump.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;All You Needed to Know about Microsoft SQL Server 2008 Failover Clustering&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I know nothing about failover clustering so this was going to be a sure win! Interestingly clustering only helps with machine fail over, not database failure.When a node does fail over, any application will fail to connect while the next node comes online. So you need to put retry code in to keep your application running.&lt;/p&gt;  &lt;p&gt;SQL server 2008 clustering works better with Windows Server 2008 R2 clustering. So the first thing you would do is setup Windows Server Clustering. Once you have done that you can then install the SQL Server clustering installation on your primary machine. You would then add all the other machines using the Add Node option in the setup wizard.&lt;/p&gt;  &lt;p&gt;Sexy feature of clustering is that you can rollout patches and service packs without any downtime by applying the patches to each node, one at a time. This gives you good uptime as there is no need to take your application offline. You can even do full version upgrades, so moving from SQL 2005 to SQL 2008 with only a min or two's worth of downtime which is just the database script upgrading to SQL 2008.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-6080352248098012974?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/6080352248098012974/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=6080352248098012974' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6080352248098012974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6080352248098012974'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/tech-ed-2009-thursday-neil-bostrom.html' title='Tech Ed 2009 - Thursday - Neil Bostrom'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-381461192878320512</id><published>2009-11-11T17:38:00.001Z</published><updated>2009-11-11T17:38:26.146Z</updated><title type='text'>Tim Jeanes - TechEd 2009 - Day 3</title><content type='html'>&lt;h4&gt;DEV310 - Software Testing with Microsoft Visual Studio Team System 2010: Part2, Making It Real&lt;/h4&gt;  &lt;p&gt;TFS can be configured to fine degree to specify how much data is captured whilst the tester is executing manual tests (event log, intellitrace, system information, test impact, video recorder, etc. can be turned on and off, and various settings tweaked for each of them). This could be very useful in avoiding massive bloat. Worth noting is that if you're not careful you'll capture all activity in all applications - not just the application being tested.&lt;/p&gt;  &lt;p&gt;I'm &lt;em&gt;so&lt;/em&gt; looking forward to Intellitrace - the ability to wind forwards and back through the code whilst debugging is going to change everything. TFS also allows you to enable this whilst the testers are testing, so the developers can replay the code execution later.&lt;/p&gt;  &lt;p&gt;(When using Intellitrace, it's important to access websites by machine name, rather than localhost, otherwise the recording won't work correctly.)&lt;/p&gt;  &lt;p&gt;TFS has a new feature called Test Impact Analysis. This records which lines of code are executed by each test case. This means that when you start testing against a new build, it will highlight which tests should be rerun. If you change something that isn't managed code (such as html), you can manually record which tests this impacts.&lt;/p&gt;  &lt;p&gt;You can specify configuration information for manual tests - for example you can list the browsers that the test should be run against. The tester will see this as multiple tests - one for each configuration.&lt;/p&gt;  &lt;p&gt;TFS has hierarchical work items - you can break tests down into test cases, and link the tests to work items that are user stories, for example.&lt;/p&gt;  &lt;p&gt;You can specify test steps for a test case: you can be as granular as you like with this (either "create an account" or "click on account, click register, type your name", etc.). Granular steps are a pain to write, but mean you can track more accurately where the test fails.&lt;/p&gt;  &lt;p&gt;You can put parameters in the test steps by prefixing with an @ (e.g. "type @FullName"). You can then specify lists of values for these parameters that will then appear as multiple iterations of the same test. The test script tool that the tester will send these values to the application being tested with a single button click, avoiding typos.&lt;/p&gt;  &lt;p&gt;Test steps can be marked as verification steps. You can specify the expected result, and this will oblige the tester to mark whether this step succeeded or failed.&lt;/p&gt;  &lt;p&gt;When running tests, the tester has the option to record their actions. These can be played back later (in whole or in part) to speed things up when they redo the test later. This works across different iterations of the same test.&lt;/p&gt;  &lt;p&gt;These action recordings can then be converted into Coded UI Tests. The code it generates is nice and clean - each granular step becomes a separate method in the generated code. It's impressive stuff - if a step involves clicking a link on a webpage, and you later change that link's id, the test will still try pretty hard to find the right link, by name or by inner text, etc.&lt;/p&gt;  &lt;p&gt;The Coded UI Tests can (and in most cases should) be tweaked by the developer to add assertions that match the verification steps in the original manual test. There's a tool that allows you to pick DOM elements directly from the browser, and add assertions as to what properties those elements should have in order for your test to pass.&lt;/p&gt;  &lt;p&gt;When specifying build processes in TFS, you can have it deploy your application onto a virtual environment of a number of virtual machines in a virtual environment - one VM to host the application and another to host the database, for example. All automated tests (including the the Coded UI Tests) can then be run automatically against these. As the Coded UI Tests actually open a browser to run them, these can also be run on VMs in the virtual environment, testing various browsers on various OSes.&lt;/p&gt;  &lt;p&gt;Damn, this is good!&lt;/p&gt;  &lt;h4&gt;DEV304 - Extend Your Web Server - What's New in IIS and the Microsoft Web Platform&lt;/h4&gt;  &lt;p&gt;The Web Platform Installer is a smart new tool that makes it very easy to get a web server up and running very quickly. It can install anything you choose from a massive range of products: all you need from Microsoft (.NET, IIS, etc.), plus a whole bunch of third party items (DasBlog, DotNetNuke, Wordpress, etc.). It can be used again later to fetch new tools and add-ons.&lt;/p&gt;  &lt;p&gt;Server Core is a cut-down version of Windows that has a minimal GUI (just a command line interface) - almost all configuration has to be done remotely. (You have to explicitly turn on remote configuration for IIS though, as you'd expect.) .NET is now available on this platform. They've removed some components (WPF, of course) to keep the overall size of Server Core minimal, but ASP.NET is there.&lt;/p&gt;  &lt;p&gt;IIS 7.5 supports secure FTP! At last!&lt;/p&gt;  &lt;p&gt;IIS has a URL rewriter that can transform nice-looking URLs (example.com/user/foo) to the ones your application requires (example.com/user.aspx?username=foo). This gives you a nice way to smarten up the URLs of an existing application without having to change the source code of the application. The tool to set this up is pretty cute: you only have to give an example URL and it will figure out the regex to use to create the transformation.&lt;/p&gt;  &lt;h4&gt;WIA202 - Microsoft Silverlight 3 - What's in it for Developers?&lt;/h4&gt;  &lt;p&gt;Now that more devices that access websites are using H.264/AAC encoding, it's good to see that Silverlight now supports this too, though DRM isn't currently supported (which is either a good or a bad thing, depending who you are.).&lt;/p&gt;  &lt;p&gt;GPU acceleration is supported now (though you have to opt-in for your application: it's not turned on by default). This doesn't include 3D support just yet, though it should be out in a later version. The setting EnableCacheVisualisation will highlight the parts of your Silverlight app that will benefit from GPU acceleration.&lt;/p&gt;  &lt;p&gt;However, you can simulate 3D using Silverlight's perspective 3D function. This uses plane projection transforms to give the 3D effect.&lt;/p&gt;  &lt;p&gt;On animation, they've built in a bunch of easing functions - the ones available will look very familiar if you use jQuery's easing plug-in.&lt;/p&gt;  &lt;p&gt;Pixel shaders can add effects to the visual display. There are two out-of-the-box ones: a drop shadow and a blur. You can write your own if you're not afraid of HLSL. As an easier alternative, you can use the ones made for WPF, available at wpffx.codeplex.com. Only one effect can be applied at a time, so if you want a drop shadow and a blur, you have to fudge it by containing your control in a canvas, then applying one effect to the canvas and one to the control itself.&lt;/p&gt;  &lt;p&gt;You can take a snapshot of Silverlight controls as bitmaps. This can be handy to show reflection effects, a ghosted item whilst dragging and dropping, or for more reliable printing.&lt;/p&gt;  &lt;p&gt;Silverlight now has a messaging system that allows multiple instances of Silverlight to communicate with one another. They don't have to be in the same browser window, nor even the same browser: an instance of IE can communicate with an instance of Firefox.&lt;/p&gt;  &lt;h4&gt;DEV304 - Deep Dive Into Developing Line-of-Business Applications Running in the Cloud&lt;/h4&gt;  &lt;p&gt;Windows Azure is great at supporting massively scalable applications, but there are a number of concerns that will need to be addressed for most such line-of-business applications.&lt;/p&gt;  &lt;p&gt;The first is Multi-Tenancy. If your application is to branded by multiple companies, it's important that tenant A cannot access tenant B's data. If you're using Azure tables for your data storage, you can easily create a new table for each tenant. Access to these are very fast, and having separate tables ensures each tenant's data is held entirely separately.&lt;/p&gt;  &lt;p&gt;If you're using SQL Azure you could create a new database for each tenant. Though this would be a maintenance nightmare for the DBA in traditional computing, Azure takes away this overhead: creating a new database is quick and hassle-free.&lt;/p&gt;  &lt;p&gt;Another issue is customisation and extensibility: each customer might want to skin the UI according to their brand; they may also need to alter the business logic within their slice of the application. This lends itself well to Azure tables: as the table can hold entirely heterogeneous data, adding additional properties to rows is no problem. The developer only has to remember to handle to case where the value is missing on older records.&lt;/p&gt;  &lt;h4&gt;DEV207 - How Microsoft Does It: Internal Use of TFS and Team System for Software Development&lt;/h4&gt;  &lt;p&gt;Microsoft have made extensive use of their own tools to develop their software, so they've learnt a lot along the way.&lt;/p&gt;  &lt;p&gt;One interesting point they raised was that by deferring fixing bugs, they never got round to it. Though it's more fun to be developing new code, the bugs mount up like the debt you don't want to think of. They found a much better way was always to fix all known bugs before moving on to the next implementation task. (A nice new feature of TFS is that you can set it up so that it will reject a check-in that doesn't compile or pass all unit tests.)&lt;/p&gt;  &lt;p&gt;Obviously Microsoft is a far bigger company than we are, so the scale of their development doesn't compare that well with us. However, it was interesting to note that they prefer to form Feature Crews: a team of no more than five developers and five testers, dedicated to producing a single feature over 6-10 weeks. This size compares well with the sort of development team that we find works as well.&lt;/p&gt;  &lt;p&gt;They've dropped their policy of 70% code coverage for unit tests, as they found that having too many led them to spending too much time maintaining unit tests and not enough time developing features. Instead, they try to target the most common usage path of the application. Interesting: we're currently wrestling with the balance of test coverage versus maintenance overhead.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-381461192878320512?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/381461192878320512/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=381461192878320512' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/381461192878320512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/381461192878320512'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/tim-jeanes-teched-2009-day-3.html' title='Tim Jeanes - TechEd 2009 - Day 3'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-3632951324284458102</id><published>2009-11-11T08:58:00.001Z</published><updated>2009-11-12T08:04:24.648Z</updated><title type='text'>Tech Ed 2009 - Wednesday - Neil Bostrom</title><content type='html'>&lt;p&gt;&lt;strong&gt;Get Virtualised with Microsoft System Centre Essentials&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This is the first interactive session I've been to this year. As we are currently running Virtual Server at work, I thought this would be a good session to find out where Microsoft are going with virtualisation. I was very impressed with System Essentials.It has all the management of your network in one place. Very powerful support for virtualisation right out of the box.&lt;/p&gt;  &lt;p&gt;The best feature they showed is a three step wizard for virtualising a physical machine to a virtual machine. It will take across everything from the physical machine using bit copy. This will save us loads of hassle when moving existing boxes into Virtual Server. The manager is pretty clever when it comes to knowing which vm's will run on which host based on hard disk, memory etc.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Extend Your Web Server: What's New in Internet Information Server (IIS) and the Microsoft Web Platform&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;David Lowe is running this session covering the new features in IIS 7.5 that comes with Windows Server 2008 R2. He started out by covering the web platform installer. It allows you to setup your server quickly and easily. It has third party products built into it allowing you to install everything you need to run on your web server. These third party tool are like WordPress and Umbraco.&lt;/p&gt;  &lt;p&gt;The new MMC interface now works over HTTP allowing you to easily mange your server from anywhere. Nice!&lt;/p&gt;  &lt;p&gt;With Windows Server 2008 R2 now support ASP.NET on Server Core. This means you can have your web server with only command line to reduce your attack surface. The server core commands look scary as!&amp;#160; &lt;/p&gt;  &lt;p&gt;Something shocking he mentioned while chatting about this is that Window Server R2 is only 64bit!!!!&lt;/p&gt;  &lt;p&gt;IIS extensions are now fully supported in managed applications in Microsoft.Web.Administration.&lt;/p&gt;  &lt;p&gt;They have a whole bunch of extensions out of the box, giving you loads of feautes like FTP, Media Server, Routing, Advanced Logging and even database explorer.&lt;/p&gt;  &lt;p&gt;Secure FTP now comes out of the box in R2. You can assign SSL certificates on your FTP site to make sure all passwords are encrypted.&lt;/p&gt;  &lt;p&gt;IIS Application request routing module is a very nice tool for setting up web farms just using IIS. It can also be used for for forwarding sites to different boxes.&lt;/p&gt;  &lt;p&gt;Must remember to use the Search Engine optimization tool more. Very sexy!&lt;/p&gt;  &lt;p&gt;Never seen Best Practices analysis before and looks like a good tool to get security tips on your websites.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Microsoft Visual Studio Team Foundation Server 2010: Becoming productive in 30 minutes&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This session is showing how to install TFS 2010 in 30 minutes. Microsoft have done some good work to make the install / configuration much easier. There is now 64x version of TFS, meaning it can make full use of uber servers.&lt;/p&gt;  &lt;p&gt;TFS now comes with a lovely administration console to tweak settings for TFS.&lt;/p&gt;  &lt;p&gt;In the new version of TFS they have introduced a concept of ProjectCollection. This means that projects are grouped into collections. These collections can be moved from server to server.&lt;/p&gt;  &lt;p&gt;This session did a really nice demo of TFS with VS 2010. See all the little changes on day to day work.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Microsoft Silverlight 3: What's in it for developers&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Silverlight 3 introduced GPU acceleration support. This feature is opt in meaning that you have to say that your silverlight project will use GPU acceleration. It only works in full screen mode on the mac due to a restriction on the mac OS. LIttle tip bit that came out was that stretching pixels in hard cpu work. GPU acceleration really helps with that. To enable GPU acceleration, you pop EnableGPUAcceleration in the html object tag. You also have to enable any elements in your xaml that you want to be accelerated by adding CacheMode="BitmapCache". They have a debug tag called EnableCacheVisualisation which will show you what parts of your silverlight application can be improved by GPU Acceleration.&lt;/p&gt;  &lt;p&gt;Silverlight 3 also got video streaming improvements and more easing functions. IIS Smooth streaming is now out of the box supported.&lt;/p&gt;  &lt;p&gt;Another nice feature that came in Silverlight 3 is local messaging support. This means we can send messages from multiple Silverlight controls. It does it via a shared memory concept. This communication can work across tabs and browsers.&lt;/p&gt;  &lt;p&gt;A quick demo was shown using the new navigation APIs. This includes support for links to jump to parts of your Silverlight application. Using this enables the use of the back and forward button. Very nice!&lt;/p&gt;  &lt;p&gt;The power behind the navigation support comes from the frame controls. You can also control the Uri that gets produced using UriMappers on the frame control.&lt;/p&gt;  &lt;p&gt;They have a nice system to break out any referenced assemblies in to smaller packages meaning the client is more likely to cache common references. This reduced your xap files.&lt;/p&gt;  &lt;p&gt;Sexy feature when using out of browser support in Silverlight 3 is CheckAndDownloadUpdateAsync(). This method will check the version of the local app and allow you to get the latest version before running the normal application.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Securing Microsoft Silverlight: Knowing the Enemy&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;As we are producing Silverlight applications, I thought I should get on top of this issue. The first topic was an easy one which is packet sniffing. Simple solution, use SSL!&lt;/p&gt;  &lt;p&gt;To protect data, keep it on the server and send down only the XAML. Isolated storage is not secured. Its just sitting around on the disk, open to the user.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;How Microsoft Does It: Internal Use of Team Foundation Server and Microsoft Visual Studio&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This session was done last year but has been updated with new stats. All the advice in this session is from Microsoft experience internally. One of the big problems they suffered with Visual Studio development was putting off bugs. Doing all the work upfront and fixing the bugs at the end. This caused a big problem as they took longer to fix later.&lt;/p&gt;  &lt;p&gt;The speaker showed a nice end to end storyboard of the visual studio 2010, 3 years ago. Very interesting to see where they went with it and how they associated them with work items.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-3632951324284458102?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/3632951324284458102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=3632951324284458102' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3632951324284458102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3632951324284458102'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/tech-ed-2009-wednesday-neil-bostrom.html' title='Tech Ed 2009 - Wednesday - Neil Bostrom'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-3676388317904032360</id><published>2009-11-10T16:55:00.001Z</published><updated>2009-11-10T17:02:37.492Z</updated><title type='text'>Tim Jeanes - TechEd 2009 - Day 2</title><content type='html'>&lt;h4&gt;Coincidentally in Berlin for the 20th anniversary of the fall of the Berlin wall.&lt;/h4&gt;  &lt;p&gt;20 years ago today a bunch of us got away without doing our German homework because our teacher was in such a good mood.&lt;/p&gt;  &lt;h4&gt;WIA203 - Streaming With IIS and Windows Media Services&lt;/h4&gt;  &lt;p&gt;IIS and WMS are two quite separate products, and which you use depends largely on your specific requirements and your available architecture.&lt;/p&gt;  &lt;p&gt;WMS2008 sits best on its own server, separate from the server holding the original content. It then does all its own smart caching, automatically dumping the less-viewed content from the cache, and preserving the media that is more on demand. A raft of recent improvements mean it can handle more than twice as many simultaneous connections as could WMS2003.&lt;/p&gt;  &lt;p&gt;On the other hand, if you're just delivering media from a web server, IIS Media Services may well be enough. It's a freely-available downloadable add-on to IIS that gives a bunch of features to improve media delivery.&lt;/p&gt;  &lt;p&gt;It has some nice settings to give more efficient usage of the available bandwidth. Typically users only watch 20% of the video media that they actually download, so the other 80% is wasted bandwidth that the media provider still has to pay for. You can configure IIS to treat media and other data files differently dependent on their file type. Typically you'd set it to download as fast as possible for the first 5-20 seconds, then drop to a proportion of the required bit rate for the rest of the video. This gives a quick spike on bandwidth initially followed by a constant rate of just enough to ensure the user doesn't experience any delays in the media they're viewing.&lt;/p&gt;  &lt;p&gt;If you need to control how and what the end user watches (for example, they may need to be forced to watch an advert before they can see the main content), you can control how they can stream and download the content. In the playlist you define on the server you can enable or disable the user's ability to skip videos or to seek within them. The URLs of the actual videos being sent are automatically obfuscated to ensure that the URL of the main content isn't guessable by the end user.&lt;/p&gt;  &lt;p&gt;Smooth streaming is now supported. This monitors the user's bandwidth and adapts the stream quality in almost-real time. This is achieved by splitting the original media into many 2-4 second long chunks and encoding each at several different qualities. IIS then delivers each chunk in succession, switching between qualities as the bandwidth allows. As it's monitored continuously, if the user experiences a temporary glitch, their video returns to its better quality within a few moments.&lt;/p&gt;  &lt;p&gt;Encoding at many bitrates is very CPU intensive, so doing this live is much harder work. Currently Microsoft has no offering that can manage this in real-time, so you'd need some third party hardware to do the hard work.&lt;/p&gt;  &lt;h4&gt;DEV317 - Agile Patterns: Agile Estimation&lt;/h4&gt;  &lt;p&gt;I suck at estimating timescales, and Getting Better At It has been on my list of tasks for the next period on every performance review I've had for the past 11 years. I'm glad to hear that I'm not alone - this was a very well-attended session where we commiserated together about how estimates (which are by definition based on incomplete information) becomes a hard deadline.&lt;/p&gt;  &lt;p&gt;A key concept is the Cone Of Uncertainty. This measures how inaccurate your estimates are as time goes by.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_zsifaW4TiJo/SvmbHeDdkmI/AAAAAAAAAB8/orUomC4pzkM/s1600-h/ConeOfUncertainty%5B2%5D.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ConeOfUncertainty" border="0" alt="ConeOfUncertainty" src="http://lh3.ggpht.com/_zsifaW4TiJo/SvmbHreLWhI/AAAAAAAAACA/DDovsxlsTwQ/ConeOfUncertainty_thumb.jpg?imgmax=800" width="244" height="180" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;A couple of points to note are that initial project estimates, based on the loosest information, are often out by a factor of 4 - either too long or too short; even when you have a clear idea of what the customer wants, estimates are still out by a factor of 2. Also notably, we can't guess with 100% accuracy when the software will be delivered until it's totally complete. Asked for a show of hands, the vast majority of the room said they've woken in the morning expecting to release a product today, end then haven't: even on the last day, we can't guess how long we've got left.&lt;/p&gt;  &lt;p&gt;As we can't avoid this, it's better to be honest about it and work with it.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;User stories&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#000000"&gt;The customer specifies a list of stories - items that must be in the product.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;em&gt;Planning poker&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#000000"&gt;From user stories, we make estimates of difficulty. This is to do with priorities - not time estimation. The estimates should be based on difficulty. Planning poker cards represent order of magnitude compared with baseline. Each person places their estimates simultaneously. Disagreements lead to discussions.&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#000000"&gt;Take a baseline: a task you know well (such as a login page), then compare the complexity of each other item with this (this is twice as hard as that, etc.). &lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;em&gt;Story points&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#000000"&gt;Break down stories into smaller pieces (that will later become your individual work items). Give each a number of story points: a number of units of relative size - multiples of say a notional hour or day, depending on the scale of the project. These aren't still really your time estimates as you don't really know yet how quickly you're going to work through them.&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#000000"&gt;Play planning poker again to decide the number of story points for each item.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;em&gt;Product backlog&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#000000"&gt;The list of work items becomes your backlog, each with an estimate attached to it. At this point you meet with the customer to prioritise the items in the backlog.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;em&gt;Velocity&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#000000"&gt;Developers commit to a number of story points for the first sprint. At the end of the first sprint, the number of completed story points is your velocity.&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#000000"&gt;TFS has some plugins that help to monitor and calculate this.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;em&gt;Re-estimation&lt;/em&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;font color="#000000"&gt;After each sprint, the customer may add more stories to the backlog, and can re-prioritise the backlog. The developers may also add bugs to the backlog.&lt;/font&gt;&lt;/p&gt;    &lt;p&gt;&lt;font color="#000000"&gt;Each sprint gives you increasingly accurate predictions of future delivery.&lt;/font&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;h4&gt;DEV303 - Source Code Management with Microsoft Visual Studio 2010&lt;/h4&gt;  &lt;p&gt;Branching has been improved: it's now a more first-class part of TFS. Branches have permissions associated with them to allow or prevent certain users from creating or merging branches. It's a faster process now as no files have to be checked out (or even copied to your local machine) to create a branch in TFS.&lt;/p&gt;  &lt;p&gt;You can create private branches by branching code and setting permissions on the new branch. Also, there's a graphical tool that shows how branches have been created and how they relate to one another. This is interactive, so branches can be created or merged from here.&lt;/p&gt;  &lt;p&gt;When viewing the history of a file or project, changesets that were branches can be drilled into to show the changes that happened in the main branch, prior to it being branched into your project.&lt;/p&gt;  &lt;p&gt;Changesets can be tracked visually through branches and merges - you can show where a change has been migrated between branches - either on the hierarchical diagram of changesets or on a timeline.&lt;/p&gt;  &lt;p&gt;It was always a pain to merge changes where there are conflicting file renames. Fortunately this has been significantly cleaned up. The conflict is now correctly detected and you're told the original name of the file as well as the two conflicting new names.&lt;/p&gt;  &lt;p&gt;Similar fixes have been implemented for the problem areas of moving files, making edits within renamed files, renaming folders, etc.&lt;/p&gt;  &lt;p&gt;These version model changes make it a whole lot clearer what's going on if you view the history for a file that's been renamed - even if it's renamed to the same name as a file that was previously deleted. If you're using VS2005/2008 with TFS2010, you'll need a patch to ensure this works.&lt;/p&gt;  &lt;p&gt;Rollbacks are now a proper feature - you don't have to resort to the command line power tool to do these. Also they now properly rollback merges (previously it would forget that the merge now hadn't taken place, so re-merging would be very difficult).&lt;/p&gt;  &lt;p&gt;A single TFS server can now have multiple Team Project Collections. These are sets of projects with their own permissions, meaning that different teams can use the same TFS installation without access to one another's projects.&lt;/p&gt;  &lt;h4&gt;WIA403 - Tips and Tricks for Building High Performance Web Applications and Sites&lt;/h4&gt;  &lt;p&gt;This was a fast-paced session with lots of quick examples. I've not listed them all, but a few of them are here:&lt;/p&gt;  &lt;p&gt;Simplifying the CSS can improve the performance of the browser. Basically speaking, the simpler the CSS rule, the more performant it will be. Also, using "ul &amp;gt; li" to specify immediate children is much more efficient than catching all descendents with "ul li".&lt;/p&gt;  &lt;p&gt;Javascript performance can be improved by making sure you use variables that are as local as possible. Similarly, the more local the property on an object (i.e. on the object itself or on its prototype), the quicker it can be accessed.&lt;/p&gt;  &lt;p&gt;A powerful feature of javascript is that it can evaluate and execute code in strings at runtime. However, this can be very slow. It's often used to run code with setTimeout - it's much better to use an anonymous function instead.&lt;/p&gt;  &lt;p&gt;Getters and setters for properties are generally good programming practice. However, as javascript isn't compiled, the slight overhead of traversing the setter/ getter method can double the time taken to access the property.&lt;/p&gt;  &lt;p&gt;The length property on a string or array is not fast: it has to count all the items in it. Thus saying for (var i = 0; i &amp;lt; myArray.length; i++) is very inefficient. Caching the length in a variable makes it faster. Or if you're iterating over DOM elements, you can use the firstChild and nextSibling properties instead: for (var el = this.firstChild; el != null; el = el.nextSibling)&lt;/p&gt;  &lt;p&gt;Having a lot of cases in a switch statement is also slow: each case has to be checked in turn. A sneaky trick that can be employed is to build an array of functions instead, and just call the appropriate one. Obviously this doesn't apply in every situation.&lt;/p&gt;  &lt;p&gt;Rather than having many small images on your page, it's better to have one large image and specify offsets for each one you want to show. SpriteMe is a handy tool that will make this mosaic for you: it scans your page for images and then glues them all together.&lt;/p&gt;  &lt;p&gt;Doloto is a tool that monitors your javascript and tracks which functions are called. It can then generate javascript library files that are dynamically loaded in the page as they are needed. It ensures that the most common functions are available immediately and others are loaded later. A quick demo on Google maps showed that it could reduce its bandwidth spent on retrieving javascript files by 89%. Impressive stuff!&lt;/p&gt;  &lt;p&gt;Microsoft Expression SuperPreview can render a page as it would appear in different versions of different browsers (Firefox, IE6, 7, and 8). It will show the results side-by-side (or even superimposed on one another) and even spot the differences for you (and highlight them).&lt;/p&gt;  &lt;h4&gt;WIA305 - What's New in ASP.NET MVC&lt;/h4&gt;  &lt;p&gt;A new feature is to be able to compose a view out of multiple calls to actions. This appears as &amp;lt;% Html.RenderAction() %&amp;gt;. This is a little smarter than Html.RenderPartial as you can perform any necessary business logic where it belongs in the correct controller instead of having to shoe-horn it in elsewhere.&lt;/p&gt;  &lt;p&gt;Areas allow you to group parts of your application into logical groups. It behaves like a folder in your project, with subfolders for models, views and controllers. There's also an AreaRegistration class that registers routes for the Area. Global.asax has to call AreaRegistration.RegisterAllAreas to activate these. By default, the area appears at the top level of its views' URLs.&lt;/p&gt;  &lt;p&gt;An exception is thrown at runtime if Areas contain controllers with the same name. This can be circumvented by specifying which namespace should be used for the controller, when you register the route.&lt;/p&gt;  &lt;p&gt;Working with ASP.NET MVC 1, I've felt frustrated with the validation. A new model allows you to specify your validation once and have it applied to each layer. Your validation rules can be specified by using Data Annotation attributes, or in an XML file, or elsewhere if you write your own provider. To enable client-side validation you only need to include a couple of Microsoft javascript libraries and add the helper method &amp;lt;% Html.EnableClientValidation(); %&amp;gt; to your page. If you invent your own validation rules, you'll also have to write your own javascript version of that validation logic - the built in framework passes the rules as JSON that you can intercept on the client.&lt;/p&gt;  &lt;p&gt;There are some new helper methods - Html.Display, Html.DisplayFor, Html.DisplayForModel, HtmlEditor, Html.EditorFor and Html.EditorForModel. Given a model, these display read-only or input field versions of all the fields on the model. You can define your own templates for these - either by type (to implement your own date picker, for example), or by giving a name of a partial view that renders an editor for the whole model. This respects inheritance too: if no template has been defined for Employee, it will fall back to the template defined for Person.&lt;/p&gt;  &lt;p&gt;A nice little tweak is that by default, JsonResult now won't allow HTTP GETs. This dodges a cross-site scripting vulnerability, though you can override it if you really want.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-3676388317904032360?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/3676388317904032360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=3676388317904032360' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3676388317904032360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3676388317904032360'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/tim-jeanes-teched-2009-day-2.html' title='Tim Jeanes - TechEd 2009 - Day 2'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_zsifaW4TiJo/SvmbHreLWhI/AAAAAAAAACA/DDovsxlsTwQ/s72-c/ConeOfUncertainty_thumb.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-3213137156412779533</id><published>2009-11-10T08:30:00.026Z</published><updated>2009-11-11T08:34:41.065Z</updated><title type='text'>Tech Ed 2009 - Tuesday - Neil Bostrom</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Microsoft Web Platform Overview&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This talk was a nice overview of the features of the web platform installer. The web platform installer is an easy way to install all the standard components required for web development. The tool allows quick installation of mvc, asp.net, IIS (and optional components), SQL Server and loads of third party plugins like DotNetNuke and Umbraco. The tool is always up to date with the latest components by reading an RSS feed during load.&lt;br /&gt;&lt;br /&gt;The tool is extremely handy for setting up new servers. You can choose all the components required by your application and get them all installed at once. This reducing setting up new servers to a simple job of just running the web platform installer.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Source Control Management with Microsoft Visual Studio Team Foundation Server 2010&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This was the second talk I went to by Brian Harry. The talk first covered the chnages coming in branching and history for TFS 2010.&lt;br /&gt;&lt;br /&gt;Loads of work has been done in this area to make branching a first class citazen. You can now fully control permissions of branches allowing you to have private branches.&lt;br /&gt;&lt;br /&gt;They have also stepped up the history support, allowing you to see history across branches. This drill down support will be extremely handy as I always want to see the full history of an item.&lt;br /&gt;&lt;br /&gt;Another sexy feature introduced are some graphs to show where are changesets are in the branch structure. With these graphs we can easily see where a changeset has been merged to and when. These aren't just charts, you can drag a change set to another branch and it will pop up the merge window with the information preloaded.&lt;br /&gt;&lt;br /&gt;Brian also spoke about the version changes to TFS, with the introduction of a basic, standard and advanced wizard. Basic just has the source control items, not including any sharepoint documents or reports. Standard contains the usual install and advanced is a fully customization version allowing you to easily put your sql into an existing clustor, or you a web farm if you already have one.&lt;br /&gt;&lt;br /&gt;The second half of this talk covered a new product that Microsoft have just purchased which gives full TFS support in Eclipse. Eclipse is an open source Java IDE. This is a great move forward for Microsoft as it extends to use of TFS to all developers. The plugin has all the features of the VS version of TFS. Even including support for building your java code in team build and even more interesting, full support for junit to feedback into the build status. I spoke to the speaker after the session to ask about xcode support. Currently apple has no provider model for xcode but if that changes they will hop on that.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Tips and Tricks&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; for building high performance web applications and sites&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This session was little bitty, some interesting nuggets. The first area was CSS. Giorgio went into details about the performance of CSS in browsers. The key advice here was to keep your selectors simple and targetted.&lt;br /&gt;&lt;br /&gt;Javacript was the next topic. A whole bunch of javacript samples were shown that demostrated what to avoid. DOM access is very expensive in javascript. An interesting point that was raised during one of the samples was that if you miss out the var on assigning a new vairable, it will become a global variable. Thats bad news!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Cracking Open Kerberos: Understanding how active directory knows who you are&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;An excellent session on the ins and outs of how Kerbours does its job. Kerberous is a ticket based authenication system. It has two types of tickets, a ticket granting ticket and a service ticket. First thing that happens is that the client computer encrypts the time using your password. Sends that to the key to AD, which verifies the password by decrypting the time using the known password. Once that passes, the server creates a ticket granting ticket encrypted using the built in password of the server. This ticket only lasts 10 hours but allows you access to the TGS (Ticket Granting Service). The client computer then asks the TGS for a service ticket for a service (i.e printer service). The AD will return a new ticket to the client and the service. Now the client computer can use that service ticket to talk to the service.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-3213137156412779533?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/3213137156412779533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=3213137156412779533' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3213137156412779533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3213137156412779533'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/tech-ed-2009-tuesday-neil-bostrom.html' title='Tech Ed 2009 - Tuesday - Neil Bostrom'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7084217638402948271</id><published>2009-11-09T15:24:00.001Z</published><updated>2009-11-09T15:24:34.829Z</updated><title type='text'>Tim Jeanes - TechEd 2009 - Day 1</title><content type='html'>&lt;h4&gt;ARC201 - The Windows Azure Platform - How and When to Use It&lt;/h4&gt;  &lt;p&gt;The pricing for Windows Azure has been out for a little while, but I found it unclear exactly what you were paying for - especially for hosting web applications. What does $0.12 per hour really mean? That's CPU hours, surely? Well no - it turns out it's bad news: that's $0.12 per hour per web role or per worker role. And an hour is an hour: for every hour that goes by on your watch, you pay $0.12 for each role you have running.&lt;/p&gt;  &lt;p&gt;That makes things very expensive very quickly if you're hosting a small web site, but this isn't what Azure is for. This gets very cheap very quickly if you're running Facebook.&lt;/p&gt;  &lt;p&gt;This is also a great pricing model if your site has massive spikes in usage: ticket sales apps or tax service sites for example. You can basically turn your site off for 95% of the time, then spin up 20 servers in the space of a minute just before the tickets go on sale and drop back to zero just after they're sold out.&lt;/p&gt;  &lt;p&gt;I think a more common route into using Azure will be for data storage. Data storage of Blob data is only $0.15 per GB per month (plus $0.15 per GB downloaded). If you've got a whole load of video or other media that you want to be constantly available, Azure could be a great dumping ground for it all: it's reliably available and isn't going to use up your bandwidth, and you can leave the rest of your app running outside Azure in an environment you're more comfortable with.&lt;/p&gt;  &lt;p&gt;Using SQL in the cloud, however, is far more expensive than raw data storage: though prices are measured by the size of your database ($9.99 per month for a database up to 1GB; $99.99 for up to 10GB), what you're really paying for is all the functionality (and CPU time) of having a structured database. You've got to know that your database is going to be used regularly before this becomes worthwhile.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;DAT204 - What's new in Microsoft SQL Azure&lt;/h4&gt;  &lt;p&gt;Oh thank goodness! Microsoft listened to everyone last year saying that accessing SQL Azure via REST was a major pain in the body part. We also now have everything you'd expect in a proper fully-functioning SQL database: gone are the days where you just have basic tables with string keys, partitioned by rules you specify.&lt;/p&gt;  &lt;p&gt;Instead now you access SQL Azure via SQL Server Management Studio: you just connect to [database name].database.windows.net, and very nearly all the functionality you'd expect from SQL Server is right there. There are a few exceptions: for example you can't use the USE keyword, as they can't guarantee your two databases are on the same physical server (though they are on the same logical server) - in fact they probably won't be, to optimise performance.&lt;/p&gt;  &lt;p&gt;A server is only a logical server - not a physical box. It's a unit of authority and a unit of geo-location, so this should be what drives the point at which you make another server. As you get to choose which datacentre's hosting your database, you can also get best performance by ensuring your application runs in the same datacentre as your database. And as data transfer within a datacentre is free, so you won't be eating into that $0.15 per GB download cost.&lt;/p&gt;  &lt;p&gt;There's a nice improvement to security too: your server now comes with a firewall, allowing you to restrict access to by IP address range. Somewhat novelly, you can't create accounts called sa, admin or root, just because those are most commonly hacked.&lt;/p&gt;  &lt;p&gt;(And next week they'll announce that you can replicate from Azure to SQL Server but shh! - you're not allowed to know that yet!)&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h4&gt;DEV-GEN - Developer General Session&lt;/h4&gt;  &lt;p&gt;The Developer General Sessions at TechEd are attended by pretty much every developer at the conference, so they're held in the largest hall on site.&lt;/p&gt;  &lt;p&gt;"Wi-fi access is not available in this hall&amp;quot;," said the sign outside. A shame, because the main part of the talk was really quite dull, very high-level and largely uninformative. "VS2010's made of WPF!" My cat knew that - and I haven't even got a cat.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-7084217638402948271?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7084217638402948271/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=7084217638402948271' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7084217638402948271'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7084217638402948271'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/tim-jeanes-teched-2009-day-1.html' title='Tim Jeanes - TechEd 2009 - Day 1'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7316922388520873575</id><published>2009-11-09T08:43:00.020Z</published><updated>2009-11-10T14:34:24.264Z</updated><title type='text'>Tech Ed 2009 - Monday - Neil Bostrom</title><content type='html'>&lt;span style="font-weight: bold;"&gt;What's new in Windows Communication Foundation 4.0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I've recently started using WCF in anger on one of our projects, which is why this session interested me. The first major feature that was discussed is the new routing functionality. This feature allows a single end point to publish multiple services &amp;amp; protocols. This single end point will forward the request to the correct service based on path / content type.&lt;br /&gt;&lt;br /&gt;The next sexy feature was auto discovery of services. At the moment you always need to put the connection information into your client. By using discovery we can just create a service of a contract and it will go and attempt to discover if anything is hosting that contract. This means you can easily do load balancing just by putting up more services offering that contract and the client will just pick the first one it finds. Bonus feature with this is that you can take services out without affecting the clients.&lt;br /&gt;&lt;br /&gt;To publish your service as discoverable, you create a UdpDiscoveryEndpoint. This will use UDP packets to make the service available to clients.&lt;br /&gt;&lt;br /&gt;Christian suggested that using ChannelFactory.CreateChannel() is better than storing the configuration in the web.config. I hadn't really got around to looking into using CreateChannel, will definitely look at making use of it.&lt;br /&gt;&lt;br /&gt;WCF 4.0 has better REST support including JSON-P features.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Microsoft Visual Studio Team Suite 2010: A lap around the developer and tester experience&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Brian Harry did a good whirlwind tour of the new features coming in TFS and VS 2010. He started off with showing the new tester experience. They have a new product coming out called Lab Management. This product is built for testers to do all types of testing including, manual testing and integration testing.&lt;br /&gt;&lt;br /&gt;The sexy part of the TFS / Labs is that during test runs, it will record all sorts of information about what is happening. Screenshots, a live video is recorded, all the system information, historic debugging saved. All of this just happens in the background and get attached to any bugs you create. This gives the developers the maximum information about the bugs.&lt;br /&gt;&lt;br /&gt;Another cute feature is that the tests know the code that they cover. This means when a new build gets produced, it can notify the tester of the manual test that would need to be run that have been effected by that build.&lt;br /&gt;&lt;br /&gt;Brian moved on to TFS features next. Showing nice branch visualization, allowing you to track changes across branches and show where changes have been applied. Brian also mentioned that the conflict resolution has been improved which should be interesting to try.&lt;br /&gt;&lt;br /&gt;TFS finally has rollback support built into the interface, meaning I don't have to use the command line to rollback changes.&lt;br /&gt;&lt;br /&gt;One feature I'm really excited about is that TFS Build has been updated to use Workflow foundation on top of MSBuild to make building build scripts much easier. This should give us loads more power in the build script. Its been really painful up to this point building complex build scripts.&lt;br /&gt;&lt;br /&gt;The new version of the TFS product will have three versions, Basic, Standard and Advanced. Basic gives you the base level functionality of source control. Standard includes the share point sites and sql reporting features. Advanced version allows you to tweak pretty much any configuration so you can run on a web farm or an existing SQL cluster etc.&lt;br /&gt;&lt;br /&gt;The server version of TFS will finally come with an admin console meaning you don't have to use command line to make changes. It also includes lots of improvements for scaling out your installation by load balancing any layer, web, business or data access.&lt;br /&gt;&lt;br /&gt;Microsoft Office System 2010 Client Overview&lt;br /&gt;This was a bit of an eye opener for me as I knew very little of the latest office buzz. The guys presentation just steamed straight into new features and changes in the office products. The interesting part of this was they kinda just assumed you knew there was online versions of all the office products. That work in any browser on any platform! OMG! I was not aware of this!&lt;br /&gt;&lt;br /&gt;It seemed like the web version would use Silverlight if its installed to give a sexier interaction but will fall back to a html / javascript version if you don't have SL installed. JS version was still fully featured and worked in every major browser!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Tech Ed Keynote&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Usually the keynotes at Tech Ed are sexy and sell harder than the Berlin wall! However today's keynote seems to just be a big flop. A few random videos with no content and a long speech that seems to lack any information. The small bits I did get out of the keynote was BitLocker to go, vague cloud computing. Even the exchange demo seems to just be some random side feature.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-7316922388520873575?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7316922388520873575/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=7316922388520873575' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7316922388520873575'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7316922388520873575'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/11/tech-ed-2009-monday-neil-bostrom.html' title='Tech Ed 2009 - Monday - Neil Bostrom'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-3122156634807437707</id><published>2009-10-15T12:56:00.004Z</published><updated>2009-10-20T10:26:07.758Z</updated><title type='text'>CDNs (CD what nows?)</title><content type='html'>&lt;p&gt;With the ever increasing demands that come with scale on popular websites, site owners are always looking for ways to move resource demands away from their traffic inundated servers.&lt;/p&gt;  &lt;p&gt;There are a number of ways of offsetting or distributing demand, I'm going to cover just one, Content Delivery Networks (CDNs).&lt;/p&gt;  &lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Content_delivery_network" target="_blank"&gt;Content Delivery Networks&lt;/a&gt; are servers which host duplicate copies of a given resource or resources, this might be your site's images, javascript or media.&lt;/p&gt;  &lt;p&gt;Why might you need to move your resources to a CDN?&lt;/p&gt;  &lt;p&gt;When your browser downloads a web page, it has a limited number of active connections it can make to a domain, typically around 2. &lt;/p&gt;  &lt;p&gt;This means that if it's busy downloading images on one, and media on another, you're not going to see the page until both have finished downloading.&lt;/p&gt;  &lt;p&gt;Pushing those resources to other domains via a CDN means you get:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;More active connections available so the page can load quicker.&lt;/li&gt;    &lt;li&gt;Resources can be pulled down from locations geographically closer to the user, resulting in even faster page speeds.&lt;/li&gt;    &lt;li&gt;A reduced load on your server, no bandwidth cost on your server.&lt;/li&gt;    &lt;li&gt;Duplication of your resources gives you redundancy failovers if servers are down.&lt;/li&gt;    &lt;li&gt;Sites that use the same resources, which a user has previously downloaded, will not need to download them again, giving big speed gains.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;You can see how there are some immediate benefits to using them.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Want to use one now?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Google and Microsoft have somewhat closed CDNs meaning they won't host your content, but they do host some common files you might need, such as &lt;a href="http://jquery.com/" target="_blank"&gt;jQuery&lt;/a&gt;.&lt;/p&gt;  &lt;div   style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; direction: ltr; max-height: 200px; cursor: text;font-family:'Courier New',courier,monospace;font-size:8pt;" id="codeSnippetWrapper"&gt;   &lt;div    style="border-style: none; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;" id="codeSnippet"&gt;     &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum1"&gt;   1:&lt;/span&gt; &amp;lt;script src=&lt;span style="color: rgb(0, 96, 128);"&gt;"http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js"&lt;/span&gt; type=&lt;span style="color: rgb(0, 96, 128);"&gt;"text/javascript"&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Or:&lt;/p&gt;&lt;div   style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; direction: ltr; max-height: 200px; cursor: text;font-family:'Courier New',courier,monospace;font-size:8pt;" id="codeSnippetWrapper"&gt;&lt;div    style="border-style: none; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;" id="codeSnippet"&gt;&lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum1"&gt;   1:&lt;/span&gt; &amp;lt;script src=&lt;span style="color: rgb(0, 96, 128);"&gt;"http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"&lt;/span&gt; type=&lt;span style="color: rgb(0, 96, 128);"&gt;"text/javascript"&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;So why wouldn't you use them?&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;u&gt;&lt;strong&gt;Cost&lt;/strong&gt;&lt;/u&gt;, there are a whole lot of ways you can customise your requirements, number of servers, redundancy, global availability etc. Akamai, Amazon, CacheFly and Limelight Networks all have offerings in this space.&lt;/p&gt;&lt;p&gt;Having issues with scale or need a high demand, high availability site and need help? contact &lt;a href="http://www.compsoft.co.uk/ContactUs" target="_blank"&gt;Compsoft&lt;/a&gt; today.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-3122156634807437707?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/3122156634807437707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=3122156634807437707' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3122156634807437707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3122156634807437707'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/10/cdns-cd-what-nows.html' title='CDNs (CD what nows?)'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_gPRWTjkTHUU/SRY7HZpOTSI/AAAAAAAAAAM/OAQvr_kigYM/S220/tree-thumb.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-5696822698110321600</id><published>2009-10-06T09:40:00.001Z</published><updated>2009-10-06T09:49:03.590Z</updated><title type='text'>Mail merging with PDF documents</title><content type='html'>&lt;p&gt;We tend to find that mail merge with word documents is a flexible mechanism for customers to control the output of their applications. Be that invoices, emails or reports. Using simple merge merge documents allows the customers to modify the output of the system without having to contact us. We find that the word mail merge solution provided by &lt;a href="http://www.aspose.com/categories/.net-components/aspose.words-for-.net/default.aspx"&gt;ASPOSE Words&lt;/a&gt; is simple and reliable.&lt;/p&gt;  &lt;p&gt;We recently had a customer that required pre made PDF forms to be source of the outputs from their system. After a quick search of the ASPOSE solutions, we found that the &lt;a href="http://www.aspose.com/categories/.net-components/aspose.pdf.kit-for-.net/default.aspx"&gt;ASPOSE PDF Kit&lt;/a&gt; had exactly what we needed.&lt;/p&gt;  &lt;p&gt;10 lines of code later, we could as easily mail merge against PDF documents as we could against word documents.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="var"&gt;MemoryStream&lt;/span&gt; outputStream = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="var"&gt;MemoryStream&lt;/span&gt;();&lt;br /&gt;&lt;span class="var"&gt;MemoryStream&lt;/span&gt; pdfForm = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="var"&gt;MemoryStream&lt;/span&gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Binary.Data);&lt;br /&gt;&lt;span class="var"&gt;Form form&lt;/span&gt; = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="var"&gt;Form&lt;/span&gt;(pdfForm, outputStream);&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; fieldName &lt;span class="kwrd"&gt;in&lt;/span&gt; form.FieldsNames)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;object&lt;/span&gt; fieldValue = &lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (mailMergeDataSource.GetValue(fieldName, &lt;span class="kwrd"&gt;out&lt;/span&gt; fieldValue))&lt;br /&gt;        form.FillField(fieldName, fieldValue.ToString());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;form.FlattenAllFields();&lt;br /&gt;form.Save();&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; outputStream;&lt;/pre&gt;&lt;br /&gt;&lt;style type="text/css"&gt; .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre  margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .var { color: #006080; } .csharpcode .str { color: #8B0000; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt  { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } &lt;/style&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Thank you &lt;a href="http://www.aspose.com/"&gt;ASPOSE&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/28989665-5696822698110321600?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/5696822698110321600/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=5696822698110321600' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5696822698110321600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5696822698110321600'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/10/mail-merging-with-pdf-documents.html' title='Mail merging with PDF documents'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-4343960492735780968</id><published>2009-10-05T16:11:00.007Z</published><updated>2009-10-05T16:28:01.793Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='JSONP'/><category scheme='http://www.blogger.com/atom/ns#' term='AJAX'/><category scheme='http://www.blogger.com/atom/ns#' term='Cross site'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>This week, I have been mostly getting JSONP</title><content type='html'>&lt;p&gt;I've just finished writing a test harness for a sms texting service. While writing this little tool I ran into a problem with cross site scripting issues.&lt;/p&gt;  &lt;p&gt;Essentially its a form that is submitted to a page which then invokes methods to deal with the faked sms. It actually plays the part of the sms gateway host and saves me 50pence a shot!&lt;/p&gt;  &lt;p&gt;The form submission is via AJAX, but because its on a different domain I get no success or useful error responses. This is where JSONP comes in.&lt;/p&gt;  &lt;p&gt;As of jQuery 1.2 you can get JSON data from another domain if you add a JSONP callback and a little bit of handling on the server.&lt;/p&gt;  &lt;p&gt;You also get the proper success and error responses.&lt;/p&gt;  &lt;p&gt;The form looks a little like this: &lt;/p&gt;  &lt;pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;form&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;action&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"http://someOtherDomain/cross-site.php"&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;method&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"get"&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#000000;"&gt; input1:&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;input&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;id&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"input1"&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;name&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"input1"&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;value&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"suits you sir"&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;form&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;button&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;type&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"button"&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;id&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"btnsubmitjson"&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#000000;"&gt;jsonp submit&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;button&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;div&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;id&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#333333;"&gt;=&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;"response"&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;div&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The javascript that handles the button click event appends the JSON callback to the url and then submits the form with the power of jQuery:&lt;/p&gt;&lt;pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;function&lt;/span&gt; &lt;span style="color:#000000;"&gt;submitjson(){&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;   &lt;span style="color:#000000;"&gt; posturl = $("&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;form&lt;/span&gt;&lt;span style="color:#000000;"&gt;").attr('action');&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;    &lt;span style="color:#000000;"&gt;posturl += "&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;&lt;span style="color:#000000;"&gt;?&lt;/span&gt;jsoncallback=?&lt;/span&gt;&lt;span style="color:#000000;"&gt;"; &lt;/span&gt;&lt;span style="color:#008000;"&gt;//append the JSON call back&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;    &lt;span style="color:#000000;"&gt;$.getJSON(posturl, $("&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;form&lt;/span&gt;&lt;span style="color:#000000;"&gt;").serialize(),&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;function&lt;/span&gt;&lt;span style="color:#000000;"&gt;(data) {&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;      &lt;span style="color:#000000;"&gt;  $('#response').text(data.&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;name&lt;/span&gt;&lt;span style="color:#000000;"&gt;);&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#000000;"&gt;    });&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#000000;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;And the final part (which is not so obvious) is the response required, generated by the server:&lt;/p&gt;&lt;pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#000000;"&gt;php&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre    style="width: 100%;   font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#000000;"&gt;$data = '&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;{"name" : "&lt;/span&gt;&lt;span style="color:#000000;"&gt;'.$_GET['&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;input1&lt;/span&gt;&lt;span style="color:#000000;"&gt;'].'&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;"}&lt;/span&gt;&lt;span style="color:#000000;"&gt;';&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" color="#ffffff" style="width: 100%;"&gt;&lt;a style="color: #0000ff" href="http://www.php.net/echo"&gt;echo&lt;/a&gt; &lt;span class="Apple-style-span"  style="color:#000000;"&gt;$_GET['&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;jsoncallback&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#000000;"&gt;'].'&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;(&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#000000;"&gt;'.$data.'&lt;/span&gt;&lt;span style="color:#8b0000;"&gt;);&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#000000;"&gt;';&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:12px;color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;?&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;And its this last magic bit in the responding with $_GET['&lt;span style="color:#8b0000;"&gt;jsoncallback&lt;/span&gt;'] which makes it all work!&lt;/p&gt;&lt;p&gt;Now I can point my tool where ever I like, AND get the right responses (ah yeah).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-4343960492735780968?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/4343960492735780968/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=4343960492735780968' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4343960492735780968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4343960492735780968'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/10/this-week-i-have-been-mostly-getting.html' title='This week, I have been mostly getting JSONP'/><author><name>John Green</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-9153358861610097878</id><published>2009-09-10T15:28:00.001Z</published><updated>2009-09-10T15:41:47.222Z</updated><title type='text'>Save XDocument to string as UTF-8</title><content type='html'>&lt;p&gt;I love LINQ to XML, I'll admit it. It has changed the way I work with XML forever, in a great way!&lt;/p&gt;  &lt;p&gt;I did however run into my first issue with using it that I felt should have been simpler than it turned out to be. I had created my uber XDocument containing all the data in the world including an XDecleration saying UTF-8 on the encoding.&lt;/p&gt;  &lt;p&gt;However, whenever I did a ToString() or Save to StringBuilder it would always come out with:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;&lt;font color="#0000ff"&gt;&amp;lt;?&lt;/font&gt;&lt;/span&gt;&lt;font color="#5f0513"&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;/font&gt;&lt;span class="attr"&gt;&lt;font color="#ff0000"&gt;version&lt;/font&gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&lt;font color="#0000ff"&gt;=&amp;quot;1.0&amp;quot;&lt;/font&gt;&lt;/span&gt; &lt;span class="attr"&gt;&lt;font color="#ff0000"&gt;encoding&lt;/font&gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&lt;font color="#0000ff"&gt;=&amp;quot;utf-16&amp;quot;&lt;/font&gt;&lt;/span&gt; &lt;span class="attr"&gt;&lt;font color="#ff0000"&gt;standalone&lt;/font&gt;&lt;/span&gt;&lt;font color="#0000ff"&gt;&lt;span class="kwrd"&gt;=&amp;quot;yes&amp;quot;&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/p&gt;  &lt;p&gt;Trying all sorts of combinations got me nowhere. The reason behind this is that strings internally to .net are stored as UTF-16. This meant the XDocument was always picking up the destination of the xml and encoding it appropriately.&lt;/p&gt;  &lt;p&gt;In the end I had to go via a MemoryStream to trick XDocument into giving me the correct declaration:&lt;/p&gt;  &lt;p&gt;&lt;font color="#008000" face="Courier New"&gt;// codesnippet:20B728DE-9E20-11DE-AFE0-B04D56D89593&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;&lt;font color="#0000ff"&gt;private static string&lt;/font&gt; GetDocumentAsString(&lt;font color="#008080"&gt;XDocument&lt;/font&gt; document)      &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160; &lt;font color="#008000"&gt; // Crazy way to get UTF8 encoding out to a string       &lt;br /&gt;&lt;/font&gt;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#008080"&gt;MemoryStream&lt;/font&gt; ms = &lt;font color="#0000ff"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;MemoryStream&lt;/font&gt;();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt;using&lt;/font&gt; (&lt;font color="#008080"&gt;XmlWriter&lt;/font&gt; xw = &lt;font color="#0000ff"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;XmlTextWriter&lt;/font&gt;(ms, &lt;font color="#008080"&gt;Encoding&lt;/font&gt;.UTF8))      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; document.Save(xw);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; xw.Flush(); &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#008080"&gt;StreamReader&lt;/font&gt; sr = &lt;font color="#0000ff"&gt;new&lt;/font&gt; &lt;font color="#008080"&gt;StreamReader&lt;/font&gt;(ms);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ms.Seek(0, &lt;font color="#008080"&gt;SeekOrigin&lt;/font&gt;.Begin);      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;font color="#0000ff"&gt; return&lt;/font&gt; sr.ReadToEnd();      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;}&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;This now produces:&lt;/p&gt;  &lt;p&gt;&lt;font face="Courier New"&gt;&lt;span class="kwrd"&gt;&lt;font color="#0000ff"&gt;&amp;lt;?&lt;/font&gt;&lt;/span&gt;&lt;font color="#5f0513"&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;/font&gt;&lt;span class="attr"&gt;&lt;font color="#ff0000"&gt;version&lt;/font&gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&lt;font color="#0000ff"&gt;=&amp;quot;1.0&amp;quot;&lt;/font&gt;&lt;/span&gt; &lt;span class="attr"&gt;&lt;font color="#ff0000"&gt;encoding&lt;/font&gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&lt;font color="#0000ff"&gt;=&amp;quot;utf-8&amp;quot;&lt;/font&gt;&lt;/span&gt; &lt;span class="attr"&gt;&lt;font color="#ff0000"&gt;standalone&lt;/font&gt;&lt;/span&gt;&lt;font color="#0000ff"&gt;&lt;span class="kwrd"&gt;=&amp;quot;yes&amp;quot;&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt; &lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt;	font-size: small;&lt;br /&gt;	color: black;&lt;br /&gt;	font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt;	background-color: #ffffff;&lt;br /&gt;	/*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt;	background-color: #f4f4f4;&lt;br /&gt;	width: 100%;&lt;br /&gt;	margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-9153358861610097878?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/9153358861610097878/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=9153358861610097878' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/9153358861610097878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/9153358861610097878'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/09/save-xdocument-to-string-as-utf-8.html' title='Save XDocument to string as UTF-8'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-8968168860881759000</id><published>2009-08-24T10:26:00.001Z</published><updated>2009-08-24T10:26:43.157Z</updated><title type='text'>JavaScript string handling - oh come on, IE!</title><content type='html'>&lt;p&gt;Anyone want to guess what the result of this bit of javascript is?&lt;/p&gt;  &lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; myString = &amp;quot;&lt;span style="color: #8b0000"&gt;abc&lt;/span&gt;&amp;quot;;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;span style="color: #0000ff"&gt;alert&lt;/span&gt;(myString[2]);&lt;br /&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Let's see, shall we?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Firefox:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://www.compsoft.co.uk/Files/tgj_Firefox.png" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Google Chrome:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://www.compsoft.co.uk/Files/tgj_Chrome.png" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Safari:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://www.compsoft.co.uk/Files/tgj_Safari.png" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;IE7:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;img src="http://www.compsoft.co.uk/Files/tgj_IE7.png" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Admittedly IE8 treats strings the same way everyone has been treating them since the 1970s, but at the rate users pick up the newer versions, we're going to have to carry this around for a good many years yet.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Sigh.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-8968168860881759000?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/8968168860881759000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=8968168860881759000' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8968168860881759000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8968168860881759000'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/08/javascript-string-handling-oh-come-on.html' title='JavaScript string handling - oh come on, IE!'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-492198220112739204</id><published>2009-08-14T12:40:00.004Z</published><updated>2009-08-14T16:55:24.587Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='stateful web'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><title type='text'>One reason ASP.NET MVC can only be a good thing</title><content type='html'>&lt;p&gt;&lt;strong&gt;ASP.NET Webforms &lt;/strong&gt;has been the standard web development model on the Microsoft .NET platform since its release in 2002. One of the key web development aims, is making the stateless nature of the internet easier to develop for.&lt;/p&gt;  &lt;p&gt;It does this by wrapping up all the things you might expect if you're coming from Windows programming:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Input controls having the same content as when you last interacted with the page (via mechanisms like ViewState).&lt;/li&gt;    &lt;li&gt;Event driven architecture (btnDoStuff.Click += new .)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;It does a great job of abstracting away the details of what's going on, it makes it easy to pick up and work with. &lt;/p&gt;  &lt;p&gt;It makes you really productive create a form, add some text box controls, add a button, wire up to the click event, grab the data from the form via a full control hierarchy. &lt;/p&gt;  &lt;p&gt;&lt;span style="font-weight: bold;"&gt;Bing, bang, bosh!&lt;/span&gt; you've got a contact form.&lt;/p&gt;  &lt;p&gt;The thing is though, the web &lt;strong&gt;isn't &lt;/strong&gt;stateful, and working with the comfy blanket of Webforms makes you forget that.&lt;/p&gt;  &lt;p&gt;&lt;span style="font-weight: bold;"&gt;ASP.NET MVC &lt;/span&gt;was released this year, it's an alternative web framework that takes you back to the truth. It runs on the same .NET platform but takes you back to thinking of pages in terms of resource request / response.&lt;/p&gt;  &lt;p&gt;We love Webforms, we've got a big investment in them and it's one of the things that enables us to build great web applications.&lt;/p&gt;  &lt;p&gt;What's the one reason &lt;span style="font-weight: bold;"&gt;ASP.NET MVC &lt;/span&gt;can only be a good thing? because it makes you remember the truth. &lt;/p&gt;  &lt;p&gt;Take the blue pill, go with the programmatic illusion of the stateful web, or take the &lt;a href="http://en.wikipedia.org/wiki/Redpill" target="_blank"&gt;red pill&lt;/a&gt; and see how deep the rabbit hole goes. I'll always take knowledge over ignorance.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-492198220112739204?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/492198220112739204/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=492198220112739204' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/492198220112739204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/492198220112739204'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/08/one-reason-aspnet-mvc-can-only-be-good.html' title='One reason ASP.NET MVC can only be a good thing'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_gPRWTjkTHUU/SRY7HZpOTSI/AAAAAAAAAAM/OAQvr_kigYM/S220/tree-thumb.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-1824393015119018455</id><published>2009-07-20T09:09:00.004Z</published><updated>2009-07-20T09:15:57.422Z</updated><title type='text'>C# coalesce operator (double question mark) gotcha</title><content type='html'>&lt;p&gt;I'm sure you've met the C# coalesce operator, where you can use a double question mark to check for null:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;x = y ?? z;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;... being equivalent to:&lt;/p&gt;&lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (y != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    x = y;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;span style="color: #0000ff"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    x = z;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;It's a handy shortcut, but sometimes it doesn't behave quite as &lt;strike&gt;you&lt;/strike&gt; I might expect.&lt;/p&gt;&lt;p&gt;Here's an example:&lt;/p&gt;&lt;p&gt;I wanted to combine the elements of an address to make a field that was searchable with a SQL LIKE statement. As we use LINQ to SQL, I needed an expression that LINQ to SQL could translate into SQL syntax. I wrote this:&lt;/p&gt;&lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;...&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;font color="#0000ff"&gt;select&lt;/font&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;{&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    SearchableAddress = c.Address.HouseName   ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + c.Address.HouseNumber ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + c.Address.Road        ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + c.Address.Town        ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + c.Address.County      ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + c.Address.Postcode    ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;I'm using the coalesce operator to replace nulls with empty strings - otherwise SQL returns NULL for the whole expression if a single element is NULL.&lt;/p&gt;&lt;p&gt;However, I found my search was rarely getting any matches, and a little digging isolated the above expression as the culprit.&lt;/p&gt;&lt;p&gt;It turns out that the coalesce operator takes lower precedence than the concatenation operator. What I meant (and what I should have written) was this:&lt;/p&gt;&lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;...&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;font color="#0000ff"&gt;select&lt;/font&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;{&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    SearchableAddress = (c.Address.HouseName   ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;) + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + (c.Address.HouseNumber ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;) + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + (c.Address.Road        ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;) + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + (c.Address.Town        ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;) + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + (c.Address.County      ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;) + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                      + (c.Address.Postcode    ?? &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;)&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;... but my version without any parentheses was equivalent to this:&lt;/p&gt;&lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;...&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;font color="#0000ff"&gt;select&lt;/font&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;{&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    SearchableAddress =             c.Address.HouseName    ?? &lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                        (&amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot; + c.Address.HouseNumber) ?? &lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                        (&amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot; + c.Address.Road)        ?? &lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                        (&amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot; + c.Address.Town)        ?? &lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                        (&amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot; + c.Address.County)      ?? &lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                        (&amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot; + &amp;quot;&lt;span style="color: #8b0000"&gt; &lt;/span&gt;&amp;quot; + c.Address.Postcode)    ??&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;                         &amp;quot;&lt;span style="color: #8b0000"&gt;&lt;/span&gt;&amp;quot;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;Getting back the first non-null element, padded with a superfluous space, was enough to make the search work occasionally enough to be confusing.&lt;/p&gt;&lt;p&gt;Maybe I should have seen it coming, as I'd happily use:&lt;/p&gt;&lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;a = b ?? c ?? d ?? e;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;to get the first non-null value, but that string concatenation threw me off the scent.&lt;/p&gt;&lt;p&gt;I dunno - to me coalesce feels like a unary operator, so I'd expect it to be evaluated first; it turns out it gets evaluated &lt;a href="http://en.csharp-online.net/ECMA-334:_14.2.1_Operator_precedence_and_associativity"&gt;almost last&lt;/a&gt;. What do you think?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-1824393015119018455?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/1824393015119018455/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=1824393015119018455' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1824393015119018455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1824393015119018455'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/07/c-coalesce-operator-double-question.html' title='C# coalesce operator (double question mark) gotcha'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-1828171746674685785</id><published>2009-07-06T10:41:00.004Z</published><updated>2009-07-06T15:15:21.482Z</updated><title type='text'>Silverlight 3 And Blend 3</title><content type='html'>&lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_0"&gt;Rumour&lt;/span&gt; has it, that &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Silverlight&lt;/span&gt; 3 isn't far from release.&lt;br /&gt;&lt;br /&gt;Here is a quick list of features I'm really excited about in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Silverlight&lt;/span&gt; 3 and Blend 3:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Element Property Binding&lt;/span&gt;&lt;br /&gt;You won't believe how much I need this in my life! I've written so much back end code to replicate this feature. Now it's all available &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Silverlight&lt;/span&gt; (as it has been in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;WPF&lt;/span&gt; since the start). It means I can wire up one controls property to another controls property. You'll be &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_5"&gt;surprised&lt;/span&gt; how much you'll use this!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Behaviors&lt;/span&gt;&lt;br /&gt;Another feature that massively increases code reuse. Write that &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_6"&gt;full screen&lt;/span&gt; code once and wire it up to anything you can think of!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Team System Source Control &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_7"&gt;Integration&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Finally! I won't need to keep checking out files in Visual Studio to modify them in blend! All the usual (not all but most) source control features will be available through Blend.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Samples Data&lt;/span&gt;&lt;br /&gt;Cute feature inside Blend to generate sample data so you are able to see what your designs will look like with some close to real world data in your controls.&lt;br /&gt;&lt;br /&gt;As of yet, there has been no &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_8"&gt;official&lt;/span&gt; Microsoft press on when &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;Silverlight&lt;/span&gt; 3 is due but I've seen some hints lying around on the net that July is the month.&lt;br /&gt;&lt;br /&gt;If you &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_10"&gt;haven't&lt;/span&gt; guessed it yet, I'm excited... bring it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-1828171746674685785?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/1828171746674685785/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=1828171746674685785' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1828171746674685785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1828171746674685785'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/07/silverlight-3-and-blend-3.html' title='Silverlight 3 And Blend 3'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-264562326634082074</id><published>2009-06-26T13:20:00.010Z</published><updated>2009-06-26T15:06:39.711Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='microformats'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>Winning with Microformats and JQuery</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Microformat"&gt;Microformats&lt;/a&gt; are a nice way to get semantic data onto a page, and here at Compsoft we have had a maptacular week which has given us the chance to use some with a little JQuery to make things nice.&lt;br /&gt;&lt;br /&gt;So on a map we are plotting locations. We are also listing these locations next to the map. You can drag and drop a selection of locations from the main list, into a short list. You can then get Google maps to create us a route based on this short list.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nyW099dZ_Zg/SkTYEQpC6vI/AAAAAAAAAAM/ZYf7JP29UXg/s1600-h/routemap.png"&gt;&lt;img id="BLOGGER_PHOTO_ID_5351639824921193202" style="margin: 0pt 10px 10px 0pt; float: left; width: 320px; cursor: pointer; height: 146px;" alt="" src="http://2.bp.blogspot.com/_nyW099dZ_Zg/SkTYEQpC6vI/AAAAAAAAAAM/ZYf7JP29UXg/s320/routemap.png" border="0" /&gt;&lt;/a&gt;But the cool thing is, you can drag items in the short list to rearrange the route!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;How though, do you know the order of the items in the short list once they have been reordered?&lt;br /&gt;&lt;br /&gt;With the magic of JQuery and microformats of course!&lt;br /&gt;&lt;br /&gt;The markup used to present also defines the data that is being displayed. CSS styling then allows us to make it look nice. This is what the markup looks like:   &lt;pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;id&lt;/span&gt;=&lt;span style="color: rgb(0, 0, 255);"&gt;"location628"&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;class&lt;/span&gt;=&lt;span style="color: rgb(0, 0, 255);"&gt;"location"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;class&lt;/span&gt;=&lt;span style="color: rgb(0, 0, 255);"&gt;"name"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Geodis UK Limited&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;class&lt;/span&gt;=&lt;span style="color: rgb(0, 0, 255);"&gt;"address"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;Warren Farm Transfer Station&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;class&lt;/span&gt;=&lt;span style="color: rgb(0, 0, 255);"&gt;"detail"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;1 mile&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt; &lt;span style="color: rgb(255, 0, 0);"&gt;class&lt;/span&gt;=&lt;span style="color: rgb(0, 0, 255);"&gt;"latlng"&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;(50.8915618, -1.1965132)&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: rgb(128, 0, 0);"&gt;div&lt;/span&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;&lt;p&gt;We can make the lists sortable and allow drag and drop between them with JQuery like this: &lt;/p&gt;&lt;pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;$(&lt;span style="color: rgb(0, 0, 255);"&gt;document&lt;/span&gt;).ready(&lt;span style="color: rgb(0, 0, 255);"&gt;function&lt;/span&gt;() {&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    $("&lt;span style="color: rgb(139, 0, 0);"&gt;#locations&lt;/span&gt;").sortable({ connectWith: "&lt;span style="color: rgb(139, 0, 0);"&gt;#selectedLocations&lt;/span&gt;" });&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    $("&lt;span style="color: rgb(139, 0, 0);"&gt;#selectedLocations&lt;/span&gt;").sortable({ connectWith: "&lt;span style="color: rgb(139, 0, 0);"&gt;#locations&lt;/span&gt;" });&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;});&lt;/pre&gt;&lt;/pre&gt;and listen for the sorting to finish with this:&lt;br /&gt;&lt;pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;$("&lt;span style="color: rgb(139, 0, 0);"&gt;#selectedLocations&lt;/span&gt;").bind('sortupdate', &lt;span style="color: rgb(0, 0, 255);"&gt;function&lt;/span&gt;(event, ui) {&lt;br /&gt;&lt;/pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    getRoute();&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255); font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;/pre&gt;And because we are using JQuery, and microformatting makes it clear what the data means, we can use a JQuery selector to get the data stored on the page in the order they are displayed! This makes it so simple to grab the ordered data.&lt;br /&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;&lt;/span&gt;function&lt;/span&gt; getRoutes() {&lt;br /&gt;&lt;pre&gt;&lt;pre   style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);font-family:consolas,'Courier New',courier,monospace;font-size:12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;var&lt;/span&gt; waypoints = [];&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255); font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;var&lt;/span&gt; stops = $("&lt;span style="color: rgb(139, 0, 0);"&gt;#selectedLocations .latlng&lt;/span&gt;");&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255); font-family: consolas,'Courier New',courier,monospace; font-size: 12px;"&gt;    &lt;span style="color: rgb(0, 0, 255);"&gt;for&lt;/span&gt; (&lt;span style="color: rgb(0, 0, 255);"&gt;var&lt;/span&gt; i = 0; i &amp;lt; stops.&lt;span style="color: rgb(0, 0, 255);"&gt;length&lt;/span&gt;; i++) {&lt;br /&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);"&gt;        &lt;span style="color: rgb(0, 0, 255);"&gt;if&lt;/span&gt; (divs[i])&lt;br /&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);"&gt;            waypoints.push(stops[i].innerHTML);&lt;br /&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);"&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;pre face="consolas,'Courier New',courier,monospace" size="12px" style="margin: 0em; width: 100%; background-color: rgb(255, 255, 255);"&gt;    &lt;span style="color: rgb(0, 128, 0);"&gt;//GDirections object connected to GMap on page to display the route&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; font-size: 12px; width: 100%; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(255, 255, 255);"&gt;    directions.loadFromWaypoints(waypoints);&lt;br /&gt;&lt;/pre&gt;&lt;pre style="margin: 0em; font-size: 12px; width: 100%; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(255, 255, 255);"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-264562326634082074?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/264562326634082074/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=264562326634082074' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/264562326634082074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/264562326634082074'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/06/winning-with-microformats-and-jquery.html' title='Winning with Microformats and JQuery'/><author><name>John Green</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_nyW099dZ_Zg/SkTYEQpC6vI/AAAAAAAAAAM/ZYf7JP29UXg/s72-c/routemap.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7760179028417385983</id><published>2009-06-15T08:37:00.001Z</published><updated>2009-06-15T08:37:13.844Z</updated><title type='text'>Animated gifs stop animating in IE</title><content type='html'>&lt;p&gt;An annoying bug/ feature of Internet Explorer is that animated gifs stop animating the moment you click a link to navigate to another page. Other things can stop them animating too: I recently found that a flash-based file uploader that we use triggers this bug when it finishes the upload.&lt;/p&gt;  &lt;p&gt;Fortunately it's not to hard to work around. If you reassign the value of the src attribute of the &amp;lt;img&amp;gt; tag, the animation starts again.&lt;/p&gt;  &lt;p&gt;jQuery makes it easy to reassign all such tags in one fell swoop:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;span style="color: #008000"&gt;//codesnippet:7660712A-6D8A-4820-A99F-751F44A57AD2&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; fixAnimatedGifsDamnYouInternetExplorer()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;{&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    $(&amp;quot;&lt;span style="color: #8b0000"&gt;img&lt;/span&gt;&amp;quot;).each(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;()&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    {&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;        &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.src = &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.src;&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;    });&lt;br /&gt;&lt;/pre&gt;&lt;pre style="font-size: 12px; margin: 0em; width: 100%; font-family: consolas,&amp;#39;Courier New&amp;#39;,courier,monospace; background-color: #ffffff"&gt;}&lt;/pre&gt;&lt;/pre&gt;&lt;br /&gt;In my case, I called this function when my upload completed, but you could easily attach it to the click event of every link on your page. &lt;br /&gt;&lt;br /&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-7760179028417385983?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7760179028417385983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=7760179028417385983' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7760179028417385983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7760179028417385983'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/06/animated-gifs-stop-animating-in-ie.html' title='Animated gifs stop animating in IE'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-3856198214148559431</id><published>2009-06-08T10:53:00.002Z</published><updated>2009-06-10T14:06:48.357Z</updated><title type='text'>Microsoft release SEO Tools</title><content type='html'>&lt;p&gt;SEO (search engine optimisation) is debatably one of the most important things to get right in a website that needs web traffic. If your web traffic is driven by search engines, you want to give the search engines anything and everything they could need to connect someone's query with your site. Especially as traffic from search is effectively free traffic.&lt;/p&gt;  &lt;p&gt;Google have webmaster tools available which give you access to stats about your site (assuming you have tracking on your site),  crawling errors etc. They have associated help sections and even have an &lt;a href="http://www.google.com/webmasters/docs/search-engine-optimization-starter-guide.pdf" target="_blank"&gt;SEO guide available&lt;/a&gt; for download.&lt;/p&gt;  &lt;p&gt;What Microsoft have released is an IIS add in that gives you a huge amount of stats, finds issues and provides diagnostic information about any site you point it at. We pointed it at the W3C (World Wide Web Consortium - Home of Web Standards), limited the tool to 5000 links and set it running.&lt;/p&gt;  &lt;p&gt;It found more than 19,000 violations:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/_gPRWTjkTHUU/SiztoCxA2FI/AAAAAAAAADY/g154sf-J2k4/s1600-h/w3c%5B3%5D.png"&gt;&lt;img style="border-width: 0px; display: inline;" title="w3c" alt="w3c" src="http://lh4.ggpht.com/_gPRWTjkTHUU/Sizto_4QYYI/AAAAAAAAADc/inTouEQhTmc/w3c_thumb%5B1%5D.png?imgmax=800" border="0" height="351" width="467" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;It ranks these by SEO, Content, Performance and Standards and gives an indication of the severity.&lt;/p&gt;  &lt;p&gt;The thing you notice when you get going with the tool is the extent to which you can drill down and the immense utility of the information it exposes.&lt;/p&gt;  &lt;p&gt;Did you know the content of the &amp;lt;title&amp;gt; tag shouldn't exceed 65 characters? search engines generally truncate the text after that.&lt;/p&gt;  &lt;p&gt;Here's a hastily thrown together image of the other menu options:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_gPRWTjkTHUU/Siztpeg8fLI/AAAAAAAAADg/ca6zBpQ8EJk/s1600-h/menuoptions%5B3%5D.png"&gt;&lt;img style="border-width: 0px; display: inline;" title="menuoptions" alt="menuoptions" src="http://lh5.ggpht.com/_gPRWTjkTHUU/SiztqDuME_I/AAAAAAAAADk/K6CdhqPVds8/menuoptions_thumb%5B1%5D.png?imgmax=800" border="0" height="343" width="529" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;It's currently in beta and only works in IIS 7 so that means it's limited to Windows Vista and Windows Server 2008. I think it'll quickly become a mainstay of the SEO optimiser's arsenal. Find out more here: &lt;a href="http://weblogs.asp.net/scottgu/archive/2009/06/03/iis-search-engine-optimization-toolkit.aspx" target="_blank"&gt;Scott Guthries blog&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/28989665-3856198214148559431?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/3856198214148559431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=3856198214148559431' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3856198214148559431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3856198214148559431'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/06/microsoft-release-seo-optimisation.html' title='Microsoft release SEO Tools'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_gPRWTjkTHUU/SRY7HZpOTSI/AAAAAAAAAAM/OAQvr_kigYM/S220/tree-thumb.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_gPRWTjkTHUU/Sizto_4QYYI/AAAAAAAAADc/inTouEQhTmc/s72-c/w3c_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-5699213877530422312</id><published>2009-06-01T15:06:00.002Z</published><updated>2009-06-01T15:21:22.436Z</updated><title type='text'>Speeding up deployment by zipping drop files in TFS</title><content type='html'>&lt;p&gt;As most of the projects we produce are web based, we use the file copy feature of ASP.NET heavily. It makes for wonderfully simple deployment. Using this feature does however mean that we zip the files up before sending them over to the live server.&lt;/p&gt;  &lt;p&gt;To speed up deployment even further, we added a zip command to our build job in Team Foundation Server Build that zips the files in the drop location, ready for copy.&lt;/p&gt;  &lt;p&gt;Zipping is not supported out of the box in TFS but the &lt;a href="http://msbuildtasks.tigris.org/"&gt;MSBuild Community Tasks Project&lt;/a&gt; has a lovely one. &lt;/p&gt;  &lt;p&gt;To use the zip command in the community tasks library you need to add a reference to it.&lt;/p&gt;  &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;   &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Import&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Project&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;Once this has been imported you can then use the zip command in your script. We tend to use the zip command in the AfterDropBuild event.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;  &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: &amp;#39;Courier New&amp;#39;, courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;CreateItem&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Include&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;$(DropLocation)\$(BuildNumber)\Release\**\*.*&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Exclude&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;$(DropLocation)\$(BuildNumber)\Release\**\*.config&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Output&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ItemName&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;ZipFiles&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TaskParameter&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;Include&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;CreateItem&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Time&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Format&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;yyyy-MM-dd&amp;quot;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Output&lt;/span&gt; &lt;span style="color: #ff0000"&gt;TaskParameter&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;FormattedTime&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;PropertyName&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;buildDate&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;Time&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;Zip&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Files&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;@(ZipFiles)&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;WorkingDirectory&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;$(DropLocation)\$(BuildNumber)\Release&amp;quot;&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ZipFileName&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=&amp;quot;$(DropLocation)\$(BuildNumber)\NBR Release $(buildDate).zip&amp;quot;&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;We also tend to put the date into the release and we do that by using the Time command. This now gives us a prepped zip file with all the release files in it. &lt;br /&gt;  &lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-5699213877530422312?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/5699213877530422312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=5699213877530422312' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5699213877530422312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/5699213877530422312'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/06/speeding-up-deployment-by-zipping-drop.html' title='Speeding up deployment by zipping drop files in TFS'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-1435863670387469718</id><published>2009-05-21T13:38:00.002Z</published><updated>2009-05-21T13:46:14.214Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='viewstate'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><title type='text'>Size of data in the ViewState</title><content type='html'>&lt;p&gt;I love the ViewState.&lt;/p&gt;  &lt;p&gt;I know it's a much-maligned technology. I know it can bloat out of all control. I know it can be an effort to tame it, but spend an afternoon reading up on it and it can really be your friend.&lt;/p&gt;  &lt;p&gt;It can be a handy place to store all sorts of state data that you don't want to (or can't) track on the server. It's dead easy to add values to it programmatically and retrieve them after a postback.&lt;/p&gt;  &lt;p&gt;You can serialize pretty much anything into the ViewState. Though putting an instance of your Customer class in there would blatantly be a bad idea - it would be vast once serialized - storing smaller constructs is feasible, and usually holding a few flags is sufficient to maintain the state of your page.&lt;/p&gt;  &lt;p&gt;What can be a little surprising, though, is how big some data items are compared with others when they're serialised to the ViewState.&lt;/p&gt;  &lt;p&gt;I spent an afternoon putting all sorts of items into the ViewState and seeing how much it made the ViewState grow. The results are in the graph below. (Click to see a legible-sized version.)&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.compsoft.co.uk/Files/ViewState.gif" target="_blank"&gt;&lt;img title="ViewState Graph" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="315" alt="ViewState Graph" src="http://www.compsoft.co.uk/Files/ViewState.gif" width="409" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Note that all the figures are multiples of four - this is because the ViewState is base 64 encoded. Unfortunately it means the figures aren't quite spot-on to the byte, but they're good enough for our purposes.&lt;/p&gt;  &lt;p&gt;The most important thing to notice is the long bar at the bottom. A List&amp;lt;string&amp;gt; containing only two three-letter strings took a whopping 312 bytes! Compare this with the array of strings holding the same values, which took only 24 bytes. An easy lesson: if you're putting a set of objects into the ViewState, turn that list into an array first.&lt;/p&gt;  &lt;p&gt;In fact, arrays perform pretty well. Arrays of arrays carry a bit of overhead but aren't too bad, all things considered.&lt;/p&gt;  &lt;p&gt;Surprisingly, int.MaxValue takes more space than the integer 1. Storing int.MaxValue.ToString() took more again, but these figures are still pretty small so it doesn't make much difference.&lt;/p&gt;  &lt;p&gt;Converting a DateTime to a string took rather more space than the raw DateTime itself.&lt;/p&gt;  &lt;p&gt;On the other hand, decimals take a vast amount of space for what they are (and decimal.MinValue took significantly more than decimal.One); but converting them to strings dropped the space right back down again.&lt;/p&gt;  &lt;p&gt;I'm surprised that storing a Guid takes three times as much space as its string representation - I can't imagine what extra information is being serialized there.&lt;/p&gt;  &lt;p&gt;Similarly, types take quite a bit of space; storing their full names is sufficient to regain the class object later and takes only about a third of the space. (Though to be fair I can't imagine what circumstances would lead you to putting a Type into the ViewState.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-1435863670387469718?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/1435863670387469718/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=1435863670387469718' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1435863670387469718'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1435863670387469718'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/05/size-of-data-in-viewstate.html' title='Size of data in the ViewState'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7304194194178188652</id><published>2009-05-18T10:29:00.003Z</published><updated>2009-05-18T10:32:43.418Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='sql ce'/><category scheme='http://www.blogger.com/atom/ns#' term='bug fix'/><title type='text'>Combatting "Unspecified error"</title><content type='html'>&lt;p&gt;In one of our Windows Mobile applications we've been noticing some bizarre exceptions where we're logging a rare exception of "Unspecified Error".&lt;/p&gt;  &lt;p&gt;It's always a pain getting this kind of error, you really have no clue where to turn. Pin pointing the general area and finding the point at which the application fails tends to be the only route and led us to find it was database related.&lt;/p&gt;  &lt;p&gt;Further research into the error implies that the issue lies in SQL CE (we're using SQL CE 3.5 SP1). It's at the point we're touching the database but ONLY after the device has come out of stand by mode and ONLY if the database file is located on the storage / memory card. Database files stored on the internal memory are fine.&lt;/p&gt;  &lt;p&gt;It turns out that the SQL Server Mobile engine has a bug when the database file is accessed before the block device driver (that allows you to access the database file) has started up after the device is restored from suspend mode.&lt;/p&gt;  &lt;p&gt;There's a &lt;a href="http://support.microsoft.com/kb/919150/en-us" target="_blank"&gt;hotfix available&lt;/a&gt; for previous versions but not the latest and it only seems to give a more intelligible error message of "The disk is not ready" or "The OS storage system (RAM, CF, SD, or IPSM) is not responding. Retry the operation".&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Which leaves us with the choice of what to do in this instance.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;1.&lt;/strong&gt; Handle database access exceptions until the device is ready again.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;2.&lt;/strong&gt; Wire up to the device's power events and handle the Power up event.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;3.&lt;/strong&gt; Move the database file to the Internal memory.&lt;/p&gt;  &lt;p&gt;I decided to go with option 2. A significant amount of work would have been required for option 1.  The devices we're working against have a 2GB storage card versus a 64mb internal memory so I felt this wouldn't work for us without impacting performance so I didn't go for option 3. &lt;/p&gt;  &lt;p&gt;The easiest way to go with option 2 is by using the &lt;a href="http://www.opennetcf.com/Products/SmartDeviceFramework/tabid/65/Default.aspx" target="_blank"&gt;opennetcf smart device framework&lt;/a&gt; framework which in the OpenNETCF.WindowsCE.PowerManagement namespace allows you to wire up to all the Power related states and their changes.&lt;/p&gt;  &lt;p&gt;Here's one possible solution:&lt;/p&gt;  &lt;div   style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; direction: ltr; max-height: 200px; cursor: text;font-family:'Courier New',courier,monospace;font-size:8pt;" id="codeSnippetWrapper"&gt;   &lt;div    style="border-style: none; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;" id="codeSnippet"&gt;     &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;void&lt;/span&gt; Main()&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum3"&gt;   3:&lt;/span&gt;     OpenNETCF.WindowsCE.PowerManagement.PowerUp += &lt;span style="color: rgb(0, 0, 255);"&gt;new&lt;/span&gt; &lt;/pre&gt;&lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;OpenNETCF.WindowsCE.DeviceNotification(PowerManagement_PowerUp);&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum5"&gt;   4:&lt;/span&gt;     &lt;span style="color: rgb(0, 128, 0);"&gt;//Run the app&lt;/span&gt;&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum6"&gt;   5:&lt;/span&gt; }&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum7"&gt;   6:&lt;/span&gt;  &lt;/pre&gt;    &lt;pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr; font-family: 'Courier New',courier,monospace; font-size: 8pt; color: black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum8"&gt;   7:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;private&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;static&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;void&lt;/span&gt; PowerManagement_PowerUp()&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum9"&gt;   8:&lt;/span&gt; {&lt;/pre&gt;    &lt;pre face="'Courier New',courier,monospace" size="8pt" color="black" style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum10"&gt;   9:&lt;/span&gt;     System.Windows.Forms.Application.Exit();&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum11"&gt;  10:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;OpenNetCF has some great products, their download count is at 3/4 million at the time of writing. They have good customer service too.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-7304194194178188652?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7304194194178188652/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=7304194194178188652' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7304194194178188652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7304194194178188652'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/05/combatting-error.html' title='Combatting &amp;quot;Unspecified error&amp;quot;'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_gPRWTjkTHUU/SRY7HZpOTSI/AAAAAAAAAAM/OAQvr_kigYM/S220/tree-thumb.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-8345489597713496334</id><published>2009-05-05T09:21:00.009Z</published><updated>2009-05-08T13:20:44.093Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='debug'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='Compsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='Neil Bostrom'/><title type='text'>Making sure your application is not left in debug="true"</title><content type='html'>You will find loads of articles around the web reminding us all that running your production ASP.NET website in complication debug=true mode is a BAD THING!  &lt;br /&gt; &lt;ul&gt;   &lt;li&gt;&lt;a href="http://weblogs.asp.net/scottgu/archive/2006/04/11/Don_1920_t-run-production-ASP.NET-Applications-with-debug_3D001D20_true_1D20_-enabled.aspx"&gt;Don't run production ASP.NET Applications with debug="true" enabled&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://aspnetresources.com/articles/debug_code_in_production.aspx"&gt;Beware Of Deploying Debug Code In Production&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://daptivate.com/archive/2008/02/12/top-10-best-practices-for-production-asp-net-applications.aspx"&gt;Top 10 Best Practices for Production ASP.NET Applications&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt; To make sure we avoid this problem we have added a start up check in our application that will make sure that the build mode (debug or release) of our binaries match that of the web.config. As all releases are done via our build server all our binaries will be in release mode. However we tend to make major changes to the web.config on the live servers so deploying the web.config is usually not an option.  &lt;br /&gt;&lt;br /&gt;To check if the web.config has debug enabled you can use HttpContext.Current.IsDebuggingEnabled.  &lt;br /&gt;&lt;br /&gt;To check what mode a binary is in, we use the #DEBUG Preprocessor Directive:  &lt;br /&gt; &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div   style="border: 1px solid silver; margin: 20px 0px 10px; padding: 4px; overflow: auto; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; direction: ltr; max-height: 200px; cursor: text;font-family:'Courier New',courier,monospace;font-size:8pt;" id="codeSnippetWrapper"&gt;   &lt;div    style="border-style: none; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;" id="codeSnippet"&gt;     &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: rgb(0, 128, 0);"&gt;// codesnippet:ADB0358E-3BD1-11DE-B2D2-764056D89593&lt;/span&gt;&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum2"&gt;   2:&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;public&lt;/span&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;static&lt;/span&gt; BuildModeEnum BuildMode&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum3"&gt;   3:&lt;/span&gt; {    &lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum4"&gt;   4:&lt;/span&gt;     get    &lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum5"&gt;   5:&lt;/span&gt;     {        &lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum6"&gt;   6:&lt;/span&gt;         &lt;span style="color: rgb(204, 102, 51);"&gt;#if&lt;/span&gt; (DEBUG)&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum7"&gt;   7:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; BuildModeEnum.Debug;&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum8"&gt;   8:&lt;/span&gt;         &lt;span style="color: rgb(204, 102, 51);"&gt;#else&lt;/span&gt;&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum9"&gt;   9:&lt;/span&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;return&lt;/span&gt; BuildModeEnum.Release;&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum10"&gt;  10:&lt;/span&gt;         &lt;span style="color: rgb(204, 102, 51);"&gt;#endif&lt;/span&gt;&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: white; width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum11"&gt;  11:&lt;/span&gt;     }&lt;/pre&gt;    &lt;pre    style="border-style: none; margin: 0em; padding: 0px; overflow: visible; text-align: left; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%; direction: ltr;font-family:'Courier New',courier,monospace;font-size:8pt;color:black;"&gt;&lt;span style="color: rgb(96, 96, 96);" id="lnum12"&gt;  12:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: consolas, "Courier New", courier, monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;.csharpcode .alt &lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-8345489597713496334?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/8345489597713496334/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=8345489597713496334' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8345489597713496334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8345489597713496334'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/05/making-sure-your-application-is-not.html' title='Making sure your application is not left in debug=&amp;quot;true&amp;quot;'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7296868850169548975</id><published>2009-04-27T16:17:00.005Z</published><updated>2009-04-28T09:09:44.912Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><category scheme='http://www.blogger.com/atom/ns#' term='MIGRATIING'/><category scheme='http://www.blogger.com/atom/ns#' term='UNIX TIME'/><category scheme='http://www.blogger.com/atom/ns#' term='UNIX EPOCH'/><category scheme='http://www.blogger.com/atom/ns#' term='MSSQL'/><title type='text'>Migrating MySQL Unix timestamps to MSSQL date time</title><content type='html'>Just this week I've been migrating data held in a MySQL database to a Microsoft SQL database, and I've run into a bit of a headache with temporal values being stored as integers.&lt;br /&gt;&lt;br /&gt;MySQL is a great database for the web. It has some nice features, one of which being the ability to export the table structure and all the data into one script you can download. It can even be zipped on the way. This makes transfering data super simple.&lt;br /&gt;&lt;br /&gt;Super simple that is unless dates and times are stored as Unix timestamps, and its going into a MSSQL database.&lt;br /&gt;&lt;br /&gt;Okay, so there is a certain amount of cleanup needed in the scripts going from one database to the other, but thats fairly easily done with an amount of regex.&lt;br /&gt;&lt;br /&gt;However, dates and times stored as int are in Unix time (or POSIX time). So to get the actual date time of the value in MySQL you need to do something like:&lt;br /&gt;&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;}??\fs20 \cf1 SELECT \cf0 FROM_UNIXTIME(date_added) \cf1 FROM \cf0 NewsStory } --&gt; &lt;div style="background: white none repeat scroll 0% 0%; font-family: Consolas; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;SELECT &lt;/span&gt;&lt;span style="color: rgb(204, 51, 204);"&gt;FROM_UNIXTIME&lt;/span&gt;(date_added) &lt;span style="color: blue;"&gt;FROM &lt;/span&gt;NewsStory &lt;/p&gt; &lt;/div&gt; &lt;br /&gt;There isn't an equivalent of FROM_UNIXTIME in MSSQL so to get at the date time value from there you need to add to the value the number of seconds since the Unix epoch (1st January 1970 00:00:00), like this:&lt;br /&gt;&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red163\green21\blue21;}??\fs20 \cf1 SELECT DateAdd\cf0 (ss, date_added, \cf4 '1970-01-01'\cf0 ) \cf1 FROM \cf0 NewsStory\par ??} --&gt; &lt;div style="background: white none repeat scroll 0% 0%; font-family: Consolas; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;SELECT &lt;span style="color: rgb(204, 51, 204);"&gt;DateAdd&lt;/span&gt;&lt;/span&gt;(ss, date_added, &lt;span style="color: rgb(163, 21, 21);"&gt;'1970-01-01'&lt;/span&gt;) &lt;span style="color: blue;"&gt;FROM &lt;/span&gt;NewsStory&lt;/p&gt; &lt;/div&gt; &lt;br /&gt;Et viola! Something sensible you can use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-7296868850169548975?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7296868850169548975/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=7296868850169548975' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7296868850169548975'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7296868850169548975'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/04/migrating-mysql-unix-timestamps-to.html' title='Migrating MySQL Unix timestamps to MSSQL date time'/><author><name>John Green</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-4921589905915764577</id><published>2009-04-23T13:25:00.002Z</published><updated>2009-04-23T13:27:03.239Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='query'/><category scheme='http://www.blogger.com/atom/ns#' term='log'/><category scheme='http://www.blogger.com/atom/ns#' term='Linq to SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Logging all LINQ to SQL queries used in a single page lifecycle</title><content type='html'>&lt;p&gt;We absolutely love LINQ to SQL here at Compsoft. It's the best ORM we've used and it's made a marked speed increase in both our application development and application performance.&lt;/p&gt;  &lt;p&gt;A concern we had initially was the amount of &amp;quot;magic&amp;quot; involved. Occasionally we'd find that LINQ was running rather more queries than we'd expected (the DataLoadOptions weren't always behaving quite as we'd anticipated), or the queries were unexpectedly complicated. Also, with all the ease of data access that LINQ gives you, it's easy to get lazy and forget quite how many trips you're making to the database to generate a single web page.&lt;/p&gt;  &lt;p&gt;We felt we needed an easy way to see what was going on under the hood. We didn't want to have to go a long way out of our way to find out which pages took a lot of database effort: we wanted to be warned about this up-front.&lt;/p&gt;  &lt;p&gt;So here's what we made: when in debug mode, this appears in the top corner of every page we're working on:&lt;/p&gt;  &lt;p&gt;&lt;img alt="" src="http://1.bp.blogspot.com/_zsifaW4TiJo/SfBJeLAqHkI/AAAAAAAAAAw/sVrNIh3A5uA/s400/DbHitCountClosed.gif" border="0" /&gt;&lt;/p&gt;  &lt;p&gt;... which expands to this when clicked:&lt;/p&gt;  &lt;p&gt;&lt;img alt="" src="http://4.bp.blogspot.com/_zsifaW4TiJo/SfBJr-KOW2I/AAAAAAAAAA4/hILhbJLGkWs/s400/DbHitCountOpen.gif" border="0" /&gt;&lt;/p&gt;  &lt;p&gt;The more queries it takes to make the page, the redder the little &amp;quot;DB hits&amp;quot; box appears, drawing our attention to pages that accidentally take a lot of work to produce.&lt;/p&gt;  &lt;p&gt;LINQ to SQL makes it easy to capture this sort of information. The Log property of DataContext is a TextWriter to which all queries are written, together with the values of any query parameters. Setting this to a new StringWriter in the constructor of our application's DataContext catches all the queries it performs.&lt;/p&gt;  &lt;p&gt;We typically use one DataContext per page lifecycle, so it would seem it would be sufficient to dump the contents of the log to the page late in the page lifecycle. However there are occasions where we create additional DataContexts for particular tasks, and we want to know what they are up to too.&lt;/p&gt;  &lt;p&gt;Here's the solution we came up with:&lt;/p&gt;  &lt;p&gt;The data context class for the application inherits from this BaseDataContext class, which lives in our reusable code libraries:&lt;/p&gt;  &lt;div style="font-size: 10px; background: white; color: black; font-family: couriernew"&gt;   &lt;p style="margin: 0px"&gt;&lt;span style="color: green"&gt;&lt;font face="Courier New" size="2"&gt;// codesnippet:4963E640-80C0-4577-A2B2-F0F6A8D41E56&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af"&gt;BaseDataContext&lt;/span&gt; : &lt;span style="color: #2b91af"&gt;DataContext&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;{&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span style="color: #e000e0"&gt;#if&lt;/span&gt; (DEBUG)&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af"&gt;TextWriter&lt;/span&gt; logWriter;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af"&gt;StringBuilder&lt;/span&gt; _Logger;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af"&gt;StringBuilder&lt;/span&gt; Logger&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; {&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;get&lt;/span&gt; { &lt;span style="color: blue"&gt;return&lt;/span&gt; _Logger; }&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;set&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; {&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; _Logger = &lt;span style="color: blue"&gt;value&lt;/span&gt;;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; logWriter = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;StringWriter&lt;/span&gt;(&lt;span style="color: blue"&gt;value&lt;/span&gt;);&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;static&lt;/span&gt; BaseDataContext()&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; {&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: #2b91af"&gt;BaseDataContext&lt;/span&gt;.Logger = &lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;StringBuilder&lt;/span&gt;();&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;span style="color: #e000e0"&gt;&lt;font face="Courier New" size="2"&gt;#endif&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;public&lt;/span&gt; BaseDataContext(&lt;span style="color: blue"&gt;string&lt;/span&gt; connectionString)&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; : &lt;span style="color: blue"&gt;base&lt;/span&gt;(connectionString)&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; {&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span style="color: #e000e0"&gt;#if&lt;/span&gt; (DEBUG)&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;this&lt;/span&gt;.Log = logWriter;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;span style="color: #e000e0"&gt;&lt;font face="Courier New" size="2"&gt;#endif&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; }&lt;/font&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;[Aside: we like &lt;a href="http://www.codinghorror.com/blog/archives/001257.html"&gt;Jeff Attwood's idea for flagging code snippets with GUIDs&lt;/a&gt;.]&lt;/p&gt;  &lt;p&gt;As you can see, the log is static, so all queries from all DataContexts will be written to the same log. This would be nightmarish if the server were handling numerous requests concurrently, but this is just a development tool for when the application is running on your local machine (which is partly why the logging only happens when the application's in debug mode).&lt;/p&gt;  &lt;p&gt;That takes care of logging the queries; next we have to display them. We have this in the class that all our pages inherit from:&lt;/p&gt;  &lt;div style="font-size: 12pt; background: white; color: black; font-family: couriernew"&gt;   &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span style="color: #e000e0"&gt;#if&lt;/span&gt; (DEBUG)&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span style="color: blue"&gt;protected&lt;/span&gt; &lt;span style="color: blue"&gt;override&lt;/span&gt; &lt;span style="color: blue"&gt;void&lt;/span&gt; Render(&lt;span style="color: #2b91af"&gt;HtmlTextWriter&lt;/span&gt; writer)&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;{&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: green"&gt;// Snip - write the contents of the log&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font size="2"&gt;&lt;font face="Courier New"&gt;&lt;span style="color: green"&gt;&amp;#160;&amp;#160;&amp;#160; // to the page&lt;/span&gt;&lt;/font&gt;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: blue"&gt;base&lt;/span&gt;.Render(writer);&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;&amp;#160;&amp;#160;&amp;#160; &lt;span style="color: #2b91af"&gt;BaseDataContext&lt;/span&gt;.Logger = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;StringBuilder&lt;/span&gt;();&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;font face="Courier New" size="2"&gt;}&lt;/font&gt;&lt;/p&gt;    &lt;p style="margin: 0px"&gt;&lt;span style="color: #e000e0"&gt;&lt;font face="Courier New" size="2"&gt;#endif&lt;/font&gt;&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;This ensures the log is cleared down right at the very end of the page lifecycle, ready to start logging queries for the next page. Also, as the log is only cleared after it's written out, no queries get lost if the page lifecycle ends prematurely in a redirect.&lt;/p&gt;  &lt;p&gt;The snipped code is a bit lengthy, but it basically renders the database hit count with a little jQuery to expand the full details of the queries when clicked, as in the screenshots above.&lt;/p&gt;  &lt;p&gt;Astonishingly you can't do this sort of thing at all in LINQ to Entities - it doesn't have this logging support - so for all the flexibility that it offers, it's still missing some features that seem pretty crucial to us.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-4921589905915764577?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/4921589905915764577/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=4921589905915764577' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4921589905915764577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4921589905915764577'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/04/logging-all-linq-to-sql-queries-used-in_23.html' title='Logging all LINQ to SQL queries used in a single page lifecycle'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_zsifaW4TiJo/SfBJeLAqHkI/AAAAAAAAAAw/sVrNIh3A5uA/s72-c/DbHitCountClosed.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-1837721630371821350</id><published>2009-04-20T15:07:00.003Z</published><updated>2009-04-28T09:36:25.862Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='interactivity'/><category scheme='http://www.blogger.com/atom/ns#' term='plugin'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>jQuery plugins - A treasure trove of awesome</title><content type='html'>&lt;span style=";font-family:verdana;font-size:85%;"  &gt;In order to provide a richer, cross-browser, more interactive experience for our client web applications, we make use of &lt;a href="http://www.jquery.com/"&gt;jQuery&lt;/a&gt;. jQuery is a robust javascript framework that takes a lot of the complexity out of writing client side javascript.&lt;br /&gt;&lt;br /&gt;One of the most powerful features of the framework is that it's been developed with a highly extensible plugin model.&lt;br /&gt;&lt;br /&gt;We recently decided to add some interactivity to our partner site &lt;a href="http://www.bluesulphur.com/"&gt;Bluesulphur&lt;/a&gt; to replace some of the flash content we currently have. As part of that, I looked at some of the plugins currently available.&lt;br /&gt;These are some of the nicest plugins I found.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_gPRWTjkTHUU/Seyc6EF0dQI/AAAAAAAAABo/T_25M8zzSw0/s1600-h/autosuggest.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: right; cursor: pointer; width: 198px; height: 272px;" src="http://3.bp.blogspot.com/_gPRWTjkTHUU/Seyc6EF0dQI/AAAAAAAAABo/T_25M8zzSw0/s320/autosuggest.png" alt="" id="BLOGGER_PHOTO_ID_5326804980616951042" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;&lt;a href="http://web2ajax.fr/examples/facebook_searchengine/"&gt;Facebook search engine&lt;/a&gt; - A Facebook style autosuggest plugin using jQuery. It's particularly pretty and although it currently uses a php source for data, this isn't a big limitation, these can be swapped out to use .NET web services as a provider quite easily.&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_gPRWTjkTHUU/SeygJ5eEJFI/AAAAAAAAABw/Q-nz3xi4YrU/s1600-h/codabubble.png"&gt;&lt;img style="margin: 10px 0pt 10px 10px; float: left; cursor: pointer; width: 279px; height: 194px;" src="http://2.bp.blogspot.com/_gPRWTjkTHUU/SeygJ5eEJFI/AAAAAAAAABw/Q-nz3xi4YrU/s320/codabubble.png" alt="" id="BLOGGER_PHOTO_ID_5326808551178642514" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;&lt;br /&gt;&lt;a href="http://jqueryfordesigners.com/demo/coda-bubble.html"&gt;coda bubble&lt;/a&gt; is a mac like popup that could be put to use in many situations.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_gPRWTjkTHUU/SeyiqMrLe2I/AAAAAAAAACA/5vS4Jz6BmwM/s1600-h/tablesorter.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 113px;" src="http://2.bp.blogspot.com/_gPRWTjkTHUU/SeyiqMrLe2I/AAAAAAAAACA/5vS4Jz6BmwM/s400/tablesorter.png" alt="" id="BLOGGER_PHOTO_ID_5326811305112992610" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;&lt;br /&gt;&lt;a href="http://tablesorter.com/docs/#demo"&gt;jQuery Tablesorter&lt;/a&gt; is a cute little plugin that makes any table sortable&lt;/p&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_gPRWTjkTHUU/SeyjddcFgCI/AAAAAAAAACI/hmiCvcUsr3w/s1600-h/fancybox.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: left; cursor: pointer; width: 316px; height: 400px;" src="http://1.bp.blogspot.com/_gPRWTjkTHUU/SeyjddcFgCI/AAAAAAAAACI/hmiCvcUsr3w/s400/fancybox.png" alt="" id="BLOGGER_PHOTO_ID_5326812185786417186" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;&lt;a href="http://fancy.klade.lv/example"&gt;Fancybox &lt;/a&gt;is a popup plugin that you can use for popup image galleries, the popups have nice transition effects as well as inbuilt navigation and grouping functionality.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_gPRWTjkTHUU/SeykZ8HE78I/AAAAAAAAACQ/wkSBJcq0pdA/s1600-h/markitup.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 385px;" src="http://2.bp.blogspot.com/_gPRWTjkTHUU/SeykZ8HE78I/AAAAAAAAACQ/wkSBJcq0pdA/s400/markitup.png" alt="" id="BLOGGER_PHOTO_ID_5326813224811950018" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;I thought for the last example, I'd show an html editor and I really like markitup, it's both simple and sexy. It looks like it's an easy integrator too, which is always a plus.&lt;/p&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;So, to sum up, there are a lot jQuery plugins out there, more than 2500 just on the &lt;a href="http://plugins.jquery.com/"&gt;jQuery plugin site&lt;/a&gt; alone. New and awesome plugins are being released every day, check them out!&lt;/p&gt;&lt;p style="font-family: verdana; font-size: 85%; display: block; clear: both;"&gt;Oh, and &lt;a href="http://www.compsoft.co.uk/"&gt;Compsoft &lt;/a&gt;are a great choice for integrating jQuery interactivity and plugins into your site too! *wink*&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-1837721630371821350?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/1837721630371821350/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=1837721630371821350' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1837721630371821350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1837721630371821350'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/04/jquery-plugins-treasure-trove-of.html' title='jQuery plugins - A treasure trove of awesome'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_gPRWTjkTHUU/SRY7HZpOTSI/AAAAAAAAAAM/OAQvr_kigYM/S220/tree-thumb.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_gPRWTjkTHUU/Seyc6EF0dQI/AAAAAAAAABo/T_25M8zzSw0/s72-c/autosuggest.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-7978070243187532844</id><published>2009-04-09T14:43:00.005Z</published><updated>2009-04-09T15:10:14.294Z</updated><title type='text'>SQL Server Express Automated Backup</title><content type='html'>SQL Server Express does not come with the SQL agent support which means there is no easy way to schedule backups of databases.&lt;br /&gt;&lt;br /&gt;After some googling, a &lt;a href="http://www.sqldbatips.com/showarticle.asp?ID=27"&gt;great article by Jasper Smith&lt;/a&gt; came up. He has built a wonderful stored procedure that backups all the databases on the instance and even produces a report for the backup.&lt;br /&gt;&lt;br /&gt;Really nice feature of the script is that it will even allows you to manage how long the backups are kept for!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.sqldbatips.com/showarticle.asp?ID=27"&gt;Read the original article&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-7978070243187532844?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.sqldbatips.com/showarticle.asp?ID=27' title='SQL Server Express Automated Backup'/><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/7978070243187532844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=7978070243187532844' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7978070243187532844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/7978070243187532844'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/04/sql-server-express-automated-backup.html' title='SQL Server Express Automated Backup'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-9196743555093743014</id><published>2009-03-30T08:08:00.008Z</published><updated>2009-04-23T08:35:55.644Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySQL'/><category scheme='http://www.blogger.com/atom/ns#' term='new id'/><category scheme='http://www.blogger.com/atom/ns#' term='multiuser'/><category scheme='http://www.blogger.com/atom/ns#' term='website'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='pear'/><category scheme='http://www.blogger.com/atom/ns#' term='insert'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrent'/><title type='text'>Multiuser atomic SQL; day one</title><content type='html'>Recently we've taken over support for a new, externally developed application that sends text messages to mobiles in response to shortcode requests for more information about cars, houses etc for sale.&lt;br /&gt;&lt;br /&gt;Under development and testing everything was fine. However, when it went live the registration process occasionally failed. After a brief examination I noticed this method for inserting records in the database class:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red128\green0\blue128;\red128\green128\blue0;}??\fs20 \cf1 {\b $newId}\cf0  \cf4 {\b =}\cf0  \cf1 {\b $this}\cf4 {\b -&gt;}\cf0 conn\cf4 {\b -&gt;}\cf0 nextID(\cf1 {\b $tableName}\cf0  \cf4 {\b .}\cf0  \cf5 "_id"\cf0 );} --&gt; &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;$newId&lt;/span&gt; &lt;span style="font-weight: bold;color:purple;" &gt;=&lt;/span&gt; &lt;span style="font-weight: bold;color:blue;" &gt;$this&lt;/span&gt;&lt;span style="font-weight: bold;color:purple;" &gt;-&gt;&lt;/span&gt;conn&lt;span style="font-weight: bold;color:purple;" &gt;-&gt;&lt;/span&gt;nextID(&lt;span style="font-weight: bold;color:blue;" &gt;$tableName&lt;/span&gt; &lt;span style="font-weight: bold;color:purple;" &gt;.&lt;/span&gt; &lt;span style="color:olive;"&gt;"_id"&lt;/span&gt;);&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;I suspected that this did something a little unusual.&lt;br /&gt;&lt;br /&gt;It had been written in Php5 backed by MySQL and was using the Pear DB package. It rapidly became clear the book "Professional PHP5" had been used a little too religiously. The book suggests this facade method for generating and getting the next ID for a new record that hides the operational differences between MySQL, PostreSQL, Oracle and other RDBMS.&lt;br /&gt;&lt;br /&gt;Under the hood, Pear DB creates an id tracking table of the same name suffixed with "_id_seq" for each table storing data with unique ids. It gets the value from this tracking table, adds one to the value, stores it back, and returns this value as the next id to be used in the insert statement for the new record.&lt;br /&gt;&lt;br /&gt;So I heard websites and the internet was a concurrent multiuser enviroment? Can anyone guess what might be the problem generating unique ids this way?&lt;br /&gt;&lt;br /&gt;MySQL gives the us the &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html"&gt;auto_increment&lt;/a&gt; feature. It also gives us the &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/mysql-insert-id.html"&gt;mysql_insert_id&lt;/a&gt; method. This allows us to get the last auto generated id if we need it:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red128\green0\blue128;}??\fs20 \cf1 {\b $newId}\cf0  \cf4 {\b =}\cf0  mysql_insert_id(\cf1 {\b $this}\cf4 {\b -&gt;}\cf0 conn\cf4 {\b -&gt;}\cf0 connection);} --&gt; &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;$newId&lt;/span&gt; &lt;span style="font-weight: bold;color:purple;" &gt;=&lt;/span&gt; mysql_insert_id(&lt;span style="font-weight: bold;color:blue;" &gt;$this&lt;/span&gt;&lt;span style="font-weight: bold;color:purple;" &gt;-&gt;&lt;/span&gt;conn&lt;span style="font-weight: bold;color:purple;" &gt;-&gt;&lt;/span&gt;connection);&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;"But surely, when inserting new records in a concurrent multiuser environment, we need actions like this to be as atomic as possible?" I hear you ask. The force (read SQL) is strong with this one. Correct.&lt;br /&gt;&lt;br /&gt;MySQL allows us to provide a value for an auto_increment field, or we can supply 'null' and allow MySQL to do it for us.&lt;br /&gt;&lt;br /&gt;So to fix this intermittent registration failure, we replace the line:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red128\green0\blue128;\red128\green128\blue0;}??\fs20 \cf1 {\b $newId}\cf0  \cf4 {\b =}\cf0  \cf1 {\b $this}\cf4 {\b -&gt;}\cf0 conn\cf4 {\b -&gt;}\cf0 nextID(\cf1 {\b $tableName}\cf0  \cf4 {\b .}\cf0  \cf5 "_id"\cf0 );} --&gt; &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;$newId&lt;/span&gt; &lt;span style="font-weight: bold;color:purple;" &gt;=&lt;/span&gt; &lt;span style="font-weight: bold;color:blue;" &gt;$this&lt;/span&gt;&lt;span style="font-weight: bold;color:purple;" &gt;-&gt;&lt;/span&gt;conn&lt;span style="font-weight: bold;color:purple;" &gt;-&gt;&lt;/span&gt;nextID(&lt;span style="font-weight: bold;color:blue;" &gt;$tableName&lt;/span&gt; &lt;span style="font-weight: bold;color:purple;" &gt;.&lt;/span&gt; &lt;span style="color:olive;"&gt;"_id"&lt;/span&gt;);&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;with:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red128\green0\blue128;\red128\green128\blue0;}??\fs20 \cf1 {\b $newId}\cf0  \cf4 {\b =}\cf0  \cf5 'null'\cf0 ;} --&gt; &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="font-weight: bold;color:blue;" &gt;$newId&lt;/span&gt; &lt;span style="font-weight: bold;color:purple;" &gt;=&lt;/span&gt; &lt;span style="color:olive;"&gt;'null'&lt;/span&gt;;&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;And LO, the bug is gone.&lt;br /&gt;Needless to say Pear DB has been replaced by something else. And interestingly if you read on a little in the book you'll see "we strongly recommend... ideally, allow your RDBMS to [generate the id]"&lt;br /&gt;&lt;br /&gt;So what? Read books carefully. Know the technology you're using. Concurrency requires atomic superness.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-9196743555093743014?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/9196743555093743014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=9196743555093743014' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/9196743555093743014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/9196743555093743014'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/03/multiuser-atomic-sql-day-one.html' title='Multiuser atomic SQL; day one'/><author><name>John Green</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-6696207888828846218</id><published>2009-03-17T10:28:00.016Z</published><updated>2009-03-25T15:28:34.413Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='login'/><category scheme='http://www.blogger.com/atom/ns#' term='password'/><category scheme='http://www.blogger.com/atom/ns#' term='website'/><category scheme='http://www.blogger.com/atom/ns#' term='user account'/><category scheme='http://www.blogger.com/atom/ns#' term='security'/><category scheme='http://www.blogger.com/atom/ns#' term='dictionary attack'/><category scheme='http://www.blogger.com/atom/ns#' term='hack'/><title type='text'>Securing web logins against dictionary attacks</title><content type='html'>It's good to learn from your mistakes; it's even better to learn from other people's. So, when &lt;a href="http://www.theregister.co.uk/2009/01/07/twitter_hack_explained/"&gt;Twitter got hacked by a simple dictionary attack&lt;/a&gt;, we, the development team at &lt;a href="http://www.compsoft.co.uk"&gt;Compsoft&lt;/a&gt;, thought it a good time to review our password security model.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Because pretty much everyone wants password protection for at least some part of their web site, password security is something we've implemented quite a few times already. And as nobody enjoys re-inventing the wheel, this already lives in our well-established reusable code libraries - meaning that if we ever identify a weakness we can fix it in one place. At the very least, all our future customers get this improvement out of the box; where appropriate, the upgrades get rolled out to our existing customers too.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Our password handling was already pretty tight - we use some pretty aggressive &lt;a href="http://en.wikipedia.org/wiki/Salt_(cryptography)"&gt;salting&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Cryptographic_hash_function"&gt;hashing&lt;/a&gt; to ensure that passwords are held so securely that even we can't crack them. Even though I have full access to the database, I don't know your password; I can't tell anything about your password; I can't even tell if two people have the same password. If I copy the password details from my user record to yours, I still won't be able to log in as you. It's got to the point that it's quite difficult for us to set up the first user record in a new database - even copying password details from one database to another won't work.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyway, storing the password securely is all well and good, but doesn't help if your users use passwords that are easily guessable, as Twitter found to their embarrassment. The key feature they'd failed to implement (and that we realised we'd immediately have to add to our arsenal) was preventing unlimited password attempts.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Though &lt;a href="http://en.wikipedia.org/wiki/Dictionary_attack"&gt;dictionary attacks&lt;/a&gt; are always going to be slow when executed across the internet, they're still entirely possible - especially given that the only limit on a typical hacker's time is how quickly he gets bored.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The easiest solution is to say "if you get your password wrong five times, your account gets blocked". This is quick and easy to implement, but what does it mean for our users? Sure, they'd be protected against having their account hacked, but could they not legitimately take five attempts before they remember which password they used for this site? At times I've taken a lot more than that, going through more and more possible passwords that I think I might have used, before finding that the one I tried first was right - I'd just typed it wrong.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Increasing the number of attempts allowed doesn't really solve the problem - if they breach it, they're locked out completely. That means we'd have to add some mechanism whereby they can contact an administrator and convince them that they are who they say they are, so that the admin will re-enable their account. Not only would this alienate users, but this isn't really practical for a solution we can reuse across many intra- and internet sites.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What's worse, it's easy for one malicious user to lock other users out of their accounts, simply by repeatedly trying to log in as them.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We need something that is entirely invisible to as many genuine users as possible, but that is insurmountable to a dictionary attack in any reasonable amount of time. Also, should we start suspecting a legitimate user might be a hacker, they mustn't feel like we've just slammed the door in their face.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The solution we finally opted for goes like this:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;You get ten attempts to try to remember your password.&lt;/li&gt;&lt;li&gt;On the eleventh attempt, your account is locked for one minute.&lt;/li&gt;&lt;li&gt;Each subsequent attempt locks your account for twice as long: two minutes, four minutes, eight minutes...&lt;/li&gt;&lt;li&gt;If you make no log in attempts for twenty-four hours, we reset the counter to zero again.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Almost all users will never see that this security exists. Those who break the ten-guess limit see a polite message informing them of why we think something's wrong ("a large number of login attempts using the wrong password") and how long they new have left to wait before they can try again.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The first few times they see this limit they'll not have to wait long, and in the meantime we're gently teaching them to think a little more carefully about what password they might have used.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On the other hand, a hacker using a dictionary attack would have to attack the same user id persistently for a full 24 hours to get through just the first 21 words in his attack dictionary.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The experience of the attacked user isn't too bad either - they'll only know there's even been a problem if they try to log in shortly after the hacker (or malicious user) has been trying to access their account. The worst that could happen would be that they wouldn't be able to log in until tomorrow.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For us, this is a nice solution. We've implemented it as part of our reusable code framework, and included it in the template used by our code generation tool. This means that even though we haven't started work making your next website for you yet, your next website is already more secure than Twitter was.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-6696207888828846218?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/6696207888828846218/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=6696207888828846218' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6696207888828846218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/6696207888828846218'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/03/securing-web-logins-against-dictionary.html' title='Securing web logins against dictionary attacks'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-8791029274549863493</id><published>2009-03-09T14:04:00.007Z</published><updated>2009-03-09T15:00:50.696Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows mobile'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='.net implementation'/><category scheme='http://www.blogger.com/atom/ns#' term='bug fix'/><title type='text'>Implementing visual inheritance in windows mobile</title><content type='html'>&lt;span style="font-family:verdana;"&gt;We've been working on a Windows Mobile 6 PDA application and one requirement is to have a status bar that shows internet connectivity and updates.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;In Windows programming, a common way to do this is to create a base form which has a status bar and a mechanism to update it, this form is then used as a template for other forms. This means that you have a single point of failure, update and maintenance. This is a good thing as if you added that status bar to all your forms, you'd increase your maintenance headache with each new form.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;On Windows Mobile, there is support for the same visual templating mechanism, but there are a few pitfalls.&lt;/span&gt; &lt;span style="font-family:verdana;"&gt;If for example on your base form you wanted to add a popup keyboard, you'd need to add a reference to Microsoft.WindowsCE.Forms.&lt;/span&gt; &lt;span style="font-family:verdana;"&gt;This unfortunately breaks the vis&lt;/span&gt;&lt;span style="font-family:verdana;"&gt;ual inheritance in Visual Studio's form designer saying "Visual inheritance is currently disabled", this also occurs when using Platform Invoke (a method of calling methods in the base operating system) in the base form.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Luckily there are a few workarounds for this:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Add a class diagram, select your base form, add a custom attribute of DesktopCompa&lt;/span&gt;&lt;span style="font-family:verdana;"&gt;tible(true), this adds an XML Metadata Attribute file (.xmta).The xmta file can cause a genasm.exe error, ensure the build action is set to None and the copy to output directory is set to Do not copy, this should now build fine.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_gPRWTjkTHUU/SbUsPJN6hFI/AAAAAAAAABg/NIaPxtrJjPk/s1600-h/properties.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 204px;" src="http://2.bp.blogspot.com/_gPRWTjkTHUU/SbUsPJN6hFI/AAAAAAAAABg/NIaPxtrJjPk/s320/properties.gif" alt="" id="BLOGGER_PHOTO_ID_5311199974237307986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt; &lt;span style="font-family:verdana;"&gt;Job done, we have visual inheritance visible in the designer.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-8791029274549863493?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/8791029274549863493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=8791029274549863493' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8791029274549863493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/8791029274549863493'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/03/implementing-visual-inheritance-in.html' title='Implementing visual inheritance in windows mobile'/><author><name>Tristan</name><uri>http://www.blogger.com/profile/17936136441649563459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_gPRWTjkTHUU/SRY7HZpOTSI/AAAAAAAAAAM/OAQvr_kigYM/S220/tree-thumb.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_gPRWTjkTHUU/SbUsPJN6hFI/AAAAAAAAABg/NIaPxtrJjPk/s72-c/properties.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-3939589644759044644</id><published>2009-03-02T11:58:00.009Z</published><updated>2009-03-02T15:41:26.629Z</updated><title type='text'>Creating an Installer for Windows Mobile Applications</title><content type='html'>We recently had a requirement come up to create a windows installer for a mobile application. So a couple of minutes of googling gets me a &lt;a href="http://msdn.microsoft.com/en-us/library/bb158529.aspx"&gt;great MSDN article&lt;/a&gt; on step by step instructions on creating an installer.&lt;br /&gt;&lt;br /&gt;However, great as MSDN is, the article had some flaws, it didn't work! The application installed on the local windows machine but didn't trigger the mobile install on the device.&lt;br /&gt;&lt;br /&gt;After some debugging of the installer code, I found that the article refers to Context.Parameters["InstallDirectory"] however it asks you to place targetdir="[TARGETDIR]\" in the CustomActionData property. This meant the install directory was not being transfered to the DLL.&lt;br /&gt;&lt;br /&gt;To make the project work you need to get those two to match. Update the code to use Context.Parameters["TargetDir"] and everything works a treat.&lt;br /&gt;&lt;br /&gt;Remember to set both Commit and Install custom actions to the new DLL otherwise it won't install correctly.&lt;br /&gt;&lt;br /&gt;The final code looks like:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    /// &lt;summary&gt;&lt;br /&gt;   /// Code implemented from: http://msdn.microsoft.com/en-us/library/bb158529.aspx&lt;br /&gt;   /// &lt;/summary&gt;&lt;br /&gt;   [RunInstaller(true)]&lt;br /&gt;   public partial class CustomInstaller : Installer&lt;br /&gt;   {&lt;br /&gt;       public &lt;/span&gt;&lt;span style="font-family:monospace;"&gt;CustomInstaller&lt;/span&gt;&lt;span style="font-family:monospace;"&gt;()&lt;br /&gt;       {&lt;br /&gt;           InitializeComponent();&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       public override void Commit(System.Collections.IDictionary savedState)&lt;br /&gt;       {&lt;br /&gt;           // Call the Commit method of the base class&lt;br /&gt;           base.Commit(savedState);&lt;br /&gt;&lt;br /&gt;           // Open the registry key containing the path to the Application Manager&lt;br /&gt;           Microsoft.Win32.RegistryKey key = null;&lt;br /&gt;           key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software\\microsoft\\windows\\currentversion\\app paths\\ceappmgr.exe");&lt;br /&gt;&lt;br /&gt;           // If the key is not null, then ActiveSync is installed on the user's desktop computer&lt;br /&gt;           if (key != null)&lt;br /&gt;           {&lt;br /&gt;               // Get the path to the Application Manager from the registry value&lt;br /&gt;               string appPath = null;&lt;br /&gt;               appPath = key.GetValue(null).ToString();&lt;br /&gt;&lt;br /&gt;               // Get the target directory where the .ini file is installed.&lt;br /&gt;               // This is sent from the Setup application&lt;br /&gt;               string strIniFilePath = "\"" + Context.Parameters["TargetDir"] + "ObScan.ini\"";&lt;br /&gt;               if (appPath != null)&lt;br /&gt;               {&lt;br /&gt;                   // Now launch the Application Manager&lt;br /&gt;                   System.Diagnostics.Process process = new System.Diagnostics.Process();&lt;br /&gt;                   process.StartInfo.FileName = appPath;&lt;br /&gt;                   process.StartInfo.Arguments = strIniFilePath;&lt;br /&gt;                   process.Start();&lt;br /&gt;               }&lt;br /&gt;           }&lt;br /&gt;           else&lt;br /&gt;           {&lt;br /&gt;               throw new Exception("No Active sync installed");&lt;br /&gt;           }&lt;br /&gt;       }&lt;br /&gt;   }&lt;/span&gt;&lt;code&gt;&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-3939589644759044644?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/3939589644759044644/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=3939589644759044644' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3939589644759044644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/3939589644759044644'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/03/creating-installer-for-windows-mobile.html' title='Creating an Installer for Windows Mobile Applications'/><author><name>Neil</name><uri>http://www.blogger.com/profile/05786592919990732043</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-1673985465455819192</id><published>2009-02-23T15:01:00.016Z</published><updated>2009-03-31T10:45:53.563Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='geocode'/><category scheme='http://www.blogger.com/atom/ns#' term='.net implementation'/><category scheme='http://www.blogger.com/atom/ns#' term='Compsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><category scheme='http://www.blogger.com/atom/ns#' term='website development'/><category scheme='http://www.blogger.com/atom/ns#' term='draggable'/><category scheme='http://www.blogger.com/atom/ns#' term='google maps'/><title type='text'>Vagaries of geocoding a postcode</title><content type='html'>Plotting 'lat lngs' on a map is a fairly straight forward task. Especially doing it on a Google map.&lt;br /&gt;&lt;br /&gt;Using a .NET implementation of a Google map is nice and easy. Doing it with PHP and javaScript is a bit more of a work up, but perhaps more satisfying when you get dirty and use some of the natty little Google features available.&lt;br /&gt;&lt;br /&gt;However, in the course of writing a site for a Letting agent [&lt;a href="http://www.batterseaflats.com/"&gt;www.batterseaflats.com&lt;/a&gt;] I came across an unexpected result when geocoding via HTTP with Google.&lt;br /&gt;&lt;br /&gt;To make the site really easy to administrate details of properties I thought it would be nice to have a field containing the property's postcode, and during the save process, geocode up the postcode to get a nice 'lat lng' to show on a map. Of course I based the expected result on the performance of locating a postcode via Google's own maps.google.co.uk interface, which is nice and accurate.&lt;br /&gt;&lt;br /&gt;Unfortunately, I often ended up with addresses that weren't quite in the right place.  Much as I like Germany, I was quite sure I shouldn't be displaying properties outside of London!&lt;br /&gt;&lt;br /&gt;I switched to using the &lt;span style="color: rgb(0, 153, 0);"&gt; &lt;/span&gt;&lt;code style="color: rgb(0, 153, 0);"&gt;GClientGeocoder &lt;/code&gt;Google object, but it still wasn't accurate enough. (Consider having four or five properties in the same street to advertise, you really want them to be in the right place on the street).&lt;br /&gt;&lt;br /&gt;So I thought I'd let the user geocode an address string (because flats are sometimes in blocks with a name that can cause problems trying to guess what the user has typed in), then allow them to move the point around on the map. A simple feature, which the client really liked!&lt;br /&gt;&lt;br /&gt;Use &lt;span style="color: rgb(0, 153, 0);"&gt; &lt;/span&gt;&lt;code style="color: rgb(0, 153, 0);"&gt;GClientGe&lt;/code&gt;&lt;code style="color: rgb(0, 153, 0);"&gt;oco&lt;/code&gt;&lt;code style="color: rgb(0, 153, 0);"&gt;der&lt;/code&gt;&lt;span style="font-family:monospace;"&gt; &lt;/span&gt;to get location:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red163\green21\blue21;}??\fs20 \cf1 function\cf0  showAddress(address) \{\par ??    geocoder.getLatLng(\par ??                address,\par ??                \cf1 function\cf0 (point) \{\par ??                    \cf1 if\cf0  (!point) \{\par ??                        alert(address + \cf4 " not found"\cf0 );\par ??                    \} \cf1 else\cf0  \{\par ??                        showPoint(point);\par ??                    \}\par ??                \}\par ??            );\par ??\}} --&gt; &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;function&lt;/span&gt; locateAddress(address) {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            geocoder.getLatLng(&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                        address,&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                        &lt;span style="color:blue;"&gt;function&lt;/span&gt;(point) {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                                                            &lt;span style="color:blue;"&gt;if&lt;/span&gt; (!point) {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                                                                                alert(address + &lt;span style="color: rgb(163, 21, 21);"&gt;" not found"&lt;/span&gt;);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                                                            } &lt;span style="color:blue;"&gt;else&lt;/span&gt; {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                                                                                showPoint(point);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                                                            }&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                                        });&lt;/p&gt; &lt;p style="margin: 0px;"&gt;}&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;When creating the marker on the map, enable the 'draggable' &lt;code style="color: rgb(0, 153, 0);"&gt;GMarker&lt;/code&gt; property:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;}??\fs20 \cf1 var\cf0  marker = \cf1 new\cf0  GMarker(point, \{ icon: iconAvailable, draggable: \cf1 true\cf0 , dragCrossmove: \cf1 true\cf0  \});} --&gt; &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;var&lt;/span&gt; marker = &lt;span style="color:blue;"&gt;new&lt;/span&gt; GMarker(point, { icon: iconAvailable, draggable: &lt;span style="color:blue;"&gt;true&lt;/span&gt;, dragCrossmove: &lt;span style="color:blue;"&gt;true&lt;/span&gt; });&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;and listen for the marker's 'dragend' and capture the new location:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red163\green21\blue21;\red0\green0\blue255;}??\fs20 GEvent.addListener(marker, \cf3 "dragend"\cf0 , \cf4 function\cf0 (latlng) \{\par ??        showLatLng(latlng);\par ??    \});} --&gt; &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;GEvent.addListener(marker, &lt;span style="color: rgb(163, 21, 21);"&gt;"dragend"&lt;/span&gt;, &lt;span style="color:blue;"&gt;function&lt;/span&gt;(latlng) {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                                captureLatLng(latlng);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    });&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;And when displaying the list of properties, go crazy by synchronising the mouse hovering on the sidebar list of entries with the markers by adding a Event Listeners for 'mouseover' and 'mouseout' switching the styles as needed:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red163\green21\blue21;\red0\green0\blue255;}??\fs20     GEvent.addDomListener(div, \cf3 'mouseover'\cf0 , \cf4 function\cf0 () \{\par ??        div.className = \cf3 'sideHighlight'\cf0 ;\par ??        marker.setImage(\cf3 'images/highlightHouse.png'\cf0 );\par ??    \});\par ??    GEvent.addDomListener(div, \cf3 'mouseout'\cf0 , \cf4 function\cf0 () \{\par ??        div.className = \cf3 'sideNormal'\cf0 ;\par ??        marker.setImage(\cf3 'images/house.png'\cf0 );\par ??    \});} --&gt; &lt;div    style="background: white none repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;GEvent.addDomListener(div, &lt;span style="color: rgb(163, 21, 21);"&gt;'mouseover'&lt;/span&gt;, &lt;span style="color:blue;"&gt;function&lt;/span&gt;() {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                            div.className = &lt;span style="color: rgb(163, 21, 21);"&gt;'sideHighlight'&lt;/span&gt;;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                            marker.setImage(&lt;span style="color: rgb(163, 21, 21);"&gt;'images/highlightHouse.png'&lt;/span&gt;);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;});&lt;/p&gt; &lt;p style="margin: 0px;"&gt;GEvent.addDomListener(div, &lt;span style="color: rgb(163, 21, 21);"&gt;'mouseout'&lt;/span&gt;, &lt;span style="color:blue;"&gt;function&lt;/span&gt;() {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                            div.className = &lt;span style="color: rgb(163, 21, 21);"&gt;'sideNormal'&lt;/span&gt;;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                            marker.setImage(&lt;span style="color: rgb(163, 21, 21);"&gt;'images/house.png'&lt;/span&gt;);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;});&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Details of the Battersea Flats project can be found here: &lt;a href="http://www.compsoft.co.uk/Portfolio_Battersea_Flats"&gt;http://www.compsoft.co.uk/Portfolio_Battersea_Flats&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-1673985465455819192?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/1673985465455819192/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=1673985465455819192' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1673985465455819192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/1673985465455819192'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/02/vagaries-of-geocoding-postcode.html' title='Vagaries of geocoding a postcode'/><author><name>John Green</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-4152137792099563378</id><published>2009-02-12T16:43:00.012Z</published><updated>2009-02-13T14:15:10.851Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='uber code'/><category scheme='http://www.blogger.com/atom/ns#' term='Tim Jeanes'/><category scheme='http://www.blogger.com/atom/ns#' term='displaying error message'/><category scheme='http://www.blogger.com/atom/ns#' term='RenderMode'/><category scheme='http://www.blogger.com/atom/ns#' term='IE Bug'/><category scheme='http://www.blogger.com/atom/ns#' term='Compsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='bug fix'/><category scheme='http://www.blogger.com/atom/ns#' term='website development'/><category scheme='http://www.blogger.com/atom/ns#' term='UpdatePanels'/><title type='text'>Empty UpdatePanels add a blank line after callback in IE</title><content type='html'>We hit a bug the other day where we found that UpdatePanels misbehave somewhat in Internet Explorer.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We spotted it because we always have an area at the top of our pages for displaying error messages. (You can see an example of this if you go to our &lt;a href="http://www.compsoft.co.uk/ContactUs"&gt;Contact Us&lt;/a&gt; page and click "Send Message" without filling in your contact details.)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you did a callback to the page that didn't result in any errors, the UpdatePanel around the error box would remain empty. Thus in most browsers you wouldn't see anything happen at the top of the page.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;However, IE would insert a blank line where the UpdatePanel was, bumping the rest of the page content down by 12 pixels or so.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is supremely annoying as it can really throw out the design of your site. It turns out it happens even if there elements in the UpdatePanel, if they're elements that don't render anything visible on the page (empty spans, hidden input controls, etc.).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, one way to fix it is to set the RenderMode of the UpdatePanel to Inline. This stops the bug in IE, but it also makes the UpdatePanel render as a span instead of a div. This is no good for us because the error box (when it renders) is a div, and nesting a div inside a span is invalid html.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So here's the solution we came up with - I hope it's useful to you too!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We created a class that inherits from UpdatePanel, but overrides how it renders, adding a style of display:inline if it's rendering as a div. So now it's still a div (and so it's valid to nest div within it), but it renders inline as a span would, thus sidestepping the IE bug.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Also, as it inherits directly from UpdatePanel, we can use &amp;lt;Compsoft:UpdatePanel&amp;gt; everywhere that we'd use &amp;lt;asp:UpdatePanel&amp;gt;. It's fire-and-forget: it behaves exactly like an UpdatePanel, except without the problems.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:x-small;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;public class&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 153, 153);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;UpdatePanel : UpdatePanel&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;  protected override void&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt; RenderChildren(&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 153, 153);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;HtmlTextWriter &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;writer)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;  {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;    // IsInPartialRendering is a reliable way of&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;    // telling it's a callback&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;    if &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;(!&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;this&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;.IsInPartialRendering &amp;amp;&amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;      this&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;.RenderMode == &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 153, 153);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;UpdatePanelRenderMode&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;.Block)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 153, 153);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;      StringBuilder &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;sb = &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;new &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 153, 153);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;StringBuilder&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;      base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;.RenderChildren(&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;new &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 153, 153);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;HtmlTextWriter&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;        new &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 153, 153);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;StringWriter&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;(sb)));&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;      string &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;renderedHtml = sb.ToString();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;      if &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;(!renderedHtml.StartsWith(&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style=""&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;div "&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style=""&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 102, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;        // This should never happen; better safe than sorry&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;        throw new &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 153, 153);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;Exception&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;          "An UpdatePanel with a RenderMode of Block "&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;          + "isn't rendering as a &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style=""&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;div&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style=""&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style=""&gt;&lt;span class="Apple-style-span" style=""&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;        writer.Write(&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style=""&gt;&lt;span class="Apple-style-span" style=""&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style=""&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 0, 0);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;div style=\"display:inline\""&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;        writer.Write(renderedHtml.Substring(4));&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;    else&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;      base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;.RenderChildren(writer);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: 'courier new';"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-4152137792099563378?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/4152137792099563378/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=4152137792099563378' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4152137792099563378'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4152137792099563378'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2009/02/empty-updatepanels-add-blank-line-after.html' title='Empty UpdatePanels add a blank line after callback in IE'/><author><name>Tim Jeanes</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/_zsifaW4TiJo/Sy9NLwsb2lI/AAAAAAAAACE/74qdhfkdS-U/S220/KeenBeard_vectorized.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-4956198440693278579</id><published>2008-11-15T15:00:00.001Z</published><updated>2008-11-15T15:02:33.218Z</updated><title type='text'>Richard Thomason: TechEnd</title><content type='html'>The first great thing about TechEd is the buzz. You could spend a little time every month poking around on Microsoft sites, subscribe to their feeds and look at the key blogs. I don't do that and instead rely on the geek version of bush telegraph to alert me of newage that I need to be aware of. This works fine for major stuff, and the killer factor is, it's very low maintenance. At TechEd though, there's a load of people who've been beavering away at Microsoft things for a whole year and are busting to show you. You can spend days reading blogs and feeds and forums and really, it's all words; ten minutes in a TechEd presentation, and you can tell from the seniority of the speaker, the information content and the demo whether something is useful now or over the horizon, irrelevant or cool, forget it or must have.&lt;br /&gt;&lt;br /&gt;Azure is a good example of this. I have a blx alarm that automatically goes off every time I hear the phrase "in the cloud", and until last week it has protected me from discovering much about it. I figured I'd better go to an overview since there was so much buzz, and ended up going to a couple more  sessions to get the big picture and some practical demonstrations. If MS get the scalability / cost right, and if they make deployment a doddle, and if you can write your app in such a way that it is deployable in or out of the cloud without too much hassle, it could be big.&lt;br /&gt;&lt;br /&gt;The second great thing is the random element. It's important to go to the widest selection of sessions that you can, since often the least likely turn out to be the most exciting. You can use the Robotics product to make a cut down version of Windows; that has to be good for something. You can also use it for loosely coupled but high performance applets which must inter-communicate. Virtual Earth, which I had pretty much written off because the Google offering is so good, is actually much better than I realised. There's no excuse now for customers to shy away from GIS functionality in their applications.&lt;br /&gt;&lt;br /&gt;Finally, it's a great team builder. There's nothing like being in an away team to clear the air and refocus. It's good to be on the plane home too though. A week's uninterrupted geekery is enough for me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/28989665-4956198440693278579?l=compsoftplc.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://compsoftplc.blogspot.com/feeds/4956198440693278579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=28989665&amp;postID=4956198440693278579' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4956198440693278579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/28989665/posts/default/4956198440693278579'/><link rel='alternate' type='text/html' href='http://compsoftplc.blogspot.com/2008/11/richard-thomason-techend.html' title='Richard Thomason: TechEnd'/><author><name>Richard</name><uri>http://www.blogger.com/profile/14019001721790919083</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-28989665.post-3138571179584699929</id><published>2008-11-14T15:24:00.001Z</published><updated>2008-11-14T15:25:55.957Z</updated><title type='text'>Tim Jeanes: TechEd 2008 - Day 5</title><content type='html'>&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;DAT317 - Project "Velocity": A First Look at Microsoft's Distributed Caching Framework&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;Velocity is Microsoft's upcoming caching framework. It's a distributed in-memory cache for all kinds of data - CLR objects, rows, XML, binary data, etc. - so long as you can serialize it, you can cache it.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;This allows you to share cached information over a number of web servers, providing fast access to the data held in the cache. The cache itself is also spread over a number of machines, but you never need to know which server is holding your cached item. Velocity supports failover too, so if one of the cache hosts goes down, your cached item is still available from another host.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;Objects are stored in the cache as named items, so the cache acts like a dictionary. Simple Get and Put commands can be used for basic access. Optimistic concurrecy can be used: Velocity tracks a version number of each item internally and only lets you update an item if there have been no other updates to it since it was retrieved. More pessimistically, you can use GetAndLock/ PutAndUnlock/ Unlock to prevent other threads or other servers updating items you're using. On top of the name of each item you cam apply tags, letting you retrieve sets of data with the same tag all in one go.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;As you'd expect, you can configure the cache to specify how long it holds on to items before they expire and have to be retrieved from the backend database again. A nice feature is that it also supports notifications, so that if you update an item in the cache, that cache host notifies all others that the item has been changed. Of course this model has a bit more overhead, so which to use depends on how time-critical the accuracy of your data is.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;Velocity also supports a SessionStoreProvider, making it easier to share session data over a number of web servers. This is about 200% faster than using SQL Server to store session state. Again this supports failover, so even if the primary machine that's storing your shopping cart goes up in smoke, that's not going to stop you spending money.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;PDC309 - Designing applications for Windows Azure&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;This was a great session because it filled in a lot of the detail of things we'd learnt about Azure earlier this week, and because it gave some coding best practices for working on the cloud. The presenter has already deployed a number of real-life Azure-based applications, so it's great to be able to pick up what he's learnt the hard way.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;I was a little surprised at some of the limitations of table storage. You can only have 255 properties per entry, which seems a bit arbitrarily small. Properties on table entities can only be the basic types (int, string, DateTime, Guid, etc.), as you'd expect, but there's a field size limit of 64K for strings and byte arrays. Each entity is limited to 1MB in total, though I suppose that makes sense - once your objects are getting that large they probably belong in a blob anyway. On the other hand, I'm glad to hear that they will be adding index support to table entity properties.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;For now you only get indexes on the row key and the partition key (both of which are strings - up to 64KB each). As a pair together, they make the primary key for the table, which I think is perhaps a little awkward: surely the row key by itself should be enough? It would make cross-partition joins much easier, and we all love GUIDs anyway. However, I suppose this does push you in the right direction: cross-partition joins can potentially be more expensive (because Azure will always ensure each partition is held entirely on one physical machine), so I guess you should avoid them where possible.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;As you don't get indexes on other properties (for the CTP, at least) this means you have to denormalise your data all over the place if you're going to want to do any kind of searching. More critically, as table storage has no support for transactions, it looks like we'll be waiting for SQL Data Services to come out before we try any real-life database-type storage in the cloud.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;We also took quite an in-depth look at queues and how to process them in worker roles.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;There is absolutely no limit to the number of queues you can have, so go crazy! One queue for each customer would be entirely feasible. The only restriction is the name of the queue: as queues can be accessed in a RESTful way, the name has to be something that you can use as part of a URI.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;I quite like the way messages are handled as they are read from a queue. When a message is read, it is marked as invisible so that other worker roles don't pick it up. If the role that took it dies and never deletes the message, it becomes visible again after a configurable timeout period. The downside is that if a malformed message always causes an exception, it remains on the queue forever. the way to handle this is to check the time the message was created, when you read it from the queue. If it's been there for a long time, delete the message from the queue. What you do next depends on your application - you could log the problem, put the bad message onto a "bad messages" queue, or whatever.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;It's possible (and more efficient) to read a number of messages from a queue at once, then process and delete them one at a time. Once the messages have been processed, you loop the worker role back to the start again - just by using while(true) - but sleep the Thread for a bit first if the queue was empty.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;One point that was mentioned a few times was that you have to code to accommodate failure. Worker roles may die unexpectedly part way through processing a message, for example, leaving your table storage in a half-baked state. The fact that everything is stateless coupled with the lack of transaction support on the table storage means there's a whole bunch of craziness you'll have to code around.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;The worker role has a property that returns its health status - you have to implement this yourself. An easy check is to see how long you've been processing the current message and flag yourself as unhealthy if it looks like you're stuck in an infinite loop. The health property does nothing in the current CTP release - in future Azure will monitor it to choose when to kill and restart the worker role.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;One little gotcha: when DateTime.Now in the cloud, remember you don't know where your code is running, so you can assume nothing about what timezone you're in. Always use DateTime.UtcNow instead.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;DVP315 - Do's and Don'ts in Silverlight 2 Applications&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;As we're just starting out in Silverlight 2, this was a really handy session. We got some tips from someone who's already made all our mistakes for us. Here they are:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;Don't:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;- Leave the default "Install Silverlight" message.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;It's rubbish and if your user hasn't heard of Silverlight then they're not going to install it. Instead display an image that shows the user what sort of thing they'll see in the real application, with a message telling them what they have to do.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;- Take a long time to load.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;Instead load assets after the main app has loaded. Also cache assets in the isolated storage so they don't have to get it again next time. That way if there's no internet access, we can look in the local cache. It there, your app can work offline.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;- Leave the default splash screen.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;- Use width and height with &lt;mediaelement&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;Resizing videos is very costly and wasteful in terms of CPU time, so show videos at their natural size only. Similarly, animating the size of text or complicated paths is also CPU intensive. To animate the size of text, build a vector from the text and scale that.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;- Use a transparent background to the Silverlight app - it's very expensive. Admittedly it can look great though...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;- Use opacity to hide something.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;If you fade something out, remember to set Visibility=Visibility.Collapsed at the end.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;Do:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;- Show the designer mock data for use in Blend.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;You can detect where a user control is being rendered by examining DesignerProperties.GetIsInDesignMode(this). Elsewhere you can check HtmlPage.IsEnabled.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;- Use EnableFrameRateCounter=true when debugging.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;This shows the current framerate in the status bar of the browser. Set the maximum framerate to something very high so you get an accurate indication of how your application's performing.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 0, 153);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span cla
