<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="http://www.theplancollection.com/styles/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en" xmlns:media="http://search.yahoo.com/mrss/" ><title type="html">Technology related articles from The Plan Collection</title><subtitle type="html">house plans articles information home building</subtitle><link rel="self" href="http://www.theplancollection.com/house-plan-related-articles/atom" /><link rel="alternate" href="http://www.theplancollection.com/house-plan-related-articles/Default.aspx" /><updated>2009-11-24T21:08:32Z</updated><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><id>http://www.theplancollection.com/house-plan-related-articles/Default.aspx</id><generator>The Plan Collection Atom Generator</generator><logo>http://www.theplancollection.com/images/logo.gif</logo><rights type="html">&amp;copy; 2009 The Plan Collection</rights><link rel="next" href="http://www.theplancollection.com/house-plan-related-articles/atom" /><link rel="previous" href="http://www.theplancollection.com/house-plan-related-articles/page-1/atom" /><link rel="first" href="http://www.theplancollection.com/house-plan-related-articles/page-1/atom" /><link rel="last" href="http://www.theplancollection.com/house-plan-related-articles/page-1/atom" /><icon>http://www.theplancollection.com/images/icon_29_29.gif</icon><entry><title>Search Using ASP.Net and Lucene</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/search-using-asp-net-and-Lucene" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/search-using-asp-net-and-Lucene</id><summary
		type="html">Getting Started
Getting Lucene to work on your asp.net website isn't hard but there are a few tricks that help.  We decided to use the Lucene.Net 2.1.0 release because it made updating the Lucene index easier via a new method on the IndexWriter object called UpdateDocument.  This method deletes the specified document and then adds the new copy into the index.  You can't download the Lucene.net 2.1.0 binary.  Instead you will need to download the source via their subversion repository and then compile it.  


Don't worry this is an easy step.  Using your subversion client - I recommend TortiseSvn get the source by doing a checkout from this url:

https://svn.apache.org/repos/asf/incubator/lucene.net/tags/Lucene.Net_2_1_0/



Next go into the directory:</summary><content
		type="html">&lt;h2&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;Getting Lucene to work on your asp.net website isn't hard but there are a few tricks that help.  We decided to use the Lucene.Net 2.1.0 release because it made updating the Lucene index easier via a new method on the IndexWriter object called UpdateDocument.  This method deletes the specified document and then adds the new copy into the index.  You can't download the Lucene.net 2.1.0 binary.  Instead you will need to download the source via their subversion repository and then compile it.  &lt;/p&gt;

&lt;p&gt;
Don't worry this is an easy step.  Using your subversion client - I recommend &lt;a href="http://tortoisesvn.tigris.org/"&gt;TortiseSvn&lt;/a&gt; get the source by doing a checkout from this url:
&lt;code&gt;
&lt;a href="https://svn.apache.org/repos/asf/incubator/lucene.net/tags/Lucene.Net_2_1_0/"&gt;https://svn.apache.org/repos/asf/incubator/lucene.net/tags/Lucene.Net_2_1_0/&lt;/a&gt;
&lt;/code&gt;
&lt;/p&gt;

&lt;p&gt;Next go into the directory: 
&lt;code&gt;
Lucene.Net_2_1_0\src\Lucene.Net
&lt;/code&gt;
You should find a Visual Studio solution file that matches your Visual Studio version.  If you are using Visual Studio 2005 be sure to load &lt;strong&gt;Lucene.Net-2.1.0-VS2005.sln&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;Hit compile.  The resulting Lucene.Net.dll in the bin/release folder is the dll you will need to reference in your Visual Studio project that will contain the Lucene code.&lt;/p&gt;

&lt;h2&gt;Creating the Lucene Index&lt;/h2&gt;
&lt;p&gt;Lucene creates a file based index that it uses to quickly return search results.  We had to find a way to index all the pages in our system so that Lucene would have a way to search all of our content.  In our case this includes all the articles, forum posts and of course house plans on the website.  To make this happen we query our database, get back urls to all of our content and then send a webspider out to pull down the content from our site.  That content is then parsed and fed to Lucene.&lt;/p&gt;

&lt;p&gt;We developed three classes to make this all work.  Most of the code is taken from examples or other kind souls who shared code.  The first class, GeneralSearch.cs creates the index and provides the mechanism for searching it.  The second class, HtmlDocument consists of code taken from &lt;a href="http://www.searcharoo.net/"&gt;Searcharoo&lt;/a&gt; a web spidering project written in C#.  The HtmlDocument class handles parsing the html for us.  Special thanks to Searcharoo for that code.  I didn't want to write it.  The last class is also borrowed from Searcharoo.  It is called HtmlDownloader.cs and its task is to download pages from the site and then create a HtmlDocument from them.&lt;/p&gt;


&lt;h2&gt;GeneralSearch.cs&lt;/h2&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Data;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Core.Utils.Html;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Lucene.Net.Analysis;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Lucene.Net.Analysis.Standard;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Lucene.Net.Documents;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Lucene.Net.Index;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Lucene.Net.QueryParsers;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Lucene.Net.Search;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Core.Search
{
    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Wrapper for Lucene to perform a general search&lt;/span&gt;
    &lt;span class="rem"&gt;/// see:&lt;/span&gt;
    &lt;span class="rem"&gt;/// http://www.codeproject.com/KB/aspnet/DotLuceneSearch.aspx&lt;/span&gt;
    &lt;span class="rem"&gt;/// for more help about the methods used in this class&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; GeneralSearch
    {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; IndexWriter _Writer = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _IndexDirectory;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; _Errors = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;();
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; _TotalResults = 0;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; _Start = 1;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; _End = 10;
        
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// General constructor method.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="indexDirectory"&amp;gt;The directory where the index &lt;/span&gt;
        &lt;span class="rem"&gt;/// is located.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; GeneralSearch(&lt;span class="kwrd"&gt;string&lt;/span&gt; indexDirectory)
        {
            _IndexDirectory = indexDirectory;                                    
        }
                
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// List of errors that occured during indexing&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; Errors
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _Errors; }
            set { _Errors = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Total number of hits return by the search&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; TotalResults
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _TotalResults; }
            set { _TotalResults = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// The number of the record where the results begin.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Start
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _Start; }
            set { _Start = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// The number of the record where the results end.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; End
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _End; }
            set { _End = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Returns a table with matching results or null&lt;/span&gt;
        &lt;span class="rem"&gt;/// if the index does not exist.  This method will page the&lt;/span&gt;
        &lt;span class="rem"&gt;/// results.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="searchText"&amp;gt;terms to search for&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="currentPage"&amp;gt;The current results page&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="hitsPerPage"&amp;gt;The number of hits to return for each results page&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;A datatable containing the number of results specified for the given page.&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; DataTable DoSearch(&lt;span class="kwrd"&gt;string&lt;/span&gt; searchText, &lt;span class="kwrd"&gt;int&lt;/span&gt; hitsPerPage, &lt;span class="kwrd"&gt;int&lt;/span&gt; currentPage)
        {
            &lt;span class="kwrd"&gt;if&lt;/span&gt;(!IndexReader.IndexExists(_IndexDirectory))
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;    
            }

            &lt;span class="kwrd"&gt;string&lt;/span&gt; field = IndexedFields.Contents;

            IndexReader reader = IndexReader.Open(_IndexDirectory);
            IndexSearcher searcher = &lt;span class="kwrd"&gt;new&lt;/span&gt; IndexSearcher(reader); 
            Analyzer analyzer = &lt;span class="kwrd"&gt;new&lt;/span&gt; StandardAnalyzer();
            QueryParser parser = &lt;span class="kwrd"&gt;new&lt;/span&gt; QueryParser(field, analyzer);
            Query query = parser.Parse(searchText);
            
            Hits hits = searcher.Search(query);

            DataTable dt = &lt;span class="kwrd"&gt;new&lt;/span&gt; DataTable();
            dt.Columns.Add(IndexedFields.Url, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt;));
            dt.Columns.Add(IndexedFields.Title, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt;));
            &lt;span class="rem"&gt;//dt.Columns.Add(IndexedFields.Summary, typeof(string));&lt;/span&gt;
            dt.Columns.Add(IndexedFields.Contents, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt;));
            dt.Columns.Add(IndexedFields.Image, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(&lt;span class="kwrd"&gt;string&lt;/span&gt;));

            &lt;span class="kwrd"&gt;if&lt;/span&gt;(currentPage &amp;lt;= 0)
            {
                currentPage = 1;
            }
            Start = (currentPage-1) * hitsPerPage;
            End = System.Math.Min(hits.Length(), Start + hitsPerPage);
            TotalResults = hits.Length();
            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = Start; i &amp;lt; End; i++)
            {
                &lt;span class="rem"&gt;// get the document from index&lt;/span&gt;
                Document doc = hits.Doc(i);
                
                DataRow row = dt.NewRow();
                row[IndexedFields.Url] = doc.Get(IndexedFields.Url);
                &lt;span class="rem"&gt;//row[IndexedFields.Summary] = doc.Get(IndexedFields.Summary);&lt;/span&gt;
                row[IndexedFields.Contents] = doc.Get(IndexedFields.Contents);
                row[IndexedFields.Title] = doc.Get(IndexedFields.Title);
                row[IndexedFields.Image] = doc.Get(IndexedFields.Image);

                dt.Rows.Add(row);
            }

            reader.Close();

            &lt;span class="kwrd"&gt;return&lt;/span&gt; dt;
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Opens the index for writing&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; OpenWriter()
        {
            &lt;span class="kwrd"&gt;bool&lt;/span&gt; create = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (!IndexReader.IndexExists(_IndexDirectory))
            {
                create = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
            }

            _Writer = &lt;span class="kwrd"&gt;new&lt;/span&gt; IndexWriter(_IndexDirectory, &lt;span class="kwrd"&gt;new&lt;/span&gt; StandardAnalyzer(), create);
            _Writer.SetUseCompoundFile(&lt;span class="kwrd"&gt;true&lt;/span&gt;);
            _Writer.SetMaxFieldLength(1000000);
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Closes and optimizes the index&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CloseWriter()
        {
            _Writer.Optimize();
            _Writer.Close();
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Loads, parses and indexes an HTML file at a given url.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="url"&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddWebPage(&lt;span class="kwrd"&gt;string&lt;/span&gt; url)
        {
            HtmlDocument html = HtmlDownloader.Download(url);

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;null&lt;/span&gt; != html)
            {
                &lt;span class="rem"&gt;// make a new, empty document&lt;/span&gt;
                Document doc = &lt;span class="kwrd"&gt;new&lt;/span&gt; Document();

                &lt;span class="rem"&gt;// Store the url&lt;/span&gt;
                doc.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Field(IndexedFields.Url, url, Field.Store.YES, Field.Index.UN_TOKENIZED));

                &lt;span class="rem"&gt;// create a uid that will let us maintain the index incrementally&lt;/span&gt;
                doc.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Field(IndexedFields.Uid, url, Field.Store.NO, Field.Index.UN_TOKENIZED));

                &lt;span class="rem"&gt;// Add the tag-stripped contents as a Reader-valued Text field so it will&lt;/span&gt;
                &lt;span class="rem"&gt;// get tokenized and indexed.&lt;/span&gt;
                doc.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Field(IndexedFields.Contents, html.WordsOnly, Field.Store.YES, Field.Index.TOKENIZED));

                &lt;span class="rem"&gt;// Add the summary as a field that is stored and returned with&lt;/span&gt;
                &lt;span class="rem"&gt;// hit documents for display.&lt;/span&gt;
                &lt;span class="rem"&gt;//doc.Add(new Field(IndexedFields.Summary, html.Description, Field.Store.YES, Field.Index.NO));&lt;/span&gt;
                
                &lt;span class="rem"&gt;// Add the title as a field that it can be searched and that is stored.&lt;/span&gt;
                doc.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Field(IndexedFields.Title, html.Title, Field.Store.YES, Field.Index.TOKENIZED));

                Term t = &lt;span class="kwrd"&gt;new&lt;/span&gt; Term(IndexedFields.Uid, url);
                _Writer.UpdateDocument(t, doc);
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
            {
                Errors.Add(&lt;span class="str"&gt;"Could not index "&lt;/span&gt; + url);
            }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Use this method to add a single page to the index.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// If you are adding multiple pages use the AddPage method instead as it only opens and closes the index once.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="url"&amp;gt;The url for the given document.  The document will not be requested from&lt;/span&gt;
        &lt;span class="rem"&gt;/// this url.  Instead it will be used as a key to access the document within the index and &lt;/span&gt;
        &lt;span class="rem"&gt;/// will be returned when the index is searched so that the document can be referenced by the&lt;/span&gt;
        &lt;span class="rem"&gt;/// client.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="documentText"&amp;gt;The contents of the document that is to be added to the index.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="title"&amp;gt;The title of the document to add to the index.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddSinglePage(&lt;span class="kwrd"&gt;string&lt;/span&gt; url, &lt;span class="kwrd"&gt;string&lt;/span&gt; documentText, &lt;span class="kwrd"&gt;string&lt;/span&gt; title, &lt;span class="kwrd"&gt;string&lt;/span&gt; image)
        {
            OpenWriter();
            AddPage(url, documentText, title, image);
            CloseWriter();
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Indexes the text of the given document, but does not request the document from the specified url.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Use this method to add a document to the index when you know it's contents and url.  This prevents&lt;/span&gt;
        &lt;span class="rem"&gt;/// a http download which can take longer.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="url"&amp;gt;The url for the given document.  The document will not be requested from&lt;/span&gt;
        &lt;span class="rem"&gt;/// this url.  Instead it will be used as a key to access the document within the index and &lt;/span&gt;
        &lt;span class="rem"&gt;/// will be returned when the index is searched so that the document can be referenced by the&lt;/span&gt;
        &lt;span class="rem"&gt;/// client.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="documentText"&amp;gt;The contents of the document that is to be added to the index.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="title"&amp;gt;The title of the document to add to the index.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="image"&amp;gt;Image to include with search results&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddPage(&lt;span class="kwrd"&gt;string&lt;/span&gt; url, &lt;span class="kwrd"&gt;string&lt;/span&gt; documentText, &lt;span class="kwrd"&gt;string&lt;/span&gt; title, &lt;span class="kwrd"&gt;string&lt;/span&gt; image)
        {
            &lt;span class="rem"&gt;// make a new, empty document&lt;/span&gt;
            Document doc = &lt;span class="kwrd"&gt;new&lt;/span&gt; Document();

            &lt;span class="rem"&gt;// Store the url&lt;/span&gt;
            doc.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Field(IndexedFields.Url, url, Field.Store.YES, Field.Index.UN_TOKENIZED));

            &lt;span class="rem"&gt;// create a uid that will let us maintain the index incrementally&lt;/span&gt;
            doc.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Field(IndexedFields.Uid, url, Field.Store.NO, Field.Index.UN_TOKENIZED));

            &lt;span class="rem"&gt;// Add the tag-stripped contents as a Reader-valued Text field so it will&lt;/span&gt;
            &lt;span class="rem"&gt;// get tokenized and indexed.&lt;/span&gt;
            doc.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Field(IndexedFields.Contents, documentText, Field.Store.YES, Field.Index.TOKENIZED));

            &lt;span class="rem"&gt;// Add the summary as a field that is stored and returned with&lt;/span&gt;
            &lt;span class="rem"&gt;// hit documents for display.&lt;/span&gt;
            &lt;span class="rem"&gt;//doc.Add(new Field(IndexedFields.Summary, documentDescription, Field.Store.YES, Field.Index.NO));&lt;/span&gt;

            &lt;span class="rem"&gt;// Add the title as a field that it can be searched and that is stored.&lt;/span&gt;
            doc.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Field(IndexedFields.Title, title, Field.Store.YES, Field.Index.TOKENIZED));

            &lt;span class="rem"&gt;// Add the title as a field that it can be searched and that is stored.&lt;/span&gt;
            doc.Add(&lt;span class="kwrd"&gt;new&lt;/span&gt; Field(IndexedFields.Image, image, Field.Store.YES, Field.Index.TOKENIZED));

            
            Term t = &lt;span class="kwrd"&gt;new&lt;/span&gt; Term(IndexedFields.Uid, url);
            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                _Writer.UpdateDocument(t, doc);
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt;(Exception ex)
            {
                Errors.Add(ex.Message);
            }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// A list of fields available in the index&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; IndexedFields
        {
            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Url = &lt;span class="str"&gt;"url"&lt;/span&gt;;
            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Uid = &lt;span class="str"&gt;"uid"&lt;/span&gt;;
            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Contents = &lt;span class="str"&gt;"contents"&lt;/span&gt;;
            &lt;span class="rem"&gt;//public const string Summary = "summary";&lt;/span&gt;
            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Title = &lt;span class="str"&gt;"title"&lt;/span&gt;;
            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Image = &lt;span class="str"&gt;"image"&lt;/span&gt;;

        }
    }
}
&lt;/pre&gt;




