Too much to digest? Slice it up in chunks!

From time to time you will find yourself in the need of slicing up large chunks of bites into smaller chunks of consumable bites.
Since I have been unable to find such a method in the .NET framework, I decided to include one on the EnumerableUtility class found in the Cuemon.Collections.Generic namespace. The name for the method was carefully chosen to be Chunk, and consist of two overloads; both accepting an IEnumerable<T> where the chunk size is defaulted to 128 elements and the other with a custom size.

To see the Chunk method in action, have a look at Figure 1. For simplicity i set a chunk size to 255 and a workload count to 4096. This means that our workload consists of 4096 elements which we will process 255 elements at time. This leaves us with a workload of 17 runs in total.


[TestClass]
public class ChunkExample
{
    [TestMethod]
    public void TestChunk()
    {
        int chunkSize = 255;
        int workload = 4096;
        int expectedWorkloadIterations = (workload + chunkSize - 1 ) / chunkSize;
        IEnumerable<int> simulatedWorkload = new List<int>(EnumerableUtility.Range(0, workload));

        Debug.WriteLine("Work to process: {0} items.", workload);
        Debug.WriteLine("Expected iterations for work: {0} runs.", expectedWorkloadIterations);

        int actualWorkloadIterations = 0;
        while (((List<int>)simulatedWorkload).Count > 0)
        {
            IEnumerable<int> chunkedWorkload = EnumerableUtility.Chunk(ref simulatedWorkload, chunkSize);
            IEnumerator<int> chunkedWorkloadEnumerator = chunkedWorkload.GetEnumerator();
            int countOfChunkedElements = EnumerableUtility.Count(chunkedWorkload);

            Assert.IsTrue(countOfChunkedElements <= chunkSize);

            int enumeratorCount = 0;
            while (chunkedWorkloadEnumerator.MoveNext())
            {
                enumeratorCount++;
            }
            actualWorkloadIterations++;

            Assert.IsTrue(enumeratorCount <= chunkSize);

            Debug.WriteLine("Remaining work to process: {0} items.", ((List<int>)simulatedWorkload).Count);
        }

        Assert.IsTrue(expectedWorkloadIterations == actualWorkloadIterations);
        Debug.WriteLine("Actual iterations for work: {0} runs.", actualWorkloadIterations);
    }
}
Figure 1: A simple test method that utilizes the Chunk method found on the EnumerableUtility class.


When executed, the test method should produce this debug output:


Debug Trace:
Work to process: 4096 items.
Expected iterations for work: 17 runs.
Remaining work to process: 3841 items.
Remaining work to process: 3586 items.
Remaining work to process: 3331 items.
Remaining work to process: 3076 items.
Remaining work to process: 2821 items.
Remaining work to process: 2566 items.
Remaining work to process: 2311 items.
Remaining work to process: 2056 items.
Remaining work to process: 1801 items.
Remaining work to process: 1546 items.
Remaining work to process: 1291 items.
Remaining work to process: 1036 items.
Remaining work to process: 781 items.
Remaining work to process: 526 items.
Remaining work to process: 271 items.
Remaining work to process: 16 items.
Remaining work to process: 0 items.
Actual iterations for work: 17 runs.
Figure 2: The output of the test in Figure 1.

I hope you liked this little peek into one of the many day-to-day helper methods found through out the Cuemon assembly family. Happy coding!

Sunday, June 9, 2013
Posted by Michael Mortensen

XML the smart way - and beyond!

Well, it's no secret - I am a big fan of XML and the possibilities it brings to a digital connected world. Yes, it may be fat - but if the consuming client support GZIP or similar - that is a big fat-loss. Still not convinced? Well, you can always transform it to a more lightweight candidate, such as JSON. That's how versatile XML is.




Speaking of versatile, there are many ways to create XML in the .NET Framework. Ranging from ways of a simple string to a StringBuilder to XmlDocument to XElement to XmlWriter to many, many more. Just Google xml .net followed by your favorite syntax, eg. c#, and several millions result is served to you.

Personally, I have always favored the XmlWriter approach, as it is as close to the core as it gets without overhead of the more popular XElement and the likes.

