Widgets WilliaBlog.Net | I dream in code


I dream in code

About the author

Robert Williams is an internet application developer for the Salem Web Network.
E-mail me Send mail
Go Daddy Deal of the Week: 30% off your order at! Offer expires 11/6/12

Recent comments




Code Project Associate Logo


The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

Windows Update Site Not Working

If you have a Laptop that is normally attached to your company's Network Domain, you may find that when you are roaming in the field, the Windows Update site does not work. The reason for this is simple. The group policies of your domain force your laptop to obtain its updates from the local network, rather than the internet. However, if you are rarely connected to the domain, this makes checking for optional updates rather difficult. One solution that I found to work is to manually re-register the Windows update components.

Click Start > Run > Type the follow commands in the box (one at a time, in sequence): 

REGSVR32 C:\WINDOWS\system32\wuapi.dll

REGSVR32 C:\WINDOWS\system32\wuauclt.exe

REGSVR32 C:\WINDOWS\system32\wuaueng.dll

REGSVR32 C:\WINDOWS\system32\atl.dll

REGSVR32 C:\WINDOWS\system32\wucltui.dll

REGSVR32 C:\WINDOWS\system32\wups.dll

One of these may not appear to work properly, but nevertheless, the whole sequence solved the problem for me.

Categories: XP
Posted by Williarob on Wednesday, December 10, 2008 7:38 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Virtual PC Cannot Access Host Via Network

I just installed Microsoft Virtual PC on Windows Vista Ultimate x64 sp1. I then installed Windows XP sp3 into a new Virtual Machine. The Virtual XP machine could not access the network shares on the host. It could access shares on other PCs in my workgroup, and I verified that file and print sharing, public folder sharing, firewall settings, etc. on the host was all correctly configured. The workgroup name matched, it could even see the host, but kept giving me an error that I did not have permission to access this resource, and suggested I contact the administrator - not much help when you are the administrator.

In my case, the solution was to increase the IRPStackSize value in the registry:

  1. Backup your Registry!
  2. Run regedit.
  3. Navigate to the following key: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanmanServer\Parameters
  4. In the right pane, double-click the IRPStackSize value.

    NOTE If the IRPStackSize value does not already exist, use the following procedure to create it:
    •  In the Parameters folder of the registry, right-click the right pane.
    • Point to New, and then click DWord Value.
    • Type IRPStackSize.

      IMPORTANT: Type "IRPStackSize" exactly as it is displayed because the value name is case-sensitive.

  5. Change the Base to decimal.
  6. In the Value Data box, type a value that is larger than the value that is listed. If you created the IRPStackSize value using the procedure described in step 4, the default value is 15. It is recommended that you increase the value by 3. Therefore, if the previous value was 11, type 14, and then click OK.
  7. Close the Registry Editor and restart the computer.

If the problem persists after you complete the preceding procedure, try to increase the value of IRPStackSize even more. The maximum value is 50 (0x32 hex). I expect that this solution would also work for similar problems encountered when running a virtual machine in VMware.

Categories: Virtualization
Posted by Williarob on Wednesday, December 03, 2008 6:26 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Instantly Increase ASP.NET Scalability

Each time a request for a .NET resource (.aspx, page, .ascx control, etc.) comes in a thread is grabbed from the available worker thread pool in the worker process (aspnet_wp.exe on IIS 5.x, w3wp.exe on IIS 6/7) and is assigned to a request. That thread is not released back into the thread pool until the final page has been rendered to the client and the request is complete.

Inside the ASP.Net Worker Process there are two thread pools. The worker thread pool handles all incoming requests and the I/O Thread pool handles the I/O (accessing the file system, web services and databases, etc.). But how many threads are there in these thread pools? I had assumed that the number of threads would vary from machine to machine – that ASP.NET and IIS would carefully balance the number of available threads against available hardware, but that is simply not the case. ASP.Net installs with a fixed, default number of threads to play with: The CLR for the 1.x Framework sets these defaults at just 20 worker threads and 20 I/O thread per CPU. Now this can be increased by modifying the machine.config, but if you are not aware of this, then 20 threads is all you’re playing with. If you have multiple sites sharing the same worker process, then they are all sharing this same thread pool.

