<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Los Techies</title><link>http://www.lostechies.com/blogs/</link><description>LosTechies.com was originally discussed a few years ago, over a couple of adult beverages whose name sounds very similar to l(D)os t(E)quies. Anyway the thought was to create a public forum where technical ideas and thoughts can be shared in the same way we all get together around a good meal and drinks. Ideas and thoughts are cultivated in discussion, and brought to fruition through professional debate and laughter. Sounds good in theory, well read our thoughts and ideas, take part in our debates and rejoice in our laughter.</description><dc:language>en-US</dc:language><generator>CommunityServer 2008.5 (Build: 30929.2835)</generator><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/LosTechies" type="application/rss+xml" /><item><title>Python Web Framework Series – Pylons Part 7: Refactoring, Deployment And Wrap-Up</title><link>http://feedproxy.google.com/~r/LosTechies/~3/6E9tFHXzi3I/python-web-series-pylons-part-7-refactoring-deployment-and-wrap-up.aspx</link><pubDate>Sat, 04 Jul 2009 12:00:00 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22631</guid><dc:creator>Ryan Svihla</dc:creator><slash:comments>5</slash:comments><description>&lt;p&gt;Lets take a look at our existing site and what we can do to clean it up and add some badly needed functionality, however that is beyond the scope of my series. So I&amp;rsquo;m going to leave some hints for the remaining functionality to get you started.&lt;/p&gt;
&lt;h3&gt;Refactoring Ideas&lt;/h3&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Replace default authkit login with custom login. HINT: make a sign-in link on your public page. then redirect to a custom login page that uses authkit. Trying it any other way will make you lose hair.&lt;/li&gt;
&lt;li&gt;Refactor database access into a class or two. This will make the db access more testable and allow you to monkey patch in different behavior later. HINT: If your controllers can avoid having to know anything about SQLAlchemy you&amp;rsquo;ve done your job.&lt;/li&gt;
&lt;li&gt;Replace return &amp;ldquo;rsvihla&amp;rdquo; in the users.py module with actual authkit user. HINT: just access pylons request object: &amp;ldquo;request.environ.get(&amp;quot;REMOTE_USER&amp;quot;)&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Create admin ui for users, with roles. HINT: look at &lt;a target="_blank" href="http://pylonsbook.com/en/1.0/simplesite-tutorial-part-3.html"&gt;Pylons Book&lt;/a&gt; for Authkit ideas here.&lt;/li&gt;
&lt;li&gt;Split threads into categories and then give the ability to respond to posts. HINT: just more controllers and views.&lt;/li&gt;
&lt;li&gt;Makes parts of your view visible depending on if a user has certain rights or not. HINT: while this is not what you&amp;rsquo;ll find in the Pylons Book I highly suggest not have gobs of if/else checks in your views. Make small functions that you can unit test easily which will change what is visible depending on role, then have your views call these. See what I did with my user.py module for a concept.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Deployment&lt;/h3&gt;
&lt;p&gt;This almost completely depends on your situation with hosting. If you are using something like &lt;a target="_blank" href="http://www.webfaction.com/"&gt;WebFaction&lt;/a&gt; you just have to upload files and follow their directions. I found it trivial to have a production site up and running with them. &lt;/p&gt;
&lt;p&gt;Now if you are using your own dedicated server or want to shrink wrap the project I suggest using Python Eggs, this is not pylons specific at all and I&amp;rsquo;ve built them for a number of other projects. There are some snags you can run into depend on your platform and how portable you want to make this but as long as your dev platform and production platform are the same all you need is &amp;ldquo;python setup.py bdist_egg&amp;rdquo; and you should have a egg file in the dist directory which can be installed with easy_install.&lt;/p&gt;
&lt;p&gt;Finally, you&amp;rsquo;ll want to build a production.ini . By and large you can copy your development.ini but you must must make your debug = false or you&amp;rsquo;ll give people access to your application in all sorts of bad ways.&amp;nbsp; Also, don&amp;rsquo;t forget to make your secret strings actually secret strings. &lt;/p&gt;
&lt;h3&gt;Overall Impressions&lt;/h3&gt;
&lt;p&gt;Things I like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pretty easy to get up and running quickly.&lt;/li&gt;
&lt;li&gt;paster and nose integration is pretty slick.&lt;/li&gt;
&lt;li&gt;being able to functional test response including view is actually nice.&amp;nbsp; Really wish I had this in Monorail as easily.&lt;/li&gt;
&lt;li&gt;Component based to the hilt. If you really don&amp;rsquo;t like something you can switch it out. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Things I don&amp;#39;t like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AuthKit is like all auth frameworks I&amp;rsquo;ve used, just a lot to make work the way I want.&lt;/li&gt;
&lt;li&gt;Too much violation of dry in the config. AuthKit being the main culprit here, while I may want to change which datasource I use, I&amp;rsquo;m not sure how helpful it is to have to select &amp;ldquo;form, cookie&amp;rdquo; for each ini file I make.&lt;/li&gt;
&lt;li&gt;Explicitly calling the view in my actions. Should have some convention over configuration here.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So I could certainly see using Pylons more once I get my own auth solution worked out, and get my own code flow working I could actually probably get work done more quickly in it than most web frameworks I&amp;rsquo;ve learned.&amp;nbsp; The majority of the time I wasted learning was dealing with authkit, in fact that took more time than everything else I studied combined.&lt;/p&gt;
&lt;p&gt;Thank you for taking the time to get this far with my posts. If you have any specifics parts you want me to dive into more depth and/or suggestions for me on the next series (which will be Pyxer with Google App Engine) let me know.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22631" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/A2BF389E31EAFC78F9FF9F733E543F1A94A1CA6C"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/A2BF389E31EAFC78F9FF9F733E543F1A94A1CA6C"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=6E9tFHXzi3I:F-C4VfBjVJA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=6E9tFHXzi3I:F-C4VfBjVJA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=6E9tFHXzi3I:F-C4VfBjVJA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=6E9tFHXzi3I:F-C4VfBjVJA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/6E9tFHXzi3I" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Python/default.aspx">Python</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Pylons/default.aspx">Pylons</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Authkit/default.aspx">Authkit</category><feedburner:origLink>http://www.lostechies.com/blogs/rssvihla/archive/2009/07/04/python-web-series-pylons-part-7-refactoring-deployment-and-wrap-up.aspx</feedburner:origLink></item><item><title>Theory Of Constraints: Productivity Metrics in Software Development</title><link>http://feedproxy.google.com/~r/LosTechies/~3/SOQ2gmRBZmE/theory-of-constraints-productivity-metrics-in-software-development.aspx</link><pubDate>Fri, 03 Jul 2009 17:38:16 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22619</guid><dc:creator>derick.bailey</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;In the past, I’ve been a true believer that software development is not really possible to measure from a productivity perspective. I was ignorant, basically. I’m now a bit wiser and I understand that software development is no different than any other product development process. We can and should measure productivity of software developers by understanding that we are building business value via functionality that the end-user wants. So, we should essentially be measuring our progress toward the end user facing functionality (as an over-simplification). &lt;/p&gt;  &lt;h3&gt;A Paper On The Theory Of Constraints&lt;/h3&gt;  &lt;p&gt;Several months ago, I wrote up a paper for an internal company effort to help define productivity metrics for software developers. This paper is largely based on the work of &lt;a href="http://agilemanagement.net/"&gt;David J. Anderson&lt;/a&gt;, in “&lt;a href="http://www.amazon.com/Agile-Management-Software-Engineering-Constraints/dp/0131424602"&gt;Agile Management For Software Engineering&lt;/a&gt;”. It also includes some of my own interpretations and understandings of the Theory of Constraints. &lt;/p&gt;  &lt;p&gt;The original intent of this paper was to facilitate the discussion of productivity and metrics in the Development Department at McLane Advanced Technologies, LLC., where I work. I decided to release it to the world, to hopefully help others understand how we can measure productivity as software developers. I did not intend this to be a comprehensive or exhaustive discussion of the points within, but am trying to spur additional research and conversations. I hope you enjoy reading it as much as I enjoyed writing it.&lt;/p&gt;  &lt;h3&gt;Download The Paper&lt;/h3&gt;  &lt;p&gt;You can download the PDF here: &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;a href="http://www.lostechies.com/media/p/22618.aspx"&gt;&lt;strong&gt;The Theory of Constraints: Productivity Metrics In Software Development&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22619" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/8B2C706DA0F7DF19BD4D8F10D4F468DE78F2BB91"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/8B2C706DA0F7DF19BD4D8F10D4F468DE78F2BB91"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=SOQ2gmRBZmE:opU10jJsLM0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=SOQ2gmRBZmE:opU10jJsLM0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=SOQ2gmRBZmE:opU10jJsLM0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=SOQ2gmRBZmE:opU10jJsLM0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/SOQ2gmRBZmE" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/Throughput/default.aspx">Throughput</category><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/E-Books/default.aspx">E-Books</category><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/Theory+Of+Constraints/default.aspx">Theory Of Constraints</category><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/Productivity/default.aspx">Productivity</category><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/Metrics/default.aspx">Metrics</category><feedburner:origLink>http://www.lostechies.com/blogs/derickbailey/archive/2009/07/03/theory-of-constraints-productivity-metrics-in-software-development.aspx</feedburner:origLink></item><item><title>How not to do Dependency Injection, in NerdDinner</title><link>http://feedproxy.google.com/~r/LosTechies/~3/2BwwdFMz5n8/how-not-to-do-dependency-injection-in-nerddinner.aspx</link><pubDate>Fri, 03 Jul 2009 16:19:29 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22612</guid><dc:creator>bogardj</dc:creator><slash:comments>36</slash:comments><description>&lt;p&gt;Checking out the &lt;a href="http://nerddinner.codeplex.com/"&gt;NerdDinner&lt;/a&gt; code the other day, I found a common Dependency Injection anti-pattern.&amp;#160; One of the core concepts of DI is that components are not responsible for locating their own dependencies.&amp;#160; The code went part of the way to full-on DI, but not quite far enough.&amp;#160; Here’s the offending code:&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;SearchController &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;Controller &lt;/span&gt;{

&lt;span style="color:#2b91af;"&gt;IDinnerRepository &lt;/span&gt;dinnerRepository;

&lt;span style="color:green;"&gt;//
// Dependency Injection enabled constructors

&lt;/span&gt;&lt;span style="color:blue;"&gt;public &lt;/span&gt;SearchController()
    : &lt;span style="color:blue;"&gt;this&lt;/span&gt;(&lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;DinnerRepository&lt;/span&gt;()) {
}