A typical way to use the aforementioned XmlWriter could be like this:
public Stream GetExmapleXml()
{
    Stream output = null;
    MemoryStream tempOutput = null;
    try
    {
        tempOutput = new MemoryStream();
        using (XmlWriter writer = XmlWriter.Create(tempOutput))
        {
            // build your XML here
            writer.WriteStartElement("Xml");
            writer.WriteString("A very simple XML representation - and yes, I could just have used writer.WriteElementString(..) - but hey - it's my example :-)");
            writer.WriteEndDocument();
            writer.Flush();
        }
        tempOutput.Flush();
        tempOutput.Position = 0;
        output = tempOutput;
        tempOutput = null;
    }
    finally
    {
        if (tempOutput != null) { tempOutput.Dispose(); }
    }
    return output;
}
Figure 1: A more common way of writing XML.

This would return a Stream holding this XML:
<?xml version="1.0" encoding="UTF-8"?>
<Xml>A very simple XML representation - and yes, I could just have used writer.WriteElementString(..) - but hey - it's my example :-)</Xml>
Figure 2: The XML output as produced by Figure 1, Figure 3, Figure 4 and Figure 5.

Although very performance friendly and to some extent easy on the eye, I decided to provide a more generic and simple way of achieving the same using the Cuemon.Xml assembly. In this assembly you will find the XmlWriterUtility class that (in the writing of this entry) consist of two methods; CreateSettings and CreateXml.

Since my primary goal is to be backward compatible with .NET 2.0 SP1, the CreateXml method can take up to 10 arguments using an Action delegate, which has the same characteristica as the one found in .NET 4.0. The default XML settings (should you choose not to provide a XmlWriterSettings) are the one found in the parameter less CreateSettings method.

Anyway, have a look at the same example as above - just the Cuemon way in three different forms:


public Stream GetExmapleXml()
{
    return XmlWriterUtility.CreateXml(GetExmapleXmlImpl);
}

public void GetExmapleXmlImpl(XmlWriter writer)
{
    writer.WriteStartElement("Xml");
    writer.WriteString("A very simple XML representation - and yes, I could just have used writer.WriteElementString(..) - but hey - it's my example :-)");
    writer.WriteEndDocument();
}
Figure 3: My preferred way of using the implementation - but hey - I am dinosaur in this fancy Lambda world.


public Stream GetExmapleXmlDelegate()
{
    return XmlWriterUtility.CreateXml(delegate(XmlWriter writer)
                                          {
                                              writer.WriteStartElement("Xml");
                                              writer.WriteString("A very simple XML representation - and yes, I could just have used writer.WriteElementString(..) - but hey - it's my example :-)");
                                              writer.WriteEndDocument();
                                          });
}
Figure 4: Same result as in Figure 3 - just using an anonymous method.


public Stream GetExmapleXmlLambda()
{
    return XmlWriterUtility.CreateXml(writer =>
        {
            writer.WriteStartElement("Xml");
            writer.WriteString("A very simple XML representation - and yes, I could just have used writer.WriteElementString(..) - but hey - it's my example :-)");
            writer.WriteEndDocument();
        });
}
Figure 5: Same result as in Figure 3 and 4 - just using lamda expression as supported by .NET 3.0.

There you have it - a smart and easy way of creating versatile XML that can be used in all sorts of scenarios. Want a string representation of the Stream? You asked for it - just use the ConvertUtility.ToString(..) like this:


ConvertUtility.ToString(GetExmapleXml());

I hope you enjoyed this little introduction to the XmlWriterUtility class - and can see and unleash the potential of it. As always - happy coding - and thanks for stopping by.

The dark side of the Cloud; network connectivity issues and service unavailability - AKA Transient Faults

In these days where everything is moving to "the cloud", new challenges arises that most of us where spared from before; temporary condition such as network connectivity issues or simply a service unavailability. The technical term for this is called Transient Fault Handling and one you must be conversant with.
On MSDN there is a very informative and good background information for Transient Fault Handling which i strongly encourage you to read. While you are there, you could consider if the comprehensive work of the Enterprise Library from version 5.0 suits your needs in what has been named the Transient Fault Handling Application Block.

If it seems a big over the top for your solution, you could consider the static TransientFaultUtility class found in the Cuemon namespace; it is fully compatible with cloud provides such as Windows Azure. It has several overloads for invoking a fault sensitive method, and will continue until the operation is successful, the amount of retry attempts has been reached, or a failed operation is not considered related to a transient fault condition.