So long as the number of concurrent requests does not exceed the number of threads available in the pool, all is well. But when you are building enterprise level applications the thread pool can become depleted under heavy load, and remember by default heavy load is more than just 20 simultaneous requests. When this happens, new requests are entered into the request queue (and the users making the requests watch an hour glass spin). ASP.NET will allow the request queue to grow only so big before it starts to reject requests at which point it starts returning Error 503, Service Unavailable.

If you are not aware of this “Glass Ceiling of Scalability”, this is a perplexing error – one that never happened in testing and may not reproducible in your test environment, as it only happens under extreme load.

So the first thing you can do to improve scalability is to raise the values. The defaults for the ASP.NET 2.0 are 100 threads in each pool per CPU and the defaults for the ASP.NET 3.x CLR is 250 per CPU for worker threads and 1000 per CPU for I/O threads, however you can tune it further using the guidelines below. 32 bit windows can handle about 1400 concurrent threads, 64 bit windows can handle more, though I don’t have the figures.

You can tune ASP.NET thread pool using maxWorkerThreads, minWorkerThreads, maxIoThreads, minFreeThreads, minLocalRequestFreeThreads and maxconnection attributes in your Machine.config file. Here are the default settings.

     <add address="*" maxconnection="2" />
  <httpRuntime minFreeThreads="8" minLocalRequestFreeThreads="4"  />
  <processModel maxWorkerThreads="100" maxIoThreads="100"  />

Here is the formula to reduce contention. Apply the recommended changes that are described below, across the settings and not in isolation.

  • Configuration setting Default value (.NET Framework 1.1) Recommended value
  • maxconnection 2 12 * #CPUs
  • maxIoThreads 20 100
  • maxWorkerThreads 20 100
  • minFreeThreads 8 88 * #CPUs
  • minLocalRequestFreeThreads 4 76 * #CPUs
  • Set maxconnection to 12 * # of CPUs. This setting controls the maximum number of outgoing HTTP connections that you can initiate from a client. In this case, ASP.NET is the client. Set maxconnection to 12 * # of CPUs.
  • Set maxIoThreads to 100. This setting controls the maximum number of I/O threads in the .NET thread pool. This number is automatically multiplied by the number of available CPUs. Set maxloThreads to 100.
  • Set maxWorkerThreads to 100. This setting controls the maximum number of worker threads in the thread pool. This number is then automatically multiplied by the number of available CPUs. * Set maxWorkerThreads to 100.
  • Set minFreeThreads to 88 * # of CPUs. This setting is used by the worker process to queue all the incoming requests if the number of available threads in the thread pool falls below the value for this setting. This setting effectively limits the number of requests that can run concurrently to maxWorkerThreads – minFreeThreads. Set minFreeThreads to 88 * # of CPUs. This limits the number of concurrent requests to 12 (assuming maxWorkerThreads is 100).
  • Set minLocalRequestFreeThreads to 76 * # of CPUs. This setting is used by the worker process to queue requests from localhost (where a Web application sends requests to a local Web service) if the number of available threads in the thread pool falls below this number. This setting is similar to minFreeThreads but it only applies to localhost requests from the local computer. Set minLocalRequestFreeThreads to 76 * # of CPUs.

Note The recommendations that are provided in this section are not rules. They are a starting point. Test to determine the appropriate settings for your scenario. If you move your application to a new computer, ensure that you recalculate and reconfigure the settings based on the number of CPUs in the new computer.

By raising these values, you raise the “glass ceiling of scalability”, and in many cases that may be all you need to do, but what happens when you start getting more than 250 simultaneous requests? To make optimum use of the thread pool all IO requests that you know could take a second or more to process should be made asynchronously. More information on Asynchronous programming in ASP.NET is coming soon.

I recommend testing your new machine.config locally or virtually somewhere first because if you make a mistake - for example you paste this in to the wrong area, or there is already a <system.web> element and you paste in a second one - ALL websites on the box will stop functioning as ASP.Net will not be able to parse the machine.config!!!

Posted by Williarob on Tuesday, December 02, 2008 7:41 AM
Permalink | Comments (1) | Post RSSRSS comment feed

Add Asynchronous Data Methods to the Enterprise Library

