tag:blogger.com,1999:blog-87458255881945547982024-03-13T11:34:52.506-07:00designdotworksI am a freelance web developer / programmer situated in Birmingham, UK for the last 3 years. I offer services including... Web Development in... html, xhtml, css, javascript, xml, php, asp.net c# or vb, flash and silverlight. Or in other terms... The complete process of taking your ideas to the page in a professional, standards compliant and above all friendly manner.Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.comBlogger33125tag:blogger.com,1999:blog-8745825588194554798.post-51071825153552743442014-12-21T03:57:00.001-08:002014-12-21T03:57:50.908-08:00.Net XDocument ToString() DeadlockI have been working on a little project recently in which we was using some heavy .Net Runtime Caching of objects to reduce the strain on server resources as users access the same page over and over. We also implemented the same approach for caching the sites RSS feed. Crudely we was doing something similar to the following:<div style="text-align: justify;">
</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>public ActionResult Feed() {</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> XDocument document = null;</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> if (Cache["feed"] == null) {</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> document = new XDocument(...);</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> // Fill the document here...</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> Cache["feed"] = document;</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> } else {</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> document = Cache["feed"] as XDocument;</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> }</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> return Content(document.ToString(), </b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> "application/rss+xml");</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>}</b></span></div>
<div>
<br /></div>
<div>
The above is a stripped down example and is prone to errors in that if many users hit the method at the same time, there is no inherent locking, also the cache feed value could be ejected before it is read the second time. But we aren't here to work on that.</div>
<div>
<br /></div>
<div>
The issue here is the line:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>return Content(document.ToString(), </b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> "application/rss+xml");</b></span></div>
<div>
<br /></div>
<div>
Because we were caching the XDocument and for each request calling ToString() this would lead to some untimely deadlocks on the liver servers where requests would run for hours never ending. The only solution was to kill the process and start the web site again.</div>
<div>
<br /></div>
<div>
After a little digging it was clear that the ToString() call being an instance method was to blame. I trudged through the source code for it and found it using several internals to iterate over the nodes to produce the string result. There is also a hint in the documentation for XDocument http://msdn.microsoft.com/en-us/library/system.xml.linq.xdocument%28v=vs.110%29.aspx which states:</div>
<blockquote class="tr_bq">
<span style="font-family: Georgia, Times New Roman, serif;"><i>Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.</i></span></blockquote>
So the solution was to simply cache the resulting ToString() rather than the XDocument, this way there is no further processing required every time a user requests this method.<br />
<br />
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>public ActionResult Feed() {</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> string xml = null;</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> if (Cache["feed"] == null) {</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> XDocument document = new XDocument(...);</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> // Fill the document here...</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> Cache["feed"] = document.ToString();</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> } else {</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> xml = (string) Cache["feed"];</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> }</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> return Content(xml, </b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b> "application/rss+xml");</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>}</b></span></div>
<div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-72859701275777487922014-08-17T16:11:00.000-07:002014-08-17T16:11:30.279-07:00MySQL Entity Framework 6 Include Performance WoesJust a short post today, but after some pretty exhaustive performance testing with Entity Framework 6 and MySQL .NET Connector I am pretty much in the camp that <span style="font-family: Courier New, Courier, monospace;">.Include(...)</span> is only ever detrimental to performance. This is down to the really poor query generation with MySQL and Entity Framework.<div style="text-align: justify;">
</div>
<div>
I have tested so far 8 parts of our current site, all different scopes of query including single record lookups, listings for a directory and more advanced filters to query on specific parameters and in each case adding Includes has increased the query times as opposed to Entity Frameworks lazy loading strategy. This seems really foreign to me but after looking at the SQL generated it is clear why MySQL has a tough time running the queries quickly. In short, stick to Lazy Loading with MySQL until the query generation in Entity Framework improves.</div>
<div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-59442325545448266552013-10-04T02:02:00.000-07:002013-10-04T02:02:32.266-07:00Here Is TerryHaven't posted anything in a while, so here is vector Terry. Done as a design for a website and just fooling around.<br />
<div>
<br />
<div style="text-align: justify;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-Zib54JEFvq4/Uk6D6CrPNAI/AAAAAAAAKR0/yHnw2ph-8Uo/s1600/terry.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="250" src="http://1.bp.blogspot.com/-Zib54JEFvq4/Uk6D6CrPNAI/AAAAAAAAKR0/yHnw2ph-8Uo/s400/terry.png" width="400" /></a></div>
<div>
<br /></div>
</div>
<div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-43969891339488427302013-06-23T17:30:00.000-07:002013-06-25T08:27:19.596-07:00XBMC Ball StreamsA while back I posted about <a href="http://designdotworks.blogspot.co.uk/2012/07/xbmc-hockey-streams.html">XBMC Hockey Streams</a> and the plugin I developed in Python for <a href="http://xbmc.org/">XBMC</a>. Well that project is still ongoing thanks to over 1,500 downloads, but say hello to it's sibling <a href="https://code.google.com/p/xbmc-ball-streams/">XBMC Ball Streams</a> delivering the same experience from <a href="http://www.ballstreams.com/">BallStreams.com</a> if your a fan of basketball and XBMC this is the plugin for you! <div class="separator" style="clear: both; text-align: center;">
<a href="https://xbmc-ball-streams.googlecode.com/svn/trunk/xbmc-ball-streams/icon.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://xbmc-ball-streams.googlecode.com/svn/trunk/xbmc-ball-streams/icon.png" /></a></div>
<div style="text-align: justify;">
</div>
<div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-71572696726488796042013-04-28T20:00:00.000-07:002013-06-25T08:16:40.986-07:00BattleShots Drinking Game Reaches 2K DownloadsHurrah! BattleShots Drinking Game has reached a milestone of 2,000 user downloads. Some of the feedback received has been great, at some point there will be more features to come but thanks to all who have downloaded, played, shared and got merry with BattleShots Drinking game.<div style="text-align: justify;">
</div>
<div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-35680552088552992272013-01-26T18:30:00.000-08:002013-06-25T07:48:36.135-07:00BattleShots Game Architecture<h2 style="background-image: none; border: 0px; font-family: arial, sans-serif; font-size: large; max-width: 700px; padding-left: 0px;">
Introduction</h2>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
The implementation of BattleShots is a little more complex than the standard android practice of creating an XML based layout and attaching events to components. To achieve a customised UI which can match a theme we have control of, we need to take charge of all drawing. This in turn severely limits the use of built in widgets for the android framework as they generally are themed with the OS version or skin in mind. Whilst they do provide theming support such as color, border, background etc. we still cannot achieve the majority of styles we want to expose from our game UI mockups.</div>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
In steps <a href="http://www.opengl.org/" rel="nofollow" style="color: #0000cc;">OpenGL</a> which is the most heavily used 2d/3d graphics API at this time. Android contains a flavour of OpenGL in the form of OpenGL ES 1.0 and OpenGL ES 2.0 (ES stands for Embedded-Systems) which is optimized for mobiles, pda's and game consoles etc.</div>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
From android version 1.0 OpenGL ES 1.0 has been available. As of version 2.2 (froyo) OpenGL ES 2.0 has been available. Both make use of hardware acceleration where devices have separate GPU's which make the API very quick allowing games to achieve 60 FPS rendering (the more frames the better).</div>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
Seeing as we wanted BattleShots to be a rich UI experience we needed to go this route or our UI would be very static.</div>
<h2 style="background-image: none; border: 0px; font-family: arial, sans-serif; font-size: large; max-width: 700px; padding-left: 0px;">
<a href="http://www.blogger.com/blogger.g?blogID=8745825588194554798" name="Game_Architecture"></a>Game Architecture</h2>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
Down to the mechanics of it! It is generally bad practice in any coding circle to perform application logic in the UI thread (unless it's short lived). For example you dont want to start processing a report in the UI thread as you may want the user to see a loading screen with an update on percentage completed. In this instance you would spawn a thread, update the UI every n seconds and wait for completion.</div>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
The BattleShots game architecture follows a similar approach. When the android Activity is initially created we create two objects.</div>
<ul style="font-family: arial, sans-serif; font-size: 13px; max-width: 62em; padding-left: 25px;">
<li style="margin-bottom: 0.3em;">The Updater</li>
<li style="margin-bottom: 0.3em;">The Renderer</li>
</ul>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
<strong>The Updater</strong> handles all game logic such as checking if the user pressed on a square, rotating the target reticle, animating a message on/off screen.</div>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
<strong>The Renderer</strong> handles drawing all objects to the screen.</div>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
<i>We don't want to merge the above into one big routine as the frame rate will drop severely for devices that take a long time in the updating part.</i></div>
<h2 style="background-image: none; border: 0px; font-family: arial, sans-serif; font-size: large; max-width: 700px; padding-left: 0px;">
<a href="http://www.blogger.com/blogger.g?blogID=8745825588194554798" name="Activity_State"></a>Activity State</h2>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
An android Activity has several states. See <a href="http://developer.android.com/reference/android/app/Activity.html" rel="nofollow" style="color: #0000cc;">Android Activity Lifecycle</a> for all its states (there is a good diagram on that page). The ones we are interested in are:</div>
<ul style="font-family: arial, sans-serif; font-size: 13px; max-width: 62em; padding-left: 25px;">
<li style="margin-bottom: 0.3em;">onCreate</li>
<li style="margin-bottom: 0.3em;">onPause</li>
<li style="margin-bottom: 0.3em;">onResume</li>
</ul>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
<strong>onCreate</strong> we create a new OpenGL based view <a href="http://developer.android.com/reference/android/opengl/GLSurfaceView.html" rel="nofollow" style="color: #0000cc;">GLSurfaceView</a> which is similar to a normal xml based view except that it expects us to render everything. Secondly we create <strong>The Renderer</strong> instance referred to above. Finally we create <strong>The Updater</strong> referred to above. <i>Think of this event as the user starting a new game so we have to regenerate all our rendering and game logic.</i></div>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
<strong>onPause</strong> when the user opens a new app, goes to the home screen, receives an incoming call etc. We hijack this event to stop our updater thread from running, this conserves battery life (as we don't have a thread spinning away) and it also means the game doesnt continue updating, effectively pausing it. <i>Basically any time our UI goes away.</i></div>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
<strong>onResume</strong> when the user returns to our app and it is still in memory (not been garbage collected). We hijack this event to resume our updater thread, this retains the state as we are not re-creating the objects over and over again. <i>Basically any time our UI comes back after using it previously.</i></div>
<h2 style="background-image: none; border: 0px; font-family: arial, sans-serif; font-size: large; max-width: 700px; padding-left: 0px;">
<a href="http://www.blogger.com/blogger.g?blogID=8745825588194554798" name="The_Updater_(Update_Loop)"></a>The Updater (Update Loop)</h2>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
The updater (referred to in the game dev world as Update Loop or Game Loop) handles all game logic as previously stated. It has two purposes.</div>
<ul style="font-family: arial, sans-serif; font-size: 13px; max-width: 62em; padding-left: 25px;">
<li style="margin-bottom: 0.3em;">Provide a list of drawing commands to the renderer</li>
<li style="margin-bottom: 0.3em;">Notify the UI thread of events e.g. user fired at a square</li>
</ul>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
The class <tt style="font-family: Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Lucida Console', monospace; font-size: 12px; max-width: 66em;">com.pterodactyl.battleshots.views.BoardGameUpdater</tt> is where you want to look for its implementation. It implements the Runnable interface which means it is intended to be run by a thread at some point. What we actually do in the classes <tt style="font-family: Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Lucida Console', monospace; font-size: 12px; max-width: 66em;">run()</tt> method is force an infinite loop when the thread starts so the updater continually runs. The loop can be broken by setting the <tt style="font-family: Monaco, 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Lucida Console', monospace; font-size: 12px; max-width: 66em;">running</tt> flag to false.</div>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
Within the loop there is code to handle the number of updates per second. We don't need the updater to run at 1,000,000 times a second and the more we can sleep the thread the more battery life and cpu we save. Currently the updater thread runs at a maximum of 30 updates per second as defined by the MAX_UPDATES_PER_SECOND variable in its class. The logic within the loop handles the three following instances.</div>
<ul style="font-family: arial, sans-serif; font-size: 13px; max-width: 62em; padding-left: 25px;">
<li style="margin-bottom: 0.3em;"><strong>Hardware is fast</strong> - sleeps the thread after every loop to meet the 30 updates per second rate)</li>
<li style="margin-bottom: 0.3em;"><strong>Hardware is just right</strong> - continually loops with no sleeping</li>
<li style="margin-bottom: 0.3em;"><strong>Hardware is slow</strong> - it forces several updates without sleeping and without pushing updates onto the render thread as it tries to play catchup</li>
</ul>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
Within a single update loop the class does four things:</div>
<ul style="font-family: arial, sans-serif; font-size: 13px; max-width: 62em; padding-left: 25px;">
<li style="margin-bottom: 0.3em;">Updates Game Objects</li>
<li style="margin-bottom: 0.3em;">Triggers Events</li>
<li style="margin-bottom: 0.3em;">Create Drawing Commands</li>
<li style="margin-bottom: 0.3em;">Send Drawing Commands To Renderer</li>
</ul>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
<strong>Update Game Objects</strong> the game state is updated every cycle. It creates objects for each UI instance e.g. a boat, a square, a user icon, text etc. and updates their state. Some common updates are:</div>
<ul style="font-family: arial, sans-serif; font-size: 13px; max-width: 62em; padding-left: 25px;">
<li style="margin-bottom: 0.3em;">Update the target reticle rotation value (so it spins)</li>
<li style="margin-bottom: 0.3em;">Changes the easing value of a text background (so it animates up and down)</li>
<li style="margin-bottom: 0.3em;">Calculates the size and position of the checkers based on screen width/height</li>
<li style="margin-bottom: 0.3em;">Calculates the size and position text</li>
<li style="margin-bottom: 0.3em;">Calculates the size and position of splashes and explosions</li>
</ul>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
<strong>Triggers Events</strong> calls any event listeners for events in the game such as a user pressing the fire button.</div>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
<strong>Create Drawing Commands</strong> creates a single drawing command (which a class that wraps up OpenGL drawing commands). It creates objects for each UI instance and uses their state from above to position, draw, colourize etc. Some common drawing commands are:</div>
<ul style="font-family: arial, sans-serif; font-size: 13px; max-width: 62em; padding-left: 25px;">
<li style="margin-bottom: 0.3em;">Load a splash texture, position it on screen and draw it</li>
<li style="margin-bottom: 0.3em;">Load a background texture, repeat it across the entire background and blend it with a blue gradient</li>
<li style="margin-bottom: 0.3em;">Draw a checker using native quads and colour them in</li>
</ul>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
<strong>Send Drawing Commands To Renderer</strong> passes the above commands to the renderer. Whilst this sounds easy enough it is one of the main reason's why the renderer and updater are broken into separate components. Because updating and rendering are done independently on separate threads, for us to pass information from the updater to the renderer we need to do it safely by locking the renderer and updating its command list. Locking is quite a slow process so it is only done once at the end of an update cycle.</div>
<h2 style="background-image: none; border: 0px; font-family: arial, sans-serif; font-size: large; max-width: 700px; padding-left: 0px;">
<a href="http://www.blogger.com/blogger.g?blogID=8745825588194554798" name="The_Renderer_(Render_Loop)"></a>The Renderer (Render Loop)</h2>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
The renderer is quite dumb. For each rendering cycle (an infinite loop controlled by OpenGL) it locks the Drawing Command list, iterates through and draws them to the screen, finally unlocking the list. This allows for the UI to be drawn very quickly as very little logic (apart from translating coordinates or scaling) is done on this thread. This is how we achieve a high FPS.</div>
<h2 style="background-image: none; border: 0px; font-family: arial, sans-serif; font-size: large; max-width: 700px; padding-left: 0px;">
<a href="http://www.blogger.com/blogger.g?blogID=8745825588194554798" name="The_Update_Loop_+_Render_Loop_=_Game_On"></a>The Update Loop + Render Loop = Game On</h2>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
I have put together a diagram below to try to explain the above process visually. Hope it helps.</div>
<div style="font-family: arial, sans-serif; font-size: 13px; line-height: 1.25em; max-width: 64em;">
<img src="http://turquoise-pterodactyl.googlecode.com/svn/wiki/resources/BattleShots%20Game%20Architecture.png" style="border: 0px; max-width: 100%;" /></div>
<div style="text-align: justify;">
</div>
<div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-9034186877187078692013-01-05T07:00:00.000-08:002013-06-25T08:13:31.454-07:00BattleShots Drinking GameBeen quiet recently and as such I usually pick up a project or two I am interested in. So here comes <a href="https://play.google.com/store/apps/details?id=com.pterodactyl.battleshots">BattleShips Drinking Game</a> for the Android Market. The game concept is around a physical drinking game we have played on occasion so what could be better than sharing this with other people and developing and Android App in the process.<br />
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/fra5PXW3N9zLKYAOD2snHcWqxi0a_L6-rbi7fyi1PLEtMYAGfPVFoAEyam1wwLjpELEP=w705" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="195" src="http://2.bp.blogspot.com/fra5PXW3N9zLKYAOD2snHcWqxi0a_L6-rbi7fyi1PLEtMYAGfPVFoAEyam1wwLjpELEP=w705" width="400" /></a></div>
<div>
<br />
<div>
<div style="text-align: justify;">
</div>
<div>
I have worked on the Android platform previously so it was nice to work on a game which some great visuals and interaction. I designed and developed the user interface, user experience, sprites and assets used in the game and got to grips with OpenGL ES 2.0 framework for hardware rendering on the Android. Although the game is two-dimensional it was nice to see the full 3D architecture of OpenGL and how I could use this in future projects.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/KUV0Vvnm0blF-fcVnkdjvK7HyNaWtUuBH3_epBZbj44PZ2I5tazJFU7lGM5g0F6cEiw" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="http://3.bp.blogspot.com/KUV0Vvnm0blF-fcVnkdjvK7HyNaWtUuBH3_epBZbj44PZ2I5tazJFU7lGM5g0F6cEiw" width="125" /></a>
<a href="http://2.bp.blogspot.com/xWM7EM1j-ETCocHA_oRCQATx600IR59fSiMqzrZrbpXxmBC4JCa2SfoNucheoNEThrc" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="http://2.bp.blogspot.com/xWM7EM1j-ETCocHA_oRCQATx600IR59fSiMqzrZrbpXxmBC4JCa2SfoNucheoNEThrc" width="125" /></a></div>
<div>
<br /></div>
<div>
The game makes use of several custom shaders for rendering performance and some real nice visuals. Font's appeared to be the big issue on the Android so I went down the route of implementing a Bitmap Fonts helper library with a Glyph mapping so that spacing could be managed between characters. Overall I think my implementation works really nicely and the text stands out as a key part of the Game. To see just how I implemented Bitmap Fonts in OpenGL ES 2.0 take a look at the source at <a href="https://code.google.com/p/turquoise-pterodactyl/source/browse/#svn%2Ftrunk%2Fprojects%2Fbattleshots%2Fsrc%2Fcom%2Fpterodactyl%2Fbattleshots%2Fshared%2Ffonts">BattleShots Bitmap Fonts Source</a> the source is well documented so it should be easy to traverse. <a href="https://code.google.com/p/turquoise-pterodactyl/source/browse/trunk/projects/battleshots/res/raw/bitmapfonts.xml">The bitmapfonts.xml file can be found there too</a>.</div>
<div>
<br /></div>
<div>
Another key element of the design was that I wanted to make the game performance a crucial factor. I felt this would be handy in future projects so BattleShots is quite heavily optimized (perhaps overly so). This is discussed in more detail in a separate article I wrote on <a href="http://designdotworks.blogspot.co.uk/2013/01/battleshots-game-architecture.html">BattleShots Game Architecture</a> please go take a look.<br />
<br />
Finally came the marketing side, so I quickly put together a site which advertises <a href="http://battleshots-app.com/">BattleShots Drinking Game</a>, I think it does a good job of conveying the BattleShots message.<br />
<br />
Working with the Android framework has been a nice change again as well as following test driven development practices throughout the development of the game, this really made it easy to quickly get iterative builds up and running for users to see.<br />
<br />
Be sure to go download the App and play with a few mates!</div>
</div>
</div>
<div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-44664938551065385382012-07-01T10:00:00.000-07:002013-06-25T07:23:49.765-07:00XBMC Hockey StreamsSo I'm a hockey fan, that is "Ice" Hockey. I also love the awesome <a href="http://xbmc.org/">XBMC</a> project. So what better use of my time would there be than building a plugin to view hockey streams on the XBMC? In steps <a href="https://code.google.com/p/xbmc-hockey-streams/">XBMC Hockey Streams</a> a plugin developed by me to watch <a href="http://www6.hockeystreams.com/">hockeystreams.com</a> content via the XBMC. The plugin is built using Python and the XBMC libraries to access the hockeystreams API for content. I should point out I am not affiliated or paid by hockeystreams.com this is purely a plugin project that uses their content. As such it's seen high demand by the hockeystreams community and I hope to continue to maintain this project into the future, check out the project page on <a href="https://code.google.com/p/xbmc-hockey-streams/">https://code.google.com/p/xbmc-hockey-streams/</a> now.<div style="text-align: justify;">
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://xbmc-hockey-streams.googlecode.com/svn/wiki/resources/start.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="193" src="http://xbmc-hockey-streams.googlecode.com/svn/wiki/resources/start.jpg" width="320" /></a></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://xbmc-hockey-streams.googlecode.com/svn/wiki/resources/browse.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="193" src="http://xbmc-hockey-streams.googlecode.com/svn/wiki/resources/browse.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://xbmc-hockey-streams.googlecode.com/svn/wiki/resources/team.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="193" src="http://xbmc-hockey-streams.googlecode.com/svn/wiki/resources/team.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://xbmc-hockey-streams.googlecode.com/svn/wiki/resources/enjoy.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="193" src="http://xbmc-hockey-streams.googlecode.com/svn/wiki/resources/enjoy.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-64290100272415100532012-03-14T13:00:00.000-07:002013-06-25T07:11:18.203-07:00Do It Yourself NASI recently set about piecing together my home network from scratch due to moving into a new home, with this came a short-sighted purchase, the Synology DS211j. The intent of this article is not to bad-mouth this device, but point out that it was not fit for "my" purpose and supposedly many others in my situation.<br />
<div style="text-align: justify;">
</div>
<div>
<br /></div>
<div>
I have a lot of media, maybe not the most but still plenty consisting of photo's, home videos, music, TV shows and movies. Initially I managed to cram most of this onto the DS211j which was setup with 4TB of space as well as nightly backups to a seperate disk. But with the recent decision to move every dvd and bluray I own off their shelves and onto the NAS I quickly ran out of space.</div>
<div>
<br /></div>
<div>
At £140 (time of writing) the Synology DS211j is great little work horse for those who don't want to get their hands dirty. But seeing as I didn't mind building a system myself I figured I could greatly reduce this price, especially when you consider moving to pre-built NAS devices with more drive capacity quickly inflates this price into its £1000's (before you even add hard drives).</div>
<div>
<br /></div>
<div>
So my task was simple, I would build my own with the following in mind...</div>
<div>
<ol>
<li><b>Components must be cheap</b> (not the cheapest but were not talking about a gaming PC here!)</li>
<li>It <b>must be low power consuming</b>, most pre-built NAS quote very low running wattage and I don't want to lose any saving I made shelling out money on the electricity bill</li>
<li>Support for <b>at least 8 hard drives</b> giving me a total of 24TB</li>
<li>Be<b> able to perform backups</b></li>
<li>Provide some level of <b>redundancy for hard drives</b></li>
</ol>
<div>
So with the above leading the way I set about picking a hardware/software combination that would theoretically be fit for purpose. The following is what I chose for the build along with reasoning...</div>
</div>
<div>
<ol>
<li><a href="http://www.ebuyer.com/108280-casecom-kb-7760-black-atx-midi-tower-case-no-psu-no-case-kb-7760bk">Casecom KB-7760 ATX Case £12.51 from Ebuyer</a></li>
<ul>
<li>11 potential hard drive bays</li>
<li>Did not need a fancy looking case as it would be tucked away</li>
</ul>
<li><a href="http://www.europc.co.uk/at5nm10t-i.html?utm_source=googlebase&utm_medium=CSE&utm_campaign=europcfeeds">Asus AT5NM10T-I £70.08 from Europc</a> with 4% cashback through quidco</li>
<ul>
<li>Low power consuming motherboard <a href="http://www.asus.com/Motherboards/Intel_CPU_on_Board/AT5NM10TI/">specs here</a></li>
<li><a href="http://ark.intel.com/products/49490">Intel Atom D525 processor</a> built in, low power and ample raw processing power for a NAS</li>
<li>4 SATA II ports</li>
<li>Gigabit Lan</li>
<li>PCIe expansion port</li>
</ul>
<li><a href="http://www.ebuyer.com/267860-huntkey-jumper-300w-psu-80plus-gold-certified-jumper-300g">Huntkey Jumper 80+ Gold Certified 300w PSU £43.38 from ebuyer</a></li>
<ul>
<li>I was considering a <a href="http://linitx.com/product/10916">12v 120w PicoPSU</a> but at boot when all the discs spin up there was potential that the little PSU wouldn't be able to power 8 drives and a motherboard with processor.</li>
<li>Don't go cheap with a PSU you get the majority of your energy saving and efficiency from here</li>
</ul>
<li><a href="http://www.crucial.com/uk/store/mpartspecs.aspx?mtbpoid=374A1955A5CA7304">2GB SODIMM DDR3 Ram £10.79 from Crucial</a> with 7% cashback through quidco</li>
<li><a href="http://www.overstock.com/Electronics/SYBA-SY-PCI40010-PCI-Serial-ATA-II-RAID-Controller-Card/4381431/product.html?cid=133635">SATA II 4 Port PCIe Card £23.99 from ebay</a></li>
<ul>
<li>Add's 4 SATA II ports to my build albeit capped at the maximum throughput allowed by the PCIe port (500MB/s), still with this limitation you would be hard pressed to max out the PCIe ports bandwidth over a network, this only really becomes an issue transferring between drives on the same machine but since this is "Network" Attached Storage it is a non-issue.</li>
<li>Didn't need any hardware raid support (would leave this to software) otherwise buy something more expensive</li>
</ul>
<li><a href="http://www.dabs.com/products/verbatim-2gb-pinstripe-usb-drive-black-71X5.html?src=3">2GB Pen Drive £3.99 from dabs</a></li>
<ul>
<li>To hold the operating system</li>
</ul>
<li><a href="http://www.freenas.org/">FreeNAS</a> operating system</li>
<ul>
<li>Provides a web based GUI</li>
<li>Support for ZFS file system which includes snapshots, end-to-end checksumming and recovery/redundancy when pooled.</li>
<li>Allows me to use <a href="http://en.wikipedia.org/wiki/RAID-Z#RAID-Z">software RAIDZ</a> so it is independent of the hardware making future upgrades easier.</li>
<li>Large community for support</li>
<li>Has been around a while and is mature</li>
</ul>
</ol>
<div>
<b>Making a grand total of £164.74 for a potential 8 bay NAS!</b> A quick Google tells me I would be lucky to get the low end models that support 8 bays for under £500.00 and these have severely reduced hardware specifications meaning you forfeit some functionality such as software raid, snapshots etc. So time to get down and dirty with the build, the following is a series of snapshots taken during the process, if you need help piecing a computer together from scratch I suggest <a href="http://www.google.co.uk/?q=how%20to%20build%20a%20pc">Google is your friend</a>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-0yYDDXIvT_E/Tw6rAuNHryI/AAAAAAAAA-8/dwlsFxG2PRo/s1600/IMG_20120111_132759.jpg" imageanchor="1"><img border="0" height="150" src="http://2.bp.blogspot.com/-0yYDDXIvT_E/Tw6rAuNHryI/AAAAAAAAA-8/dwlsFxG2PRo/s200/IMG_20120111_132759.jpg" width="200" /></a>
<a href="http://3.bp.blogspot.com/-fJH1b9Hq1Gg/Tw6rBR3PowI/AAAAAAAAA_A/FpgwckuWty0/s1600/IMG_20120111_132811.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="150" src="http://3.bp.blogspot.com/-fJH1b9Hq1Gg/Tw6rBR3PowI/AAAAAAAAA_A/FpgwckuWty0/s200/IMG_20120111_132811.jpg" width="200" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-nwG1GJYpZRI/Tw6rB0nAwGI/AAAAAAAAA_M/rR2lwoWFCTI/s1600/IMG_20120111_132919.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="http://1.bp.blogspot.com/-nwG1GJYpZRI/Tw6rB0nAwGI/AAAAAAAAA_M/rR2lwoWFCTI/s200/IMG_20120111_132919.jpg" width="150" /></a><a href="http://2.bp.blogspot.com/-_zXNPcEDHl4/Tw6rDQ48ltI/AAAAAAAAA_c/2jgMYHFWJQk/s1600/IMG_20120111_133256.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="http://2.bp.blogspot.com/-_zXNPcEDHl4/Tw6rDQ48ltI/AAAAAAAAA_c/2jgMYHFWJQk/s200/IMG_20120111_133256.jpg" width="150" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-2gmMErigS8c/Tw6rE6mnp8I/AAAAAAAAA_g/XcSF2kcbbjw/s1600/IMG_20120111_133659.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="http://3.bp.blogspot.com/-2gmMErigS8c/Tw6rE6mnp8I/AAAAAAAAA_g/XcSF2kcbbjw/s200/IMG_20120111_133659.jpg" width="150" /></a><a href="http://1.bp.blogspot.com/-Y1cxFQtLmfw/Tw6rHTaAIwI/AAAAAAAABAA/hwuL6jYdOZU/s1600/IMG_20120111_135118.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="http://1.bp.blogspot.com/-Y1cxFQtLmfw/Tw6rHTaAIwI/AAAAAAAABAA/hwuL6jYdOZU/s200/IMG_20120111_135118.jpg" width="150" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-GPdSgTWFCpc/Tw6rIH1BkqI/AAAAAAAABAI/ZJa2GEYpgDQ/s1600/IMG_20120111_135123.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="http://4.bp.blogspot.com/-GPdSgTWFCpc/Tw6rIH1BkqI/AAAAAAAABAI/ZJa2GEYpgDQ/s200/IMG_20120111_135123.jpg" width="150" /></a><a href="http://1.bp.blogspot.com/-tfh1PmflvTE/Tw6rIwtQqXI/AAAAAAAABAQ/wcqErwQhgP0/s1600/IMG_20120111_135427.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="http://1.bp.blogspot.com/-tfh1PmflvTE/Tw6rIwtQqXI/AAAAAAAABAQ/wcqErwQhgP0/s200/IMG_20120111_135427.jpg" width="150" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-mw0kMr6Txpo/Tw6rJncjUtI/AAAAAAAABAY/a2TzW2oQsDQ/s1600/IMG_20120111_141127.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="http://4.bp.blogspot.com/-mw0kMr6Txpo/Tw6rJncjUtI/AAAAAAAABAY/a2TzW2oQsDQ/s200/IMG_20120111_141127.jpg" width="150" /></a><a href="http://2.bp.blogspot.com/-bscbAwaIOxk/Tw6rKXVTb_I/AAAAAAAABAg/GuvdrNc9QJM/s1600/IMG_20120111_141136.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="150" src="http://2.bp.blogspot.com/-bscbAwaIOxk/Tw6rKXVTb_I/AAAAAAAABAg/GuvdrNc9QJM/s200/IMG_20120111_141136.jpg" width="200" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-ISfNDz886Rs/Tw6rL8SxJQI/AAAAAAAABAw/JA2eVV-a3fc/s1600/IMG_20120111_141146.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="150" src="http://4.bp.blogspot.com/-ISfNDz886Rs/Tw6rL8SxJQI/AAAAAAAABAw/JA2eVV-a3fc/s200/IMG_20120111_141146.jpg" width="200" /></a><a href="http://1.bp.blogspot.com/-W9VH7os8uPg/Tw6rMmkKZLI/AAAAAAAABA8/wlBQPTwXoTE/s1600/IMG_20120111_170705.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="http://1.bp.blogspot.com/-W9VH7os8uPg/Tw6rMmkKZLI/AAAAAAAABA8/wlBQPTwXoTE/s200/IMG_20120111_170705.jpg" width="150" /></a></div>
<br />
<br />
So with the build ready I needed to set-up FreeNAS,<a href="http://doc.freenas.org/index.php/Installing_from_the_Image"> following the instructions on their wiki I managed to install FreeNAS to a USB drive</a> and boot into the FreeNAS console. Everything appeared to just work, it configured all my network settings automatically (I was connected to my network via Ethernet) and told me my device was available at 192.168.x.x. So using another PC I logged into the web GUI for FreeNAS and again after<a href="http://doc.freenas.org/index.php/Volumes"> following more instructions on their wiki I had assigned a volume to my hard disk, setup a dataset for this volume</a> and<a href="http://doc.freenas.org/index.php/CIFS_Shares"> shared it with my windows clients</a>. All was well.<br />
<br />
Now for testing. A speed test was first on my list, I used the<a href="http://www.intel.com/products/server/storage/NAS_Perf_Toolkit.htm"> intel nas performance toolkit</a> to measure throughput, to be completely honest this program is overkill for what information I wanted but it does the trick. The following is breakdown of my initial tests when compared to the DS211j that I own.<br />
<br />
<table>
<thead>
<tr>
<th>Test Name</th>
<th>DS211j</th>
<th>DIYNAS</th>
</tr>
</thead>
<tbody>
<tr>
<td>HD Video Playback</td>
<td>Throughput: 32MB/s</td>
<td>Throughput: 40MB/s</td>
</tr>
<tr>
<td>HD Video Playback x2</td>
<td>Throughput: 32MB/s</td>
<td>Throughput: 40MB/s</td>
</tr>
<tr>
<td>HD Video Playback x4</td>
<td>Throughput: 30MB/s</td>
<td>Throughput: 36MB/s</td>
</tr>
<tr>
<td>HD Video Playback and HD Video Record</td>
<td>Throughput: 27MB/s</td>
<td>Throughput: 28MB/s</td>
</tr>
<tr>
<td>File Copy To NAS</td>
<td>Throughput: 18MB/s</td>
<td>Throughput: 30MB/s</td>
</tr>
<tr>
<td>File Copy From NAS</td>
<td>Throughput: 32MB/s</td>
<td>Throughput: 42MB/s</td>
</tr>
<tr>
<td>Directory Copy From NAS</td>
<td>Throughput: 28MB/s</td>
<td>Throughput: 37MB/s</td>
</tr>
<tr>
<td>Directory Copy To NAS</td>
<td>Throughput: 16MB/s</td>
<td>Throughput: 26MB/s</td>
</tr>
</tbody>
</table>
</div>
</div>
<div>
To say I was a little disappointed with these first results is true but never fear. I figured there may be some "tweaking" involved to get the most out of FreeNAS (it is designed to work on hundreds of pieces of hardware). So I had a play around with some of the kernel settings relating to buffers and zfs options and came to a trial-and-error solution that works for my hardware.</div>
<div>
<br /></div>
<div>
<a href="http://doc.freenas.org/index.php/Loaders">Adding the following settings to the loaders</a> part of the FreeNAS GUI worked wonders.</div>
<div>
<br /></div>
<div>
<span style="background-color: #d9ead3; font-family: 'Courier New', Courier, monospace;">vm.kmem_size 1</span></div>
<div>
<span style="background-color: #d9ead3; font-family: 'Courier New', Courier, monospace;">vm.kmem_size_max 1</span></div>
<div>
<span style="background-color: #d9ead3; font-family: 'Courier New', Courier, monospace;">vfs.zfs.prefetch_disable 0</span></div>
<div>
<br /></div>
<div>
And the new results following this change?<br />
<br /></div>
<table>
<thead>
<tr>
<th>Test Name</th>
<th>DS211j</th>
<th>DIYNAS</th>
</tr>
</thead>
<tbody>
<tr>
<td>HD Video Playback</td>
<td>Throughput: 30MB/s</td>
<td>Throughput: 65MB/s</td>
</tr>
<tr>
<td>HD Video Playback x2</td>
<td>Throughput: 30MB/s</td>
<td>Throughput: 45MB/s</td>
</tr>
<tr>
<td>HD Video Playback x4</td>
<td>Throughput: 30MB/s</td>
<td>Throughput: 41MB/s</td>
</tr>
<tr>
<td>HD Video Playback and HD Video Record</td>
<td>Throughput: 30MB/s</td>
<td>Throughput: 36MB/s</td>
</tr>
<tr>
<td>File Copy To NAS</td>
<td>Throughput: 30MB/s</td>
<td>Throughput: 38MB/s</td>
</tr>
<tr>
<td>File Copy From NAS</td>
<td>Throughput: 30MB/s</td>
<td>Throughput: 66MB/s</td>
</tr>
<tr>
<td>Directory Copy From NAS</td>
<td>Throughput: 30MB/s</td>
<td>Throughput: 61MB/s</td>
</tr>
<tr>
<td>Directory Copy To NAS</td>
<td>Throughput: 30MB/s</td>
<td>Throughput: 32MB/s</td>
</tr>
</tbody>
</table>
<br />This made a huge difference to my results and as a result I get much snappier file transfers. In summary you can build a cheap NAS for your storage needs, I feel I have the FreeNAS bug now so there may be more DIY builds coming soon!<div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-17578870541953654892011-10-06T05:44:00.000-07:002011-10-06T05:44:39.514-07:00Risk, It's All About The Magic, ShazamJust my thought of the day after playing Risk with a group of friends in a board game extravaganza of an evening. What really are the odds to consider when attacking someone? Well, in any given 1 on 1 there are 36 combinations that can be rolled e.g. one die for each player. This results in a win percentage for the defender an average 58.3% of the time with a remaining 41.7% chance of a win for the aggressor.<div>
<br /><div style="text-align: justify;">
</div>
<div>
So when considering that 15 out of 36 attempts by the attacker will be successful and 21 will be won by the defender we need to balance the odds. To get to our magic 50% we need 18 of our 36 rolls to be winners! Thus we need 3 more rolls than we are currently achieving, 3/15 gives us the extra number of rolls we require to win, a nice 0.2 which means I need 1.2 dice to be on equal terms with the defender.</div>
<div>
<br /></div>
<div>
Aha "you can't have 0.2 of a dice" I hear you say, which sadly is true so all in all I've wasted 2 minutes typing this up! Stick to the rule of two to one when attacking and you'll be dandy although the above doesn't account for SOD's law which appears to apply to me in this game more than anyone else. Damn you Mike-"Genghis"-Croft!</div>
</div>
<div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-28225514971451844592011-09-05T07:55:00.000-07:002011-09-05T07:55:32.252-07:00Love Money Management Even For Nationwide<div>
Two blog posts in one day! You might be thinking what the heck?!?</div>
<div>
<br /></div>
<a href="http://www.lovemoney.com/">Love Money</a> have just released an online service to budget and manage your finances. Due to the nightmare that is the IFA in the UK automation for these kind of services is pretty terrible but they have somehow done it. Genius! I can now even connect to my Nationwide account without having to upload OFX's, CSV's and the like.<div style="text-align: justify;">
</div>
<div>
<br /></div>
<div>
It really is looking promising, make sure you give this find of the day a go!</div>
<div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-63875645378772985652011-09-05T02:15:00.000-07:002011-09-05T02:15:50.146-07:00GWT Dialog Box With Close ButtonDue to the internals of the <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.3/com/google/gwt/user/client/ui/DialogBox.html">GWT Dialog Box</a>, extending it to add support for a close button can be a little tricky if you dont understand what your looking for. Alas below demonstrates adding an anchor to the caption area of the dialog, all that's left to do is for you to style the anchor. Happy GWT'ing.<br />
<div style="text-align: justify;">
</div>
<div>
<br />
Some people will moan that adding a library such as <a href="http://code.google.com/p/smartgwt/">Smart GWT</a> will add this functionality. Whilst true it also adds a boat load of library code you may never need. Keep compile times short and sweet and use the minimum amount necessary.</div>
<div>
<br /></div>
<pre class="java" name="code">// Create anchor we want to accept click events
final Anchor myAnchor = new Anchor("My Anchor");
// Add handler to anchor
myAnchor.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
Window.alert("Anchor was clicked");
}
});
// Create dialog
final DialogBox myDialog = new DialogBox();
myDialog.setText("My Dialog");
// Get caption element
final HTML caption = ((HTML)myDialog.getCaption());
// Add anchor to caption
caption.getElement().appendChild(myAnchor.getElement());
// Add click handler to caption
caption.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
// Get x,y caption click relative to the anchor
final int x = event.getRelativeX(myAnchor.getElement());
final int y = event.getRelativeY(myAnchor.getElement());
// Check click was within bounds of anchor
if(x >= 0 && y >= 0 &&
x <= myAnchor.getOffsetWidth() &&
y <= myAnchor.getOffsetHeight()) {
// Raise event on anchor
myAnchor.fireEvent(event);
}
}
});
// Show the dialog
myDialog.show();
</pre>
<div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-83926395105679134592010-12-23T04:57:00.000-08:002010-12-23T04:57:03.096-08:00Craig and Charlotte's 100 things to do in Britain - #14 Iron Bridge, Shropshire<div style="text-align: justify;">The birthplace of industry! And its not too bad a place to visit too. With plenty of museums (although you have to pay) to visit and walking trails through the gorge and the surrounding greenery you can definitely make a day of this. Make sure you turn up early though as it is a nightmare to traverse the steep narrow roads whilst trying to find a parking space.<br />
</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">Set in a quaint town/village (although its hard to believe this place exists right next to the M54) Iron Bridge has all the niceties you expect from small tea shops, hand made toy stores and useless garden ornaments! You might just forget that the bridge itself is pretty impressive. Do yourself a favour, take a picnic and make a day of it by getting lost in the woodland.<br />
</div><br />
<div style="text-align: left;"><table align="center"><tbody>
<tr><td><a href="http://lh4.ggpht.com/_ZNPMZwry3vA/TRNDnPcceoI/AAAAAAAAALM/iOsPdBRwkAA/s800/41141_468996416322_568681322_6924978_3741226_n.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" src="http://lh4.ggpht.com/_ZNPMZwry3vA/TRNDnPcceoI/AAAAAAAAALM/iOsPdBRwkAA/s144/41141_468996416322_568681322_6924978_3741226_n.jpg" style="cursor: hand; cursor: pointer; display: block; height: 100px; margin: 0px auto 10px; text-align: center;" /></a></td><td><a href="http://lh4.ggpht.com/_ZNPMZwry3vA/TRNDnL30RbI/AAAAAAAAALQ/vFXb_2mE7fk/s800/41036_468998056322_568681322_6925091_2134308_n.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" src="http://lh4.ggpht.com/_ZNPMZwry3vA/TRNDnL30RbI/AAAAAAAAALQ/vFXb_2mE7fk/s144/41036_468998056322_568681322_6925091_2134308_n.jpg" style="cursor: hand; cursor: pointer; display: block; height: 100px; margin: 0px auto 10px; text-align: center;" /></a></td><td><a href="http://lh5.ggpht.com/_ZNPMZwry3vA/TRNDnQTMuPI/AAAAAAAAALU/cCuL4E6C0Z8/s800/47789_468996636322_568681322_6924987_2248129_n.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" style="text-decoration: none;"><img alt="" border="0" src="http://lh5.ggpht.com/_ZNPMZwry3vA/TRNDnQTMuPI/AAAAAAAAALU/cCuL4E6C0Z8/s144/47789_468996636322_568681322_6924987_2248129_n.jpg" style="cursor: hand; cursor: pointer; display: block; height: 100px; margin: 0px auto 10px; text-align: center;" /></a></td></tr>
</tbody></table></div><div style="text-align: justify;"><table><tbody>
<tr><td>Rating: </td><td><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /></td></tr>
</tbody></table></div><div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-44807004060066783362010-09-01T01:22:00.000-07:002010-09-01T01:26:30.236-07:00Craig and Charlotte's 100 things to do in Britain - #16 Caernarvon Castle<div style="text-align: justify;">A great little drive towards the back end of beyond 'Bangor' in North Wales will see you come across the mighty castle of Caernarvon. An awesomely English built slap in the face to the welsh all them years ago proving that we indeed were superior :P (until it got sacked by the welsh).</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">The castle itself houses a small town with coffee shops, cake stores a market and your classic 'bits n bobs' shops. The castle is kept in fabulous condition and is a real charm to walk round, through and under. A small entry fee is well worth the price with museum's and staff on hand to point out just how magnificent it really all is. A small wharf-side also is of interest for those who like a bit of a walk across to the lookout post on the opposite hillside.</div><div style="text-align: justify;"><br />
</div><div style="text-align: justify;">Along with the drive this is a great scenic day out, and with a few coastal towns locally to the castle its easy to spend the entire day (neigh weekend!) in the area. Cheap and Cheerful, just how I like it!</div><br />
<div style="text-align: left;"><table align="center"><tbody>
<tr><td><a href="http://lh6.ggpht.com/_ZNPMZwry3vA/TH4MYk51-zI/AAAAAAAAAKY/6AAVmhcPfIo/s800/28460_427092781322_568681322_5815050_5525478_n.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5401381720851721058" src="http://lh6.ggpht.com/_ZNPMZwry3vA/TH4MYk51-zI/AAAAAAAAAKY/6AAVmhcPfIo/s144/28460_427092781322_568681322_5815050_5525478_n.jpg" style="cursor: hand; cursor: pointer; display: block; height: 100px; margin: 0px auto 10px; text-align: center;" /></a></td><td><a href="http://lh6.ggpht.com/_ZNPMZwry3vA/TH4MYs3pGjI/AAAAAAAAAKc/IbK9-LpZlFE/s800/28460_427094576322_568681322_5815092_2302987_n.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5401381713973334626" src="http://lh6.ggpht.com/_ZNPMZwry3vA/TH4MYs3pGjI/AAAAAAAAAKc/IbK9-LpZlFE/s144/28460_427094576322_568681322_5815092_2302987_n.jpg" style="cursor: hand; cursor: pointer; display: block; height: 100px; margin: 0px auto 10px; text-align: center;" /></a></td><td><a href="http://lh3.ggpht.com/_ZNPMZwry3vA/TH4MYxwVkpI/AAAAAAAAAKg/S9AB02sKSfc/s800/28460_427096041322_568681322_5815153_4906743_n.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" style="text-decoration: none;"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5401381711999028498" src="http://lh3.ggpht.com/_ZNPMZwry3vA/TH4MYxwVkpI/AAAAAAAAAKg/S9AB02sKSfc/s144/28460_427096041322_568681322_5815153_4906743_n.jpg" style="cursor: hand; cursor: pointer; display: block; height: 100px; margin: 0px auto 10px; text-align: center;" /></a></td></tr>
</tbody></table></div><div style="text-align: justify;"><table><tbody>
<tr><td>Rating: </td><td><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /></td></tr>
</tbody></table></div><div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-34519558870514507542010-07-22T08:40:00.000-07:002010-07-22T08:40:28.932-07:00Money Off MyProtein.co.uk Order With Referral Code MP253762Hey, I'm a shameless self-promoter here is the referral code for you all to get money off your first order at <a href="http://www.myprotein.co.uk/">www.myprotein.co.uk</a> MP253762<br />
<div style="text-align: justify;"></div><div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-26049853936930381592010-04-30T08:50:00.000-07:002010-04-30T08:50:29.497-07:00The Red Bull (Light) Challenge (Success)Hey, i'm not dead! Week over and a steady one can of year old Red Bull light every day with no side effects apart from birthing a small dwarf after the final can. Everyone can feel safe in the knowledge that drinking a year old can of the stuff will not kill you, challenge over!<div><div style="text-align: justify;"></div></div><div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-38049287651201096722010-04-29T04:53:00.000-07:002010-04-29T04:55:47.942-07:00Craig and Charlotte's 100 things to do in Britain - #100 Bond Street, London<div style="text-align: justify;">Back again for the second part of our London trip, i'm afraid it's a bit of a poor show picture wise as the security donned in fitted suits were warding off the bums and japanese tourists. <br />
<br />
It's always a great feeling knowing that as you stroll past the many windows you will be coming out of the street with all your money in tact (this I made CLEAR to Charlotte before-hand :D). I do really feel sorry for the number of blokes wincing as the assistant told them how many times they will need to re-mortgage their homes to afford the 'rock' their wives are ogling.<br />
<br />
On the whole Bond Street is great to visit if only to see all the amazing amount of crud a woman can attach to herself.</div><br />
<div style="text-align: left;"><table align="center"><tbody>
<tr><td><a href="http://lh5.ggpht.com/_ZNPMZwry3vA/S9lorVy2RPI/AAAAAAAAAGk/KpJCT3_mVj0/s800/16335_222969776322_568681322_4608111_5616255_n.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5401381720851721058" src="http://lh5.ggpht.com/_ZNPMZwry3vA/S9lorVy2RPI/AAAAAAAAAGk/KpJCT3_mVj0/s800/16335_222969776322_568681322_4608111_5616255_n.jpg" style="display: block; height: 100px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center;" /></a></td><td><a href="http://lh3.ggpht.com/_ZNPMZwry3vA/S9lorqSLWkI/AAAAAAAAAGo/-M9OEhvB_CE/s800/16335_222974236322_568681322_4608134_7591265_n.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5401381713973334626" src="http://lh3.ggpht.com/_ZNPMZwry3vA/S9lorqSLWkI/AAAAAAAAAGo/-M9OEhvB_CE/s800/16335_222974236322_568681322_4608134_7591265_n.jpg" style="cursor: hand; cursor: pointer; display: block; height: 100px; margin: 0px auto 10px; text-align: center;" /></a></td><td><a href="http://lh3.ggpht.com/_ZNPMZwry3vA/S9lori_rocI/AAAAAAAAAGs/tB_-b9vmQZU/s800/16335_222974266322_568681322_4608136_2575566_n.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" style="text-decoration: none;"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5401381711999028498" src="http://lh3.ggpht.com/_ZNPMZwry3vA/S9lori_rocI/AAAAAAAAAGs/tB_-b9vmQZU/s800/16335_222974266322_568681322_4608136_2575566_n.jpg" style="cursor: hand; cursor: pointer; display: block; height: 100px; margin: 0px auto 10px; text-align: center;" /></a></td></tr>
</tbody></table></div><br />
<div style="text-align: justify;"><table><tbody>
<tr><td>Rating: </td><td><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /></td></tr>
</tbody></table></div><div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-7087112018392625592010-04-23T05:09:00.000-07:002010-04-23T15:33:53.520-07:00The Red Bull (Light) ChallengeToday started an epic battle between out of date Red Bull (12 months) and my body. Fellow employees winced at the idea of drinking the stuff shouting from the hills "that stuff will kill you!" and "<i>best before</i> mean's it is out of date dumbass!" The term <i>best before</i> is a conspiracy one which the Red Bull challenge will topple (obviously being the first person to do this...)<br />
<div><br />
</div><div>If I don't post back within a month then take it that I officially am dead of RB poisoning or have felt the need to end my life from Mikes pathetic attempts to <i>'Lay the Hammer'</i> on me.<br />
<div style="text-align: justify;"></div></div><div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-86107018807988033082010-03-01T04:04:00.000-08:002010-03-01T04:04:55.605-08:00Craig and Charlotte's 100 things to do in Britain - #21 The London Eye<div style="text-align: justify;">Howdy, doody! Haven't been keeping on top of these for a while but your in for a treat (well... maybe if you like big wheels!) as me and Chappers headed down to "The Hub" of Britain for the weekend aka. London.<br />
<br />
First up on our trip was the gargantuan London Eye, and it truly is a huge beast! Besides from putting Charlotte off just from the height she also wasn't feeling too hot which probably is not the best combination. I was impressed with the wait time being only 20 minutes as the last thing we wanted to do on a cold winters night was spend 3 hours queuing!<br />
<br />
Once on and moving you get some great views of the city which are only bettered when viewing it at night, London lights up amazingly well and is definitely a must do in the capital, if not for the ride but also for being the only place where you can really see all the main sites from one spot. Parliament, Tower of London, Tower Bridge, Westminster, Canary Wharf... You name it and you can see it.</div><br />
<div style="text-align: left;"><table align="center"><tbody>
<tr><td><a href="http://lh4.ggpht.com/_ZNPMZwry3vA/S4urSTzvvPI/AAAAAAAAAGA/tx2BI0A7WVM/s800/16335_222925421322_568681322_4607953_6548145_n.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5401381720851721058" src="http://lh4.ggpht.com/_ZNPMZwry3vA/S4urSTzvvPI/AAAAAAAAAGA/tx2BI0A7WVM/s800/16335_222925421322_568681322_4607953_6548145_n.jpg" style="display: block; height: 120px; margin-bottom: 10px; margin-left: auto; margin-right: auto; margin-top: 0px; text-align: center;" /></a></td><td><a href="http://lh6.ggpht.com/_ZNPMZwry3vA/S4urSAQWevI/AAAAAAAAAF8/fPQwxXfvHpw/s800/16335_222925376322_568681322_4607949_5746305_n.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5401381713973334626" src="http://lh6.ggpht.com/_ZNPMZwry3vA/S4urSAQWevI/AAAAAAAAAF8/fPQwxXfvHpw/s800/16335_222925376322_568681322_4607949_5746305_n.jpg" style="cursor: hand; cursor: pointer; display: block; height: 120px; margin: 0px auto 10px; text-align: center;" /></a></td><td><a href="http://lh3.ggpht.com/_ZNPMZwry3vA/S4urSQUmIlI/AAAAAAAAAGE/Psf3oaCG2S0/s800/16335_222930701322_568681322_4607984_5156283_n.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" style="text-decoration: none;"><img alt="" border="0" id="BLOGGER_PHOTO_ID_5401381711999028498" src="http://lh3.ggpht.com/_ZNPMZwry3vA/S4urSQUmIlI/AAAAAAAAAGE/Psf3oaCG2S0/s800/16335_222930701322_568681322_4607984_5156283_n.jpg" style="cursor: hand; cursor: pointer; display: block; height: 120px; margin: 0px auto 10px; text-align: center;" /></a></td></tr>
</tbody></table></div><br />
<div style="text-align: justify;">A good 20 minutes passes and we gradually come down to ground level (to Charlottes relief). All in all what appears to be a rather lacklustre post is actually one of the best experiences I have had in London. Make sure you try it.</div><br />
<div style="text-align: justify;"><table><tbody>
<tr><td>Rating: </td><td><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border: 0 none;" /></td></tr>
</tbody></table></div><div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-84412425847588507922009-11-07T06:59:00.000-08:002009-11-07T07:29:09.244-08:00Craig and Charlotte's 100 things to do in Britain - #13 Shakespeare's Home, Stratford on Avon<div style="text-align: justify;">Well, well, well... Stratford on Avon is a quaint little place with more mimes, street artists and musicians than you can shake a swan at. The whole area lives and breathes Shakespeare, and why not. From the variety of gift shops, boutiques and stalls you can pretty much deck your home with anything Shakespeare, but a must do is getting your mug shot in front of good old William's home complete with authentic electrical lighting...</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">Well some of the 'realism' has definitely been lost along the way but this shouldn't deter anybody as the vibe in the area is great. Some of the restaurants here are also little gems in themselves but those who have travelled to Stratford on Avon before will be distraught to find that the 'Teddy Bear Museum' has up and ran off to London. No fear we managed to find 'another' with human sized teddy waiting for us just outside the door which more than made up for it :D.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">The highlight of this brief visit was the awesome Christmas shop opposite old Shakespeare's crib. It is decked out a mighty 365 days a year and again you can find anything with a Santa Claus on it. I'm not really a Christmas fan but its worth a delve for the laugh.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">Overall Stratford on Avon does what it says on the tin, its a fun little area packed with things to see, eat and see some more. Parking and travelling were a breeze and was a great relaxing day out. Be prepared to meet the Chinese though, they love old Shakey's house.</div><br /><div style="text-align: left;"><table align="center"><tbody><tr><td><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_ZNPMZwry3vA/SvWQDq-nq2I/AAAAAAAAAE4/kymtTUoCylg/s1600-h/9231_159643531322_568681322_3966596_2529607_n.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;height: 120px;" src="http://1.bp.blogspot.com/_ZNPMZwry3vA/SvWQDq-nq2I/AAAAAAAAAE4/kymtTUoCylg/s200/9231_159643531322_568681322_3966596_2529607_n.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5401381720851721058" /></a></td><td><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_ZNPMZwry3vA/SvWQDRWr0mI/AAAAAAAAAEw/xaSy3jDO2C0/s1600-h/9231_159643521322_568681322_3966595_5695532_n.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;height: 120px;" src="http://4.bp.blogspot.com/_ZNPMZwry3vA/SvWQDRWr0mI/AAAAAAAAAEw/xaSy3jDO2C0/s200/9231_159643521322_568681322_3966595_5695532_n.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5401381713973334626" /></a></td><td><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_ZNPMZwry3vA/SvWQDJ_-TRI/AAAAAAAAAEo/Ivm7L6nXSow/s1600-h/9231_159634496322_568681322_3966441_3733654_n.jpg" style="text-decoration: none;"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand; height: 120px;" src="http://2.bp.blogspot.com/_ZNPMZwry3vA/SvWQDJ_-TRI/AAAAAAAAAEo/Ivm7L6nXSow/s200/9231_159634496322_568681322_3966441_3733654_n.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5401381711999028498" /></a></td></tr></tbody></table></div><div style="text-align: justify;"><table><tbody><tr><td>Rating: </td><td><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border:0 none" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border:0 none" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border:0 none" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border:0 none" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border:0 none" /></td></tr></tbody></table></div><div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-14876326890956349292009-08-17T04:15:00.000-07:002009-08-17T16:27:42.035-07:00Craig and Charlotte's 100 things to do in Britain - #63 The Rows, Chester<div style="text-align: justify;">A Roman-Norman-Saxon-Victorian charm of a city, closely knit shopping streets and some great architecture both historical and modern make Chester a great place to visit. We found ourselves almost lost in the hundreds and hundreds of shops ranging from high street brands to small independant's tucked away in "The Rows". You can spend hours perusing what Chester has to offer and with most things to see and do literally 10 minutes walk away we loved every minute of it. After shops, milkshakes, afternoon tea, a brass band on the promenade, some truly weird people dressed as medieval characters and the Roman amphitheatre we were plum tuckered out. Again the evening was great with a mixture of loud venues and bars for the young and hearty or the not so loud but no less enjoyable restaurants that add a touch of class. We happened upon the "Sian" a Thai restaurant on the canal which is a definite recommendation.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;"><i>As an extra, the following day we spent at the absolutely huge Chester Zoo which should not be missed at all costs if your in Chester. By far the best in the UK.</i></div><br /><div style="text-align: left;"><table align="center"><tbody><tr><td><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_ZNPMZwry3vA/Sonmgo8KgLI/AAAAAAAAAEg/8tIggA5ZomE/s1600-h/6448_146247846322_568681322_3771549_8069573_n.jpg"><img style="cursor:pointer; cursor:hand; height: 140px;" src="http://4.bp.blogspot.com/_ZNPMZwry3vA/Sonmgo8KgLI/AAAAAAAAAEg/8tIggA5ZomE/s200/6448_146247846322_568681322_3771549_8069573_n.jpg" id="BLOGGER_PHOTO_ID_5371077479035994290" /></a></td><td><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_ZNPMZwry3vA/SonmgUCjcdI/AAAAAAAAAEY/cHKjZh0VeBA/s1600-h/6448_146247866322_568681322_3771552_3183972_n.jpg"><img style="cursor:pointer; cursor:hand;height: 140px;" src="http://4.bp.blogspot.com/_ZNPMZwry3vA/SonmgUCjcdI/AAAAAAAAAEY/cHKjZh0VeBA/s200/6448_146247866322_568681322_3771552_3183972_n.jpg" id="BLOGGER_PHOTO_ID_5371077473425650130" /></a></td><td><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_ZNPMZwry3vA/SonmgHYbeMI/AAAAAAAAAEQ/gGpBEi8Py-o/s1600-h/6448_146242706322_568681322_3771498_3910028_n.jpg"><img style="cursor:pointer; cursor:hand; height: 140px;" src="http://3.bp.blogspot.com/_ZNPMZwry3vA/SonmgHYbeMI/AAAAAAAAAEQ/gGpBEi8Py-o/s200/6448_146242706322_568681322_3771498_3910028_n.jpg" id="BLOGGER_PHOTO_ID_5371077470027741378" /></a></td></tr></tbody></table></div><div style="text-align: justify;"><i><br /></i></div><div style="text-align: justify;">The only down side would be the parking, there was very little and what we found of it seemed to be a hell of a way away from the centre. Tip of the day, park at the train station, plenty of spaces and relatively cheap but it is literally 5 minutes walk to the shops.</div><br /><div style="text-align: justify;"><table><tbody><tr><td>Rating: </td><td><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border:0 none" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border:0 none" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border:0 none" /></td></tr></tbody></table></div><div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com1tag:blogger.com,1999:blog-8745825588194554798.post-13363220274871176542009-08-16T13:46:00.000-07:002009-08-16T14:21:11.224-07:00Craig and Charlotte's 100 things to do in Britain - #90 Sherwood Forest National Nature Reserve, Nottingham<div style="text-align: left;">First place visited on our list, the mighty Sherwood Forest, home of the heroic outlaw Robin Hood. I had high hopes for Robin and his band of Merry Men and they did not disapoint. Arriving on the 9th August 2009 we happend upon the "The Robin Hood Festival" which takes place yearly, being free apart from parking we had a brilliant time with falconry, jousting and live music aplenty as well as a lot of activities for kids including archery, face painting and jesters (which to be fair we enjoyed just as much :D). And if all that is not enough there is miles and miles and yes... more miles of walks through the scenic forest to enjoy. The day was great and the visitor centre is pretty good value for money considering that would be <i>nothing</i>. One tip though, turn up early as people were being turned away who came later than mid day.</div><div style="text-align: left;"><br /></div><div style="text-align: left;"><table align="center"><tbody><tr><td><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh3FI4_WeI/AAAAAAAAAEI/xr25eRWuZlc/s1600-h/6448_142203116322_568681322_3702640_5763599_n.jpg"><img style="cursor:pointer; cursor:hand;height: 140px;" src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh3FI4_WeI/AAAAAAAAAEI/xr25eRWuZlc/s200/6448_142203116322_568681322_3702640_5763599_n.jpg" id="BLOGGER_PHOTO_ID_5370673485808884194" /></a></td><td><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_ZNPMZwry3vA/Soh3E_tOO1I/AAAAAAAAAEA/oMri71sp3F4/s1600-h/6448_142200406322_568681322_3702626_3211561_n.jpg"><img style="cursor:pointer; cursor:hand;height: 140px;" src="http://4.bp.blogspot.com/_ZNPMZwry3vA/Soh3E_tOO1I/AAAAAAAAAEA/oMri71sp3F4/s200/6448_142200406322_568681322_3702626_3211561_n.jpg" id="BLOGGER_PHOTO_ID_5370673483343608658" /></a></td><td><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_ZNPMZwry3vA/Soh3EhQSH8I/AAAAAAAAAD4/uriUDpbVBJE/s1600-h/6448_142200371322_568681322_3702622_6667610_n.jpg"><img style="cursor:pointer; cursor:hand; height: 140px;" src="http://3.bp.blogspot.com/_ZNPMZwry3vA/Soh3EhQSH8I/AAAAAAAAAD4/uriUDpbVBJE/s200/6448_142200371322_568681322_3702622_6667610_n.jpg" id="BLOGGER_PHOTO_ID_5370673475169165250" /></a></td></tr></tbody></table></div><div style="text-align: left;"><br /></div><div style="text-align: justify;"><i><b>Being the first place to visit on our adventure were going to set the score at 5 out of 10 and this will be used as the benchmark for future expeditions.</b></i></div><div style="text-align: justify;"><br /></div><div style="text-align: justify;"><table><tbody><tr><td>Rating: </td><td><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://2.bp.blogspot.com/_ZNPMZwry3vA/Soh0Dwz8FCI/AAAAAAAAADo/c-3lKP2MjIo/s200/star.png" style="border:0 none" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border:0 none" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border:0 none" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border:0 none" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border:0 none" /><img src="http://1.bp.blogspot.com/_ZNPMZwry3vA/Soh0j2lLbjI/AAAAAAAAADw/asT0OU9sExc/s200/star_fade.png" style="border:0 none" /></td></tr></tbody></table></div><div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-27702246154657984542009-08-16T13:25:00.000-07:002010-12-23T04:57:48.070-08:00Craig and Charlotte's 100 things to do in Britain<div style="text-align: justify;"></div><br />
<div>Figuring that I am in great need of fresh air, a more cultured outlook and a "life" me and my other half have put together a listing of 100 things to do in Britain. By no means are these "the best" things to do, especially since we dont know what half of them are :P but we rekon you should know where you come from (roughly) and have set upon this mini adventure. Well be posting up each place as and when we visit them with some aw(ful)esome pictures and a bit of a write up about what went on for future place goers...</div><div><br />
</div><div>It is also important to say that the following are in no particular order.</div><ol><li>Hadrian's Wall, Northumberland</li>
<li>Natural History Museum, London</li>
<li>Lincoln Cathedral</li>
<li>Newcastle Race Course</li>
<li>Climb Big Ben Clock Tower</li>
<li>Outdoor Proms Concert, Belton House</li>
<li>Castle Howard, Malton</li>
<li>Windsor Castle</li>
<li>Stonehenge</li>
<li>Snowdonia, Wales</li>
<li>York Minster Cathedral</li>
<li>Roman Baths, Bath</li>
<li><a href="http://designdotworks.blogspot.com/2009/11/craig-and-charlottes-100-things-to-do.html">Shakespeare's Home, Stratford on Avon</a></li>
<li><a href="http://designdotworks.blogspot.com/2010/12/craig-and-charlottes-100-things-to-do.html">Iron Bridge, Shropshire</a></li>
<li>Edinburgh Castle</li>
<li><a href="http://designdotworks.blogspot.com/2010/09/craig-and-charlottes-100-things-to-do.html">Caernarvon Castle</a></li>
<li>The Royal Pavillion, Brighton</li>
<li>British Museum, London</li>
<li>Tate Modern, London</li>
<li>National Gallery, London</li>
<li><a href="http://designdotworks.blogspot.com/2010/03/craig-and-charlottes-100-things-to-do.html">The London Eye</a></li>
<li>The Victoria and Albert Museum</li>
<li>Madam Tussauds</li>
<li>The Tower of London</li>
<li>National Maritime Museum</li>
<li>Kings Cross Station</li>
<li>Wembley Stadium</li>
<li>The Houses of Parliament</li>
<li>Science Museum, London</li>
<li>Queen Mary's Rose Gardens, London</li>
<li>Changing of the Guard, London</li>
<li>Camden Market, London</li>
<li>Portabello Market, London</li>
<li>Westminster Abbey</li>
<li>Orkney, Orkney Islands</li>
<li>King Arthurs Castle</li>
<li>Murder Mystery Dinner, London</li>
<li>The playhouse Theatre, London</li>
<li>Blackpool Tower</li>
<li>Colchester Castle</li>
<li>Harewood HSE</li>
<li>Penshurst Place and Gardens</li>
<li>York Ghost Trail</li>
<li>York Dungeon</li>
<li>King Arthurs Labrynth</li>
<li>The Museum of Welsh Life</li>
<li>Conwy Castle</li>
<li>Athurs Seat, Edinburgh</li>
<li>The Scottish National Gallery of Modern Art</li>
<li>The Witchery Tour, Edinburgh</li>
<li>Castle Campbell, Scotland</li>
<li>Glenfiddich Distillery, Scotland</li>
<li>John O' Groats, Scotland</li>
<li>The Biblical Garden, Scotland</li>
<li>Waltzing Waters, Scotland</li>
<li>Seaforde Butterfly HSE, N Ireland</li>
<li>The Glens of Antrim, N Ireland</li>
<li>Tollymore Forest Park, N Ireland</li>
<li>Tolkeins House</li>
<li>Cotswold Wildlife Park</li>
<li>Kew Gardens</li>
<li>River Camto, Cambridge</li>
<li><a href="http://designdotworks.blogspot.com/2009/08/craig-and-charlottes-100-things-to-do_17.html">The Rows, Chester</a></li>
<li>Lake District</li>
<li>Longleat Safari Park</li>
<li>Kingsgate Bay, Kent</li>
<li>Twycross Zoo</li>
<li>Garston Wood</li>
<li>Blue Water Shopping Centre and Ice Rink</li>
<li>The Norfolk and Suffolk Broads</li>
<li>Cheddar Gorge</li>
<li>Raby Castle, High Force Waterfall</li>
<li>Peak Cavern</li>
<li>Weston Supermare Beach</li>
<li>Norwich Medieval Castle</li>
<li>Eden Project, Cornwall</li>
<li>Canonteign Falls, Devon</li>
<li>Jurrasic Coast, Dorset</li>
<li>The National Marine Aquarium, Plymouth</li>
<li>Pensthorpe</li>
<li>London Zoo</li>
<li>The Town of Harrogate</li>
<li>Cotswold Wildlife Park and Farm</li>
<li>Winter Wonderland, Hyde Park</li>
<li>Bath Christmas Market</li>
<li>Wimbledon</li>
<li>Up-Helly-AA, Shetland Isles</li>
<li>The Great Ormes Head Copper Mine, Llandudno</li>
<li>Aberglasney House and Gardens, Wales</li>
<li><a href="http://designdotworks.blogspot.com/2009/08/craig-and-charlottes-100-things-to-do_16.html">Sherwood Forest National Nature Reserve, Nottingham</a></li>
<li>Pistyll Rhaeadr, Wales</li>
<li>Lulworth Cove</li>
<li>Giants Causeway, N Ireland</li>
<li>St. Michael's Mount, Cornwall</li>
<li>Groombridge Place Gardens</li>
<li>The Trafford Centre</li>
<li>River Thames</li>
<li>Carrick-A-Rede, N Ireland</li>
<li>Creetown Gem Rock Museum, Scotland</li>
<li><a href="http://designdotworks.blogspot.com/2010/04/craig-and-charlottes-100-things-to-do.html">Bond Street, London</a></li>
</ol><div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com1tag:blogger.com,1999:blog-8745825588194554798.post-31904520806620212492009-07-13T14:30:00.000-07:002009-07-14T07:35:04.612-07:00Clean Up Your Unmanaged Objects<div style="text-align: justify;">After working for a few days on a project which had partially been started, I hit across a gem of a piece of code to help myself clean up those nasty COM components. Yes, the dreaded COM! Due to the fact that this was the actual core of the system (having no other choice) I set about at least trying to make it tidy. Quickly I found references to objects, destruction of instances and the good old .Net Garbage Collector couldn't handle what had been written. So time for a rethink.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">I was quite lucky in the fact that the COM library in question was written pretty well and most of it was named sensibly (full marks to the bloke who did the naming).</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;">So to business. The requirements, simply to allow disposal of the object if I manually call it and/or if the so called variable is no longer in scope or referenced anywhere I want the .Net Garbage Collector to clean it up.</div><div style="text-align: justify;"><br /></div><div style="text-align: justify;"><b>Step 1. The class</b></div><div style="text-align: justify;"><b><br /></b></div><div style="text-align: justify;">Due to not being able to inherit from this COM library I set about wrapping up the instances of each type in a class using Generics to pass the objects type through at runtime.</div><pre name="code" class="vb.net"><br />Public Class ComWrapper(Of T)<br /><br />Private _value As T<br /><br />Public ReadOnly Property Value() As T<br /> Get<br /> Return Me._value<br /> End Get<br />End Property<br /><br />Public Sub New(ByVal value As T)<br /> Me._value = value<br />End Sub<br /><br />End Class<br /></pre><br /><div style="text-align: justify;"><b>Step 2. IDisposable</b></div><div style="text-align: justify;"><b><br /></b></div><div style="text-align: justify;">Having the base class in shape I now implemented the .Net IDisposable interface to follow the .Net IDisposable pattern, meaning any using statements would clean the object but also I could call "Dispose()" manually and simply follow the .Net way. The proper way to dispose of COM objects is to use the "Marshal" class found in the namespace "System.Runtime.InteropServices". Calling "ReleaseComObject()" will force the object to be cleaned safely.</div><pre name="code" class="vb.net"><br />Private _disposed As Boolean = False ' To detect redundant calls<br /><br />Public Sub Dispose() Implements IDisposable.Dispose<br /> Dispose(True)<br /> GC.SuppressFinalize(Me)<br />End Sub<br /><br />Protected Overridable Sub Dispose(ByVal disposing As Boolean)<br /> If Not Me._disposed Then<br /> If disposing Then<br /> ' TODO: free other state (managed objects) if you have any.<br /> End If<br /><br /> If Me._value IsNot Nothing Then<br /> System.Runtime.InteropServices.Marshal.ReleaseComObject(Me._value)<br /> Me._value = Nothing<br /> End If<br /> End If<br /> Me._disposed = True<br />End Sub<br /></pre><br /><div style="text-align: justify;"><b>Step 3. Finalize it!</b></div><div style="text-align: justify;"><b><br /></b></div><div style="text-align: justify;">Finally :P we override the "Finalize" method making sure to implement the base finalize but also clear up the COM object. This means if the variable goes out of scope and gets flagged for the Garbage Collector to dispose of it will clean it up nicely and not leave unmanaged instances everywhere.</div><pre name="code" class="vb.net"><br />Protected Overrides Sub Finalize()<br /> If Me._value IsNot Nothing Then<br /> System.Runtime.InteropServices.Marshal.ReleaseComObject(Me._value)<br /> Me._value = Nothing<br /> End If<br /> MyBase.Finalize()<br />End Sub<br /></pre><div style="text-align: justify;"><br /></div><div style="text-align: justify;">So that's it, you should have nicely managed objects now, and for those who need to be nursed hand in hand a sample below shows the full class and some examples of usage and when they will be cleaned up.</div><pre name="code" class="vb.net"><br />Public Class ComWrapper(Of T)<br />Implements IDisposable<br /><br />Private _value As T<br />Private _disposed As Boolean = False ' To detect redundant calls<br /><br />Public ReadOnly Property Value() As T<br /> Get<br /> Return Me._value<br /> End Get<br />End Property<br /><br />Public Sub New(ByVal value As T)<br /> Me._value = value<br />End Sub<br /><br />Public Sub Dispose() Implements IDisposable.Dispose<br /> Dispose(True)<br /> GC.SuppressFinalize(Me)<br />End Sub<br /><br />Protected Overridable Sub Dispose(ByVal disposing As Boolean)<br /> If Not Me._disposed Then<br /> If disposing Then<br /> ' TODO: free other state (managed objects) if you have any.<br /> End If<br /><br /> If Me._value IsNot Nothing Then<br /> System.Runtime.InteropServices.Marshal.ReleaseComObject(Me._value)<br /> Me._value = Nothing<br /> End If<br /> End If<br /> Me._disposed = True<br />End Sub<br /><br />Protected Overrides Sub Finalize()<br /> If Me._value IsNot Nothing Then<br /> System.Runtime.InteropServices.Marshal.ReleaseComObject(Me._value)<br /> Me._value = Nothing<br /> End If<br /> MyBase.Finalize()<br />End Sub<br /><br />End Class<br /><br />' #### Now Some Examples<br />' #### Where "MyComObject" is the com librarys namespace<br />' #### and "MyComType" is the com object your creating an instance of<br /><br />Public Sub Test1()<br />Dim com1 As New ComWrapper(Of MyComObject.MyComType)(New MyComObject.MyComType())<br />' ... Use com1.Value<br />com1.Dispose() ' Object disposed here<br />End Sub<br /><br />Public Sub Test2()<br />Using com2 As New ComWrapper(Of MyComObject.MyComType)(New MyComObject.MyComType())<br /> ' ... Use com2.Value<br />End Using ' Object disposed here<br />End Sub<br /><br />Public Sub Test3()<br />Dim com3 As New ComWrapper(Of MyComObject.MyComType)(New MyComObject.MyComType())<br /><br />' Object is not disposed of but once the variable is out of scope or in other words the methods ends the garbage collector flags "com3" for finalizing. This will not happen instantly so dont rely on it, but it should be fine for those of us who get a bit lazy :P<br />End Sub<br /></pre><div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0tag:blogger.com,1999:blog-8745825588194554798.post-32718235365944510092009-06-16T11:37:00.000-07:002009-06-16T11:39:09.421-07:00Norway is Light!<div style="text-align: justify;">After having just returned from the might home of the vikings to my own discovery I have concluded that Norway is in perpetual light! Camping under the somewhat cloudy stars for three nights makes you aware of this. Note for future reference, no torch required.</div><div class="blogger-post-footer">http://www.designdotworks.co.uk</div>Craig McNicholashttp://www.blogger.com/profile/01900558792551214973noreply@blogger.com0