The minimum required parameters for invoking a transient fault protected method is an integer specifying retryAttempts, a function delegate that will determine if isTransientFault and last but not least; a function delegate/action delegate pointing to the faultSensitiveMethod.

To see this in action, have a look at Figure 1. What we do here is simply throwing an HttpException should we encounter a HTTP 502. This can easily be extended to the ones listed in the IsTransientFault callback method. Otherwise we just write some debug information. Figure 2 shows how to consume the TransientFaultExample class and is intentionally set to fail in the first run. Figure 3 shows the Debug Trace.


public class TransientFaultExample
{
    public TransientFaultExample()
    {
        NetHttpUtility.DefaultHttpTimeout = TimeSpan.FromSeconds(15);
    }

    public void OpenWebsite(Uri location)
    {
        using (HttpWebResponse response = NetHttpUtility.HttpGet(location))
        {
            if (response.StatusCode == HttpStatusCode.BadGateway) { throw new HttpException(502, response.StatusDescription); }
            Debug.WriteLine("Status code in response was {0} - {1}.", (int)response.StatusCode, response.StatusDescription);
            Debug.WriteLine("The headers of the response was {0}.", ConvertUtility.ToDelimitedString(response.Headers.AllKeys, ", ", HeaderConverter, response.Headers) as object);
        }
    }

    private string HeaderConverter(string header, WebHeaderCollection headers)
    {
        return string.Format("{0}: {1}", header, headers[header] ?? "null");
    }

    public bool IsTransientFault(Exception exception)
    {
        HttpException httpException = exception as HttpException;
        if (httpException != null)
        {
            switch (httpException.GetHttpCode())
            {
                case 404:
                case 408:
                case 410:
                case 500:
                case 502:
                case 503:
                case 504:
                    return true;
                default:
                    return false;
            }
        }
        return (exception.Message.IndexOf("timed out", StringComparison.OrdinalIgnoreCase) >= 0);
    }
}
Figure 1: A simple TransientFaultExample class that can easily be rewritten to more real-life scenarios

[TestClass]
public class TransientFaultExampleTest
{
    [TestMethod]
    public void TransientFault()
    {
        TransientFaultExample transient = new TransientFaultExample();

        try
        {
            TransientFaultUtility.ExecuteAction(5, transient.IsTransientFault, transient.OpenWebsite, new Uri("http://www.google.com:88/"));
        }
        catch (TransientFaultException ex)
        {
            Debug.WriteLine("TransientFaultException was thrown (which is good): {0}", ConvertUtility.ToString(ex, Encoding.Default, true) as object);
        }

        try
        {
            TransientFaultUtility.ExecuteAction(5, transient.IsTransientFault, transient.OpenWebsite, new Uri("http://www.google.com/"));
        }
        catch (TransientFaultException ex)
        {
            Debug.WriteLine("TransientFaultException was thrown (which is not so good - for Google at least): {0}", ConvertUtility.ToString(ex, Encoding.Default, true) as object);
            Assert.Fail();
        }
    }
}
Figure 2: Consumes the class defined in Figure 1


Debug Trace:

TransientFaultException was thrown (which is good): TransientFaultException (Cuemon)
Source:
    Cuemon
Message:
    The amount of retry attempts has been reached.
Data:
    Key: Attempts
    Value: 5
    Key: RecoveryWaitTimeInSeconds
    Value: 21
    Key: TotalRecoveryWaitTimeInSeconds
    Value: 56
InnerException [of TransientFaultException]:
    TimeoutException (System)
Source:
    Cuemon
Message:
    The operation has timed out.

Status code in response was 200 - OK.
The headers of the response was Cache-Control: private, max-age=0, Content-Type: text/html; charset=ISO-8859-1, Date: Thu, 25 Apr 2013 01:09:52 GMT, Expires: -1, Set-Cookie: PREF=ID=fd0ca0865d752f5b:FF=0:TM=1366852192:LM=1366852192:S=KNM_xhwUAUmLa1-f; expires=Sat, 25-Apr-2015 01:09:52 GMT; path=/; domain=.google.dk,NID=67=vYXlkUfWQ_paZ7fdrkXaq2gmgUati-Y3FfiPzpRLQTTWn7lQgWowKZgE53z4_D1G04SmEk0N_4YdaUKC2RZkajhrCZ69QrCRHKBumdejJg4Z2MKak7fUF0QUbL7nKf3F; expires=Fri, 25-Oct-2013 01:09:52 GMT; path=/; domain=.google.dk; HttpOnly, P3P: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info.", Server: gws, X-XSS-Protection: 1; mode=block, X-Frame-Options: SAMEORIGIN, Transfer-Encoding: chunked.
Figure 3: The output of the test in Figure 2