A Data Access Layer that does not support Asychronous I/O is not scalable. Period. However, since Microsoft kindly provided the source code along with the Enterprise Library, it is possible to make the Enterprise Library's Data Application Block scalable by adding the Asynchronous methods (BeginExecuteNonQuery, BeginExecuteReader, etc.) to the SQL Database Object. I took the code from the 3.x library and modified the file SqlDatabase.cs found here c:\EntLib3Src\App Blocks\Src\Data\Sql (assuming you installed the source files to the root of your C drive). The following download includes the modified binaries and my SqlDatabase.cs code file: (348.39 kb)

I don't think I implemented every overload, and again this is for the 3.0 library, but you should be able to modify the 4.x libraries and add more overloads by following the patterns I'm using. To use the binaries included in the zip file above, simply drop them into the bin folder of your web site or web application project, add references if necessary and don't forget to add the async=true attribute to both your <% page %>  tag and your connection string! Here is a simple example of how you might use it, to get you started:


    1 using System;

    2 using System.Collections;

    3 using System.Configuration;

    4 using System.Data;

    5 using System.Data.SqlClient;

    6 using System.Linq;

    7 using System.Web;

    8 using System.Web.Configuration;

    9 using System.Web.Security;

   10 using System.Web.UI;

   11 using System.Web.UI.HtmlControls;

   12 using System.Web.UI.WebControls;

   13 using System.Web.UI.WebControls.WebParts;

   14 using System.Xml.Linq;


   16 public partial class temp : System.Web.UI.Page

   17 {

   18     protected void Page_Load(object sender, EventArgs e)

   19     {

   20         if (!IsPostBack)

   21         {

   22             RegisterAsyncTask(new PageAsyncTask(new BeginEventHandler(BeginUpdateByAsyncEL), new EndEventHandler(EndUpdateByAsyncEL), new EndEventHandler(AsyncUpdateTimeout), null, true));

   23         }

   24     }


   26     /// <summary>

   27     /// Creates a SqlDatabase Object and stores it in HttpContext for the duration of the request.

   28     /// </summary>

   29     /// <value></value>

   30     /// <returns>A SqlDatabase Object</returns>

   31     /// <remarks></remarks>

   32     public static Microsoft.Practices.EnterpriseLibrary.Data.Sql.SqlDatabase AsyncNorthWindDB

   33     {

   34         get

   35         {

   36             if (HttpContext.Current == null)

   37             {

   38                 return new Microsoft.Practices.EnterpriseLibrary.Data.Sql.SqlDatabase(WebConfigurationManager.ConnectionStrings["AsyncNorthwind"].ConnectionString);

   39             }

   40             if (HttpContext.Current.Items["AsyncNorthWindDB"] == null)

   41             {

   42                 HttpContext.Current.Items.Add("AsyncNorthWindDB", new Microsoft.Practices.EnterpriseLibrary.Data.Sql.SqlDatabase(WebConfigurationManager.ConnectionStrings["AsyncNorthwind"].ConnectionString));

   43             }

   44             return HttpContext.Current.Items["AsyncNorthWindDB"];

   45         }

   46     }


   48     /// <summary>

   49     /// Begins an asynchronous call the the Northwind Database 

   50     /// </summary>

   51     /// <param name="sender"></param>

   52     /// <param name="e"></param>

   53     /// <param name="cb"></param>

   54     /// <param name="state"></param>

   55     /// <returns>An IAsyncResult Interface</returns>

   56     /// <remarks>These methods do not exist in the standard Enterprise Library</remarks>

   57     public IAsyncResult BeginUpdateByAsyncEL(object sender, EventArgs e, AsyncCallback cb, object state)

   58     {

   59         SqlCommand cmd = new SqlCommand("Update Products SET UnitPrice = 79.0 WHERE productID = 20");

   60         return AsyncNorthWindDB.BeginExecuteNonQuery(cmd, cb, state);

   61     }


   63     public void EndUpdateByAsyncEL(IAsyncResult ar)

   64     {

   65         AsyncNorthWindDB.EndExecuteNonQuery(ar);

   66     }


   68     /// <summary>

   69     /// Async Timeout method

   70     /// </summary>

   71     /// <param name="ar"></param>

   72     /// <remarks></remarks>

   73     public void AsyncUpdateTimeout(IAsyncResult ar)

   74     {

   75         Label1.Text = "Connection Timeout";

   76     }

   77 }