&lt;h2&gt;HtmlDocument.cs&lt;/h2&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text.RegularExpressions;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Core.Utils.Html
{
    
    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// This code was taken from:&lt;/span&gt;
    &lt;span class="rem"&gt;/// http://www.searcharoo.net/SearcharooV5/&lt;/span&gt;
    &lt;span class="rem"&gt;/// &lt;/span&gt;
    &lt;span class="rem"&gt;/// Storage for parsed HTML data returned by ParsedHtmlData();&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Arbitrary class to encapsulate just the properties we need &lt;/span&gt;
    &lt;span class="rem"&gt;/// to index Html pages (Title, Meta tags, Keywords, etc).&lt;/span&gt;
    &lt;span class="rem"&gt;/// A 'generic' search engine would probably have a 'generic'&lt;/span&gt;
    &lt;span class="rem"&gt;/// document class, so maybe a future version of Searcharoo &lt;/span&gt;
    &lt;span class="rem"&gt;/// will too...&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; HtmlDocument
    {
        &lt;span class="preproc"&gt;#region&lt;/span&gt; Private fields: _Uri, _ContentType, _RobotIndexOK, _RobotFollowOK

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; _SummaryCharacters = 350;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _IgnoreRegionTagNoIndex = &lt;span class="str"&gt;""&lt;/span&gt;;

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _All = String.Empty;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; Uri _Uri;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; String _ContentType;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _Extension;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; _RobotIndexOK = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; _RobotFollowOK = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _WordsOnly = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;MimeType so we know whether to try and parse the contents, eg. "text/html", "text/plain", etc&amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _MimeType = String.Empty;
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;Html &amp;amp;lt;title&amp;amp;gt; tag&amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; String _Title = String.Empty;
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;Html &amp;amp;lt;meta http-equiv='description'&amp;amp;gt; tag&amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _Description = String.Empty;
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;Length as reported by the server in the Http headers&amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;long&lt;/span&gt; _Length;        
        
        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="kwrd"&gt;public&lt;/span&gt; ArrayList LocalLinks;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; ArrayList ExternalLinks;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; Public Properties: Uri, RobotIndexOK
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// http://www.ietf.org/rfc/rfc2396.txt&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Uri Uri
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _Uri; }
            set
            {
                _Uri = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
            }
        }
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Whether a robot should index the text &lt;/span&gt;
        &lt;span class="rem"&gt;/// found on this page, or just ignore it&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Set when page META tags are parsed - no 'set' property&lt;/span&gt;
        &lt;span class="rem"&gt;/// More info:&lt;/span&gt;
        &lt;span class="rem"&gt;/// http://www.robotstxt.org/&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; RobotIndexOK
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _RobotIndexOK; }
        }
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Whether a robot should follow any links &lt;/span&gt;
        &lt;span class="rem"&gt;/// found on this page, or just ignore them&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Set when page META tags are parsed - no 'set' property&lt;/span&gt;
        &lt;span class="rem"&gt;/// More info:&lt;/span&gt;
        &lt;span class="rem"&gt;/// http://www.robotstxt.org/&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; RobotFollowOK
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _RobotFollowOK; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Title
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _Title; }
            set { _Title = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Whether to ignore sections of HTML wrapped in a special comment tag&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IgnoreRegions
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _IgnoreRegionTagNoIndex.Length &amp;gt; 0; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ContentType
        {
            get
            {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; _ContentType;
            }
            set
            {
                _ContentType = &lt;span class="kwrd"&gt;value&lt;/span&gt;.ToString();
                &lt;span class="kwrd"&gt;string&lt;/span&gt;[] contentTypeArray = _ContentType.Split(&lt;span class="str"&gt;';'&lt;/span&gt;);
                &lt;span class="rem"&gt;// Set MimeType if it's blank&lt;/span&gt;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (_MimeType == String.Empty &amp;amp;&amp;amp; contentTypeArray.Length &amp;gt;= 1)
                {
                    _MimeType = contentTypeArray[0];
                }
                &lt;span class="rem"&gt;// Set Encoding if it's blank&lt;/span&gt;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (Encoding == String.Empty &amp;amp;&amp;amp; contentTypeArray.Length &amp;gt;= 2)
                {
                    &lt;span class="kwrd"&gt;int&lt;/span&gt; charsetpos = contentTypeArray[1].IndexOf(&lt;span class="str"&gt;"charset"&lt;/span&gt;);
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (charsetpos &amp;gt; 0)
                    {
                        Encoding = contentTypeArray[1].Substring(charsetpos + 8, contentTypeArray[1].Length - charsetpos - 8);
                    }
                }
            }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; MimeType
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _MimeType; }
            set { _MimeType = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Extension
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _Extension; }
            set { _Extension = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
        }
        
        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; Public fields: Encoding, Keywords, All
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;Encoding eg. "utf-8", "Shift_JIS", "iso-8859-1", "gb2312", etc&amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Encoding = String.Empty;
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;Html &amp;amp;lt;meta http-equiv='keywords'&amp;amp;gt; tag&amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Keywords = String.Empty;

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Raw content of page, as downloaded from the server&lt;/span&gt;
        &lt;span class="rem"&gt;/// Html stripped to make up the 'wordsonly'&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Html
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _All; }
            set
            {
                _All = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
                _WordsOnly = StripHtml(_All);
            }
        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; WordsOnly
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.Keywords + &lt;span class="kwrd"&gt;this&lt;/span&gt;._Description + &lt;span class="kwrd"&gt;this&lt;/span&gt;._WordsOnly; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;long&lt;/span&gt; Length
        {
            get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _Length; }
            set { _Length = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }
        }

        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Description
        {
            get
            {
                &lt;span class="rem"&gt;// ### If no META DESC, grab start of file text ###&lt;/span&gt;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (String.Empty == &lt;span class="kwrd"&gt;this&lt;/span&gt;._Description)
                {
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (_WordsOnly.Length &amp;gt; _SummaryCharacters)
                    {
                        _Description = _WordsOnly.Substring(0, _SummaryCharacters);
                    }
                    &lt;span class="kwrd"&gt;else&lt;/span&gt;
                    {
                        _Description = WordsOnly;
                    }
                    _Description = Regex.Replace(_Description, &lt;span class="str"&gt;@"\s+"&lt;/span&gt;, &lt;span class="str"&gt;" "&lt;/span&gt;).Trim();
                }
                &lt;span class="rem"&gt;// http://authors.aspalliance.com/stevesmith/articles/removewhitespace.asp&lt;/span&gt;
                &lt;span class="kwrd"&gt;return&lt;/span&gt; _Description;
            }
            set
            {
                _Description = Regex.Replace(&lt;span class="kwrd"&gt;value&lt;/span&gt;, &lt;span class="str"&gt;@"\s+"&lt;/span&gt;, &lt;span class="str"&gt;" "&lt;/span&gt;).Trim();
            }
        }
        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;

        &lt;span class="preproc"&gt;#region&lt;/span&gt; Public Methods: SetRobotDirective, ToString()
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Pass in a ROBOTS meta tag found while parsing, &lt;/span&gt;
        &lt;span class="rem"&gt;/// and set HtmlDocument property/ies appropriately&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// More info:&lt;/span&gt;
        &lt;span class="rem"&gt;/// * Robots Exclusion Protocol *&lt;/span&gt;
        &lt;span class="rem"&gt;/// - for META tags&lt;/span&gt;
        &lt;span class="rem"&gt;/// http://www.robotstxt.org/wc/meta-user.html&lt;/span&gt;
        &lt;span class="rem"&gt;/// - for ROBOTS.TXT in the siteroot&lt;/span&gt;
        &lt;span class="rem"&gt;/// http://www.robotstxt.org/wc/norobots.html&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetRobotDirective(&lt;span class="kwrd"&gt;string&lt;/span&gt; robotMetaContent)
        {
            robotMetaContent = robotMetaContent.ToLower();
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (robotMetaContent.IndexOf(&lt;span class="str"&gt;"none"&lt;/span&gt;) &amp;gt;= 0)
            {
                &lt;span class="rem"&gt;// 'none' means you can't Index or Follow!&lt;/span&gt;
                _RobotIndexOK = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
                _RobotFollowOK = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (robotMetaContent.IndexOf(&lt;span class="str"&gt;"noindex"&lt;/span&gt;) &amp;gt;= 0) { _RobotIndexOK = &lt;span class="kwrd"&gt;false&lt;/span&gt;; }
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (robotMetaContent.IndexOf(&lt;span class="str"&gt;"nofollow"&lt;/span&gt;) &amp;gt;= 0) { _RobotFollowOK = &lt;span class="kwrd"&gt;false&lt;/span&gt;; }
            }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// For debugging - output all links found in the page&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ToString()
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; linkstring = &lt;span class="str"&gt;""&lt;/span&gt;;
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;object&lt;/span&gt; link &lt;span class="kwrd"&gt;in&lt;/span&gt; LocalLinks)
            {
                linkstring += Convert.ToString(link) + &lt;span class="str"&gt;"\r\n"&lt;/span&gt;;
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; Title + &lt;span class="str"&gt;"\r\n"&lt;/span&gt; + Description + &lt;span class="str"&gt;"\r\n----------------\r\n"&lt;/span&gt; + linkstring + &lt;span class="str"&gt;"\r\n----------------\r\n"&lt;/span&gt; + Html + &lt;span class="str"&gt;"\r\n======================\r\n"&lt;/span&gt;;
        }
        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;


        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// "Original" link search Regex used by the code was from here&lt;/span&gt;
        &lt;span class="rem"&gt;/// http://www.dotnetjunkies.com/Tutorial/1B219C93-7702-4ADF-9106-DFFDF90914CF.dcik&lt;/span&gt;
        &lt;span class="rem"&gt;/// but it was not sophisticated enough to match all tag permutations&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// whereas the Regex on this blog will parse ALL attributes from within tags...&lt;/span&gt;
        &lt;span class="rem"&gt;/// IMPORTANT when they're out of order, spaced out or over multiple lines&lt;/span&gt;
        &lt;span class="rem"&gt;/// http://blogs.worldnomads.com.au/matthewb/archive/2003/10/24/158.aspx&lt;/span&gt;
        &lt;span class="rem"&gt;/// http://blogs.worldnomads.com.au/matthewb/archive/2004/04/06/215.aspx&lt;/span&gt;
        &lt;span class="rem"&gt;///&lt;/span&gt;
        &lt;span class="rem"&gt;/// http://www.experts-exchange.com/Programming/Programming_Languages/C_Sharp/Q_20848043.html&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Parse()
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; htmlData = &lt;span class="kwrd"&gt;this&lt;/span&gt;.Html;    &lt;span class="rem"&gt;// htmlData will be munged&lt;/span&gt;

            &lt;span class="rem"&gt;//xenomouse http://www.codeproject.com/aspnet/Spideroo.asp?msg=1271902#xx1271902xx&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.IsNullOrEmpty(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Title))
            {   &lt;span class="rem"&gt;// title may have been set previously... non-HTML file type (this will be refactored out, later)&lt;/span&gt;
                &lt;span class="kwrd"&gt;this&lt;/span&gt;.Title = Regex.Match(htmlData, &lt;span class="str"&gt;@"(?&amp;lt;=&amp;lt;title[^\&amp;gt;]*&amp;gt;).*?(?=&amp;lt;/title&amp;gt;)"&lt;/span&gt;,
                    RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture).Value;
            }

            &lt;span class="kwrd"&gt;string&lt;/span&gt; metaKey = String.Empty, metaValue = String.Empty;
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (Match metamatch &lt;span class="kwrd"&gt;in&lt;/span&gt; Regex.Matches(htmlData
                , &lt;span class="str"&gt;@"&amp;lt;meta\s*(?:(?:\b(\w|-)+\b\s*(?:=\s*(?:"&lt;/span&gt;&lt;span class="str"&gt;"[^"&lt;/span&gt;&lt;span class="str"&gt;"]*"&lt;/span&gt;&lt;span class="str"&gt;"|'[^']*'|[^"&lt;/span&gt;&lt;span class="str"&gt;"'&amp;lt;&amp;gt; ]+)\s*)?)*)/?\s*&amp;gt;"&lt;/span&gt;
                , RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture))
            {
                metaKey = String.Empty;
                metaValue = String.Empty;
                &lt;span class="rem"&gt;// Loop through the attribute/value pairs inside the tag&lt;/span&gt;
                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (Match submetamatch &lt;span class="kwrd"&gt;in&lt;/span&gt; Regex.Matches(metamatch.Value.ToString()
                    , &lt;span class="str"&gt;@"(?&amp;lt;name&amp;gt;\b(\w|-)+\b)\s*=\s*("&lt;/span&gt;&lt;span class="str"&gt;"(?&amp;lt;value&amp;gt;[^"&lt;/span&gt;&lt;span class="str"&gt;"]*)"&lt;/span&gt;&lt;span class="str"&gt;"|'(?&amp;lt;value&amp;gt;[^']*)'|(?&amp;lt;value&amp;gt;[^"&lt;/span&gt;&lt;span class="str"&gt;"'&amp;lt;&amp;gt; ]+)\s*)+"&lt;/span&gt;
                    , RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture))
                {

                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="str"&gt;"http-equiv"&lt;/span&gt; == submetamatch.Groups[1].ToString().ToLower())
                    {
                        metaKey = submetamatch.Groups[2].ToString();
                    }
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; ((&lt;span class="str"&gt;"name"&lt;/span&gt; == submetamatch.Groups[1].ToString().ToLower())
                        &amp;amp;&amp;amp; (metaKey == String.Empty))
                    { &lt;span class="rem"&gt;// if it's already set, HTTP-EQUIV takes precedence&lt;/span&gt;
                        metaKey = submetamatch.Groups[2].ToString();
                    }
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="str"&gt;"content"&lt;/span&gt; == submetamatch.Groups[1].ToString().ToLower())
                    {
                        metaValue = submetamatch.Groups[2].ToString();
                    }
                }
                &lt;span class="kwrd"&gt;switch&lt;/span&gt; (metaKey.ToLower())
                {
                    &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;"description"&lt;/span&gt;:
                        &lt;span class="kwrd"&gt;this&lt;/span&gt;.Description = metaValue;
                        &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                    &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;"keywords"&lt;/span&gt;:
                    &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;"keyword"&lt;/span&gt;:
                        &lt;span class="kwrd"&gt;this&lt;/span&gt;.Keywords = metaValue;
                        &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                    &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;"robots"&lt;/span&gt;:
                    &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;"robot"&lt;/span&gt;:
                        &lt;span class="kwrd"&gt;this&lt;/span&gt;.SetRobotDirective(metaValue);
                        &lt;span class="kwrd"&gt;break&lt;/span&gt;;
                }
                &lt;span class="rem"&gt;//                ProgressEvent(this, new ProgressEventArgs(4, metaKey + " = " + metaValue));&lt;/span&gt;
            }

            &lt;span class="kwrd"&gt;string&lt;/span&gt; link = String.Empty;

            ArrayList linkLocal = &lt;span class="kwrd"&gt;new&lt;/span&gt; ArrayList();
            ArrayList linkExternal = &lt;span class="kwrd"&gt;new&lt;/span&gt; ArrayList();

            &lt;span class="rem"&gt;// http://msdn.microsoft.com/library/en-us/script56/html/js56jsgrpregexpsyntax.asp&lt;/span&gt;
            &lt;span class="rem"&gt;// Original Regex, just found &amp;lt;a href=""&amp;gt; links; and was "broken" by spaces, out-of-order, etc&lt;/span&gt;
            &lt;span class="rem"&gt;// @"(?&amp;lt;=&amp;lt;a\s+href="").*?(?=""\s*/?&amp;gt;)"&lt;/span&gt;
            &lt;span class="rem"&gt;// Looks for the src attribute of:&lt;/span&gt;
            &lt;span class="rem"&gt;// &amp;lt;A&amp;gt; anchor tags&lt;/span&gt;
            &lt;span class="rem"&gt;// &amp;lt;AREA&amp;gt; imagemap links&lt;/span&gt;
            &lt;span class="rem"&gt;// &amp;lt;FRAME&amp;gt; frameset links&lt;/span&gt;
            &lt;span class="rem"&gt;// &amp;lt;IFRAME&amp;gt; floating frames&lt;/span&gt;
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (Match match &lt;span class="kwrd"&gt;in&lt;/span&gt; Regex.Matches(htmlData
                , &lt;span class="str"&gt;@"(?&amp;lt;anchor&amp;gt;&amp;lt;\s*(a|area|frame|iframe)\s*(?:(?:\b\w+\b\s*(?:=\s*(?:"&lt;/span&gt;&lt;span class="str"&gt;"[^"&lt;/span&gt;&lt;span class="str"&gt;"]*"&lt;/span&gt;&lt;span class="str"&gt;"|'[^']*'|[^"&lt;/span&gt;&lt;span class="str"&gt;"'&amp;lt;&amp;gt; ]+)\s*)?)*)?\s*&amp;gt;)"&lt;/span&gt;
                , RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture))
            {
                &lt;span class="rem"&gt;// Parse ALL attributes from within tags... IMPORTANT when they're out of order!!&lt;/span&gt;
                &lt;span class="rem"&gt;// in addition to the 'href' attribute, there might also be 'alt', 'class', 'style', 'area', etc...&lt;/span&gt;
                &lt;span class="rem"&gt;// there might also be 'spaces' between the attributes and they may be ", ', or unquoted&lt;/span&gt;
                link = String.Empty;
                &lt;span class="rem"&gt;//                ProgressEvent(this, new ProgressEventArgs(4, "Match:" + System.Web.HttpUtility.HtmlEncode(match.Value) + ""));&lt;/span&gt;
                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (Match submatch &lt;span class="kwrd"&gt;in&lt;/span&gt; Regex.Matches(match.Value.ToString()
                    , &lt;span class="str"&gt;@"(?&amp;lt;name&amp;gt;\b\w+\b)\s*=\s*("&lt;/span&gt;&lt;span class="str"&gt;"(?&amp;lt;value&amp;gt;[^"&lt;/span&gt;&lt;span class="str"&gt;"]*)"&lt;/span&gt;&lt;span class="str"&gt;"|'(?&amp;lt;value&amp;gt;[^']*)'|(?&amp;lt;value&amp;gt;[^"&lt;/span&gt;&lt;span class="str"&gt;"'&amp;lt;&amp;gt; \s]+)\s*)+"&lt;/span&gt;
                    , RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture))
                {
                    &lt;span class="rem"&gt;// we're only interested in the href attribute (although in future maybe index the 'alt'/'title'?)&lt;/span&gt;
                    &lt;span class="rem"&gt;//                    ProgressEvent(this, new ProgressEventArgs(4, "Submatch: " + submatch.Groups[1].ToString() + "=" + submatch.Groups[2].ToString() + ""));&lt;/span&gt;
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="str"&gt;"href"&lt;/span&gt; == submatch.Groups[1].ToString().ToLower())
                    {
                        link = submatch.Groups[2].ToString();
                        &lt;span class="kwrd"&gt;if&lt;/span&gt; (link != &lt;span class="str"&gt;"#"&lt;/span&gt;) &lt;span class="kwrd"&gt;break&lt;/span&gt;; &lt;span class="rem"&gt;// break if this isn't just a placeholder href="#", which implies maybe an onclick attribute exists&lt;/span&gt;
                    }
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="str"&gt;"onclick"&lt;/span&gt; == submatch.Groups[1].ToString().ToLower())
                    {   &lt;span class="rem"&gt;// maybe try to parse some javascript in here&lt;/span&gt;

                        &lt;span class="kwrd"&gt;string&lt;/span&gt; jscript = submatch.Groups[2].ToString();
                        &lt;span class="rem"&gt;// some code here to extract a filename/link to follow from the onclick="_____"&lt;/span&gt;
                        &lt;span class="rem"&gt;// say it was onclick="window.location='top.htm'"&lt;/span&gt;
                        &lt;span class="kwrd"&gt;int&lt;/span&gt; firstApos = jscript.IndexOf(&lt;span class="str"&gt;"'"&lt;/span&gt;);
                        &lt;span class="kwrd"&gt;int&lt;/span&gt; secondApos = jscript.IndexOf(&lt;span class="str"&gt;"'"&lt;/span&gt;, firstApos + 1);
                        &lt;span class="kwrd"&gt;if&lt;/span&gt; (secondApos &amp;gt; firstApos)
                        {
                            link = jscript.Substring(firstApos + 1, secondApos - firstApos - 1);
                            &lt;span class="kwrd"&gt;break&lt;/span&gt;;  &lt;span class="rem"&gt;// break if we found something, ignoring any later href="" which may exist _after_ the onclick in the &amp;lt;a&amp;gt; element&lt;/span&gt;
                        }
                    }
                }
                &lt;span class="rem"&gt;// strip off internal links, so we don't index same page over again&lt;/span&gt;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (link.IndexOf(&lt;span class="str"&gt;"#"&lt;/span&gt;) &amp;gt; -1)
                {
                    link = link.Substring(0, link.IndexOf(&lt;span class="str"&gt;"#"&lt;/span&gt;));
                }
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (link.IndexOf(&lt;span class="str"&gt;"javascript:"&lt;/span&gt;) == -1
                    &amp;amp;&amp;amp; link.IndexOf(&lt;span class="str"&gt;"mailto:"&lt;/span&gt;) == -1
                    &amp;amp;&amp;amp; !link.StartsWith(&lt;span class="str"&gt;"#"&lt;/span&gt;)
                    &amp;amp;&amp;amp; link != String.Empty)
                {
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; ((link.Length &amp;gt; 8) &amp;amp;&amp;amp; (link.StartsWith(&lt;span class="str"&gt;"http://"&lt;/span&gt;)
                        || link.StartsWith(&lt;span class="str"&gt;"https://"&lt;/span&gt;)
                        || link.StartsWith(&lt;span class="str"&gt;"file://"&lt;/span&gt;)
                        || link.StartsWith(&lt;span class="str"&gt;"//"&lt;/span&gt;)
                        || link.StartsWith(&lt;span class="str"&gt;@"\\")))
                    {
                        linkExternal.Add(link);
                        //                        ProgressEvent(this, new ProgressEventArgs(4, "&lt;/span&gt;External link: &lt;span class="str"&gt;" + link));
                    }
                    else if (link.StartsWith("&lt;/span&gt;?&lt;span class="str"&gt;"))
                    {
                        // it's possible to have /?query which sends the querystring to the
                        // 'default' page in a directory
                        linkLocal.Add(this.Uri.AbsolutePath + link);
                        //                        ProgressEvent(this, new ProgressEventArgs(4, "&lt;/span&gt;? Internal &lt;span class="kwrd"&gt;default&lt;/span&gt; page link: &lt;span class="str"&gt;" + link));
                    }
                    else
                    {
                        linkLocal.Add(link);
                        //                        ProgressEvent(this, new ProgressEventArgs(4, "&lt;/span&gt;I Internal link: &lt;span class="str"&gt;" + link));
                    }
                } // add each link to a collection
            } // foreach
            this.LocalLinks = linkLocal;
            this.ExternalLinks = linkExternal;
        } // Parse
        
        /// &amp;lt;summary&amp;gt;
        /// Stripping HTML
        /// http://www.4guysfromrolla.com/webtech/042501-1.shtml
        /// &amp;lt;/summary&amp;gt;
        /// &amp;lt;remarks&amp;gt;
        /// Using regex to find tags without a trailing slash
        /// http://concepts.waetech.com/unclosed_tags/index.cfm
        ///
        /// http://msdn.microsoft.com/library/en-us/script56/html/js56jsgrpregexpsyntax.asp
        ///
        /// Replace html comment tags
        /// http://www.faqts.com/knowledge_base/view.phtml/aid/21761/fid/53
        /// &amp;lt;/remarks&amp;gt;
        protected string StripHtml(string Html)
        {
            //Strips the &amp;lt;script&amp;gt; tags from the Html
            string scriptregex = @"&lt;/span&gt;&amp;lt;scr&lt;span class="str"&gt;" + @"&lt;/span&gt;ipt[^&amp;gt;.]*&amp;gt;[\s\S]*?&amp;lt;/sc&lt;span class="str"&gt;" + @"&lt;/span&gt;ript&amp;gt;&lt;span class="str"&gt;";
            System.Text.RegularExpressions.Regex scripts = new System.Text.RegularExpressions.Regex(scriptregex, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.ExplicitCapture);
            string scriptless = scripts.Replace(Html, "&lt;/span&gt; &lt;span class="str"&gt;");

            //Strips the &amp;lt;style&amp;gt; tags from the Html
            string styleregex = @"&lt;/span&gt;&amp;lt;style[^&amp;gt;.]*&amp;gt;[\s\S]*?&amp;lt;/style&amp;gt;&lt;span class="str"&gt;";
            System.Text.RegularExpressions.Regex styles = new System.Text.RegularExpressions.Regex(styleregex, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.ExplicitCapture);
            string styleless = styles.Replace(scriptless, "&lt;/span&gt; &lt;span class="str"&gt;");

            //Strips the &amp;lt;NOSEARCH&amp;gt; tags from the Html (where NOSEARCH is set in the web.config/Preferences class)
            //TODO: NOTE: this only applies to INDEXING the text - links are parsed before now, so they aren't "&lt;/span&gt;excluded&lt;span class="str"&gt;" by the region!! (yet)
            string ignoreless = string.Empty;
            if (IgnoreRegions)
            {
                string noSearchStartTag = "&lt;/span&gt;&amp;lt;!--&lt;span class="str"&gt;" + _IgnoreRegionTagNoIndex + "&lt;/span&gt;--&amp;gt;&lt;span class="str"&gt;";
                string noSearchEndTag = "&lt;/span&gt;&amp;lt;!--/&lt;span class="str"&gt;" + _IgnoreRegionTagNoIndex + "&lt;/span&gt;--&amp;gt;&lt;span class="str"&gt;";
                string ignoreregex = noSearchStartTag + @"&lt;/span&gt;[\s\S]*?&lt;span class="str"&gt;" + noSearchEndTag;
                System.Text.RegularExpressions.Regex ignores = new System.Text.RegularExpressions.Regex(ignoreregex, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.ExplicitCapture);
                ignoreless = ignores.Replace(styleless, "&lt;/span&gt; &lt;span class="str"&gt;");
            }
            else
            {
                ignoreless = styleless;
            }

            //Strips the &amp;lt;!--comment--&amp;gt; tags from the Html    
            //string commentregex = @"&lt;/span&gt;&amp;lt;!\-\-.*?\-\-&amp;gt;&lt;span class="str"&gt;";        // alternate suggestion from antonello franzil 
            string commentregex = @"&lt;/span&gt;&amp;lt;!(?:--[\s\S]*?--\s*)?&amp;gt;&lt;span class="str"&gt;";
            System.Text.RegularExpressions.Regex comments = new System.Text.RegularExpressions.Regex(commentregex, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.ExplicitCapture);
            string commentless = comments.Replace(ignoreless, "&lt;/span&gt; &lt;span class="str"&gt;");

            //Strips the HTML tags from the Html
            System.Text.RegularExpressions.Regex objRegExp = new System.Text.RegularExpressions.Regex("&lt;/span&gt;&amp;lt;(.|\n)+?&amp;gt;&lt;span class="str"&gt;", RegexOptions.IgnoreCase);

            //Replace all HTML tag matches with the empty string
            string output = objRegExp.Replace(commentless, "&lt;/span&gt; &lt;span class="str"&gt;");

            //Replace all _remaining_ &amp;lt; and &amp;gt; with &amp;amp;lt; and &amp;amp;gt;
            output = output.Replace("&lt;/span&gt;&amp;lt;&lt;span class="str"&gt;", "&lt;/span&gt;&amp;amp;lt;&lt;span class="str"&gt;");
            output = output.Replace("&lt;/span&gt;&amp;gt;&lt;span class="str"&gt;", "&lt;/span&gt;&amp;amp;gt;");

            objRegExp = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; output;
        }

    }
}
&lt;/pre&gt;