If you don't like the default recovery wait time this can easily be added using one of the overloads on the TransientFaultUtility class. For your convenience, I have included the default implementation in Figure 4.


/// <summary>
/// Specifies the amount of time to wait for a transient fault to recover gracefully before trying a new attempt.
/// </summary>
/// <param name="currentAttempt">The current attempt.</param>
/// <returns>A <see cref="TimeSpan"/> that defines the amount of time to wait for a transient fault to recover gracefully.</returns>
/// <remarks>Default implementation is <see cref="RecoveryWaitTime"/> + 2^ to a maximum of 5; a total of 5 (default) + 32 = 37 seconds.</remarks>
public static TimeSpan RecoveryWaitTime(int currentAttempt)
{
    TimeSpan sleep = DefaultRecoveryWaitTime;
    sleep = sleep.Add(TimeSpan.FromSeconds(Math.Pow(2, currentAttempt > 5 ? 5 : currentAttempt)));
    return sleep;
}
Figure 4: The default implementation of the function delegate recoveryWaitTime

I hope this little introduction have inspired you to master Transient Fault Handling one way or another. Happy coding.

AES - An Easy way of applying Security?

So you are running .NET 2.0 and want to implement the Advanced Encryption Standard (hereafter referred to as AES), eh? Well, no worries. Although this was first "officially" supported with .NET 3.5 in the System.Security.Cryptography namespace, the standard itself is based on the Rijndael cipher why it is rather easy to take advantage of this widely accepted encryption standard.

For more information about the theory behind Rijndael and AES take a look at this Wikipedia article.

As you may have discovered from the reading above and the example provided by MSDN, it can be rather cumbersome and time consuming to implement the AES, why the Cuemon.Security.Cryptography namespace provide you with a static AdvancedEncryptionStandardUtility class that significantly will ease the implementation of an AES secured application accepting key sizes of 128-, 192- and 256-bit.

To give an example on how you could use the AES, have a look at Figure 1. This very basic AesExample class will pre-initialize some required properties that we can use in Figure 2 with an equally basic test method. Figure 3 shows the output of the test.


public class AesExample
{
    public AesExample()
    {
        this.Encoding = Encoding.UTF8;
        this.InitializationVector = AdvancedEncryptionStandardUtility.GenerateInitializationVector();
    }

    public virtual byte[] SecretKey
    {
        get { return Convert.FromBase64String("bzl6ZmxoU3Z3a2x4YkVLTmdZYkRGTEI5TEVUMTAya0s="); }
    }

    public Encoding Encoding { get; private set; }

    public byte[] InitializationVector { get; set; }

    public byte[] Lock(string secret)
    {
        return AdvancedEncryptionStandardUtility.Encrypt(ConvertUtility.ToByteArray(secret, PreambleSequence.Remove, this.Encoding),
            this.SecretKey,
            this.InitializationVector);
    }

    public string Unlock(byte[] secret)
    {
        return ConvertUtility.ToString(AdvancedEncryptionStandardUtility.Decrypt(secret, this.SecretKey, this.InitializationVector),
            PreambleSequence.Remove,
            this.Encoding);
    }
}
Figure 1: A basic class to show a potential usage of the AdvancedEncryptionStandardUtility class

[TestClass]
public class AesExampleTest
{
    [TestMethod]
    public void TestAes()
    {
        AesExample aes = new AesExample();
        string sensitiveValue = "This is my top secret value that needs protection by AES 256.";
        byte[] lockedValue = aes.Lock(sensitiveValue);
        string unlockedValue = aes.Unlock(lockedValue);
        Assert.IsTrue(sensitiveValue.Equals(unlockedValue));
        Debug.WriteLine("Sensitive value is: {0}", sensitiveValue as object);
        Debug.WriteLine("Secret key is: {0}", Convert.ToBase64String(aes.SecretKey) as object);
        Debug.WriteLine("Initialization Vector is: {0}", Convert.ToBase64String(aes.InitializationVector) as object);
        Debug.WriteLine("Locked value is: {0}", Convert.ToBase64String(lockedValue) as object);
        Debug.WriteLine("Unlocked value is: {0}", unlockedValue as object);
    }
}
Figure 2: A simple test method that utilizes the class in Figure 1

