Wednesday, August 6, 2014

And then... They took my Optical Drive...



Woke up this morning and my Win7 PC couldn't see the bluray drive.

Went through all the usual suspects (loose connection, uninstall/scan for changes in device manager, safe mode, disabling AV, cursing, praying, more cursing) but I couldn't get it to show up (Windows would always fail on trying to install the driver). Finally, I figured it out. Turns out that when I uninstalled a virtual drive program that I added to install an ISO, the removal didn't complete as successfully as the uninstaller let on...

 To Fix

  1. Open up Regedit 
  2. Expand to: [HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class\{4D36E965-E325-11CE-BFC1-08002BE10318]
  3. Delete the "LowerFilters" value. You might also have to delete the "UpperFilters" value, I didn't.
  4. Restart
  5. Burst into tears of joy

Friday, January 17, 2014

Any List Will Do... : Sharing a Set Between Instances Using C# Generics and LINQ with ListLimitedItem



Introduction

Every so often a class comes along that will truly change your life as a programmer. It will fit in like glue everywhere; binding together all your unfinished code, resolving your past issues, and literally simplifying everything. It might even make your friends like you more.

This, dear reader, is not one of those classes.

It is a helpful class, however. But I'm getting ahead of myself, first let me explain the problem I was facing, and how this class developed. With that perspective I will demonstrate how it works and, if you are still with me, some of the nuts and bolts of its (very quick) implementation. Finally, I'll just provide the class.

The problem was this: I was working on a GUI that contained a spinner control whose databinding would change on the selection of another control. The spinner control's integer value could be selected, or not selected, but if it were selected I wanted that value to be unavailable to the other data references that were using it. In other words, when a value, say "1," was selected and then the reference changed, "1" would be skipped and only 2 through n  would be available.

In the land of metaphors, this would be analogous to a number waiting system at the Department of Motor Vehicles (or insert your favorite government agency here). If you are old enough, you'll remember that this used to be accomplished by a little red machine that had a ticket you would pull, subsequently followed by a decent into madness as you stared at a little "Now Serving Number" sign. But I digress. In this example, the building represents the control. The tickets or numbers are the values in the list, and the people are the data references. Once a person has a number it is unavailable to others. Although it is very much possible for a person to need to leave (maybe their lunch hour is up) and return their number to the pool.

Ok, so the goal was to move this "availability" logic out of the GUI's code and into a container class that would:

  1. Take a shared SortedSet amongst instances.
  2. Provide accessor functions to move up and down the list.
  3. Provide a "neutral" value. That is, a value that is not in the list so a reference could not be holding on to anything.
  4. And, what the heck, since we're doing this... let's do this. Make it a generic so the container will take any type.
  5. Support the increment (++) and decrement (--) operators for those types that support it.

So now that you have the background, let's see it in use.


Usage

Let's start with a caveat. This class was coded towards my convenience and not performance, so it is entirely possible that ListLimitedItem might not scale to your needs (I am using a SortedSet, after all). That being said, for a reasonable number of references and a list measuring less than 1e6, you should be ok. No promises, of course.


Ok let's look at instantiation and use of an int based ListLimitedItem object.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ListLimitedItem;

namespace ListLimitedItemExample
{
    class Program
    {
        static void Main(string[] args)
        {
            //
            // ListLimitedItem with an integer set
            //

            //create a set of ints numbering between 1 and 20
            SortedSet<int> available_nums = new SortedSet<int>(Enumerable.Range(1, 20));

            //lets get rid of 11 - 14 to simulate that these numbers are in use by other
            //instances of ListLimitedItem
            available_nums = new SortedSet<int>(available_nums.Where(x => x <= 10 || x >= 14));

            //we pass in the SortedSet<t> as well as what value is a "neutral" number. If set to the
            //neutral, any existing value is returned to the list and the ListLimitedItem no longer
            //occupies any values. Here we pass in the default for int, which is zero.
            ListLimitedItem<int> testItemInt = new ListLimitedItem<int>(ref available_nums, default(int));

            //testItemInt starts with the neutral value of zero.
            Console.WriteLine("testItemInt Currrent Value: {0}", testItemInt.Value);


            testItemInt.moveUpTo(10); //moves and occupies 10, 10 is removed from the list
            testItemInt.moveUpTo(11); //There isn't an 11, so 14 is occupied. 10 is returned to the list.
            testItemInt.moveUpTo(12); //There isn't a 12, but 14 is already occupied. Since moving up, stay at 14.
            testItemInt.moveUpTo(13); //There isn't a 13, but 14 is already occupied. Since moving up, stay at 14.
            testItemInt.moveUpTo(14); //14 is already occupied. Since moving up, stay at 14.
            testItemInt.moveUpTo(15); //moves and occupies 15, 14 is returned to the list.
            testItemInt.moveUpTo(16); //moves and occupies 16, 15 is returned to the list.
            testItemInt.moveUpTo(20); //moves and occupies 20, 16 is returned to the list.
            testItemInt.moveUpTo(21); //20 is the highest value, and it is already occupied. Since moving up, stay at 20.
            testItemInt.moveUpTo(22); //20 is the highest value, and it is already occupied. Since moving up, stay at 20.

            //testItemInt.moveDownTo(...) follows the same pattern of rules, but in the opposite direction

            //for those classes that implement the increment/decrement operator, the appropriate unary operators can be used.
            //If the object doesn't, nothing happens.

            //move back to the neutral position
            testItemInt.moveDownTo(testItemInt.AllowedNeutralItem);
            testItemInt++; //moves and occupies 1, 1 is removed from the list
            testItemInt--; //1 is the lowest value, and it is already occupied. Since moving down, stay at 1.

        }

    }
}

Alright, so the above example pretty much demonstrates all the class features. The SortedSet stuff is just to create a list from 1 to 20 and remove some values to demonstrate what the class would do when those integers are missing (presumably being held by other references). I didn't want to include other references to keep things simple.

The instantiation just has you passing in the SortedSet, and setting what the neutral item is going to be. The default value of an int is 0.

Next, the moveUpTo(...) method is shown and since it is explained step by step in the comments I'll let it stand at that. Just know that the argument that you are "moving up to" is a request. If that value is not available, the next highest value will be taken. If there are no values greater than the current position, the value stays put. This might mean that the instance remains on the neutral item (not getting any values from the list). The moveDownTo(...) method has the same behavior but, predictably, in the opposite direction of the list. Finally, an example of moving to the neutral item is displayed, followed by an example of using the decrement/increment operators as an alternative for the accessor functions (that is, since int supports them).

NOTE: Only use the decrement/increment operators if you know the type supports them. If it isn't supported, nothing will happen in your code though a costly InvalidOperationException is being swallowed at each attempt (See below).

"But what of a type that isn't a number?" you ask. Let's answer that by looking at a DateTime SortedSet.

            //
            //ListLimitedItem test with a non-numeric
            //

            SortedSet<DateTime> available_dates = new SortedSet<DateTime>();


            //Base after now. When..? Just now. We're at now now.
            DateTime dtime1 = DateTime.Now;

            //As before, let's make a gap and start the next datetime as 4 days from dtime1
            DateTime dtime2 = dtime1.AddDays(4);
            DateTime dtime3 = dtime1.AddDays(5);
            DateTime dtime4 = dtime1.AddDays(6);

            //Just to show that the SortedSet will automatically sort
            available_dates.Add(dtime4);
            available_dates.Add(dtime1);
            available_dates.Add(dtime3);
            available_dates.Add(dtime2);

            //Here let's set the neutral position as the DateTime's MinValue
            ListLimitedItem<DateTime> testItemDateTime = new ListLimitedItem<DateTime>(ref available_dates, DateTime.MinValue);

            testItemDateTime.moveUpTo(dtime1); //move to first position of dtime1. It is removed from the list

            DateTime dtime_target = dtime1.AddDays(3);  //let's purposely create a date that falls in the hole
                                                        //between dtime1 and dtime2... again to simulate that this time
                                                        //is occupied.

            testItemDateTime.moveUpTo(dtime_target); //There isn't a dtime_target value, so dtime2 is occupied. dtime1 is returned to the list. 
            testItemDateTime++; //increment/decrement is not implemented by DateTime. So nothing happens here. Except an invisible InvalidOperationException.

No surprises here. It functions in the same way as an int based set. That is, of course, with the exception of the decrement/increment not being supported and the neutral item is the minimum DateTime value.

"But what if I want to use my own custom type?", you ask. Ok now you are just being difficult. Fine. Here's an example with a class that implements IComparable.

    public class dumbTest : IComparable
    {
        public string Name { get; set; }
        public int Ordinal { get; set; }
        public int NextOrdinal { get; set; }
        public int CompareTo(object obj)
        {
            dumbTest dt = obj as dumbTest;
            if (dt == null)
                throw new InvalidOperationException("The type'" + obj.GetType().Name + "' compare is not supported.");
            if (this.Ordinal > dt.Ordinal)
                return 1;
            else if (this.Ordinal < dt.Ordinal)
                return -1;
            else
                return 0;

        }
    }

And here is the custom type in action:

            SortedSet<dumbTest> available_nums3 = new SortedSet<dumbTest>();

            dumbTest a = new dumbTest();
            a.Name = "a";
            a.Ordinal = 1;
            available_nums3.Add(a);

            dumbTest b = new dumbTest();
            b.Name = "b";
            b.Ordinal = 2;
            available_nums3.Add(b);

            ListLimitedItem<dumbTest> dumblist = new ListLimitedItem<dumbTest>(ref available_nums3, null);
            ListLimitedItem<dumbTest> dumblist2 = new ListLimitedItem<dumbTest>(ref available_nums3, null);

            dumblist.moveUpTo(b); //move to b
            dumblist2.moveUpTo(a); //move to a

And that should be all you need to use it! Next, let's look at a couple of interesting points in the implementation of ListLimitedItem.



Inspection

Since you will have the entire class to look through at your leisure (and since this is already a long post), I'll focus only on a couple of interesting points in the code.

First, let's look at the LINQ used to find the next value. All roads lead to getItem(...), so it is not a surprise that it lives there.

            T next_item = allowed_neutral_item;
            lock (available_items)
            {
                try
                {
                    //If the set has the item, we're done. Otherwise, use LINQ to find the closest
                    //item.
                    if (available_items.Contains(requested_item))
                        next_item = requested_item;
                    else
                        next_item = (isForward) ? available_items.Where(n => n.CompareTo(requested_item) >= 0).First() : available_items.Where(n => n.CompareTo(requested_item) <= 0).Last();
                }
                catch (Exception err)
                {
                    //This should never happen, but in case it does throw a ListLimiteItemException.
                    string base_message = "An exception occured seeking the next list position.";
                    if (err is NullReferenceException)
                    {
                        if (available_items == null)
                            base_message += " The available items internal list is null.";
                        if (requested_item == null)
                            base_message += " The requested item is null.";
                    }
                    throw new ListLimitedItemException(base_message, err);
                }
                available_items.Remove(next_item);
                addBackItem(next_item);
            }

            selected_item = next_item;

This is the heart of the class, I'd say. Most of the other stuff is either gating to here, or list handling (addBackitem(...), for example), but this is what does the actual "finding." When you really look at it, it is pretty straight forward. The next_item variable is set to the neutral value, after which me make an attempt to find their requested value in the list. If it's there, the search is over. If not, we need to find the next nearest so LINQ is used. The ternary operator just divides the direction of the LINQ search: we will find either the last or first item, depending on traversal direction. If something fails unexpectedly in the seek, a ListLimitedItemException is thrown. So your client code should be prepared to handle that.

After the next candidate is found, the item is removed from the availability list, and the previous item (the item the class is giving up for the move) is added back.

The second part of the code I wanted to draw attention to was not my idea, which is of course why I found it interesting. I was trying to think of a way to be able to add an overload for the increment operator on a generic type but wasn't getting there. I found this little gem by Marc Gravell showing how to do so using LINQ Expressions (Note the aforementioned InvalidOperationException that may be caught and swallowed).


        /// <summary>
        /// The overloaded increment operator. If not supported by the underlying type, the 
        /// item is unchanged.
        /// SOURCE: The expression technique, for me at least, can be attributed to Marc Gravell from here: http://www.yoda.arachsys.com/csharp/genericoperators.html
        /// </summary>
        /// <param name="li">Current ListLimitedItem</param>
        /// <returns>The incremented ListLimitedItem</returns>
        public static ListLimitedItem<T> operator ++(ListLimitedItem<T> li)
        {
            if (li.selected_item != null && li.available_items.Count > 0 && li.selected_item.CompareTo(li.available_items.Last()) < 0 && HasIncrementOperator(typeof(T)))
            {
                try
                {
                    if (increment == null)
                    {
                        ParameterExpression paramA = Expression.Parameter(typeof(T), "a");
                        UnaryExpression body = Expression.Increment(paramA);
                        increment = Expression.Lambda<Func<T, T>>(body, paramA).Compile();
                    }
                    li.moveUpTo(increment(li.selected_item));
                }
                catch (InvalidOperationException) { }
            }
            return li;
        }

We basically do a check (to the best of our ability) to see if the increment operator is there. If it is, we create the UnaryExpression for the object and compile it. Spiffy. The check looks like this:


        /// 
        /// This helper function determines if the passed in type has an increment operator.
        /// 
        /// The type to verify it supports an increment operation.
        /// True if the increment is supported, false if not.
        public static bool HasIncrementOperator(Type t)
        {
            if (t.IsPrimitive)
                return true;

            var op_MI = t.GetMethod("op_Increment");
            return op_MI != null && op_MI.IsSpecialName;
        }

The decrement of course works in similar fashion.

But is there a performance cost? Yes. Yes there is. But it is much more pronounced on the first call. Once the expression is compiled, albeit slower, the increment works at an acceptable performance compared to the method call (for my purposes, at least).

Comparison of seek time increment/decrement (++/--) vs method call (UP/DOWN). All times are in milliseconds.

In the interest of brevity, I'll leave it there.




Last Thoughts and the Code

"But I use method x and it works fantastic. Why would you do this?" you ask. Oh, great. You again.  Well I'm sure method x is awesome and I'd love to hear about it. But as the expression goes, there are many ways to skin an algorithm. This just happens to be what I wanted to do. I'm not suggesting this is the only way to do it. I'm not even suggesting this is the best  way. It's just the route I went. If it strikes your fancy, by all means use it. If offends your sensibilities, my deepest apologies to said sensibilities.

On to the "using" portion. There is a license attribution at the top of the code (which the biggest part is you shouldn't remove that bit), but I'll paraphrase it here. You may use it however you like in any endeavor you pursue. All I ask is that you leave the notice on the top of the file and consider coming back here and commenting on how (or if) it helped you. Also this is a completely as-is offering. By using this code you indemnify me of anything that may happen (or not happen) . If your program won't compile, your company fails, your lucky number becomes unlucky... whatever... you absolve me of any responsibility. I also am not making any promise to support it at all. Things are busy, so don't be offended if I don't answer your questions regarding it.

Thanks for reading this long article. And if you just skipped to here: Yes, I am shaming you. For doing what I probably would have done. :o)

ListLimitedItem and ListLimitedItemException
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace ListLimitedItem
{
    /// <summary>
    /// This class is used with a shared finite list of items between its instances
    /// to which a item can only be possessed by one instance.
    /// 
    /// AUTHOR: Scott Myers January, 2014
    /// SITE: http://neuralcorrelates.blogspot.com/2014/01/any-list-will-do-sharing-set-between-csharp-instances.html
    /// LICENSE: For all purposes as long as this attributation stays intact and you agree to use as is and disavow 
    /// the author, Scott Myers, of any
    /// and all damages, real or preceived from its use.
    /// </summary>
    /// <exception cref="ListLimitedItemException"/>
    public class ListLimitedItem<T> where T : IComparable
    {
        #region Fields
        private SortedSet<T> available_items;
        private T selected_item;
        private readonly T allowed_neutral_item;
        static private Func<T, T> increment;
        static private Func<T, T> decrement;
        #endregion

        #region Constructor
        /// <summary>
        /// Neutral item constructor.
        /// </summary>
        /// <param name="available_items">The list to use as limited list</param>
        /// <param name="allowed_neutral_item">A item that, if used, will not be removed from the list.</param>
        public ListLimitedItem(ref SortedSet<T> available_items, T allowed_neutral_item)
        {
            //make sure the neutral number wasn't added to the list by mistake
            if (allowed_neutral_item != null && available_items.Contains(allowed_neutral_item))
                throw new Exception("The neutral item must not be contained in the available items set.");
            this.allowed_neutral_item = allowed_neutral_item;
            this.available_items = available_items;
            if (allowed_neutral_item != null)
                selected_item = allowed_neutral_item;
        }
        #endregion

        #region Properties
        /// <summary>
        /// The number of items still up for grabs.
        /// </summary>
        public int RemainingCount
        {
            get
            {
                return available_items.Count;
            }
        }
        /// <summary>
        /// The current selected value. This might be the AllowedNeutralItem.
        /// </summary>
        public T Value
        {
            get
            {
                return selected_item;
            }
        }
        /// <summary>
        /// A value that, if the Value is set to, represents the instance
        /// currently has no claims on an item in the set.
        /// </summary>
        public T AllowedNeutralItem
        {
            get
            {
                return allowed_neutral_item;
            }
        }
        #endregion

        #region Internal Methods
        /// <summary>
        /// Accessor to move down the list.
        /// </summary>
        /// <param name="requested_item">The item to move down to. If not available, the next lowest will be attempted. If none are available
        /// the current position will be retained (which might be no position if the current is the AllowedNeturalItem).</param>
        /// <returns></returns>
        public T moveDownTo(T requested_item)
        {
            return getItem(requested_item, false);
        }
        /// <summary>
        /// Accessor to move up the list.
        /// </summary>
        /// <param name="requested_item">The item to move up to. If not available, the next highest will be attempted. If none are available
        /// the current position will be retained (which might be no position if the current is the AllowedNeturalItem).</param>
        /// <returns></returns>
        public T moveUpTo(T requested_item)
        {
            return getItem(requested_item, true);
        }
        /// <summary>
        /// Main internal accessor to traverse the list.
        /// </summary>
        /// <param name="requested_item">The item to move to. If not available, the next closest will be attempted (according to direction). If none are available
        /// the current position will be retained (which might be no position if the current is the AllowedNeturalItem).</param>
        /// <param name="isForward">A boolean of whether the list direction is forward. True if so, false if not.</param>
        /// <returns>Next Item (T)</returns>
        /// <exception cref="ListLimitedItemException">If soemthing goes wrong in seeking the next item, the exception is thrown.</exception>
        private T getItem(T requested_item, bool isForward)
        {
            //if we are changing to neutral item, return our item back into the list
            //set to the value and return
            if (allowed_neutral_item != null && allowed_neutral_item.Equals(requested_item))
            {
                lock (available_items)
                    addBackItem(requested_item);

                selected_item = requested_item;
                return selected_item;
            }


            if (available_items.Count > 0)
            {
                if (selected_item != null && !selected_item.Equals(allowed_neutral_item))
                {
                    //This stops movement if the request is to move up yet the current number is greater (or vice versa for moving down the list)
                    if ((((selected_item != null) && (requested_item.Equals(selected_item))) ||
                    (isForward && ((requested_item.CompareTo(selected_item) <= 0) || requested_item.CompareTo(available_items.Last()) > 0)) ||
                    (!isForward && ((requested_item.CompareTo(selected_item) >= 0) || requested_item.CompareTo(available_items.First()) < 0))))
                        return selected_item;
                }

                //if the request overshoots or undershoots the list give the max/min
                //available respectively
                if (isForward && requested_item.CompareTo(available_items.Last()) >= 0)
                    requested_item = available_items.Last();
                else if (!isForward && requested_item.CompareTo(available_items.Last()) <= 0)
                    requested_item = available_items.First();
            }
            else if ((allowed_neutral_item == null && selected_item != null) || (selected_item.CompareTo(allowed_neutral_item) >= 0))
                return selected_item; //if we have a spot, but their no other spots available, stay put.


            T next_item = allowed_neutral_item;
            lock (available_items)
            {
                try
                {
                    //If the set has the item, we're done. Otherwise, use LINQ to find the closest
                    //item.
                    if (available_items.Contains(requested_item))
                        next_item = requested_item;
                    else
                        next_item = (isForward) ? available_items.Where(n => n.CompareTo(requested_item) >= 0).First() : available_items.Where(n => n.CompareTo(requested_item) <= 0).Last();
                }
                catch (Exception err)
                {
                    //This should never happen, but in case it does throw a ListLimiteItemException.
                    string base_message = "An exception occured seeking the next list position.";
                    if (err is NullReferenceException)
                    {
                        if (available_items == null)
                            base_message += " The available items internal list is null.";
                        if (requested_item == null)
                            base_message += " The requested item is null.";
                    }
                    throw new ListLimitedItemException(base_message, err);
                }
                available_items.Remove(next_item);
                addBackItem(next_item);
            }

            selected_item = next_item;

            return next_item;
        }
        /// <summary>
        /// When the instance leaves a position, this method returns it to the list.
        /// </summary>
        /// <param name="next_item">The next item. If it is equal to the current value, nothing is returned to the set.</param>
        private void addBackItem(T next_item)
        {
            if (selected_item != null && next_item != null && !selected_item.Equals(next_item))
            {
                if (!available_items.Contains(selected_item))
                {
                    if (allowed_neutral_item == null || !selected_item.Equals(allowed_neutral_item))
                        available_items.Add(selected_item);
                }

            }
        }
        #endregion

        #region Operator Overloading
        /// <summary>
        /// The overloaded increment operator. If not supported by the underlying type, the 
        /// item is unchanged.
        /// SOURCE: The expression technique, for me at least, can be attributed to Marc Gravell from here: http://www.yoda.arachsys.com/csharp/genericoperators.html
        /// </summary>
        /// <param name="li">Current ListLimitedItem</param>
        /// <returns>The incremented ListLimitedItem</returns>
        public static ListLimitedItem<T> operator ++(ListLimitedItem<T> li)
        {
            if (li.selected_item != null && li.available_items.Count > 0 && li.selected_item.CompareTo(li.available_items.Last()) < 0 && HasIncrementOperator(typeof(T)))
            {
                try
                {
                    if (increment == null)
                    {
                        ParameterExpression paramA = Expression.Parameter(typeof(T), "a");
                        UnaryExpression body = Expression.Increment(paramA);
                        increment = Expression.Lambda<Func<T, T>>(body, paramA).Compile();
                    }
                    li.moveUpTo(increment(li.selected_item));
                }
                catch (InvalidOperationException) { }
            }
            return li;
        }
        /// <summary>
        /// The overloaded decrement operator. If not supported by the underlying type, the 
        /// item is unchanged.
        /// SOURCE: The expression technique, for me at least, can be attributed to Marc Gravell from here: http://www.yoda.arachsys.com/csharp/genericoperators.html
        /// </summary>
        /// <param name="li">Current ListLimitedItem</param>
        /// <returns>The decremented ListLimitedItem</returns>
        public static ListLimitedItem<T> operator --(ListLimitedItem<T> li)
        {
            if (li.selected_item != null && li.available_items.Count > 0 && li.selected_item.CompareTo(li.available_items.First()) > 0 && HasDecrementOperator(typeof(T)))
            {
                try
                {
                    if (decrement == null)
                    {
                        ParameterExpression paramA = Expression.Parameter(typeof(T), "a");
                        UnaryExpression body = Expression.Decrement(paramA);
                        decrement = Expression.Lambda<Func<T, T>>(body, paramA).Compile();
                    }
                    li.moveDownTo(decrement(li.selected_item));
                }
                catch (InvalidOperationException) { }
            }
            return li;
        }
        /// <summary>
        /// This helper function determines if the passed in type has an increment operator.
        /// </summary>
        /// <param name="t">The type to verify it supports an increment operation.</param>
        /// <returns>True if the increment is supported, false if not.</returns>
        public static bool HasIncrementOperator(Type t)
        {
            if (t.IsPrimitive)
                return true;

            var op_MI = t.GetMethod("op_Increment");
            return op_MI != null && op_MI.IsSpecialName;
        }
        /// <summary>
        /// This helper function determines if the passed in type has an decrement operator.
        /// </summary>
        /// <param name="t">The type to verify it supports a decrement operation.</param>
        /// <returns>True if the decrement is supported, false if not.</returns>
        public static bool HasDecrementOperator(Type t)
        {
            if (t.IsPrimitive)
                return true;

            var op_MI = t.GetMethod("op_Decrement");
            return op_MI != null && op_MI.IsSpecialName;
        }
        #endregion
    }
    /// <summary>
    /// This is the general exception that is thrown if something goes very, very wrong.
    /// </summary>
    public class ListLimitedItemException : Exception
    {
        public ListLimitedItemException(string message)
            : base(message)
        {
        }
        public ListLimitedItemException(string message, Exception innerException)
            : base(message, innerException)
        {
        }
    }
}

Wednesday, August 21, 2013

Ubuntu 12.04 and Wireless Not Playing Nice... When on Battery.

Wrong place, wrong time. Story of my life.

I ran into this problem when, in one of my insomiac states, was writing some code on the Linux side of my laptop. In my vantage point it appeared I really broke something. When I booted up, Ubuntu would connect to my Wireless network. At least it said it did... but I couldn't reach the internet. So after a few profanities, I resigned myself to the fact that i wasn't going to sleep just yet. And started the investigation.

First I looked to see what did go right and typed the ubiquitous:

ifconfig -a

This returned and showed that I indeed did have an IP Address leased from my router. It also showed errors on transmit and receipt. Uh-oh. I then tried to ping my router... no dice. I found that if I turned off wireless through my laptop button and turned it back on it worked! But when I rebooted, and it automatically connected, I was back to the problem state.

Head bowed down, I then went off down the troubleshooting-bricked road. Restarted the router. Nope. Checked resolve.conf. Nothing in there. Checked to make sure software and hardware firewalls were behaving. Nice try. and then...

I noticed that the signal strength dropped and was very weak. Even though I was a few feet from the router. "Odd," I thought. But it had to be something to do with what I was working on. Right? Right?!?

It then dawned on me that at my home I'm never on battery power... could it be... could it possibly be an incompatibility with Ubuntu power management on battery and my wireless card (Intel 5100 AGN, for you keeping track at home)?

I began an internet search on this and found that there were indeed issues for some wireless adapters when on battery. I couldn't find a setting to change, but I did find that there was a work around. Basically you create a blank file called "wireless" and copy it to:

/etc/pm/power.d

This is because this blank file is read first and that other power management wireless file located
in /usr/lib/pm-utils/power.d is ignored.

I then rebooted, and low and behold, my problems went down the drain. Get it? Drain? Like battery drain? Ah, never mind.

Of course this might mean shortened battery life, but who cares if you can get some sleep?


Wednesday, August 7, 2013

The Strange Case of Creative's X-Fi Randomly Uninstalling Itself

Flashback to January of 2012. That's when I first put my old Creative X-Fi platinum into my office PC.  Although, like most (if not all) modern Motherboards, mine had on-board audio, I still wanted to install the X-Fi. For one, I liked the fidelity. For another, I liked the break-away box I could install in the front of the case; it gave me a wider variety of connections. Stereo aux-in RCA jacks, MIDI-in and MIDI-out connectors, a quarter-inch headphone and stereo mic/line-in jacks with volume control, plus coaxial and optical S/PDIF inputs and outputs. Oh my.

I've had this setup for awhile and eagerly installed it into the new PC. Everything seemed to install fine (and due to past experiences with Creative drivers causing BSOD, this was a good thing), when, a day later, I noticed that I had no sound. Looking into Sound properties of Windows 7 I could plainly see the "speakers" output was missing. I uninstalled the X-Fi from device manager, rebooted, and everything was back. Besides my settings, of course.

And so began the vicious, frustrating cycle. Well, maybe not vicious... but definitely frustrating.

I tried to figure out what was going on to no avail. Installed the latest drivers, etc. Still from time to time (and with seemingly greater and greater frequency) a reboot would mean I was in the soundless Gulag. Granted, I got a little smarter and, instead of rebooting, I just right-clicked Sound, Video, and Game Controllers in device manager and selected Scan for Hardware Changes. This circumvented the rebooting step but still amounted to a major pain.

I gradually learned to live with it. Occasionally, I'd scour the internet in nerd rage to find some seemingly sensible answer, and time and time again I'd end up (eventually) with no sound. As time rolled on,  my attempts became fewer and fewer; my resolve less solvent. I had regulated my self to the cold, bitter winters of creative re-install land. I had given up.

So almost a year and a half later it happened again. Nothing new there. But something bubbled up within me. Perhaps because it was late. Perhaps because I was sick of being bullied by this hunk of silicon. Or maybe a little of both. I screamed, "Enough!" and decided that I was going to solve this once and for all or relegate the card (and break-away box) to the bin. Either way, I had no plans of letting this cycle continuing any further.

Well unlike my previous searches, I found more info on it. First that I was not alone. And second, it seemed to have something to do with the Creative driver (yeah, not surprised) and  having an SSD. Wow. Leave it to Creative to party like its 1998 with an outstanding driver issue on new but not so new hardware.

 I worked through every post on the Creative thread. All 560 of them. Within were a lot well meaning community provided answers which included different drivers, different uninstall procedures, and even programs to change the driver load order. Nothing worked. I thought I'd try one last thing, and then throw the white flag. I figured I'd move the windows swap file from its place on the SSD to one of my mechanical HDD data drives. I don't know what made me think of that -- probably because it was 4am -- but I figured why not. So I moved the swap file from my SSD to my mechanical HDD.

You know what? It worked. It's been two weeks and nary a re-install in Creative land. I've been basking in the warm glow of constant sound since.

Any repercussions to moving the swap you might ask? I don't think so. If anything, it will prolong the the life of your SSD drive (although the amount might not be too significant). Some people even suggest running without one with machines that contain large amounts of physical RAM -- though I didn't want to do that.

So without further ado, here is a step-by-step of changing your swap file location. I won't be going over how to uninstall/install the creative driver. If you are here, you know how to do that oh too well. And because I never. Want to. Do that. Again. Not even in my mind's eye.


  1. Install the Creative Drivers so they are installed and working. I'm using the SBXF_PCDRV_L11_2_18_0015A drivers for Windows 64-bit.
  2. Click on the Win 7 Orb -> Right-click Computer -> Properties...
  3. In the left pane, click the Advanced Settings link.
  4. Choose the Advanced tab, and in the Performance group box click the Settings... button.
  5. In the Performance Options dialog, select the Advanced tab. Click the Change... button located in the Virtual Memory group box.
  6. This is where the magic happens. (1)Uncheck the Automatically manage paging file size for all drives check box. Select your C drive from the list box (pictured). (2)Select the no paging file radio button. (3)Click the Set button.
  7. Still in the Virtual Memory dialog, select the mechanical HDD you have (in my case, E). Select the System managed size radio button. Click the Set button.
  8. Click Ok 3 times to dismiss all the dialogs. Reboot your machine and enjoy not reinstalling those freaking drivers and trying solutions as, Brian Fantana would say, "60% of the time works everytime."

Saturday, May 4, 2013

The Living Room PC, User Shells, and the Long Logoff Goodbye...

The Turing Box, my HTPC, lovingly named after mathematician
 and computer scientist Alan Turing

In a past post I mentioned that I was building an HTPC of which the lion's share of purpose was going to be towards living room gaming. One of my goals of the project was to create a device that was going to resemble more of a living room appliance (but of which I had full control) than a personal computer. To accomplish this, I removed the Windows branding, changed the login background screens to an image of my own choosing, and even created a custom startup animation (pictured above).

The last piece of the puzzle was removing windows explorer altogether when the user logged in. The visible effect of this is when logging in the user no longer sees the desktop, but instead only sees the application that runs as a shell. Why would one want to do this?

  • Performance - By having this program be the only one running (besides some windows services), it will have majority use of windows resources. This also cuts down on a lot of windows activity that comes along with launching explorer.
  • Start Time - The start time of the program (as a shell) is near instant.
  • Stability - As the only application running, the chance of conflicts decrease.
  • Clarity - When the user goes straight to the shell there isn't any discerning of purpose; you are up and running!
  • Cool Factor - It's just extra geeky cool to build your own appliance!

Now to accomplish this you have to substitute another program as a shell. In this you have a couple of options. You can replace the complete shell or on a by user basis. The complete shell wasn't really what I wanted to do, I wanted the logon screen to be present. I just wanted each user to have a separated shell or concern. Basically, on the Turing Box your "users" are nothing more than buttons to start an activity.

Some of the activities on the Turing Box

So next I'll explain how I setup one activity, "Play," on the box. I'll then talk about a nasty bug I ran into that took trial and error to figure out. Keep in mind this isn't a detailed tutorial, just a discussion about the major things I changed. I won't go into the customization of login background screens or startup animations... maybe in another post!


Setting Steam as the Alternate Shell

NOTE: This article talks about changing your registry. Only attempt if you really do know what you're doing (or could care less about wrecking your PC). Even then, proceed at your own risk. There really isn't anything in here that *should* be that dangerous, but I've seen people dazzle with how much damage they can dole out with seemingly no opportunity.

First things first, you should have one administrator account which is active and not part of these shenanigans. I make the other accounts, normal user accounts. This is to enforce the principle of least privilege for both security and consistency (each of these activities is a concern, or task, and none of them involve installing software). 

So, from within your "Play" account launch Steam and start it in Big Picture Mode (using the "Big Picture" button in the upper right hand corner of the Steam interface). Click the Gear Icon ("Settings") and then select the Account menu item. Finally check the "Start Steam in Big Picture Mode" option.

Setting Steam to start in Big Picture Mode

Note that I am participating in the beta. You don't have to but, at least currently, I'd recommend it. There is a Direct3D bug, causing frequent crashing of the steam client,  that was introduced to Windows 7 through the IE10 install (whether or not you use the browser) and the latest beta client corrects for that. Ok that's it for Steam. Now on to the registry!

It's important that you change the registry key while logged into the "Play" user account. You'll be changing the HKEY_CURRENT_USER key and you wouldn't want to change the wrong one! Go ahead and open regedit (WinKey+R -> type "regedit" without the quotes).

Obviously at this point you'll want to back up your registry. Browse to and export the following key somewhere safe.

[HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Winlogon]

In this key you will want to create a new string value and name it "Shell" (without the quotes).

Add the Shell String Value
Now, Double click on the "Shell" value and add the path to the Steam client. For example:

C:\Program Files (x86)\Steam\Steam.exe

And that's it! If you log off and log on as "Play"  it should go straight to Steam in Big Picture Mode. Now here are a couple of things to keep in mind:


  • Steam right now doesn't have a "Log off" feature from the GUI's power menu. To log off, Press CTRL+ALT+DELETE and select Log off from the menu.
  • To temporarily bring up a desktop (say if steam crashes and all you have is a black screen), simply press CTRL+ALT+DELETE, and start task manager. Click the "New Task..." button on task manager and type "explorer" (without the quotes) followed by enter. That will get you a desktop. Note: In newer versions of windows, this might not be possible to bring up explorer in this way. If you experience this, simply open regedit and change the key to "xShell" signout and sign in and you should see explorer. When done change back to "Shell" signout/sign in. 
  • At any time if you want to restore explorer as the shell, go to the key above logged in as the "Play" user (and be careful that it is the key above), select the shell key value (it should have that Steam path) and delete it. When complete there should not be a value called "Shell" at all there. Log off and log back on and you should be back to the usual Redmond experience!

Logging off is so hard to do...

And that brought me to the proverbial fly in the ointment. Everything was working swimmingly... until I logged off. It took forever. How long varied, but it took over an hour at one point! This behavior did not occur when I logged off with explorer as the shell.

I tried so many things to find out what this was. But every rain dance I tried yielded no, well, rain.

Finally I started from scratch and did a clean boot. This is where you launch msconfig.exe, hide Microsoft services and disable everything. It worked! The log off was under five seconds. I then proceeded to add back in the startup processes and then the services, one by one until it failed. It was the last service. I kid you not. The culptrit? The Broadcom Wireless LAN Tray Service. I disabled this and everything worked as expected!


Last Thoughts

And there you have it. For each user you want to add simply repeat these steps adding a different exe for the shell and you should be good to go. A word of advice if it is a browser: use Firefox and not Chrome. Chrome doesn't render pages properly without explorer running. Not only does firefox render fine, it is naturally written to behave as you would expect in a sort of "Kiosk" mode.

Hopefully this helps you on your quest for the perfect living room PC experience. Happy shelling!

Friday, April 26, 2013

Dealing with old Saves in Bioshock Infinite



I feel a little compelled to say some things myself about Bioshock Infinite, but for now I wanted to share this tip (which I learned the hard way). One thing that is painfully obvious is Papa Bear Levine went without Save Anywhere or Quick Save. What's worse is that you can only do one playthrough at a time. You can save off your current saves (in Steam) by turning off cloud sync in steam AND the game's options and copying off the folder:

[steam install folder]\userdata\remote\[Your Profile ID (a Number)]\8870\remote\savedata\

But what you might notice (when you copy these saves in) especially after a new install, is that when you start a game "Continue," in the gameplay menu, is grayed out. This has to do with the file dates being older than the current date. To get your save to work:

  1. Go to [steam install folder]\userdata\remote\[Your Profile ID (a Number)]\8870\remote\savedata\
  2. Copy off any files you want to save here and then copy in your old saves you want to use. Sort by date.
  3. The one on the top is the newest (or should be) memorize that file name.
  4. Open a command prompt (WinKey + R and then type cmd and hit enter).
  5. In the command prompt, change directories (cd) until you have found thesavedata folder above.
  6. Type copy \b [FileName memorized in step 3].sav +,, (This is sort of the DOS equivalent of the linux touch... and yes, the +,, is necessary)
  7. Hit enter.
  8. You should see that the filename you memorized in step 3, but with a more current date... and "Continue" should now be actionable. 
Now, find the girl and wipe away the debt.

Thursday, December 20, 2012

System Shock 2: Spend the holidays with the Many
(They love you more than your family anyway)



System Shock 2 was, in my opinion, a watershed moment in pc gaming. It (and later, Deus Ex) had the gall to join many game styles into one wonderful narrative experience at a time when it was a firm belief that these were divergent styles of play. Take one part FPS, one part adventure game, 1/2 part role playing game, throw in a dash of survival horror, place in your deep space oven at 2.7 Kelvin for 20 minutes and voila! System Shock 2 will greet you you with a sardonic Shodan laugh. Hacker.

For me the "deep space oven" was Amazon. It was the first non-book product I ever bought from there and, if memory serves, I think it was in the first wave of PC software that you could by from the book selling giant (inject dinosaur sounds here). When it arrived I happily stared at the packaging, and quickly installed. What followed was many fun hours of running through the halls of the Rickenbacker and the Von Braun.

That's not to say that, by today's standards, the game doesn't have some warts. It doesn't run well in Windows 7 (if at all), doesn't support widescreen, the movie playbacks fail, patches are hard to find. That is until a mysterious poster named 'Le Corbeau' posted on the French forum Ariane4Ever. There have been a lot of fixes, over the years, for this beloved game. Texture upgrades, unofficial fixes and such. But this "patch" rolls them up in one easy to use package. Plus the cloak-and-daggerness of this mysterious poster just offering it up out of nowhere gets the mind racing in conspiracy based thoughts: Was this an original developer? Was he or she circumventing Electronic Arts and trying to fix this game? I don't know. But what I do know, is that it works.  I'm going to provide a very short guide on how to use this and other patches to get this working on your system at the end of this article.

I got this running and enjoyed watching, with new eyes, as my girlfiend started her journey. For so long the sound effects of the Rickenbacker were relegated to notifications on my phone (and I have to admit for a few minutes as she clicked on door releases I instinctively wanted to check my phone for text messages), but now I got to hear them again as they were intended. In all their System Shock goodness. So without further adieu (pun intended), here is the guide:

Ok, obviously, you'll need the game. Do not run the installer. From the CD-ROM, extract the contents of the shock folder as sshock2 somewhere. On Windows Vista/7 it is important to copy this to the root and not into the "Program Files" directory. I was able to copy mine into "C:\Games" and it worked fine but I believe some have had trouble with long file names and, believe it or not, this game was built for Windows 98... which was still layered on DOS (inject dying dinosaur sounds here).

First download the mods listed at the end of this article. Come back here when you are done. This article doesn't talk about using the SS2 Mod Manager, but instead just discusses manually installing the mods.

Next the aforementioned awesome patch has been included into the equally awesome SSTool. Run it and it will install the official and unofficial patch. This will also create a folder in the directory called "PermanentDataFolder" which is where you will want to install the texture/model upgrade mods.

Now that you have installed the patches with SSTool, you will be able to extract the mods to beautify the game. How this works is you will open an archive and extract the contents into the PermanentDataFolder located in the sshock2 folder. Keep in mind that the order of which archives you extract first are important and, when it prompts to overwrite files, say "Yes" or "Yes to all."

This is the order of extraction you will want:
  1. SHTUP
  2. Rebirth
  3. ADaOB
  4. Tacticool Weapons (any order for these zips)
You should be able run System Shock 2 at this point. How easy was that?!? But before you start there is one more modification you may want to make...

And that modification is to create a user.cfg file to change how the game plays. This is something that was added with the last official patch. Some mechanics that some people weren't thrilled by was the random spawning of enemies and periodic degradation of weapons. You might love those things... or you might be one of those people who don't. If you count yourself among those who like to catch your breath every once in awhile (there are parts where spawning will continue, no matter what you do), create a text file and paste these contents into it:

[OPTIONS]
/s
/n="System Shock 2"
[REQUIREMENTS]
no_spawn
gun_degrade_rate 0

You might want to tweak the gun_degrade_rate variable to taste. "0" means no degradation happens at all while "1" means weapons degrade at the normal rate. "0.5" would then be halfway between the two. Obviously not including an option will result in that option behaving as intended by the original devs (omitting no_spawn, for example).   After you are satisfied save it as user.cfg (make sure you have windows not set to hide extensions of known types or notepad will append an invisible ".txt" to the end. In Windows Explorer -> Organize -> Folder and Search Options -> View Tab and uncheck "Hide extensions for known file types"). Copy this file into the sshock2 folder.

That's it! You can now double click on sshock2.exe and you should be good to go. As an added "retro" plus, you might want to add it as a "non-steam shortcut" to your steam library. If you do that, and rename it to "System Shock 2," you will blow your friends minds as they see your status as "In-Game System Shock 2."

I hope this post was helpful. Enjoy the game that inspired Bioshock, and revel in the fun that can be had in just a few hundred megabytes totaling to a story created over 13 years ago.

And, of course... Happy holidays pathetic insect.





All files show latest version as of time of this article.

[: Patcher :]

SSTool v4.4

[: Textures :]

SHTUP Beta 6

[: Lighting :]

ADaOB v0.3.0

[: Models :]

System Shock 2 Rebirth v02.7
Of these you will want:
  •  TC_Pistol_ADaoB028-compatible_v1.1b.ss2mod (Rename this to .zip!!)
  •  Tacticool_Wrench_Replacement_v1.0.zip
  •  Tacticool_Shotgun_Replacement_v1.0.zip
  •  Tacticool_Laser_Pistol_Replacement_v1.1.zip
  •  Tacticool_Assault_Rifle_Replacement_v1.0.zip
  •  Tacticool_Grenade_Launcher_Replacement_v1.0.zip



Wednesday, November 21, 2012

On the Right Track: Nordictrack Treadmill Connection Problems

The beautiful green wireless icon in all of its glory
So a few years ago I bought a treadmill. A Nordictrack 1750 Commerical, to be exact. Saving the time I had to have a roller replaced (get the 3 year in home warranty!) it has really been a great treadmill and, given my predilection for all things computer-y, it was an easy choice back then because it had a built-in wireless adapter that connected to their ifit online service. The service has a way to go, but certainly shows promise.

That is, if I could get to it.

I couldn't get the damn adapter to connect to my network with the default firmware in it. I tried removing the encryption from the network, getting a wireless repeater, everything. What's worse, there isn't any other way to update the firmware on the machine. When I did a network test through the "Settings" menu it always failed.

That's when it got weird. The machine was on the network. It just didn't know it was. I learned the secret handshake to leave the confines of nordictrack's menu and go to the underlying linux distro underneath (if anyone's interested in the steps for this let me know in the comments). The process to get to Linux was akin to hidden entrance scenes from the old gothic movies of the 50's, where the hero would pull out a certain book from the library's bookshelf that would then give way to a secret passage. At any rate, once there I was able to surf the web using the midori web browser. Followed by me screaming to the heavens, "Why?!?"