&lt;h2&gt;HtmlDownloader.cs&lt;/h2&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Core.Utils.Html
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; HtmlDownloader
    {
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _UserAgent = &lt;span class="str"&gt;"Mozilla/6.0 (MSIE 6.0; Windows NT 5.1; ThePlanCollection.com; robot)"&lt;/span&gt;;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; _RequestTimeout = 5;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; System.Net.CookieContainer _CookieContainer = &lt;span class="kwrd"&gt;new&lt;/span&gt; System.Net.CookieContainer();

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Attempts to download the Uri into the current document.&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// http://www.123aspx.com/redir.aspx?res=28320&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; HtmlDocument Download(&lt;span class="kwrd"&gt;string&lt;/span&gt; url)
        {
            Uri uri = &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(url);
            HtmlDocument doc = &lt;span class="kwrd"&gt;null&lt;/span&gt;;

            &lt;span class="rem"&gt;// Open the requested URL&lt;/span&gt;
            System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(uri.AbsoluteUri);
            req.AllowAutoRedirect = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
            req.MaximumAutomaticRedirections = 3;
            req.UserAgent = _UserAgent; &lt;span class="rem"&gt;//"Mozilla/6.0 (MSIE 6.0; Windows NT 5.1; Searcharoo.NET)";&lt;/span&gt;
            req.KeepAlive = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
            req.Timeout = _RequestTimeout * 1000; &lt;span class="rem"&gt;//prefRequestTimeout &lt;/span&gt;

            &lt;span class="rem"&gt;// SIMONJONES http://codeproject.com/aspnet/spideroo.asp?msg=1421158#xx1421158xx&lt;/span&gt;
            req.CookieContainer = &lt;span class="kwrd"&gt;new&lt;/span&gt; System.Net.CookieContainer();
            req.CookieContainer.Add(_CookieContainer.GetCookies(uri));

            &lt;span class="rem"&gt;// Get the stream from the returned web response&lt;/span&gt;
            System.Net.HttpWebResponse webresponse = &lt;span class="kwrd"&gt;null&lt;/span&gt;;

            &lt;span class="kwrd"&gt;try&lt;/span&gt;
            {
                webresponse = (System.Net.HttpWebResponse)req.GetResponse();
            }
            &lt;span class="kwrd"&gt;catch&lt;/span&gt;(Exception ex)
            {
                webresponse = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
                Console.Write(&lt;span class="str"&gt;"request for url failed: {0} {1}"&lt;/span&gt;, url, ex.Message);
            }

            &lt;span class="kwrd"&gt;if&lt;/span&gt; (webresponse != &lt;span class="kwrd"&gt;null&lt;/span&gt;)
            {
                webresponse.Cookies = req.CookieContainer.GetCookies(req.RequestUri);
                &lt;span class="rem"&gt;// handle cookies (need to do this incase we have any session cookies)&lt;/span&gt;
                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (System.Net.Cookie retCookie &lt;span class="kwrd"&gt;in&lt;/span&gt; webresponse.Cookies)
                {
                    &lt;span class="kwrd"&gt;bool&lt;/span&gt; cookieFound = &lt;span class="kwrd"&gt;false&lt;/span&gt;;
                    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (System.Net.Cookie oldCookie &lt;span class="kwrd"&gt;in&lt;/span&gt; _CookieContainer.GetCookies(uri))
                    {
                        &lt;span class="kwrd"&gt;if&lt;/span&gt; (retCookie.Name.Equals(oldCookie.Name))
                        {
                            oldCookie.Value = retCookie.Value;
                            cookieFound = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
                        }
                    }
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!cookieFound)
                    {
                        _CookieContainer.Add(retCookie);
                    }
                }

                doc = &lt;span class="kwrd"&gt;new&lt;/span&gt; HtmlDocument();
                
                doc.MimeType = ParseMimeType(webresponse.ContentType.ToString()).ToLower();
                doc.ContentType = ParseEncoding(webresponse.ToString()).ToLower();
                doc.Extension = ParseExtension(uri.AbsoluteUri);

                &lt;span class="kwrd"&gt;string&lt;/span&gt; enc = &lt;span class="str"&gt;"utf-8"&lt;/span&gt;; &lt;span class="rem"&gt;// default&lt;/span&gt;
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (webresponse.ContentEncoding != String.Empty)
                {
                    &lt;span class="rem"&gt;// Use the HttpHeader Content-Type in preference to the one set in META&lt;/span&gt;
                    doc.Encoding = webresponse.ContentEncoding;
                }
                &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (doc.Encoding == String.Empty)
                {
                    doc.Encoding = enc; &lt;span class="rem"&gt;// default&lt;/span&gt;
                }
                &lt;span class="rem"&gt;//http://www.c-sharpcorner.com/Code/2003/Dec/ReadingWebPageSources.asp&lt;/span&gt;
                System.IO.StreamReader stream = &lt;span class="kwrd"&gt;new&lt;/span&gt; System.IO.StreamReader
                    (webresponse.GetResponseStream(), System.Text.Encoding.GetEncoding(doc.Encoding));

                doc.Uri = webresponse.ResponseUri; &lt;span class="rem"&gt;// we *may* have been redirected... and we want the *final* URL&lt;/span&gt;
                doc.Length = webresponse.ContentLength;
                doc.Html = stream.ReadToEnd();
                stream.Close();

                doc.Parse();

                webresponse.Close();
            }

            &lt;span class="kwrd"&gt;return&lt;/span&gt; doc;
        }


        &lt;span class="preproc"&gt;#region&lt;/span&gt; Private Methods: ParseExtension, ParseMimeType, ParseEncoding
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ParseExtension(&lt;span class="kwrd"&gt;string&lt;/span&gt; filename)
        {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; System.IO.Path.GetExtension(filename).ToLower();
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ParseMimeType(&lt;span class="kwrd"&gt;string&lt;/span&gt; contentType)
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; mimeType = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;
            &lt;span class="kwrd"&gt;string&lt;/span&gt;[] contentTypeArray = contentType.Split(&lt;span class="str"&gt;';'&lt;/span&gt;);
            &lt;span class="rem"&gt;// Set MimeType if it's blank&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (mimeType == String.Empty &amp;amp;&amp;amp; contentTypeArray.Length &amp;gt;= 1)
            {
                mimeType = contentTypeArray[0];
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; mimeType;
        }

        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ParseEncoding(&lt;span class="kwrd"&gt;string&lt;/span&gt; contentType)
        {
            &lt;span class="kwrd"&gt;string&lt;/span&gt; encoding = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty;
            &lt;span class="kwrd"&gt;string&lt;/span&gt;[] contentTypeArray = contentType.Split(&lt;span class="str"&gt;';'&lt;/span&gt;);
            &lt;span class="rem"&gt;// Set Encoding if it's blank&lt;/span&gt;
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (encoding == String.Empty &amp;amp;&amp;amp; contentTypeArray.Length &amp;gt;= 2)
            {
                &lt;span class="kwrd"&gt;int&lt;/span&gt; charsetpos = contentTypeArray[1].IndexOf(&lt;span class="str"&gt;"charset"&lt;/span&gt;);
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (charsetpos &amp;gt; 0)
                {
                    encoding = contentTypeArray[1].Substring(charsetpos + 8, contentTypeArray[1].Length - charsetpos - 8);
                }
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; encoding;
        }
        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;
    }
}
&lt;/pre&gt;