Debug Trace:
Senstive value is: This is my top secret value that needs protection by AES 256.
Secret key is: bzl6ZmxoU3Z3a2x4YkVLTmdZYkRGTEI5TEVUMTAya0s=
Initialization Vector is: RkJnTlRlYXlxNjBya1R2cQ==
Locked value is: J+wLayRmJIglaHUKSMfFblL75Cz1g5qU2oWrXUU9wVhR8aMbhw0YQPZQ3fTsRfxFYZfHlm1Xp31MD7CdQwIvDw==
Unlocked value is: This is my top secret value that needs protection by AES 256.
Figure 3: The output of the test in Figure 2

When using the AES always provide a new, random and unique IV on each usage. With this in mind, it is perfectly safe to send the IV together with the encrypted value as there is no way to guess the secret key since the output is unpredictable. For more information do take a look at this Wikipedia article.


I hope this little introduction to the AdvancedEncryptionStandardUtility class has proven usefull to you. Happy coding.

Say what? Hash in my code?!

At some point you will eventually find the need to implement a way of either verifying or securing part of your data with the use of cryptographic hash functions. Luckily .NET offers a comprehensive set of classes for this task found in the System.Security.Cryptography namespace.

What is a cryptographic hash function? Well, for a meaningful explanation do refer to this Wikipedia article and afterwards think of it as a digital fingerprint (or checksum if you prefer).

Like i said, .NET offers a comprehensive set of classes to accommodate the need for hashing, and although simple to work with out-of-the-box, it can be rather cumbersome in the long run as you have to remember which algorithm type to use, create a byte array and last but not least; remember to dispose your object afterwards. This is one of the reasons why I introduced the static HashUtility class; to ease the usage while offering a flexible way of hashing your objects.

The overloads taking either a string or a string array in the above mentioned class, all uses UTF-16 as the backing encoding by design, where as most online hashing generators uses UTF-8. However, this can easily be overridden by using of the many overloads of the ComputeHash method.

Supported hash algorithm types per April 24th 2013 is:

  • MD5 (default)
  • SHA-1
  • SHA-256
  • SHA-384
  • SHA-512
  • RIPEMD-160
  • CRC-32

Let's get on with the show; in Figure 1 you can see an example of a simple PasswordHashExample class that will use a SHA256 hash algorithm using UTF-8 for backing encoding, where Figure 2 show an equally simple test method that uses this class. Figure 3 shows the output of the test.


public class PasswordHashExample
{
    public PasswordHashExample()
    {
        this.PasswordSalt = StringUtility.CreateRandomString(32);
    }

    public string PasswordHash { get; private set; }

    public string PasswordSalt { get; set; }

    public void SetPassword(string password)
    {
        this.PasswordHash = this.ComputePassword(password, this.PasswordSalt);
    }

    public bool ValidatePassword(string password)
    {
        return this.PasswordHash.Equals(this.ComputePassword(password, this.PasswordSalt));
    }

    private string ComputePassword(string password, string salt)
    {
        return HashUtility.ComputeHash(new string[] { password, salt }, HashAlgorithmType.SHA256, Encoding.UTF8);
    }
}
Figure 1: A simple class to show a potential usage of the HashUtility class


[TestClass]
public class PasswordHashExampleTest
{
    [TestMethod]
    public void TestPassword()
    {
        string password = "mySuperStr0ngP@ssword!";
        PasswordHashExample example = new PasswordHashExample();
        example.SetPassword(password);
        Assert.IsTrue(example.ValidatePassword(password));
        Assert.IsFalse(example.ValidatePassword("mySuperStrongPassword!"));
        Debug.WriteLine("Password is: {0}", password as object);
        Debug.WriteLine("Salt is: {0}", example.PasswordSalt as object);
        Debug.WriteLine("Hashed password is: {0}", example.PasswordHash as object);
    }
}
Figure 2: An equally simple test method that utilizes the class in Figure 1