So I tried everything to figure this out. I was sure if I got the latest firmware everything would probably work, but I was in a catch-22. To get the firmware to make the network function I had to get on the network. Enter in trying all permutations of everything (including sacrificing of random chickens) when I finally was able to pull it off! Just in case someone falls into this mire, and stumbles upon this post, I'll write it below:

Note: This is for an older Commercial 1750. This problem may not exist with newer default firmware and models. Your mileage may vary.
  1. Enter in your network information as usual (see your treadmill's instructions for help with that). You may need to reset to the default firmware first, if you've been tinkering for awhile.
  2. Going to settings (Main Menu -> "I" in lower right -> Gears Icon in lower right), you will see that the network status indicator shows a red dot.
  3. At this point, attempt to login to iFit (Main Menu -> "Workouts" -> "Live Workouts"). It will hang but the wireless icon in the upper right hand corner will appear and be yellow.
  4. Cancel out of the login.
  5. Go to the settings (Main Menu -> "I" in lower right -> Gears Icon), and select Firmware Update. Follow the instructions (which will include a power cycle).
  6. You should be on the latest firmware and Boom! Everything should work now.
Settings Screen
Network status Indicator  (That green network dot can be yours!)



Wednesday, October 3, 2012

[: That's the sound of the world breaking... :]

Once, many years ago,  a friend of mine (you know who you are) offered me a diet coke, to which I shrank back in revulsion and offered that I would rather be... well let's just say I said that I'd rather be terribly maimed by a member of Florida fauna... than drink diet soda.

Fast forward quite a few years later to which that same friend's jaw dropped when he watched me order a diet soda in a restaurant. I nodded. Not only had my tastes changed, I could no longer drink regular soda. Hyperbole and pride aside, I just couldn't.

Well with social networking and blogs I found myself, unbeknownst to me, in the same exact waters. I just couldn't see how I would ever use either thing. The novelty of "oh-wow-I-can-talk-to-strangers-around-the-world" had already faded long before the invention of either technology.

Yeah, I know. This is a blog.

So, I'm going back on a lot of diatribe here. A lot of diatribe. I am officially offering up my soul to social networking and the aging blogosphere. For many years I have single-handedly declared that I would never use them. Not that I had taken issue with them as a whole; I just couldn't  think of a reason why I would ever use either platform. So the first question would be:

Who cares?

That of course would be anyone who wanted to say, "I told you so." The second question (mainly for those folks would care about the first question) would be:

Why?

For the most part I want to connect with friends and family who, throughout the years, have moved away. Or have started families. Or both.

So am I going to be a daily blogger? No. Will I use this to share longer style posts that won't fit in social media? Yes. Just little posts between my friends, family, and I. Plus the rest of the world.

Who knows, I just might throw in tidbits on programming, PC gaming, writing, and robotics as well.

Weird. Perhaps Chuck Norris was right when he said that there was a harbinger at hand of a thousand years of darkness, and he just mistook it for this election cycle. Maybe the tremor he felt was from the fact that Scott was now blogging. And drinking diet soda.

Tuesday, September 25, 2012

[: PC in a Shoebox :]

UPDATE: I've since replaced the LG Electronics DVD drive with a Panasonic Blu-ray one and added a Samsung 840pro SSD for the data drive (relegating the WD HDD to a backup drive). This is reflected below.


So in comparing the PC apple to the console orange there are really only a couple of categories you must award an edge to the Console (which is, of course, itself a budget PC): Price, and the "couch factor."

Price is actually a little dicey. It's more like a "buy-in" price, where the console wins. If you start looking at things like cost of ownership and maybe a price per value kind of thing, the PC starts to get a lot more competitive. A PC is ready to customize. Dying to be customized, in fact. This versatility might make its money back to its owner as you can use it for a myriad of things, in literally any way you want to. Coupled with digital distribution game sales on platforms such as Steam, the PC allows their owners to buy games at a much cheaper rate (due to the lack of royalty on the Windows platform) than its console brethren.

The "couch factor" as it were, allows for you to play video games slumping on your couch, with Doritos stained orange fingertips mashing on a controller as -- according to many -- God intended. I'm not always the biggest fan of this idea, in part, due to the fact the controllers just don't have the resolution that the keyboard/mouse combo have. I also am not a fan of the lower resolution on TVs, and the speed of the hardware found on today's aging consoles. But even after saying all that, there is a real argument here; sometimes you just want to slump in front of the TV and play your games. That, and if you want to make this a social thing, particularly in sports games... it really is a better experience.

So I wanted to have my Doritos cake and eat it too. I did not want to sacrifice quality for the "buy-in" price of a console and was quite willing to invest in a mini-living room PC that would provide gaming, media, and more. And so began my quest to build the shoebox PC!

First, in this example I'm shelling out a decent amount of dough. As I said, I wanted to future-proof this purchase.

[: The Shopping List :]

SilverStone SST-SG08B Black  Mini-ITX Desktop Computer Case 600W Power Supply
ASUS P8Z77-I Deluxe LGA 1155 Intel Z77 Mini ITX Intel Motherboard
Intel Core i7-3770K Ivy Bridge 3.5GHz (3.9GHz Turbo) LGA 1155 77W Quad-Core
(2) CORSAIR Vengeance LP 8GB 240-Pin DDR3 SDRAM DDR3 1600
EVGA GeForce GTX 670 FTW 2GB  Video Card
Kingston HyperX 3K SH103S3/240G 2.5" 240GB Internal Solid State Drive (SSD) (System Drive)
Samsung Electronics 840 Pro Series 512gb SSD (Data Drive)
Western Digital Blue WD10EALX 1TB 7200 RPM SATA 6.0Gb/s 3.5" HDD (Backup Drive)
Logitech Wireless Combo MK260 920-002950 Black USB RF Wireless Standard Keyboard and Mouse
LG Electronics - Slim DVD±RW Drive
Panasonic UJ240 6x Blu-ray Burner BD-RE/8x DVD±RW Drive
Microsoft Windows 7 Home Premium SP1 64-bit - OEM

So you can see cost could be easily trimmed on memory, storage, and even processor model. But if you want to be an enthusiast, go big!

The items on the list that really "make" a mini-pc are the case and the motherboard. And in this setup I went with the Silverstone SG08B for the case and the Asus P8Z77-I Deluxe for the motherboard.

The Silverstone case dimensions are quite small at 8.75" x 7.49" x 13.82" (WxHxD), and it's black aluminum finish allow it to fit in aesthetically quite easily with other home theater components. It uses a positive pressure system: a single 180mm fan on top of the case blows air through the case and pushes out through the side venting. Early on I decided to use stock cooling (as this was not going to be an overclocked system), so this seemed a-OK with me.  Note: I did see a review where they successfully swapped this fan out with a radiator and closed watercooling system.


All that stuff has gotta go in that little black box

The case comes with a 600W power supply -- more than sufficient for a mini-pc system. It is, unforunately not modular. This seems to be a strange design choice for such a small space! It would be theoretically possible to swap it out with a modular one, but you will have to do your research... it is a tight fit with the video card.











A lot of performance packed into a tiny space

The Asus P8Z77-I Deluxe was chosen for the motherboard do its high performance reviews as a Mini-ITX board and the inclusion of a built in wireless radio. Wires... the natural enemy of living rooms since ancient times. 












[: Putting it all Together :]

Ok so the next step is putting all the pieces together. I was pretty nervous as this was my first Mini-ITX build and, unlike more traditional builds, requires more attention to spatial details. It went pretty fast, actually. I was sick when I did it, so I did a couple of bonehead things along the way
(including using the part that was meant to be discarded for the VGA duct and almost throwing away the actual duct), but I made it through pretty well.

The Asus P8Z77-I Deluxe installed

The first thing I noticed after installing the motherboard was just how tiny it actually was! It went in without a hitch.














Cable management. Early and often

Cable management was one of the hardest things to do in this build. It was a constant process of planning, tying, fitting a component, and the re-evaluating the cable positions.










Already starting to get crazy...
even before the video card is installed
(that groove to the left will be its home)






















Gigantic Video Card. Check.

The most challenging component to install was the full sized video card. This was easily the hardest step. After much patience (and by patience, I mean swearing) I was able to install the card from the side and click into place.











Hard drive cage, Slim DVD drive, and fan installed

Finally the HDD cage, fan, and DVD drive were installed. This added the last roadblock; trying to get these components in and cables placed in a way to allow for the case to close properly.












Reporting for duty

















[: Temperatures :]

With a mini-case comes hight temperatures. Or do they? Let's take a look.

For GPU stress testing I used Real-Time HDR IBL while for CPU stress testing I used Prime95. The 180mm fan has two settings: High and Low. All tests were run with both fan settings. All temperatures are in Celsius.

CPU Testing

Idle (Fan on Low)

CPU Average 31 (31 33 30 30)

Idle (Fan on High)

CPU Average 29 (29 30 28 28)

Prime95 small fft (Fan on Low)

CPU Average 81 (79 78 81 85)

Prime95 small fft (Fan on High)

CPU Average 79 (77 75 79 83)


GPU Testing

Idle (Fan on Low)

GPU 35

Idle (Fan on High)

GPU 35

[rthdribl.exe] 1720x982 GPU Fan auto (Fan on Low)

GPU 78

[rthdribl.exe] 1720x982 GPU Fan auto (Fan on High)

GPU 78



These temps seem fine for stock cooling. With a TJMax of 105C, definitely nothing to worry about!. The GPU also appears to have very nice temps for such an enclosed space (its safe max is 97C).

We can see that the 180mm settting really only buys about 2C on cpu temps (and none on GPU) so it would be fine in this setup to keep on low and save the noise.

[: Conclusion :]

The only negatives were the aforementioned non-modular power supply and my data drive (WD10EALX) was a little loud in access. This wasn't noticeable with anything that has sound  (games, movies, music) so I'm not too worried about it(No access noise with the new 840 Pro SSD!).

As a major coincidence the very next day after I put this system together Valve released the "Big Picture Mode" for the Steam beta client (an interface designed for High Definition TVs). Talk about meant to be!

Rise... Steam. RIIIIISE!

It looks beautiful on a 1080p TV (although for fidelity nothing beats a good monitor) and thanks to the Steam Cloud, I can play my steam games interchangeably between the two locations.

The budget wireless keyboard/mouse combo I bought works surprisingly well. Although to be safe I disabled the 2.4GHz radio on the motherboard and am only using 5GHz (to prevent interference).

Now all I need to do is invest in a couple of game controllers (for sports games) and a bag of Doritos. Game on!