&lt;h2&gt;References:&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://incubator.apache.org/lucene.net/docs/2.1/"&gt;Apache Lucene.Net 2.1 Class Library API&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://www.searcharoo.net/"&gt;Searcharoo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><updated>2008-03-11T05:24:03Z</updated><published>2008-03-11T05:24:03Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>Be Careful With Page.PreviousPage</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/be-careful-with-page_previouspage" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/be-careful-with-page_previouspage</id><summary
		type="html">I found something interesting while testing the website tonight.  The new search we implemented was not working on the pages that display house plans.  I thought that it was some kind of routing error that could be attributed to the url rewriting.  However, closer examination showed that this is the error:

'Page.PreviousPage' threw an exception of type 'System.Threading.ThreadAbortException'

For some reason ASP.Net doesn't like certain nested master pages and will throw this error.  My solution was to remove the Page.PreviousPage reference and key off of a parameter value - in this case the value contained in the search box.  All that I can figure is that the PreviousPage reference attempts to actually load the page which can result in errors and thus the exception.  I haven't had</summary><content
		type="html">&lt;p&gt;I found something interesting while testing the website tonight.  The new search we implemented was not working on the pages that display house plans.  I thought that it was some kind of routing error that could be attributed to the url rewriting.  However, closer examination showed that this is the error:&lt;/p&gt;
