<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-9120211891716727685</id><updated>2010-03-18T16:12:22.323-05:00</updated><title type='text'>Cedar City Group</title><subtitle type='html'>The solution to your technology puzzle&lt;br&gt;&lt;br&gt;
Donnie Hall, Managing Consultant&lt;br&gt;
(615) 584-2729, dhall@cedarcitygroup.com</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default?start-index=26&amp;max-results=25'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/04094292761538176618</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>30</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-8156338469890563233</id><published>2009-01-24T17:07:00.005-06:00</published><updated>2009-01-24T17:17:35.985-06:00</updated><title type='text'>Interpolate is available!</title><content type='html'>Several years ago, I worked for a company that sold some small hand held computers made by Sharp.  They were pretty fascinating devices for the time. The &lt;a href=http://pocket.free.fr/html/sharp/pc-1262_e.html&gt;PC-1262&lt;/a&gt; was by far the most popular.&lt;br /&gt;&lt;br /&gt;I wrote some small utilities for use by medical physicists and we sold quite a few of them.  I had several ideas for products that would cater to engineers and scientists of all types, but we couldn't really get the ideas going into full fledged products.&lt;br /&gt;&lt;br /&gt;David Hinson, is a friend of mine in Florida who is focused on iPhone development among other things.  I ran an idea by him that I had way back when and in a matter of a few weeks, we have a product available for the iPhone called 'Interpolate'.&lt;br /&gt;&lt;br /&gt;This application allows the user to store known data points for multiple datasets and then allows them to obtain values for unknown points.  Believe it or not, there are people that need that sort of thing.  &lt;br /&gt;&lt;br /&gt;Here's a demo....&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/m4XRsa5wtN8&amp;hl=en&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/m4XRsa5wtN8&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;It is available on iTunes, buy it today!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-8156338469890563233?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/8156338469890563233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=8156338469890563233' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/8156338469890563233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/8156338469890563233'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2009/01/interpolatie-is-available.html' title='Interpolate is available!'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-5980384128266595514</id><published>2009-01-14T07:39:00.002-06:00</published><updated>2009-01-14T07:50:49.124-06:00</updated><title type='text'>Avoiding object aliasing....</title><content type='html'>Aliasing is a fancy term for referring to the same object by two different names.  Sometimes it can be useful, most times it will causes some unintended consequences.  As frameworks become more and more complex, with objects pointing to other objects (referred to as graphs) the potential for aliasing increases.&lt;br /&gt;&lt;br /&gt;Sometimes, you want to create a totally new instance of an object graph, but programming something list this can be very tricky.  Luckily, serialization gives us a very quick and easy way to perform a 'deep copy' of an object graph regardless of how complex it is.&lt;br /&gt;&lt;br /&gt;Below is my DeepCopy&lt;T&gt; class and its associated test...&lt;br /&gt;&lt;br /&gt;&lt;pre name=code class=c#&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Runtime.Serialization.Formatters.Binary;&lt;br /&gt;using System.IO;&lt;br /&gt;&lt;br /&gt;namespace ccglib&lt;br /&gt;{&lt;br /&gt;    public class DeepCopy&amp;lt;T&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        // create a new graph with new instances of all objects&lt;br /&gt;        public static T Copy(T graph)&lt;br /&gt;        {&lt;br /&gt;            T newgraph;&lt;br /&gt;            MemoryStream ms = new MemoryStream();&lt;br /&gt;            BinaryFormatter formatter = new BinaryFormatter();&lt;br /&gt;            formatter.Serialize(ms,graph);&lt;br /&gt;            ms.Seek(0, SeekOrigin.Begin);&lt;br /&gt;            newgraph = (T)formatter.Deserialize(ms);&lt;br /&gt;            ms.Dispose();&lt;br /&gt;            return newgraph;            &lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;using NUnit.Framework;&lt;br /&gt;using ccglib;&lt;br /&gt;&lt;br /&gt;namespace ccglibtests&lt;br /&gt;{&lt;br /&gt;    [Serializable]&lt;br /&gt;    public class class1&lt;br /&gt;    {&lt;br /&gt;        public int x;&lt;br /&gt;        public int y;&lt;br /&gt;        public class2 z;         &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Serializable]&lt;br /&gt;    public class class2&lt;br /&gt;    {&lt;br /&gt;        public int a;&lt;br /&gt;        public int b;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [TestFixture]&lt;br /&gt;    public class deepcopytest&lt;br /&gt;    {&lt;br /&gt;        [Test]&lt;br /&gt;        public void aliastest()&lt;br /&gt;        {&lt;br /&gt;        class1 obj1 = new class1();&lt;br /&gt;        class2 obj2 = new class2();&lt;br /&gt;        class1 alias;&lt;br /&gt;        class1 deepcopy;&lt;br /&gt;&lt;br /&gt;            // create a simple object graph&lt;br /&gt;        obj1.x = 1;&lt;br /&gt;        obj1.y = 2;&lt;br /&gt;        obj2.a = 3;&lt;br /&gt;        obj2.b = 4;&lt;br /&gt;        obj1.z = obj2;&lt;br /&gt;&lt;br /&gt;        alias = obj1;&lt;br /&gt;        deepcopy = DeepCopy&lt;class1&gt;.Copy(obj1);&lt;br /&gt;&lt;br /&gt;        alias.x = 10;&lt;br /&gt;        deepcopy.x = 100;&lt;br /&gt;        Assert.AreEqual(alias.x, obj1.x);&lt;br /&gt;        Assert.AreNotEqual(deepcopy.x, obj1.x);&lt;br /&gt;&lt;br /&gt;        alias.z.a = 40;&lt;br /&gt;        alias.z.a = 400;&lt;br /&gt;        deepcopy.z.a = 4000;&lt;br /&gt;&lt;br /&gt;        Assert.AreEqual(alias.z.a, obj1.z.a);&lt;br /&gt;        Assert.AreNotEqual(deepcopy.z.a, obj1.z.a);&lt;br /&gt;        }        &lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Not to state the obvious, but all involved classes need to be serializable...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-5980384128266595514?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/5980384128266595514/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=5980384128266595514' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/5980384128266595514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/5980384128266595514'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2009/01/avoiding-object-aliasing.html' title='Avoiding object aliasing....'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-6296496518591942683</id><published>2009-01-14T03:59:00.013-06:00</published><updated>2009-01-14T06:14:11.178-06:00</updated><title type='text'>Abstraction...</title><content type='html'>One of the important basic principles of computer science is abstraction.  Following is the text book definition....&lt;br /&gt;&lt;br /&gt;&lt;i&gt;abstraction is a mechanism and practice to reduce and factor out details so that one can focus on a few concepts at a time.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Back in my college days, we studied this intently.  The languages available at the time didn't support the concept as well as the languages do today.  But we did the best we could using the languages that we had available.&lt;br /&gt;&lt;br /&gt;One of my favorite courses was data structures, in that class we studied different ways to store data to achieve different goals.  We studied, linked lists, stacks, queues and the like.  We were given the opportunity to develop our own data structures based on the problem we were given.&lt;br /&gt;&lt;br /&gt;The primary teaching language for teaching computer science at that time was Pascal, but we were exposed to many different languages.  In my last semester, the teacher was pushing a class in the Ada language (a huge language developed by the DoD), on a whim I also took  a class in an emerging language called C.&lt;br /&gt;&lt;br /&gt;Although I've never heard of a job requesting experience in the Ada language, I'm grateful for the class.  The Ada language was the first object oriented language we studied (this was 1986) and allowed advanced concepts like like operator overloading and generics.  The Ada compilers were in beta testing at that time so actually developing a program in Ada was difficult, but the concepts were crucial.&lt;br /&gt;&lt;br /&gt;Today, C# provides a lot of the same features that we studied back then, so I've taken a little bit of time to dig into generics.  Generics are the ultimate level of abstraction because the algorithm is completely divorced from the data type.  If you look at the concept of the simple List&lt;T&gt; in System.Collections.Generic, you see what I mean.  Even if you create your own class, you can easily create a type safe collection of them.  If your class can be compared, the collection will even sort them for you.  Very powerful if you ask me.&lt;br /&gt;&lt;br /&gt;But simple collections are not the only application of generics, any data structure that you may want create can be created such that the data structure and its associated operations are completely divorced from the class that is stored in it.&lt;br /&gt;&lt;br /&gt;I'm sure there are thousands of implementations of the mathematical concept of sets out there, but this was one of the first generic data structure that I decided to implement.  Below is the code, the namespace is a reference to my roots in the Pascal language...&lt;br /&gt;&lt;br /&gt;For definition of some of the basic mathematical concepts check out &lt;a href=http://en.wikipedia.org/wiki/Set_theory#Basic_concepts&gt;Set theory basic concepts&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name=code class=c#&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;&lt;br /&gt;namespace ccg.paslib&lt;br /&gt;{&lt;br /&gt;    public class Set&amp;lt;T&amp;gt; &lt;br /&gt;    {&lt;br /&gt;        List&amp;lt;T&amp;gt; _internallist = new List&amp;lt;T&amp;gt;();&lt;br /&gt;&lt;br /&gt;        &lt;br /&gt;        // add a member                &lt;br /&gt;        public void Add(T parm)&lt;br /&gt;        {&lt;br /&gt;            _internallist.Add(parm);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        // remove a member&lt;br /&gt;        public void Remove(T parm)&lt;br /&gt;        {&lt;br /&gt;            _internallist.Remove(parm);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;&lt;br /&gt;        // is the supplied value a member of this set?&lt;br /&gt;        public bool Contains(T parm)&lt;br /&gt;        {&lt;br /&gt;            return _internallist.Contains(parm);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // returns the Union of two sets&lt;br /&gt;        public Set&amp;lt;T&amp;gt; Union(Set&amp;lt;T&amp;gt; parm)&lt;br /&gt;        {&lt;br /&gt;            Set&amp;lt;T&amp;gt; retval = new Set&amp;lt;T&amp;gt;();&lt;br /&gt;            foreach (T val in _internallist)&lt;br /&gt;                retval.Add(val);&lt;br /&gt;            foreach (T val in parm)&lt;br /&gt;                if (!retval.Contains(val))&lt;br /&gt;                    retval.Add(val);&lt;br /&gt;            return retval;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        // returns the intersection of two sets&lt;br /&gt;        public Set&amp;lt;T&amp;gt; Intersection(Set&amp;lt;T&amp;gt; parm)&lt;br /&gt;        {&lt;br /&gt;            Set&amp;lt;T&amp;gt; retval = new Set&amp;lt;T&amp;gt;();&lt;br /&gt;            foreach (T val in _internallist)&lt;br /&gt;                if (parm.Contains(val))&lt;br /&gt;                    retval.Add(val);&lt;br /&gt;            return retval;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        // returns the difference between two sets&lt;br /&gt;        public Set&amp;lt;T&amp;gt; Difference(Set&amp;lt;T&amp;gt; parm)&lt;br /&gt;        {&lt;br /&gt;            Set&amp;lt;T&amp;gt; retval = new Set&amp;lt;T&amp;gt;();&lt;br /&gt;            foreach (T val in _internallist)&lt;br /&gt;                if (!parm.Contains(val))&lt;br /&gt;                    retval.Add(val);&lt;br /&gt;            return retval;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // return members that are in one set but not both&lt;br /&gt;        public Set&amp;lt;T&amp;gt; ExclusiveOr(Set&amp;lt;T&amp;gt; parm)&lt;br /&gt;        {&lt;br /&gt;            Set&amp;lt;T&amp;gt; retval = new Set&amp;lt;T&amp;gt;();&lt;br /&gt;            foreach (T s in this)&lt;br /&gt;                if (!parm.Contains(s))&lt;br /&gt;                    retval += s;&lt;br /&gt;            foreach (T s in parm)&lt;br /&gt;                if (!this.Contains(s))&lt;br /&gt;                    retval += s;&lt;br /&gt;            return retval;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        // return an enumerator for the set&lt;br /&gt;        public List&amp;lt;T&amp;gt;.Enumerator GetEnumerator()&lt;br /&gt;        {&lt;br /&gt;            return _internallist.GetEnumerator();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        // return the number of members in the set&lt;br /&gt;        public int Count&lt;br /&gt;        {&lt;br /&gt;            get { return _internallist.Count; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        #region operators&lt;br /&gt;        public static Set&amp;lt;T&amp;gt; operator +(Set&amp;lt;T&amp;gt; set, T value)&lt;br /&gt;        {            &lt;br /&gt;             set.Add(value);&lt;br /&gt;             return set;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static Set&amp;lt;T&amp;gt; operator +(Set&amp;lt;T&amp;gt; set1, Set&amp;lt;T&amp;gt; set2)&lt;br /&gt;        {&lt;br /&gt;            return set1.Union(set2);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static Set&amp;lt;T&amp;gt; operator -(Set&amp;lt;T&amp;gt; set1, Set&amp;lt;T&amp;gt; set2)&lt;br /&gt;        {&lt;br /&gt;            return set1.Difference(set2);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static Set&amp;lt;T&amp;gt; operator *(Set&amp;lt;T&amp;gt; set1, Set&amp;lt;T&amp;gt; set2)&lt;br /&gt;        {&lt;br /&gt;            return set1.Intersection(set2);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public static Set&amp;lt;T&amp;gt; operator ^(Set&amp;lt;T&amp;gt; set1, Set&amp;lt;T&amp;gt; set2)&lt;br /&gt;        {&lt;br /&gt;            return set1.ExclusiveOr(set2);&lt;br /&gt;        }&lt;br /&gt;        #endregion&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;&lt;br /&gt;    // generic class to create an ordered pair of objects for the Catesian Product&lt;br /&gt;    public class OrderedPair&amp;lt;T, S&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        public T A;&lt;br /&gt;        public S B;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    // Generic static class to implement the catesian product&lt;br /&gt;    public class CartesianProduct&amp;lt;T,S&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        public static Set&amp;lt;OrderedPair&amp;lt;T,S&amp;gt;&amp;gt; Product(Set&amp;lt;T&amp;gt; a,Set&amp;lt;S&amp;gt; b)&lt;br /&gt;        {&lt;br /&gt;            Set&amp;lt;OrderedPair&amp;lt;T,S&amp;gt;&amp;gt; retval = new Set&amp;lt;OrderedPair&amp;lt;T,S&amp;gt;&amp;gt;();&lt;br /&gt;            foreach(T i in a)&lt;br /&gt;                foreach(S j in b)&lt;br /&gt;                {&lt;br /&gt;                    OrderedPair&amp;lt;T,S&amp;gt; value = new OrderedPair&amp;lt;T,S&amp;gt;();&lt;br /&gt;                    value.A = i;&lt;br /&gt;                    value.B = j;&lt;br /&gt;                    retval.Add(value);&lt;br /&gt;                }&lt;br /&gt;            return retval;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;   &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So, how can this be used?  Does the mathematical concept of a set have anything to do with software development?  Absolutely....at its core, a relational database is based on set theory.  Below are some of the NUnit tests that I wrote for testing this class.&lt;br /&gt;&lt;br /&gt;&lt;pre name=code class=c#&gt;&lt;br /&gt;        [Test]&lt;br /&gt;        public void uniontest()&lt;br /&gt;        {&lt;br /&gt;            Set&amp;ltColor&amp;gt set1 = new Set&amp;lt;Color&amp;gt;();&lt;br /&gt;            Set&amp;lt;Color&amp;gt; set2 = new Set&amp;lt;Color&amp;gt;();&lt;br /&gt;&lt;br /&gt;            set1.Add(Color.Red);&lt;br /&gt;            set1.Add(Color.Blue);&lt;br /&gt;            set2.Add(Color.Green);&lt;br /&gt;            set2.Add(Color.White);&lt;br /&gt;&lt;br /&gt;            Set&lt;Color&gt; set3 = set1.Union(set2);&lt;br /&gt;            Assert.AreEqual(set3.Count, 4);&lt;br /&gt;            foreach (Color val in set3)&lt;br /&gt;                Assert.IsTrue(set1.Contains(val) || set2.Contains(val));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [Test]&lt;br /&gt;        public void intersectiontest()&lt;br /&gt;        {&lt;br /&gt;            Set&amp;lt;Color&amp;gt; set1 = new Set&amp;lt;Color&amp;gt;();&lt;br /&gt;            Set&amp;lt;Color&amp;gt; set2 = new Set&amp;lt;Color&amp;gt;();&lt;br /&gt;&lt;br /&gt;            set1.Add(Color.Red);&lt;br /&gt;            set1.Add(Color.Blue);&lt;br /&gt;            set2.Add(Color.Blue);&lt;br /&gt;            set2.Add(Color.Green);&lt;br /&gt;            set2.Add(Color.White);&lt;br /&gt;&lt;br /&gt;            Set&amp;lt;Color&amp;gt; set3 = set1.Intersection(set2);&lt;br /&gt;            Assert.IsTrue(set3.Count == 1);&lt;br /&gt;            foreach (Color val in set3)&lt;br /&gt;                Assert.IsTrue(val.Equals(Color.Blue));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [Test]&lt;br /&gt;        // test some of the operators&lt;br /&gt;        public void exclusiveortest()&lt;br /&gt;        {&lt;br /&gt;            Set&amp;lt;Color&amp;gt; set1 = new Set&amp;lt;Color&amp;gt;();&lt;br /&gt;            Set&amp;lt;Color&amp;gt; set2 = new Set&amp;lt;Color&amp;gt;();&lt;br /&gt;&lt;br /&gt;            set1 += Color.Red;&lt;br /&gt;            set1 += Color.Blue;&lt;br /&gt;            set2 += Color.Blue;&lt;br /&gt;            set2 += Color.Green;&lt;br /&gt;            set2 += Color.White;&lt;br /&gt;&lt;br /&gt;            Set&amp;lt;Color&amp;gt; set3 = set1 ^ set2;&lt;br /&gt;            Assert.IsTrue(set3.Count == 3);&lt;br /&gt;            Assert.IsTrue(set3.Contains(Color.Red));&lt;br /&gt;            Assert.IsTrue(set3.Contains(Color.Green));&lt;br /&gt;            Assert.IsTrue(set3.Contains(Color.White));&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The OrderedPair&amp;lt;T, S&amp;gt; and CartesianProduct&amp;lt;T,S&amp;gt; classes are pretty interesting.  Below is a test that I wrote for that class.&lt;br /&gt;&lt;br /&gt;&lt;pre name=code class=c#&gt;&lt;br /&gt;        [Test]&lt;br /&gt;        public void caresianproducttest()&lt;br /&gt;        {&lt;br /&gt;            Set&amp;lt;DateTime&amp;gt; set1 = new Set&amp;lt;DateTime&amp;gt;();&lt;br /&gt;            for (int i = 0; i &lt; 10; i++)&lt;br /&gt;                set1.Add(new DateTime(2009, 1, 1).AddDays(i));&lt;br /&gt;&lt;br /&gt;            Set&amp;lt;Color&amp;gt; set2 = new Set&amp;lt;Color&amp;gt;();&lt;br /&gt;            set2.Add(Color.Blue);&lt;br /&gt;            set2.Add(Color.Red);&lt;br /&gt;            set2.Add(Color.Green);&lt;br /&gt;&lt;br /&gt;            Set&amp;lt;OrderedPair&amp;lt;DateTime, Color&amp;gt;&amp;gt; set3 = CartesianProduct&amp;lt;DateTime, Color&amp;gt;.Product(set1, set2);&lt;br /&gt;&lt;br /&gt;            Assert.AreEqual(set3.Count, set1.Count * set2.Count);&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So, now what?  Just like the List&amp;lt;T&amp;gt; generics, the Set&amp;lt;T&amp;gt; generic can be used with custom written classes.  There is a caution here though.  The default implementation of the Equals() method tests that the reference of two objects are equal.  In other words, if you have two instances of a class that contain the same data, the default implementation of Equals() will return false because they are different instances.  For the Set&amp;lt;T&amp;gt; generic to work as expected on custom classes, you must override the default implementation of Equals.  Below is an example...&lt;br /&gt;&lt;br /&gt;&lt;pre name=code class=c#&gt;&lt;br /&gt;      public class Customer&lt;br /&gt;        {&lt;br /&gt;            // public member variable violate the concept of abstraction, &lt;br /&gt;            // but this is just a test, not production code&lt;br /&gt;            public int ID;&lt;br /&gt;            public string Name;&lt;br /&gt;&lt;br /&gt;            public Customer(int id, string name)&lt;br /&gt;            {&lt;br /&gt;                ID = id;&lt;br /&gt;                Name = name;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            public override bool Equals(object obj)&lt;br /&gt;            {&lt;br /&gt;                Customer objvalue = (Customer)obj;&lt;br /&gt;                return this.ID == objvalue.ID;&lt;br /&gt;            }&lt;br /&gt;                       &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        [Test]&lt;br /&gt;        public void CustomObjectTest()&lt;br /&gt;        {&lt;br /&gt;            Set&amp;lt;Customer&amp;gt; set1 = new Set&amp;lt;Customer&amp;gt;();&lt;br /&gt;            set1 += new Customer(1, "customer 1");&lt;br /&gt;            set1 += new Customer(2, "customer 2");&lt;br /&gt;            set1 += new Customer(3, "customer 3");&lt;br /&gt;&lt;br /&gt;            Set&amp;lt;Customer&amp;gt; set2 = new Set&amp;lt;Customer&amp;gt;();&lt;br /&gt;            set2 += new Customer(2, "customer 2");&lt;br /&gt;&lt;br /&gt;            // without overriding Equals() set3 contains all three members&lt;br /&gt;            Set&amp;lt;Customer&amp;gt; set3 = set1 - set2;&lt;br /&gt;            Assert.AreEqual(set3.Count, 2);&lt;br /&gt;            Assert.IsTrue(set3.Contains(new Customer(1,"customer 1")));&lt;br /&gt;            Assert.IsTrue(set3.Contains(new Customer(3,"customer 3")));            &lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Combining custom objects with the concepts of Set Theory, allows some sophisticated operations to be performed using simple mathematical operators.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-6296496518591942683?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/6296496518591942683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=6296496518591942683' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/6296496518591942683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/6296496518591942683'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2009/01/abstraction.html' title='Abstraction...'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-6335122482977320775</id><published>2009-01-13T13:48:00.004-06:00</published><updated>2009-01-13T14:43:58.842-06:00</updated><title type='text'>Geeks gone wild....</title><content type='html'>I have a friend named David Hinson who moved from the Nashville area to Florida some time last year.  David and I worked together back when processor speeds were measured in mHz.&lt;br /&gt;&lt;br /&gt;Anyway, Dave is seriously into developing applications for the iPhone and seemed to be searching for ideas for new applications.  I ran an idea by him that I had thought of for years before never found a reasonable platform for developing it.&lt;br /&gt;&lt;br /&gt;I sent Dave some code and he ran with it....this may be coming to iPhone app store soon. &lt;br /&gt;&lt;br /&gt;If there were more than 6 people on the planet that would use something like this, we'd be rich.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.youtube.com/watch?v=m4XRsa5wtN8"&gt;Interpolate Demo&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/m4XRsa5wtN8&amp;hl=en&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/m4XRsa5wtN8&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-6335122482977320775?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/6335122482977320775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=6335122482977320775' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/6335122482977320775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/6335122482977320775'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2009/01/geeks-gone-wild.html' title='Geeks gone wild....'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-5796366093081391835</id><published>2009-01-08T23:01:00.004-06:00</published><updated>2009-01-08T23:08:14.722-06:00</updated><title type='text'>New Resume....</title><content type='html'>This week, I spent a significant amount of time reformatting my resume.  The previous format was confusing to some because the projects that I have completed were separated from the places I had worked.  I did this in an effort to keep the resume short.  This version provides a lot more detail and shows the projects that I have done in chronological order.&lt;br /&gt;&lt;br /&gt;I am currently seeking new opportunities, if you are currently beginning new projects, or have any needs in the area of technology, I would appreciate your consideration.&lt;br /&gt;&lt;br /&gt;Donnie&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-5796366093081391835?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/5796366093081391835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=5796366093081391835' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/5796366093081391835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/5796366093081391835'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2009/01/new-resume.html' title='New Resume....'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-5328013985772528628</id><published>2009-01-04T21:24:00.013-06:00</published><updated>2009-01-05T10:08:18.836-06:00</updated><title type='text'>A Time For Reflection (Factory Pattern in Action part 3)</title><content type='html'>For a preview of the application being discussed here please visit &lt;a href=http://www.cedarcitygroup.com/digitaldarkroom/uncolormyworld.aspx&gt;this page&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The preceding portions of this series can be found &lt;a href=http://www.cedarcityblog.com/2008/12/factory-pattern-in-action.html&gt;here&lt;/a&gt; and &lt;a href=http://www.cedarcityblog.com/2008/12/uncolor-my-world-factory-pattern-in.html&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Setting properties on Factory Generated Objects&lt;/b&gt;&lt;br /&gt;The grayscale and sepia objects were unique in that they do not require any parameters to operate.  They know what they are supposed to do and can do it with no input provided by the controlling object.  But, it should be obvious that to be useful, some objects will need to have some input provided.  If the a factory returns only a base type, how can you set a property on a returned object without breaking the barrier of anonymity that the factory pattern provides?&lt;br /&gt;&lt;br /&gt;Interfaces provide a possible solution, and possibly a better solution from a type safety perspective.  However, in the interest of making the coupling as loose as possible, I have chosen to use reflection as the means of communicating with the object returned from the factory pattern.&lt;br /&gt;&lt;br /&gt;For this portion, I selected to use a couple of filters that modify the colors in bitmap. The first filter can lighten or darken a photo using a &lt;a href=http://en.wikipedia.org/wiki/Gamma_correction&gt;gamma correction&lt;/a&gt;.  The gamma value must be greater than 0. A gamma value of 1.0 leaves the image unchanged, values less than 1 lighten the images, values greater than 1.0 darken the image.  Following is the code for my LightenDarken filter.&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections;&lt;br /&gt;using System.Runtime.Serialization;&lt;br /&gt;using System.Drawing.Imaging;&lt;br /&gt;using System.Drawing;&lt;br /&gt;&lt;br /&gt;namespace ccg.imaging&lt;br /&gt;{&lt;br /&gt; /// &lt;summary&gt;&lt;br /&gt; /// Performs a gamma correction on the processed image&lt;br /&gt; /// &lt;/summary&gt;&lt;br /&gt; /// &lt;br /&gt; [Serializable]&lt;br /&gt; [NameAttribute("Ligthens or Darkens an image")]&lt;br /&gt; [DescriptionAttribute("Adjusts the brightness of the entire image.")]&lt;br /&gt; public class LightenDarken: ImageProcessBase&lt;br /&gt; {&lt;br /&gt;  public LightenDarken()&lt;br /&gt;  {&lt;br /&gt;   &lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;        public LightenDarken(float gamma)&lt;br /&gt;        {&lt;br /&gt;            _gamma = gamma;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        float _gamma = 1.0f;&lt;br /&gt;&lt;br /&gt;        public float Gamma&lt;br /&gt;        {&lt;br /&gt;            set { _gamma = value; }&lt;br /&gt;            get { return _gamma; }&lt;br /&gt;        }&lt;br /&gt;   &lt;br /&gt;  protected override System.Drawing.Bitmap ProcessSafe(System.Drawing.Bitmap bitmapin)&lt;br /&gt;  {               &lt;br /&gt;   System.Drawing.Bitmap outmap = new System.Drawing.Bitmap(bitmapin.Width,bitmapin.Height);&lt;br /&gt;   Graphics g = Graphics.FromImage(outmap);&lt;br /&gt;            ImageAttributes ia = new ImageAttributes();&lt;br /&gt;            ia.SetGamma(_gamma);&lt;br /&gt;            g.DrawImage(bitmapin,new Rectangle(0,0,outmap.Width, outmap.Height),0,0,&lt;br /&gt;                        bitmapin.Width,bitmapin.Height,GraphicsUnit.Pixel,ia);&lt;br /&gt;   g.Dispose();&lt;br /&gt;   &lt;br /&gt;   return outmap;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The class allows the gamma value to be set in the constructor, but also allows it to be set as a property.  Since the factory returns an ImageProcessBase type, the Gamma property is not available directly.  The property could be set directly, but to do that, the controlling code would need to know the name of the class returned by the factory.  In my opinion, this forces the controlling code to know too much about the underlying implementation of the filter.  The most loosely couple approach is to set the property using reflection.  The controlling code can retrieve the Type information from the class and use that to set the property using reflection.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="c#"&gt;&lt;br /&gt;    ImageProcessBase proc = filterfactory.ActivateFilter("lightendarken");&lt;br /&gt;    Type t = proc.GetType();&lt;br /&gt;    object[] parms = { gamma };   // gamma declared and initialized earlier&lt;br /&gt;    t.InvokeMember("Gamma", System.Reflection.BindingFlags.SetProperty,&lt;br /&gt;                   null, proc, parms);&lt;br /&gt;    output = proc.Process(output);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This approach has its downfalls, the main one being that if the property name is changed on the LightenDarken class, then the problem will show up at run time instead of compile time.  However, this approach requires the least amount of information to be known be the controlling code.  Casting or using interfaces requires the controlling code to know the name of the class or interface and the name of the property.  Using reflection requires only the name of the property to be known.  Since loose coupling is my primary design goal, this is the approach I selected.&lt;br /&gt;&lt;br /&gt;The second filter uses the ColorMap property of the ImageAttributes class in the .NET framework to modify the colors in the bitmap. The ColorMap property of the ImageAttribute class allows you to specify a 'from' color and a 'to' color. When the bitmap is regenerated in the DrawImage call, this color mapping is used. My original intentions was to use it to reduce the number of shades of grey in an image my mapping multiple 'from' colors to the same 'to' color.  However, I found it to be much more useful than just that.  By supplying different ColorMaps, this filter can achieve some pretty cool effects.  To make this simpler, I created an abstract class called ColorMapper.  The only abstract method is the protected initializecolormap method.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Collections;&lt;br /&gt;using System.Drawing.Imaging;&lt;br /&gt;&lt;br /&gt;namespace ccg.imaging&lt;br /&gt;{&lt;br /&gt; /// &lt;summary&gt;&lt;br /&gt; /// This is an abstract class to allow the creation of multiple colormapping &lt;br /&gt;        /// classes&lt;br /&gt; /// &lt;/summary&gt;&lt;br /&gt; /// &lt;br /&gt; [NameAttribute("ColorMapper")]&lt;br /&gt; [DescriptionAttribute("Maps Colors within a bitmap to different colors")]&lt;br /&gt; [Serializable]&lt;br /&gt; public abstract class ColorMapper: ImageProcessBase&lt;br /&gt; {&lt;br /&gt;  &lt;br /&gt;        #region Constructors&lt;br /&gt;        public ColorMapper()&lt;br /&gt;        {&lt;br /&gt;        }&lt;br /&gt;  &lt;br /&gt;        #endregion&lt;br /&gt;       &lt;br /&gt;        //--- create the color mapping&lt;br /&gt;        protected abstract ColorMap[] initializecolormap(Bitmap bitmapin);  &lt;br /&gt;&lt;br /&gt;        /// &lt;summary&gt;&lt;br /&gt;        /// process the incoming image to map colors to different colors&lt;br /&gt;        /// &lt;/summary&gt;        &lt;br /&gt; protected override System.Drawing.Bitmap ProcessSafe(System.Drawing.Bitmap&lt;br /&gt;                                                             bitmapin)&lt;br /&gt; {   &lt;br /&gt;            ImageAttributes ia = new ImageAttributes();&lt;br /&gt;            ia.SetRemapTable(initializecolormap(bitmapin));&lt;br /&gt;            Bitmap outimg = new Bitmap(bitmapin.Width,bitmapin.Height);&lt;br /&gt;            Graphics g = Graphics.FromImage(outimg);&lt;br /&gt;            g.DrawImage(bitmapin, new Rectangle(0, 0, outimg.Width, &lt;br /&gt;                        outimg.Height), 0, 0, bitmapin.Width, bitmapin.Height, &lt;br /&gt;                        GraphicsUnit.Pixel, ia);&lt;br /&gt;            g.Dispose();&lt;br /&gt;            return outimg;&lt;br /&gt; }    &lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;With this base class, we can easily produce a couple of color mapping effects.  ShadeReducer maps multiple 'from' colors to the same 'to' color to reduce the number of shades in a grayscale bitmap.  ColorShift uses the specified BaseColor as the color to shade rather than Black. &lt;br /&gt;&lt;br /&gt;&lt;pre name='code' class='c#'&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Collections;&lt;br /&gt;using System.Drawing.Imaging;&lt;br /&gt;&lt;br /&gt;namespace ccg.imaging&lt;br /&gt;{&lt;br /&gt;   /// &lt;summary&gt;&lt;br /&gt;   /// Summary description for ShadeReducer&lt;br /&gt;   /// &lt;/summary&gt;&lt;br /&gt;   /// &lt;br /&gt;  [NameAttribute("Shade Reducer")]&lt;br /&gt;  [DescriptionAttribute("Reduces the image to the specified number of shades")]&lt;br /&gt;  [Serializable]&lt;br /&gt;  public class ShadeReducer: ColorMapper&lt;br /&gt;    {&lt;br /&gt; //--- default number of shades of no value is provided&lt;br /&gt; int _numberofshades = 255;&lt;br /&gt;&lt;br /&gt;        #region Constructors&lt;br /&gt;        public ShadeReducer()&lt;br /&gt;        {&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt; public ShadeReducer(int numberofshades)&lt;br /&gt; {&lt;br /&gt;   _numberofshades = numberofshades;&lt;br /&gt;        }&lt;br /&gt;        #endregion&lt;br /&gt;&lt;br /&gt;        /// &lt;summary&gt;&lt;br /&gt;        /// Property to set the number of shades to use&lt;br /&gt;        /// &lt;/summary&gt;&lt;br /&gt;        public int NumberOfShades&lt;br /&gt;        {&lt;br /&gt;            get { return this._numberofshades; }&lt;br /&gt;            set { this._numberofshades = value; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        //--- create the color mapping&lt;br /&gt;        protected override ColorMap[] initializecolormap(Bitmap bitmapin)&lt;br /&gt;   {            &lt;br /&gt;            ColorMap[] cmarray = new ColorMap[255];&lt;br /&gt;            int newvalue;&lt;br /&gt;            int shadeincrement = (255 / _numberofshades);&lt;br /&gt;            for (int i = 254; i &gt;= 0; i--)&lt;br /&gt;              {&lt;br /&gt;              ColorMap cm = new ColorMap();&lt;br /&gt;              cm.OldColor = Color.FromArgb(i, i, i);&lt;br /&gt;              newvalue = 255-(shadeincrement * ((254-i) / shadeincrement));&lt;br /&gt;              cm.NewColor = Color.FromArgb(newvalue, newvalue, newvalue);&lt;br /&gt;              cmarray[i] = cm;                 &lt;br /&gt;              }&lt;br /&gt;            return cmarray;            &lt;br /&gt;          }         &lt;br /&gt;     }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name='code' class='c#'&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Collections;&lt;br /&gt;using System.Drawing.Imaging;&lt;br /&gt;&lt;br /&gt;namespace ccg.imaging&lt;br /&gt;{&lt;br /&gt; /// &lt;summary&gt;&lt;br /&gt; /// Summary description for ShadeReducer&lt;br /&gt; /// &lt;/summary&gt;&lt;br /&gt; /// &lt;br /&gt; [NameAttribute("Color Shifter")]&lt;br /&gt; [DescriptionAttribute("Converts a grayscale bitmap to shades of the specified Base Color")]&lt;br /&gt; [Serializable]&lt;br /&gt; public class ColorShifter: ColorMapper&lt;br /&gt; {  &lt;br /&gt;        Color _basecolor = Color.FromArgb(0x000000);&lt;br /&gt;&lt;br /&gt;        #region Constructors&lt;br /&gt;        public ColorShifter()&lt;br /&gt;        {&lt;br /&gt;        }  &lt;br /&gt;        #endregion&lt;br /&gt;&lt;br /&gt;        public Color BaseColor&lt;br /&gt;        {&lt;br /&gt;            get { return _basecolor; }&lt;br /&gt;            set { _basecolor = value; }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /// &lt;summary&gt;&lt;br /&gt;        /// This method produces as many shades of the basecolor as possible&lt;br /&gt;        /// The BaseColor will be the darkest color in the bitmap.&lt;br /&gt;        /// The method will produce as many shades as possible of the color&lt;br /&gt;        /// without changing it&lt;br /&gt;        /// &lt;/summary&gt;        &lt;br /&gt;        private Color GetColorShade(Color colortoshade, int shadevalue)&lt;br /&gt;        {&lt;br /&gt;            int redvalue = colortoshade.R + shadevalue;&lt;br /&gt;            int greenvalue =  colortoshade.G + shadevalue;&lt;br /&gt;            int bluevalue =  colortoshade.B + shadevalue;&lt;br /&gt;&lt;br /&gt;            if (redvalue &gt; 255)&lt;br /&gt;            {&lt;br /&gt;                greenvalue -= redvalue - 255;&lt;br /&gt;                bluevalue -= redvalue - 255;&lt;br /&gt;                redvalue = 255;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (greenvalue &gt; 255)&lt;br /&gt;            {&lt;br /&gt;                bluevalue -= greenvalue - 255;&lt;br /&gt;                redvalue -= greenvalue - 255;&lt;br /&gt;                greenvalue = 255;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (bluevalue &gt; 255)&lt;br /&gt;            {&lt;br /&gt;                redvalue -= bluevalue - 255;&lt;br /&gt;                greenvalue -= bluevalue - 255;&lt;br /&gt;                bluevalue = 255;&lt;br /&gt;            }&lt;br /&gt;            return Color.FromArgb(redvalue, greenvalue, bluevalue);            &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        //--- create the color mapping&lt;br /&gt;        protected override ColorMap[] initializecolormap(Bitmap bitmapin)&lt;br /&gt;          {            &lt;br /&gt;            ColorMap[] cmarray = new ColorMap[255];&lt;br /&gt;            int newvalue;&lt;br /&gt;            int shadeincrement = (255 / _numberofshades);&lt;br /&gt;            for (int i = 0; i &lt; 255; i++)&lt;br /&gt;            {&lt;br /&gt;                ColorMap cm = new ColorMap();&lt;br /&gt;                cm.OldColor = Color.FromArgb(i, i, i);&lt;br /&gt;                cm.NewColor = GetColorShade(_basecolor, i);&lt;br /&gt;                cmarray[i] = cm;                 &lt;br /&gt;            }&lt;br /&gt;            return cmarray;            &lt;br /&gt;          }         &lt;br /&gt;     }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The controlling code can use reflection to set the NumberOfShades and BaseColor properties as needed.&lt;br /&gt;&lt;br /&gt;The example of these filters in action is available at &lt;a href=http://www.cedarcitygroup.com/digitaldarkroom/uncolormyworld.aspx&gt;http://www.cedarcitygroup.com/digitaldarkroom/uncolormyworld.aspx&lt;/a&gt;.  The .NET framework provides a tremendous amount of flexibility in processing images.  Breaking different operations down into filters allows them to be mixed and matched into a processing pipeline that can be applied to a large number of images easily.  &lt;br /&gt;&lt;br /&gt;I hope that this series has been beneficial.  Be on the lookout for an image processing utility for webmasters available here soon.&lt;br /&gt;&lt;br /&gt;I just got my hands on some numerical analysis code that I wrote 20 years ago in Pascal.  I'm dying to convert it to C#, there will be some posts about it soon as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-5328013985772528628?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/5328013985772528628/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=5328013985772528628' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/5328013985772528628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/5328013985772528628'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2009/01/time-for-reflection-factory-pattern-in.html' title='A Time For Reflection (Factory Pattern in Action part 3)'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-1404307523848454016</id><published>2009-01-01T09:33:00.002-06:00</published><updated>2009-01-01T09:39:10.951-06:00</updated><title type='text'>First attempt at flash training....</title><content type='html'>I put this flash movie together as a follow up to a post that I did on my &lt;a href=www.constanttransformation.blogspot.com&gt;personal blog&lt;/a&gt;.  Like a lot of computer guys, I'm a frustrated musician.  Flash is pretty cool because I can utilize my hobbies and profession into one medium.  I used audactity to record and process the audio, Flash CS3 to put it all together.  I learned a ton by doing it.  I need to figure out the synchronization of audio and animation thing though.  It's synchronized during development, but one seems to get ahead of the other after publishing.  I'm going to figure that out...Any comments or tips are appreciated...&lt;br /&gt;&lt;br /&gt;&lt;object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="400" height="290" id="NumberSystem" align="middle"&gt;&lt;br /&gt; &lt;param name="allowScriptAccess" value="sameDomain" /&gt;&lt;br /&gt; &lt;param name="allowFullScreen" value="false" /&gt;&lt;br /&gt; &lt;param name="movie" value="http://www.cedarcitygroup.com/flash/NumberSystem.swf" /&gt;&lt;param name="quality" value="high" /&gt;&lt;param name="bgcolor" value="#000000" /&gt; &lt;embed src="http://www.cedarcitygroup.com/flash/NumberSystem.swf" quality="high" bgcolor="#000000" width="400" height="290" name="NumberSystem" align="middle" allowScriptAccess="sameDomain" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" &gt;&lt;/embed&gt;&lt;br /&gt; &lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-1404307523848454016?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/1404307523848454016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=1404307523848454016' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/1404307523848454016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/1404307523848454016'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2009/01/first-attempt-at-flash-training.html' title='First attempt at flash training....'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-724045884569394881</id><published>2008-12-28T21:43:00.036-06:00</published><updated>2008-12-29T06:50:06.843-06:00</updated><title type='text'>Uncolor My World, The Factory Pattern In Action part 2</title><content type='html'>&lt;i&gt;For a preview of the result of this rather long post, please visit &lt;br /&gt;&lt;a href=http://www.cedarcitygroup.com/digitaldarkroom/uncolormyworld.aspx target=_blank&gt;http://www.cedarcitygroup.com/digitaldarkroom/uncolormyworld.aspx&lt;/a&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;In the days of film photography, black and white photos were considered of higher quality than color photos.  Many professional photographers, most notably Ansel Adams, would only shoot black and white photos. In the film days, color negatives could be used to make black and white prints by using black and white paper.  To achieve the highest quality prints, however, black and white negatives were used.&lt;br /&gt;&lt;br /&gt;But in the days of digital photography, how do you convert a color photograph to black and white?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;First attempt, Pixel by Pixel&lt;/b&gt;&lt;br /&gt;Just to review, each pixel in color jpeg bitmap is represented by four bytes, the color of the pixel is represented by three bytes, one byte for each of the colors (red, green and blue)  The fourth bytes is used to control the opacity of the pixel, commonly referred to as the alpha value.  Each byte contains a value from 0 to 255.  When the red, green and blue components are the same, the result is a shade of gray ranging from 0x000000 for black to 0xFFFFFF for white.  The task of converting a color bitmap to a grayscale bitmap involves using the values of the red, green and blue components of a pixel to compute a shade of gray to be used to accurately represent that color.  Based on some analysis that I don't completely understand, a formula to do this turns out to be:&lt;br /&gt;&lt;br /&gt;&lt;pre style=c# name=code&gt;shadeofgray = 0.212671f * red + 0.715160f * green + 0.072169f * blue;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;When I initially wrote this filter, I implemented it using  a brute force method of computing the grayscale value pixel by pixel.  This was the primary reason that I added the code to the ImageProcessBase class to allow unsafe code.  After doing some research, I found that the .NET framework provides a high speed method of achieving the same effect, using only managed code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Dust off your Linear Algebra textbook&lt;/b&gt;&lt;br /&gt;The System.Drawing namespace provides the ColorMatrix class that can be used to manipulate colors during the rendering of a bitmap.  You can find a pretty good explanation of the ColorMatrix class and the mathematics behind it &lt;a href=http://en.csharp-online.net/GDIplus_Graphics_Transformation%E2%80%94Color_Transformation_and_the_Color_Matrix target=_blank&gt;here&lt;/a&gt;.  For our purposes, I'll just show the code for my grayscale class.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br/&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections;&lt;br /&gt;using System.Runtime.Serialization;&lt;br /&gt;using System.Drawing.Imaging;&lt;br /&gt;using System.Drawing;&lt;br /&gt;&lt;br /&gt;namespace ccg.imaging&lt;br /&gt;{&lt;br /&gt; /// &lt;summary&gt;&lt;br /&gt; /// Converts a color image into a grayscale image&lt;br /&gt; /// &lt;/summary&gt;&lt;br /&gt; /// &lt;br /&gt; [Serializable]&lt;br /&gt; [NameAttribute("Convert To Grayscale")]&lt;br /&gt; [DescriptionAttribute("Converts the incoming image to a grayscale image.")]&lt;br /&gt; public class Grayscale: ImageProcessBase&lt;br /&gt; {&lt;br /&gt;  public Grayscale()&lt;br /&gt;  {&lt;br /&gt;   &lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  protected override System.Drawing.Bitmap ProcessSafe(System.Drawing.Bitmap bitmapin)&lt;br /&gt;  {&lt;br /&gt;               &lt;br /&gt;    ColorMatrix cm = new ColorMatrix();           &lt;br /&gt;&lt;br /&gt;    cm.Matrix00 = 0.212671f;&lt;br /&gt;    cm.Matrix01 = 0.212671f;&lt;br /&gt;    cm.Matrix02 = 0.212671f;&lt;br /&gt;    cm.Matrix10 = 0.715160f;&lt;br /&gt;    cm.Matrix11 = 0.715160f;&lt;br /&gt;    cm.Matrix12 = 0.715160f;&lt;br /&gt;    cm.Matrix20 = 0.072169f;&lt;br /&gt;    cm.Matrix21 = 0.072169f;&lt;br /&gt;    cm.Matrix22 = 0.072169f;&lt;br /&gt;&lt;br /&gt;    System.Drawing.Bitmap outmap = &lt;br /&gt;              new System.Drawing.Bitmap(bitmapin.Width,bitmapin.Height);&lt;br /&gt;    Graphics g = Graphics.FromImage(outmap);&lt;br /&gt;    ImageAttributes ia = new ImageAttributes();&lt;br /&gt;    ia.SetColorMatrix(cm);&lt;br /&gt;    g.DrawImage(bitmapin,new Rectangle(0,0,outmap.Width,&lt;br /&gt;              outmap.Height),0,0,bitmapin.Width,&lt;br /&gt;              bitmapin.Height,GraphicsUnit.Pixel,ia);&lt;br /&gt;    g.Dispose();&lt;br /&gt;   &lt;br /&gt;    return outmap;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What can Brown do for you?&lt;/b&gt;&lt;br /&gt;In the early days of photography, prints were toned with Sepia as a preservation technique.  The original black and white prints were soaked in a solution made from the Sepia officinalis cuttlefish that produced prints that were more resistant to breakdown over time.  The result was a brown tinted printed instead of gray.  The result was beautiful in many ways.  Today, many photos are converted to a Sepia tone to simulate this old fashioned beauty.  By changing the values in the ColorMatrix, the same code will generate a Sepia toned bitmap.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br/&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections;&lt;br /&gt;using System.Runtime.Serialization;&lt;br /&gt;using System.Drawing.Imaging;&lt;br /&gt;using System.Drawing;&lt;br /&gt;&lt;br /&gt;namespace ccg.imaging&lt;br /&gt;{&lt;br /&gt; /// &lt;summary&gt;&lt;br /&gt; /// Converts a color image into a sepia image&lt;br /&gt; /// &lt;/summary&gt;&lt;br /&gt; /// &lt;br /&gt; [Serializable]&lt;br /&gt; [NameAttribute("Convert To Sepia")]&lt;br /&gt; [DescriptionAttribute("Converts the incoming image to a sepia image.")]&lt;br /&gt; public class Sepia: ImageProcessBase&lt;br /&gt; {&lt;br /&gt;  public Sepia()&lt;br /&gt;  {&lt;br /&gt;   &lt;br /&gt;  }&lt;br /&gt;   &lt;br /&gt;  protected override System.Drawing.Bitmap ProcessSafe(System.Drawing.Bitmap bitmapin)&lt;br /&gt;  {   &lt;br /&gt;     ColorMatrix cm = new ColorMatrix();&lt;br /&gt;            &lt;br /&gt;     cm.Matrix00 = 0.393f;&lt;br /&gt;     cm.Matrix01 = 0.349f;&lt;br /&gt;     cm.Matrix02 = 0.272f;&lt;br /&gt;     cm.Matrix10 = 0.769f;&lt;br /&gt;     cm.Matrix11 = 0.686f;&lt;br /&gt;     cm.Matrix12 = 0.534f;&lt;br /&gt;     cm.Matrix20 = 0.189f;&lt;br /&gt;     cm.Matrix21 = 0.168f;&lt;br /&gt;     cm.Matrix22 = 0.131f;     &lt;br /&gt;&lt;br /&gt;     System.Drawing.Bitmap outmap = new  &lt;br /&gt;            System.Drawing.Bitmap(bitmapin.Width,bitmapin.Height);&lt;br /&gt;     Graphics g = Graphics.FromImage(outmap);&lt;br /&gt;     ImageAttributes ia = new ImageAttributes();&lt;br /&gt;     ia.SetColorMatrix(cm);&lt;br /&gt;     g.DrawImage(bitmapin,new Rectangle(0,0,outmap.Width,&lt;br /&gt;             outmap.Height),0,0,bitmapin.Width,bitmapin.Height,GraphicsUnit.Pixel,ia);&lt;br /&gt;     g.Dispose();&lt;br /&gt;   &lt;br /&gt;     return outmap;&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Keeping it loose&lt;/b&gt;&lt;br /&gt;Now that we have a couple of classes that actually manipulate images, it's time to take a look at the factory itself.  'Loose Coupling' is a term that you may hear a lot in development circles.  The basic idea is to reduce the amount of information shared between components of an application.  This allows changes to be made to one component without forcing changes or even recompilation of other components.  This is what the factory pattern is all about.&lt;br /&gt;&lt;br /&gt;In this application, I have elected to place all of the shared information in a separate dll called ccg.imaging.foundation.  This dll contains all of the base classes and the factory itself (for now).  A reference to this dll will need to be added to any application (winforms or webforms) that intends to use the ccg.imaging components.  Any dll projects that implement the abstract classes will also need to reference the foundation dll.  The important point here is that it is not necessary for the application to directly reference any other imaging dlls.  The factory class can use reflection to activate the processing components providing the ability to update the component dlls without recompiling the entire application.  I've created a FactoryBase class to provide some basic Factory services.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code" &gt;&lt;br/&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Reflection;&lt;br /&gt;&lt;br /&gt;namespace ccg.imaging&lt;br /&gt;{&lt;br /&gt;   &lt;br /&gt;    public class FilterFactoryBase&lt;br /&gt;    {&lt;br /&gt;        // a dictionary used to store object specifications&lt;br /&gt;        private Dictionary&amp;lt;string, string&amp;gt; _filters = null;&lt;br /&gt;&lt;br /&gt;        protected FilterFactoryBase()&lt;br /&gt;        {&lt;br /&gt;            _filters = new Dictionary&amp;lt;string,string&amp;gt;();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // a method provided so that the subclassed factory can provide an&lt;br /&gt;        // application dependent id for the class, the fully qualified name of &lt;br /&gt;        // the class and the path to the assembly that contains the class&lt;br /&gt;        protected void AddFilter(string id, string classname, string assemblypath)&lt;br /&gt;        {&lt;br /&gt;            // store the path and classname in the dictionary using a delimited string&lt;br /&gt;            _filters.Add(id, assemblypath + "|" + classname);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        // a method to activate a class identified by the application specified id&lt;br /&gt;        public ImageProcessBase ActivateFilter(string id)&lt;br /&gt;        {&lt;br /&gt;            ImageProcessBase objfilter = null;&lt;br /&gt;&lt;br /&gt;            // retrieve the specification from the dictionary&lt;br /&gt;            string classspec = _filters[id];&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                // if the classspec is found&lt;br /&gt;                if (!string.IsNullOrEmpty(classspec))&lt;br /&gt;                {&lt;br /&gt;                    // break the stored spec down into its components (see AddFilter() method)&lt;br /&gt;                    string[] typespec = classspec.Split('|');&lt;br /&gt;                    string assemblypath = typespec[0].Trim();&lt;br /&gt;                    string classname = typespec[1].Trim();&lt;br /&gt;                    &lt;br /&gt;                    // make sure the needed assembly is loaded&lt;br /&gt;                    Assembly remoteassembly = Assembly.LoadFrom(assemblypath);&lt;br /&gt;                    // retrieve the Type from the assembly&lt;br /&gt;                    Type remotetype = remoteassembly.GetType(classname);&lt;br /&gt;                    // create an instance of the class&lt;br /&gt;                    objfilter = (ImageProcessBase)Activator.CreateInstance(remotetype);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            catch &lt;br /&gt;            {&lt;br /&gt;                &lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            // will be null if the class is not found or cannot be activated&lt;br /&gt;            return objfilter;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now all the FilterFactory subclass needs to do is provide the application defined id, the class name and assembly path for each class that it wants to activate.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br/&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;&lt;br /&gt;namespace ccg.imaging&lt;br /&gt;{&lt;br /&gt; /// &lt;summary&gt;&lt;br /&gt; /// This Class provides a  means to find out what filters are available&lt;br /&gt; /// and what they do.&lt;br /&gt; /// &lt;/summary&gt;&lt;br /&gt; public class FilterFactory: FilterFactoryBase&lt;br /&gt; {  &lt;br /&gt;  public FilterFactory()&lt;br /&gt;  {&lt;br /&gt;     string dllpath = AppDomain.CurrentDomain.BaseDirectory +&lt;br /&gt;            "bin\\ccg.imaging.dll";&lt;br /&gt;     AddFilter("grayscale", "ccg.imaging.Grayscale", dllpath );&lt;br /&gt;     AddFilter("sepia", "ccg.imaging.Sepia", dllpath);  &lt;br /&gt;  } &lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Pulling it all together&lt;/b&gt;&lt;br /&gt;&lt;a href=http://www.cedarcitygroup.com/digitaldarkroom/uncolormyworld.aspx target=_blank&gt;http://www.cedarcitygroup.com/digitaldarkroom/uncolormyworld.aspx&lt;/a&gt; is an example web page that uses these classes to manipulate a fixed image according to gestures made on the user interface.  &lt;br /&gt;&lt;br /&gt;The main aspx page places the name of the image to be used in a session variable and provides the user input controls.  An image tag is present with its source set to a second aspx page where all the magic happens. When the process button is pressed, the source for the image tag is changed so that the user's selections are passed to the processing page in the form of url parameters.  Following is the code for the processing page.&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code" &gt;&lt;br/&gt;&lt;br /&gt;using System.Configuration;&lt;br /&gt;using System.Collections;&lt;br /&gt;using System.Web;&lt;br /&gt;using ccg.imaging;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Drawing.Imaging;&lt;br /&gt;using System.IO;&lt;br /&gt;&lt;br /&gt;public partial class digitaldarkroom_darkroomprocess : System.Web.UI.Page&lt;br /&gt;{&lt;br /&gt;    protected void Page_Load(object sender, EventArgs e)&lt;br /&gt;    {&lt;br /&gt;        // load the image using a utility class to resolve pathname and whatnot&lt;br /&gt;        darkroombl bl = new darkroombl();&lt;br /&gt;        Bitmap output = bl.GetImage(Request["image1"].ToString());&lt;br /&gt;&lt;br /&gt;        // use the colorization command to obtain the object to use &lt;br /&gt;        //to implement the command&lt;br /&gt;        string colorcommand = Request["color"].ToString().ToLower();&lt;br /&gt;&lt;br /&gt;        // if the user specifies "full color", then we need to do nothing&lt;br /&gt;        if (!string.IsNullOrEmpty(colorcommand) &amp;&amp; !colorcommand.Equals("full color"))&lt;br /&gt;        {&lt;br /&gt;            // instantiate the factory&lt;br /&gt;            FilterFactoryBase filterfactory = new FilterFactory();&lt;br /&gt;            // activate the class based on the user's input&lt;br /&gt;            ImageProcessBase proc = filterfactory.ActivateFilter(colorcommand);&lt;br /&gt;            //process the image&lt;br /&gt;            output = proc.Process(output);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        // send the resulting image back as a jpeg&lt;br /&gt;        Response.ContentType = "image/jpeg";&lt;br /&gt;        MemoryStream ms = new MemoryStream();&lt;br /&gt;        output.Save(ms,ImageFormat.Jpeg);&lt;br /&gt;        ms.WriteTo(Response.OutputStream);&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What does all this banjo work give us?&lt;/b&gt;&lt;br /&gt;So, what is the final result?&lt;br /&gt;&lt;br /&gt;1.  The application that uses the image process classes does not need to have a reference to the assembly they are located in.  Only the ccg.imaging.foundation is referenced by the top level project.  Additional filters can be added to the dll without reguiring the application to be rebuilt.&lt;br /&gt;&lt;br /&gt;2.  The factory class only requires string values to be initialized.  Right now, the class specifications are hard coded in the factory's constructor.  They could be read from the web.config file or even loaded from a database.&lt;br /&gt;&lt;br /&gt;3.  The actual processing classes can be moved to different assemblies easily.  The factory is the only class that would needed to be updated.&lt;br /&gt;&lt;br /&gt;In the next post I'll implement some more filters and look at how reflection can be used to provide some more customizable capabilities.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-724045884569394881?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/724045884569394881/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=724045884569394881' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/724045884569394881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/724045884569394881'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2008/12/uncolor-my-world-factory-pattern-in.html' title='Uncolor My World, The Factory Pattern In Action part 2'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-4888346218868707091</id><published>2008-12-18T05:32:00.003-06:00</published><updated>2008-12-18T06:00:20.333-06:00</updated><title type='text'>The psychology of software development....</title><content type='html'>I'm going to get back to my series on the factory class soon, but there was something on my mind yesterday that I wanted to post here.  Before I start, I'd like to ask a couple of questions:&lt;br /&gt;&lt;br /&gt;Have you ever sat in front of you computer, wracking your brain to solve a problem, then have the solution just come to you later when you are doing something totally unrelated to programming?&lt;br /&gt;&lt;br /&gt;Have you ever been close to a project deadline and found yourself being totally unproductive because you can't stay focused?&lt;br /&gt;&lt;br /&gt;Software development is an amazing pursuit.  It requires knowledge, but at its core it requires creativity.  Most non-developers don't understand that a developer can have the same relationship with an application that a songwriter has with a song.&lt;br /&gt;&lt;br /&gt;The human mind is an amazing thing, as someone who uses their mind as a means of income, I suggest that you be attentive to how your mind works and when you are productive and when you are not.&lt;br /&gt;&lt;br /&gt;I know that my experience is not the same as everyone, all of our minds work differently, but this has been my experience.&lt;br /&gt;&lt;br /&gt;If I am dealing with a difficult problem, I'll work on it until I realize that I'm not going to find the answer quickly.  At that point, if I walk away, and do something that I enjoy, the answer will just 'come to me'.  My theory is that the mind keeps working on the problem even though you are consciously working on it, when it finds the answer, it will notify you.&lt;br /&gt;&lt;br /&gt;There is tremendous power in explaining the problem to someone else.  Find another developer that has time to listen to you.  Start explaining the problem to them, most of the time, the process of explaining it to someone else will help you find the issue.  My theory: by vocalizing the problem, you move the problem to a different part of the brain that might have a better chance at solving it.&lt;br /&gt;&lt;br /&gt;Realistic deadlines motivate, unrealistic deadlines kill productivity.  Software development requires creativity.  Creativity requires that you be relaxed.  Deadlines obviously have to be set, but they have to be realistic.  I have found myself many time fighting unrealistic deadlines.  What tends to happen is that my mind tends to focus on the deadline instead of the software.  Stress kills productivity, do what ever you can to stay relaxed.&lt;br /&gt;&lt;br /&gt;Many times over the years, I've been in situations where deadlines were set based on business needs with no respect for the amount of work that needed to be done.  Since software is basically invisible, folks that don't write software typically don't understand the amount of effort that it requires.  Many times I've had clients give a 15 minute explanation of what they want and the ask "How long will it take?".  When asked this question, I usually try to ask questions that help them related to the process of software development.  My favorite is:  "How long does it take to solve a crossword puzzle?"  The answer is: "it depends on the puzzle".  That's right, and there are usually puzzles in an application that you can't completely understand until you get into it.&lt;br /&gt;&lt;br /&gt;Just a few notes from an old code dog...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-4888346218868707091?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/4888346218868707091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=4888346218868707091' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/4888346218868707091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/4888346218868707091'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2008/12/psychology-of-software-development.html' title='The psychology of software development....'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-1359916902610085683</id><published>2008-12-16T17:56:00.002-06:00</published><updated>2008-12-16T18:02:12.041-06:00</updated><title type='text'>Google Webmaster Tools....</title><content type='html'>I spent most of the day today working with Google's web master tools.  I've used them before, but they have been expanded greatly.  I whipped up a quick program to search a website development directory and generate a google compatible site map (using the factory pattern of course)&lt;br /&gt;&lt;br /&gt;I'll probably post the code at some point, I have some ideas on how to improve it.  If you have a site, and want to be able to generate a sitemap for it quickly, give me a call.&lt;br /&gt;&lt;br /&gt;If you are a webmaster and want to see what the webmaster tools can do for you, go to &lt;a href=http://www.google.com/webmasters&gt;Google Webmaster Tools&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-1359916902610085683?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/1359916902610085683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=1359916902610085683' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/1359916902610085683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/1359916902610085683'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2008/12/google-webmaster-tools.html' title='Google Webmaster Tools....'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-1305870768112416700</id><published>2008-12-12T04:02:00.027-06:00</published><updated>2008-12-14T06:33:36.966-06:00</updated><title type='text'>The Factory Pattern in Action....</title><content type='html'>In my opinion, the factory pattern is a powerful mechanism for processing data.  The cool thing about it is that you can break a complex process down into small manageable pieces.  Those pieces can then be applied interchangeably to create a flexible powerful process.&lt;br /&gt;&lt;br /&gt;One of my own personal interests for years has image processing.  I've been taking photographs since I was a kid.  Now that photographs are digital instead of chemical, it presents some really interesting possibilities for the analytical side of the brain.&lt;br /&gt;&lt;br /&gt;I've been toying with the idea of creating an automated image processing program for years, I actually had a pretty cool version of it working a few years ago, but I've never been able to polish it up enough to make a product out of it.  What I can do though, is write about what I was working on.  It may give other people some ideas or teach someone something cool about the .NET framework.  &lt;br /&gt;&lt;br /&gt;Professional imaging programs like Photoshop and Fireworks provide a "batch" mode where you can determine a set of operations to perform on a group of images.  This is very useful feature for webmasters.  But how would you design something like that if you needed to go beyond the operations that those programs provide?&lt;br /&gt;&lt;br /&gt;My plan was to break any possible operation on an image (resizing, convert to black and white, lighten/darken etc.) into a single object.  Each operation would have a common method that performed its operation.  The "Process" method would accept an image as a parameter and return the processed image when it was done.&lt;br /&gt;&lt;br /&gt;Once a collection of these objects was built, they could be mixed and matched into an image processing "pipeline" that could do some pretty amazing stuff on a large group of images.&lt;br /&gt;&lt;br /&gt;Here is an ideal base class for the image processing pipeline....&lt;br /&gt;&lt;br /&gt;&lt;pre class="c#" name="code"&gt;&lt;br/&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Drawing.Imaging;&lt;br /&gt;using System.Runtime.Serialization;&lt;br /&gt;&lt;br /&gt;namespace ccg.imaging&lt;br /&gt;{&lt;br /&gt;  &lt;br /&gt;  [Serializable]&lt;br /&gt;  public class IdealImageProcessBase&lt;br /&gt;  {  &lt;br /&gt;    public virtual Bitmap Process(System.Drawing.Bitmap bitmapin)&lt;br /&gt;    {&lt;br /&gt;      return bitmapin;   &lt;br /&gt;    }        &lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Reality quickly sets in&lt;/b&gt;&lt;br /&gt;This "do nothing" base class for image processing is simple and works, however, in reality it needs some work.&lt;br /&gt;&lt;br /&gt;The problem is, when you are dealing with images, you are dealing with large volumes of data.  The System.Drawing.Imaging namespace provides a ton of very powerful features for manipulating images, but at some point, it may be necessary to manipulate the image 1 pixel at a time.  The System.Drawing.Bitmap object provides the GetPixel() and SetPixel() methods for doing this, but, being managed code, they get very slow when processing large images.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Take A Walk On The Wild Side&lt;/b&gt;&lt;br /&gt;Back in the day before C had anything after it, nothing was 'safe'.  Before the days of managed code, you could easily write code that stepped all over itself.  The hallmark of the C language was its speed.  C was a language with no boundaries, direct manipulation of memory locations provided a tremendous amount of speed and flexibility...and danger.  It was very easy to write code that had unintended results, I won't bore you with the details, just suffice it to say that operations as simple as concatenation of strings presented a lot of danger to your application.&lt;br /&gt;&lt;br /&gt;Managed code provides a lot of safety for your applications, but the trade off is a lot of overhead.  Thankfully, you can still get down to processing memory directly,  but it requires some special security privileges and object locking.&lt;br /&gt;&lt;br /&gt;Here is my real-world image processing base class...&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="c#"&gt;&lt;br /&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Drawing.Imaging;&lt;br /&gt;using System.Runtime.Serialization;&lt;br /&gt;using System.Security;&lt;br /&gt;&lt;br /&gt;namespace ccg.imaging&lt;br /&gt;{&lt;br /&gt;  /// &lt;summary&gt;&lt;br /&gt;  /// This is a base class to provide low level image &lt;br /&gt;  /// processing services for different&lt;br /&gt;  /// filters and image processors.&lt;br /&gt;  /// &lt;/summary&gt;&lt;br /&gt;  /// &lt;br /&gt;  [Serializable]&lt;br /&gt;  public class ImageProcessBase&lt;br /&gt;   {&lt;br /&gt;  &lt;br /&gt;   protected static bool _allowunsafe;&lt;br /&gt;   protected static bool _permissionchecked = false;&lt;br /&gt;&lt;br /&gt;   #region Bitmap Locking and Unlocking&lt;br /&gt;&lt;br /&gt;   //--- locks the bitmaps data bits so that we can access them more speedily&lt;br /&gt;   protected System.Drawing.Imaging.BitmapData LockBits(Bitmap b)&lt;br /&gt;     {&lt;br /&gt;     // GDI+ still lies to us - the return format is BGR, NOT RGB. &lt;br /&gt;     return b.LockBits(new Rectangle(0, 0, b.Width, b.Height),&lt;br /&gt;                       ImageLockMode.ReadWrite, &lt;br /&gt;                       PixelFormat.Format24bppRgb);    &lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;   protected virtual void UnlockBits(Bitmap b, BitmapData bmd)&lt;br /&gt;     {&lt;br /&gt;     b.UnlockBits(bmd);&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;   #endregion&lt;br /&gt;&lt;br /&gt;   public ImageProcessBase()&lt;br /&gt;     { &lt;br /&gt;     if (!_permissionchecked)&lt;br /&gt;       {&lt;br /&gt;       _permissionchecked = true;&lt;br /&gt;       try &lt;br /&gt;         {    &lt;br /&gt;         System.Security.Permissions.SecurityPermission perm = &lt;br /&gt;                   new System.Security.Permissions.SecurityPermission(&lt;br /&gt;                  System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode);&lt;br /&gt;         _allowunsafe = true;&lt;br /&gt;         } &lt;br /&gt;       catch &lt;br /&gt;         {&lt;br /&gt;         _allowunsafe = false;&lt;br /&gt;         }&lt;br /&gt;     }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  public virtual Bitmap Process(System.Drawing.Bitmap bitmapin)&lt;br /&gt;    {   &lt;br /&gt;    if (_allowunsafe)&lt;br /&gt;      return ProcessUnsafe(bitmapin);&lt;br /&gt;    else&lt;br /&gt;      return ProcessSafe(bitmapin);   &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;  protected virtual Bitmap ProcessUnsafe(Bitmap bitmapin)&lt;br /&gt;    {&lt;br /&gt;    return ProcessSafe(bitmapin);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;  protected virtual Bitmap ProcessSafe(Bitmap bitmapin)&lt;br /&gt;    {&lt;br /&gt;    return bitmapin;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  [DataAttribute(DataAttributeType.Hidden)]&lt;br /&gt;  public string FilterName&lt;br /&gt;    {&lt;br /&gt;    get&lt;br /&gt;     {  &lt;br /&gt;     Type t = this.GetType();&lt;br /&gt;     object [] attrs = t.GetCustomAttributes(true);&lt;br /&gt;     if (attrs != null)&lt;br /&gt;       {&lt;br /&gt;       foreach(object attr in attrs)&lt;br /&gt;         if (attr is NameAttribute)&lt;br /&gt;           return ((NameAttribute)attr).Value;     &lt;br /&gt;       }&lt;br /&gt;     return t.Name;&lt;br /&gt;     }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;  [DataAttribute(DataAttributeType.Hidden)]&lt;br /&gt;  public string FilterDescription&lt;br /&gt;    {      &lt;br /&gt;    get&lt;br /&gt;      {  &lt;br /&gt;      Type t = this.GetType();&lt;br /&gt;      object [] attrs = t.GetCustomAttributes(true);&lt;br /&gt;      if (attrs != null)&lt;br /&gt;        {&lt;br /&gt;        foreach(object attr in attrs)&lt;br /&gt;          if (attr is DescriptionAttribute)&lt;br /&gt;            return ((DescriptionAttribute)attr).Value;     &lt;br /&gt;        }&lt;br /&gt;      return t.Name;&lt;br /&gt;      }    &lt;br /&gt;    }  &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now the first ImageProcessor object checks to see if unmanaged code is allowed.  By making the _permissionchecked and _allowunsafe properties static, we know that this will only be checked once.  The Process() method uses the _allowunsafe property to determine whether or not to call the ProcessUnsafe() method.  Since the default implementation of ProcessUnsafe() is to call ProcessSafe(), objects are not required to have an unsafe implementation.  The base class provides the methods to Lock and Unlock the bitmap object for unsafe processing and also provides some attribute properties to provide information to the GUI.&lt;br /&gt;&lt;br /&gt;All of this will lead to Factory Pattern, I promise, this is just the initial base class implementation.  The next installment will cover the implementation of a couple of real processor classes and possibly the factory...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-1305870768112416700?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/1305870768112416700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=1305870768112416700' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/1305870768112416700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/1305870768112416700'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2008/12/factory-pattern-in-action.html' title='The Factory Pattern in Action....'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-5424529131055193863</id><published>2008-12-08T11:47:00.002-06:00</published><updated>2008-12-08T11:52:35.726-06:00</updated><title type='text'>Recommendations....</title><content type='html'>Many times employers and clients want to see recommendations when they are considering hiring a new employee or contractor.  If I have done a project for you, or we have worked together, I would appreciate any glowing compliments that you might have about our time together.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-5424529131055193863?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/5424529131055193863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=5424529131055193863' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/5424529131055193863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/5424529131055193863'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2008/12/recommendations.html' title='Recommendations....'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-3063979143442548507</id><published>2008-12-06T07:58:00.003-06:00</published><updated>2008-12-06T09:15:54.045-06:00</updated><title type='text'>My Favorite Pattern....</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iYtmTluoApU/STqFNM1tnOI/AAAAAAAAADg/MGZ2TgR9Kb8/s1600-h/factorypattern.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 320px;" src="http://2.bp.blogspot.com/_iYtmTluoApU/STqFNM1tnOI/AAAAAAAAADg/MGZ2TgR9Kb8/s320/factorypattern.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5276676375249263842" /&gt;&lt;/a&gt;&lt;br /&gt;In my first post to this blog I mentioned that you are unlikely to find any ground breaking software ideas.  My target audience is the beginning to intermediate programmer that is learning coding and design.  I stand by that, that is the spirit with which this is written.&lt;br /&gt;&lt;br /&gt;Several years ago, the &lt;a href=http://en.wikipedia.org/wiki/Gang_of_Four_(software)&gt;"Gang of Four"&lt;/a&gt; came out with their book "Design Patterns: Elements of Reusable Object-Oriented Software".  Much to my chagrin, I've never read the book cover to cover.  I have resorted to reading interpretations by others.  To be honest, I've only used a few of their patterns in real life.  The &lt;a href=http://en.wikipedia.org/wiki/Factory_method_pattern&gt;Factory Method Pattern&lt;/a&gt;, however, is one that I find myself using over and over.  There is a ton of information available on the net about it.  There is nothing new here, but this is my contribution to the reader on how I use it.&lt;br /&gt;&lt;br /&gt;The factory method pattern allows multiple similar objects to be created and used by the application, without the application having to know a lot of the details of what the objects are doing.  In my opinion, one of the keys to writing a good maintainable application is to remove as much detail as possible from the top level code.  The details need to be "hidden" in lower level objects.  The trouble with this idea however is that you create many small objects that do similar yet different functions.  These objects need to be able to share commonly needed functionality while being able to add their own distinct functionality.  This is where the factory method pattern excels.&lt;br /&gt;&lt;br /&gt;Here are a few real world examples that I've implemented lately:&lt;br /&gt;&lt;br /&gt;An application needs to be able to generate several reports.  Each report has its own set of parameters that it needs.  Some reports require a specific date, while others need a date range for example.  There is a common UI used to provide the parameters for the report, once the needed data is provided, each report does it's own thing in generating the output.&lt;br /&gt;&lt;br /&gt;A food broker needs to be able to communicate with multiple external entities (manufacturers, distributors, customers etc.) via EDI.  The EDI format is standard, and like all standards, everybody has their own version of it.  The application needs to communicate with all external entities using their version of the "standard".&lt;br /&gt;&lt;br /&gt;A company that hosts conferences needs to be able to update a Microsoft Dynamics CRM database on site during the conference.  They have a custom application that uses bar codes to identify attendees that need to be updated.  Several different types of business entities need to be updated.  The workstations that the attendees visit communicates with a common server and send transactions depending on the update needed.  The server needs to identify the transaction and send the correct update to Dynamics CRM.&lt;br /&gt;&lt;br /&gt;Enter the factory method pattern...&lt;br /&gt;&lt;br /&gt;The factory method pattern allows several similar yet different classes to be created easily.  Each class can share common code (placed in the base abstract class) but has the ability to modify the functionality to meet its individual needs.  The factory class is responsible for identifying the needed concrete object and creating it.  The controlling code can then use the created object as needed without knowing the specific class that has been created.&lt;br /&gt;&lt;br /&gt;In the report example listed above, the base class contains needed UI support routines as well as an abstract GenerateReport() method.  Each concrete implementation can override the UI routines as needed as well as implementing the needed report generation.  The factory creates the concrete report object based on the user's selection.  The controlling code interrogates the created object to find out what parameters are needed and shows or hides input controls based on the information needed.  Once the parameters for the report are provided, the GenerateReport() method is called to create the final output.&lt;br /&gt;&lt;br /&gt;The EDI example may be obvious, the abstract base class contains common EDI functionality, the concrete classes implement each entities version of the standard.  The factory determines who we are talking to and generates the appropriate class.  The differences in formats is completely hidden from the controlling application.&lt;br /&gt;&lt;br /&gt;In the Microsoft Dynamics CRM example, the server receives a transaction from a workstation, the factory determines what type of concrete class is needed, the concrete class implement the logic needed to update the appropriate type, the abstract class provides support logic needed by all concrete classes.&lt;br /&gt;&lt;br /&gt;So what are the benefits of doing things this way?  Here are a few off the top of my head:&lt;br /&gt;&lt;br /&gt;1.  The top level code doesn't contain the detail of what is begin updated and how.  The logic at the top level is minimal, understandable and maintainable.&lt;br /&gt;&lt;br /&gt;2.  For each detailed concrete class, the code required is minimal.  If you design the base abstract class well, then you will find that each concrete class contains very little code, only the code required to implement the differences will appear.&lt;br /&gt;&lt;br /&gt;Ok, I have to come up with some shortcomings of the pattern...&lt;br /&gt;&lt;br /&gt;Hmmm....well, I guess some folks my struggle with inheritance, however, if you are going to be a successful developer using object oriented languages you will need to become very familiar with that.  You especially need to be very familiar with some of the qualifiers like public, protected, static and abstract.  I love the static keyword, it means very different things depending on where its used.&lt;br /&gt;&lt;br /&gt;Documentation is key.  It is difficult to look at the code and determine what is going on unless you are familiar with the specific technique.  Learn UML, a picture is worth a thousand words goes for documentation as well.  Assume that the person coming behind you to maintain your code is a beginner.  You will thank me one day because if you stay in this business long enough, there will come a time when you look at your own code and say "What was I thinking?"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-3063979143442548507?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/3063979143442548507/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=3063979143442548507' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/3063979143442548507'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/3063979143442548507'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2008/12/my-favorite-pattern.html' title='My Favorite Pattern....'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iYtmTluoApU/STqFNM1tnOI/AAAAAAAAADg/MGZ2TgR9Kb8/s72-c/factorypattern.jpg' height='72' width='72'/><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-1715718599899726929</id><published>2008-12-04T13:53:00.002-06:00</published><updated>2008-12-04T14:11:03.496-06:00</updated><title type='text'>Window Class Name Is Not Valid....</title><content type='html'>I have a Windows Forms application that I wrote several years ago (my first production C# application actually) that occasionally throws an exception when it starts.  The Error message says "Window Class Name Is Not Valid" and it happens when the startup code tries to show the main form.&lt;br /&gt;&lt;br /&gt;I did some searching around and found that there are several people that have encountered the same error.  In my case, it only happened when I tried to debug the program.  It used to happen once, and then I would retry running the program and it would work correctly.  I hit the wall though, this time it happened every time I executed the application.  &lt;br /&gt;&lt;br /&gt;I read &lt;a href=http://forums.microsoft.com/msdn/showpost.aspx?postid=101613&amp;siteid=1&amp;sb=0&amp;d=1&amp;at=7&amp;ft=11&amp;tf=0&amp;pageid=2&gt;this fairly lengthy thread&lt;/a&gt; about the problem.  The solution that worked for me was turning off the Visual Studio Hosting Process.  &lt;br /&gt;&lt;br /&gt;Right click on the project that is giving you trouble, select properties, select the Debug tab.  The Visual Studio Hosting Process selection is a check box at the end of the list.  When I unchecked it, my project would debug every time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-1715718599899726929?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/1715718599899726929/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=1715718599899726929' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/1715718599899726929'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/1715718599899726929'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2008/12/window-class-name-is-not-valid.html' title='Window Class Name Is Not Valid....'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-3306635851039371615</id><published>2008-09-15T06:11:00.002-05:00</published><updated>2008-09-15T06:14:32.225-05:00</updated><title type='text'>Ch....Ch....Ch.....Changes</title><content type='html'>Beginning October 1, 2008 Cedar City Group, LLC is closing as a business entity.  I (Donnie Hall) will continue to do consulting, however, I am currently working primarily through Sysgenix Resources.  I continue to support some of my existing clients.&lt;br /&gt;&lt;br /&gt;If you have troubleshooting, or some small development projects of any type, please call me and I will help you or find someone that can.&lt;br /&gt;&lt;br /&gt;I'm not going away, just changing the way that things are being done.&lt;br /&gt;&lt;br /&gt;Thank you,&lt;br /&gt;&lt;br /&gt;Donnie&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-3306635851039371615?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/3306635851039371615/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=3306635851039371615' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/3306635851039371615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/3306635851039371615'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2008/09/chchchchanges.html' title='Ch....Ch....Ch.....Changes'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-5243902255116475191</id><published>2008-02-01T20:20:00.000-06:00</published><updated>2008-02-01T20:34:03.360-06:00</updated><title type='text'>Email Hosting Changeover</title><content type='html'>On Saturday February 2nd, our email hosting is to change to a new hosting provider.  This change over will require you to take action to make this transition smooth.&lt;br /&gt;&lt;br /&gt;If you did not change your password and it does not contain between 7 and 64 characters and include 1 upper case letter and 1 lower case letter.  Then you will need to change your password when you login.&lt;br /&gt;&lt;br /&gt;In addition, you will need to modify your account settings if you read your email through a client such as Outlook.  The following document provides instructions modifying the password and changing your email client.&lt;br /&gt;&lt;br /&gt;&lt;a href=http://66.203.146.57/zimbra&gt;Email Change Over Instructions&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If after attempting to perform these procedures, you are still unable please call 1.888.277.9320 for technical support.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-5243902255116475191?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/5243902255116475191/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=5243902255116475191' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/5243902255116475191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/5243902255116475191'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2008/02/email-hosting-changeover.html' title='Email Hosting Changeover'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-7799858733591752470</id><published>2007-12-19T08:16:00.000-06:00</published><updated>2007-12-19T08:18:20.890-06:00</updated><title type='text'>Cool quote....</title><content type='html'>I saw this quote yesterday...it applies to software development and many other areas of life..&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Talent hits a target no one else can hit,  genius hits a target that no one else can see.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Happy coding....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-7799858733591752470?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/7799858733591752470/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=7799858733591752470' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/7799858733591752470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/7799858733591752470'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2007/12/cool-quote.html' title='Cool quote....'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-5127826338403556167</id><published>2007-12-17T19:57:00.001-06:00</published><updated>2007-12-18T09:59:47.028-06:00</updated><title type='text'>A long time requirement finally met...</title><content type='html'>As long as I can remember, I have felt that when you use a text box to perform data entry for a database column, that the maxlength of the text box should match the definition of the column in the database.  And that it should automatically  change on the text box if the database design changed.  I never had the gumption to actually write the code to do that, but I've always felt that it should be done.&lt;br /&gt;&lt;br /&gt;I'm sitting here working on a fairly simple data entry form for a web application, I'm populating a text box with the value from a SubSonic field and that old urge to set the max length kicked in.  I dug around in the SubSonic object model for a little bit and came up with the following code.&lt;br /&gt;&lt;p style=font-family:courier;font-size:8px&gt;&lt;br /&gt; txtFirstName.Text = buyer.FirstName;&lt;br /&gt; txtFirstName.MaxLength = buyer.GetSchema().GetColumn("firstname").MaxLength;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;as my buddy Tim says Schweet!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-5127826338403556167?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/5127826338403556167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=5127826338403556167' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/5127826338403556167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/5127826338403556167'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2007/12/long-time-requirement-finally-met.html' title='A long time requirement finally met...'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-7273629870698758065</id><published>2007-12-14T06:10:00.000-06:00</published><updated>2007-12-14T06:42:28.609-06:00</updated><title type='text'>Abstraction...</title><content type='html'>In my &lt;a href=http://www.cedarcitygroupblog.com/2007/09/whats-up-with-cedar-city-group.html&gt;original post&lt;/a&gt; to this blog, I mentioned who the audience is.  If you are an experienced developer that has it all figured out, then I'm not going to post anything here that you don't already know.  However, if you are a beginner to intermediate level programmer, I hope that I can give some advice that will be helpful to you.&lt;br /&gt;&lt;br /&gt;I've been posting about Subsonic for a while, but the question is:  Why is a tool like subsonic important?  The key point here is abstraction.  This is a key principle in software development that has been around for years and years.  It's important.  At the application level, you must learn to think abstractly (I'm setting the date of birth for an employees vs.  I'm updating the dob column in the employee database).  The mind can only deal with so much detail, thinking abstractly helps you solve bigger problems.  Object oriented programming helps in this quest.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Datasets are objects too....&lt;/b&gt;&lt;br /&gt;Well, yeah they are, but not the kind of objects that I'm talking about here.  Datasets do not provide abstraction.  Think about this, when you deal with an application that is dataset oriented, what is the documentation that you refer to most often?  Could it be the database schema?  Your column names appear at the top level of your code.  There is no abstraction.  With true business objects, the top level appication has no idea how the objects are stored, the application deals with operations like, Save, Update, Delete.  Much more abstract.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The problem with business objects&lt;/b&gt;&lt;br /&gt;The downside of writing business object oriented code has always been the overhead.  Business object oriented code has always taken a lot of time because of the code needed to 'translate' between the object model and the database model.  Datasets seem to be quicker because there doesn't need to be any translation code.  In the end, however, dataset oriented applications become brittle because they are tied to the database in an unhealthy way.  What about strong typing?  With datasets you must constantly typecast your data.  The business object model provides strong typing which by definition improves your code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;If the abstraction argument doesn't work...&lt;/b&gt;&lt;br /&gt;If the concept of abstraction doesn't appeal to you, then how about this.  If you use true business objects, you have intellisense at the application level, even when databinding to controls.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The reason Subsonic is important....&lt;/b&gt;&lt;br /&gt;Subsonic provides the needed abstraction while removing the overhead of writing the translation code yourself. The concept of abstraction is what is important, not the specific tool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-7273629870698758065?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/7273629870698758065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=7273629870698758065' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/7273629870698758065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/7273629870698758065'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2007/12/abstraction.html' title='Abstraction...'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-8811600651567720380</id><published>2007-12-14T05:47:00.000-06:00</published><updated>2007-12-14T06:09:01.522-06:00</updated><title type='text'>I'll get off of the SubSonic Kick.....</title><content type='html'>At some point but not right now.&lt;br /&gt;&lt;br /&gt;Yesterday, I was posting some recent web site changes to a test site.  For the last couple of projects that I've worked on, I've had access to &lt;a href=http://www.red-gate.com/products/SQL_Compare/index.htm&gt;SQLCompare&lt;/a&gt; which is a darn good product.  I have encouraged several companies to buy it, though I don't have a copy of my own.  Anyway, I had a bunch of database changes to make, no SQLCompare to synchronize, what do you do?&lt;br /&gt;&lt;br /&gt;Subsonic to the rescue.  With a few rules to follow, Subsonic provides a cool mechanism for upgrading your database.  Subcommander provides a /version option which will create two scripts.  One script will create the schema for the configured database, the other will create a script that will recreate the data.  Pretty cool stuff.  I 'versioned' the new database and the destination database.  Run the new schema script on the destination db, then run the destination data script to re-insert the data.&lt;br /&gt;&lt;br /&gt;Obviously, there are some rules here:  you can't delete columns, or tables (without modifying the data script).  But this provides a cool mechanism for developers. &lt;br /&gt;&lt;br /&gt;How many times have you need to duplicate a database for development purposes?  You want a development, testing and production version of your database.  You can use backup/restore to create a new database but this provides a quick mechanism for duplicating that is very easy to understand.&lt;br /&gt;&lt;br /&gt;There are many uses for this utility, creating your initial install scripts, version control of schema (and data!) also, though I've not checked this out yet, but  a poor man's SQL Compare could be created with the combination of SubSonic and a text comparison tool like &lt;a href=http://www.componentsoftware.com/Products/csdiff/&gt;csdiff&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Pretty cool stuff, Thanks guys.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-8811600651567720380?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/8811600651567720380/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=8811600651567720380' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/8811600651567720380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/8811600651567720380'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2007/12/ill-get-off-of-subsonic-kick.html' title='I&apos;ll get off of the SubSonic Kick.....'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-4244057780411849138</id><published>2007-12-13T06:18:00.000-06:00</published><updated>2007-12-13T06:49:06.516-06:00</updated><title type='text'>Subsonic Rocks</title><content type='html'>Ok, I've been talking about Subsonic for a little bit.  I'm working on a project now where I'm really starting to put it through its paces.  I have to say that the more I work with it, the more impressed I am.&lt;br /&gt;&lt;br /&gt;I must admit that I got sucked in by the scaffolding approach.  You drop one control on a form and poof you have a data entry application.  Well..almost.  I was writing a form to do some simple content management.  I didn't want the content to appear on the front list.  With the scaffold control, it appears that you get everything.  There is also a quicktable control which provides more control, but as soon as you need to add any logic to the process (hey I need to hash the password instead of storing it in clear text) at that point you are writing your own form.&lt;br /&gt;&lt;br /&gt;On the plus side, writing your own form is much easier with Subsonic than without it.  Subsonic plus partial classes in c# very easily solve the dilemma of customizing code that is generated.  Typically, I need a method that retrieves an object by something other than the primary key.  I typically let subsonic generate code for me into a separate data layer project.  The subsonic code goes into a folder called 'generated'.  I then create a second folder called 'Custom' at the same level.  Any time I need to add a method to a subsonic class, I create a partial class in custom that has the same namespace and class name as the subsonic code, and add the method that I need.  My new method appears on the objects as if subsonic created it.  If I need to regenerate the subsonic code, my custom code remains in tact.  Pretty cool stuff.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-4244057780411849138?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/4244057780411849138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=4244057780411849138' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/4244057780411849138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/4244057780411849138'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2007/12/subsonic-rocks.html' title='Subsonic Rocks'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-8205877863212754185</id><published>2007-12-04T06:08:00.000-06:00</published><updated>2007-12-04T06:11:51.796-06:00</updated><title type='text'>How things have changed....</title><content type='html'>I downloaded the Visual Studio 2008 (3.3G) and can't help but think about the first compiler that I used as a professional developer.  I was so excited when we got it....Turbo Pascal 4.  As far as I know, it was one of the first languages to use the IDE approach.  Anyway, it arrived on 2 5.25" floppies one floppy was nothing but samples.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-8205877863212754185?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/8205877863212754185/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=8205877863212754185' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/8205877863212754185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/8205877863212754185'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2007/12/how-things-have-changed.html' title='How things have changed....'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-93898331102747844</id><published>2007-12-02T13:06:00.000-06:00</published><updated>2007-12-04T05:56:32.623-06:00</updated><title type='text'>SubSonic, the best thing since crunchy peanut butter</title><content type='html'>My first introduction to the MVC way of doing things was via SubSonic.  The project that I was working on at the time was suffering from death by n-tier.  One of the worst things that could happen while working on the project was to realize that you needed a new piece of data from the database.  We were going by the book so here are the steps we had to go through:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Write a stored procedure to access the tables.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Write the code in the dataaccess layer to call the stored procedure (thank goodness we were using the Enterprise Library which simplified that code)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Write a business layer routine to call the data access layer&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;Death by n-tier.  I guess if the business layer added any value, I could understand it, but it didn't.&lt;br /&gt;&lt;br /&gt;I was introduced to &lt;a href=http://www.SubSonicproject.com&gt;SubSonic&lt;/a&gt;.  SubSonic is a data layer generator that implements the ActiveRecord pattern.  In a nutshell, it automatically generates the code to present your application with strongly typed data objects and collections based on your database design.  It can operate in two modes:  mode one automatically updates the code datlayer code for you at compile time using their build provider.  This is cool, becuase you can update your database and the changes are automatically refelected in your code the next time you compile.&lt;br /&gt;&lt;br /&gt;I prefer mode 2 where Subsonic generates code for you and places it into a separate data layer project.  You have to go through some extra steps, but this method just feels better to me.  This mode is also recommended if you are going to be deploying to a shared host.&lt;br /&gt;&lt;br /&gt;SubSonic also provides a Scaffolding control that can help you prototype your data input logic quickly.&lt;br /&gt;&lt;br /&gt;I'm by no means an expert on this stuff.  But SubSonic seems like a good tool to have in your tool box.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-93898331102747844?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/93898331102747844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=93898331102747844' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/93898331102747844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/93898331102747844'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2007/12/subsonic-best-thing-since-crunchy.html' title='SubSonic, the best thing since crunchy peanut butter'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-2731938162799442423</id><published>2007-11-27T06:17:00.001-06:00</published><updated>2007-11-27T06:22:20.910-06:00</updated><title type='text'>My approach to MVC...</title><content type='html'>Over the holiday, in addition to several other tasks, I decided to develop my approach to the upcoming release of Microsoft's MVC framework.  From what I've learned so far, MVC is definitely the way to go.  After studying MVC, web forms looks like a kludgy mess.  MVC is clean and cool.&lt;br /&gt;&lt;br /&gt;Anyway, my problem is that I have several sites that could use some revamping.  I want to use MVC but what do you do?  Microsoft's frame work isn't available.  Monorail is out and stable but will it be used going forward?  I studied several approaches, including writing web forms in a more MVC like manner.  &lt;br /&gt;&lt;br /&gt;I've decided to use monorail for my upcoming projects.  I am certain that there will be a simple upgrade path to Microsoft's MVC if necessary.  Monorail gets me on the way with my upcoming projects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-2731938162799442423?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/2731938162799442423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=2731938162799442423' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/2731938162799442423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/2731938162799442423'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2007/11/my-approach-to-mvc.html' title='My approach to MVC...'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9120211891716727685.post-2619040080875813300</id><published>2007-11-22T03:55:00.000-06:00</published><updated>2007-11-22T04:17:10.902-06:00</updated><title type='text'>What to do?</title><content type='html'>As I've mentioned, I've been studying monorail and the whole MVC architecture.  I am excited about it.  Can't wait to get started with it, however, I was a little disappointed to see &lt;a href=http://hammett.castleproject.org/?p=219&gt;this post&lt;/a&gt; from the leader of monorail indicating their wait and see attitude towards Microsoft's MVC framework.  I'm ready to go, ready to get started.  MVC seems to solve a lot of problems that have held me up for years.  But, what do you do?  Investing a lot of time in learning and implementing monorail seems like it may lead to a dead-end.  I began learning the brail view engine, but Hammett indicates that it doesn't work with MVC.  Will it by the time its released?  Does anyone else have an opinion on what we can do now?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9120211891716727685-2619040080875813300?l=www.cedarcityblog.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cedarcityblog.com/feeds/2619040080875813300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=9120211891716727685&amp;postID=2619040080875813300' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/2619040080875813300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9120211891716727685/posts/default/2619040080875813300'/><link rel='alternate' type='text/html' href='http://www.cedarcityblog.com/2007/11/what-to-do.html' title='What to do?'/><author><name>Donnie Hall</name><uri>http://www.blogger.com/profile/16400585747653558371</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='04920216116780475934'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry></feed>