Download the Full Enterprise Library (including the complete source code) from


kick it on

Posted by Williarob on Monday, December 01, 2008 8:50 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Begin/End Async WebService Proxy Methods No Longer Generated

If you have added a Web Reference for a Web Service recently you may have noticed that the wsdl tool no longer creates Begin and End methods for you, instead it implements what is known as the Event based Async Pattern. Which is fine if you are building a Windows or Console application, but if you are trying to call a web service asynchronously using the AddOnPreRenderAsync or RegisterAsyncTask methods in ASP.NET you really need a Begin method that returns an IAsyncResult Interface. There are several ways you can work around this.

You could, assuming you still have it, create a project in Visual Studio 2003, add the web reference there and copy it to your 2005 project, or you can run the wsdl tool manually and use the /parameters option to specify a configuration file with the "oldAsync" flag. For example, for a reference to, which creates a proxy class with both begin/end (a.k.a. "old style") and event-based (a.k.a. "new style") methods, you'd use the command

  wsdl.exe /parameters:MyParameters.xml

Where MyParameters.xml is as below:


<wsdlParameters xmlns="">
    <codeGenerationOptions>properties oldAsync newAsync</codeGenerationOptions>

However, my preferred method is to set a project level property WebReference_EnableLegacyEventingModel to true.

To do that, you need unload the project from Visual Studio, and edit the project file directly in a text editor. (I recommend creating a backup first)

In the first section of PropertyGroup, you will see many properties like:


Don't change any of those, but do add a new property into that section:


Save the file, and reload the project into Visual Studio.

After that, you have to regenate all proxy code (by updating the reference, or running the custom tool on the .map file)

This is my preferred method because unlike the others I described, this one lets you refresh or update the web reference as normal, which if your project is shared with other developers is a big plus!

Posted by Williarob on Monday, December 01, 2008 7:12 AM
Permalink | Comments (2) | Post RSSRSS comment feed

Accessing Global Resource Files from a Class Library in ASP.NET

If you add an App_GlobalResources Folder to your 2.0 web application you may want to access some of the values within it from a class library - such as a Business Logic Layer (BLL). Since there is unlikely to be a reference from your BLL to the main site, and even if there were, the designer class that shadows the resource file is declared with "Friend" keywords so that class would not be visible to the BLL. Therefore trying to call it using the Resources.[Filename].[key] syntax that works from anywhere within the site will not work. Instead you can simply create a wrapper like the following somwhere within your class library:

    1 Imports System.Resources

    2 Imports System.Web


    4 Namespace Resources

    5     Public Class ResourceWrapper


    7         Public Shared Function Strings1(ByVal key As String) As String

    8             Return HttpContext.GetGlobalResourceObject("Strings1", key)

    9         End Function


   11         Public Shared Function Strings2(ByVal key As String) As String

   12             Return HttpContext.GetGlobalResourceObject("Strings2", key)

   13         End Function


   15         Public Shared Function Strings3(ByVal key As String) As String

   16             Return HttpContext.GetGlobalResourceObject("Strings3", key)

   17         End Function


   19     End Class

   20 End Namespace


Then you can retrieve values from the resource files from within your class library simply by passing in the key you want to retrieve:




This example assumes that you have created three .resx resource files inside the App_GlobalResources folder of an ASP.Net Web Application, and that you created them within Visual Studio (as opposed to a text editor for example), and that you named the files "Strings1.resx", "Strings2.resx" and "Strings3.resx", and that Strings1.resx contains the key "SupportEmail".


The Great thing about adding .resx files in this fashion is that you can actually edit the values in a text editor on the live site without having to recompile and republish your entire project. Having said that, adding new key value pairs in the text editor will not create the properties in the class that shadows it, and removing or renaming existig key value pairs could cause runtime errors so if you need to do anything other than change the value of an existing key, do so within visual studio and republish.

Posted by Williarob on Thursday, November 20, 2008 6:06 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Silverlight 1.0 Applications Not Working in Firefox 3.x