&lt;code&gt;
'Page.PreviousPage' threw an exception of type 'System.Threading.ThreadAbortException'
&lt;/code&gt;
&lt;p&gt;For some reason ASP.Net doesn't like certain nested master pages and will throw this error.  My solution was to remove the Page.PreviousPage reference and key off of a parameter value - in this case the value contained in the search box.  All that I can figure is that the PreviousPage reference attempts to actually load the page which can result in errors and thus the exception.  I haven't had this problem with any of the other pages on the site.&lt;/p&gt;

&lt;p&gt;My fix may not be the one I want, but it is fixed.&lt;/p&gt;</content><updated>2008-03-05T06:57:33Z</updated><published>2008-03-05T06:57:33Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>XML Encoding Problems - Hexadecimal Value 0x1A, is an Invalid Character</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/hexadecimal-value-invalid-character" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/hexadecimal-value-invalid-character</id><summary
		type="html">Recently I started noticing exceptions in my log files that stated "hexadecimal value 0x1A, is an invalid character".  I did some searching and a lot of other people have had the same problem.  It occurs when someone pastes in text that contains specific unicode characters that are invalid in XML.  From what I gather this frequently happens when someone copies in text from Microsoft Word.

The trick was to find out which characters are invalid and then use a regular expression to remove them.

You can look at the specs for all the details:

http://www.w3.org/TR/xml11/#charsets

http://www.w3.org/TR/REC-xml/#charsets
http://www.unicode.org/Public/UNIDATA/UCD.html


But it is probably easier to just get the code:


        /// &amp;lt;summary&amp;gt;
        /// This removes</summary><content
		type="html">&lt;p&gt;Recently I started noticing exceptions in my log files that stated "hexadecimal value 0x1A, is an invalid character".  I did some searching and a lot of other people have had the same problem.  It occurs when someone pastes in text that contains specific unicode characters that are invalid in XML.  From what I gather this frequently happens when someone copies in text from Microsoft Word.&lt;/p&gt;

&lt;p&gt;The trick was to find out which characters are invalid and then use a regular expression to remove them.&lt;/p&gt;