&lt;span style="color:blue;"&gt;public &lt;/span&gt;SearchController(&lt;span style="color:#2b91af;"&gt;IDinnerRepository &lt;/span&gt;repository) {
    dinnerRepository = repository;
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The second constructor is correct – the SearchController’s dependencies are passed in through the constructor.&amp;#160; This is because the IDinnerRepository is a required, or primal dependency.&amp;#160; SearchController depends on IDinnerRepository to function properly, and won’t work without it.&amp;#160; But on the first constructor, we violate DI by having the SearchController create a concrete DinnerRepository!&amp;#160; We’re now back to concrete, opaque dependencies.&amp;#160; We have a small benefit of easier testability, but we still force our controller to locate its own dependencies.&lt;/p&gt;

&lt;p&gt;So why is this a Bad Thing?&lt;/p&gt;

&lt;p&gt;For one, it’s confusing to have two constructors.&amp;#160; Why go through all the trouble of creating the IDinnerRepository interface if I’m just going to depend directly on an implementer?&amp;#160; Now what if DinnerRepository now needs some dependency?&amp;#160; What if it now needs some ILogger, security or policy dependency?&amp;#160; Do I now need to go fix all of my calls to “new”?&lt;/p&gt;

&lt;p&gt;And that’s the whole point of Dependency Injection, and the Dependency Inversion Principle.&amp;#160; I only know about my first level dependencies, and abstractions on top of that.&amp;#160; If we check out DinnerRepository, we see another issue:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;DinnerRepository &lt;/span&gt;: NerdDinner.Models.&lt;span style="color:#2b91af;"&gt;IDinnerRepository &lt;/span&gt;{

    &lt;span style="color:#2b91af;"&gt;NerdDinnerDataContext &lt;/span&gt;db = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NerdDinnerDataContext&lt;/span&gt;();&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;A private, opaque dependency to NerdDinnerDataContext.&amp;#160; If we wanted to make that opaque dependency explicit, we’d have to fix our SearchController (and all the other controllers as well).&amp;#160; It’s these kinds of ripple effects that prevent refactoring and improvement.&lt;/p&gt;

&lt;h3&gt;&lt;/h3&gt;

&lt;h3&gt;Fixing it&lt;/h3&gt;

&lt;p&gt;But we can fix this, quite easily.&amp;#160; From &lt;a href="http://www.codeplex.com/MVCContrib"&gt;MvcContrib&lt;/a&gt;, we can grab any one of the ControllerFactory implementations for the IoC container of our choice.&amp;#160; For me, that’s &lt;a href="http://structuremap.sourceforge.net/Default.htm"&gt;StructureMap&lt;/a&gt;.&amp;#160; First, we’ll need to configure StructureMap to wire up all of our dependencies.&amp;#160; The preferred way to do so is to create a Registry:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NerdDinnerRegistry &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;Registry
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;public &lt;/span&gt;NerdDinnerRegistry()
    {
        Scan(scanner =&amp;gt;
        {
            scanner.TheCallingAssembly();
            scanner.WithDefaultConventions();
        });

        ForRequestedType&amp;lt;&lt;span style="color:#2b91af;"&gt;NerdDinnerDataContext&lt;/span&gt;&amp;gt;()
            .CacheBy(&lt;span style="color:#2b91af;"&gt;InstanceScope&lt;/span&gt;.HttpContext)
            .TheDefault.Is.ConstructedBy(() =&amp;gt; &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NerdDinnerDataContext&lt;/span&gt;());
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;In the first part, we just tell StructureMap to scan the calling assembly with default conventions.&amp;#160; This will wire up IDinnerRepository to DinnerRepository.&amp;#160; Probably 99% of our dependencies will be taken care of in that one call.&amp;#160; Next, we need to wire up the NerdDinnerDataContext (for reasons we’ll see soon).&amp;#160; Since that class has multiple constructors, StructureMap likes to use the greediest dependency, with the most arguments.&amp;#160; I don’t want that, so I override it to use the no-arg constructor.&amp;#160; Finally, I cache it by HttpContext, though I could probably go Singleton if it’s expensive to instantiate.&lt;/p&gt;

&lt;p&gt;Next, I need a wrapper class to initialize StructureMap:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public static class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;IoCContainer
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;public static void &lt;/span&gt;Configure()
    {
        &lt;span style="color:#2b91af;"&gt;ObjectFactory&lt;/span&gt;.Initialize(init =&amp;gt;
        {
            init.AddRegistry&amp;lt;&lt;span style="color:#2b91af;"&gt;NerdDinnerRegistry&lt;/span&gt;&amp;gt;();
        });
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Initialize only needs to get called once per AppDomain, and all I need to do is add the NerdDinnerRegistry I created earlier.&amp;#160; I &lt;em&gt;could&lt;/em&gt; wire up everything here, but again, the preferred configuration method is through registries.&amp;#160; The next piece is to wire up ASP.NET MVC to both call our configuration method and use the StructureMapControllerFactory:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;void &lt;/span&gt;Application_Start()
{
    RegisterRoutes(&lt;span style="color:#2b91af;"&gt;RouteTable&lt;/span&gt;.Routes);

    &lt;span style="color:#2b91af;"&gt;IoCContainer&lt;/span&gt;.Configure();
    &lt;span style="color:#2b91af;"&gt;ControllerBuilder&lt;/span&gt;.Current.SetControllerFactory(&lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;StructureMapControllerFactory&lt;/span&gt;());

    &lt;span style="color:#2b91af;"&gt;ViewEngines&lt;/span&gt;.Engines.Clear();
    &lt;span style="color:#2b91af;"&gt;ViewEngines&lt;/span&gt;.Engines.Add(&lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;MobileCapableWebFormViewEngine&lt;/span&gt;());
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;I put all this in with the other MVC configuration in the Global.asax Application_Start method.&amp;#160; One final piece is to remove the extra constructors on our controller:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;DinnersController &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;Controller &lt;/span&gt;{

    &lt;span style="color:#2b91af;"&gt;IDinnerRepository &lt;/span&gt;dinnerRepository;

    &lt;span style="color:green;"&gt;//
    // Dependency Injection enabled constructors

    &lt;/span&gt;&lt;span style="color:blue;"&gt;public &lt;/span&gt;DinnersController(&lt;span style="color:#2b91af;"&gt;IDinnerRepository &lt;/span&gt;repository) {
        dinnerRepository = repository;
    }&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;And make our DinnerRepository expose its dependencies explicitly:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;DinnerRepository &lt;/span&gt;: NerdDinner.Models.&lt;span style="color:#2b91af;"&gt;IDinnerRepository &lt;/span&gt;{
    
    &lt;span style="color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;NerdDinnerDataContext &lt;/span&gt;db;

    &lt;span style="color:blue;"&gt;public &lt;/span&gt;DinnerRepository(&lt;span style="color:#2b91af;"&gt;NerdDinnerDataContext &lt;/span&gt;db)
    {
        &lt;span style="color:blue;"&gt;this&lt;/span&gt;.db = db;
    }&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Note that there are no no-arg constructors to be found!&amp;#160; When StructureMap creates a DinnersController, it will look to resolve the IDinnerRepository dependency.&amp;#160; That’s a DinnerRepository, which in turn needs the NerdDinnerDataContext.&amp;#160; But that’s all hidden from us, we never need to wire up an entire graph, as we would if we stuck to the “new” operator.&amp;#160; Just to make sure everything works, I can navigate to view upcoming dinners:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_411EA2FB.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_thumb_5F00_34149D1D.png" width="644" height="437" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;&lt;/h2&gt;

&lt;h3&gt;Wrapping it up&lt;/h3&gt;

&lt;p&gt;In the original NerdDinner code, dependency inversion was only partially implemented as the original controllers still contained a constructor that called a constructor of a concrete class.&amp;#160; To fix this, we added StructureMap to the mix, configuring ASP.NET MVC to use StructureMap to create controllers instead of the default controller factory.&amp;#160; Finally, we pushed the dependency inversion principle all the way down to our repository, removing the opaque dependencies where we found them.&amp;#160; When we finished, all of our classes exposed their dependencies explicitly through their constructor.&amp;#160; No one class knew more than one level of depth, and our controllers now properly depended exclusively on the IDinnerRepository abstraction.&lt;/p&gt;

&lt;p&gt;In the future, we can add things like logging, policies and the like to custom IDinnerRepository implementations, without needing to change any of our controllers.&amp;#160; Once we introduce inversion of control to our application, we open a lot of doors for functionality and simplicity, but only going halfway won’t give us the full benefit.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22612" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/E7F33F62DB730384803FF28D64350492B95F120F"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/E7F33F62DB730384803FF28D64350492B95F120F"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=2BwwdFMz5n8:WumYr2j9BYI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=2BwwdFMz5n8:WumYr2j9BYI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=2BwwdFMz5n8:WumYr2j9BYI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=2BwwdFMz5n8:WumYr2j9BYI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/2BwwdFMz5n8" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/Refactoring/default.aspx">Refactoring</category><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/StructureMap/default.aspx">StructureMap</category><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/07/03/how-not-to-do-dependency-injection-in-nerddinner.aspx</feedburner:origLink></item><item><title>Python Web Framework Series – Pylons: Part 6 Basic Authorization With AuthKit</title><link>http://feedproxy.google.com/~r/LosTechies/~3/j61An8i9Cxo/python-web-framework-series-pylons-part-6-authentication-and-authorization-with-authkit.aspx</link><pubDate>Fri, 03 Jul 2009 12:00:00 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22599</guid><dc:creator>Ryan Svihla</dc:creator><slash:comments>1</slash:comments><description>Last post we left off with very basic database access, and testing story completed. Now we&amp;#39;re going to look at basic Authorization and Authentication with AuthKit. NOTE: most of this post is just an aggregation of a couple of chapters in the &lt;a href="http://pylonsbook.com/en/1.0/simplesite-tutorial-part-3.html"&gt;Pylons Book&lt;/a&gt; since this setup is a good base starting point. Read the previous link to the Pylons Book for more in depth coverage of this topic.&amp;#160; &lt;h3&gt;Setting Up AuthKit&lt;/h3&gt;  &lt;p&gt;First lets make sure we have AuthKit installed: &lt;em&gt;easy_install AuthKit&lt;/em&gt;. For this post we&amp;#39;re working with AuthKit 0.4.3, your mileage may vary if you read this post in the future and are using a different version. Now that we have Authkit installed open up &lt;strong&gt;pylonsforum\config\middleware.py&lt;/strong&gt; add the following imports: &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;   &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:0e36f3d6-bf71-45bf-bf78-d6c30cc7a027" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;&lt;b&gt;authkit.authenticate&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;&lt;b&gt;authkit.permissions&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;#160;ValidAuthKitUser&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt; &lt;/p&gt;  &lt;p&gt;and then add somewhere inside the &lt;em&gt;if asbool(full_stack):&lt;/em&gt; code block.&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:0b036444-d3da-4656-a78f-7f21d223d9ae" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
permission&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;ValidAuthKitUser()&lt;br /&gt;
app&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;authorize&lt;span style="color:#666666;"&gt;.&lt;/span&gt;middleware(app,&amp;#160;permission)&lt;br /&gt;
app&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;authenticate&lt;span style="color:#666666;"&gt;.&lt;/span&gt;middleware(app,app_conf)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;in &lt;strong&gt;development.ini&lt;/strong&gt; add this to the end of your&lt;em&gt; [app:main]&lt;/em&gt; section&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:12fd82fc-e581-4566-a046-5f4fbfda3665" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;setup&lt;span style="color:#666666;"&gt;.&lt;/span&gt;enable&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;true&lt;br /&gt;
authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;setup&lt;span style="color:#666666;"&gt;.&lt;/span&gt;method&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;form,&amp;#160;cookie&lt;br /&gt;
authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;form&lt;span style="color:#666666;"&gt;.&lt;/span&gt;authenticate&lt;span style="color:#666666;"&gt;.&lt;/span&gt;user&lt;span style="color:#666666;"&gt;.&lt;/span&gt;type&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;users&lt;span style="color:#666666;"&gt;.&lt;/span&gt;sqlalchemy_driver:UsersFromDatabase&lt;br /&gt;
authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;form&lt;span style="color:#666666;"&gt;.&lt;/span&gt;authenticate&lt;span style="color:#666666;"&gt;.&lt;/span&gt;user&lt;span style="color:#666666;"&gt;.&lt;/span&gt;data&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;pylonsforum&lt;span style="color:#666666;"&gt;.&lt;/span&gt;model&lt;br /&gt;
authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;cookie&lt;span style="color:#666666;"&gt;.&lt;/span&gt;secret&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;secret&amp;#160;string&lt;br /&gt;
authkit&lt;span style="color:#666666;"&gt;.&lt;/span&gt;cookie&lt;span style="color:#666666;"&gt;.&lt;/span&gt;signoutpath&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#666666;"&gt;/&lt;/span&gt;home&lt;span style="color:#666666;"&gt;/&lt;/span&gt;signout&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;Open your home.py controller and for now add a “signout” action:&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:2cc06811-a8cf-4df3-a509-fe95dd80ef5d" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;signout&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;You&amp;#39;ve&amp;#160;been&amp;#160;signed&amp;#160;out&amp;quot;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;Now in your &lt;strong&gt;websetup.py&lt;/strong&gt; we have a ton to add to get the basic setup working. Start right after imports and add these line.&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:0631806d-df32-4901-9f17-8f78e5a5532c" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;&lt;b&gt;authkit.users.sqlalchemy_driver&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;#160;UsersFromDatabase&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;next add the following in your “setup_app” method after load_environment&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:8cbafdcf-409e-43f0-bb5e-19a168a2f984" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;&lt;b&gt;pylonsforum.model&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;#160;meta&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata&lt;span style="color:#666666;"&gt;.&lt;/span&gt;bind&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;engine&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;filename&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;os&lt;span style="color:#666666;"&gt;.&lt;/span&gt;path&lt;span style="color:#666666;"&gt;.&lt;/span&gt;split(conf&lt;span style="color:#666666;"&gt;.&lt;/span&gt;filename)[&lt;span style="color:#666666;"&gt;-&lt;/span&gt;&lt;span style="color:#666666;"&gt;1&lt;/span&gt;]&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;log&lt;span style="color:#666666;"&gt;.&lt;/span&gt;info(&lt;span style="color:#BA2121;"&gt;&amp;quot;Adding&amp;#160;the&amp;#160;AuthKit&amp;#160;model...&amp;quot;&lt;/span&gt;)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;users&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;UsersFromDatabase(model)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata&lt;span style="color:#666666;"&gt;.&lt;/span&gt;create_all(checkfirst&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;log&lt;span style="color:#666666;"&gt;.&lt;/span&gt;info(&lt;span style="color:#BA2121;"&gt;&amp;quot;Adding&amp;#160;roles&amp;#160;and&amp;#160;uses...&amp;quot;&lt;/span&gt;)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;users&lt;span style="color:#666666;"&gt;.&lt;/span&gt;user_create(&lt;span style="color:#BA2121;"&gt;&amp;quot;admin&amp;quot;&lt;/span&gt;,&amp;#160;password&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#BA2121;"&gt;&amp;quot;admin&amp;quot;&lt;/span&gt;)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;For the final piece delete your development.db file and run &lt;em&gt;paster setup.app development.ini&lt;/em&gt; to recreate it with the AuthKit user model. Now you have very basic authentication working in your site&lt;/p&gt;  &lt;p&gt;&lt;a href="http://localhost:5000"&gt;http://localhost:5000&lt;/a&gt; reveals:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/Picture2_5F00_21F07175.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="Picture 2" border="0" alt="Picture 2" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/Picture2_5F00_thumb_5F00_343BC8E8.png" width="348" height="296" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;type in “admin” for the username and password and it should let you pass.&amp;#160; Note going back to the site will not bring up a password box again.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://localhost:5000/home/signout"&gt;http://localhost:5000/home/signout&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;will remove your cookie and you’ll see the sign in form once more if you go to &lt;a href="http://localhost:5000"&gt;http://localhost:5000&lt;/a&gt; .&amp;#160; Stayed tuned for more posts as I go more in depth with the different features and customizations of AuthKit.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22599" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/79BBD282566B83AF81745798198C4ABA975F0B06"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/79BBD282566B83AF81745798198C4ABA975F0B06"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=j61An8i9Cxo:cAVv_jnp9kc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=j61An8i9Cxo:cAVv_jnp9kc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=j61An8i9Cxo:cAVv_jnp9kc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=j61An8i9Cxo:cAVv_jnp9kc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/j61An8i9Cxo" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Python/default.aspx">Python</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Pylons/default.aspx">Pylons</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Authkit/default.aspx">Authkit</category><feedburner:origLink>http://www.lostechies.com/blogs/rssvihla/archive/2009/07/03/python-web-framework-series-pylons-part-6-authentication-and-authorization-with-authkit.aspx</feedburner:origLink></item><item><title>Python Web Framework Series – Pylons: Part 5 Testing Models</title><link>http://feedproxy.google.com/~r/LosTechies/~3/UXdlqSLxks8/python-web-framework-series-pylons-part-5-testing-models.aspx</link><pubDate>Thu, 02 Jul 2009 20:09:11 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22596</guid><dc:creator>Ryan Svihla</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;When we last left of with our Pylons forum we had a had just successfully created a post, and then could immediately retrieve that same post. However, we kind of skimped on the testing story so lets fill in the gaps and do some refactoring as a bonus.&lt;/p&gt;  &lt;h3&gt;Functional Testing Models&lt;/h3&gt;  &lt;p&gt;Open your functional controller test located at &lt;strong&gt;pylonsforum\tests\functional\test_home.py&lt;/strong&gt; and add the following import line&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:ea9eb64a-87d7-44db-b556-7b0ae4bdfdc3" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;&lt;b&gt;pylonsforum.model&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;#160;Thread,&amp;#160;Post,&amp;#160;meta&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;and the following methods&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:477b4d45-bb43-409b-ac13-36373a0c94ba" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;setUp&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;remove()&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata&lt;span style="color:#666666;"&gt;.&lt;/span&gt;create_all(meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;engine)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_createpost(&lt;span style="color:#666666;"&gt;5&lt;/span&gt;)&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;_createpost&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;,times):&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;i&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#666666;"&gt;0&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/span&gt;&amp;#160;i&amp;#160;&lt;span style="color:#666666;"&gt;&amp;lt;&lt;/span&gt;&amp;#160;times:&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;i&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;i&amp;#160;&lt;span style="color:#666666;"&gt;+&lt;/span&gt;&lt;span style="color:#666666;"&gt;1&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;thread&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;Thread()&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;subject&amp;#160;&amp;quot;&lt;/span&gt;&amp;#160;&lt;span style="color:#666666;"&gt;+&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;str&lt;/span&gt;(i)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;post&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;Post()&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;post&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;posting&amp;#160;away&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;post&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;post&lt;span style="color:#666666;"&gt;.&lt;/span&gt;isparent&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts&lt;span style="color:#666666;"&gt;.&lt;/span&gt;append(post)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;add(thread)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;commit()&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;and change the test_recent_posts method to&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:5121d806-a714-43ee-8d45-ac625e97f68a" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;test_five_most_recent_threads_show_in_homepage&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;response&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;app&lt;span style="color:#666666;"&gt;.&lt;/span&gt;post(url(controller&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#BA2121;"&gt;&amp;quot;home&amp;quot;&lt;/span&gt;,&amp;#160;action&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#BA2121;"&gt;&amp;quot;index&amp;quot;&lt;/span&gt;))&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;subject&amp;#160;1&amp;quot;&lt;/span&gt;&amp;#160;&lt;span style="color:#AA22FF;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;#160;response&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;subject&amp;#160;2&amp;quot;&lt;/span&gt;&amp;#160;&lt;span style="color:#AA22FF;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;#160;response&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;subject&amp;#160;3&amp;quot;&lt;/span&gt;&amp;#160;&lt;span style="color:#AA22FF;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;#160;response&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;subject&amp;#160;4&amp;quot;&lt;/span&gt;&amp;#160;&lt;span style="color:#AA22FF;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;#160;response&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;subject&amp;#160;5&amp;quot;&lt;/span&gt;&amp;#160;&lt;span style="color:#AA22FF;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;#160;response&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;In summary here we’re adding a _createpost factory method that generates some basic test threads and parent posts. running &lt;em&gt;nosetests –-with-pylons=test.ini &lt;/em&gt;should result in failed tests.&lt;/p&gt;  &lt;h3&gt;Changing The View and Controller&lt;/h3&gt;  &lt;p&gt;Now adjust your &lt;strong&gt;index.mako &lt;/strong&gt;view to the following:&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:0603f2e8-543b-4335-bec6-bef0da5dd580" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#BC7A00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&amp;#160;&lt;span style="color:#7D9029;"&gt;name=&lt;/span&gt;&lt;span style="color:#BA2121;"&gt;&amp;quot;title()&amp;quot;&lt;/span&gt;&lt;span style="color:#BC7A00;"&gt;&amp;gt;&lt;/span&gt;Pylons&amp;#160;Forum&lt;span style="color:#BC7A00;"&gt;&amp;lt;/%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&lt;span style="color:#BC7A00;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#BC7A00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&amp;#160;&lt;span style="color:#7D9029;"&gt;name=&lt;/span&gt;&lt;span style="color:#BA2121;"&gt;&amp;quot;head_tags()&amp;quot;&lt;/span&gt;&lt;span style="color:#BC7A00;"&gt;&amp;gt;&amp;lt;/%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&lt;span style="color:#BC7A00;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;div&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#7D9029;"&gt;id=&lt;/span&gt;&lt;span style="color:#BA2121;"&gt;&amp;quot;recentposts&amp;quot;&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;table&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;&lt;/b&gt;&lt;/span&gt;subject&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;&lt;/b&gt;&lt;/span&gt;author&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;&lt;/b&gt;&lt;/span&gt;date&amp;#160;submitted&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;tbody&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#BC7A00;"&gt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt;&amp;#160;t&amp;#160;&lt;span style="color:#AA22FF;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;#160;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;threads:&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#BC7A00;"&gt;${&lt;/span&gt;t&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&lt;span style="color:#BC7A00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#BC7A00;"&gt;${&lt;/span&gt;t&lt;span style="color:#666666;"&gt;.&lt;/span&gt;parentpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&lt;span style="color:#BC7A00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#BC7A00;"&gt;${&lt;/span&gt;t&lt;span style="color:#666666;"&gt;.&lt;/span&gt;dateadded&lt;span style="color:#BC7A00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/b&gt;&lt;/span&gt;&amp;#160;&amp;#160;&lt;span style="color:#408080;"&gt;&lt;i&gt;&amp;lt;!--&amp;#160;changed&amp;#160;posts&amp;#160;properties&amp;#160;to&amp;#160;thread&amp;#160;properties&amp;#160;and&amp;#160;added&amp;#160;parentpost&amp;#160;--&amp;gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#BC7A00;"&gt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;endfor&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/tbody&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/table&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/div&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;So once you’ve changed the to using a “threads” object, added parentpost (where did that come from? I’ll get to that in minute) and changed our properties around we need to change the our &lt;strong&gt;home.py &lt;/strong&gt;controller index action for our cosmetic changes and to work with our new tests:&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:ccbbb1ad-b28d-4796-b144-7014f2be59fd" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;index&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;username&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;rsvihla&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#408080;"&gt;&lt;i&gt;#&amp;#160;removing&amp;#160;this&amp;#160;line&amp;#160;&amp;#160;&amp;#160;&amp;#160;c.posts&amp;#160;=&amp;#160;[Post(&amp;quot;jkruse&amp;quot;,&amp;#160;&amp;quot;New&amp;#160;Kindle&amp;quot;,&amp;#160;&amp;quot;06/24/2009&amp;quot;)]&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;thread_query&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;query(model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Thread)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;threads&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;thread_query&lt;span style="color:#666666;"&gt;.&lt;/span&gt;order_by(model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;dateadded&lt;span style="color:#666666;"&gt;.&lt;/span&gt;desc())&lt;span style="color:#666666;"&gt;.&lt;/span&gt;limit(&lt;span style="color:#666666;"&gt;5&lt;/span&gt;)&lt;span style="color:#666666;"&gt;.&lt;/span&gt;all()&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;#160;render(&lt;span style="color:#BA2121;"&gt;&amp;#39;index.mako&amp;#39;&lt;/span&gt;)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;So our index action now is querying for the 5 most recent threads and storing in our new c.threads context variable. Lets strip the query down into pieces.&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:1a41659f-81a5-4faa-a6a7-e259e0e7a2f4" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
thread_query&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;query(model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Thread)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;we’re working with SQLAlchemy Session object. We call then store a Thread query object inside the thread_query variable.&amp;#160; Now through the thread_query variable we can get access Thread objects stored in the database.&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:9d73b132-bd56-4889-b0d4-ebc164ad8bcb" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;threads&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;thread_query&lt;span style="color:#666666;"&gt;.&lt;/span&gt;order_by(model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;dateadded&lt;span style="color:#666666;"&gt;.&lt;/span&gt;desc())&lt;span style="color:#666666;"&gt;.&lt;/span&gt;limit(&lt;span style="color:#666666;"&gt;5&lt;/span&gt;)&lt;span style="color:#666666;"&gt;.&lt;/span&gt;all()&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;Here we call “order_by” on our query object and then pass in the Thread model specifying a descending order of the dateadded property. Next we limit it to 5 rows and then call “all()” which returns our results in a nice python “list” object.&lt;/p&gt;  &lt;h3&gt;Custom Properties on the Model&lt;/h3&gt;  &lt;p&gt;Ok so back a few paragraphs ago in the &lt;strong&gt;index.mako&lt;/strong&gt; view I stuck in a “parentpost” property on the thread, and I’m quite certain you’re wondering how I did that. So I’ve created the following class &lt;strong&gt;tests\test_model.py&lt;/strong&gt;&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:f56c8f6c-a468-4b9b-a58d-b4b3acdaabf3" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;&lt;b&gt;pylonsforum.model&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;#160;Thread,&amp;#160;Post,&amp;#160;meta&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;&lt;b&gt;pylonsforum.tests&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#666666;"&gt;*&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;&lt;b&gt;TestThreadParent&lt;/b&gt;&lt;/span&gt;(TestController):&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;_makethread&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;,&amp;#160;hasparent):&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;thread&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;Thread()&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;test&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;parentpost&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;Post()&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;parentpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;parentpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;first&amp;#160;post&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;parentpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;isparent&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;hasparent&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;childpost&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;Post()&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;childpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;childpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;childpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;isparent&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;False&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts&lt;span style="color:#666666;"&gt;.&lt;/span&gt;append(childpost)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts&lt;span style="color:#666666;"&gt;.&lt;/span&gt;append(parentpost)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;#160;thread&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;test_should_find_parent_post&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;thread&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_makethread(&lt;span style="color:#008000;"&gt;True&lt;/span&gt;)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;#160;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;parentpost&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&amp;#160;&lt;span style="color:#666666;"&gt;==&lt;/span&gt;&amp;#160;&lt;span style="color:#BA2121;"&gt;&amp;quot;first&amp;#160;post&amp;quot;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;test_should_not_find_parent_when_none_set&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;thread&amp;#160;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;_makethread(&lt;span style="color:#008000;"&gt;False&lt;/span&gt;)&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;#160;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;parentpost&amp;#160;&lt;span style="color:#AA22FF;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;None&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;Our test has a _makethread factory method (another one of those maybe time for a factory class soon!) which can make a parent post or not depending on its parameter, then two tests documenting its behavior in each situation.&lt;/p&gt;  &lt;p&gt;So I’ve gone back to our &lt;strong&gt;models\__init__.py&lt;/strong&gt; class and changed the Thread class to look like this:&lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:2c459365-15ee-44a0-965f-34e631b61cdd" class="wlWriterEditableSmartContent"&gt;&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;&lt;b&gt;Thread&lt;/b&gt;&lt;/span&gt;(&lt;span style="color:#008000;"&gt;object&lt;/span&gt;):&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#AA22FF;"&gt;@property&lt;/span&gt;&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#0000FF;"&gt;parentpost&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt;&amp;#160;p&amp;#160;&lt;span style="color:#AA22FF;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts:&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt;&amp;#160;p&lt;span style="color:#666666;"&gt;.&lt;/span&gt;isparent&amp;#160;&lt;span style="color:#666666;"&gt;==&lt;/span&gt;&amp;#160;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;:&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;#160;p&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Not the best method however its VERY interesting for static language veterans. We are searching an&lt;u&gt; instance variable that we have not even defined&lt;/u&gt;!&amp;#160; Remember only our SQLAlchemy mapper even makes mention of a “posts” variable through our relationship mapping, yet our “parentpost” property is searching through self.posts.&amp;#160; Once it finds a parent post it returns true, this is not perfect and again not the ideal way to enforce a database constraint but for a demo it works fine.&lt;/p&gt;  &lt;p&gt;Calling &lt;em&gt;nosetests –-with-pylons=test.ini&lt;/em&gt; should now give you all passing tests&lt;em&gt;. &lt;/em&gt;Running &lt;em&gt;paster serve –-reload development.ini&lt;/em&gt; and opening &lt;a href="http://localhost:5000"&gt;http://localhost:5000&lt;/a&gt; , adding a couple of threads and you should have something that looks like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/Picture1_5F00_6219E7BC.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="Picture 1" border="0" alt="Picture 1" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/Picture1_5F00_thumb_5F00_71505089.png" width="610" height="410" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;h3&gt;Summary&lt;/h3&gt;  &lt;p&gt;We’ve completed a home page now that has some dynamic data, added a custom property on our database class, and addressed functional testing with models.&amp;#160; &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22596" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/CB2DEC411ED7070D5D8A78108CAA5F2EC3094343"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/CB2DEC411ED7070D5D8A78108CAA5F2EC3094343"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=UXdlqSLxks8:PpjGPbJYjnU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=UXdlqSLxks8:PpjGPbJYjnU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=UXdlqSLxks8:PpjGPbJYjnU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=UXdlqSLxks8:PpjGPbJYjnU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/UXdlqSLxks8" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Python/default.aspx">Python</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Pylons/default.aspx">Pylons</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/SqlAlchemy/default.aspx">SqlAlchemy</category><feedburner:origLink>http://www.lostechies.com/blogs/rssvihla/archive/2009/07/02/python-web-framework-series-pylons-part-5-testing-models.aspx</feedburner:origLink></item><item><title>Congrats to the Los Techies MVPs!</title><link>http://feedproxy.google.com/~r/LosTechies/~3/y8UtGr1BzMI/congrats-to-the-los-techies-mvps.aspx</link><pubDate>Thu, 02 Jul 2009 01:03:38 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22574</guid><dc:creator>bogardj</dc:creator><slash:comments>5</slash:comments><description>&lt;p&gt;This morning, I and fellow Los Techies alumni Eric Hexter and Chris Patterson learned that we are MVPs!&amp;#160; Well, technically I learned last night through an IM of a re-tweet of my MVP lead, but hey, close enough, right?&amp;#160; I know it’s cheesy, but I think these awards are a testament to the great community Los Techies has built over the years, so for me, this is really an award for Los Techies.&amp;#160; The roundup includes:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Jimmy Bogard, MVP ASP.NET&lt;/li&gt;    &lt;li&gt;Eric Hexter, MVP ASP.NET&lt;/li&gt;    &lt;li&gt;Chris Patterson, MVP C#&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Personally, I’ve viewed my community involvement as simply a desire to share my journey with others, and in turn learn where others have been and are going.&amp;#160; My favorite experiences thus far have been the open space conferences, book clubs, dojos and code camps, as it gives me a great chance to meet and talk with a lot of smart people.&amp;#160; Thanks again everyone!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22574" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/E54FF461465AA6808C18EFEA136C22695F9A5152"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/E54FF461465AA6808C18EFEA136C22695F9A5152"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=y8UtGr1BzMI:Y9ldva2pZcQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=y8UtGr1BzMI:Y9ldva2pZcQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=y8UtGr1BzMI:Y9ldva2pZcQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=y8UtGr1BzMI:Y9ldva2pZcQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/y8UtGr1BzMI" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/Misc/default.aspx">Misc</category><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/07/01/congrats-to-the-los-techies-mvps.aspx</feedburner:origLink></item><item><title>I'm a Microsoft C# MVP!</title><link>http://feedproxy.google.com/~r/LosTechies/~3/uG78bS9JZmk/i-m-a-microsoft-c-mvp.aspx</link><pubDate>Thu, 02 Jul 2009 00:14:35 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22573</guid><dc:creator>Chris Patterson</dc:creator><slash:comments>3</slash:comments><description>&lt;p&gt;Opening my Inbox this morning resulted in a pleasant surprise from Microsoft. I have been presented with the 2009 Microsoft&amp;reg; MVP Award as a recognition for sharing my expertise in Visual C# with others. It is an honor to be recognized by Microsoft for doing something that I truly enjoy - building really cool software.&lt;/p&gt;

&lt;div style="text-align:center;"&gt;&lt;img src="http://blog.phatboyg.com/wp-content/uploads/2009/07/mvpbanner.png" alt="MVPbanner.png" border="0" width="584" height="108" /&gt;&lt;/div&gt;

&lt;p style="text-align:center;"&gt;&lt;blockquote&gt;&lt;em&gt;Microsoft Most Valuable Professionals (MVPs) are exceptional technical community leaders from around the world who are awarded for voluntarily sharing their high quality, real world expertise in offline and online technical communities. Microsoft MVPs are a highly select group of experts that represents the technical community&amp;#39;s best and brightest, and they share a deep commitment to community and a willingness to help others.&lt;/em&gt;&lt;/blockquote&gt;
&lt;/p&gt;
&lt;p&gt;A community-based award like this would not be possible without the support of my peers, and I look forward to meeting up with some of those very peers at the next MVP Summit! In the meantime, congratulations to all the new and renewed MVPs!&lt;/p&gt;

&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22573" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/9CC583EB0100C0BA41E79953AD16B179E80E054D"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/9CC583EB0100C0BA41E79953AD16B179E80E054D"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=uG78bS9JZmk:QtBrWP3TQxA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=uG78bS9JZmk:QtBrWP3TQxA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=uG78bS9JZmk:QtBrWP3TQxA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=uG78bS9JZmk:QtBrWP3TQxA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/uG78bS9JZmk" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/chris_patterson/archive/tags/.net/default.aspx">.net</category><category domain="http://www.lostechies.com/blogs/chris_patterson/archive/tags/c_2300_/default.aspx">c#</category><feedburner:origLink>http://www.lostechies.com/blogs/chris_patterson/archive/2009/07/01/i-m-a-microsoft-c-mvp.aspx</feedburner:origLink></item><item><title>Updated TDD Productivity Plug-in for Resharper</title><link>http://feedproxy.google.com/~r/LosTechies/~3/pdyTCOQY5Hk/updated-tdd-productivity-plug-in-for-resharper.aspx</link><pubDate>Wed, 01 Jul 2009 03:41:03 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22550</guid><dc:creator>erichexter</dc:creator><slash:comments>9</slash:comments><description>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;I first want to thank JetBrains for being pretty awesome.&amp;#160; I have complained a lot about how they are constantly chaining their APIs to Resharper and as a result it makes keeping plugins very hard to maintain but they went way out of their way to help.&amp;#160; I received and email from one of their developers offering to help on my plugin.&amp;#160; Their was a change made in the latest version of resharp which made my plugin incompatible&amp;#160; and their telemetry showed them a pattern with this problem.&amp;#160; Just this week they made a commit to the source code and updated the project.&amp;#160; I did not have the time to get into the internals of this change and I was really motivated by their help.&lt;/p&gt;  &lt;p&gt;As a result, if you were using the plugin I recommend you download the latest version and install it!&lt;/p&gt;  &lt;h4&gt;&lt;a href="http://code.google.com/p/resharper-tdd-productivity-plugin/" target="_blank"&gt;Download it Here&lt;/a&gt;&lt;/h4&gt;  &lt;p&gt;For those of you who do not use it yet I will run down the features that are available.&lt;/p&gt;  &lt;h3&gt;1. Code forward, create a class in a referenced project.&lt;/h3&gt;  &lt;p&gt;When prompted with Quick Fixes for a non-existent class You get the following menu.&amp;#160; This adds menu items to create the class in all referenced projects.( If this menu does not show up… you may need to add the project references to you unit test project).&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_1CA2EF1F.png" width="1028" height="404" /&gt; &lt;/p&gt;  &lt;p&gt;After selecting a menu item.&amp;#160; The class is created in the project you selected but the IDE stays in your test class.&amp;#160; And you are prompted with the quick fix for adding the using for your classes namespace.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_4C7D90E0.png" width="1028" height="627" /&gt; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;The class file is created in the corresponding project under the correct folder and namespace.&amp;#160; It is that easy!&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_03776F1A.png" width="644" height="465" /&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;h3&gt;2. Move Class/Interface to referenced project&lt;/h3&gt;  &lt;p&gt;If you prefer working with your Class or Interface under test in the same file as your test class and move the class to your referenced project after you get your tests passing this feature will reduce the number of steps it takes to move the class to the referenced project. This eliminates the need to fumble around in the Solution Explorer window.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_2F47C309.png" width="1028" height="272" /&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22550" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/9737C63EEBC4C5D0787A727512E08389701E1A2C"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/9737C63EEBC4C5D0787A727512E08389701E1A2C"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=pdyTCOQY5Hk:Zv9tp0udRNI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=pdyTCOQY5Hk:Zv9tp0udRNI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=pdyTCOQY5Hk:Zv9tp0udRNI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=pdyTCOQY5Hk:Zv9tp0udRNI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/pdyTCOQY5Hk" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/hex/archive/tags/c_2300_/default.aspx">c#</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/agile/default.aspx">agile</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/testing/default.aspx">testing</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Tools/default.aspx">Tools</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Open+Source+Software/default.aspx">Open Source Software</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Unittests/default.aspx">Unittests</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Resharper/default.aspx">Resharper</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/TDD/default.aspx">TDD</category><feedburner:origLink>http://www.lostechies.com/blogs/hex/archive/2009/06/30/updated-tdd-productivity-plug-in-for-resharper.aspx</feedburner:origLink></item><item><title>Opinionated Input Builders – Part 9 override the default Date Time picker</title><link>http://feedproxy.google.com/~r/LosTechies/~3/DF5TGGyd_X8/opinionated-input-builders-part-9-override-the-default-date-time-picker.aspx</link><pubDate>Tue, 30 Jun 2009 13:07:23 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22523</guid><dc:creator>erichexter</dc:creator><slash:comments>7</slash:comments><description>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/09/opinionated-input-builders-for-asp-net-mvc-using-partials-part-i.aspx"&gt;Part 1 – Overview&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/09/opinionated-input-builders-for-asp-net-mvc-part-2-html-layout-for-the-label.aspx"&gt;Part 2 – the Labe&lt;/a&gt;l &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/10/opinionated-input-builders-for-asp-net-mvc-part-3-the-source-code.aspx"&gt;Part 3 – the Source Code&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/10/opinionated-input-builders-for-asp-net-mvc-part-3-the-partial-view-inputs.aspx"&gt;Part 4 – the Partial View&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/10/opinionated-input-builders-for-asp-net-mvc-part-5-the-required-input.aspx"&gt;Part 5 – the Required Field Indicator&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/13/opinionated-input-builders-part-6-performance-of-the-builders.aspx"&gt;Part 6 – the Performance&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/14/opinionated-input-builders-part-7-more-on-performance-take-2.aspx"&gt;Part 7 – the Performance Take 2&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.lostechies.com/blogs/hex/archive/2009/06/17/opinionated-input-builders-part-8-the-auto-form.aspx"&gt;Part 8 – the AutoForm&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Part 9 – override the default Date Time Picker&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I received a comment from Scott Hanselman about how would a better date time picker look using the opinionated input builders.&amp;#160; I knew that this would be a complex problem just for the fact that there are currently very few good solutions to this problem now.&amp;#160; While JQuery provides a great Date picker I am not very happy with the time picker.&amp;#160; So&amp;#160; here is a version of what this could look like.&amp;#160; What I like about this approach is that it takes all the complexity including the multiple form elements and javascript and pushes it to a small partial that can be easily reused as well as it could be easily tested using QUnit.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;The user interface I came up with is a combination of the Jquery UI datepicker and a set of dropdowns to select the time.&amp;#160; I trimmed down the minute select box so that it only contains fifteen minute increments for this example.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_393D72DF.png" width="616" height="174" /&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;In order to implement this I added a call to the Partial( ) method and passed in the name of my opinion for how a datetime should be rendered.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_69844795.png" width="1145" height="167" /&gt; &lt;/p&gt;  &lt;p&gt;The next step was to add a partial control with the same name to my Shared view folder.&amp;#160; This could have been placed in the Home folder if I only wanted to have this input available for that controller.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_1D4C3DE7.png" width="245" height="357" /&gt; &lt;/p&gt;  &lt;p&gt;The code for the Partial view looks like the following. The view page is strongly typed to a DateTime model property. Than comes some jquery to pull it all together. &lt;/p&gt;  &lt;p&gt;I rendered a hidden field, this field will be used to databind when being posted back to my Save Action.&amp;#160; The other elements I appended some fixed names so that I can wire up an event that updates the hidden field when any of the values of the dropdowns or the date pickker text box changes.&amp;#160; I also write a dynamice method named after the input field in order to reduce the client side code.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/hex/image_5F00_75398EC7.png" width="1028" height="429" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;This is one approach to solve this problem,&amp;#160; if you did not want to include this javascript and do the client side wire up of updating the hidden field this same work could be done in a Custom Model Binder that is wired up for DateTime objects that could look for fields with these names and than it could do the formatting.&amp;#160; So there you go a few ways to tackle this problem.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22523" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/E72FEFEADC7AC48F1FE1229B9D006C6C5BCB42BE"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/E72FEFEADC7AC48F1FE1229B9D006C6C5BCB42BE"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=DF5TGGyd_X8:WVMHxrzjOV8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=DF5TGGyd_X8:WVMHxrzjOV8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=DF5TGGyd_X8:WVMHxrzjOV8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=DF5TGGyd_X8:WVMHxrzjOV8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/DF5TGGyd_X8" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/hex/archive/tags/c_2300_/default.aspx">c#</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/mvc/default.aspx">mvc</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/mvccontrib/default.aspx">mvccontrib</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Asp.Net/default.aspx">Asp.Net</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/.Net/default.aspx">.Net</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Asp.Net+MVC/default.aspx">Asp.Net MVC</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/OSS/default.aspx">OSS</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/Open+Source+Software/default.aspx">Open Source Software</category><category domain="http://www.lostechies.com/blogs/hex/archive/tags/CoC/default.aspx">CoC</category><feedburner:origLink>http://www.lostechies.com/blogs/hex/archive/2009/06/30/opinionated-input-builders-part-9-override-the-default-date-time-picker.aspx</feedburner:origLink></item><item><title>How we do MVC – View models</title><link>http://feedproxy.google.com/~r/LosTechies/~3/_fYk6Mp_QV0/how-we-do-mvc-view-models.aspx</link><pubDate>Tue, 30 Jun 2009 03:06:36 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22505</guid><dc:creator>bogardj</dc:creator><slash:comments>29</slash:comments><description>&lt;p&gt;A while back, I went over a few of the patterns and opinions we’ve gravitated towards on our current large-ish ASP.NET MVC project, or, &lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/04/24/how-we-do-mvc.aspx"&gt;how we do MVC&lt;/a&gt;.&amp;#160; Many of these opinions were forged the hard way, by doing the wrong thing many times until we found the “right” opinion.&amp;#160; Of course, many of these opinions are only really valid in the constraints of our project.&amp;#160; While the domain of this project isn’t important, here are some key aspects to consider:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;AJAX is used very, very sparingly.&amp;#160; Section 508 compliance is required&lt;/li&gt;    &lt;li&gt;XHTML compliance is also required&lt;/li&gt;    &lt;li&gt;XHTML DTD validation is also required&lt;/li&gt;    &lt;li&gt;All (well, 99%) operations revolve a single uber-entity.&amp;#160; Think customer relationship management, where everything you do deals with exactly one customer&lt;/li&gt;    &lt;li&gt;Snippets of information repeated across many screens&lt;/li&gt;    &lt;li&gt;Screens are either edit, or view, but never both.&amp;#160; (99% never)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Given these constraints, these opinions may or may not apply to the project you work on.&amp;#160; Again, patterns are all about tradeoffs, benefits and liabilities.&amp;#160; But, opinionated software is like building a bullet train.&amp;#160; It goes extremely fast, but only in the direction you build it.&lt;/p&gt;  &lt;p&gt;That said, I’m going to go over some of the main aspects of our MVC usage in a series of posts – starting with ViewModels.&lt;/p&gt;  &lt;h3&gt;ViewModel design&lt;/h3&gt;  &lt;p&gt;For our application, the ViewModel is a central aspect of our MVC architecture.&amp;#160; One of the first dilemmas facing MVC developers is to decide what the “M” in MVC means in ASP.NET MVC.&amp;#160; In Rails, this is fairly clear, the M is ActiveRecord (by default).&amp;#160; But in ASP.NET MVC, the “M” is silent!&amp;#160; Its out-of-the-box architecture offers no guidelines nor advice on what the M should be.&amp;#160; Should it be an entity?&amp;#160; Data access object?&amp;#160; DTO?&amp;#160; Something else?&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Sidenote – the term DTO is far overused.&amp;#160; DTO is a &lt;a href="http://martinfowler.com/eaaCatalog/dataTransferObject.html"&gt;Data Transfer Object&lt;/a&gt;.&amp;#160; The pattern describes the usage, not the shape of a type.&amp;#160; Just because an object is all properties and no methods does NOT mean it’s a DTO.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;For us, the ViewModel is inextricably linked to Views, which leads us to our first rule:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Rule #1 – All Views are strongly-typed&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I think I’ve gone over this one enough, as I really can’t stand magic strings and loose contracts.&amp;#160; A dictionary as ViewModel is a very loose contract between the Controller and View.&amp;#160; While on rare occasions we still need to pass information in the dictionary part, we’ve limited this to supporting information to help render some of the lower-level pieces of the View, and are used for some “plumbing” pieces, these pieces do not show up in our Controller action nor are they visible when you design the view.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Rule #2 – For each ViewModel type, there is defined exactly one strongly typed View&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;We’ll get into how we do this soon, but this rule has a lot of implications:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;ViewModel types are distinct from our Domain Model types&lt;/li&gt;    &lt;li&gt;The choice of what View to show can be decided strictly on the shape of your ViewModel&lt;/li&gt;    &lt;li&gt;Re-used pieces in a View (through Partials) can be decided through re-using ViewModel types&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_05CE4D53.png"&gt;&lt;img title="image" style="border-right:0px;border-top:0px;display:inline;border-left:0px;border-bottom:0px;" height="153" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_thumb_5F00_6C664A18.png" width="425" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;On the first point, we never pass an Domain Model entity straight into the view.&amp;#160; Most of the time, we only show a slice of information from a single entity.&amp;#160; And many other times, the same snippet is shown in many places.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Rule #3 – The View dictates the design of the ViewModel.&amp;#160; Only what is required to render a View is passed in with the ViewModel.&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;If a Customer object has fifty properties, but one component only shows their name, then we create a custom ViewModel type with &lt;em&gt;only those two properties&lt;/em&gt;.&amp;#160; Because we only have one ViewModel type per View, we shape our ViewModel around only what is displayed (or used) in that View.&amp;#160; Why is this a Good Thing?&lt;/p&gt;  &lt;p&gt;For one, just having a ViewModel points us to the right View.&amp;#160; We need any other information other than your ViewModel type to pick the correct View.&amp;#160; This also means we no longer need to concern ourselves with locating views by some arbitrary name, as the ViewModel &lt;em&gt;is&lt;/em&gt; the View.&amp;#160; Things like RenderPartial, which I have to select a name, become rather pointless at that point.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Rule #4 – The ViewModel contains only data and behavior related to the View&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;For the most part, our ViewModel contains only data.&amp;#160; Most, if not all aggregations/calculations or shaping is done through our Domain Model.&amp;#160; But occasionally, we have View-specific behavior or information, and that rightly belongs on our ViewModel.&lt;/p&gt;  &lt;p&gt;We’ve looked at how we design our ViewModel and what it looks like, but how does it get there?&amp;#160; If we create all these distinct ViewModel types separate from our Domain Model, didn’t we just create a bunch of work for ourselves?&amp;#160; We thought so too, which is why we developed &lt;a href="http://automapper.codeplex.com/"&gt;AutoMapper&lt;/a&gt; on this project.&lt;/p&gt;  &lt;h3&gt;Building the ViewModel&lt;/h3&gt;  &lt;p&gt;When we introduced AutoMapper into our MVC pipeline, we had a real problem.&amp;#160; Do Controllers need to do the mapping between Domain Model and ViewModel in each action method?&amp;#160; That becomes rather annoying for unit testing, as the mapping operation could warp things to a state that it becomes difficult to pull things back out.&amp;#160; For example, or EditModels (ViewModels for forms) are very string-y, where DateTimes, Ints, Decimals etc are represented as strings.&amp;#160; This comes from us using Castle Validators (future post, I promise) for validation.&amp;#160; &lt;/p&gt;  &lt;p&gt;So more moving parts, a dependency across &lt;em&gt;all&lt;/em&gt; controllers?&amp;#160; No, mapping in our Controller action just won’t do.&amp;#160; Instead, we’ll use an Action Filter to do the work for us:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_2510F426.png"&gt;&lt;img title="image" style="border-right:0px;border-top:0px;display:inline;border-left:0px;border-bottom:0px;" height="209" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/jimmy_5F00_bogard/image_5F00_thumb_5F00_1D1951C4.png" width="744" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;A request comes in, handled by an Action.&amp;#160; The Action does its thing, ultimately deciding how to respond to the request.&amp;#160; In many cases, this means rendering a view (ViewResult).&amp;#160; From there, our Action Filter comes into play.&amp;#160; On our Action method, we decorate it with an AutoMap attribute to configure the source/destination type pair to be mapped:&lt;/p&gt;  &lt;pre class="code"&gt;[&lt;span style="color:#2b91af;"&gt;AutoMap&lt;/span&gt;(&lt;span style="color:blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;Product&lt;/span&gt;), &lt;span style="color:blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;ShowProduct&lt;/span&gt;))]
&lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;ActionResult &lt;/span&gt;Details(&lt;span style="color:blue;"&gt;int &lt;/span&gt;id)
{
    &lt;span style="color:blue;"&gt;var &lt;/span&gt;product = _productRepository.GetById(id);

    &lt;span style="color:blue;"&gt;return &lt;/span&gt;View(product);
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Very trivial, yes, but here we see that we still use the strongly-typed version of the View method, so that means that our model on the Action side, which I call the Presentation Model (feel free to pick a better name), is the strongly-typed ViewModel &lt;em&gt;for the moment&lt;/em&gt;.&amp;#160; The Presentation Model, which the Action creates, can be an entity, an aggregate root, or some other &lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/02/04/ddd-aggregate-component-pattern-in-action.aspx"&gt;custom aggregate component&lt;/a&gt; that we build up.&lt;/p&gt;

&lt;p&gt;From there, we decorated our action with a filter that specified we need to map from Product to ShowProduct.&amp;#160; Why do we have to specify the source type?&amp;#160; Well, many ORMs, including NHibernate, rely on proxy types for things like lazy loading.&amp;#160; Instead of relying on the runtime type, we’ll explicitly specify our source type directly.&amp;#160; This also helps us later in testing, as we can whip through all of our controller actions using reflection, and test to make sure the source/destination type specified is actually configured.&lt;/p&gt;

&lt;p&gt;The filter attribute is very simple:&lt;/p&gt;

&lt;pre class="code"&gt;[&lt;span style="color:#2b91af;"&gt;AttributeUsage&lt;/span&gt;(&lt;span style="color:#2b91af;"&gt;AttributeTargets&lt;/span&gt;.Method, AllowMultiple = &lt;span style="color:blue;"&gt;false&lt;/span&gt;)]
&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;AutoMapAttribute &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;ActionFilterAttribute
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;_sourceType;
    &lt;span style="color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;_destType;

    &lt;span style="color:blue;"&gt;public &lt;/span&gt;AutoMapAttribute(&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;sourceType, &lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;destType)
    {
        _sourceType = sourceType;
        _destType = destType;
    }

    &lt;span style="color:blue;"&gt;public override void &lt;/span&gt;OnActionExecuted(&lt;span style="color:#2b91af;"&gt;ActionExecutedContext &lt;/span&gt;filterContext)
    {
        &lt;span style="color:blue;"&gt;var &lt;/span&gt;filter = &lt;span style="color:blue;"&gt;new &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;AutoMapFilter&lt;/span&gt;(SourceType, DestType);

        filter.OnActionExecuted(filterContext);
    }

    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;SourceType
    {
        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;_sourceType; }
    }

    &lt;span style="color:blue;"&gt;public &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;DestType
    {
        &lt;span style="color:blue;"&gt;get &lt;/span&gt;{ &lt;span style="color:blue;"&gt;return &lt;/span&gt;_destType; }
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;We simply capture the types and delegate to the real action filter for the work.&amp;#160; This is again because I believe in separating metadata in attributes from the behavior they perform.&amp;#160; Attributes just don’t work well for behavior.&amp;#160; Instead, I’ll create a separate action filter:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color:blue;"&gt;public class &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;AutoMapFilter &lt;/span&gt;: &lt;span style="color:#2b91af;"&gt;BaseActionFilter
&lt;/span&gt;{
    &lt;span style="color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;_sourceType;
    &lt;span style="color:blue;"&gt;private readonly &lt;/span&gt;&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;_destType;

    &lt;span style="color:blue;"&gt;public &lt;/span&gt;AutoMapFilter(&lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;sourceType, &lt;span style="color:#2b91af;"&gt;Type &lt;/span&gt;destType)
    {
        _sourceType = sourceType;
        _destType = destType;
    }

    &lt;span style="color:blue;"&gt;public override void &lt;/span&gt;OnActionExecuted(&lt;span style="color:#2b91af;"&gt;ActionExecutedContext &lt;/span&gt;filterContext)
    {
        &lt;span style="color:blue;"&gt;var &lt;/span&gt;model = filterContext.Controller.ViewData.Model;

        &lt;span style="color:blue;"&gt;object &lt;/span&gt;viewModel = &lt;span style="color:#2b91af;"&gt;Mapper&lt;/span&gt;.Map(model, _sourceType, _destType);

        filterContext.Controller.ViewData.Model = viewModel;
    }
}&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The BaseActionFilter is just a class that implements the various filter methods as virtual members, so I can override just the ones I need to use.&amp;#160; The AutoMapFilter pulls the original PresentationModel out of ViewData, performs the mapping operation, and puts the mapped ViewModel into the ViewData.Model property.&amp;#160; From there, the strongly-typed view for our specified ViewModel type is rendered.&lt;/p&gt;

&lt;p&gt;Because AutoMapper can flatten source types, we often find our ViewModel to simply follow a property chain for various pieces of information.&amp;#160; Again, we let our View shape that piece.&amp;#160; If we decide not to flatten, it’s usually because we’re creating a partial that re-uses a ViewModel type across other parent ViewModel types.&lt;/p&gt;

&lt;h3&gt;&lt;/h3&gt;

&lt;h3&gt;Wrapping it up&lt;/h3&gt;

&lt;p&gt;Designing ViewModels is quite ambiguous with MVC, as the shipped platform doesn’t offer any guidance or opinions in that area.&amp;#160; But by forming rules around our ViewModel, we can create a path and direction for our innovation.&amp;#160; Our rules are designed to strengthen the relationship between the View and the Model, with a concept of ViewModel – a Model designed exclusively for exactly one View.&lt;/p&gt;

&lt;p&gt;In the next post, we’ll look at designing our views – for both viewing and editing data, and how we’ve crafted opinionated HTML builders to eliminate a lot of duplication and enforce standardization.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22505" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/93A72CA986AAB383E2411DC9E51C3B228EF4DFA4"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/93A72CA986AAB383E2411DC9E51C3B228EF4DFA4"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=_fYk6Mp_QV0:qM44NXGkt8o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=_fYk6Mp_QV0:qM44NXGkt8o:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=_fYk6Mp_QV0:qM44NXGkt8o:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=_fYk6Mp_QV0:qM44NXGkt8o:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/_fYk6Mp_QV0" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/ASP.NET+MVC/default.aspx">ASP.NET MVC</category><category domain="http://www.lostechies.com/blogs/jimmy_bogard/archive/tags/AutoMapper/default.aspx">AutoMapper</category><feedburner:origLink>http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/06/29/how-we-do-mvc-view-models.aspx</feedburner:origLink></item><item><title>Python Web Framework Series – Pylons: Part 4 Introduction For Database Support With SQL Alchemy.</title><link>http://feedproxy.google.com/~r/LosTechies/~3/Kzl0Og38C8Y/python-web-framework-series-pylons-part-4-database-support-with-sql-alchemy.aspx</link><pubDate>Mon, 29 Jun 2009 02:54:00 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22417</guid><dc:creator>Ryan Svihla</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;We last left off with &lt;a href="http://www.lostechies.com/blogs/rssvihla/archive/2009/06/25/python-web-framework-series-pylons-part-3-views-with-mako.aspx" target="_blank"&gt;Views with Mako&lt;/a&gt;, now Pylons does not enforce on you an ORM at all, so you can use hand crafted SQL if you prefer. However, since I&amp;rsquo;ve done enough of that for a career or two we&amp;rsquo;re going to use my Python ORM of choice and the preferred one for Pylons SQLAlchemy. &lt;/p&gt;
&lt;h3&gt;Where does SQLAlchemy fit in as an ORM?&lt;/h3&gt;
&lt;p&gt;If you used NHibernate, you should feel pretty close to right at home with SQLAlchemy. If you come from an ActiveRecord, Entity Framework, Subsonic,&amp;nbsp; or even Linq2Sql background this will be a bit more hand management than you are used to. If that is the case, I suggest&amp;nbsp; &lt;a href="http://elixir.ematia.de/trac/wiki" target="_blank"&gt;Elixir&lt;/a&gt; (which I&amp;rsquo;ve heard great things about) or &lt;a href="http://www.sqlobject.org/" target="_blank"&gt;SQLObject&lt;/a&gt; (which I&amp;rsquo;ve used as well and works fine).&lt;/p&gt;
&lt;h3&gt;Mapping and Setup&lt;/h3&gt;
&lt;p&gt;There are three different ways to map tables to classes with SQLAlchemy, I will pick the most commonly used one, but will show the other two in a later post. In our PylonsForum project open &lt;b&gt;model\__init__.py&amp;nbsp; &lt;/b&gt;and change the file to look like so:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:f4025bb5-54a0-4914-8a01-39bfa2b9209a" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#ba2121;"&gt;&lt;i&gt;&amp;quot;&amp;quot;&amp;quot;The&amp;nbsp;application&amp;#39;s&amp;nbsp;model&amp;nbsp;objects&amp;quot;&amp;quot;&amp;quot;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;sqlalchemy&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;orm&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;sqlalchemy&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;as&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;sa&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;datetime&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;pylonsforum.model&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;meta&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;now&lt;/span&gt;():&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;datetime&lt;span style="color:#666666;"&gt;.&lt;/span&gt;datetime&lt;span style="color:#666666;"&gt;.&lt;/span&gt;now()&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;init_model&lt;/span&gt;(engine):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&lt;i&gt;&amp;quot;&amp;quot;&amp;quot;Call&amp;nbsp;me&amp;nbsp;before&amp;nbsp;using&amp;nbsp;any&amp;nbsp;of&amp;nbsp;the&amp;nbsp;tables&amp;nbsp;or&amp;nbsp;classes&amp;nbsp;in&amp;nbsp;the&amp;nbsp;model&amp;quot;&amp;quot;&amp;quot;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;configure(bind&lt;span style="color:#666666;"&gt;=&lt;/span&gt;engine)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;engine&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;engine&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;Post&lt;/b&gt;&lt;/span&gt;(&lt;span style="color:#008000;"&gt;object&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;pass&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;Thread&lt;/b&gt;&lt;/span&gt;(&lt;span style="color:#008000;"&gt;object&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;pass&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
posts_table&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Table(&lt;span style="color:#ba2121;"&gt;&amp;quot;posts&amp;quot;&lt;/span&gt;,&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata,&amp;nbsp;&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Integer,&amp;nbsp;primary_key&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;threadid&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Integer,sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;ForeignKey(&lt;span style="color:#ba2121;"&gt;&amp;#39;threads.id&amp;#39;&lt;/span&gt;)),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(&lt;span style="color:#666666;"&gt;4000&lt;/span&gt;),&amp;nbsp;nullable&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;False&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;author&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(&lt;span style="color:#666666;"&gt;255&lt;/span&gt;),&amp;nbsp;nullable&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;False&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;created&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;TIMESTAMP(),&amp;nbsp;default&lt;span style="color:#666666;"&gt;=&lt;/span&gt;now()),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;isparent&amp;quot;&lt;/span&gt;&amp;nbsp;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Boolean,&amp;nbsp;nullable&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;)&lt;br /&gt;
		)&lt;br /&gt;
threads_table&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Table(&lt;span style="color:#ba2121;"&gt;&amp;quot;threads&amp;quot;&lt;/span&gt;,&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata,&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Integer,&amp;nbsp;primary_key&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;subject&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(&lt;span style="color:#666666;"&gt;255&lt;/span&gt;))&lt;br /&gt;
		)&lt;br /&gt;
orm&lt;span style="color:#666666;"&gt;.&lt;/span&gt;mapper(Post,&amp;nbsp;posts_table)&lt;br /&gt;
orm&lt;span style="color:#666666;"&gt;.&lt;/span&gt;mapper(Thread,&amp;nbsp;threads_table,properties&lt;span style="color:#666666;"&gt;=&lt;/span&gt;{&lt;span style="color:#ba2121;"&gt;&amp;#39;posts&amp;#39;&lt;/span&gt;:orm&lt;span style="color:#666666;"&gt;.&lt;/span&gt;relation(Post,&amp;nbsp;backref&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;thread&amp;#39;&lt;/span&gt;)})&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:ae4f52d8-3391-4b24-b22a-9eb112817b37" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Not the best table structure and you&amp;rsquo;re welcome to improve this on your own but I wanted to create a default setup that was easy to read.&amp;nbsp; Lets take a bit to recap the pieces:&lt;/p&gt;
&lt;hr /&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:1e770a1b-16bc-448e-ace4-cbc920d062aa" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;init_model&lt;/span&gt;(engine):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&lt;i&gt;&amp;quot;&amp;quot;&amp;quot;Call&amp;nbsp;me&amp;nbsp;before&amp;nbsp;using&amp;nbsp;any&amp;nbsp;of&amp;nbsp;the&amp;nbsp;tables&amp;nbsp;or&amp;nbsp;classes&amp;nbsp;in&amp;nbsp;the&amp;nbsp;model&amp;quot;&amp;quot;&amp;quot;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;configure(bind&lt;span style="color:#666666;"&gt;=&lt;/span&gt;engine)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;engine&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;engine&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Straightforward method here sets up a Session object with the database engine passed into the method.&amp;nbsp; Pylons will call init_model itself when the site is accessed.&lt;/p&gt;
&lt;hr /&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:7960a112-25d7-46d6-a9c8-d3eac146ff18" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;Post&lt;/b&gt;&lt;/span&gt;(&lt;span style="color:#008000;"&gt;object&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;pass&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;Thread&lt;/b&gt;&lt;/span&gt;(&lt;span style="color:#008000;"&gt;object&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;pass&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;So a couple of empty classes?&amp;nbsp; Python being a dynamic language can get away with this and just add the properties at runtime.&amp;nbsp; These are the objects we&amp;rsquo;ll be interacting with when we want to store data.&lt;/p&gt;
&lt;hr /&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:1d500b79-b3df-444a-a6ce-3c85fe1be8d4" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
posts_table&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Table(&lt;span style="color:#ba2121;"&gt;&amp;quot;posts&amp;quot;&lt;/span&gt;,&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata,&amp;nbsp;&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Integer,&amp;nbsp;primary_key&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;threadid&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Integer,sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;ForeignKey(&lt;span style="color:#ba2121;"&gt;&amp;#39;threads.id&amp;#39;&lt;/span&gt;)),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(&lt;span style="color:#666666;"&gt;4000&lt;/span&gt;),&amp;nbsp;nullable&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;False&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;author&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(&lt;span style="color:#666666;"&gt;255&lt;/span&gt;),&amp;nbsp;nullable&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;False&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;dateadded&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;TIMESTAMP(),&amp;nbsp;default&lt;span style="color:#666666;"&gt;=&lt;/span&gt;now()),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;isparent&amp;quot;&lt;/span&gt;&amp;nbsp;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Boolean,&amp;nbsp;nullable&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;)&lt;br /&gt;
		)&lt;br /&gt;
threads_table&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Table(&lt;span style="color:#ba2121;"&gt;&amp;quot;threads&amp;quot;&lt;/span&gt;,&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;metadata,&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;id&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Integer,&amp;nbsp;primary_key&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;),&lt;br /&gt;
		sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Column(&lt;span style="color:#ba2121;"&gt;&amp;quot;subject&amp;quot;&lt;/span&gt;,&amp;nbsp;sa&lt;span style="color:#666666;"&gt;.&lt;/span&gt;types&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(&lt;span style="color:#666666;"&gt;255&lt;/span&gt;))&lt;br /&gt;
		)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ok these table declarations are providing the data definition logic, including some basic relationship, nothing too interesting here post in comments if you have specific questions.&lt;/p&gt;
&lt;hr /&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:cc7574da-0863-4768-9570-c62e486b548e" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
orm&lt;span style="color:#666666;"&gt;.&lt;/span&gt;mapper(Post,&amp;nbsp;posts_table)&lt;br /&gt;
orm&lt;span style="color:#666666;"&gt;.&lt;/span&gt;mapper(Thread,&amp;nbsp;threads_table,properties&lt;span style="color:#666666;"&gt;=&lt;/span&gt;{&lt;span style="color:#ba2121;"&gt;&amp;#39;posts&amp;#39;&lt;/span&gt;:orm&lt;span style="color:#666666;"&gt;.&lt;/span&gt;relation(Post,&amp;nbsp;backref&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;thread&amp;#39;&lt;/span&gt;)})&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Here the orm.mapper calls take the Page and Thread classes and map them with the table data definitions typed in earlier.&amp;nbsp; You can also specify relationships here as we have done in the thread mapping, the properties argument is referencing the &lt;i&gt;Post&lt;/i&gt; class and mapping it to a property called posts on the &lt;i&gt;Thread&lt;/i&gt; class, while also mapping the other direction and putting thread on the &lt;i&gt;Post&lt;/i&gt; class.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Finally run &lt;i&gt;paster setup-app development.ini&lt;/i&gt; from the root pylonsforum directory and you should see a bunch of SQL flying by which indicates it has build the database schema for us:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_3D5BCA36.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_thumb_5F00_214D9BFC.png" border="0" width="609" height="420" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;Making Our New Thread Store In The Database&lt;/h3&gt;
&lt;p&gt;In the interest of space and time I&amp;rsquo;ll skip the testing story for another post.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;Open up &lt;i&gt;controllers\home.py&lt;/i&gt; .&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remove the Post class we created several posts ago &lt;/li&gt;
&lt;li&gt;under the imports add &lt;i&gt;import pylonsforum.model as model &lt;/i&gt;&lt;/li&gt;
&lt;li&gt;under the imports add &lt;i&gt;import pylonsforum.model.meta as meta&lt;/i&gt; &lt;/li&gt;
&lt;li&gt;change the submitnewthread method to the following      
&lt;ul&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:205d3b50-c0a8-4b5f-ae6b-b43755eb1e3b" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
	thread&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Thread()&amp;nbsp;&lt;br /&gt;
	thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;request&lt;span style="color:#666666;"&gt;.&lt;/span&gt;POST[&lt;span style="color:#ba2121;"&gt;&amp;#39;subject&amp;#39;&lt;/span&gt;]&lt;br /&gt;
	post&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Post()&lt;br /&gt;
	post&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;users&lt;span style="color:#666666;"&gt;.&lt;/span&gt;get_current_user(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;)&lt;br /&gt;
	post&lt;span style="color:#666666;"&gt;.&lt;/span&gt;isparent&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;&lt;br /&gt;
	post&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;request&lt;span style="color:#666666;"&gt;.&lt;/span&gt;POST[&lt;span style="color:#ba2121;"&gt;&amp;#39;content&amp;#39;&lt;/span&gt;]&lt;br /&gt;
	thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts&lt;span style="color:#666666;"&gt;.&lt;/span&gt;append(post)&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;#adding&amp;nbsp;post&amp;nbsp;to&amp;nbsp;the&amp;nbsp;thread&amp;nbsp;object&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
	meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;add(thread)&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;#look&amp;nbsp;only&amp;nbsp;have&amp;nbsp;to&amp;nbsp;add&amp;nbsp;the&amp;nbsp;thread&amp;nbsp;object&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
	meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;flush()&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;#optional&amp;nbsp;when&amp;nbsp;AutoCommit&amp;nbsp;is&amp;nbsp;on,&amp;nbsp;but&amp;nbsp;useful&amp;nbsp;for&amp;nbsp;control&amp;nbsp;in&amp;nbsp;data&amp;nbsp;integrity&amp;nbsp;cases&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
	meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;commit()&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;#makes&amp;nbsp;changes&amp;nbsp;real&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
	thread_query&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;meta&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Session&lt;span style="color:#666666;"&gt;.&lt;/span&gt;query(model&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Thread)&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;#query&amp;nbsp;back&amp;nbsp;submitted&amp;nbsp;data&amp;nbsp;to&amp;nbsp;display&amp;nbsp;to&amp;nbsp;ui&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
	thread&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;thread_query&lt;span style="color:#666666;"&gt;.&lt;/span&gt;filter_by(&lt;span style="color:#008000;"&gt;id&lt;/span&gt;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;id)&lt;span style="color:#666666;"&gt;.&lt;/span&gt;first()&amp;nbsp;&lt;span style="color:#408080;"&gt;&lt;i&gt;#&amp;nbsp;yes&amp;nbsp;actually&amp;nbsp;querying&amp;nbsp;using&amp;nbsp;the&amp;nbsp;thread&amp;nbsp;id&amp;nbsp;of&amp;nbsp;our&amp;nbsp;created&amp;nbsp;object&amp;nbsp;above&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;username&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts[&lt;span style="color:#666666;"&gt;0&lt;/span&gt;]&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&lt;br /&gt;
	c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&lt;br /&gt;
	c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;thread&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts[&lt;span style="color:#666666;"&gt;0&lt;/span&gt;]&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;render(&lt;span style="color:#ba2121;"&gt;&amp;#39;submitnewthread.mako&amp;#39;&lt;/span&gt;)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally run the newthread action&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &lt;a href="http://localhost:5000/home/newthread" target="_blank"&gt;http://localhost:5000/home/newthread&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;then create a thread&lt;/p&gt;
&lt;p&gt;&lt;a title="http://localhost:5000/home/submitnewthread" href="http://localhost:5000/home/submitnewthread"&gt;http://localhost:5000/home/submitnewthread&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Should be no change in the actual outward appearance of from what we were doing before.&lt;/p&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;h3&gt;Summary and Recap&lt;/h3&gt;
&lt;p&gt;This was a very quick and basic introduction to SQLAlchemy and I will do more with it over the next couple of posts, but please add any comments to things I did not make clear. SQLAlchemy and ORM&amp;rsquo;s in general are a very large subjects and those of us that have used them for a long time tend to forget not all of this was so obvious when we started.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22417" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/785A51E06BCAC0692FBC229EDD3B6C371D3A9823"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/785A51E06BCAC0692FBC229EDD3B6C371D3A9823"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=Kzl0Og38C8Y:kWMY9qrehEo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=Kzl0Og38C8Y:kWMY9qrehEo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=Kzl0Og38C8Y:kWMY9qrehEo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=Kzl0Og38C8Y:kWMY9qrehEo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/Kzl0Og38C8Y" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Python/default.aspx">Python</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/ORM/default.aspx">ORM</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Pylons/default.aspx">Pylons</category><feedburner:origLink>http://www.lostechies.com/blogs/rssvihla/archive/2009/06/28/python-web-framework-series-pylons-part-4-database-support-with-sql-alchemy.aspx</feedburner:origLink></item><item><title>Real World Refactoring</title><link>http://feedproxy.google.com/~r/LosTechies/~3/WiQJ5sbwOfE/real-world-refactoring.aspx</link><pubDate>Mon, 29 Jun 2009 00:35:29 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22485</guid><dc:creator>Joshua Flanagan</dc:creator><slash:comments>5</slash:comments><description>&lt;p&gt;If you’ve ever asked, or been asked, for an example to illustrate a software design principle, you know how frustrating it can be to work with a contrived example. There is rarely any depth to the example, and it lines up so neatly with the concept being explained that the student may have trouble recognizing similar situations in the wild. I’m going to try and relate a real world example of a recent refactoring effort, with the hope that the extra context and narrated walkthrough will help someone make a connection that has failed before.&lt;/p&gt;  &lt;h3&gt;A little background&lt;/h3&gt;  &lt;p&gt;My discussion revolves around &lt;a href="http://docu.jagregory.com/" target="_blank"&gt;Docu&lt;/a&gt;, which is an open source project for converting .NET XML comments into HTML documentation. (&lt;em&gt;Note: I want to make clear is that this is not a criticism of any of the Docu code. All code is written with specific goals and constraints in mind. As the goals evolve, some designs that worked perfectly in early iterations may start to create friction, and deserve to be reconsidered.&lt;/em&gt;) &lt;a href="http://msdn.microsoft.com/en-us/library/b2s063f7.aspx" target="_blank"&gt;.NET XML comments&lt;/a&gt; are constructed by applying a set of top-level tags to code elements such as classes, methods, or properties. Top-level tags are things like &lt;a href="http://msdn.microsoft.com/en-us/library/2d6dt3kf.aspx" target="_blank"&gt;&amp;lt;summary/&amp;gt;&lt;/a&gt;, &lt;a href="http://msdn.microsoft.com/en-us/library/3zw4z1ys.aspx" target="_blank"&gt;&amp;lt;remarks/&amp;gt;&lt;/a&gt;, or &lt;a href="http://msdn.microsoft.com/en-us/library/8cw818w8.aspx" target="_blank"&gt;&amp;lt;param/&amp;gt;&lt;/a&gt;. Within the contents of the top-level tags, you can use embedded tags to provide additional contextual information. Embedded tags are things like &lt;a href="http://msdn.microsoft.com/en-us/library/acd0tfbe.aspx" target="_blank"&gt;&amp;lt;see/&amp;gt;&lt;/a&gt;, &lt;a href="http://msdn.microsoft.com/en-us/library/x640hcd2.aspx" target="_blank"&gt;&amp;lt;para/&amp;gt;&lt;/a&gt;, or &lt;a href="http://msdn.microsoft.com/en-us/library/wb7x2fhw.aspx" target="_blank"&gt;&amp;lt;paramref/&amp;gt;&lt;/a&gt;. The following example shows a top level &amp;lt;remarks/&amp;gt; tag, with embedded &amp;lt;paramref/&amp;gt; and &amp;lt;para/&amp;gt; tags: &lt;/p&gt;  &lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:d9db1802-6276-4d14-b945-b305ebd1578e" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="xml:nocontrols"&gt;///&amp;lt;remarks&amp;gt;Make sure the &amp;lt;paramref name=”maxValue” /&amp;gt; is a positive number.
///&amp;lt;para&amp;gt;Do not call more than once.&amp;lt;/para&amp;gt;&amp;lt;/remarks&amp;gt; &lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In Docu, the job of translating the XML contents of a single top-level tag into a semantic model is handled by the CommentParser. Let’s take a look at the &lt;a href="http://github.com/jagregory/docu/blob/e5569e48aea80084f1f8c1abc0c77e9d26906e37/src/Docu.Console/Parsing/Comments/CommentParser.cs" target="_blank"&gt;original implementation&lt;/a&gt;:&lt;/p&gt;

&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:8a832f5b-43a7-40fe-8c08-b28fce9e9c96" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class CommentParser : ICommentParser
{
    private readonly IDictionary&amp;lt;Func&amp;lt;XmlNode, bool&amp;gt;, Func&amp;lt;XmlNode, bool, bool, IComment&amp;gt;&amp;gt; parsers =
        new Dictionary&amp;lt;Func&amp;lt;XmlNode, bool&amp;gt;, Func&amp;lt;XmlNode, bool, bool, IComment&amp;gt;&amp;gt;();

    private readonly InlineTextCommentParser InlineText = new InlineTextCommentParser();
    private readonly InlineCodeCommentParser InlineCode = new InlineCodeCommentParser();
    private readonly MultilineCodeCommentParser MultilineCode = new MultilineCodeCommentParser();
    private readonly SeeCodeCommentParser See = new SeeCodeCommentParser();
    private readonly ParagraphCommentParser Paragraph;
    private readonly ParameterReferenceParser ParameterReference = new ParameterReferenceParser();
    private readonly InlineListCommentParser InlineList;

    public CommentParser()
    {
        Paragraph = new ParagraphCommentParser(this);
        InlineList = new InlineListCommentParser(this);
        parsers.Add(node =&amp;gt; node is XmlText, InlineText.Parse);
        parsers.Add(node =&amp;gt; node.Name == &amp;quot;c&amp;quot;, InlineCode.Parse);
        parsers.Add(node =&amp;gt; node.Name == &amp;quot;code&amp;quot;, MultilineCode.Parse);
        parsers.Add(node =&amp;gt; node.Name == &amp;quot;see&amp;quot;, See.Parse);
        parsers.Add(node =&amp;gt; node.Name == &amp;quot;para&amp;quot;, Paragraph.Parse);
        parsers.Add(node =&amp;gt; node.Name == &amp;quot;paramref&amp;quot;, ParameterReference.Parse);
        parsers.Add(node =&amp;gt; node.Name == &amp;quot;list&amp;quot;, InlineList.Parse);
    }

    public IList&amp;lt;IComment&amp;gt; Parse(XmlNodeList nodes)
    {
        var blocks = new List&amp;lt;IComment&amp;gt;();

        int count = nodes.Count;
        for(int i = 0; i &amp;lt; count; i++)
        {
            XmlNode node = nodes;
            bool first = (i == 0);
            bool last = (i == (count - 1));

            foreach(var pair in parsers)
            {
                var isValid = pair.Key;
                var parser = pair.Value;

                if(!isValid(node))
                    continue;

                var block = parser(node, first, last);

                if(block != null)
                {
                    blocks.Add(block);
                    continue;
                }
            }
        }

        return blocks;
    }&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can see (lines 18-24 above) that in its constructor it builds up a collection of function (Func&amp;lt;&amp;gt;) pairs: one function that is used to identify a specific embedded tag, paired with another function that knows how to parse that tag into its model representation (an instance of IComment). The collection is used by the primary method in CommentParser, which iterates over all of the child nodes of a given chunk of XML, finds a parsing function that can handle that node, invokes the function, and collects the results. &lt;/p&gt;

&lt;p&gt;The functions that perform the parsing of individual embedded tags are implemented in separate classes (I’ll call them “node parsers”). The CommentParser creates an instance of each node parser and stores it in a field where it can be referenced by the collection of function pairs. The benefit of moving the embedded tag parsing into separate classes is that they can be developed and tested independent of CommentParser. Unfortunately, you need to make a number of changes to CommentParser every time you add a new node parser. Since there are still quite a few embedded tags that are not yet recognized by Docu, and each embedded tag (generally) requires a new node parser, the CommentParser class will be continuously modified and unstable. The primary goal of my refactoring effort is to create a more stable CommentParser that is open for extension (support for new embedded tags can be added) but closed for modification. &lt;/p&gt;

&lt;h3&gt;High Cohesion&lt;/h3&gt;

&lt;p&gt;As stated above, the logic for determining when a specific parsing function should be applied was inside of CommentParser, while the logic to implement that function was in the individual parsing classes. These two pieces of logic are tightly related to each other. You cannot safely apply an arbitrary node parser to any node – it only makes sense to apply a parser to the type of node it was designed for. We can make the node parsers and the CommentParser more cohesive by moving both pieces of logic into the node parsing classes. I’ll add a CanParse(XmlNode) method to each node parser. The method returns true if the parser knows how to parse a given comment node. I implement them by copying the logic for identifying specific tags from the Func&amp;lt;&amp;gt; pairs in CommentParser.&lt;/p&gt;

&lt;h3&gt;Low Coupling &lt;/h3&gt;

&lt;p&gt;We still have the problem that the CommentParser creates and stores an instance of each specific node parser class (lines 6-11 above). This high coupling between the CommentParser and the node parsing classes makes it impossible to execute in isolation. You cannot use a CommentParser without bringing all of the functionality of all node parsers along. You also have to modify the CommentParser every time a new type of node parser is added (as when adding support for a new type of comment tag).&lt;/p&gt;

&lt;p&gt;I’ll reduce coupling between CommentParser and individual node parsers by introducing an interface (ICommentNodeParser) to describe the functionality exposed by the node parsers. The CommentParser will only interact with this interface, which exposes the CanParse and Parse methods. I then change the node parsers so that they implement the new interface. Since they already had all of the needed functionality, it was just a matter of making sure the method signatures matched correctly. &lt;/p&gt;

&lt;h3&gt;Slight detour&lt;/h3&gt;

&lt;p&gt;When I started to add the interface to all of the node parsing classes, I noticed they all derived from CommentParserBase. However, none of the code in the application referred to these classes through this base class. That’s a pretty good indicator that inheritance is being used to share common functionality rather than for polymorphism. Using inheritance just to share some common functionality can lead to more inflexible designs and less cohesive classes. You are usually better off using composition instead of inheritance in these scenarios. In this case, the only shared functionality was a single helper method that had some special logic for string trimming. Since the method didn’t make use of any instance data, it was easy to move it to a separate class as an extension method on string. Now that CommentParserBase was empty, there was no reason to keep it around, so it was eliminated. The fact that no code broke when the base class was deleted (without using a refactoring tool) is a good indicator that it was the right decision.&lt;/p&gt;

&lt;h3&gt;Composition through dependency injection&lt;/h3&gt;

&lt;p&gt;At this point we have a bunch of node parsers that all implement a common interface. But the CommentParser is still tightly coupled to the various implementations because it has to create the instances. This is the perfect opportunity to use dependency injection to pass the node parser instances into the CommentParser. I just change the constructor of CommentParser to require an array of ICommentNodeParsers, and delete all the code that was creating the node parser instances. Whoever creates an instance of CommentParser will need to pass in the collection of node parser instances. CommentParser is no longer coupled to the specific node parsers and can be more easily used in isolation. You can see that the newer version is greatly simplified:&lt;/p&gt;

&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:40abf482-65bd-4279-842c-f0dc82396fef" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public class CommentParser : ICommentParser
   {
       private readonly ICommentNodeParser[] _parsers;

       public CommentParser(ICommentNodeParser[] parsers)
       {
           _parsers = parsers;
       }

       public IList&amp;lt;IComment&amp;gt; Parse(XmlNodeList nodes)
       {
           var blocks = new List&amp;lt;IComment&amp;gt;();

           var count = nodes.Count;
           for(var i = 0; i &amp;lt; count; i++)
           {
               var node = nodes;
               var first = (i == 0);
               var last = (i == (count - 1));

               var parser = _parsers.FirstOrDefault(p =&amp;gt; p.CanParse(node));
               if (parser == null) continue;

               var block = parser.Parse(this, node, first, last);
               if (block != null)
               {
                   blocks.Add(block);
               }
           }

           return blocks;
       }&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;At this point you may be thinking I just “passed the buck” for creating the individual node parser instances to another class up the stack. Someone still needs to create them, and will therefore be tightly coupled to the implementations. That is true. However, if we can pass that responsibility up the stack far enough, it can be handled by code that has no other responsibility than to configure and bootstrap our application. That type of code doesn’t typically have any logic that would be re-used and doesn’t have the same concerns about designing for maintainability. Luckily, in the case of Docu, we already use &lt;a href="http://structuremap.sourceforge.net/" target="_blank"&gt;StructureMap&lt;/a&gt; to compose our object instances so we get this functionality for free. I simply had to add a single line to the StructureMap configuration to tell it to make use of any implementation of ICommentNodeParser it finds in the Docu assembly.&lt;/p&gt;

&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:812469c5-0cb0-4c63-8c15-c81123a09de7:c4eff773-4ded-44d3-831b-39478edb3125" class="wlWriterEditableSmartContent"&gt;&lt;pre name="code" class="c#"&gt;public DefaultRegistry() {
  Scan(x =&amp;gt;  {
    x.AssemblyContainingType&amp;lt;DocumentationGenerator&amp;gt;();
    x.WithDefaultConventions();
    x.AddAllTypesOf&amp;lt;ICommentNodeParser&amp;gt;();&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Now when an instance of CommentParser is requested from StructureMap, it will automatically have the array of all node parsers injected to its constructor.&lt;/p&gt;

&lt;h3&gt;Wrap up&lt;/h3&gt;

&lt;p&gt;So what did we gain? Let’s compare the stories for adding the ability to parse a new XML documentation tag. In the original implementation, we had to:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Create a class with code that parses the new tag &lt;/li&gt;

  &lt;li&gt;Create a new field in CommentParser to hold an instance of the new parsing class &lt;/li&gt;

  &lt;li&gt;Modify CommentParser’s constructor to register the new class, along with a predicate that determines when it should be used &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And now we simply:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Create a class that implements ICommentNodeParser with code that recognizes and parses the new tag &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notice that you didn’t have to touch CommentParser? We just gave it new functionality without having to change (and potentially destabilize) the code. That’s the open-closed principle in action. The increased cohesion of the node parsers makes them easier to understand and helps localize any future changes to their implementation. We also saw that the use of dependency injection and a composition tool (StructureMap in this case) made it painless for us to pull code apart into separate classes. The code was made easier to maintain by applying a few established object oriented design principles. Hopefully this example helped clarify the application of these principles. Your feedback is appreciated.&lt;/p&gt;

&lt;p&gt;For additional context, you can &lt;a href="http://github.com/jagregory/docu/commit/41bf6458ed4297a355400b0ea2c465a1511122b0" target="_blank"&gt;view the commit&lt;/a&gt; that contained the changes discussed above.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22485" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/DF5C9251EFD53D68DD270A311F231CBE8631BCD8"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/DF5C9251EFD53D68DD270A311F231CBE8631BCD8"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=WiQJ5sbwOfE:RqLY3lvu3yw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=WiQJ5sbwOfE:RqLY3lvu3yw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=WiQJ5sbwOfE:RqLY3lvu3yw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=WiQJ5sbwOfE:RqLY3lvu3yw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/WiQJ5sbwOfE" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/joshuaflanagan/archive/tags/structuremap/default.aspx">structuremap</category><category domain="http://www.lostechies.com/blogs/joshuaflanagan/archive/tags/docu/default.aspx">docu</category><category domain="http://www.lostechies.com/blogs/joshuaflanagan/archive/tags/composition/default.aspx">composition</category><category domain="http://www.lostechies.com/blogs/joshuaflanagan/archive/tags/design/default.aspx">design</category><feedburner:origLink>http://www.lostechies.com/blogs/joshuaflanagan/archive/2009/06/28/real-world-refactoring.aspx</feedburner:origLink></item><item><title>Walking through the creation of a complex installer package</title><link>http://feedproxy.google.com/~r/LosTechies/~3/8XJuVPYiJj4/walking-through-the-creation-of-a-complex-installer-package.aspx</link><pubDate>Fri, 26 Jun 2009 12:05:21 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22458</guid><dc:creator>Gabriel N. Schenker</dc:creator><slash:comments>1</slash:comments><description>&lt;h2&gt;Introduction&lt;/h2&gt;  &lt;p&gt;In this post I want to describe the issues and pain points I had when trying to generate a setup package for a complex product with many thousand of files. This is a post mainly for self documenting purposes but hopefully it might add some other people trying to create a complex product installer.&lt;/p&gt;  &lt;p&gt;I received the following list of requirements&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The install process must be transactional&lt;/li&gt;    &lt;li&gt;Repair of a corrupt installation must be possible&lt;/li&gt;    &lt;li&gt;Patching and Upgrading must be possible&lt;/li&gt;    &lt;li&gt;Some files (mainly config files) must be backed up during an upgrade&lt;/li&gt;    &lt;li&gt;Must be able to automatically launch an application at the end of the install&lt;/li&gt;    &lt;li&gt;Must support localization&lt;/li&gt;    &lt;li&gt;Can automatically create a virtual directory and an application pool for IIS&lt;/li&gt;    &lt;li&gt;Can assign write permissions for specific folders to users/groups&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;In the past our company had used Install Shield to generate the setup packages. But this was overly complex and became a maintenance burden with the time. Not to mention that Install Shield is rather expensive compared to the two products discussed in this post which are both – ahhh – free! The products I want to have a look at in this post are WIX and NSIS.&lt;/p&gt;  &lt;h2&gt;WIX – Windows Installer XML&lt;/h2&gt;  &lt;p&gt;WIX is an open source project of Microsoft. It is based on the Microsoft Windows Installer technology. Everything about WIX (download and documentation) can be found &lt;a href="http://wix.sourceforge.net/index.html"&gt;here&lt;/a&gt;.&lt;/p&gt;  &lt;h3&gt;Tutorial&lt;/h3&gt;  &lt;p&gt;If you are new to WIX I absolutely recommend to read &lt;a href="http://www.tramontana.co.hu/wix/"&gt;this&lt;/a&gt; wonderful and extensive tutorial.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;“… Instead of a tool with a graphical interface that allows the developers to collect the files and other related tasks making up the installation process manually, it is much more like a programming language. &lt;em&gt;Integrating perfectly with the usual process of creating applications,&lt;/em&gt; it uses a text file (based on the increasingly popular XML format) to describe all the elements of the installation process. The toolset has a compiler and a linker that will create the setup program just like our usual compiler creates our application from the source files. Therefore, WiX can be made part of any automated application build process very easily, be that based either on the classical technology of makefiles or the similar features of contemporary integrated development environments. …”&lt;/p&gt; &lt;/blockquote&gt;  &lt;h3&gt;Analyze an existing MSI package with ORCA&lt;/h3&gt;  &lt;p&gt;If you ever want to analyze the .msi package created by WIX there is a tool called &lt;strong&gt;ORCA&lt;/strong&gt; available in the Microsoft Windows SDK. With this tool any detail of such a package can be analyzed in details, e.g. the components included, the icon used or the install execution sequence.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/gabrielschenker/image_5F00_4C0120D9.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/gabrielschenker/image_5F00_thumb_5F00_6DF956D2.png" width="644" height="424" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Let’s now have a look at various elements of a setup project in WIX.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;h3&gt;Defining Variables&lt;/h3&gt;  &lt;p&gt;If you are used to e.g. &lt;a href="http://nant.sourceforge.net/"&gt;Nant&lt;/a&gt; or MSBuild you certainly define properties which later on you use in the script instead of hard coded values. WIX has a similar concept of &lt;em&gt;variables&lt;/em&gt;. With the aid of pre-processor &amp;lt;?define …&amp;gt; statements we can define variables that later on can be used at the place of hard coded values&lt;/p&gt;  &lt;div&gt;   &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;     &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;define&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;BuildPath&lt;/span&gt; = &lt;span style="color:#0000ff;"&gt;&amp;quot;.\..\..\..\build&amp;quot;&lt;/span&gt; ?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;define&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Help&lt;/span&gt; = &lt;span style="color:#0000ff;"&gt;&amp;quot;$(var.BuildPath)\Help&amp;quot;&lt;/span&gt; ?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;define&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Skin&lt;/span&gt; = &lt;span style="color:#0000ff;"&gt;&amp;quot;$(var.Help)\Skin&amp;quot;&lt;/span&gt; ?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;define&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Data&lt;/span&gt; = &lt;span style="color:#0000ff;"&gt;&amp;quot;$(var.Help)\Data&amp;quot;&lt;/span&gt; ?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Note that once a variable is defined it can be used by applying the following syntax: $(var.&lt;em&gt;VariableName&lt;/em&gt;). It took me a while to find this all out since unfortunately it is not well documented in the WIKI.&lt;/p&gt;

&lt;h3&gt;Properties&lt;/h3&gt;

&lt;p&gt;To define a property and assign a (constant) value use a statement similar to this&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Property&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;NOTEPAD&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;Notepad.exe&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Property&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Note that when using an all caps id for the property the property is considered to be global and can be used every where in the setup files.&lt;/p&gt;

&lt;p&gt;To define the value of a property with a nested statement like a registry search&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Property&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;IIS&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;RegistrySearch&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;IISInstalledVersion&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;                  &lt;span style="color:#ff0000;"&gt;Root&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;HKLM&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;                  &lt;span style="color:#ff0000;"&gt;Key&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;SOFTWARE\Microsoft\InetStp&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;                  &lt;span style="color:#ff0000;"&gt;Type&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;raw&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;MajorVersion&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Property&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;In the above snippet the property &lt;strong&gt;IIS&lt;/strong&gt; is assigned the value of the registry key &lt;strong&gt;HKLM\SOFTWARE\Microsoft\InetStp\MajorVersion&lt;/strong&gt; which is a &lt;strong&gt;DWORD&lt;/strong&gt; in this case. If IIS 7.0 is installed the property &lt;strong&gt;IIS&lt;/strong&gt; would contain the value “#7”.&lt;/p&gt;

&lt;p&gt;Such a property can then e.g. be used in a condition. The following condition tests whether IIS 6.0 or 7.0 is installed on the current machine&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Condition&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Message&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;This setup requires IIS 6.0 or 7.0 is installed.&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;!&lt;/span&gt;[CDATA[IIS=&amp;quot;#7&amp;quot; OR IIS=&amp;quot;#6&amp;quot;]]&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Condition&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Use environment variables to set properties, e.g.&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Property&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ROOTDRIVE&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Value&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;$(env.SystemDrive)&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;For a full list of all possible system directory values take a look &lt;a href="http://msdn.microsoft.com/en-us/library/aa372057(VS.85).aspx"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Components&lt;/h3&gt;

&lt;p&gt;The component is the atomic unit of things to be installed. It consists of resources—files, registry keys, shortcuts or anything else—that should always be installed as a single unit. Installing a component should never influence other components, removing one should never damage another component or leave any orphaned resource on the target machine. As a consequence, components cannot share files: the same file going to the same location must never be included in more than one component.&lt;/p&gt;

&lt;p&gt;A component has to have its own &lt;strong&gt;Id&lt;/strong&gt; identifier as well as its own &lt;strong&gt;GUID&lt;/strong&gt;.&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Component 1&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Guid&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;170A4245-9DE3-4bd7-B68A-110000000010&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Once defined a component can be referenced by its &lt;strong&gt;id&lt;/strong&gt;, e.g.&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Component 1&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;Component Groups&lt;/h3&gt;

&lt;p&gt;A component group is a handy way to tie together a group of related components.&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentGroup&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Help&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Help&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Help.Content&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Help.Content.Administration&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentGroup&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;later on in the setup package this group of components can be easily referenced, e.g.&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Feature&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Core&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Title&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Core&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Level&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentGroupRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Help&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Feature&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;Conditions&lt;/h3&gt;

&lt;p&gt;Often we need to define some conditions, e.g. launch conditions, conditional installation of some components, etc. For this purpose we have the &amp;lt;Condition Message=’…’&amp;gt;Inner text&amp;lt;/Condition&amp;gt; construct. Here at the place of ‘Inner text’ one would define the condition (logic). If the condition is a launch condition and the evaluation of the condition logic result in false then the install process would be aborted and the text in the Message attribute would be reported. Typical launch conditions are&lt;/p&gt;

&lt;p&gt;Request for sufficient privileges&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;Condition Message=&lt;span style="color:#006080;"&gt;&amp;quot;You need to be an administrator to install this product.&amp;quot;&lt;/span&gt;&amp;gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  Privileged&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;/Condition&amp;gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;a specific version of a framework (e.g. .NET 3.5) must be installed&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;Condition Message=&lt;span style="color:#006080;"&gt;&amp;quot;This application requires .NET Framework 3.5. Please install the .NET Framework then run this installer again.&amp;quot;&lt;/span&gt;&amp;gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &amp;lt;![CDATA[Installed OR NETFRAMEWORK35]]&amp;gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;/Condition&amp;gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;IIS 6.0 or above must be installed&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;Condition Message=&lt;span style="color:#006080;"&gt;&amp;quot;This setup requires IIS 6.0 or 7.0 is installed.&amp;quot;&lt;/span&gt;&amp;gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &amp;lt;![CDATA[IIS=&lt;span style="color:#006080;"&gt;&amp;quot;#7&amp;quot;&lt;/span&gt; OR IIS=&lt;span style="color:#006080;"&gt;&amp;quot;#6&amp;quot;&lt;/span&gt;]]&amp;gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;lt;/Condition&amp;gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;For the above condition to work we have to define the property IIS since this is a custom property. We can do so with the following snippet&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Property&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;IIS&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;RegistrySearch&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;IISInstalledVersion&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;                  &lt;span style="color:#ff0000;"&gt;Root&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;HKLM&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;                  &lt;span style="color:#ff0000;"&gt;Key&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;SOFTWARE\Microsoft\InetStp&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;                  &lt;span style="color:#ff0000;"&gt;Type&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;raw&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;MajorVersion&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Property&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;here the value of the property IIS is set by the nested registry search which looks for a required key in the registry.&lt;/p&gt;

&lt;h3&gt;Permissions on folders&lt;/h3&gt;

&lt;p&gt;If we want to create a folder during setup which has special permissions we can use the following snippet inside a component&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;CreateFolder&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;index&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#008000;"&gt;&amp;lt;!-- pay attention when using on non-english system! --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Permission&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;User&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Everyone&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;GenericAll&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;yes&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;CreateFolder&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;Permissions and globalization/localization issues&lt;/h3&gt;

&lt;p&gt;Regarding localization issues have a look at &lt;a href="http://social.msdn.microsoft.com/Forums/en-US/vssetup/thread/39d9e905-2b35-4ce9-a544-4564f6b5a376"&gt;this&lt;/a&gt; article.&lt;/p&gt;

&lt;p&gt;The following snippet would cause problems on a computer having a say German Windows operating installed&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;CreateFolder&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;index&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Permission&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;User&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Users&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;GenericAll&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;yes&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;CreateFolder&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;since the group ‘Users’ is called ‘Benutzer’ in German. Thus we need a more sophisticated way using custom actions and conditions. First we define a global(!) property with a default value&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Property&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;USERGROUP_USERS&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Value&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Users&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;then we define a custom action to apply the localized name for the group ‘Users’&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;CustomAction&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;SetUserGroup_Users_De&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;              &lt;span style="color:#ff0000;"&gt;Property&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;USERGROUP_USERS&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;              &lt;span style="color:#ff0000;"&gt;Value&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Benutzer&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;              &lt;span style="color:#ff0000;"&gt;Return&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;check&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;and then we execute the correct custom action based on the condition on which system language the operating system uses&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;InstallUISequence&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Custom&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Action&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;SetUserGroup_Users_De&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;After&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;LaunchConditions&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        SystemLanguageID = &amp;quot;1031&amp;quot;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Custom&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Custom&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Action&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;SetUserGroup_Users_Fr&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;After&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;LaunchConditions&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        SystemLanguageID = &amp;quot;1036&amp;quot;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Custom&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;InstallUISequence&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;finally the Permission tag uses our global property which now should contain the correct value&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;CreateFolder&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;index&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Permission&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;User&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;[USERGROUP_USERS]&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;GenericAll&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;yes&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;CreateFolder&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Wow, this is a lot of work. Way too complicated in my opinion. If somebody know a more elegant way to do it, I am open for any suggestions!&lt;/p&gt;

&lt;h3&gt;Extensions&lt;/h3&gt;

&lt;p&gt;WIX provides some useful extension for common tasks. The namespace of an extension must be defined in the file where the respective functionality is used. If we want to use the IIS extensions then use the following definition&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Wix&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;xmlns&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;http://schemas.microsoft.com/wix/2006/wi&amp;#39;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;     &lt;span style="color:#ff0000;"&gt;xmlns:iis&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;http://schemas.microsoft.com/wix/IIsExtension&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Wix&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Now the commands provided by the extensions can be used like this&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;&amp;lt;!-- Create an application pool on IIS --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;iis:WebAppPool&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;TestAppPool&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Test Application Pool&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Identity&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;networkService&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;which creates a new application pool for IIS during installation.&lt;/p&gt;

&lt;h3&gt;Define an application pool for IIS&lt;/h3&gt;

&lt;p&gt;On task of our setup package is to create a new application pool for IIS during installation. It comes handy that WIX provides an extension providing IIS related tasks which among other tasks allows us to just do that. First we have to define the namespace for the extension&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Wix&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;xmlns&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;http://schemas.microsoft.com/wix/2006/wi&amp;#39;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;     &lt;span style="color:#ff0000;"&gt;xmlns:iis&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;http://schemas.microsoft.com/wix/IIsExtension&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;then we can use all available commands. In our case this is the one we need&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;iis:WebAppPool&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;SampleAppPool&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Sample Application Pool&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Identity&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;networkService&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The above command creates a new application pool and assigns it the network service identity. Note that the command has to be a child of a &lt;strong&gt;component&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;Create a virtual directory for IIS&lt;/h3&gt;

&lt;p&gt;Not only do we have to create a new application pool but also we need a new virtual directory for IIS. With the same extension we can use this fragment to do just that&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;iis:WebVirtualDir&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;MyWebApp&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Alias&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;MyWebApp&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;                   &lt;span style="color:#ff0000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;INSTALLDIR&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;                   &lt;span style="color:#ff0000;"&gt;WebSite&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;DefaultWebSite&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;iis:WebApplication&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;SampleWebApplication&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Sample&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;WebAppPool&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;SampleAppPool&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;iis:WebVirtualDir&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The above command creates a new virtual directory for the physical folder [INSTALLDIR] and calls it MyWebApp. The new virtual directory is defined for the &lt;strong&gt;DefaultWebSite&lt;/strong&gt;. It then creates an Web application and assigns this application to the application pool created previously. Again this command has to be a child of a component.&lt;/p&gt;

&lt;p&gt;Now finally we have to define what is our &lt;strong&gt;DefaultWebSite&lt;/strong&gt;. This is done with the following command&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;iis:WebSite&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;DefaultWebSite&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Description&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Default Web Site&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;TARGETDIR&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;iis:WebAddress&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;AllUnassigned&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Port&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;80&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;iis:WebSite&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Note that the above command usually should not be put inside a Component otherwise if put it inside the Component, a new Web Site will be created and uninstall will remove it.&lt;/p&gt;

&lt;h3&gt;Modularize the setup&lt;/h3&gt;

&lt;p&gt;When building a complex setup package it is advisable to modularize it. &lt;a href="http://lostechies.com/blogs/gabrielschenker/archive/2009/01/21/real-swiss-don-t-need-srp-do-they.aspx"&gt;SRP&lt;/a&gt; anybody…? We have modules, includes and fragments for this purpose. There will be one main .wxs file and several satellite .wxs or .wxi files.&lt;/p&gt;

&lt;h4&gt;The main installation file&lt;/h4&gt;

&lt;p&gt;We have to have one main wxs file which defines our overall setup package. The schema of this file contains the following main parts&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   1:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;xml&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;version&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;encoding&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;utf-8&amp;quot;&lt;/span&gt;?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   2:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Wix&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;xmlns&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;http://schemas.microsoft.com/wix/2006/wi&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   3:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   4:&lt;/span&gt;   &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Product&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;170A4245-9DE3-4bd7-B68A-100000000000&amp;#39;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   5:&lt;/span&gt;            &lt;span style="color:#ff0000;"&gt;UpgradeCode&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;170A4245-9DE3-4bd7-B68A-200000000000&amp;#39;&lt;/span&gt; ...&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   6:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   7:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Package&lt;/span&gt; ...&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   8:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   9:&lt;/span&gt;     &lt;span style="color:#008000;"&gt;&amp;lt;!-- Define the directory structure on target computer --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  10:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;TARGETDIR&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;SourceDir&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  11:&lt;/span&gt;       &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ProgramFilesFolder&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  12:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;INSTALLDIR&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;TOPAZ TE6&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  13:&lt;/span&gt;             &lt;span style="color:#008000;"&gt;&amp;lt;!-- define more (sub-) directories if needed --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  14:&lt;/span&gt;             ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  15:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  16:&lt;/span&gt;       &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  17:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  18:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  19:&lt;/span&gt;     &lt;span style="color:#008000;"&gt;&amp;lt;!-- Define the components and component groups --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  20:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;DirectoryRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;INSTALLDIR&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  21:&lt;/span&gt;       &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Component 1&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Guid&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;170A4245-9DE3-4bd7-B68A-110000000010&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  22:&lt;/span&gt;         ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  23:&lt;/span&gt;       &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  24:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;DirectoryRef&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  25:&lt;/span&gt;     &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  26:&lt;/span&gt;     &lt;span style="color:#008000;"&gt;&amp;lt;!-- Define the list of features available to install --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  27:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Feature&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Complete&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Level&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  28:&lt;/span&gt;       &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  29:&lt;/span&gt;       &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Feature&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Feature 1&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Title&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Feature 1&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Level&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  30:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentGroupRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Group 1&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  31:&lt;/span&gt;             ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  32:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Component 1&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  33:&lt;/span&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;MergeRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Merge Module 1&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  34:&lt;/span&gt;       &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Feature&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  35:&lt;/span&gt;       &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  36:&lt;/span&gt;       &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Feature&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Feature 2&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Title&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Feature 2&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Level&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1000&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  37:&lt;/span&gt;         ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  38:&lt;/span&gt;       &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Feature&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  39:&lt;/span&gt;       &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  40:&lt;/span&gt;     &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Feature&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  41:&lt;/span&gt;   &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Product&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  42:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Wix&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The root node on line 2 is &amp;lt;&lt;strong&gt;Wix&lt;/strong&gt;&amp;gt; and we have to define at least the root namespace “http://schemas.microsoft.com/wix/2006/wi”. &lt;/p&gt;

&lt;p&gt;The wix node has a single child node &amp;lt;&lt;strong&gt;Product&lt;/strong&gt;&amp;gt; which defines such things as the name of the product, the manufacturer, the version, etc. Very important are also the &lt;strong&gt;Id&lt;/strong&gt; and the &lt;strong&gt;UpgradeCode&lt;/strong&gt; of the product tag which uniquely define an installed product. Both of them are GUIDs. The &lt;strong&gt;UpgradeCode&lt;/strong&gt; is very important if you plan to patch or upgrade an installation in the future since (to work properly) the patch- or upgrade package will have to reference this &lt;strong&gt;UpgradeCode&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On line 7 we define the (setup-) package in more details. There we define the required version of the Microsoft Windows installer, whether or not the package is compressed, the manufacturer and other things.&lt;/p&gt;

&lt;p&gt;Starting from line 10 we have the definition of the directory structure we want to create on the target computer.&lt;/p&gt;

&lt;p&gt;Starting from line 20 we define the components that shall be included in our setup package.&lt;/p&gt;

&lt;p&gt;On line 27 and following we define the list of features this setup package provides. This list is visible to the user during the setup and he can enable or disable certain features. Normally during a setup the user is presented with 3 choices&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/gabrielschenker/image_5F00_6BCC323C.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" border="0" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/gabrielschenker/image_5F00_thumb_5F00_511F9623.png" width="497" height="364" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Level&lt;/strong&gt; attribute of a feature determines whether a feature is included in the typical or only in the complete setup. In our sample Level=’1’ means that the feature is included in the typical setup whilst Level=’1000’ means it is not included.&lt;/p&gt;

&lt;h4&gt;Include Files&lt;/h4&gt;

&lt;p&gt;The content found in an Include file is just imported and placed at the position where you put an &lt;font face="Courier New"&gt;&amp;lt;?include …&amp;gt;&lt;/font&gt; pre-processor directive, e.g.&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;include&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;MyIncludeFile&lt;/span&gt;.&lt;span style="color:#ff0000;"&gt;wsi&lt;/span&gt;?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;A include file usually has the extension .wsi. As an example I have defined an include file which contains (some of) the launch conditions of our setup&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;xml&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;version&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1.0&amp;#39;&lt;/span&gt;?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Include&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;xmlns&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;http://schemas.microsoft.com/wix/2006/wi&amp;#39;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;     &lt;span style="color:#ff0000;"&gt;xmlns:iis&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;http://schemas.microsoft.com/wix/IIsExtension&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#008000;"&gt;&amp;lt;!-- check whether .NET 3.5 SP1 is installed --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;PropertyRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;NETFRAMEWORK35&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;PropertyRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;NETFRAMEWORK35_SP_LEVEL&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Condition&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Message&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;This application requires .NET Framework 3.5. Please install the .NET Framework then run this installer again.&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;!&lt;/span&gt;[CDATA[Installed OR NETFRAMEWORK35]]&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Condition&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Condition&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Message&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;This application requires .NET Framework 3.5 SP1. Please install the .NET Framework then run this installer again.&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;!&lt;/span&gt;[CDATA[Installed OR (NETFRAMEWORK35_SP_LEVEL and NOT NETFRAMEWORK35_SP_LEVEL = &amp;quot;#0&amp;quot;)]]&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Condition&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Condition&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Message&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;You need to be an administrator to install this product.&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    Privileged&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Condition&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Include&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Please note that the root tag of an include file has to be &amp;lt;&lt;strong&gt;Include&lt;/strong&gt;&amp;gt; and not &amp;lt;Wix&amp;gt;&lt;/p&gt;

&lt;h4&gt;Fragment&lt;/h4&gt;

&lt;p&gt;Useful if you want to define a component or component group that later on is referenced in the main .wxs file. As an example I take the component responsible to install the online help for the product&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;xml&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;version&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1.0&amp;#39;&lt;/span&gt;?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;define&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;BuildPath&lt;/span&gt; = &lt;span style="color:#0000ff;"&gt;&amp;quot;.\..\..\..\build&amp;quot;&lt;/span&gt; ?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;define&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Help&lt;/span&gt; = &lt;span style="color:#0000ff;"&gt;&amp;quot;$(var.BuildPath)\Help&amp;quot;&lt;/span&gt; ?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;define&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Skin&lt;/span&gt; = &lt;span style="color:#0000ff;"&gt;&amp;quot;$(var.Help)\Skin&amp;quot;&lt;/span&gt; ?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;define&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Data&lt;/span&gt; = &lt;span style="color:#0000ff;"&gt;&amp;quot;$(var.Help)\Data&amp;quot;&lt;/span&gt; ?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Wix&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;xmlns&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;http://schemas.microsoft.com/wix/2006/wi&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Fragment&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;FragmentHelp&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentGroup&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Help&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Help&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Help.Skin&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Help.Data&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentGroup&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;DirectoryRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Help&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Help&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Guid&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;170A4245-9DE3-4bd7-B68A-110000000003&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;File&lt;/span&gt;  &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Reviews.pdf&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Reviews.pdf&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Source&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;$(var.Help)\Reviews.pdf&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;DiskId&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Help.Skin&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Skin&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Help.Skin&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Guid&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;170A4245-9DE3-4bd7-B68A-110000000013&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;File&lt;/span&gt;  &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Blank.htm&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Blank.htm&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Source&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;$(var.Skin)\Blank.htm&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;DiskId&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;File&lt;/span&gt;  &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;BrowseSequences.htm&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;BrowseSequences.htm&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Source&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;$(var.Skin)\BrowseSequences.htm&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;DiskId&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;File&lt;/span&gt;  &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Favorites.htm&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Favorites.htm&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Source&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;$(var.Skin)\Favorites.htm&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;DiskId&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;File&lt;/span&gt;  &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Index.htm&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Index.htm&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Source&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;$(var.Skin)\Index.htm&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;DiskId&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;          ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Help.Data&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Data&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Help.Data&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Guid&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;170A4245-9DE3-4bd7-B68A-110000000023&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;          &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;File&lt;/span&gt;  &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Alias.xml&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Alias.xml&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Source&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;$(var.Data)\Alias.xml&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;DiskId&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;          ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;DirectoryRef&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Fragment&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Wix&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;At the top I define a component group which in turn is then referenced in the main .wxs file by its it (here ‘Help’). Below I define the components with their content. In this case I want to install some files in a &lt;strong&gt;Help&lt;/strong&gt; subfolder of the installation folder. The help subfolder in turn has two child folders &lt;strong&gt;Skin&lt;/strong&gt; and &lt;strong&gt;Data&lt;/strong&gt; which in turn will contain other files. The whole definition is wrapped by a Fragment tag.&lt;/p&gt;

&lt;h4&gt;Merge Module&lt;/h4&gt;

&lt;p&gt;Merge modules are used to deliver shared code, files, resources, registry entries, and setup logic to applications as a single compound file.However, a merge module cannot be installed alone, it must be merged into an installation package.&amp;#160; A very basic module definition is given below&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;?&lt;/span&gt;&lt;span style="color:#800000;"&gt;xml&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;version&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1.0&amp;#39;&lt;/span&gt;?&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Wix&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;xmlns&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;http://schemas.microsoft.com/wix/2006/wi&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;   &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Module&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;TestModule&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Language&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1033&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Version&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1.0.0.0&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;     &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Package&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;170A4245-9DE3-4bd7-B68A-100000000000&amp;#39;&lt;/span&gt; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;               &lt;span style="color:#ff0000;"&gt;Description&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Basic Merge Module&amp;#39;&lt;/span&gt;                &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;               &lt;span style="color:#ff0000;"&gt;Comments&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;A basic Windows Installer Merge Module&amp;#39;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;               &lt;span style="color:#ff0000;"&gt;Manufacturer&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;TOPAZ Techonlogies&amp;#39;&lt;/span&gt; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;               &lt;span style="color:#ff0000;"&gt;InstallerVersion&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;200&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;TARGETDIR&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;SourceDir&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;MyModuleDirectory&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;MyModuleComponent&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Guid&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;170A4245-9DE3-4bd7-B68A-100000000001&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;               &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;File&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;readme2&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;readme2.txt&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Source&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;readme2.txt&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;            &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;         &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;     &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;   &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Module&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Wix&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The above merge module just installs a single file ‘readme2.txt’ into the target directory. The main difference between the wxs file of an normal install and the wxs file of a merge module is that the former has a &amp;lt;Product&amp;gt; tag whereas the latter has a &amp;lt;Module&amp;gt; tag.&lt;/p&gt;

&lt;h3&gt;Standard Actions&lt;/h3&gt;

&lt;p&gt;There are many standard actions available but not scheduled by default. &lt;strong&gt;ScheduleReboot&lt;/strong&gt;, for instance, will instruct the user to reboot after the installation:&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;InstallExecuteSequence&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ScheduleReboot&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;After&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;InstallFinalize&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;InstallExecuteSequence&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;If the need to reboot depends on a condition (for instance, the operating system the installer is running on), we can use a condition:&lt;/p&gt;

&lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;InstallExecuteSequence&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ScheduleReboot&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;After&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;InstallFinalize&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;VersionNT = 400&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;ScheduleReboot&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;InstallExecuteSequence&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;A reboot will be required if the OS is Windows NT 4.0.&lt;/p&gt;

&lt;h3&gt;Custom Actions&lt;/h3&gt;

&lt;p&gt;It&amp;#39;s not only these so-called standard actions that you can schedule and re-schedule. There are a couple of custom actions as well (custom here means that they don&amp;#39;t appear in the standard course of events but we can use them wherever and whenever we like). A very common need is to launch the application we have just installed or to show a readme.txt file in Notepad.exe at the end of the installation? To do the latter we just add the following code to the .wxs file&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#008000;"&gt;&amp;lt;!-- show the readme.txt file at the end of the installation --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Property&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;NOTEPAD&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;Notepad.exe&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Property&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;CustomAction&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;LaunchFile&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Property&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;NOTEPAD&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;ExeCommand&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;[SourceDir]readme.txt&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Return&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;asyncNoWait&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;InstallExecuteSequence&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Custom&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Action&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;LaunchFile&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;After&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;InstallFinalize&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;NOT Installed&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Custom&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;InstallExecuteSequence&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The “NOT Installed” condition means that the action is only executed if the product has not already been installed at a previous time.&lt;/p&gt;

&lt;h3&gt;Features&lt;/h3&gt;

&lt;p&gt;When installing an application we usually are presented with a list of features we can install. Some of them are mandatory and some of them are optional. The list &lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Feature&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Complete&amp;#39;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;         &lt;span style="color:#ff0000;"&gt;Title&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;TOPAZ Enterprise 6.0&amp;#39;&lt;/span&gt; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;         &lt;span style="color:#ff0000;"&gt;Description&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;The complete package&amp;#39;&lt;/span&gt; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;         &lt;span style="color:#ff0000;"&gt;Display&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;expand&amp;#39;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;         &lt;span style="color:#ff0000;"&gt;ConfigurableDirectory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;INSTALLDIR&amp;#39;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;         &lt;span style="color:#ff0000;"&gt;Level&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Feature&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Please note the attribute &lt;strong&gt;ConfigurableDirectory&lt;/strong&gt; which defines the directory that can be configured by the user during setup. In our case this would be the INSTALLDIR which by default points to the sub-folder “TOPAZ TE6” of the program files folder (refer to chapter: the main installation file).&lt;/p&gt;

&lt;p&gt;The attribute Level=’1’ indicates that this feature is included in the typical installation.&lt;/p&gt;

&lt;p&gt;The features can be (hierarchically) nested. That is each feature can have as many child features as needed. Inside a feature tag we have to reference the components, component groups or merge modules which pertain to the said feature. E.g.&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Feature&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Core&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Title&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Core&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Level&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Backup&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentGroupRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;Help&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;MergeRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;MyModule&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Feature&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;In the above case the feature ‘&lt;strong&gt;Core’&lt;/strong&gt; would contain the component &lt;strong&gt;Backup&lt;/strong&gt;, the component group &lt;strong&gt;Help&lt;/strong&gt; and the merge module &lt;strong&gt;MyModule&lt;/strong&gt; amongst others.&lt;/p&gt;

&lt;h3&gt;Compile and link the installation package&lt;/h3&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The creation of an .msi package is a two step process. First we have to compile the .wxs and .wxi files and then link them. The compiler is called candle.exe and the linker light.exe.&lt;/p&gt;

&lt;p&gt;Assuming we only have one .wsx file called &lt;strong&gt;Product.wxs&lt;/strong&gt; and we use functionality of the two extensions &lt;strong&gt;IISExtension&lt;/strong&gt; and &lt;strong&gt;WixUtilExtension&lt;/strong&gt; the creation would be&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;candle.exe Product.wxs -ext IISExtension -ext WixUtilExtension&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;light.exe Product.wixobj -ext IISExtension -ext WixUtilExtension&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;which results in a &lt;strong&gt;Product.msi&lt;/strong&gt; file.&lt;/p&gt;

&lt;p&gt;If our Product.wxs file references components or component groups defined in another fragment file (e.g. called FramgmentHelp.wxs) then our calls have to be modified as follows&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;candle.exe Product.wxs FragmentHelp.wxs -ext IISExtension -ext WixUtilExtension&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;light.exe Product.wixobj FragmentHelp.wixobj –out Product.msi -ext IISExtension -ext WixUtilExtension&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Please note the &lt;strong&gt;“–out Product.msi&lt;/strong&gt;” part of the second command. Since we have more than one input file for the linker we have to define the name for the output file.&lt;/p&gt;

&lt;p&gt;If we have many include- and fragment files and/or merge modules to include in our compile and link process then we can also define a (text) file from where the candle.exe and the light.exe take their input and thus our commands will be&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;candle.exe @candleInput.txt&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;light.exe @lightInput.txt&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h3&gt;Dealing with many files&lt;/h3&gt;

&lt;p&gt;Our setup package contains many hundred files. It would be a tedious task to add them all manually to the respective wxs files. Unfortunately it is not possible to use file names with wildcards (IMHO this is one of the major disadvantages of WIX compared to NSIS). Each file has to be explicitly added to the setup. Thus I decided to write a small application that automatically creates those entries for me.&lt;/p&gt;

&lt;p&gt;Starting from a given base directory the program loops through all files and recursively through all sub-folders and creates the appropriate XML fragments. Having a directory structure like this&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;ParentFolder&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    File1&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    File2&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ChildFolder1&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        File3&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        GrandChildFolder1&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;            File4&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;            File5&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ChildFolder2&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        File6&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;the application creates an XML fragment like this&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentGroup&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder.ChildFolder1&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder.ChildFolder1.GrandChildFolder1&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder.ChildFolder2&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentGroup&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;DirectoryRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Guid&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;...&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;File&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;...&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;File1&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Source&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;$(var.ParentFolder)\File1&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;DiskId&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;File&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;...&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;File2&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Source&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;$(var.ParentFolder)\File2&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;DiskId&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder.ChildFolder1&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ChildFolder1&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder.ChildFolder1&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Guid&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;...&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;File&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;...&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;File3&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Source&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;$(var.ParentFolder)\ChildFolder1\File3&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;DiskId&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder.ChildFolder1.GrandChildFolder1&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;GrandChildFolder1&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder.ChildFolder1.GrandChildFolder1&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Guid&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;...&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;File&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;...&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;File4&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Source&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;$(var.ParentFolder)\ChildFolder1\GrandChildFolder1\File4&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;DiskId&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;File&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;...&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;File5&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Source&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;$(var.ParentFolder)\ChildFolder1\GrandChildFolder1\File5&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;DiskId&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder.ChildFolder2&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ChildFolder2&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder.ChildFolder2&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Guid&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;...&amp;#39;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;      &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;File&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;...&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;File6&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Source&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;$(var.ParentFolder)\ChildFolder2\File6&amp;#39;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;DiskId&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;1&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Component&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Directory&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;DirectoryRef&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;where at the place of the ‘…’ the application puts a GUID. The code is really simple; it’s just a recursive walk through the directory structure and its files.&lt;/p&gt;

&lt;p&gt;In the main wxs file I then just reference the component group e.g.&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComponentGroupRef&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Id&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;#39;ParentFolder&amp;#39;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h2&gt;Nullsoft Scriptable Install System – NSIS&lt;/h2&gt;

&lt;p&gt;I will touch this framework only briefly since in the end we decided to take WIX for our purposes. Everything about NSIS (download and documentation) can be found &lt;a href="http://nsis.sourceforge.net/Main_Page"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“… NSIS is a professional open source system to create Windows installers. It is designed to be as small and flexible as possible and is therefore very suitable for internet distribution. …&lt;/p&gt;

  &lt;p&gt;NSIS is script-based and allows you to create the logic to handle even the most complex installation tasks. Many plug-ins and scripts are already available: you can create web installers, communicate with Windows and other software components, install or update shared components and more. …”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;NSIS is &lt;strong&gt;NOT&lt;/strong&gt; based on the &lt;strong&gt;Microsoft Windows Installer&lt;/strong&gt; technology! Thus no msi files are produced but rather exe files. My first impression of the product was very good. I especially liked the speed of an installation. Even complex installations take a fraction of the time a MS Windows Installer based installation needs.&lt;/p&gt;

&lt;h3&gt;The Installer Script File&lt;/h3&gt;

&lt;p&gt;As said above NSIS is a script base install system. Our installation script we have to place in a file with the extension &lt;strong&gt;nsi&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Such a file can be compiled to a setup package with this simple command line&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;makensis.exe TOPAZ.nsi&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;where &lt;strong&gt;TOPAZ.nsi&lt;/strong&gt; contains our installation scripts. The compilation is very quick. The creation of a setup package can thus be very easily integrated in an automated build.&lt;/p&gt;

&lt;h3&gt;Define Variables&lt;/h3&gt;

&lt;p&gt;We can define variables for further usage as follows&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!define COMPANY &lt;span style="color:#006080;"&gt;&amp;quot;TOPAZ Technologies&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!define COMPANYLEGAL &lt;span style="color:#006080;"&gt;&amp;quot;Ldt&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!define URL &lt;span style="color:#006080;"&gt;&amp;quot;http://www.topazti.com&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!define PRODUCT &lt;span style="color:#006080;"&gt;&amp;quot;TE6&amp;quot;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;we can also conditionally define a variable depending on the fact whether or not the variable has already been defined e.g. as a command line parameter when calling the NSIS make&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!ifndef VERSION&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  !define VERSION &lt;span style="color:#006080;"&gt;&amp;quot;0.1.0&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!endif&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;later on a variable can be referenced by using the ${&lt;em&gt;VariableName&lt;/em&gt;} syntax, e.g.&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;;Set &lt;span style="color:#0000ff;"&gt;default&lt;/span&gt; installation folder&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;InstallDir &lt;span style="color:#006080;"&gt;&amp;quot;$PROGRAMFILES\${COMPANY}\${PRODUCT}&amp;quot;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;This is very similar to what we are used from tools like &lt;a href="http://nant.sourceforge.net/"&gt;Nant&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Predefined variables are accessed with the syntax $&lt;em&gt;VariableName&lt;/em&gt;; that is no curly braces are needed. An example would be&lt;/p&gt;

&lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;SetOutPath &lt;span style="color:#006080;"&gt;&amp;quot;$INSTDIR&amp;quot;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;which sets the output directory to the content of the pre-defined variable INSTDIR.&lt;/p&gt;

&lt;h3&gt;Sections&lt;/h3&gt;

&lt;p&gt;A nsi file consists of several sections. At least two of them are needed; one to define the install actions and one to define the un-install actions.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Each section contains zero or more instructions. &lt;/li&gt;

  &lt;li&gt;Sections are executed in order by the resulting installer, and if ComponentText is set, the user will have the option of disabling/enabling each visible section. &lt;/li&gt;

  &lt;li&gt;If a section&amp;#39;s name is &amp;#39;Uninstall&amp;#39; or is prefixed with &amp;#39;un.&amp;#39;, it&amp;#39;s an uninstaller section.&lt;/li&gt;
&lt;/ul&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;Section &lt;span style="color:#006080;"&gt;&amp;quot;Core&amp;quot;&lt;/span&gt; SEC_CORE&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    SetOutPath &lt;span style="color:#006080;"&gt;&amp;quot;$INSTDIR&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;SectionEnd&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;Adding Files to the Setup Package&lt;/h3&gt;

&lt;p&gt;To add a single file to the setup package use a command similar to this&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;File readme.txt&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;To add a whole tree of files (while maintaining the hierarchy) I use a command similar to this&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;File /r /x .svn /x index /x log ..\..\build\*.*&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The above command starts from a base directory (here a relative path ‘..\..\build\*.*’) and traverses the whole sub-tree and adds all files found including their relative folders. By using the ‘/x &lt;em&gt;folderName’&lt;/em&gt; command line parameter I can exclude certain files or folders. &lt;em&gt;Compared to how much effort is needed with WIX to accomplish the same thing is is really a “killer feature”.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Creating Directories on the target machine&lt;/h3&gt;

&lt;p&gt;to conditionally create a directory on the target machine I use the following syntax&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;IfFileExists $INSTDIR\index +2 0&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  CreateDirectory $INSTDIR\index&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;User Interface&lt;/h3&gt;

&lt;p&gt;There are several different UI available for the installer; standard, modern UI and ultra modern UI. In the sample we will use the modern UI. To use this UI we have to include the corresponding library with this command&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!include &lt;span style="color:#006080;"&gt;&amp;quot;MUI2.nsh&amp;quot;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;later in the script file we have e.g.&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!insertmacro MUI_PAGE_WELCOME&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!insertmacro MUI_PAGE_LICENSE &lt;span style="color:#006080;"&gt;&amp;quot;.\Eula.rtf&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!insertmacro MUI_PAGE_COMPONENTS&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!insertmacro MUI_PAGE_DIRECTORY&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!insertmacro MUI_PAGE_INSTFILES&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!define MUI_FINISHPAGE_NOAUTOCLOSE&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!define MUI_FINISHPAGE_SHOWREADME &lt;span style="color:#006080;"&gt;&amp;quot;$INSTDIR\readme.txt&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!insertmacro MUI_PAGE_FINISH&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!insertmacro MUI_UNPAGE_WELCOME&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!insertmacro MUI_UNPAGE_CONFIRM&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!insertmacro MUI_UNPAGE_INSTFILES&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!define MUI_UNFINISHPAGE_NOAUTOCLOSE&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!insertmacro MUI_UNPAGE_FINISH&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The above fragment defines that we want to have a set of pages defined in the modern UI library included during our setup and during the uninstall of the product. Of course we should not forget to provide resources of the desired language used by the installer. This can be done by adding this statement&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;!insertmacro MUI_LANGUAGE &lt;span style="color:#006080;"&gt;&amp;quot;English&amp;quot;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;Functions&lt;/h3&gt;

&lt;p&gt;We can define functions in our installer file. As an example I provide the function used to detect whether IIS is installed and whether it is at least IIS 6.0.&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;Function CheckIISVersion&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ClearErrors&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ReadRegDWORD $0 HKLM &lt;span style="color:#006080;"&gt;&amp;quot;SOFTWARE\Microsoft\InetStp&amp;quot;&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;quot;MajorVersion&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ReadRegDWORD $1 HKLM &lt;span style="color:#006080;"&gt;&amp;quot;SOFTWARE\Microsoft\InetStp&amp;quot;&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;quot;MinorVersion&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    IfErrors 0 NoAbort&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    Abort &lt;span style="color:#006080;"&gt;&amp;quot;Setup could not detect Microsoft Internet Information Server v5 or later; this is required for installation. Setup will abort.&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    IntCmp $0 6 NoAbort IISMajVerLT6 NoAbort&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    NoAbort:&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        DetailPrint &lt;span style="color:#006080;"&gt;&amp;quot;Found Microsoft Internet Information Server v$0.$1&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        Goto ExitFunction&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    IISMajVerLT6:&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;        Abort &lt;span style="color:#006080;"&gt;&amp;quot;Setup could not detect Microsoft Internet Information Server v6 or later; this is required for installation. Setup will abort.&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ExitFunction:&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;FunctionEnd&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The script language is simple but powerful. It remembers a little bit the old days we still used to develop in assembler.&lt;/p&gt;

&lt;p&gt;A function like the above one can then be called from a section of the installation file&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;Section &lt;span style="color:#006080;"&gt;&amp;quot;Install Virtual Directory&amp;quot;&lt;/span&gt; SEC_IIS&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    Call CheckIISVersion&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    Call ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;    ...&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;SectionEnd&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;Register Product and prepare Uninstaller&lt;/h3&gt;

&lt;p&gt;NSIS does not automatically register an installed product on the system such as that it is visible in the list of installed products. We have to manually do this. I use the following section to just accomplish this task. The section creates some registry keys and finally creates an uninstaller exe in the install directory.&lt;/p&gt;

&lt;div&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;Section &lt;span style="color:#006080;"&gt;&amp;quot;-Common Items&amp;quot;&lt;/span&gt; SEC_COM&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  ;Store installation folder&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  WriteRegStr HKCU &lt;span style="color:#006080;"&gt;&amp;quot;Software\${COMPANY}\${PRODUCT}&amp;quot;&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;quot;&amp;quot;&lt;/span&gt; $INSTDIR&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  ;Add uninstall information to Add/Remove Programs&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  WriteRegStr HKLM &lt;span style="color:#006080;"&gt;&amp;quot;Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANY} ${PRODUCT}&amp;quot;&lt;/span&gt; \&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;                 &lt;span style="color:#006080;"&gt;&amp;quot;DisplayName&amp;quot;&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;quot;${COMPANY} ${PRODUCT}&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  WriteRegStr HKLM &lt;span style="color:#006080;"&gt;&amp;quot;Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANY} ${PRODUCT}&amp;quot;&lt;/span&gt; \&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;                 &lt;span style="color:#006080;"&gt;&amp;quot;URLInfoAbout&amp;quot;&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;quot;${URL}&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  WriteRegStr HKLM &lt;span style="color:#006080;"&gt;&amp;quot;Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANY} ${PRODUCT}&amp;quot;&lt;/span&gt; \&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;                 &lt;span style="color:#006080;"&gt;&amp;quot;Publisher&amp;quot;&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;quot;${COMPANY} ${COMPANYLEGAL}&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  WriteRegStr HKLM &lt;span style="color:#006080;"&gt;&amp;quot;Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANY} ${PRODUCT}&amp;quot;&lt;/span&gt; \&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;                 &lt;span style="color:#006080;"&gt;&amp;quot;DisplayVersion&amp;quot;&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;quot;${VERSION}&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  WriteRegStr HKLM &lt;span style="color:#006080;"&gt;&amp;quot;Software\Microsoft\Windows\CurrentVersion\Uninstall\${COMPANY} ${PRODUCT}&amp;quot;&lt;/span&gt; \&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;                 &lt;span style="color:#006080;"&gt;&amp;quot;UninstallString&amp;quot;&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;quot;$\&amp;quot;$INSTDIR\uninstall.exe$\&amp;quot;&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  ;Create uninstaller&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;  WriteUninstaller &lt;span style="color:#006080;"&gt;&amp;quot;$INSTDIR\Uninstall.exe&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, &amp;#39;Courier New&amp;#39;, courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;SectionEnd&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;In my opinion this puts an unnecessary burden onto the shoulders of the developer since every single installed product has to be registered. Thus I would expect that this happens automatically. Also there is no such thing as an automatic repair functionality. Compared to WIX we have a clear disadvantage here.&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;In this post I have shown in detail the various steps needed to create a setup package with WIX for a product consisting of many hundreds of files. The setup package also assigns write access for certain folders to specific users and/or groups. It creates a virtual directory for the application and defines a new application pool to which the virtual directory is assigned. Furthermore the setup creates a backup of pre-existing configuration files when upgrading a previous version of the product. The whole setup is fully transactional and can be changed or repaired at a later time. The product is ready for patches or upgrades if needed. I have also shown how the setup can be localized.&lt;/p&gt;

&lt;p&gt;We use WIX to create our setup packages. WIX is free and open source. Some tasks could be simpler or more streamlined (like e.g. the usage of properties) and the documentation could be more detailed. Once all missing pieces of information are collected the creation of a setup package is straight forward and easy to do.&lt;/p&gt;

&lt;p&gt;IMHO comparing NSIS with WIX is similar to comparing C++ (no .NET) with C# on .NET. With NSIS you have much more fine grain control of the installation process than with WIX. On the other hand you have to invest more time in providing such useful features as transactional install and repair functionality as well as fail-safe de-installation. This was the main reason that we finally decided to take WIX as our tool for the creation of setup packages. Still I think NSIS is a very powerful and mature product with lightening speed.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22458" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/976F2AC0015A0AAC0FD4ACF68F320D78182E768B"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/976F2AC0015A0AAC0FD4ACF68F320D78182E768B"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=8XJuVPYiJj4:frOT3P_3lF0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=8XJuVPYiJj4:frOT3P_3lF0:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=8XJuVPYiJj4:frOT3P_3lF0:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=8XJuVPYiJj4:frOT3P_3lF0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/8XJuVPYiJj4" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/gabrielschenker/archive/tags/tutorial/default.aspx">tutorial</category><category domain="http://www.lostechies.com/blogs/gabrielschenker/archive/tags/installation/default.aspx">installation</category><category domain="http://www.lostechies.com/blogs/gabrielschenker/archive/tags/NSIS/default.aspx">NSIS</category><category domain="http://www.lostechies.com/blogs/gabrielschenker/archive/tags/WIX/default.aspx">WIX</category><feedburner:origLink>http://www.lostechies.com/blogs/gabrielschenker/archive/2009/06/26/walking-through-the-creation-of-a-complex-installer-package.aspx</feedburner:origLink></item><item><title>How To? Highly Complex Query Generating Based On Security Needs</title><link>http://feedproxy.google.com/~r/LosTechies/~3/sO_yoD96rhw/how-to-highly-complex-query-generating-based-on-security-needs.aspx</link><pubDate>Thu, 25 Jun 2009 20:26:29 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22430</guid><dc:creator>derick.bailey</dc:creator><slash:comments>11</slash:comments><description>&lt;p&gt;I have the following object model:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;img title="image" style="border-top-width:0px;display:inline;border-left-width:0px;border-bottom-width:0px;border-right-width:0px;" height="508" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/derickbailey/image_5F00_38648237.png" width="512" border="0" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;An Office belongs to one Office Group. An Office also belongs to one Office Region. There is no relationship between Office Group and Office Region. They are two separate groupings for various reasons. A Counselor belongs to one Office. A Veteran is assigned to one Office.&lt;/p&gt;  &lt;p&gt;I need to implement the following security rules for a Counselor looking at Veterans, starting with “deny access to all Veteran records, unless any of the following are true”:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;If a Counselor is an Administrator (a role of the Counselor), that Counselor can see all Veteran records &lt;/li&gt;    &lt;li&gt;A Counselor can see any Veteran that has no current Office assignment &lt;/li&gt;    &lt;li&gt;A Counselor can see Veterans that are assigned to an Office within the Counselor’s Office Group &lt;/li&gt;    &lt;li&gt;If a Counselor belongs to a “Regional Office”, that Counselor can see Veterans that are assigned to that Region &lt;/li&gt;    &lt;li&gt;… a few others in similar fashion … &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;I also need to implement the following around the above rules:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;When a Counselor searches for Veterans, they are only allowed to see search results that meet the above criteria &lt;/li&gt;    &lt;li&gt;When a Counselor views the detail of a Veteran, they are only allowed to see the the Veteran if the above criteria is met. This includes, if a Counselor tries to manually load a Veteran (manually type in url “id=1234”)&lt;/li&gt;    &lt;ol&gt;     &lt;li&gt;… and the Counselor is not allowed to see the Veteran, show a “Not Authorized” message &lt;/li&gt;      &lt;li&gt;… and the Vet does not exist, show a “Vet Does Not Exist” message &lt;/li&gt;   &lt;/ol&gt; &lt;/ol&gt;  &lt;p&gt;so…&lt;/p&gt;  &lt;p&gt;how do you create a search process around a security need like this? How do you go about creating a very complex rule system to determine which Veterans the Counselor can see? In my ideal world, I’d have some way of checking this security need against the search results and against an individual veteran record, without duplicating the code or logic for that check anywhere… is this a realistic expectation? What “standard” security implementations are out there, that would help me resolve my needs?&lt;/p&gt;  &lt;p&gt;This is being done in C# in an ASP.NET Webforms app, using NHibernate for our ORM. I don’t expect NHibernate to be able to solve this problem for us, but if it can, that’s even better. And, I do expect to be able to write some sort of Unit or Integration tests around whatever the process is.&lt;/p&gt;  &lt;p&gt;Any advice or help is appreciated.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22430" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/5F8C343B3C10E744C53559EB4FE2772E18869737"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/5F8C343B3C10E744C53559EB4FE2772E18869737"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=sO_yoD96rhw:zDIQRwZBRUo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=sO_yoD96rhw:zDIQRwZBRUo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=sO_yoD96rhw:zDIQRwZBRUo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=sO_yoD96rhw:zDIQRwZBRUo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/sO_yoD96rhw" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/Unit+Testing/default.aspx">Unit Testing</category><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/.NET/default.aspx">.NET</category><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/Data+Access/default.aspx">Data Access</category><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://www.lostechies.com/blogs/derickbailey/archive/tags/Security/default.aspx">Security</category><feedburner:origLink>http://www.lostechies.com/blogs/derickbailey/archive/2009/06/25/how-to-highly-complex-query-generating-based-on-security-needs.aspx</feedburner:origLink></item><item><title>Python Web Framework Series – Pylons: Part 3 Views with Mako</title><link>http://feedproxy.google.com/~r/LosTechies/~3/M45tDu3sVeY/python-web-framework-series-pylons-part-3-views-with-mako.aspx</link><pubDate>Thu, 25 Jun 2009 04:53:00 GMT</pubDate><guid isPermaLink="false">ded273ab-9e87-4979-8222-e4e2e46f1b46:22416</guid><dc:creator>Ryan Svihla</dc:creator><slash:comments>3</slash:comments><description>&lt;p&gt;This is a huge post and I should have split this into several smaller ones so please bear with me while I get my series format tweaked.&amp;nbsp; We last left off with &lt;a href="http://www.lostechies.com/blogs/rssvihla/archive/2009/06/24/python-web-framework-series-pylons-part-2-controllers-and-views.aspx" target="_blank"&gt;Controllers, Views and Testing&lt;/a&gt; with a basic test, basic view and basic controller.&amp;nbsp; Now with our basic scaffold built we can focus on making our views reusable, dynamic, and more pleasant to look at.&lt;/p&gt;
&lt;h3&gt;First things first&lt;/h3&gt;
&lt;p&gt;First before we dive too deeply into Mako, lets setup a default home page by doing the following: &lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;delete the index.html in the &lt;b&gt;pylonsforum\publ&lt;/b&gt;&lt;i&gt;ic\&lt;/i&gt; folder. &lt;/li&gt;
&lt;li&gt;in&lt;b&gt; pylonsforum\config\routing.py&lt;/b&gt; add the following line somewhere under the line &lt;b&gt;&amp;ldquo;# CUSTOM ROUTES HERE&amp;rdquo;&lt;/b&gt; but before &lt;b&gt;&amp;ldquo;return map&amp;rdquo;&lt;/b&gt;.       &lt;ol&gt;
&lt;li&gt;map.connect(&amp;quot;home&amp;quot;, &amp;quot;/&amp;quot;, controller=&amp;quot;login&amp;quot;, action=&amp;quot;index&amp;quot;) &lt;/li&gt;
&lt;/ol&gt;   &lt;/li&gt;
&lt;li&gt;assuming you have your Pylons command we used earlier&amp;nbsp; &lt;b&gt;paster server &amp;ndash;-reload development.ini &lt;/b&gt;then open your browser to &lt;a href="http://127.0.0.1:5000"&gt;http://127.0.0.1:5000&lt;/a&gt; and you should see the view we created in the last lesson. &lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;h3&gt;Basics&lt;/h3&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Mako uses standard python mixed with HTML to display views. This gives you both a great deal of flexibility and a great deal of ability to hang yourself. So be warned, avoid putting to much logic into your view, since you can do about anything there.&lt;/p&gt;
&lt;p&gt;Open up &lt;b&gt;templates\index.mako&lt;/b&gt;&lt;i&gt; &lt;/i&gt;replace the table rows in the table body with the following:&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:8647342E-C6F6-4230-979C-77E8BB3FA682:846a2bbe-f783-4ffb-a6d5-1019a7648ebb" class="wlWriterSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;tbody&amp;gt;&lt;/b&gt;&lt;/span&gt;       &lt;br /&gt;&lt;span style="color:#bc7a00;"&gt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; p &lt;span style="color:#aa22ff;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts:       &lt;br /&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;p&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;p&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;p&lt;span style="color:#666666;"&gt;.&lt;/span&gt;dateadded&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/b&gt;&lt;/span&gt;       &lt;br /&gt;&lt;span style="color:#bc7a00;"&gt;%&lt;/span&gt;endfor&amp;nbsp; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/tbody&amp;gt;&lt;/b&gt;&lt;/span&gt;       &lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;for good measure in the beginning of the body before the &amp;ldquo;recent posts&amp;rdquo; div place the following&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:8647342E-C6F6-4230-979C-77E8BB3FA682:3c3e6661-c103-4282-8f49-f3f524932984" class="wlWriterSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;body&amp;gt;&lt;/b&gt;&lt;/span&gt;       &lt;br /&gt;username: &lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;username&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;div&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;id=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;recentposts&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;style=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;float: right&amp;quot;&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;gt;&lt;/b&gt;&lt;/span&gt;       &lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Looking at this, for the tables we&amp;rsquo;ve done a for loop over some variable called c.posts. In the second we&amp;rsquo;re accessing another variable c.username. &amp;ldquo;c&amp;rdquo; is shorthand for Template Context, similar to ViewData in Asp.Net MVC and PropertyBag in Monorail, except we&amp;rsquo;re not accessing a string dictionary.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;Add the following tests in &amp;ldquo;&lt;b&gt;pylonsforum\tests\functional\test_home.py&lt;/b&gt;&amp;rdquo;&amp;nbsp; for what we need to add to the controller:&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:8647342E-C6F6-4230-979C-77E8BB3FA682:97574e79-c88f-4bc0-bbcc-9c9464479c8c" class="wlWriterSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;test_username&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):       &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; response &lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;app&lt;span style="color:#666666;"&gt;.&lt;/span&gt;get(url(controller&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;home&amp;#39;&lt;/span&gt;, action&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;index&amp;#39;&lt;/span&gt;))       &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;username: rsvihla&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; response       &lt;br /&gt;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;test_recent_posts&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):       &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; response &lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;app&lt;span style="color:#666666;"&gt;.&lt;/span&gt;get(url(controller&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;home&amp;#39;&lt;/span&gt;, action&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;index&amp;#39;&lt;/span&gt;))       &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;jkruse&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;New Kindle&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;06/24/2009&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; response       &lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;running &lt;i&gt;nosetests &amp;ndash;-with-pylons=test.init&lt;/i&gt; should give you two assertion failures.&lt;/p&gt;
&lt;p&gt;now change &amp;ldquo;&lt;b&gt;pylonsforum\controllers\home.py&lt;/b&gt;&amp;rdquo; to look like so:&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:8647342E-C6F6-4230-979C-77E8BB3FA682:ba5c3c97-1eb6-4ef4-bc39-47fd77ceeb80" class="wlWriterSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;logging&lt;/b&gt;&lt;/span&gt;       &lt;br /&gt;      &lt;br /&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;pylons&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt; request, response, session, tmpl_context &lt;span style="color:#008000;"&gt;&lt;b&gt;as&lt;/b&gt;&lt;/span&gt; c       &lt;br /&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;pylons.controllers.util&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt; abort, redirect_to       &lt;br /&gt;      &lt;br /&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;pylonsforum.lib.base&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt; BaseController, render       &lt;br /&gt;      &lt;br /&gt;log &lt;span style="color:#666666;"&gt;=&lt;/span&gt; logging&lt;span style="color:#666666;"&gt;.&lt;/span&gt;getLogger(__name__)       &lt;br /&gt;      &lt;br /&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;Post&lt;/b&gt;&lt;/span&gt;(&lt;span style="color:#008000;"&gt;object&lt;/span&gt;):       &lt;br /&gt;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;__init__&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;, author, subject, dateadded):       &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author &lt;span style="color:#666666;"&gt;=&lt;/span&gt; author       &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject &lt;span style="color:#666666;"&gt;=&lt;/span&gt; subject       &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;dateadded &lt;span style="color:#666666;"&gt;=&lt;/span&gt; dateadded       &lt;br /&gt;      &lt;br /&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;HomeController&lt;/b&gt;&lt;/span&gt;(BaseController):       &lt;br /&gt;      &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;index&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):       &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;username &lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;rsvihla&amp;quot;&lt;/span&gt;       &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts &lt;span style="color:#666666;"&gt;=&lt;/span&gt; [Post(&lt;span style="color:#ba2121;"&gt;&amp;quot;jkruse&amp;quot;&lt;/span&gt;, &lt;span style="color:#ba2121;"&gt;&amp;quot;New Kindle&amp;quot;&lt;/span&gt;, &lt;span style="color:#ba2121;"&gt;&amp;quot;06/24/2009&amp;quot;&lt;/span&gt;)]       &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; render(&lt;span style="color:#ba2121;"&gt;&amp;#39;index.mako&amp;#39;&lt;/span&gt;)       &lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;ve added a Post class with basic attributes and placed them in an array in the c.posts variable, also we&amp;rsquo;ve hardcoded the username &amp;ldquo;rsvihla&amp;rdquo;.&amp;nbsp; I know the more experience developers here are cringing at my awful little Post class, don&amp;rsquo;t worry its a just a place holder and will be removed later.&amp;nbsp; The point here is building functionality in steps with test coverage.&amp;nbsp; Now run nosetests just as before and you should have all tests passing.&amp;nbsp; For bonus measure refresh &lt;a href="http://127.0.0.1:5000"&gt;http://127.0.0.1:5000&lt;/a&gt; .&lt;/p&gt;
&lt;h3&gt;Base Layouts&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ve built a very basic page now, but suppose we want to build several and have some bits of information show up over and over again, like user name or menu structure.&lt;/p&gt;
&lt;p&gt;create a base template named &amp;ldquo;base.mako&amp;rdquo; in the templates directory that has the following in it:&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:4debdbf4-d16d-47ad-be89-81cefed9ed24" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;namespace&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;name=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;module=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;pylonsforum.model.users&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#bc7a00;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;!DOCTYPE&amp;nbsp;html&amp;nbsp;PUBLIC&amp;nbsp;&amp;quot;-//W3C//DTD&amp;nbsp;XHTML&amp;nbsp;1.0&amp;nbsp;Transitional//EN&amp;quot;&amp;nbsp;&amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;html&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;head&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;title&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;title()&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/title&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;head_tags()&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;style&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#7d9029;"&gt;type=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;text/css&amp;quot;&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;#header{&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;height&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;70px&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;width&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;100&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;%;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;border-width&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;.5px&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;border-style&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;solid&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;font-size&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#aa22ff;"&gt;:30px&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;text-align&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;center&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;background-color&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;#9B2C25&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;#sidebar{&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;background-color&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;#C1AD72&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;border-width&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;.5px&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;border-style&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;dotted&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;width&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;150px&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;height&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;600px&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;float&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;right&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;font-size&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;15px&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;padding-top&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#aa22ff;"&gt;:10px&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;padding-left&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#aa22ff;"&gt;:5px&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;#content{&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;margin-top&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#aa22ff;"&gt;:10px&lt;/span&gt;&lt;span style="color:#666666;"&gt;;&lt;/span&gt;&lt;br /&gt;
}&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;body&lt;/b&gt;&lt;/span&gt;&amp;nbsp;{&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;background-color&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#666666;"&gt;:&lt;/span&gt;&amp;nbsp;&lt;span style="color:#666666;"&gt;#DACEAB&lt;/span&gt;;&lt;br /&gt;
}&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/style&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/head&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;body&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;div&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;id=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;header&amp;quot;&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;gt;&lt;/b&gt;&lt;/span&gt;Pylons&amp;nbsp;Forum&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/div&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;div&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;id=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;sidebar&amp;quot;&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
username:&amp;nbsp;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;user&lt;span style="color:#666666;"&gt;.&lt;/span&gt;get_current_user()&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/div&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;div&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;id=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;content&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;body()&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;br /&gt;
	&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/div&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/div&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/body&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/html&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Most everything is standard HTML so lets restrict this to the interesting bits:&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:8f61ba60-2ee5-467f-834a-25ad871eabc0" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;namespace&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;name=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;module=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;pylonsforum.model.users&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#bc7a00;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The namespace directive here is basically doing an import of a custom module and giving it an alias of user. This is no different than in normal python code typing:&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:95232d96-8fd9-4dfd-bd60-438f4f6ff2f8" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;pylonsforum.model.users&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;as&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;user&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;This is used later in the div sidebar by pulling the current user from my customer users module:&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:83af8ad1-3bb5-4f9e-834a-fb8a571d9578" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
username&amp;nbsp;:&amp;nbsp;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;user&lt;span style="color:#666666;"&gt;.&lt;/span&gt;get_current_user()&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;the module source only contains a simple hard coded value for now&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:ad20fa72-5e3d-457d-a8ea-d6c037af5d60" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;get_current_user&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;rsvihla&amp;quot;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Now onto the next non-HTML tidbits&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:e28f96b3-5405-4df2-80f9-ddee6b7ae9e1" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;title&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;title()&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/title&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;head_tags()&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;body()&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Everyone of the above methods establishes a base method that the child templates must now call with the exception of self.body (which is called when the templates actually render the content anyway).&amp;nbsp; So lets adjust &amp;ldquo;index.mako&amp;rdquo; template to the following: &lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:bef7ee62-9d54-4e85-b28b-feb9cabb2c08" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;inherit&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;file=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;/base.mako&amp;quot;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;name=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;title()&amp;quot;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&lt;/span&gt;Pylons&amp;nbsp;Forum&lt;span style="color:#bc7a00;"&gt;&amp;lt;/%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;name=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;head_tags()&amp;quot;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&amp;lt;/%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;div&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;id=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;recentposts&amp;quot;&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;table&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;&lt;/b&gt;&lt;/span&gt;subject&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;&lt;/b&gt;&lt;/span&gt;author&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;&lt;/b&gt;&lt;/span&gt;date&amp;nbsp;submitted&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;tbody&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt;&amp;nbsp;p&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;nbsp;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;posts:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;p&lt;span style="color:#666666;"&gt;.&lt;/span&gt;author&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;p&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;p&lt;span style="color:#666666;"&gt;.&lt;/span&gt;dateadded&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;%&lt;/span&gt;endfor&amp;nbsp;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/tbody&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/table&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/div&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The inherit line at the very top references our base.mako template. The next two lines with the &amp;lt;%def tag are where our previous self.head_tags() and self.title() methods are referenced.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll notice the title method is passing in a new title for the page, and our head_tags method is doing nothing, so no changes there. Browse to your pylons home page and you should see something resembling this:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_024C9A53.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_thumb_5F00_4B061317.png" border="0" width="624" height="412" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Your tests should also still pass with no modification.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_296A8FE0.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_thumb_5F00_4436B5EC.png" border="0" width="655" height="91" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;Forms and Web Helpers&lt;/h3&gt;
&lt;p&gt;Lets add a basic submit form and a link in the base.mako template to go to the new form page. &lt;/p&gt;
&lt;p&gt;Add the following tests to &lt;b&gt;test_home.py&lt;/b&gt;&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:bea5181a-f96a-474e-a0a2-917cc4c923ae" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;test_new_thread&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;app&lt;span style="color:#666666;"&gt;.&lt;/span&gt;get(url(controller&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;home&amp;quot;&lt;/span&gt;,&amp;nbsp;action&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;newthread&amp;quot;&lt;/span&gt;))&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;&amp;lt;input&amp;nbsp;id=&lt;/span&gt;&lt;span style="color:#bb6622;"&gt;&lt;b&gt;\&amp;quot;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;subject&lt;/span&gt;&lt;span style="color:#bb6622;"&gt;&lt;b&gt;\&amp;quot;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;nbsp;name=&lt;/span&gt;&lt;span style="color:#bb6622;"&gt;&lt;b&gt;\&amp;quot;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;subject&lt;/span&gt;&lt;span style="color:#bb6622;"&gt;&lt;b&gt;\&amp;quot;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;nbsp;type=&lt;/span&gt;&lt;span style="color:#bb6622;"&gt;&lt;b&gt;\&amp;quot;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;text&lt;/span&gt;&lt;span style="color:#bb6622;"&gt;&lt;b&gt;\&amp;quot;&lt;/b&gt;&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;nbsp;/&amp;gt;&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;nbsp;response&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;test_submit_new_thread&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;response&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;self&lt;/span&gt;&lt;span style="color:#666666;"&gt;.&lt;/span&gt;app&lt;span style="color:#666666;"&gt;.&lt;/span&gt;post(url(controller&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;home&amp;quot;&lt;/span&gt;,&amp;nbsp;action&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;submitnewthread&amp;quot;&lt;/span&gt;),&amp;nbsp;params&lt;span style="color:#666666;"&gt;=&lt;/span&gt;{&lt;span style="color:#ba2121;"&gt;&amp;#39;subject&amp;#39;&lt;/span&gt;:&lt;span style="color:#ba2121;"&gt;&amp;#39;test&amp;#39;&lt;/span&gt;,&lt;span style="color:#ba2121;"&gt;&amp;#39;content&amp;#39;&lt;/span&gt;:&lt;span style="color:#ba2121;"&gt;&amp;#39;testcontent&amp;#39;&lt;/span&gt;})&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#ba2121;"&gt;&amp;quot;post&amp;nbsp;submitted&amp;quot;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;nbsp;response&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Install FormBuild with the following command:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_786ADF32.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_thumb_5F00_61AB97A9.png" border="0" width="647" height="39" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Next open &lt;b&gt;lib\helpers.py &lt;/b&gt;and change the imports to as follows: &lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_080D7AF5.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_thumb_5F00_181C49AC.png" border="0" width="655" height="85" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;In the sidebar div under username add &lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:2c07eb80-2f2d-4011-b82c-4d76e81d20d0" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;br/&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;h&lt;span style="color:#666666;"&gt;.&lt;/span&gt;link_to(&lt;span style="color:#ba2121;"&gt;&amp;#39;new&amp;nbsp;thread&amp;#39;&lt;/span&gt;,&amp;nbsp;h&lt;span style="color:#666666;"&gt;.&lt;/span&gt;url_for(controller&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;home&amp;#39;&lt;/span&gt;,&amp;nbsp;action&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;newthread&amp;#39;&lt;/span&gt;))&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now add an action on the home controller for :&amp;rdquo;new thread&amp;rdquo; and create a view in your templates folder called &lt;b&gt;newthread.mako&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;Add the following to your &lt;b&gt;home.py&lt;/b&gt; controller:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:ac0780ed-a2e7-45f2-a783-6d041c6a6fd6" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;newthread&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;render(&lt;span style="color:#ba2121;"&gt;&amp;#39;newthread.mako&amp;#39;&lt;/span&gt;)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;&lt;/h3&gt;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;The newthread.mako file should have the following in it:&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:a13873fd-1c5f-4254-9a3b-7f100bbb7487" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;inherit&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;file=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;/base.mako&amp;quot;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;name=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;title()&amp;quot;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&lt;/span&gt;Make&amp;nbsp;A&amp;nbsp;New&amp;nbsp;Thread&lt;span style="color:#bc7a00;"&gt;&amp;lt;/%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;name=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;head_tags()&amp;quot;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&amp;lt;/%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;h&lt;span style="color:#666666;"&gt;.&lt;/span&gt;form_start(h&lt;span style="color:#666666;"&gt;.&lt;/span&gt;url_for(controller&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;home&amp;#39;&lt;/span&gt;,&amp;nbsp;action&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;submitnewthread&amp;#39;&lt;/span&gt;),&amp;nbsp;method&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;post&amp;quot;&lt;/span&gt;)&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;h&lt;span style="color:#666666;"&gt;.&lt;/span&gt;field(&lt;span style="color:#ba2121;"&gt;&amp;quot;Subject&amp;quot;&lt;/span&gt;,&amp;nbsp;field&lt;span style="color:#666666;"&gt;=&lt;/span&gt;h&lt;span style="color:#666666;"&gt;.&lt;/span&gt;text(name&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;subject&amp;#39;&lt;/span&gt;))&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;h&lt;span style="color:#666666;"&gt;.&lt;/span&gt;field(&lt;span style="color:#ba2121;"&gt;&amp;quot;Content&amp;quot;&lt;/span&gt;&amp;nbsp;,field&lt;span style="color:#666666;"&gt;=&lt;/span&gt;h&lt;span style="color:#666666;"&gt;.&lt;/span&gt;textarea(name&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;content&amp;#39;&lt;/span&gt;))&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&amp;nbsp;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;h&lt;span style="color:#666666;"&gt;.&lt;/span&gt;field(field&lt;span style="color:#666666;"&gt;=&lt;/span&gt;h&lt;span style="color:#666666;"&gt;.&lt;/span&gt;submit(value&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;Create&amp;nbsp;Thread&amp;quot;&lt;/span&gt;,&amp;nbsp;name&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;submit&amp;#39;&lt;/span&gt;))&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;h&lt;span style="color:#666666;"&gt;.&lt;/span&gt;form_end()&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Sooooooo what are h values everywhere?&amp;nbsp; Do I need them? They come from our earlier imports in &lt;b&gt;&lt;span style="text-decoration:underline;"&gt;l&lt;/span&gt;ib\helpers.py , &lt;/b&gt;and no you do not actually need to use them, a typical HTML form tag is all you actually need, this is an available option for those interested. &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;h.form_start and h.form_end are pretty self explanatory &lt;/li&gt;
&lt;li&gt;h.field takes label text as argument one, and then a url for argument two. &lt;/li&gt;
&lt;li&gt;h.text, h.textarea, h.hidden and h.submit represent their html counterparts.\ &lt;/li&gt;
&lt;li&gt;h.url_for takes a controller and action to make a url for you. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;We now need another action for actually posting our data. so add another method to our &lt;b&gt;home.py&lt;/b&gt; controller:&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:c69f6d2b-9e26-474b-b1f2-e2784ae7d40b" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;submitnewthread&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;username&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;uses&lt;span style="color:#666666;"&gt;.&lt;/span&gt;get_current_user(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;request&lt;span style="color:#666666;"&gt;.&lt;/span&gt;POST[&lt;span style="color:#ba2121;"&gt;&amp;#39;subject&amp;#39;&lt;/span&gt;]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;request&lt;span style="color:#666666;"&gt;.&lt;/span&gt;POST[&lt;span style="color:#ba2121;"&gt;&amp;#39;content&amp;#39;&lt;/span&gt;]&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;render(&lt;span style="color:#ba2121;"&gt;&amp;#39;submitnewthread.mako&amp;#39;&lt;/span&gt;)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;With the following import at the top &lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:b28d6fbd-c69b-4aec-8b5f-4bcdf4bf1fa0" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;pylonsforum.model.users&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Our &lt;b&gt;submitnewthread.mako&lt;/b&gt; view should have the following:&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:16860153-7811-4e62-aaa1-8ad81dc59676" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;inherit&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;file=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;/base.mako&amp;quot;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;name=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;title()&amp;quot;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&lt;/span&gt;Thank&amp;nbsp;You&amp;nbsp;For&amp;nbsp;Your&amp;nbsp;Submission&lt;span style="color:#bc7a00;"&gt;&amp;lt;/%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#bc7a00;"&gt;&amp;lt;%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&amp;nbsp;&lt;span style="color:#7d9029;"&gt;name=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;quot;head_tags()&amp;quot;&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&amp;lt;/%&lt;/span&gt;&lt;span style="color:#008000;"&gt;def&lt;/span&gt;&lt;span style="color:#bc7a00;"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;p&amp;gt;&lt;/b&gt;&lt;/span&gt;post&amp;nbsp;submitted&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;/p&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
data&amp;nbsp;was&amp;nbsp;as&amp;nbsp;follows&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;br/&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
author:&amp;nbsp;&amp;nbsp;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;username&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;br/&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
subject:&amp;nbsp;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;subject&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;br&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;/&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
content:&amp;nbsp;&lt;span style="color:#bc7a00;"&gt;${&lt;/span&gt;c&lt;span style="color:#666666;"&gt;.&lt;/span&gt;content&lt;span style="color:#bc7a00;"&gt;}&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;&amp;lt;br&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;/&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;newthread view should look like so&lt;/p&gt;
&lt;h3&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_0C868C6D.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_thumb_5F00_67F4FEE8.png" border="0" width="595" height="376" /&gt;&lt;/a&gt; &lt;/h3&gt;
&lt;p&gt;and submitnewthread page should look like this&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_63124B2C.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_thumb_5F00_10936AF0.png" border="0" width="598" height="524" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;Validation&lt;/h3&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Validation is a huge subject in Pylons, I&amp;rsquo;m going to just focus on the most basic common case.&lt;/p&gt;
&lt;p&gt;Open &lt;b&gt;home.py &lt;/b&gt;controller again and add these two imports to the top&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:35507e73-57d6-427f-b725-8b472eaa8e23" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;formencode&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;from&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;pylons.decorators&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;validate&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Then in the same file for now below the post object add&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:7db17913-29ff-4325-b34b-83b813d7b3fb" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&lt;span style="color:#008000;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;&lt;b&gt;PostForm&lt;/b&gt;&lt;/span&gt;(formencode&lt;span style="color:#666666;"&gt;.&lt;/span&gt;Schema):&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;allow_extra_fields&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;filter_extra_fields&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;subject&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;formencode&lt;span style="color:#666666;"&gt;.&lt;/span&gt;validators&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(not_empty&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;content&amp;nbsp;&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&amp;nbsp;formencode&lt;span style="color:#666666;"&gt;.&lt;/span&gt;validators&lt;span style="color:#666666;"&gt;.&lt;/span&gt;String(not_empty&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;)&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Finally on top of the submitnewthead action in the same class file add&lt;/p&gt;
&lt;div style="padding-bottom:0px;margin:0px;padding-left:0px;padding-right:0px;display:inline;float:none;padding-top:0px;" id="scid:2EC9848E-067D-4e79-BAB7-06CA927DB962:2d176cfe-6783-47e6-9bcd-cc49bb38970a" class="wlWriterEditableSmartContent"&gt;
&lt;div style="font-family:consolas,lucida console,courier,monospace;"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#aa22ff;"&gt;@validate&lt;/span&gt;(schema&lt;span style="color:#666666;"&gt;=&lt;/span&gt;PostForm(),&amp;nbsp;form&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#ba2121;"&gt;&amp;#39;newthread&amp;#39;&lt;/span&gt;,&amp;nbsp;post_only&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;,&amp;nbsp;on_get&lt;span style="color:#666666;"&gt;=&lt;/span&gt;&lt;span style="color:#008000;"&gt;True&lt;/span&gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color:#008000;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color:#0000ff;"&gt;submitnewthread&lt;/span&gt;(&lt;span style="color:#008000;"&gt;self&lt;/span&gt;):&lt;br /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now if you attempt to leave either the subject or content fields blank PylonsForum will now notify you of what you missed.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_26E91035.png"&gt;&lt;img style="border-right-width:0px;display:inline;border-top-width:0px;border-bottom-width:0px;border-left-width:0px;" title="image" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_thumb_5F00_546A2FF8.png" border="0" width="605" height="388" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;When done your tests should all pass&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_17F14468.png"&gt;&lt;img style="border-bottom:0px;border-left:0px;display:inline;border-top:0px;border-right:0px;" title="image" alt="image" src="http://www.lostechies.com/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/rssvihla/image_5F00_thumb_5F00_5E6E3470.png" border="0" width="602" height="91" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;We went through the 80% cases for views, controllers and a brief bit about testing the response object. We still haven&amp;rsquo;t done a lot of unit testing in the traditional sense but we&amp;rsquo;ve been focusing exclusively on UI.&amp;nbsp; Stay tuned next for my SQL Alchemy piece.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://www.lostechies.com/aggbug.aspx?PostID=22416" width="1" height="1"&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/LOSTECHIES/0D82BCCF942A9588C825997A3D3B850461353CF0"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/LOSTECHIES/0D82BCCF942A9588C825997A3D3B850461353CF0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=M45tDu3sVeY:SPBZqfYoMos:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=M45tDu3sVeY:SPBZqfYoMos:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?i=M45tDu3sVeY:SPBZqfYoMos:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/LosTechies?a=M45tDu3sVeY:SPBZqfYoMos:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/LosTechies?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/LosTechies/~4/M45tDu3sVeY" height="1" width="1"/&gt;</description><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Python/default.aspx">Python</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Pylons/default.aspx">Pylons</category><category domain="http://www.lostechies.com/blogs/rssvihla/archive/tags/Mako/default.aspx">Mako</category><feedburner:origLink>http://www.lostechies.com/blogs/rssvihla/archive/2009/06/25/python-web-framework-series-pylons-part-3-views-with-mako.aspx</feedburner:origLink></item></channel></rss>