If, like me, you suddenly noticed that your silverlight 1.0 application no longer works in Firefox 3.0 then all you need to do is to update your silverlight.js file to the latest version: Download it here: (3.58 kb)

Categories: Silverlight
Posted by Williarob on Thursday, November 20, 2008 7:15 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Could not load file or assembly 'System.Web.Abstractions, Version=, Culture=neutral, PublicKeyToken= 31bf3856ad364e35' or one of its dependencies.

If you had tried to visit this site in mid-November, this is the ugly error message you would have received: "Could not load file or assembly 'System.Web.Abstractions, Version=, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies". My last update had been 2 full weeks before the site went down. My hosting provider (GoDaddy) assures me that nothing has changed at their end, I knew nothing had changed at my end and the last modified dates of my files on their server reflected this. A republish of the site did not help. Deleting all the files from the server, testing it locally (which worked even though I did not have the missing assembly on my PC) and republishing did not resolve the issue. So while I still have no idea why my project suddenly requires the System.Web.Abstractions.dll assembly I did at least figure out how to bring it back online. First I downloaded the Microsoft ASP.NET MVC Beta installer and ran it on my local machine. Then I searched my hard drive for the System.Web.Abstractions.dll file again and found it here: "C:\Program Files\Microsoft ASP.NET\ASP.NET MVC Preview 3\Assemblies". I FTP'd the file into my bin folder on the server and tested my site. Almost the same error, but instead of not finding the assembly at all, it now found the wrong version. It was looking for version and the latest MVC Beta (BETA 3) has version A quick Google search lead me to this solution which suggested adding a bindingRedirect to my web.config. I added it right before the closing </configuration> tag at the very bottom of my web.config:

  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <assemblyIdentity name="System.Web.Abstractions" publicKeyToken="31BF3856AD364E35"/>
    <bindingRedirect oldVersion="" newVersion=""/>

And voila, the site is back up. Did anyone else experience this issue recently? 2 weeks prior to this I had updated from BlogEngine.Net 1.3 to 1.4.5; and for the first time compiled the site with Visual Studio 2008 instead of Visual Studio 2005. I had also upgraded the Ajax Control Toolkit to version 3.5. However, as I mentioned before, all of this happened a full two weeks before the site went down with this error. I suspect that (since not even a single line of text was changed on this site in all that time) GoDaddy must have applied a service pack, or an update to their server to cause the dependency on the missing assembly. If anyone has more information, please let me know.


Posted by Williarob on Wednesday, November 19, 2008 7:00 PM
Permalink | Comments (2) | Post RSSRSS comment feed

Page Load Event Fires Twice

If you have set a breakpoint in the page_load event of your web form and have found it fires twice, view source on the page and check for anything that uses a src="" attribute that is either empty or contains number sign (src="#"). If you find one, make sure you set it to something, if it is an image find a spacer.gif or something you can use, if it is a script or an Iframe either set it or remove it. If you think about it this makes perfect sense, an image tag with an empty src attribute will end up calling the page as the source, which will fire the page load event again. In my case, I was using an <asp:image> tag that had no imageurl until the submit button was pushed and a green check mark or red cross was assigned to it as part of an onscreen Success/Failure message. Making it default to the check mark image resolved my issue. While researching this I found these other possible causes:

  • Check to see if AutoEventWireUp is set to false in the page/control directive.
  • If you are using Visual Basic, check to see that your Handles keyword is only handling one event:"Handles MyBase.Load, Me.Load" would cause it to fire twice.
  • If it only happens on postback, check that your Javascript form validation does not end with form.submit() which would effectively submit your form twice.

Categories: ASP.Net | C# | VB
Posted by Williarob on Thursday, July 24, 2008 1:23 PM
Permalink | Comments (3) | Post RSSRSS comment feed

Process and Thread Basics

Programs, Processes and Threads

In .NET terms, a program can be defined as an assembly, or group of assemblies, that work together to accomplish a task. Assemblies are little more than a way of packaging instructions into maintainable elements and are generally compiled into a dynamic link library (DLL) or an executable (EXE), or a combination of the two.