&lt;p&gt;You can look at the specs for all the details:&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.w3.org/TR/xml11/#charsets"&gt;http://www.w3.org/TR/xml11/#charsets
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.w3.org/TR/REC-xml/#charsets"&gt;http://www.w3.org/TR/REC-xml/#charsets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.unicode.org/Public/UNIDATA/UCD.html"&gt;http://www.unicode.org/Public/UNIDATA/UCD.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But it is probably easier to just get the code:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;
        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// This removes characters that are invalid for xml encoding&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="text"&amp;gt;Text to be encoded.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;Text with invalid xml characters removed.&amp;lt;/returns&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; CleanInvalidXmlChars(&lt;span class="kwrd"&gt;string&lt;/span&gt; text)
        {
            &lt;span class="rem"&gt;// From xml spec valid chars:&lt;/span&gt;
            &lt;span class="rem"&gt;// #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]    &lt;/span&gt;
            &lt;span class="rem"&gt;// any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.&lt;/span&gt;
            &lt;span class="kwrd"&gt;string&lt;/span&gt; re = &lt;span class="str"&gt;@"[^\x09\x0A\x0D\x20-\xD7FF\xE000-\xFFFD\x10000-x10FFFF]"&lt;/span&gt;;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; Regex.Replace(text, re, &lt;span class="str"&gt;""&lt;/span&gt;);
        }&lt;/pre&gt;</content><updated>2008-03-04T04:17:20Z</updated><published>2008-03-04T04:17:20Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>Updated Forums</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/updated-forums" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/updated-forums</id><summary
		type="html">We recently updated our forums.  This was a big move as it required retiring our old forum software and migrating all the old posts to our new custom forums.  We feel that the change will provide a better experience for everyone using the site.

If you have any questions or would like to make a comment feel free to post to the forum and let us know what you think!

One quick tip.  If you paste a link to a house plan in the forum like this:

http://www.theplancollection.com/house-plans/home-plan-9218

the software will automatically add in the image of the house plan and create a working</summary><content
		type="html">&lt;p&gt;We recently updated our forums.  This was a big move as it required retiring our old forum software and migrating all the old posts to our new custom forums.  We feel that the change will provide a better experience for everyone using the site.&lt;/p&gt;

&lt;p&gt;If you have any questions or would like to make a comment feel free to post to the forum and let us know what you think!&lt;/p&gt;

&lt;p&gt;One quick tip.  If you paste a link to a house plan in the forum like this:&lt;/p&gt;
&lt;blockquote&gt;
http://www.theplancollection.com/house-plans/home-plan-9218
&lt;/blockquote&gt;
&lt;p&gt;the software will automatically add in the image of the house plan and create a working link.&lt;/p&gt;</content><updated>2008-02-25T07:16:15Z</updated><published>2008-02-25T07:16:15Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>The Forums are Broken</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/the-forums-are-broken" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/the-forums-are-broken</id><summary
		type="html">The forums are busted at the moment.  Sorry about that.  We are currently using a piece of software called community server that we purchased so we didn't have to write our own.  It has been nothing but trouble so now we are moving away from it to a simpler system.  We are writing it so it will take a bit longer to finish, but you can expect to see it running within the week.  The debate between whether to write your own software or to find something that exists is always a tough one.  It is always nice to let someone else do the work for you, but over time it can actually be more cost effective to develop your own solution if:


What you need is only a small subset of the off the shelf software and you want to simplify the experience for your users.
You need a highly customized</summary><content
		type="html">&lt;p&gt;The forums are busted at the moment.  Sorry about that.  We are currently using a piece of software called community server that we purchased so we didn't have to write our own.  It has been nothing but trouble so now we are moving away from it to a simpler system.  We are writing it so it will take a bit longer to finish, but you can expect to see it running within the week.  The debate between whether to write your own software or to find something that exists is always a tough one.  It is always nice to let someone else do the work for you, but over time it can actually be more cost effective to develop your own solution if:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What you need is only a small subset of the off the shelf software and you want to simplify the experience for your users.&lt;/li&gt;
&lt;li&gt;You need a highly customized solution that would require extensive modification of existing software.&lt;/li&gt;
&lt;li&gt;The off the shelf software you choose is not so great.&lt;/li&gt;
&lt;li&gt;You can afford to do it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In our case all the above criteria apply.  I have written more than a few forums in the past in various programming languages so writing a custom one will only take me a few days.  Now back to work I go.&lt;/p&gt;</content><updated>2008-02-14T07:27:05Z</updated><published>2008-02-14T07:27:05Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>Why Asp.net Sucks (Tonight)</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/why-asp-net-sucks-tonight" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/why-asp-net-sucks-tonight</id><summary
		type="html">I have noticed a slight slow down on a few of the pages on the website so I figured that it was time to get in there and turn on some caching.  Asp.net, the technology we use, is supposed to make this very simple.  All you have to do is something like this:






Then magic happens and your page is magically stored in memory and millions of people can view it at the same time.  The problem is that every page on The Plan Collection contains a login control.  It is the little piece of code in the upper right.  If you turn on caching guess what happens.  The first person to login and view a page gets their user account broadcast to everyone else that sees that page.  That's right the designers of the LoginView Asp.net control were so short sighted that they didn't realize that that</summary><content
		type="html">&lt;p&gt;I have noticed a slight slow down on a few of the pages on the website so I figured that it was time to get in there and turn on some caching.  Asp.net, the technology we use, is supposed to make this very simple.  All you have to do is something like this:
&lt;/p&gt;

&lt;code&gt;
&lt;%@ OutputCache Duration="600" VaryByParam="none" %&gt;
&lt;/code&gt;

&lt;p&gt;Then magic happens and your page is magically stored in memory and millions of people can view it at the same time.  The problem is that every page on The Plan Collection contains a login control.  It is the little piece of code in the upper right.  If you turn on caching guess what happens.  The first person to login and view a page gets their user account broadcast to everyone else that sees that page.  That's right the designers of the LoginView Asp.net control were so short sighted that they didn't realize that that control should NEVER be cached.&lt;/p&gt;

&lt;p&gt;There are other problems with caching in asp.net as well including a lovely problem with the varybycustom parameter when you do cross page posting.  The fun part of that is that if you set the parameter in page one then post to page two where a second varybycustom parameter is set the framework coughs, sputters and throws an exception letting you know that the parameter has already been set.  How about this guys.  Instead of throwing an exception vary by two parameters?&lt;/p&gt;

&lt;p&gt;Don't worry this code never made it to production.  I am once again going to go in and deal with the caching programatically so that site will get a boost.  However, it is frustrating when 'enterprise' frameworks like asp.net fail you in terrible ways.  Come on guys even though you are Microsoft and the world is accustomed to being let down by you, you can do better.&lt;/p&gt;</content><updated>2008-02-01T07:37:03Z</updated><published>2008-02-01T07:37:03Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>Ping Feedburner, Ping-o-Matic, Google, Technorati and All the Other Cool Kids Using ASP.NET and Some Magic</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/Ping-Using-ASP-NET-and-Some-Magic" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/Ping-Using-ASP-NET-and-Some-Magic</id><summary
		type="html">It has been a long time coming, but we have finally managed to migrate away from Community Server to our own custom blog software that is integrated directly into the web site.  The reasons for the change are numerous including the need to customize the look and navigation of our blogging software and our desire to provide readers a more streamlined experience.

The final part of the migration to this new system was released tonight.  This final piece being the ability to ping the various providers that watch new blog posts.  The code required to do this is not difficult to write.  I am posting it below in case anyone is interested in how it is done.

Ironically enough this post will be the first one to actually use the ping service.  Here's a link that helped me figure out how to do</summary><content
		type="html">&lt;p&gt;It has been a long time coming, but we have finally managed to migrate away from Community Server to our own custom blog software that is integrated directly into the web site.  The reasons for the change are numerous including the need to customize the look and navigation of our blogging software and our desire to provide readers a more streamlined experience.&lt;/p&gt;

&lt;p&gt;The final part of the migration to this new system was released tonight.  This final piece being the ability to ping the various providers that watch new blog posts.  The code required to do this is not difficult to write.  I am posting it below in case anyone is interested in how it is done.&lt;/p&gt;

&lt;p&gt;Ironically enough this post will be the first one to actually use the ping service.  &lt;a href="http://www.xmlpronews.com/2007/11/20/ping-using-xml-rpc-in-aspnet/" title="Ping Using XML-RPC In ASP.NET"&gt;Here's a link that helped me figure out how to do the ping&lt;/a&gt; and here's the code:&lt;/p&gt;

&lt;code&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.IO;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Net;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Xml;
&lt;span class="kwrd"&gt;using&lt;/span&gt; ThePlanCollectionCore.Utils;

&lt;span class="kwrd"&gt;namespace&lt;/span&gt; ThePlanCollectionCore.DataFeeds
{
    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Wrapper for xml rpc service&lt;/span&gt;
    &lt;span class="rem"&gt;/// that can ping ping-o-matic and other services&lt;/span&gt;
    &lt;span class="rem"&gt;/// when your blog is updated.&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Ping
    {
        &lt;span class="rem"&gt;// List of services that accept an xml rpc ping.&lt;/span&gt;
        &lt;span class="rem"&gt;// If you surf around the net you will find many other&lt;/span&gt;
        &lt;span class="rem"&gt;// services but many of them are offline or &lt;/span&gt;
        &lt;span class="rem"&gt;// appear to be junk.  Stick with the main ones.&lt;/span&gt;
        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; [] _Services = {
            &lt;span class="str"&gt;"http://rpc.pingomatic.com"&lt;/span&gt;,
            &lt;span class="str"&gt;"http://blogsearch.google.com/ping/RPC2"&lt;/span&gt;,
            &lt;span class="str"&gt;"http://www.blogsnow.com/ping"&lt;/span&gt;,
            &lt;span class="str"&gt;"http://www.wasalive.com/ping/"&lt;/span&gt;
            };


        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Sends a ping to the above services using the given website name &lt;/span&gt;
        &lt;span class="rem"&gt;/// and url&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="websiteName"&amp;gt;The name of the website or blog&lt;/span&gt;
        &lt;span class="rem"&gt;/// that has been updated.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="websiteUrl"&amp;gt;The url of the website or blog&lt;/span&gt;
        &lt;span class="rem"&gt;/// that has been updated.  This should be an absolute root url&lt;/span&gt;
        &lt;span class="rem"&gt;/// not a direct link to the individual page that has been updated.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Send(&lt;span class="kwrd"&gt;string&lt;/span&gt; websiteName, &lt;span class="kwrd"&gt;string&lt;/span&gt; websiteUrl)
        {
            &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; _Services.Length; i++)
            {
                &lt;span class="kwrd"&gt;try&lt;/span&gt;
                {
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_Services[i]);
                    request.Method = &lt;span class="str"&gt;"POST"&lt;/span&gt;;
                    request.ContentType = &lt;span class="str"&gt;"text/xml"&lt;/span&gt;;
                    request.Timeout = 3000;

                    &lt;span class="rem"&gt;// Add in the updated page&lt;/span&gt;
                    BuildRequest(request, websiteName, websiteUrl);

                    &lt;span class="rem"&gt;// Send off the request&lt;/span&gt;
                    request.GetResponse();
                }
                &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
                {
                    &lt;span class="rem"&gt;// Log the error.&lt;/span&gt;
                    Error err = &lt;span class="kwrd"&gt;new&lt;/span&gt; Error();
                    err.Title = &lt;span class="str"&gt;"Ping Request Failure"&lt;/span&gt;;
                    err.Body = &lt;span class="str"&gt;"Ping to "&lt;/span&gt; + _Services[i] + &lt;span class="str"&gt;" failed with error: "&lt;/span&gt; + ex.Message;
                    err.Save();
                }
            }
        }

        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// Adds the requred xml to the request.  This includes the website name and url&lt;/span&gt;
        &lt;span class="rem"&gt;/// along with the method name 'ping' that will tell the remote servers that&lt;/span&gt;
        &lt;span class="rem"&gt;/// and update has been made&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="request"&amp;gt;A http webrequest generated by the method 'Send' above.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="websiteName"&amp;gt;The name of the website or blog&lt;/span&gt;
        &lt;span class="rem"&gt;/// that has been updated.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;/// &amp;lt;param name="websiteUrl"&amp;gt;The url of the website or blog&lt;/span&gt;
        &lt;span class="rem"&gt;/// that has been updated.  This should be an absolute root url&lt;/span&gt;
        &lt;span class="rem"&gt;/// not a direct link to the individual page that has been updated.&amp;lt;/param&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; BuildRequest(HttpWebRequest request, &lt;span class="kwrd"&gt;string&lt;/span&gt; websiteName, &lt;span class="kwrd"&gt;string&lt;/span&gt; websiteUrl)
        {
            Stream stream = request.GetRequestStream();
            &lt;span class="kwrd"&gt;using&lt;/span&gt; (XmlTextWriter writer = &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlTextWriter(stream, Encoding.ASCII))
            {
                writer.WriteStartDocument();
                writer.WriteStartElement(&lt;span class="str"&gt;"methodCall"&lt;/span&gt;);
                writer.WriteElementString(&lt;span class="str"&gt;"methodName"&lt;/span&gt;, &lt;span class="str"&gt;"ping"&lt;/span&gt;);
                writer.WriteStartElement(&lt;span class="str"&gt;"params"&lt;/span&gt;);
                writer.WriteStartElement(&lt;span class="str"&gt;"param"&lt;/span&gt;);
                
                &lt;span class="rem"&gt;// Add the name of your website here&lt;/span&gt;
                writer.WriteElementString(&lt;span class="str"&gt;"value"&lt;/span&gt;, websiteName);
                writer.WriteEndElement();
                writer.WriteStartElement(&lt;span class="str"&gt;"param"&lt;/span&gt;);

                &lt;span class="rem"&gt;// The absolute URL of your website - not the updated or new page&lt;/span&gt;
                writer.WriteElementString(&lt;span class="str"&gt;"value"&lt;/span&gt;, websiteUrl);
                writer.WriteEndElement();
                writer.WriteEndElement();
                writer.WriteEndElement();
            }
        }
    }
}
&lt;/pre&gt;
&lt;/code&gt;</content><updated>2008-01-31T04:29:13Z</updated><published>2008-01-31T04:29:13Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>Fixed The Main House Plan Pages</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/Fixed-The-Main-House-Plan-Pages" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/Fixed-The-Main-House-Plan-Pages</id><summary
		type="html">The other update I made last night was with the main landing pages.  Some of the pages -
