<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>hexadecimal</title>
	<atom:link href="http://blog.hexadecimal.se/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.hexadecimal.se</link>
	<description>Being creative in the digital age</description>
	<lastBuildDate>Fri, 05 Feb 2010 19:40:51 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Day 0 and day 1 completed at PDC</title>
		<link>http://blog.hexadecimal.se/2009/11/18/day-0-and-day-1-completed-at-pdc/</link>
		<comments>http://blog.hexadecimal.se/2009/11/18/day-0-and-day-1-completed-at-pdc/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 05:36:34 +0000</pubDate>
		<dc:creator>q</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.hexadecimal.se/2009/11/18/Day0AndDay1CompletedAtPDC.aspx</guid>
		<description><![CDATA[I highly doubt that anyone will leave PDC thinking that Microsoft is aimless. They have a very clear vision, which they pursue with an almost feverish fervor. Everyone at Microsoft seems to be keenly aware of that vision, their aggressive strategy to realize that vision and how it will impact the industry in the decade [...]]]></description>
			<content:encoded><![CDATA[<p>I highly doubt that anyone will leave PDC thinking that Microsoft is aimless. They have a very clear vision, which they pursue with an almost feverish fervor. Everyone at Microsoft seems to be keenly aware of that vision, their aggressive strategy to realize that vision and how it will impact the industry in the decade to come.&#160; If I were to summarize PDC, Microsoft’s vision and their agenda, it would be <em>cloud computing</em>. According to Microsoft, computing as we know it is changing. Just as we saw the emergence of client/server based software in the 90’s, which evolved into SOA architecture in the last decade, we will see that concept taken a step further where everything is delivered as a service. Infrastructure, platforms, applications, data, you name it.</p>
<p>Microsoft has presented some compelling arguments as to why this will happen, cost benefits, architectural benefits, technical benefits, and so on. I can truly see their point. Cloud computing really is the coolest thing since sliced bread.</p>
<p>I cannot begin to convey the benefits and opportunities of a global computing cloud where everything from processing power to gigantic raw data feeds are available at everyone’s fingertips. All the world’s statistics; flight traffic information, stock markets, civic registries, motor registries, price and stock lists from manufacturers, news, periodic tables, historical data and statistics on toxic waste and energy consumption, all of it, at my disposal. This is the single largest effort to embrace the mentality of the digital generation, where consuming, remixing and publishing is as natural as breathing. This could very well change the way we use and think about information and computing in the future.</p>
<p>I am not alone in worrying about such things as data sovereignty, information ownership, data protection and standards compliance. Microsoft is taking steps to acquire the necessary certifications, such as PCI, to allow the business community to fully commit to their take on cloud computing and the Azure platform, but they’re not quite there just yet.</p>
<p>The problem is that standards such as PCI aren’t designed to be implemented on a cloud computing scenario. What is more likely to happen is that such standards will adapt to cloud computing terms and scenarios. That will take time. Until then, interconnected public and private clouds will be the name of the game.</p>
<p>For now, I’m happy to sift through all the free t-shirts and blinking beer mugs I got at the partner expo.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hexadecimal.se/2009/11/18/day-0-and-day-1-completed-at-pdc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>2 days to PDC</title>
		<link>http://blog.hexadecimal.se/2009/11/14/2-days-to-pdc/</link>
		<comments>http://blog.hexadecimal.se/2009/11/14/2-days-to-pdc/#comments</comments>
		<pubDate>Sat, 14 Nov 2009 17:42:30 +0000</pubDate>
		<dc:creator>q</dc:creator>
				<category><![CDATA[PDC]]></category>

		<guid isPermaLink="false">http://www.hexadecimal.se/2009/11/14/2DaysToPDC.aspx</guid>
		<description><![CDATA[When in Los Angeles, do take the time to enjoy the pretzel that is the Californian traffic system. After all, someone with a dry sense of humor spent a lot of time to prepare this exhilarating rollercoaster for your personal enjoyment. And remember, the car’s horn is your best friend!

]]></description>
			<content:encoded><![CDATA[<p>When in Los Angeles, do take the time to enjoy the pretzel that is the Californian traffic system. After all, someone with a dry sense of humor spent a lot of time to prepare this exhilarating rollercoaster for your personal enjoyment. And remember, the car’s horn is your best friend!</p>
<p><a href="http://www.hexadecimal.se/content/binary/WindowsLiveWriter/2daystoPDC_106D6/Los_Angeles_Traffic_System_2.png"><img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="Los_Angeles_Traffic_System" border="0" alt="Los_Angeles_Traffic_System" src="http://www.hexadecimal.se/content/binary/WindowsLiveWriter/2daystoPDC_106D6/Los_Angeles_Traffic_System_thumb.png" width="516" height="271" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hexadecimal.se/2009/11/14/2-days-to-pdc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>3 days to PDC</title>
		<link>http://blog.hexadecimal.se/2009/11/13/3-days-to-pdc/</link>
		<comments>http://blog.hexadecimal.se/2009/11/13/3-days-to-pdc/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 22:19:38 +0000</pubDate>
		<dc:creator>q</dc:creator>
				<category><![CDATA[PDC]]></category>

		<guid isPermaLink="false">http://www.hexadecimal.se/2009/11/13/3DaysToPDC.aspx</guid>
		<description><![CDATA[We finally arrived tired and bleary-eyed in LA last night after 19 excruciating hours of travel.
We did a fair bit of research before we left, and although the research encountered a multitude of opinions, everyone seemed to agree on staying well clear of an area called Inglewood. Needless to say, it was with mounting trepidation [...]]]></description>
			<content:encoded><![CDATA[<p>We finally arrived tired and bleary-eyed in LA last night after 19 excruciating hours of travel.</p>
<p>We did a fair bit of research before we left, and although the research encountered a multitude of opinions, everyone seemed to agree on staying well clear of an area called Inglewood. Needless to say, it was with mounting trepidation that we observed how our shuttle-bus from the rental-car service left LA international airport far behind, and sped off deeper and deeper into precisely that area.</p>
<p>The rental service turned out to be so far away from the airport, that our carefully printed out directions and local maps ended up being of no immediate use. </p>
<p>Eventually we managed to guess our way to the freeway, only to be greeted by the LA rush-hour traffic.</p>
<p>I kid you not; spending two hours tip-tapping the accelerator on a fiftyeleven lane wide spaghetti-freeway in rush-hour in an awkward rental-car with a way too sensitive accelerator after not having slept for 72 hours, truly is a remarkable experience! I highly recommend it!</p>
<p>The hotel we stay at is a rather cozy place on West Olympic Blvd, cuddled up against the eastern edge of Koreatown, or K–town as the natives refer to it.</p>
<p>Half an hour after arriving at the hotel, the awful memory of what passes for pizza in Sweden was pleasantly swept away by a friendly deliveryman from Domino’s. Thank you, Domino’s! My first decent pizza in over ten years!</p>
<p>Oh, while shopping today, I saw an actual LAPD squad car! After having seen these chase bad-guys all across my TV since childhood, I just had to snap an inconspicuous picture <img src='http://blog.hexadecimal.se/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p><img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="squadcar" border="0" alt="squadcar" src="http://www.hexadecimal.se/content/binary/WindowsLiveWriter/3daystoPDC_14578/squadcar_3.jpg" width="500" height="299" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hexadecimal.se/2009/11/13/3-days-to-pdc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Implementing an XML Data Provider for Oxite, Part III</title>
		<link>http://blog.hexadecimal.se/2009/06/21/implementing-an-xml-data-provider-for-oxite-part-iii/</link>
		<comments>http://blog.hexadecimal.se/2009/06/21/implementing-an-xml-data-provider-for-oxite-part-iii/#comments</comments>
		<pubDate>Sun, 21 Jun 2009 01:01:04 +0000</pubDate>
		<dc:creator>q</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Oxite]]></category>

		<guid isPermaLink="false">http://www.hexadecimal.se/2009/06/21/ImplementingAnXMLDataProviderForOxitePartIII.aspx</guid>
		<description><![CDATA[In my previous post, I detailed the outline of how I would implement the XML Data Provider for Oxite.
After some refactoring and additional coding, the class structure looks like this:

The XmlTableBase and XmlTable classes are re-usable for generic LINQ friendly XML table-like storage of classes.
Most of the “tables” in the OxiteXmlContext use the XmlTable class [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a href="http://www.hexadecimal.se/2009/06/13/ImplementingAnXMLDataProviderForOxitePartII.aspx">previous post</a>, I detailed the outline of how I would implement the XML Data Provider for Oxite.</p>
<p>After some refactoring and additional coding, the class structure looks like this:</p>
<p><a href="http://www.hexadecimal.se/content/binary/WindowsLiveWriter/ImplementinganXMLDataProviderforOxitePar_2A68/oxite-class-diagram_2.png" target="_blank"><img style="display: block; float: none; margin-left: auto; margin-right: auto; border-width: 0px;" title="oxite-class-diagram" src="http://www.hexadecimal.se/content/binary/WindowsLiveWriter/ImplementinganXMLDataProviderforOxitePar_2A68/oxite-class-diagram_thumb.png" border="0" alt="oxite-class-diagram" width="508" height="339" /></a></p>
<p>The XmlTableBase and XmlTable classes are re-usable for generic LINQ friendly XML table-like storage of classes.</p>
<p>Most of the “tables” in the OxiteXmlContext use the XmlTable class directly. Most classes which inherit from the NamedEntity base class in Oxite get handled by the OxiteEntityTable class, which adds default behavior on top of the XmlTable. Those classes which require additional logic when serializing / deserializing the entities are implemented as classes which inherit either from XmlTable or OxiteEntityTable, as shown in the class diagram above.</p>
<p>I have opted to not use the standard XML serialization classes for this, because I wanted to reuse the existing classes in the Oxite model, which aren’t decorated with any serialization attributes. This allows for the Oxite model to change somewhat without any maintenance being required for the XML Data Provider.</p>
<p>The other option had been to implement a layer on top of the Oxite model which has Xml serialization attributes, and although perhaps a better practice, it just seemed too redundant at this point.</p>
<p>Therefore I have written custom serialization and deserialization methods that use generics and reflection to achieve storage and retrieval.</p>
<p>The serialization/deserialization methods recognize all the standard value type codes in .NET, as well as Enums, Nullable&lt;T&gt;, Guid and the Uri types.</p>
<p>Basically, the deserialization process iterates all attributes and child elements of the entity element and invokes this method:</p>
<pre class="brush: csharp">private static void SetPropertyValue(object obj,
    string propertyName, object value)
{
    if (obj == null || value == null)
        return;

    PropertyInfo propertyInfo = obj.GetType().GetProperty(
        propertyName, BINDING_FLAGS);

    // Skip non-existing properties. Will be handled with
    // custom deserialization by descendant classes
    if (propertyInfo == null)
        return;

    Type propertyType = propertyInfo.PropertyType;

    // If nullable generic type, use the generic
    // parameter instead
    if (propertyType.Name == "Nullable`1")
        propertyType = propertyType.GetGenericArguments()[0];

    if (Type.GetTypeCode(propertyType) == TypeCode.Object)
    {
        if (propertyType == typeof(Guid))
            value = new Guid(value.ToString());
        else if (propertyType == typeof(Uri))
            value = new Uri(value.ToString());
        else // Skip on unknown types
            return;
    }

    if (propertyType.IsEnum)
        value = Enum.Parse(propertyType, value.ToString());

    propertyInfo.SetValue(obj, Convert.ChangeType(value,
        propertyType, CultureInfo.InvariantCulture), null);
}</pre>
<p>Most of the XML Data Provider is now complete. I opted for simplicity over completeness for the initial version, deferring caching in favor of a more straight-forward thread-safety mechanism which locks the class on operations that modify files. Currently this has the weakness of locking all file operations of the same type, regardless if they conflict or not. Two comments being saved at the same time for separate posts will be queued, despite them being saved to separate files.</p>
<p>At the moment I feel it’s more important to work out the kinks in the repository implementations and get to a point where everything works, before I polish the whole thing to a fancy shine.</p>
<div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:2828616b-0d82-4edb-bf7b-17ee870880ec" class="wlWriterEditableSmartContent" style="margin: 0px; display: inline; float: none; padding: 0px;">Technorati Tags: <a rel="tag" href="http://technorati.com/tags/VS2008">VS2008</a>,<a rel="tag" href="http://technorati.com/tags/C%23">C#</a>,<a rel="tag" href="http://technorati.com/tags/Oxite">Oxite</a>,<a rel="tag" href="http://technorati.com/tags/XML">XML</a></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.hexadecimal.se/2009/06/21/implementing-an-xml-data-provider-for-oxite-part-iii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Implementing an XML Data Provider for Oxite, Part II</title>
		<link>http://blog.hexadecimal.se/2009/06/13/implementing-an-xml-data-provider-for-oxite-part-ii/</link>
		<comments>http://blog.hexadecimal.se/2009/06/13/implementing-an-xml-data-provider-for-oxite-part-ii/#comments</comments>
		<pubDate>Sat, 13 Jun 2009 22:25:00 +0000</pubDate>
		<dc:creator>q</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Oxite]]></category>

		<guid isPermaLink="false">http://www.hexadecimal.se/2009/06/13/ImplementingAnXMLDataProviderForOxitePartII.aspx</guid>
		<description><![CDATA[In my previous post, I tackled the concept of an XML Data Provider for Oxite and outlined one possible structure for storing the data.
What I have done so far, is write some generic Linq to XML classes that do most of the heavy lifting of storing and retrieving objects using reflection, and used those to [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a href="http://www.hexadecimal.se/2009/05/03/ImplementingAnXMLDataProviderForOxitePartI.aspx">previous post</a>, I tackled the concept of an XML Data Provider for Oxite and outlined one possible structure for storing the data.</p>
<p>What I have done so far, is write some generic Linq to XML classes that do most of the heavy lifting of storing and retrieving objects using reflection, and used those to implement the repositories.</p>
<p>I have then implemented a class called OxiteXmlContext which aims to resemble a traditional Linq to SQL data context. This class has properties like Tags, Sites, Languages, Phrases and so on. These “tables” wrap up all the functionality of storing, retrieving and removing objects in an XDocument (one for each table).</p>
<p>This has allowed me to reuse some of the query logic in the Linq to SQL provider. But in many cases I have been able to greatly simplify or remove the queries entirely. This, due to the fact that the XML provider does not have a second layer of classes on top of the native Oxite model, and thus not requiring any projection.</p>
<p>The larger storages, such as posts, pages, comments and so on, where it isn’t feasible to read everything into memory and sort it out afterwards, have been split into one folder per post/page. Each folder contains separate files for body, comments and trackbacks. This is to avoid having to rewrite the post body when a new comment is added. The relations between posts, pages, tags and areas have been indexed in separate files along with creation and publish dates, status and so on. These indexes might grow a bit once post count reaches a thousand or so. Hopefully if the author is diligent enough to post thousands of posts, the author in question will also be enough of an enthusiast to invest in an SQL storage instead.</p>
<p>As you can see by this class diagram, the hierarchy is quite straightforward.</p>
<p><a href="http://www.hexadecimal.se/content/binary/WindowsLiveWriter/ImplementinganXMLDataProviderforOxitePar_124/xmlclasses_2.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="xmlclasses" border="0" alt="xmlclasses" src="http://www.hexadecimal.se/content/binary/WindowsLiveWriter/ImplementinganXMLDataProviderforOxitePar_124/xmlclasses_thumb.png" width="498" height="480" /></a> If you look closely, you’ll see a property on the OxiteXmlContext called PostHeaders. This property is actually the index and translates to a class called PostHeader. PostHeader contains, as the name indicates, header fields for the post, such as Id, Title, Status, Publish date, Tags and so on. It also contains a method called <font face="Courier New">GetPost</font>, which fetches the post from disk by reading the body.xml, comments.xml and trackbacks.xml files in the post’s folder.</p>
<p>Saving of the post is done either in whole by calling the <font face="Courier New">Save</font> method on OxiteXmlContext or by saving individual parts of it by calling the <font face="Courier New">SaveBody</font>, <font face="Courier New">SaveComments</font> or <font face="Courier New">SaveTrackbacks</font> method.</p>
<p>Less complex types, such as Site and Plugin which also contain child objects, but don’t deserve having them stored in separate files like comments for posts, instead inherit from the XmlTable class and override the serialization methods to store/retrieve these sub items from the XDocument directly.</p>
<pre class="brush: csharp" name="code">public class OxitePluginTable : XmlTable&lt;Plugin&gt;
{
    public OxitePluginTable(string baseDirectory)
        : base(baseDirectory, &quot;ID&quot;)
    {
    }

    protected override XElement ProjectEntity(TEntity entity)
    {
        XElement element = base.ProjectEntity(entity);

        Plugin plugin = (Plugin)entity;

        element.Add(new XElement(&quot;settings&quot;,
            from r in plugin.Settings.AllKeys
            select new XElement(r, plugin.Settings[r])));

        return element;
    }

    protected override TEntity ProjectEntity(XElement element)
    {
        Plugin plugin = (Plugin)base.ProjectEntity(element);
        plugin.Settings = new NameValueCollection();

        element.Element(&quot;settings&quot;).Elements().ToList().ForEach(e =&gt;
            plugin.Settings.Add(e.Name.ToString(), e.Value));

        return plugin;
    }
}</pre>
<p>As you can see by the PluginRepository, the code is strikingly similar to that of Linq to SQL, yet not quite exactly the same.</p>
<pre class="brush: csharp" name="code">public class PluginRepository : IPluginRepository
{
    private OxiteXmlContext mContext;

    public PluginRepository(Site site)
    {
        mContext = new OxiteXmlContext(site);
    }

    public IList&lt;IPlugin&gt; GetPlugins()
    {
        var query = from p in mContext.Plugins
                    orderby p.Category, p.Name
                    select p;

        return query.Cast&lt;IPlugin&gt;().ToList();
    }

    public IPlugin GetPlugin(Guid pluginID)
    {
        return mContext.Plugins.GetEntity(pluginID);
    }

    public bool GetPluginExists(Guid pluginID)
    {
        return mContext.Plugins.GetEntity(pluginID) != null;
    }

    public void Save(IPlugin plugin)
    {
        mContext.Plugins.Save(projectPlugin(plugin));
    }

    private Plugin projectPlugin(IPlugin p)
    {
        return new Plugin
        {
            Category = p.Category,
            Enabled = p.Enabled,
            ID = p.ID,
            Name = p.Name,
            Settings = p.Settings
        };
    }

    public void Save(IPlugin plugin, NameValueCollection settings)
    {
        Plugin p = projectPlugin(plugin);
        p.Settings = settings;
        mContext.Plugins.Save(p);
    }

    public NameValueCollection GetPluginSettings(Guid pluginID)
    {
        return GetPlugin(pluginID).Settings;
    }

    public void SaveSetting(Guid pluginID, string name, string value)
    {
        Plugin plugin = mContext.Plugins.GetEntity(pluginID);
        plugin.Settings[name] = value;
        mContext.Plugins.Save(plugin);
    }
}</pre>
<h4>What’s next?</h4>
<h5>IPageRepository</h5>
<p>The page repository still remains to be implemented.</p>
<h5>Caching</h5>
<p>I aim to add a simple per-process in-memory cache of entities to avoid having to fetch them from disk each time they are requested. This not only helps performance each time a page is served, but also on a lower level, since the Linq queries can result in multiple hits on the same entity, which would result in the same entity being deserialized multiple times.</p>
<h5>Tread-safety</h5>
<p>None of the classes are currently thread-safe, which they need to be in order for Oxite to be able to serve more than one visitor at a time, lest two instances try and write to the same file at the same time! I have purposefully skipped this part is I will implement this as part of the caching mechanism and refactor the repositories to go through the cache which in turn will serialize requests into the store.</p>
<p>I would really have liked to use the Concurrent classes from .NET 4.0, but I’m going to take a stab in the dark here and guess that’s not an option until next year. Which means no SpinLock either. ReaderWriterLockSlim it is!</p>
<h5>Refactoring</h5>
<p>I will refactor XmlEntityTable to inherit from XmlTable instead of XmlTableBase and reuse what is implemented on XmlTable.</p>
<p>I will try and tidy up the xml storage classes so they can be reused in other projects that need xml database-like storage.</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:f3eff90f-6827-4177-9ac3-0bda2c5224f7" class="wlWriterEditableSmartContent">Technorati Tags: <a href="http://technorati.com/tags/VSTS2008" rel="tag">VSTS2008</a>,<a href="http://technorati.com/tags/C%23" rel="tag">C#</a>,<a href="http://technorati.com/tags/Oxite" rel="tag">Oxite</a>,<a href="http://technorati.com/tags/XML" rel="tag">XML</a></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.hexadecimal.se/2009/06/13/implementing-an-xml-data-provider-for-oxite-part-ii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Another real world application of MGrammar (Oslo)</title>
		<link>http://blog.hexadecimal.se/2009/06/12/another-real-world-application-of-mgrammar-oslo/</link>
		<comments>http://blog.hexadecimal.se/2009/06/12/another-real-world-application-of-mgrammar-oslo/#comments</comments>
		<pubDate>Fri, 12 Jun 2009 22:37:23 +0000</pubDate>
		<dc:creator>q</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[MGrammar]]></category>
		<category><![CDATA[Oslo]]></category>

		<guid isPermaLink="false">http://www.hexadecimal.se/2009/06/12/AnotherRealWorldApplicationOfMGrammarOslo.aspx</guid>
		<description><![CDATA[I have received a ton of emails and questions following my previous post on MGrammar (which is a part of Oslo). Some of those have been people asking advice on how they can adopt MGrammar as a basis for a rule engine for more generic purposes than the one I provided.
So, I decided to sit [...]]]></description>
			<content:encoded><![CDATA[<p>I have received a ton of emails and questions following my <a href="http://www.hexadecimal.se/2009/03/17/ARealWorldApplicationOfMGrammarOslo.aspx">previous post</a> on MGrammar (which is a part of <a href="http://msdn.microsoft.com/en-us/oslo/default.aspx">Oslo</a>). Some of those have been people asking advice on how they can adopt MGrammar as a basis for a rule engine for more generic purposes than the one I provided.</p>
<p>So, I decided to sit down, download the latest Oslo SDK and write a new rule engine based on a DSL implemented in MGrammar.</p>
<p>Basically, what I wanted to demonstrate, was how you can create a domain specific language, in which your business analysts, end-users and grease-monkeys can express business rules in natural-like-language, which you can then feed through MGrammar and parse into something relatively coherent.</p>
<p>Consider the following typical business rules at Northwind Traders Co.:</p>
<ul>
<li>Only supervisors may place orders with a discount higher than 7% </li>
<li>The total price of a sales order must exceed the total cost. </li>
<li>Even though the designers of the software that Northwind uses had left the field <em>Credit Rating</em> on the customer records as optional, Northwind now wants it to be mandatory when adding new customers as part of their new and improved risk management strategy. </li>
</ul>
<p>Now, these rules can be expressed in many ways. Imagine that you have written a shrink-wrapped sales system which you sell from your website. You really don’t want your 2 411 customers to call you on the phone while you’re busy playing the beta of Mass Effect 2 just because they want some optional field to suddenly become a required field, or because they want to restrict the discount level for sales staff on Mondays if there’s a full moon and the employee has been with the company for less than six months and wears jeans to work. Yes, I know! Customers really do get the strangest and often misguided “requirements” into their heads.</p>
<p>And let’s be honest, you couldn’t possibly have imagined that your newest customer would [one month later] want to restrict the discount level that sales employees that wear jeans to work are allowed to give on Mondays when there’s a full moon! Yet, there they are, at your doorstep, in their tastefully chalk-streaked $2000 suits, pulling you away from pruning your blog and monitoring the Google analysis charts, wanting this very feature implemented!</p>
<p>If only you had supplied the sales software with a simple rules engine so that customers could take care of these things on their own!</p>
<h4>Constraining business objects using a natural-like language</h4>
<p>Using a domain specific language, the above bulleted rules could be expressed like this:</p>
<pre class="c#:nogutter" name="code">RuleSet Northwind
  // Max discount of 7%
  Add rule for Order that requires Discount to be
    less than or equal to &quot;0.07&quot; unless
    SalesPerson.Supervisor is true

  // Price must be gt cost
  Add rule for Order that requires TotalPrice to be
    greater than TotalCost

  // Credit rating is now a required field
  Add rule for Customer that requires CreditRating
    to not be empty
End RuleSet</pre>
<p>It’s enough like plain English, that whoever writes these rules won’t need to learn another language and syntax, only some basic rules. That, and somehow be provided with a list of what fields there are. You could provide a user interface that adds the “Add rule for” text at the beginning of each new line as the user presses the <em>enter</em> key, and have a ListBox that shows a list of business objects such as Customer, Order, Product that the user can double-click on to insert into the text at the current cursor position. Well, you get the idea.</p>
<p>Now, in your code, you may have business objects (Linq to SQL or Entities or whatever), like this:</p>
<pre class="brush: csharp" name="code">public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string CreditRating { get; set; }
}</pre>
<p>You could then implement an extension method called IsValid that will take care of all the heavy lifting for you (yes, very heavy…):</p>
<pre class="brush: csharp" name="code">public static class RuleSet
{
    public static bool IsValid(this object value)
    {
        return evaluate(value);
    }
}</pre>
<p>And invoke it like this:</p>
<pre class="brush: csharp" name="code">// Read business rules from file or blob field in database
RuleSet.Add(resourceStream);

// Create a customer
Customer c = new Customer
{
    Id = 10,
    Name = &quot;Contoso&quot;,
    CreditRating = null // &lt;- Will cause validation to fail!
};

// Will print out: Customer valid: False
Console.WriteLine(&quot;Customer valid: {0}&quot;, c.IsValid());

c.CreditRating = &quot;Excellent&quot;;

// Will print out: Customer valid: True
Console.WriteLine(&quot;Customer valid: {0}&quot;, c.IsValid());</pre>
<p>What I do, is feed the business rules along with the DSL specification through MGrammar and project the result into a class library that uses reflection to validate the rules.</p>
<p>The MGrammar needed to parse and understand the above business rules is quite simple, actually:</p>
<pre class="brush: csharp" name="code">module ObjectContraints
{
    export ObjectRules;

    language ObjectRules
    {
        // Basic tokens
        token Whitespace = (' ' | '\r' | '\n' );
        token Digit = ('0'..'9');
        token Identifier =
            ('A'..'Z' | 'a'..'z' | '.' | '_')+;
        token Linebreak = '\n' | '\r' | '\r\n';

        // Keywords
        @{Classification[&quot;Keyword&quot;]}
        token RuleSet = 'RuleSet';
        @{Classification[&quot;Keyword&quot;]}
        token End = 'End' | 'end';
        @{Classification[&quot;Keyword&quot;]}
        token AddRuleFor = 'Add rule for';
        @{Classification[&quot;Keyword&quot;]}
        token ThatRequires = 'that requires';
        @{Classification[&quot;Keyword&quot;]}
        token ToBe = 'to be';
        @{Classification[&quot;Keyword&quot;]}
        token ToNotBe = 'to not be';
        @{Classification[&quot;Keyword&quot;]}
        token Is = 'is';
        @{Classification[&quot;Keyword&quot;]}
        token IsNot = 'is not';
        @{Classification[&quot;Keyword&quot;]}
        token When = 'when';
        @{Classification[&quot;Keyword&quot;]}
        token Unless = 'unless';

        // Operators
        @{Classification[&quot;Keyword&quot;]}
        token EqualTo = 'equal to';
        @{Classification[&quot;Keyword&quot;]}
        token GreaterThan = 'greater than';
        @{Classification[&quot;Keyword&quot;]}
        token GreaterThanOrEqualTo = 'greater than or equal to';
        @{Classification[&quot;Keyword&quot;]}
        token LessThan = 'less than';
        @{Classification[&quot;Keyword&quot;]}
        token LessThanOrEqualTo = 'less than or equal to';
        @{Classification[&quot;Keyword&quot;]}
        token Empty = 'empty';
        @{Classification[&quot;Keyword&quot;]}
        token True = 'true';
        @{Classification[&quot;Keyword&quot;]}
        token False = 'false';

        // Comments
        @{Classification[&quot;Comment&quot;]}
        token CommentToken = CommentDelimited | CommentLine;
        token CommentDelimited =
          &quot;/*&quot; CommentDelimitedContent* &quot;*/&quot;;
        token CommentDelimitedContent = ^('*') | '*'  ^('/');  

        token CommentLine = &quot;//&quot; CommentLineContent*;
        token CommentLineContent
          = ^(
               '\u000A' // New Line
            |  '\u000D' // Carriage Return
            |  '\u0085' // Next Line
            |  '\u2028' // Line Separator
            |  '\u2029' // Paragraph Separator
            );  

        // Quoted values
        token QuoteDelimited =
          '&quot;' c:QuoteDelimitedContent* '&quot;' =&gt; c;
        token QuoteDelimitedContent = ^('&quot;');              

        interleave Skippable = Whitespace | Comment;
        interleave Comment = CommentToken;

        // Main syntax
        syntax Main = RuleSet name:Identifier rules:Rule* End RuleSet
            =&gt; { Name =&gt; name, Rules =&gt; rules };

        // Single rule syntax
        syntax Rule = AddRuleFor className:Identifier ThatRequires
                expression:Expression1 condition:Condition?
            =&gt; { ClassName =&gt; className, Expression =&gt; expression,
                    Condition =&gt; condition };

        syntax Expression1 = propertyName:Identifier inverse:ToBeOrNotToBe
            operation:Operation =&gt;
            { PropertyName =&gt; propertyName, Inverse =&gt; inverse,
              Comparison =&gt; operation };

        syntax Expression2 = propertyName:Identifier inverse:IsOrIsNot
            operation:Operation =&gt;
            { PropertyName =&gt; propertyName, Inverse =&gt; inverse,
              Comparison =&gt; operation };

        syntax Operation =
                  EqualTo value:Value               =&gt;
                        { Operator =&gt; &quot;Eq&quot;, Value =&gt; value }
                | GreaterThanOrEqualTo value:Value  =&gt;
                        { Operator =&gt; &quot;GtEq&quot;, Value =&gt; value }
                | GreaterThan value:Value           =&gt;
                        { Operator =&gt; &quot;Gt&quot;, Value =&gt; value }
                | LessThanOrEqualTo value:Value     =&gt;
                        { Operator =&gt; &quot;LtEq&quot;, Value =&gt; value }
                | LessThan value:Value              =&gt;
                        { Operator =&gt; &quot;Lt&quot;, Value =&gt; value }
                | Empty                             =&gt;
                        { Operator =&gt; &quot;IsEmpty&quot; }
                | True                              =&gt;
                        { Operator =&gt; &quot;IsTrue&quot; }
                | False                             =&gt;
                        { Operator =&gt; &quot;IsFalse&quot; };

        syntax Condition = c1:ConditionWhen =&gt; c1 | c2:ConditionUnless =&gt; c2;
        syntax ConditionWhen = When expression:Expression2 =&gt; expression;
        syntax ConditionUnless = Unless expression:Expression2 =&gt; expression;

        syntax ToBeOrNotToBe = ToNotBe =&gt; true | ToBe =&gt; false;
        syntax IsOrIsNot = IsNot =&gt; true | Is =&gt; false;

        syntax Value = value1:Identifier =&gt; Identifier { value1 }
                     | value2:QuoteDelimited =&gt; Literal { value2 };
    }
}</pre>
<p>That’s it!</p>
<p>The class library that evaluates the business rules is also quite simple. The core method is Evaluate which is invoked by the IsValid extension method:</p>
<pre class="brush: csharp" name="code">public bool Evaluate(object value)
{
    if (value == null)
        return false;

    if (PropertyInfo == null)
        return false;

    object propertyValue = PropertyInfo.GetValue(value, null);
    Type propertyType = PropertyInfo.PropertyType;

    bool result = false;
    switch (Operator)
    {
        case RuleOperator.Eq: result = (compare(propertyValue,
            getValue(value)) == 0); break;
        case RuleOperator.Gt: result = (compare(propertyValue,
            getValue(value)) == -1); break;
        case RuleOperator.GtEq: result = (compare(propertyValue,
            getValue(value)) &gt;= 0); break;
        case RuleOperator.IsEmpty: result =
            (compare(propertyValue, null) == 0); break;
        case RuleOperator.IsFalse: result =
            (compare(propertyValue, false) == 0); break;
        case RuleOperator.IsTrue: result =
            (compare(propertyValue, true) == 0); break;
        case RuleOperator.Lt: result =
            (compare(propertyValue, getValue(value)) == 1); break;
        case RuleOperator.LtEq: result =
            (compare(propertyValue, getValue(value)) &lt;= 0); break;
        default: return false;
    }
    return result ^ Inverse;
}</pre>
<p>In fact, instead of projecting it into an expression tree-like class library and use reflection to validate the object, you could actually emit real IL code!<br />
  <br /><em>- I’ll leave that part as an exercise for the reader <img src='http://blog.hexadecimal.se/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </em></p>
<p>Well, for now, here’s a natural-language-like business rules engine that validates objects using reflection.</p>
<p>Source code is for Visual Studio 2010 B1 with May 2009 CTP of Oslo. </p>
<p>Download source code: </p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:F60BB8FA-6F02-4999-8F5E-9DD4E92C4DA7:07db0077-bcfb-4f6d-a34c-7900156ec49c" class="wlWriterEditableSmartContent">
<div><a href="http://www.hexadecimal.se/content/binary/WindowsLiveWriter/AnotherrealworldapplicationofMGrammarOsl_37C/MGrammarDemo2.zip" target="_self">MGrammarDemo2.zip</a></div>
</div>
<p><em>Disclaimer: The source code has some limitations. It will not follow property paths (such as SalesPerson.Manager.IsSupervisor). It’s limited to simple literals and property names and the operators listed above. It is intended as a source of inspiration and not a third-party library that you can download and hook into your production code.</em></p>
</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:ace91c54-f5d0-498d-a76a-63a58e6f0572" class="wlWriterEditableSmartContent">Technorati Tags: <a href="http://technorati.com/tags/Oslo" rel="tag">Oslo</a>,<a href="http://technorati.com/tags/MGrammar" rel="tag">MGrammar</a>,<a href="http://technorati.com/tags/VSTS2010" rel="tag">VSTS2010</a>,<a href="http://technorati.com/tags/C%23" rel="tag">C#</a></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.hexadecimal.se/2009/06/12/another-real-world-application-of-mgrammar-oslo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Implementing an XML Data Provider for Oxite, Part I</title>
		<link>http://blog.hexadecimal.se/2009/05/03/implementing-an-xml-data-provider-for-oxite-part-i/</link>
		<comments>http://blog.hexadecimal.se/2009/05/03/implementing-an-xml-data-provider-for-oxite-part-i/#comments</comments>
		<pubDate>Sun, 03 May 2009 19:09:07 +0000</pubDate>
		<dc:creator>q</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Oxite]]></category>

		<guid isPermaLink="false">http://www.hexadecimal.se/2009/05/03/ImplementingAnXMLDataProviderForOxitePartI.aspx</guid>
		<description><![CDATA[In my previous post, I gave some thoughts about Oxite. Never one to sit idle, I proceeded to tackle the first item on the list.
Oxite comes with an SQL data provider, which is great. But I wanted an XML data provider, so the content could be stored like in dasBlog.
As an experiment, I created an [...]]]></description>
			<content:encoded><![CDATA[<p>In my <a href="http://www.hexadecimal.se/2009/05/02/ThisThingCalledOxite.aspx">previous post</a>, I gave some thoughts about Oxite. Never one to sit idle, I proceeded to tackle the first item on the list.</p>
<p><a href="http://www.codeplex.com/oxite">Oxite</a> comes with an SQL data provider, which is great. But I wanted an XML data provider, so the content could be stored like in dasBlog.</p>
<p>As an experiment, I created an XSD schema from the database that ships with Oxite, and implemented a class called OxiteDbContext, which serves as a cache.</p>
<pre class="brush: csharp" name="code">public static class OxiteDbContext
{
    private static OxiteDb mDatabase = new OxiteDb();
    private static string mFilename =
      HttpContext.Current.Server.MapPath(
      &quot;~/App_Data/oxite.xml&quot;);

    static OxiteDbContext()
    {
        mDatabase.ReadXml(mFilename);
    }

    public static void Save()
    {
        lock (mDatabase)
        {
            mDatabase.AcceptChanges();
            mDatabase.WriteXml(mFilename);
        }
    }

    public static OxiteDb Data
    {
        get
        {
            return mDatabase;
        }
    }
}</pre>
<p>I then copy/pasted the code from the SQL provider and re-mapped the LINQ to SQL code to the new typed DataSet, like so:</p>
<pre class="brush: csharp" name="code">public Area GetArea(string areaName)
{
    return (from a in OxiteDbContext.Data.oxite_Area
            where a.SiteID == siteID &amp;&amp; string.Compare(
            a.AreaName, areaName, true) == 0
            select ProjectArea(a)).FirstOrDefault();
}</pre>
<p>It’s not exactly impressive, as it stores the entire dataset in a single XML file, and whenever it saves anything, it re-writes the entire XML file.</p>
<p>Imagine that you have 200 MB of posts on your Blog, someone adds a comment, and the blog re-writes 200 MB on the disk. Not exactly “best practice”, but it will suffice as a first experiment.</p>
<p>A better approach would be to make more use of the disk structure, and split the schema into separate XML files, to minimize disk access.</p>
<p>One plausible structure could be like this:</p>
<p><img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="tree" border="0" alt="tree" src="http://www.hexadecimal.se/content/binary/WindowsLiveWriter/ImplementinganXMLDataProviderforOxitePar_12971/tree_3.png" width="164" height="287" /> </p>
<p>Much better! </p>
<p>Stay tuned for the next part in the series!</p>
<p>As always, source code included:</p>
<p><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:8eb9d37f-1541-4f29-b6f4-1eea890d4876:cafbb53d-4804-4a3f-a87f-c7fa9e3049dc" class="wlWriterEditableSmartContent">
<div><a href="http://www.hexadecimal.se/content/binary/WindowsLiveWriter/ImplementinganXMLDataProviderforOxitePar_12971/Oxite.LinqToXmlDataProvider.zip" target="_self">Download: Oxite.LinqToXmlDataProvider.zip</a></div>
</p>
</div>
<p><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:d81016e0-a531-4f21-a1fd-98d9c9455dfd" class="wlWriterEditableSmartContent">Technorati Tags: <a href="http://technorati.com/tags/Oxite" rel="tag">Oxite</a></div></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hexadecimal.se/2009/05/03/implementing-an-xml-data-provider-for-oxite-part-i/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>This thing called Oxite</title>
		<link>http://blog.hexadecimal.se/2009/05/02/this-thing-called-oxite/</link>
		<comments>http://blog.hexadecimal.se/2009/05/02/this-thing-called-oxite/#comments</comments>
		<pubDate>Sat, 02 May 2009 14:56:16 +0000</pubDate>
		<dc:creator>q</dc:creator>
				<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://www.hexadecimal.se/2009/05/02/ThisThingCalledOxite.aspx</guid>
		<description><![CDATA[I’ve been fiddling around with Oxite recently. Although I find it highly interesting and a lot of fun, it being based on ASP.NET MVC and all, it’s not yet mature enough to be an out-of-the-box blogging engine.
None of the shortcomings are show-stoppers as such, and it’s not intended to compete with the major actors out [...]]]></description>
			<content:encoded><![CDATA[<p>I’ve been fiddling around with <a href="http://oxite.net/">Oxite</a> recently. Although I find it highly interesting and a lot of fun, it being based on ASP.NET MVC and all, it’s not yet mature enough to be an out-of-the-box blogging engine.</p>
<p>None of the shortcomings are show-stoppers as such, and it’s not intended to compete with the major actors out there—yet.</p>
<p>Most of the issues with Oxite are little things like lack of ready-made themes, plug-ins, statistics and the ability to post images and videos to the blog via the <a href="http://en.wikipedia.org/wiki/MetaWeblog">metaweblog API</a>, instead requiring the user to mess around with FTP settings.</p>
<p>Despite the shortcomings, I’m quite excited. I’ve already picked it apart and put most of it back together (hence the lack of blog posts the past couple of weeks).</p>
<p>The first thing I did was create my own theme, tweak the styles and add menus and such. This required a whole bunch of CSS coding and some actual C# plumbing.</p>
<p><a href="http://www.hexadecimal.se/content/binary/WindowsLiveWriter/ThisthingcalledOxite_E7AC/oxite-theme_2.png"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="oxite-theme" border="0" alt="oxite-theme" src="http://www.hexadecimal.se/content/binary/WindowsLiveWriter/ThisthingcalledOxite_E7AC/oxite-theme_thumb.png" width="519" height="419" /></a> </p>
<p>What struck me as a bit quaint, was that even though you can add your own content pages (applause!), those pages don’t automatically appear in any menus or anything. You actually need to hand-edit the C# code to add links to those pages in the menus.</p>
<p>One thing that I really like about dasBlog, is that it runs without&#160; a relational database engine, such as Microsoft SQL Server, or MySQL. It operates purely on disk-based XML files. That right there just cut off 50% of the hosting fee.</p>
<p>Luckily, Oxite has a lot of extension points. Adding a data provider that is based on XML files instead of Microsoft SQL Server, <em>shouldn’t</em> be too much of a problem.</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:c34cc95b-3857-484d-9c0f-b396b7e28f91" class="wlWriterEditableSmartContent">Technorati Tags: <a href="http://technorati.com/tags/ASP.NET+MVC" rel="tag">ASP.NET MVC</a>,<a href="http://technorati.com/tags/Coding" rel="tag">Coding</a>,<a href="http://technorati.com/tags/Internet" rel="tag">Internet</a>,<a href="http://technorati.com/tags/Blogging" rel="tag">Blogging</a></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.hexadecimal.se/2009/05/02/this-thing-called-oxite/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Windows 7 RC to be released on April 30th</title>
		<link>http://blog.hexadecimal.se/2009/04/27/windows-7-rc-to-be-released-on-april-30th/</link>
		<comments>http://blog.hexadecimal.se/2009/04/27/windows-7-rc-to-be-released-on-april-30th/#comments</comments>
		<pubDate>Mon, 27 Apr 2009 18:06:32 +0000</pubDate>
		<dc:creator>q</dc:creator>
				<category><![CDATA[News]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://www.hexadecimal.se/2009/04/27/Windows7RCToBeReleasedOnApril30th.aspx</guid>
		<description><![CDATA[In a recent blog post by Brandon LeBlanc, the release of the much awaited Windows 7 RC has been confirmed to April 3oth for MSDN/TechNet subscribers and May 5th for everyone else.
As I described in a previous post, I’ve been using the Windows 7 beta since it came out. My favorite operating system before that [...]]]></description>
			<content:encoded><![CDATA[<p>In a <a href="http://windowsteamblog.com/blogs/windows7/archive/2009/04/24/windows-7-release-candidate-update.aspx">recent blog post</a> by Brandon LeBlanc, the release of the much awaited Windows 7 RC has been confirmed to April 3oth for MSDN/TechNet subscribers and May 5th for everyone else.</p>
<p>As I described in <a href="http://www.hexadecimal.se/2009/02/11/Windows7.aspx">a previous post</a>, I’ve been using the Windows 7 beta since it came out. My favorite operating system before that was Windows XP. I never liked Vista. I loved the eye candy and the new features, but I wasn’t willing to trade it for the performance and memory hit it required. Windows 7 truly is everything that Vista should have been.</p>
<p>I’ve been doing everything with and to my Windows 7 installations. I’ve coded and debugged, played games, watched movies, listened to music, installed all kinds of quirky software and utilities, and of course browsed the web. So far, it’s been the best and most solid operating system Microsoft has released since MS DOS 6.22. I mean, it’s difficult to compete with the solidity of MS DOS. After all, there wasn’t a lot in there. No pesky graphics drivers and so on. </p>
<p><em>I’ve not had a single crash since I first installed it. I’ve only had to reboot a few times after driver updates and I’ve only turned the computer off once (I was on a one week vacation). Other than that, my desktop computer has been running non-stop for almost four months without so much as a hiccup.</em></p>
<p>My laptop has far more battery life that those of my colleagues (exact same laptops, but with Windows Vista), and boots in one third of the time or less.</p>
<p>So far, after all my code-bashing and system abuse, the only problem I’ve had with Windows 7 is on my laptop, where the wireless adapter fails to recover from hibernation. Not exactly a show-stopper.</p>
<p>Both of my <a href="http://www.wacom.com/index.html">Wacom</a> tablets work perfectly. Without any special drivers, I might add. All the hardware on all my installations is accounted for, except my HP LaserJet 1000 printer. Which is mostly because HP discontinued it years ago and the newest drivers available are for 32 bit Windows XP, and I don’t want to … soil … my 64 bit installation with 32 bit XP drivers, that’s even if I could get them to work in the first place. I couldn’t get them to work in Vista, so I didn’t even bother trying in Windows 7. </p>
<p>I instead export a PDF file to an UNC drop folder, which is then picked up by a little service running on one of my servers where the printer is attached and printed from there.</p>
<p>All in all, I can but tip my hat to Microsoft, for a job very well done!</p>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:d6ac57b9-db0e-462a-aec3-9c34230a8aa9" class="wlWriterEditableSmartContent">Technorati Tags: <a href="http://technorati.com/tags/Windows" rel="tag">Windows</a></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.hexadecimal.se/2009/04/27/windows-7-rc-to-be-released-on-april-30th/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Contacting me</title>
		<link>http://blog.hexadecimal.se/2009/04/09/contacting-me/</link>
		<comments>http://blog.hexadecimal.se/2009/04/09/contacting-me/#comments</comments>
		<pubDate>Thu, 09 Apr 2009 16:24:54 +0000</pubDate>
		<dc:creator>q</dc:creator>
				<category><![CDATA[News]]></category>

		<guid isPermaLink="false">http://www.hexadecimal.se/2009/04/09/ContactingMe.aspx</guid>
		<description><![CDATA[I’ve had reports of people having trouble using the email form on my blog. I’m not sure why this is, and I’ve not been able to reproduce this problem. It could be a bug in dasBlog, or it could be due to the theme I’m using. 
Until I can confirm/sort this out, I’ve replaced the [...]]]></description>
			<content:encoded><![CDATA[<p>I’ve had reports of people having trouble using the email form on my blog. I’m not sure why this is, and I’ve not been able to reproduce this problem. It could be a bug in dasBlog, or it could be due to the theme I’m using. </p>
<p>Until I can confirm/sort this out, I’ve replaced the dasBlog email form with one of my own. I hope this will solve the problem.</p>
<p><a href="http://contact.hexadecimal.se">Send me an email</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hexadecimal.se/2009/04/09/contacting-me/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