A process gives a program a place to run, allowing access to memory and resources. Generally, each process runs relatively independent of other processes. In particular, the memory where your program variables will reside is completely separate from the memory used by other processes. Your email program cannot directly assign a new value to a variable in the web browser program. If your email program can communicate with your web browser—for instance, to have it open a web page from a link you received in email—it does so with some form of communication that takes much more time than a memory access.

By putting programs into processes and using only a restricted, mutually agreed-upon communication between them has a number of advantages. One of the advantages is that an error in one process will be less likely to interfere with other processes. Before multitasking operating systems, it was much more common for a single program to be able to crash the entire machine. Putting tasks into processes, and limiting interaction with other processes and the operating system, has greatly added to system stability.

All modern operating systems support the subdivision of processes into multiple threads of execution. Threads run independently, like processes, and no thread knows what other threads are running or where they are in the program unless they synchronize explicitly. The key difference between threads and processes is that the threads within a process share all the data of the process. Thus, a simple memory access can accomplish the task of setting a variable in another thread. Every program will have at least one thread.

In his book ".NET Multithreading" Alan Dennis compares a Process to a house and a thread to a housecat. He writes:

The cat spends most of its time sleeping, but occasionally it wakes up and performs some action, such as eating. The house shares many characteristics with a process. It contains resources available to beings in it, such as a litter box. These resources are available to things within the house, but generally not to things outside the house. Things in the house are protected from things outside of the house. This level of isolation helps protect resources from misuse. One house can easily be differentiated from another by examining its address. Most important, houses contain things, such as furniture, litter boxes, and cats.

Cats perform actions. A cat interacts with elements in its environment, like the house it lives in. A housecat generally has a name. This helps identify it from other cats that might share the same household. It has access to some or the entire house depending on its owner’s permission. A thread’s access to elements may also be restricted based on permissions, in this case, the system’s security settings.


Multitasking means that more than one program can be active at a time. You may take it for granted that you can have an email program and a web browser program running at the same time. Yet, not that long ago, this was not the case. In the days of DOS you would need to save and close your spreadsheet before opening your word processor. With the advent of Windows, you could open multiple applications at once. Windows 3.x used something called Cooperative Multitasking which is based on the assumption that all running processes will yield control to the operating system at a frequent interval. The problem with this model was that not all software developers followed these rules and a program that did not return control to the system, or did so very infrequently, could destabilize the operating system, causing it to "lock up". When Windows 3.x started a new application, that application was invoked from the main thread. Windows passed control to the application with the understanding that control would quickly be returned to windows. If that didn't happen, all other running applications including the operating system could no longer execute instructions. Today, Windows employs Preemptive Multitasking. In this model, instead of relying on programs to return control to the system at regular intervals, the OS simply takes it. 

The main thread of a typical windows program executes a loop (Called a message pump). The loop checks a message queue to see if there is work to do and if there is, it does the work. For example, when a user clicks on a button in a windows application the click event adds work to the message queue indicating which method should be executed. This method is of course known as an event handler. While the loop is executing an event handler, it cannot process additional messages. Multithreading (literally using more than one thread) is how we can work around this limitation. Instead of having the main thread that was assigned to this program do the time consuming work, we assign the work to a seperate thread and have it do the work.

There are a number of ways to create and manage these new threads - using System.Threading, creating a delegate method, implementing the Event Based Asynchronous Pattern, using waithandles, etc. and I intend to explore all of them future articles. In a single core processor, this execution on a separate thread would be periodically interrupted by the operating system to allow other threads a chance to get work done; but after decades in a world where most computers had only one central processing unit (CPU), we are now in a world where only "old" computers have one CPU. Multi-core processors are now the norm. Therefore, every software developer needs to Think Parallel.


Multithreading allows a process to overlap I/O and computation. One thread can execute while another thread is waiting for an I/O operation to complete. Multithreading makes a GUI (graphical user interface) more responsive. The thread that handles GUI events, such as mouse clicks and button presses, can create additional threads to perform long-running tasks in response to the events. This allows the event handler thread to respond to more GUI events. Multithreading can speed up performance through parallelism. A program that makes full use of two processors may run in close to half the time. However, this level of speedup usually cannot be obtained, due to the communication overhead required for coordinating the threads.

Posted by Williarob on Saturday, June 28, 2008 9:00 PM
Permalink | Comments (0) | Post RSSRSS comment feed