luxury house plans,
country house plans, and
arts and crafts house plans looked fine because we had edited those pages by hand.  However, many of our other pages like cape code style house plans page and our colonial style house plans page looked terrible.

I was able to use our existing page processing system and create a template for our landing pages that is loaded dynamically and then sent through the processor.  The template contains place holders that are replaced with values specific to the style.  Those values are replaced on the fly and then the page is generated.  The result is a much better looking page that the guys in the office don't have to maintain by</summary><content
		type="html">&lt;p&gt;The other update I made last night was with the main landing pages.  Some of the pages -
&lt;a href="http://www.theplancollection.com/luxury-house-plans" title="View our main luxury house plans page"&gt;luxury house plans&lt;/a&gt;,
&lt;a href="http://www.theplancollection.com/country-house-plans" title="View our main country house plans page including our featured country home plan"&gt;country house plans&lt;/a&gt;, and
&lt;a href="http://www.theplancollection.com/arts-and-crafts-house-plans" title="View our main arts and crafts house plans including our featured arts and crafts home plan"&gt;arts and crafts house plans&lt;/a&gt; looked fine because we had edited those pages by hand.  However, many of our other pages like &lt;a href="http://www.theplancollection.com/cape-cod-house-plans" title="View our cape code style house plans including our featured cape code home plan"&gt;cape code style house plans&lt;/a&gt; page and our &lt;a href="http://www.theplancollection.com/colonial-house-plans" title="View colonial style house plans and our featured colonial style home plan"&gt;colonial style house plans&lt;/a&gt; page looked terrible.&lt;/p&gt;

&lt;p&gt;I was able to use our existing page processing system and create a template for our landing pages that is loaded dynamically and then sent through the processor.  The template contains place holders that are replaced with values specific to the style.  Those values are replaced on the fly and then the page is generated.  The result is a much better looking page that the guys in the office don't have to maintain by hand.&lt;/p&gt;</content><updated>2008-01-29T18:19:30Z</updated><published>2008-01-29T18:19:30Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>Updated Image Processing</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/Updated-Image-Processing" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/Updated-Image-Processing</id><summary
		type="html">Working on a website in the middle of the night as I usually do is always an interesting and lonely experience.  The benefit is that you get a lot done because no one bothers you.  The downside is that waking up the next day is never fun.

This evening I managed to image processing code for our site.  Every image - hundreds of thousands of them are passed through that code.  It is fun to watch on the server because you can see the images being generated and then cached on the fly.  Hundreds of them are generated every second.  Pretty cool eh?

The uncool part was that it has had a few problems this last week.  We recently received some images from our designers that were in a new format.  (Who would have thought that there are so many formats for gif and jpg).  At any rate the image</summary><content
		type="html">&lt;p&gt;Working on a website in the middle of the night as I usually do is always an interesting and lonely experience.  The benefit is that you get a lot done because no one bothers you.  The downside is that waking up the next day is never fun.&lt;/p&gt;

&lt;p&gt;This evening I managed to image processing code for our site.  Every image - hundreds of thousands of them are passed through that code.  It is fun to watch on the server because you can see the images being generated and then cached on the fly.  Hundreds of them are generated every second.  Pretty cool eh?&lt;/p&gt;

&lt;p&gt;The uncool part was that it has had a few problems this last week.  We recently received some images from our designers that were in a new format.  (Who would have thought that there are so many formats for gif and jpg).  At any rate the image processor was choking on some of some of the unsupported formats, throwing an exception, and then spewing out the 'Image Not Found' thumbnail that it likes to spit out when it gets lost.&lt;/p&gt;

&lt;p&gt;This of course drove everyone in the office crazy because, well the image was there but the computer was telling then it wasn't. &lt;/p&gt; 

&lt;p&gt;Its fixed now.&lt;/p&gt;

&lt;p&gt;In case you wonder what made the difference here it is:&lt;/p&gt;

&lt;p&gt;
This was the exception:&lt;br /&gt;
&lt;strong&gt;A Graphics object cannot be created from an image that has an indexed pixel format.&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;a href="http://msdn2.microsoft.com/en-us/library/system.drawing.graphics.fromimage.aspx"&gt;Here's the documentation from Microsoft&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
and here is the code I used to deal with the issue:
&lt;code&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;pre class="csharpcode"&gt;
        &lt;span class="kwrd"&gt;private&lt;/span&gt; Bitmap GetTempImage(&lt;span class="kwrd"&gt;int&lt;/span&gt; width, &lt;span class="kwrd"&gt;int&lt;/span&gt; height)
        {
            Bitmap tempImage;
            &lt;span class="kwrd"&gt;if&lt;/span&gt;(_CurrentImage.PixelFormat == PixelFormat.Undefined ||
               _CurrentImage.PixelFormat == PixelFormat.DontCare ||
               _CurrentImage.PixelFormat == PixelFormat.Format1bppIndexed ||
               _CurrentImage.PixelFormat == PixelFormat.Format4bppIndexed ||
               _CurrentImage.PixelFormat == PixelFormat.Format8bppIndexed ||
               _CurrentImage.PixelFormat == PixelFormat.Format16bppGrayScale ||
               _CurrentImage.PixelFormat == PixelFormat.Format16bppArgb1555)
            {
                &lt;span class="rem"&gt;// None of the above types are support so &lt;/span&gt;
                &lt;span class="rem"&gt;//just create a bitmap that uses the default pixel format&lt;/span&gt;
                tempImage = &lt;span class="kwrd"&gt;new&lt;/span&gt; Bitmap(width, height);
            }
            &lt;span class="kwrd"&gt;else&lt;/span&gt;
            {
                tempImage = &lt;span class="kwrd"&gt;new&lt;/span&gt; Bitmap(width, height, _CurrentImage.PixelFormat);
            }
            &lt;span class="kwrd"&gt;return&lt;/span&gt; tempImage;
        }&lt;/pre&gt;
&lt;/code&gt;
&lt;/p&gt;</content><updated>2008-01-29T08:56:56Z</updated><published>2008-01-29T08:56:56Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>Updated The Article System</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/updated-article-system" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/updated-article-system</id><summary
		type="html">I updated the way we handle articles this evening.  We used to use Commmunity Server from telligent systems for blogging, but I found that it was too cumbersome and way too difficult to update.  The themes are terrible to maintain so I build a system that meets our specific needs.
Our new system is divided into topics that I hope our visitors will find relevant.  Most of our main content will end up in the 'House Plans'.  However, we hope to venture out a bit and include relevant content in the business section where we will talk about how we manage ThePlanCollection.com and our technology in this section.  In addition, we have added a green building section where we hope to highlight methods of responsible</summary><content
		type="html">&lt;p&gt;I updated the way we handle articles this evening.  We used to use Commmunity Server from telligent systems for blogging, but I found that it was too cumbersome and way too difficult to update.  The themes are terrible to maintain so I build a system that meets our specific needs.&lt;/p&gt;
&lt;p&gt;Our new system is divided into topics that I hope our visitors will find relevant.  Most of our main content will end up in the &lt;a href="http://www.theplancollection.com/house-plan-related-articles" title="Read house plan related articles."&gt;'House Plans'&lt;/a&gt;.  However, we hope to venture out a bit and include relevant content in the &lt;a href="http://www.theplancollection.com/house-plan-related-articles-business" title="Information about the business of ThePlanCollection.com"&gt;business&lt;/a&gt; section where we will talk about how we manage &lt;a href="http://www.theplancollection.com"&gt;ThePlanCollection.com&lt;/a&gt; and our &lt;a href="http://www.theplancollection.com/house-plan-related-articles-technology" title="Technology related items"&gt;technology&lt;/a&gt; in this section.  In addition, we have added a &lt;a href="http://www.theplancollection.com/house-plan-related-articles-green+building" title="Green home building and design"&gt;green building&lt;/a&gt; section where we hope to highlight methods of responsible homebuilding.&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;</content><updated>2008-01-25T08:36:30Z</updated><published>2008-01-25T08:36:30Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>New Technology Section</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/new-technology-section" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/new-technology-section</id><summary
		type="html">As part of our efforts to become more interesting and more transparent we have added a couple of new sections to ThePlanCollection.com.  This section will focus on the technology we use, updates to the website and other technical issues that we find are interesting or relevant.  Hopefully everyone finds this</summary><content
		type="html">&lt;p&gt;As part of our efforts to become more interesting and more transparent we have added a couple of new sections to &lt;a href="http://www.theplancollection.com" title="View House Plans on our home page"&gt;ThePlanCollection.com&lt;/a&gt;.  This section will focus on the technology we use, updates to the website and other technical issues that we find are interesting or relevant.  Hopefully everyone finds this useful.&lt;/p&gt;</content><updated>2008-01-25T08:29:40Z</updated><published>2008-01-25T08:29:40Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>The Plan Collection is on Facebook</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/ThePlanCollection_facebook_application" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/ThePlanCollection_facebook_application</id><summary
		type="html">When you are a small business and don't have an enormous development team you have to be careful about technology decisions.  Most of our time is spent ensuring that our application is secure and running properly.  Some of our time is spent adding new features including making changes to the design of the interface so that the website looks nicer.

