text: tag:blogger.com,1999:blog-173328162018-05-20T11:29:45.731+08:00Cup(Of T)Software, Data and Analyticspiers7 no migration path from PowerPivot + PowerQuery to SSAS Tabular in SQL 2016 (RC0)<p>Power <strong>pasted data </strong>because SSAS can’t talk PowerQuery.</p> <p>So in order to ‘upsize’ between PowerPivot and SSAS Tabular you have to:</p> <ul> <li>Re-author all your PowerQueries as traditional SSIS ETLs (or similar) </li> <li>Land the data in a relational database </li> <li>Change your PowerPivot model to source from those tables, rather than from PowerQuery. </li> <li>This actually involves recreating them all, since for tables sourced from PowerQuery, the connection type can’t be changed. </li> <li>And the calculated columns and measures </li> <li>And the formatting and sort orders </li> <li>etc… </li> </ul> <p].</p> <p>Only… seems like it’s actually <strong>not</strong>.</p>  <a href="">release notes</a> have been very quiet on this front.</p> <p>The only concrete thing I’ve found is this tantilizing (and presumably unintentional) bit in the <a href="">SQL 2016 Preview</a> site’s <a href="">Deeper Insights Across Data</a> white paper:</p> <p><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="" width="644" height="125" /></p> <p>I stress that’s not my highlighting :-(</p> <p> </p> <p><font size="1">[1] Can’t find where I originally got this idea from. May have just got the wrong end of the wrong stick <br />[2] See </font><a title="" href=""><font size="1"></font></a><font size="1">. That being said, SSRS can use SSIS as a source, so if <em>that </em>was to be implemented… <br />[3] See </font><a title="" href=""><font size="1"></font></a><font size="1"> and </font><a title="" href=""><font size="1"></font></a><font size="1"> or just vote for </font><a title="" href=""><font size="1"></font></a></p><img src="" height="1" width="1" alt=""/>piers7 RGB LED strips from the Raspberry Pi - A Brief OverviewIn 2013 I put my first set of programmable Christmas lights together, a very simple project which involved hanging a <a href="">5m addressable RGB LED strip (based on LDP8806)</a>.<br /><br />The LDP8806 strips were a simple way to get started, because the protocol they speak is basically SPI. Since the RPi has hardware SPI support, this means talking to them is pretty much as simple as writing bytes to <span style="font-family: "Courier New", Courier, monospace;">/dev/spidev0.0</span>. You have to write the <em>right</em> bytes of course, but even that's pretty simple - write as many G,R,B bytes as you have pixels, then a trailing zero. And again, Adafruit have <a href="">great</a> <a href="">tutorials</a> with ready-to-roll sample code (including a gamma correction).<br /><br />I was hooked. But what became immediately apparent was that 5m wasn't going to cut it. Wrapped round the 'Christmas tree' in a spiral it suddenly looked a lot smaller. I needed <strong>moar pixels</strong>.<br /><br />So last year (2014) I started playing with <a href="">WS2812</a>-based lights (aka <a href="">Neopixels</a>).).<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="" width="200" /></a></div><br />(The WS2812 LED, with integrated controller chip visible)<br /><br />So the question arises, how to control the WS2812's from the Raspberry Pi. This will be the topic of the next post.<br /><br /><em>(Of course just when you thought you were on top of it all everything all changes again. Adafruit is now selling a range of LED strips under the brand '</em><a href=""><em>DotStar</em></a><em>' which claim to be a fair bit easier to talk to than WS2812, and as best I can tell from the </em><a href=""><em>RPi Python demo code</em></a><em> they talk SPI).</em><br /><img src="" height="1" width="1" alt=""/>piers7 issues with SQL 2012 SP2After rolling out SQL 2012 SP2 (CU1) across all our environments, we noticed all our TeamCity builds were going a <b>lot </b>slower, or never completing. I didn't make the connection at first, but I eventually tracked it down to a SMO call in our install script that was taking a <i>long </i>time to return (actually I think it either deadlocks or never returns on our busy build server).<br /><br />Firing.<br /><br />Clearly we should have looked at <a href="">SetDefaultInitFields</a> before, but the performance was always good enough we didn't have to bother. Which makes me suspect <b>strongly </b>that either the defaults have changed with SP2 (CU1), or the 'get all properties for the database' query has changed to include additional data (probably something cloud related), which reduces the performance substantially in the 'get everything' case.<br /><br /:<br /><blockquote class="tr_bq"><span style="font-weight: bold;">this</span>.m_comparer = parentsrv.Databases[<span style="color: blue;">"msdb"</span>].StringComparer;</blockquote>This object depends on a couple of server properties, but I think 'Collation' is the key one here - if that's not loaded then the the newer 'all properties' query kicks in, which is again much slower than it was before.<br /><br /><b>Moral</b>: be sure to add 'Collation' to your SetDefaultInitFields() list for Databases.<img src="" height="1" width="1" alt=""/>piers7'Specified wildcard pattern is invalid' with Octopus Deploy and PSakeSo we upgraded to Octopus Deploy v2, and all our deployments are now failing with this error:<br /><br />;">22/07/2014 11:51:08 AM: An Error;">Test-Path : Cannot retrieve the dynamic parameters for the cmdlet. The <;">specified wildcard pattern is not;">Octopus.Environment.MachinesInRole[myproject-sql-node]<;">At D:\Octopus\Applications\Test\ORDW.Staging.TPPS\7.0.310-trunk_1\Tools\Install<;">\psake.psm1:357 char:17<;">+ if (test-path "variable:\$key") {</div></div><br /.<br /><br /?<br /><br />Where psake is failing is where it pushes properties into variable scope for each of the tasks it executes as part of the 'build', and apparently it's choking because <b>test-path</b> doesn't like it. So I put together some tests to exercise test-path with different variable names, and find out when it squealed. This all works against the same code as runs in psake, ie:<br /><br /><span style="background-color: white; color: #444444; font-family: Monaco, Menlo, Consolas, 'Lucida Console', 'Courier New', monospace; font-size: 12px; line-height: 20px; white-space: pre-wrap;">test-path "variable:\$key"</span><br /><br /><table><colgroup><col></col><col></col></colgroup><tbody><tr><th>$key</th><th>Result</th></tr><tr><td>a</td><td>Ok</td></tr><tr><td>a.b</td><td>Ok</td></tr><tr><td>a-b</td><td>Ok</td></tr><tr><td>b.a</td><td>Ok</td></tr><tr><td>b-a</td><td>Ok</td></tr><tr><td>a.b.c</td><td>Ok</td></tr><tr><td>a-b-c</td><td>Ok</td></tr><tr><td>c.b.a</td><td>Ok</td></tr><tr><td>c-b-a</td><td>Ok</td></tr><tr><td>a[a]</td><td>Ok</td></tr><tr><td>a[a.b]</td><td>Ok</td></tr><tr><td>a[a-b]</td><td>Ok</td></tr><tr><td>a[b.a]</td><td>Ok</td></tr><tr><td><span style="color: red;">a[b-a]</span></td><td><span style="color: red;">Cannot retrieve the dynamic parameters for the cmdlet. </span><br /><span style="color: red;">The specified wildcard pattern is not valid: a[b-a]</span></td></tr><tr><td>a[a.b.c]</td><td>Ok</td></tr><tr><td>a[a-b-c]</td><td>Ok</td></tr><tr><td>a[c.b.a]</td><td>Ok</td></tr><tr><td><span style="color: red;">a[c-b-b]</span></td><td><span style="color: red;">Cannot retrieve the dynamic parameters for the cmdlet. </span><br /><span style="color: red;">The specified wildcard pattern is not valid: a[c-b-b]</span></td></tr><tr><td>a[b-b-a]</td><td>Ok</td></tr></tbody></table><br />I've highlighted the failure cases, but what's just as interesting is which cases <i>pass</i><i style="font-weight: bold;">. </i>This gives a clue as to the underlying implementation, and why the failure happens.<br /><br />To cut a long story short, it appears that any time you use <b>square brackets </b>in your variable name, PowerShell uses <i>wildcard matching </i>to parse the content within the brackets. <b>If </b>that content contains a hypen, then the letters before and after the <b>first hyphen </b>are used as a range for matching, and the range end is prior to the range start (ie: alphabetically earlier), you get an error.<br /><br />Nasty.<br /><br / <i>just fine</i>, and there's no obvious way of supressing the wildcard detection. Ultimately I think this is probably a PowerShell bug. Whichever way you look at it, the chances of me getting it fixed soon are fairly slight.<br /><br />In this case I can just change all my Octopus role names to use dots not hypens, and I <i>think</i> I'll be out of the woods, but this could be a right royal mess to fix otherwise. I'd probably have to forcefully remove variables from scope just to keep PSake happy, which would be ugly.<br /><br />Interestingly the documentation for <b>Test-Path </b>is a bit confused as to whether wildcard matching is or isn't allowed here - the description says they are, but Accept wildcard characters' claims otherwise:<br /><br /><pre>PS C:\> help Test-Path -parameter:Path<br /><br />-Path <string><br /> Specifies a path to be tested. <b>Wildcards are permitted</b>. If the path includes spaces, enclose it in quotation marks. The parameter <br /> name ("Path") is optional.<br /> <br /> Required? true<br /> Position? 1<br /> Default value <br /> Accept pipeline input? True (ByValue, ByPropertyName)<br /> <b>Accept wildcard characters? false</b><br /></string></pre><br />Also interesting is that <b>Set-Variable </b>suffers from the same issue, for exactly the same cases (and wildcarding definitely doesn't make any sense there). Which means you can do this:<br /><blockquote class="tr_bq">${a[b-a]} = 1</blockquote>but not this<br /><blockquote class="tr_bq">Set-Variable 'a[b-a]' 1</blockquote>Go figure.<br /><br /><br /><strong>Update 23/7:</strong><br /><ul><li>You can work around this by escaping the square brackets with backticks, eg Set-Variable 'a`[b-a`]'</li><li>I raised a <a href="">Connect issue</a> for this, because I think this is a bug</li><li>I've raised an <a href="">issue with Psake</a> on this, because I think they should go the escaping route to work around it.</li></ul><img src="" height="1" width="1" alt=""/>piers7's time to bring Data Tainting to the CLRLast week's <a href="">Heartbleed</a> bug once again exposes the shaky foundations of current software development processes. Decades-old issues such as inadvertent use of user-input values, and unintended access to memory (whether read or write) continue to be critical risks to the infrastructure on which our economies are increasingly reliant.<br /><br />How do we deal with these risks? We implore developers to be more careful. This is clearly not working.<br /><br / <strong>doing something fundamentally less risky - </strong>engineering the risk away. As an industry, we could learn a thing or two here.<br /> <a href="">SQLi</a> and <a href="">XSS</a> attacks instead.<br /><br />I think it's time to fix this. I think it's time we made the <em>trustworthiness </em>of data a first-class citizen in our modern languages. I think it's time to <a href=""><strong>bring Data Tainting to the CLR</strong></a>.<br /><br />Data Tainting is a language feature where all objects derived[1] from user input are flagged as 'tainted' unless explicitly cleared, a bit like that infamous <a href="">'downloaded from the internet' flag</a> that block you running your downloads. Combined with other code paths asserting that their arguments are <u>un</u>tainted, this can <strong>largely eliminate the problem of unsanitized user input being inadvertently trusted.</strong><br /><br /><a href="">Taint Checking</a> is not a new idea, it's just not very common outside of academia[2] (Perl and Ruby are the only extant languages I know of that support it, having strangely failed to take hold in JavaScript after Netscape introduced it <em>last century</em>). But it's exactly what we need if we are to stop making the same security mistakes, over and over again.<br /><br />It has bugged me for over a decade that this never took off, but the last straw for me was questions like this on security overflow: <a href="">Would Heartbleed have been prevented if OpenSSL was written in (blah) ...</a> Why? Because the depressing answer is <strong>no</strong>. Whilst a managed implementation of TLS could not have a direct memory scraping vulnerability, the <em>real </em>bug here - that the output buffer sizing was based on what the client wrote in the input header - is not prevented. So the flaw could still be misused, perhaps allowing to DOS the SSL endpoint somehow.<br /><br / <em>directly </em>passed to your database / shown to other users / used as your balance / written to the filesystem etc... The myriad ways we can find to exploit these holes should not be a testament not to our ingenuity, but highlight an elephant in the room: <strong>it's still too hard to write secure code</strong>. Can we do more to fall into the pit of success? I think so.<br /><br />Implementing taint checking in the CLR will not be a trivial task by any means, so Microsoft are going to take a fair bit of persuading that matters enough to commit to. And that's where I need your help:<br /><ul><li>If any of this resonates with you, please vote for my user voice suggestion: <a href=""><strong>bring Data Tainting to the CLR</strong></a></li><li>If you think it sucks, comment on it (or this post) and tell me why</li></ul>Imagine a world where Heartbleed could not happen. How do we get there?<br /><br />Next time: what taint checking might look like on the CLR.<br /><br /><span style="font-size: x-small;">[1] Tainting spreads through operators, so combining tainted data with other data results in data with the taint bit set.</span><br /><span style="font-size: x-small;">[2] Microsoft Research did a good review of the landscape here, if you can wade through the overly-theoretical bits: </span><a href=""><span style="font-size: x-small;"></span></a><img src="" height="1" width="1" alt=""/>piers7 not load file or assembly ApprovalTestsIf you get the following error when running <a href="">ApprovalTests</a>... <blockquote>Could not load file or assembly 'ApprovalTests, Version=3.0.0.0, Culture=neutral, PublicKeyToken=11bd7d124fc62e0f' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)</blockquote> ...make sure the assembly that your <b>tests</b> are in is not <i>itself</i> called ApprovalTests. As perhaps it might be if you were just demoing it to someone quickly. Doh!<img src="" height="1" width="1" alt=""/>piers7 PowerShell Gotcha - Order of precidence and type inferenceThere was a fun moment at last week's Perth Dot Net User Group when the presenter (demonstrating Octopus Deploy's new scripting console), put in the following PowerShell:<br /><br /><code> > Write-Host [Environment]::MachineName<br /></code><br />And got back (literally)<br /><br /><code>[Environment]::MachineName<br /></code><br />...which wasn't what he expected <em>at all. </em>It's worth pausing to consider why this happens.<br /><br />Remember of course that when passing strings as arguments in PowerShell, the quotes are optional - it would make a fairly poor shell replacement otherwise. So for example the following is completely valid:<br /><br /><code>> Write-Host Hello!</code><br /><br />This is the reason<sup>[1]</sup> why variables in PowerShell have the dollar prefix - it makes their use in binding fairly unambiguous (just as the @ symbol in Razor achieves the same thing).<br /><br /><code>> $a = 'Moo'<br />> Write-Host $a</code><br /><code>Moo<br /></code><br />If you <em>really </em>wanted to write '$a' you'd have to enclose it in single quotes (as I just did) or escape the dollar symbol.<br /><br />Anyway back to the original problem, you can see that PowerShell has two possible ways of interpreting<br /><br /><code>> Write-Host [Environment]::MachineName<br /></code><br />...and since it doesn't start with a $, you get the 'bind to as an object' behavior, which - in this case - gives you a string (since it's clearly not a number).<br /><br />What you really wanted was one of the following:<br /><br /><code>> Write-Host ([Environment]::MachineName)<br />> Write-Host $([Environment]::MachineName)</code><br /><code>SOMECOMPUTERNAME<br /></code><br />They both give the intended result, by forcing the expression within the brackets to be evaluated <em>first </em>(which on its own is unambiguous to the parser), and then passing the <em>result</em> of that as an argument to the bind for Write-Host.<br /><br />This is really important trick to know, because will otherwise bite you again and again when you try and call a .Net method, and attempt to supply a parameter via an expression, for example:<br /><br /><code>$someClass.SomeMethod($a.length -1)</code><br />...when what you need to say is<br /><br /><code>$someClass.SomeMethod(($a.length -1))</code><br />Key take-home: <strong>When in doubt, add more brackets<sup>[2]</sup></strong><br /><br /><span style="font-size: x-small;">[1] presumably</span><br /><span style="font-size: x-small;">[2] parenthesis</span><img src="" height="1" width="1" alt=""/>piers7 trivia: BINARY_CHECKSUMYou know how in SQL Books online the doco tells you to be wary of using <a href="">CHECKSUM</a> and <a href="">BINARY_CHECKSUM</a> functions because they will miss some updates. Here's a trivial example:<br /><br /><pre>select <br /> BINARY_CHECKSUM(A),<br /> BiggestInt,<br /> BINARY_CHECKSUM(BiggestInt)<br />from (<br /> select cast(null as int) as A,<br /> Power(cast(2 as bigint),31) -1 as BiggestInt<br />) x<br /></pre><br />Which returns 2147483647 in all 3 cases. So essentially BINARY_CHECKSUM is blind to the difference between a null and an int(max value). Which is fair enough... but does illustrate the point that even if you are only doing a checksum on a single nullable<i> </i>4 byte field, you can't stuff it into 32 bits without getting at least one collision.<img src="" height="1" width="1" alt=""/>piers7 Reader In Memoriam<blockquote class="tr_bq">So, Farewell Then Google Reader<br />Your feed<br />Has expired<br />Like Bloglines,<br />Which you killed<br />Off</blockquote><blockquote class="tr_bq">I guess<br />Now<br />We'll just have to use<br />Something else<br />Instead</blockquote>Google Reader was 7 1/2<br />(With apologies to <a href="">E.J.Thribb</a>)<img src="" height="1" width="1" alt=""/>piers7 the Analysis Services Deployment UtilityThe <a href="">Analysis Services Deployment Utility</a> is a utility that can be used to deploy Analysis Services build outputs (.asdatabase files) to a server, or to generate the XMLA for offline deployment.<br /><br />I've often used this as part of an automated installation process to push releases out into an integration environment, but on this project I wanted to perform this installation as part of a nightly build. It failed - because the utility (and it's dependencies) weren't installed on the build server.<br /><br />I wasn't entirely sure what I needed to get it installed (and I was attempting to install the minimum amount of stuff). It turns out this tool is distributed as part of <b>Sql Management Studio</b>, not the SSDT/BIDS projects (as I'd previously assumed). Not sure if the Basic or Complete option is required, because I picked 'complete' and that fixed it.<br /><br />Also, for 2012 the path has changed, and the utility is now at:<br /><br /><span style="font-family: Courier New, Courier, monospace;">C:\Program Files (x86)\Microsoft SQL Server\110\Tools\Binn\<b>ManagementStudio</b>\Microsoft.AnalysisServices.Deployment.exe</span><br /><br /><img src="" height="1" width="1" alt=""/>piers7 BIDS project templates for SQL 2012You can <i>absolutely </i>be forgiven for being confused about how to install the BIDS project templates for SQL 2012. They've moved to the new <a href="">Sql Server Data Tools</a> (SSDT), but Microsoft are themselves inconsistent about what SSDT <i>is</i>. To make matters worse, you've got Visual Studio 2010 and 2012 versions of each package, depending on what IDE you want to work in.<br /><br />I'll attempt to clarify:<br /><br /><ul><li>SSDT is only the updated <b>SQL database</b> project template, that replaces the Database Edition GDR / datadude stuff (and subsumes the SQL-CLR project type)</li><li>SSDT-BI is the other, ex-BIDS projects: SSIS, SSRS, SSAS</li></ul><div>Unfortunately the SQL 2012 install media uses the term 'Sql Server Data Tools' to refer to both at the same time, and up-until-last-week the SSDT-BI project didn't exist outside of the SQL install media. Much confusion and delay. Hopefully the following guidance clears it up a bit:</div><div><br /></div><h3>If you only care about the SQL Server Database project</h3><br />(eg: you are a C# developer, and your SQL database schema as a project in your solution)<br /><br />Install the appropriate version of SSDT that matches the version of Visual Studio (2010 or 2012) you're using right now (or both if necessary):<br /><ul><li><a href="">SSDT for Visual Studio 2010</a></li><li><a href="">SSDT for Visual Studio 2012</a></li></ul><div>Note these <b>do not</b> include the BIDS project templates (SSRS, SSIS, SSAS); they <b>only</b> include the new SQL Server Database project template.<br /><br /></div><h3>If you are a BI developer, and want the lot</h3><h4>...in a Visual Studio 2010 Shell</h4><div>Install the 'Sql Server Data Tools' component from the SQL 2012 install media. This gets you everything you need.<br />Optionally, <i>also </i>install the updated version of the SQL project template (only) by installing <a href="">SSDT for Visual Studio 2010</a><br /><h4>...in a Visual Studio 2012 Shell</h4><div></div></div>Install the standalone version of <a href="">SSDT for Visual Studio 2012</a> (for the database project) and <a href="">SSDT-BI for Visual Studio 2012</a> (for the SSRS, SSIS, SSAS templates)<br /><h4>...but don't know which shell to use</h4><div>If you plan to create a single Visual Studio Solution (.sln) combining BIDS artifacts database projects and other project types (e.g. C# or VB projects), then that will determine your choice here. It's certainly easier working in just one IDE than having to have two open.</div><div><br /></div><div>Otherwise just pick one. You might be swayed by some of the new VS 2012 features, then again you get the 2010 version already on the install media, so that option is less downloading. Given they shipped against one version, but now support the next as far as I can see they'll have to support both versions going forwards, at least for a couple of years.</div><div><br /></div><div><i><br /></i></div><div><i>Editors Note: This rewrite replaces the sarcastic rant I had here previously, which was quite cathartic, but not desperately helpful in navigating the landscape here.</i></div><img src="" height="1" width="1" alt=""/>piers7: Worst. Interface. Ever<p>As any .Net UI developer will tell you, <a href="">INotifyPropertyChanged</a> is a fundamental part of 'binding' an object to a UI control. Without it binding is essentially one-way: changes in the control change the object, but if this has a ripple effect on other properties, or properties are changed by other 'below the UI' processes, the UI can't know to repaint. This is essentially an implementation of the Observer pattern[1]. <br /> <br />Unfortunately it's not for free - you have to implement it yourself - and that's where the problems start. <i>So much</i> has been written on the pain of implementing INotifyPropertyChanged (INPC for short) that I need not repeat it all here. It's generated <a href="">so many questions on StackOverflow</a> you'd think it's due its own StackExchange site by now.</p> <p>The principal complaints are around all the boilerplate code and magic strings required to implement, so for the sake of completeness I'll summarize some of the solutions available:</p> <ul> <li>Design-time assistance to crank out the boilerplate through Snippets, or tools like <a href="">ReSharper</a> that also facilitate refactoring (without breaking magic strings)</li> <li>Compile-time IL re-writing approaches such as <strike>NotifyPropertyWeaver</strike> <a href="">Fody</a> and <a href="">PostSharp</a></li> <li>Run-time implementations using reflection, expression trees (such as in <a href="">Caliburn.Micro's PropertyChangedBase</a>), call interception using ContextBoundObject or Dynamic Proxies (e.g. <a href="">Castle</a> or <a href="">roll-your-own</a>), or the use of <a href="">[CallerMemberName] in .Net 4.5</a></li> <li>Employing the <a href="">Value Object</a> pattern and turning all your your properties into some kind of Notifiable<T> (<a href="">Ayende has a good example</a>, <a href="">here’s another</a>). This does mean changing all your binding however (x.FirstName becomes x.FirstName.Value)</li> </ul> Pick one of these, stick with it and you're done. Ok, there's still a bit of griping about separation of concerns, and whether <a href="">this is an anti-pattern</a>, but you're done right? <br /> <br />No. <br /> <br />It's <i>so much</i> worse than that. <br /> <br />Do you remember the first time you implemented GetHashCode(), and later when you <a href="">realized you'd done it wrong</a>? And later when you <i>really</i> realized you'd done it wrong, that there was <em>no good way</em> you could override Equals() for a mutable object, and the sneaking realization that <a href="">this whole problem existed only for the benefit of Hashtables</a>? It's a bit like that. <br /> <br />What we have with INotifyPropertyChanged is an <i>implicit contract</i>, that is to say that a large part of the contract can't be formally defined in code. Which means you have to validate your implementation manually. In this case the implicit bit is about <b>threading</b>. INotifyPropertyChanged exists to support UI frameworks and (bizarrely, in this day-and-age) they are still single threaded, and can only execute on the thread that constructed them – including event handlers. Think about this a bit, and you will eventually conclude: <br /> <blockquote class="tr_bq"><b>An object that implements INotifyPropertyChanged must raise the PropertyChanged event only on the thread that was originally used to construct any registered subscribers for that event</b></blockquote> <p>Now <i>there's</i> a problem[2]. <br /> <br />Clearly this is something that's just not possible to check for at runtime, so your design has to cater for this. Passing objects that <em>might </em>have been bound to business logic that might mutate them? UI thread please. Adding an item into a collection that <em>might </em>be ObservableCollection? UI thread please. Doing some calculations in the background to pass back to an object that <em>may </em>have been bound? Marshal via UI thread please. And so on. And don't even get me started on what you do if you have two (or more) 'UI' threads[3]. <br /> <br />This is a horrible, horrible creeping plague of uncertainty that spreads through your UI, where the validity of an operation can't be determined at the callsite, but must also take into account the underlying type of an object (violating polymorphism), where that object came from (violating encapsulation), and what thread is being used to process the call (violating all that is sacred). These are aspects that we just can't model or visualize well with current tooling, at least not at design time, and <b>none</b> of the solutions above will save you here. <br /> <br />So there you go. INotifyPropertyChanged: far, <i>far</i> worse than you imagined. <br /> <br /> <br /><font size="1">[1] ok, <i>any</i> use of .net events could be argued is Observer, but the intent here is the relevant bit: the object is explicitly signalling that it's changed state. <br />[2] Actually I've over-simplified, because you can have whole chains of objects listening to each other, and if <i>any one of them</i> is listened to by an object with some type of thread-affinity, that's the constraint you have to consider. <br />[3] Don’t try this at home. There are any number of lessons you’ll learn the hard way.</font></p> <img src="" height="1" width="1" alt=""/>piers7 reference leakage using extension methods and genericsIt appears that if you have an extension method, that is in-scope (i.e. namespace included), <strong>even if you don't use it </strong>you have to reference all the assemblies that are part of the generic type constraint. <br /><br />This kinda sucks.<br /><br />Normally if you use a type from another assembly, and that type has as part of its interface another type in another assembly, you have to reference both assembly. Fine. <strong>But only if you use it.</strong><br /><br />eg: if you reference assembly 'Animal' and use a class 'Cow' that has a property 'Color', and the type of Color is defined somewhere else (System.Windows.Forms) you have to reference that too. But if you get the cow via the IBovine interface, and that doesn't expose Color, you don't need the reference (at least not statically).<br /><br />If, however, in the same namespace, there's an extension method that you're not using, and that extension method has some type constraints, you have to reference all the assemblies for all the type constraint parameters.<br /><br />For example, if you put this in one assembly, in a namespace <i>you merely import</i>:<br /><br /><code></code><br /><pre><code> public static class NotUsed{<br /> public static void DefinatelyNotUsed<tcontext>(this TContext context, Action<datacontext> thing)<br /> where TContext : DataContext<br /> {<br /> <br /> }<br /> }<br /></datacontext></tcontext></code></pre><code></code> ... then you'll also have to pull in System.Data.Linq to get the 'importing' assembly to compile.<br /><br />Doesn't this strike you as odd? I'm sure I can hear a gestalt Eric Lippert in my head explaining why, but I was certainly surprised.<img src="" height="1" width="1" alt=""/>piers7 on empty collectionsPowerShell's pipeline just <i>loves</i> to unravel collections, with the result that sometimes, when you want to do something on the collection itself, you can't. Like with Get-Member:<br /><pre><blockquote><br />$blah.Catalogs | Get-Member<br /><span style="color: red;">Get-Member : No object has been specified to the get-member cmdlet.</span><br /></blockquote><br /></pre><div>What happened? Did $object.Catalogs return null, or did it return an empty IEnumerable? This has bitten me a few times, especially when poking around in an API for the first time (ie: at this point I have no idea what 'Catalogs' is, whether it's ICollection or whatever).</div><div><br /></div><div>The answer, I realize, is to avoid the pipeline:</div><pre><blockquote><br />Get-Member -inputObject:$blah.Catalogs<br /><br /> TypeName: BlahNamespace.BlahCollection<br /><br />Name MemberType Definition <br />---- ---------- ---------- <br />Add Method System.Void Add(Microsoft.SqlServer.Management.IntegrationSer...<br />Clear Method System.Void Clear() <br /></blockquote><br /></pre><div>Much better</div><img src="" height="1" width="1" alt=""/>piers7 2012 Data Tier Applications explained<b>You:</b> So what are these DACPAC things then?<br /><b>Microsoft:</b><br /><blockquote class="tr_bq">"</blockquote><blockquote class="tr_bq"><a href=""></a> </blockquote><br /><b>You:</b> Hey, that sounds familiar. How is that different from Visual Studio 2010 Database Edition aka DataDude aka GDR aka VSDBCMD.exe?<br /><b>Microsoft:</b> They're, like, totally different ok.<br /><br /><b>You:</b> How so?<br /><b>Microsoft:</b> Well they just are. DACPACs <i>replace</i> all that GDR stuff. That was just crazy stuff the Visual Studio guys came up with you know. This is the real deal from the SQL product team. And we can package data too, in BACPACs.<br /><br /><b>You:</b> Awesome. So this'll solve that problem about also upgrading reference data when I push out a new version of the schema?<br /><b>Microsoft:</b> Oh no. BACPACs can't be used to upgrade an existing database instance. Just to load data into new databases. They're for moving databases between servers.<br /><br /><b>You:</b> Like a backup<br /><b>Microsoft:</b> Exactly like a backup, yes.<br /><br /><b>You:</b> ...so... can't you just use a backup?<br /><b>Microsoft:</b> No. DACPACs and BACPACs don't just contain the database. They encapsulate the whole data tier application, so they include other items you'd need to deploy, like logins.<br /><br /><b>You:</b> Cool. And agent jobs as well I guess?<br /><b>Microsoft:</b> Oh no. Just logins and ... well logins anyway. Try doing that with GDR. And you wouldn't be using sql_variant anyway would you? No.<br /><br /><b>You:</b> Come again?<br /><b>Microsoft:</b> Oh nothing.<br /><br /><br /><span style="font-size: x-small;">The author notes this conversation was imaginary, and any resemblance to reality is entirely coincidental</span><img src="" height="1" width="1" alt=""/>piers7 Windows RT desktop. For why?I still don't understand Windows 8 RT (aka Microsoft Surface, aka Windows on Arm), or more specifically it's desktop mode.<br /><br />On Windows 8 Pro (the x86 version) it all makes sense: desktop mode opens the door to all the 'legacy' apps you know and love, whilst the device itself weans you onto the world of RT/store apps. As an enterprise developer you can target either, most likely running existing corporate apps on the desktop whilst mulling the trade-offs (and $) involved in rewriting the front end to target Metro.<br /><br />But on Arm it's crippled: running only Microsoft-sanctioned apps (Office, Notepad and explorer) <a href="">without jailbreaking</a>. Why?<br /><br />Clearly you can't expect it to run existing x86 apps, but for enterprise developers working in .Net this is a slap in the face. You're barred from running existing .net 4 desktop apps on the Surface RT desktop, and you can't build desktop apps using the Win RT runtime <i>either</i>.<br /><br />This is a crazy situation that smacks of half-baked.<br /><br />If the desktop mode on Arm is useful - and I'd argue it is - it should be possible for more than just Microsoft to write for it. Ideally enterprises could run existing .Net apps unmodified, but there's clearly advantages (re: capability, performance and battery life) in encouraging them to embrace the Win RT APIs.<br /><br />Conversely if the desktop mode is redundant, Microsoft need to seriously pull their finger out replicating all that functionality in the Metro interface, including a Metro version.<br /><br />I would like for the former to be the case. I suspect Microsoft's roadmap is the latter, that the desktop's just there till Office gets ported proper. Whichever way, we have a ridiculous situation where if an enterprise developer wants to target Windows 7 and both Windows 8's they have to ... write a web app. Way-to-go Microsoft!<sup>[1]</sup><br /><br />I keenly await Xamarin's Mono-Surface<sup>[2]</sup>, which will let you run .Net apps <i>on the Microsoft Platform</i>. Now that would be progress.<br /><br /><br /><span style="font-size: xx-small;">[1] Sure they gave the enterprise the finger with the phone too. I guess we shouldn't be surprised. But perhaps this is just <a href="">Sinofsky</a>'s <a href="">'my way or the high way'</a> showing through</span><br /><span style="font-size: xx-small;">[2] This is a fictitious product, and any resemblance to actual products planned or otherwise is entirely coincidental</span><img src="" height="1" width="1" alt=""/>piers7 XmlConvert.ToString(DateTime)XmlConvert is the utility class that controls fundamental .Net data types being converted to/from their XML representations. For dates, the DateTimeOffset overloads are less ambigious than the DateTime ones, and as a result the latter have been depricated. But you'd still expect it to basically work for the fundamental scenarios. <br /><br />Nope. For DateTimeKind=UTC dates, it's totally broken.<br /><br />Ttry this (in Linqpad):<br /><code></code><br /><code></code><br /><code></code><br /><code><pre> var localTime = DateTime.Now;<br /> var utcTime = localTime.ToUniversalTime();<br /> <br /> localTime.Dump("Local Time");<br /> utcTime.Dump("UTC time");<br /> utcTime.Kind.Dump("UTC Kind");<br /> utcTime.ToString("yyyy-MM-ddTHH:mm:ss K").Dump("Expected XML");<br /> XmlConvert.ToString(utcTime).Dump("Actual XML from XML Convert");<br /></pre></code><br />Gives:<br /><br /><div><table style="text-align: left;"><tbody><tr><th>Local Time</th><td>23/10/2012 11:11:11 AM</td></tr><tr><th>UTC time</th><td>23/10/2012 3:11:11 AM</td></tr><tr><tr><th>UTC Kind</th><td>UTC</td></tr><tr><th>Expected XML</th><td>2012-10-23T03:11:11 Z</td></tr><tr><th>Actual XML from XML Convert</th><td>2012-10-23T03:11:11.0773940<strong><span style="background-color: yellow;">+08:00</span></strong></td></tr></tr></tbody></table><br /><br />You'll notice immediately (because of the highlighting), that it's done something really really dumb. It's made out that the UTC time is actually a local time in my local timezone offset (+8). <strong>It's screwed up the XML representation, and as a result changed the actual time value being passed, </strong>even though it <em>knows</em> (based on DateTime.Kind==DateTimeKind.Utc, that the ToUniversalTime() method always gives you) that it's a UTC date.<br /><br />This is because internally that method does this:<br /><br />[<span style="color: midnightblue; font-weight: bold;">Obsolete</span>(<span style="color: blue;">"Use XmlConvert.ToString() that takes in XmlDateTimeSerializationMode"</span>)]<br /><span style="color: blue; font-weight: bold;">public</span> <span style="color: brown;">static</span> <span style="color: red;">string</span> <span style="color: midnightblue; font-weight: bold;">ToString</span>(DateTime <span style="font-weight: bold;">value</span>);">zzzzzz</span>"</span>);<br />}<br /><br />...and those z's add the local timezone offset <strong>from your PC</strong>. This is <strong>wrong </strong>for a DateTime with Kind=UTC. A better implementation would be as per my example above, ie:;">K</span>"</span>);<br /><br />The K specifier is not so dumb, and adds the time zone to <strong>local time </strong>datetime instances, and adds the <strong>Z</strong> to UTC instances. Or alternatively an if{}else{} based on value.Kind==DateTimeKind.UTC.<br /><br />Anything but what it does right now.<br /><br />Why do I care? Well WCF generates webservices proxies using DateTime, not DateTimeOffset, so I want to make damn sure it's not making the same mistake.</div><img src="" height="1" width="1" alt=""/>piers7 Package Restore with internet-restricted build serversThe first time I enabled nuget package restore I had a nasty shock: the TeamCity build server didn't have internet access (and wasn't getting any).<br /><br />I initially went back to storing-packages-in-source-control, but when I created a spike ASP.Net MVC 4 project, which wanted to add some <b>30</b> packages, I decided I needed to address the root problem.<br /><br />A few people suggested I should setup a local nuget repository, the simplest version of which is just to dump all the packages you need into a file share. But how to point the build server at the share, rather than the standard nuget feed URL? Short of logging in as the build server user and changing the settings through Visual Studio (lame), there appear to be a couple of ways:<br /><br /><h3>Editing %appdata%\nuget\nuget.config (for the build server user)</h3>This achieves the same as the above, but you don't have to log in as that user. It's reliable, but because it doesn't 'carry' with the solution in source control it's brittle (needs doing again if the build server user changes etc...) and you can't vary it on a project by project basis, which is a bit limiting.<br /><h3>Editing the generated nuget.targets file that package restore adds to your solution</h3>This looks like the go, and even has comments in there to show you what to change. But I didn't find this reliable. On my local machine (under a no-internet user) this worked just fine, but on my build server I kept having package resolution errors (from a Silverlight 4 project).<br /><h3>Setting the PackageSources build parameter</h3>What the above did show is what MSBuild properties are involved, so I was able to specify that property on the MSBuild command line and that seems to work consistently:<br /><blockquote class="tr_bq">MSBuild mysolution <b>/p:PackageSources=\\server\fileshare</b></blockquote>...now <i>finally</i> I have a green light on TeamCity and can go and do something actually productive instead.<img src="" height="1" width="1" alt=""/>piers7 SQL Credentials for Network Service account<p>It’s fairly normal in production environments to find the SQL Server configured to disallow use of the SQL Agent account for the execution of certain types of job steps: SSIS packages and CmdExec for example. Instead you have to configure an explicit SQL Agent proxy, which requires first storing credentials within SQL’s credential store.</p> <p>For domain accounts this is fairly straightforward, but if you attempt to add credentials from one of the ‘virtual accounts’ (such as Network Service), you’ll get the following error: “The secret stored in the password field is blank”</p> <p><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="" width="534" height="236" /></p> <p>The solution is (eventually) obvious: add the credential using TSQL (or SMO), and avoid the UI validation:</p> <blockquote> <p><font face="Consolas">USE [master] <br /></font><font face="Consolas">GO</font></p> <p><font face="Consolas">CREATE CREDENTIAL [Network Service] WITH IDENTITY = N'NT AUTHORITY\NETWORK SERVICE' <br /></font><font face="Consolas">GO</font></p> </blockquote> <p>et, voila:</p> <p><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="image" border="0" alt="image" src="" width="197" height="131" /></p> <img src="" height="1" width="1" alt=""/>piers7 'built by a runtime newer than the currently loaded runtime and cannot be loaded'When deploying the latest version of our application to the Production server we got this error: <blockquote>Unhandled Exception: System.BadImageFormatException: Could not load file or assembly 'vsdbcmd.exe' or one of its dependencies. This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded. File name: 'vsdbcmd.exe'</blockquote> Oh god, I thought. Yet <i>more</i> VSDBCMD wierdness. But this box had SQL Server installed, so the normal <a href="">'needs SMO / Batch Parser'</a> caveats didn't apply. Eventually I ILSpy'd the assemblies to <a href="">check the bittyness</a>, and guess what! The error message was completely accurate. I'd accidentally picked up the VSDBCMD not from the VS 2008 folder (9.0) but instead from the VS 2010 folder (10.0). Which is .Net 4. Which really is a more recent version of the runtime than was installed on the Windows 2008 R2 server. Embarrasing to be caught out by a completely accurate error message (though if it listed the versions involved I might have paid attention)<img src="" height="1" width="1" alt=""/>piers7 Services 2008 R2 breaking change when deploying from the command lineAs collegues of mine will attest, I will script anything that has to be deployed. Some things are easier than others.<br /><br / <a href="">Analysis Services deployment utility</a> to do this for me, since this can supplied with command line arguments:<br /> <pre>write-host "Generating XMLA"<br />$dumpbin</a>) you'll see it's marked as a <strong>command line application</strong>:<br /><br /><pre>C:\>dumpbin /headers "C:\Program Files (x86)\Microsoft SQL Server\90\Tools\Binn\VSShell\Common7\IDE\Microsoft.AnalysisServices.Deployment.exe" | find /i "subsystem"<br /> 4.00 subsystem version<br /> 3 subsystem (Windows CUI)<br /></pre><br /><br />...but the 2008 R2 version is marked as a <strong>gui</strong> application:<br /><pre>C:\>dumpbin /headers "C:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Microsoft.AnalysisServices.Deployment.exe" | find /i "subsystem"<br /> 4.00 subsystem version<br /> 2 subsystem (Windows GUI)<br /></pre><br /.<br /><br />In this case the answer was to control the process launching, so we can explicitly decide to wait:<br /><pre><br /> start-process -FilePath:$asDeploy -ArgumentList:$asdatabase,"/d","/o:$xmla" -Wait;<br /></pre. <br />Good reference sources:<br /><a href="">Stack Overflow: Can one executable be both a console and GUI app?</a><br /><a href="">MSDN: A Tour of the Win32 Portable Executable File Format</a><br /><img src="" height="1" width="1" alt=""/>piers7 2008, virtual accounts and a breaking security change from 2005Interesting gotcha today regarding the different ways Sql 2005 and Sql 2008 grant permissions to the service account they are running under. Interesting, because the differences broke my app, and exposed my complete lack of understanding of a key Windows 2008 R2 security concept - <em>virtual accounts.</em><br />In Sql 2005, to simplfy management of the service account's permissions against SQL itself (specifically with regard to changing which account SQL is running under) the product team started creating local Windows security groups, of the form:<br /><blockquote class="tr_bq">computername\SQLServer2005MSSQLUser$computername$MSSQLSERVER</blockquote>This group is configured by the installer to contain the service account (eg Network Service), and a corresponding SQL login is created (for the windows group) granting <strong>sysadmin</strong> rights: />I'm a big fan of running services as Network Service. Not having to create explicit service accounts means less admin overhead (both creation, and password expiry maintanance) and a lower overall attack footprint for your enterprise. But there is a downside - a lack of permissions isolation between services also running as Network Service on the same box. In this case, because of the above, <em>anything else on that box that runs as Network Service is automatically sysadmin on your SQL instance</em>.<br /><br />In Sql 2008 on Windows 2008 R2 the situation is a bit different, because Windows 2008 R2 introduces so-called virtual accounts. I'm still a bit hazy on these, but one of the things this enables you to do is grant permissions to a service <em>without knowing which account it's running under</em>. The actual permissions the service has at runtime are then the union of permissions explicitly granted to the service account as well as the permissions granted <em>to the service itself</em>.<br />Which is cool. If a bit freaky at first.<br />So whilst Sql 2008 still has one of those local Windows groups created for it's service accounts, the contents of this are now, somewhat tautologically:<br /><br />NT SERVICE\MSSQL$SQL2008<br /><br /><div class="separator" style="clear: both; text-align: center;"><a href="" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="" /></a></div><div class="separator" style="clear: both; text-align: left;">...and at the database level, the group is actually ignored, and the login (and SA grant) is given directly to itself, not the group:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="" /></a></div><br />(note: i've got SQL 2008 as a non-default instance, hence the specific naming. But you get the idea).<br /><br />What does all this mean? Put simply (and somewhat recursively):<br /><ul><li><strong>Only the SQL 2008 service <em>itself </em>is setup as an adminstrator on the SQL 2008 service. </strong>The principal (service account) that runs it is not - by itself - an administrator on that instance.</li><li><strong>It is no longer the case that other applications running under the SQL Server service account are sysadmins on any SQL instances running under those same credentials.</strong></li></ul>It was the second bullet that broke my app. This is illustrative of poor original design, for sure, but giving Analysis Service carte blanche over the SQL instance on that same box seemed like a fairly safe call originally. But it exposed a really cool security improvement in Windows 2008 R2.<br /><br />In this case the problem <em>is</em> the solution: I can just go an add a grant for the virtual service account for Analysis Services, give it enough SQL permissions to do what it needs and the problem goes away.<br /><br />More on virtual accounts from the <a href="">Sql 2012 doco</a>, and from Technet articles <a href="">Managed Service Accounts (MSAs) Versus Virtual Accounts in Windows Server 2008 R2</a> and <a href="">What's New in Service Accounts</a><img src="" height="1" width="1" alt=""/>piers7 with the Kinect SDK for Windows<p>Playing with the Kinect SDK for Windows, and having a ball, but the doco is (understandably) a bit rubbish in places, or to be more specific – lacks critical details around the form that a parameter takes, where that detail is important.</p> <p>Anyway, this is my list of gotchas so far:</p> <h4>Depth Data Inverted when Player Index tracking enabled</h4> <p>Bizarrely, whether you initialize and open your depth image stream with ImageType.Depth or ImageType.DepthAndPlayerIndex makes the difference between whether what you get is ‘right way round’ or horizontally inverted.</p> <p>Inverted is generally more useful, because it matches with the ‘mirror image’ video stream. So why isn’t the stream like that always? Seems like an unnecessary inconsistency to me, and one you might want to <em>spell out in the doco</em>.</p> <h4>Different Depth Data Pixel Values when Player Index Tracking Enabled</h4> <p>When you do turn player index tracking on, the depth stream ‘pixels’ are lshifted 3 positions, leaving the lower 3 bits for the player index. This <em>is</em> documented, and I understand you’ve got to put the player index somewhere, but why not make the format consistent in both cases, and just leave the lower bits zero if tracking not enabled? Better still, why not put the (optional) player index in the high bits?</p> <p>This is especially irritating because...</p> <h4>GetColorPixelCoordinatesFromDepthPixel() Requires Bit-Shifted Input</h4> <p>The nuiCamera.GetColorPixelCoordinatesFromDepthPixel() mapping method expects the ‘depthValue’ parameter to be in the format it <em>would have been</em> if you had player tracking enabled. If you don’t, you’ll have to lshift 3 places to the left yourself, just to make it work. So depending on how you setup the runtime, the pixels from one part of the API can or can’t be passed to another part of the API. That’s poor form, if you ask me.</p> <p>Not that you’ll find that in the doco of course, least of all the parameter doco.</p> <h4>No GetDepthPixelFromColorPixelCoordinates Method</h4> <p>Ok, so I <em>understand</em> that the depth to video coordinate space translation is a lossy one, but I still don’t see why this method doesn’t exist.</p> <p>I picked up the Kinect SDK and the first thing I wanted to do was depth-clipping background removal. And the easy way to do this is to loop through the <em>video </em>pixels, and for each find the corresponding <em>depth pixel </em>and see what its depth was. And you can’t do that. </p> <p>Instead you have to loop through the <em>depth</em> pixels and call the API method to translate to video pixels, but because there are less of them compared to the video pixels, you have to paint them out as a 2x2 block, and even then there’ll be lots of video pixels you don’t processes, so many you have to run the loop twice: once to set all the video pixels to some kind of default state, and once for those that map to depth pixels to put the depth ‘on’.</p> <p>Just didn’t feel right.</p> <img src="" height="1" width="1" alt=""/>piers7 in HTML 5Ok, so it’s not actually part of HTML 5 (the spec), but conceptually at least it’s definitely part of HTML 5 (the brand).<br /><br />So what’s actually involved. Hmm. OH MY GOD IS IT THAT EASY !?<br /><code> function showMap(position) {<br />// Show a map centered at (position.coords.latitude, position.coords.longitude).<br />}<br /><br />// One-shot position request.<br />navigator.geolocation.getCurrentPosition(showMap);</code><br /><br />[from the <a href="">W3 geolocation spec</a>]<br /><br />So you just rock up to <a href="" title="">html5demos.com/geo</a> and ...<br /><a href=""><img alt="image" border="0" height="68" src="" style="background-image: none; border-width: 0px; display: inline; padding-left: 0px; padding-right: 0px; padding-top: 0px;" title="image" width="570" /></a> <br /><br />Holy crap. I won’t show you the resulting map because it shows where I live. What’s really freaky about that is <strong>this netbook doesn’t have a GPS. </strong>So either Windows 7 or IE 9 has fallen back to IP-based location inference, and somehow still got me <em>only one house out</em>.<br /><br />I’m totally freaked out.<br /><br />Anyway, the point of all this is that IE 9 is the browser for Windows Phone 7.5 (Mango), which – if it actually supports this API (and Wikipedia says <a href="">yes it does</a>) - means you can write location-aware mobile apps targeting Mango without having to ‘go native’. And for the demo I want to put together, this can only be a good thing...<img src="" height="1" width="1" alt=""/>piers7 8: First ImpressionsQ: "Your first impression? Love or hate?"<br /><br />Well that's a really good question.<br /> <br />I was always horribly dissapointed with my HP TX2 multitouch laptop, and whislt some of that was about the hardware (rubbish battery life, noisy fan), some of it was just how non-touch capable Windows 7 was to actually use. Windows Media Center achieves many of my 'media center kiosk' wants, but doesn't let me Skype or browse the web without dropping back to the desktop and so forth. Then you've got to go and find the mouse and all that crap. I realised that, like Media Center, a different usage type required a very different UI experience.<br /> <br />So in many ways what I was after was absolutely where Windows 8 is going. And (in the 30 mins I've actually played with it) I love it for that.<br /> <br />That being said, they're going to have to be really careful they don't throw the baby out with the bath water. Ok the desktop's still there for 'traditional' apps, but the Start bar is gone, as is apparently ALT-TAB task switching. And without a touch screen, that metro UI really sucks actually.<br /> <br />It'd be more than a shame if embracing a device/cloud future required ditching 10 years worth of desktop productivity, it'd be a Vista-scale corporate-desktop disaster.<img src="" height="1" width="1" alt=""/>piers7