Debug Trace:
Password is: mySuperStr0ngP@ssword!
Salt is: FWoyWJxrK6cqS9lL5EFzPp5EMKoGFteP
Hashed password is: 95dae249a69c67654868a59077fae296a532aef39332c919975de5b1e69a60a6
Figure 3: The output of the test in Figure 2

As you can see, the usage is very simple and the only thing you need to consider is the encoding should you choose to use one of the overloads where a string or an array of strings needs hashing. Since all strings in .NET "per se" is UTF-16 encoded, this is also the default here; but only for the string overloads.

I hope you liked this little sneak preview into the HashUtility class. Happy coding.

WebConfigurationUtility - one of the newborns

There are still areas in the .NET Framework where I ask myself why? Why was this obvious method not part of the otherwise comprehensive collection of methods?



What I am talking about here is of course a way to get custom HTTP handlers. For reasons unknown to me, you cannot get a collection of HTTP handlers as you can with HTTP modules on the HttpApplication Class. What you can try instead is to open a web.config file using the WebConfigurationManager Class, but surprisingly this does not provide access to custom HTTP handlers from IIS7+, as this StackOverflow article also confirms.


So what can you do?


Well (for me at least) the most obvious solution was to bypass the ConfigurationManager while supporting elements from it, and simply provide ways to open a Web-application configuration file and afterwards provide ways to get specific areas of this file. I know - one could just parse the XML and find the area of interest them self, but I want to lend a helping hand in these matters so the code is kept as clean without the clutter of XPath expressions.


So, with the above in mind, I decided to create a static class named WebConfigurationUtility shown in Figure 1, where I added the methods i needed up front for my latest development additions while looking for ways to re-factor some of my older code to use these new methods; all while keeping the compatibility to IIS6 and newer.



Figure 1: WebConfigurationUtility members








To provide an example, you can see in Figure 2 that we are opening a Web-application configuration file from the root of an ASP.NET application. From here we call the GetHandlers method which in return gives us an IEnumerable of the HttpHandlerAction Class which we can then iterate and work with as we are used to.

IXPathNavigable webConfig = WebConfigurationUtility.OpenWebConfiguration("/");
IEnumerable<HttpHandlerAction> handlers = WebConfigurationUtility.GetHandlers(webConfig);
foreach (Type endpointType in EndpointRoutes.Keys)
{
    foreach (HttpHandlerAction handler in handlers)
    {
        if (endpointType == CallingAssembly.GetType(handler.Type))
        {
            EndpointHandlers.Add(endpointType, handler);
        }
    }
}
Figure 2: Code snippet from a future Endpoint addition of the Cuemon.ServiceModel assembly

Well, that is all I have for now in regards to the WebConfigurationUtility. I hope this gave a little insight in finding ways to support and - to some extend - improve existing functionality.
Tuesday, April 23, 2013
Posted by Michael Mortensen

A warm welcome to my first blog

Let me start by introducing myself. My name is Michael, I am 35 years of age and currently sole contributor to the Cuemon .NET Framework Additions project, which was first released in 2008.

The main reason for the project back in the days was to:

  • Have a simple, logical and every-day usage additions to the Microsoft .NET Framework that help solves trivial matters
  • Support XML and XSLT in traditional web pages
  • Having a way of defining business entities
  • Having an abstract repository for storage of data for business entities
  • Ease the usage of XML related operations
  • Follow the highly acclaimed book "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" by Krzysztof Cwalina and Brad Abrams
Today this assembly library has grown every so large and continuous to add new ways to extend the .NET Framework from version 2.0 with SP1 and forward; and I will strive to keep it targeted this platform as many projects still rely on this framework version - with a good reason; the CLR is robust, flexible and versatile - and up to this date - even with .NET Framework 4.5, the CLR in 2.0 and 4.0 is very similar to one another.

The Microsoft architects and engineers really did an excellent job with the .NET Framework and i sincerely hope it will inspire others as it did me.



That being said, let me go to the purpose of this blog; it is created to support the Cuemon project with motives and background for implementing an idea, the route to an idea, explanation of how and why i choose to do things the way i do, walk through of the assembly family members and hopefully input from visitors to this blog with feedback as well as new ideas.


Posted by Michael Mortensen

Popular Post

Google+ Followers

© 2008-2013 MuchMore. All rights reserved.. Powered by Blogger.

© 2008-2013 MuchMore. All rights reserved.
Metrominimalist
Powered by Blogger
Designed by Johanes Djogan