Then there is time that we spend working on search engine optimization (SEO).  We prefer to spend our time trying to get organic traffic because one, it is the best traffic and two it is free if you dont count all the time we spend on SEO.  Of course my justification for not counting SEO as a direct marketing expense is that it usually makes our site better when done right.

Every once in a while we have a moment to breathe and we do</summary><content
		type="html">&lt;p&gt;When you are a small business and don't have an enormous development team you have to be careful about technology decisions.  Most of our time is spent ensuring that our application is secure and running properly.  Some of our time is spent adding new features including making changes to the design of the interface so that the website looks nicer.&lt;/p&gt;

&lt;p&gt;Then there is time that we spend working on search engine optimization (SEO).  We prefer to spend our time trying to get organic traffic because one, it is the best traffic and two it is free if you dont count all the time we spend on SEO.  Of course my justification for not counting SEO as a direct marketing expense is that it usually makes our site better when done right.&lt;/p&gt;

&lt;p&gt;Every once in a while we have a moment to breathe and we do something that is fun and interesting and that will hopefully lead to new opportunities.  To this end we have created a &lt;a href="http://www.facebook.com" title="Go to Facebook"&gt;Facebook&lt;/a&gt; application that lets users save house plans and then share them with friends.  Users can also add comments to house plans and then watch what others are doing/saying.&lt;/p&gt;  

&lt;p&gt;We realize that Facebook applications are no longer bleeding edge, but this is a chance to see if any sort of meaningful interaction will take place in our application and discover if Facebook can provide benefits to small business.  We currently have around 1300 users which is nothing compared to the most popular applications, but given that our application is very niche specific and our target audience is smaller it is a great start.  Many Facebook users are in college or right out of college.  As they get  get ready to purchase their first home our hope is that they will use their social network to get ideas and they will find us there.&lt;/p&gt;

&lt;p&gt;If you want to try out the application you will need a Facebook account.  Then all you need to do is &lt;a href="http://apps.facebook.com/house-plans/" title="Install the 'My House Plans' application on Facebook"&gt;click here to install our house plans application.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How beneficial social networks will be to businesses like ours is yet to be determined.  Creating an application might just burn up more of our server resources and bandwidth or it might bring users who buy something.  It might be a great, free marketing resource or it might just give a bunch of kids a place to post vulgarities.  Whatever the outcome well keep posting to let you know what happens in this emerging space.&lt;/p&gt;</content><updated>2008-01-14T21:47:38Z</updated><published>2008-01-14T21:47:38Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>Need a Building? Just Add Water</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/Need-a-Building--Just-Add-Water" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/Need-a-Building--Just-Add-Water</id><summary
		type="html">
 
I thought this article was worth sharing with you.
Need a Building? Just Add Water
As an emergency shelter alternative to tents, which provide poor protection, and prefabricated buildings that are expensive to transport, two engineers working on their master&amp;#8217;s degrees at the Royal College of Art in London have come up with a &amp;#8220;building in a bag.&amp;#8221; Erecting the &amp;#8220;Concrete Canvas&amp;#8221; structure entails adding water to a sack of cement-impregnated fabric and inflating it with air. The volume of the sack controls the water-to-cement ratio, eliminating the need for water measurement. The Nissen hut-shaped shelter is dry and ready to use in about 12 hours. The inventors said they thought of the approach after hearing about inflatable structures that are built around</summary><content
		type="html">&lt;HR align=center width="100%" SIZE=2&gt;
 
&lt;P&gt;I thought this article was worth sharing with you.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Need a Building? Just Add Water&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;&lt;PL&gt;As an emergency shelter alternative to tents, which provide poor protection, and prefabricated buildings that are expensive to transport, two engineers working on their master&amp;#8217;s degrees at the Royal College of Art in London have come up with a &amp;#8220;building in a bag.&amp;#8221; Erecting the &amp;#8220;Concrete Canvas&amp;#8221; structure entails adding water to a sack of cement-impregnated fabric and inflating it with air. The volume of the sack controls the water-to-cement ratio, eliminating the need for water measurement. The Nissen hut-shaped shelter is dry and ready to use in about 12 hours. The inventors said they thought of the approach after hearing about inflatable structures that are built around broken gas pipes to carry out repairs. &amp;#8220;This gave us the idea of making a giant concrete eggshell for a shelter, using inflation to optimize the structure for a compressive load,&amp;#8221; said co-inventor Peter Brewin. &amp;#8220;Eggs are entirely compressive structures with enormous strength for a very thin wall.&amp;#8221; A bag weighing about 500 pounds inflates into a structure with 172 square feet and would cost about $7,700. Full-scale production of the shelter is being planned. (&lt;A href="http://www.wired.com/"&gt;&lt;FONT color=#333399&gt;www.wired.com&lt;/FONT&gt;&lt;/A&gt;)&lt;STRONG&gt; &lt;BR&gt;Wired News (3/15/05); Rowan Hooper&lt;/STRONG&gt;&lt;/P&gt;</content><updated>2005-03-22T13:51:00Z</updated><published>2005-03-22T13:51:00Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>Apologies in advance</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/Apologies-in-advance" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/Apologies-in-advance</id><summary
		type="html">I haven't been posting very often latetly - again.  We are currently working on a new version of software for The Plan Collection and it is taking up quite a bit of my time.  Hopefully the new version will better meet the needs of everyone who visits.  If you have any suggestions or features that you desire go ahead and post them in the comments and we'll do what we can to add</summary><content
		type="html">I haven't been posting very often latetly - again.  We are currently working on a new version of software for The Plan Collection and it is taking up quite a bit of my time.  Hopefully the new version will better meet the needs of everyone who visits.  If you have any suggestions or features that you desire go ahead and post them in the comments and we'll do what we can to add them.</content><updated>2004-11-23T15:25:00Z</updated><published>2004-11-23T15:25:00Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>Thanks for coming</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/Thanks-for-coming" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/Thanks-for-coming</id><summary
		type="html">As a software engineer there is nothing more gratifying then having people actually use the software you have created.  Over the years as I have met new people, it is interesting to find how many have visited The Plan Collection.  We receive many visitors each day from all around the world.  When we moved our hosting services to a new provider this year our provider was shocked to see the amount of visitors that come each day.  Whether you are looking for a home plan or just browsing for ideas thanks for</summary><content
		type="html">&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;As a software engineer there is nothing more gratifying then having people actually use the software you have created.&lt;SPAN style="mso-spacerun: yes"&gt;  &lt;/SPAN&gt;Over the years as I have met new people, it is interesting to find how many have visited The Plan Collection.&lt;SPAN style="mso-spacerun: yes"&gt;  &lt;/SPAN&gt;We receive many visitors each day from all around the world.&lt;SPAN style="mso-spacerun: yes"&gt;  &lt;/SPAN&gt;When we moved our hosting services to a new provider this year our provider was shocked to see the amount of visitors that come each day.&lt;SPAN style="mso-spacerun: yes"&gt;  &lt;/SPAN&gt;Whether you are looking for a home plan or just browsing for ideas thanks for coming.&lt;/P&gt;</content><updated>2004-07-02T13:44:00Z</updated><published>2004-07-02T13:44:00Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry><entry><title>About a blog</title><link rel="alternate " type="text/html" href="http://www.theplancollection.com/house-plan-related-articles-technology/About-a-blog" /><id>http://www.theplancollection.com/house-plan-related-articles-technology/About-a-blog</id><summary
		type="html">   When you are a geek and spend ninety percent of you time in a virtual world you forget   that the rest of the world spends their time doing things like going outside or actually   talking to people.  Not everyone has run across the "blog" phenomenon before.    Blog is a shortened version of the phrase web log.  Blogs are website where individuals   may record their daily observations about various topics.  They are a great way   to disseminate information on a more personal level.  In addition, you will find   that most blogs include a link to an RSS or an Atom feed.  These links are usually   orange buttons, but may not always be so conspicuous.  If you click one of these   links you will get a page of text that is difficult to read.  The text on the   resulting pages is intended for</summary><content
		type="html">&lt;p&gt;   When you are a geek and spend ninety percent of you time in a virtual world you forget   that the rest of the world spends their time doing things like going outside or actually   talking to people.  Not everyone has run across the "blog" phenomenon before.    Blog is a shortened version of the phrase web log.  Blogs are website where individuals   may record their daily observations about various topics.  They are a great way   to disseminate information on a more personal level.  In addition, you will find   that most blogs include a link to an RSS or an Atom feed.  These links are usually   orange buttons, but may not always be so conspicuous.  If you click one of these   links you will get a page of text that is difficult to read.  The text on the   resulting pages is intended for an RSS aggregator.  These are programs that are   capable of bringing the information from many different blogs or websites together   into one place.  This can be very useful if you read information from many sources   as the aggregator will gather up all the news and allow you to view it without visiting   each individual site.  If you are like me and read news from hundreds of sources   this can be a real time saver.&lt;/p&gt;&lt;p&gt;   I personally use a program called SharpReader.  You can download it for free   at &lt;a href="http://www.sharpreader.net/"&gt;http://www.sharpreader.net/&lt;/a&gt;.  There   are many choices available.  &lt;a href="http://www.pcworld.com/resource/printable/article/0,aid,116018,00.asp"&gt;This   article&lt;/a&gt; from PC World lists several good readers and gives a good introduction   into how to find and use RSS.&lt;/p&gt;&lt;p&gt;   On The Plan Collection website our blogs try to focus on home plans and how to build   new homes.  You will find that &lt;a title="" HREF="/Blog/home_design/" target="_blank"&gt;Jake&lt;/a&gt;'s blog focuses on home designs while Jaren's   blog will focus on how to build a home.  &lt;a title="" HREF="/Blog/home_design/" target="_blank"&gt;Jake&lt;/a&gt; Smith's blog will display some   of the more popular home plans from The Plan Collection.  I will probably spend   a lot of time complaining about building a new home.  I will also include some   technical information about the software that runs The Plan Collection.  As time   goes on other members of our organization may also join our effort.  &lt;/p&gt;&lt;p&gt;   Our hope is that you will find our website a welcoming place that is easy to use.    We have long sought a better way to connect with those who use The Plan Collection.    If there is anything you fell we are doing wrong or that we can do better we always   welcome feedback.  I look forward to interacting with all of you that share our   passion for home design.&lt;/p&gt;&lt;p&gt;   Justin&lt;/p&gt;&lt;p&gt;    &lt;/p&gt;</content><updated>2004-06-29T13:17:00Z</updated><published>2004-06-29T13:17:00Z</published><author><name>The Plan Collection</name><uri>http://www.theplancollection.com</uri></author><rights type="html">&amp;copy; 2009 The Plan Collection</rights></entry></feed>