<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title>Blair Kitchen</title>
	<link href="http://dongola7.github.com/atom.xml" rel="self"/>
	<link href="http://dongola7.github.com/"/>
	<updated>2012-10-23T16:49:25-07:00</updated>
	<id>http://dongola7.github.com/</id>
	<author>
		<name>Blair Kitchen</name>
		<email>blair@the-blair.com</email>
	</author>
	
	
		<entry>
			<title>A WCF Tutorial</title>
			<link href="http://dongola7.github.com/2010/04/02/wcf-tutorial.html"/>
			<updated>Fri Apr 02 00:00:00 -0700 2010</updated>
			<id>http://dongola7.github.com/2010/04/02/wcf-tutorial</id>
			<content type="html">&lt;h3&gt;Introduction&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;m recently coming out of a job in which I was learning the basics of &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt;.  We used the Microsoft .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; platform extensively, and had used .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; Remoting in some past projects.  Various problems with .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; Remoting led us to choose &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; for a new project.&lt;/p&gt;
&lt;p&gt;I wrote up this basic tutorial based on some lessons learned with &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; and am posting it here in hopes that it might help someone out (and also so I have a place to look when I inevitably forget everything).  I wish I had found a similar tutorial when starting out with &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt;.&lt;/p&gt;
&lt;h3&gt;What is &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;The main idea with &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; is that you define service contracts and data contracts.  A service contract identifies an interface that will be implemented by a &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; service.  Clients are guaranteed that the service implement this interface and can therefore call all of the appropriate methods.  Data contracts identify classes and structs that may be transmitted across the wire from client to server and server to client.&lt;/p&gt;
&lt;p&gt;In order to identify an interface as a service contract, it must have the &lt;code&gt;ServiceContract&lt;/code&gt; attribute applied to it.  Any methods on the interface that will be exposed to the client will need to have the &lt;code&gt;OperationContract&lt;/code&gt; applied.&lt;/p&gt;
&lt;p&gt;If any of the methods return a class or struct, then that class/struct must have the &lt;code&gt;DataContract&lt;/code&gt; attribute applied.  This allows &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; to serialize the object across the wire.  Further, any members of the class/struct that are to be serialized need to have the &lt;code&gt;DataMember&lt;/code&gt; attribute applied.&lt;/p&gt;
&lt;h3&gt;Working Example&lt;/h3&gt;
&lt;p&gt;This example code is available on GitHub in the &lt;a href=&quot;http://github.com/dongola7/wcf_chatter&quot;&gt;wcf_chatter repository&lt;/a&gt;.  The repository contains a working VS 2008 solution implementing the chat service described here.&lt;/p&gt;
&lt;h4&gt;Interfaces&lt;/h4&gt;
&lt;p&gt;Let&amp;#8217;s take a simple example of a chat server (I think everyone can understand a chat server).  A chat server has three main functions: allow users to login, allow users to logout, allow users to send messages to all other logged in users.  An interface that exposes these three methods might appear as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
[ServiceContract]
public interface IChatService
{
   [OperationContract]
   void Login(string userName);
   
   [OperationContract]
   void Logout();
   
   [OperationContract]
   void SendMessage(string message);   
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the &lt;code&gt;ServiceContract&lt;/code&gt; and &lt;code&gt;OperationContract&lt;/code&gt; attributes.  The interface is tagged with the &lt;code&gt;ServiceContract&lt;/code&gt; attribute which identifies to &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; that this interface will be made available to client code.  Each of the methods in the interface is tagged with the &lt;code&gt;OperationContract&lt;/code&gt; attribute, identifying that each of the methods will be exposed to clients.  It is possible to have methods declared on an interface that &lt;em&gt;do not&lt;/em&gt; have the &lt;code&gt;OperationContract&lt;/code&gt; attribute.  These methods &lt;em&gt;would not&lt;/em&gt; be available to connected clients.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s assume that we went to design we review and it was pointed out that this interface has no way of enumerating the currently logged in users.  Management wants a way of listing these users and the time at which they logged into the chat server.  The interface can be extended to look as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
[ServiceContract]
public interface IChatService
{
   [OperationContract]
   void Login(string userName);
   
   [OperationContract]
   void Logout();
   
   [OperationContract]
   void SendMessage(string message);
   
   ChatUser[] LoggedInUsers
   {
      [OperationContract]
      get;
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;#8217;ve added a property to the interface that allows us to retrieve a list of currently logged in users.  Note that, for properties, the &lt;code&gt;OperationContract&lt;/code&gt; attribute is applied to either the &lt;code&gt;get&lt;/code&gt; or &lt;code&gt;set&lt;/code&gt; portion of the property, rather than the property itself.  The property returns an array of &lt;code&gt;ChatUser&lt;/code&gt; instances.  So, the &lt;code&gt;ChatUser&lt;/code&gt; class will need to be serialized across the wire.  This means we&amp;#8217;ll need to use the &lt;code&gt;DataContract&lt;/code&gt; and &lt;code&gt;DataMember&lt;/code&gt; attributes as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
[DataContract]
public class ChatUser
{
   [DataMember]
   public string UserName {get;set;}
   
   [DataMember]
   public DateTime LogInTime {get;set;}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the &lt;code&gt;ChatUser&lt;/code&gt; class is tagged with the &lt;code&gt;DataContract&lt;/code&gt; attribute.  This identifies to &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; that the class may be serialized.  Further, the &lt;code&gt;DataMember&lt;/code&gt; attribute is applied to each of the properties in the class.  This identifies to &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; that these properties should be serialized.  It is possible to declare other properties or fields that &lt;em&gt;do not&lt;/em&gt; have the &lt;code&gt;DataMember&lt;/code&gt; attribute applied.  These &lt;em&gt;would not&lt;/em&gt; be serialized.  This is useful if a class maintains some sort of cache, for example.  You might not want to transmit the cache across the wire, as it could be large.  You&amp;#8217;d rather have the client simply regenerate the cache if needed.&lt;/p&gt;
&lt;p&gt;At this stage, we have more or less defined the server-side interfaces for our chat software.  But what about the client?  How does the chat server send messages to a client?  In order to do so, we need to use what are called &lt;em&gt;Callback Contracts&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;Callback Contract&lt;/em&gt; is applied to a server-side interface and identifies &lt;em&gt;another&lt;/em&gt; interface that is expected to be implemented by the client.  The server may then assume there are certain methods available on the client that it may call.  Let&amp;#8217;s start by defining the interface that will be implemented by the client.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
public interface IChatClient
{
   [OperationContract(IsOneWay = true)]
   void ReceiveMessage(string userName, string message);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A chat client will implement the &lt;code&gt;IChatClient&lt;/code&gt; interface.  Each time &lt;code&gt;ReceiveMessage&lt;/code&gt; is called, it can then print the message to the screen.  Notice that we are using the &lt;code&gt;OperationContract&lt;/code&gt; attribute, but &lt;em&gt;not&lt;/em&gt; the &lt;code&gt;ServiceContract&lt;/code&gt; attribute.  This is because the client is not implementing a service, just a callback.  Also note the user of &lt;code&gt;IsOneWay&lt;/code&gt; in the &lt;code&gt;OperationContract&lt;/code&gt; attribute.  What this means is that the caller does not wait for the method to complete before returning.  In normal &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; operations, when a remote method is called, the caller waits for a response from the remote system before returning.  In this case, we could run into performance problems when using the normal procedure.  What if the server had 100 clients connected and each client&amp;#8217;s &lt;code&gt;ReceiveMessage&lt;/code&gt; method took 1 second to execute?  It would then take 100 seconds for the server to fully distribute a single chat message &amp;#8212; not optimal.  The chat server doesn&amp;#8217;t really &lt;em&gt;care&lt;/em&gt; if the client is done or not, it just needs to ship off the message and move on, so we use the &lt;code&gt;IsOneWay&lt;/code&gt; property to indicate we don&amp;#8217;t want the default process.&lt;/p&gt;
&lt;p&gt;Finally, in order for &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; to understand what&amp;#8217;s going on here, we need to hook all of this up and identify that &lt;code&gt;IChatClient&lt;/code&gt; is the callback contract for &lt;code&gt;IChatService&lt;/code&gt;.  We do this by modifying the &lt;code&gt;ServiceContract&lt;/code&gt; attribute on &lt;code&gt;IChatService&lt;/code&gt;.  Our &lt;code&gt;IChatService&lt;/code&gt; interface is now defined as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
[ServiceContract(CallbackContract = typeof(IChatClient))]
public interface IChatService
{
   [OperationContract]
   void Login(string userName);
   
   [OperationContract]
   void Logout();
   
   [OperationContract]
   void SendMessage(string message);
   
   ChatUser[] LoggedInUsers
   {
      [OperationContract]
      get;
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now all of our interfaces are defined in a manner that is usable by &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt;.  We can place all of these interfaces and classes in a ChatInterfaces project in Visual Studio, allowing them to be shared between server and client implementations.&lt;/p&gt;
&lt;h4&gt;Client&lt;/h4&gt;
&lt;p&gt;The client in our example is composed of three pieces:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;The connection code&lt;/li&gt;
	&lt;li&gt;The client callback (&lt;code&gt;IChatClient&lt;/code&gt;) implementation&lt;/li&gt;
	&lt;li&gt;A .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; configuration file containing &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; config information.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;#8217;s start with the &lt;code&gt;IChatClient&lt;/code&gt; implementation, as it is extremely straightforward.  We define a class, &lt;code&gt;ChatClientImpl&lt;/code&gt;, as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
class ChatClientImpl : IChatClient
{
   public void ReceiveMessage(string userName, string message)
   {
      Console.WriteLine(&quot;{0}: {1}&quot;, userName, message);
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yes, that&amp;#8217;s it.  No &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; stuff, just a standard .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; class implementing an interface.  When &lt;code&gt;ReceiveMessage&lt;/code&gt; is called we simply print the message to the Console.&lt;/p&gt;
&lt;p&gt;The connection code is a little more complex, but not by much.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
var channelFactory = new DuplexChannelFactory&amp;lt;IChatService&amp;gt;(new ChatClientImpl(), &quot;ChatServiceEndpoint&quot;);
IChatService server = channelFactory.CreateChannel();
server.Login(Environment.UserName);

// Do some stuff such as reading messages from the user and sending them to the server

server.Logout();
channelFactory.Close();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above code, the &lt;code&gt;DuplexChannelFactory&lt;/code&gt; is used to actually connect to the chat server.  A &lt;code&gt;ChatClientImpl&lt;/code&gt; instance is passed as the callback object.  Any object could be passed, as long as it implements the &lt;code&gt;IChatClient&lt;/code&gt; interface.  This is the object that will be called by the server.  The final argument to the constructor is the name of an endpoint to which the connection should be established.  Notice there is no computer name, port number, IP address, or anything else.  All of this goes in the configuration file, which we&amp;#8217;ll get to next.&lt;/p&gt;
&lt;p&gt;As a side note, there is also a &lt;code&gt;ChannelFactory&lt;/code&gt; class that is near identical to &lt;code&gt;DuplexChannelFactory&lt;/code&gt;.  The difference is that it&amp;#8217;s constructor does not accept a callback object.  If you have an &lt;code&gt;ServiceContract&lt;/code&gt; that does not declare a callback contract, the &lt;code&gt;ChannelFactory&lt;/code&gt; class should be used rather than &lt;code&gt;DuplexChannelFactory&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The call to &lt;code&gt;CreateChannel&lt;/code&gt; in the next line returns our server interface.  Note that a connection to the server &lt;em&gt;is not yet established&lt;/em&gt;.  In order to do so, you actually have to call a method on the service.  Keep this in mind when writing client programs.  Just calling &lt;code&gt;CreateChannel&lt;/code&gt; will not identify whether or not the connection is valid.&lt;/p&gt;
&lt;p&gt;Next, we login to the server using the &lt;code&gt;Login&lt;/code&gt; method declared on the &lt;code&gt;IChatService&lt;/code&gt; interface.  Some application specific logic would then take place, before we call &lt;code&gt;Logout&lt;/code&gt; on the service interface and &lt;code&gt;Close&lt;/code&gt; the &lt;code&gt;DuplexChannelFactory&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As stated earlier, all of the items such as computer name, port number, etc., are included not in the client application code, but, rather in the App.config file.  When built, this file is copied to &amp;lt;exe-name&amp;gt;.exe.config (i.e., ChatClient.exe.config).  The values in this file are available to the .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; environment at runtime.  Our App.config file for the client is as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;configuration&amp;gt;
  &amp;lt;system.serviceModel&amp;gt;
    &amp;lt;client&amp;gt;
      &amp;lt;endpoint name=&quot;ChatServiceEndpoint&quot;
                address=&quot;net.tcp://localhost:8080/ChatService&quot;
                binding=&quot;netTcpBinding&quot;
                bindingConfiguration=&quot;BindingConfiguration&quot;
                contract=&quot;ChatInterfaces.IChatService&quot;&amp;gt;
        &amp;lt;identity&amp;gt;
          &amp;lt;servicePrincipalName value=&quot;&quot;/&amp;gt;
        &amp;lt;/identity&amp;gt;
      &amp;lt;/endpoint&amp;gt;
    &amp;lt;/client&amp;gt;

    &amp;lt;bindings&amp;gt;
      &amp;lt;netTcpBinding&amp;gt;
        &amp;lt;binding name=&quot;BindingConfiguration&quot;
                 transferMode=&quot;Buffered&quot;/&amp;gt;
      &amp;lt;/netTcpBinding&amp;gt;
    &amp;lt;/bindings&amp;gt;
  &amp;lt;/system.serviceModel&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Most of the config file is boilerplate code that can be re-used.  Reading the &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; documentation will explain most of these fields as well.  The important items are the &lt;code&gt;endpoint&lt;/code&gt; &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; element.  Specifically, the &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;address&lt;/code&gt;, &lt;code&gt;binding&lt;/code&gt;, and &lt;code&gt;contract&lt;/code&gt; attributes.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; attribute identifies the name of the endpoint.  This is the string passed to the &lt;code&gt;DuplexChannelFactory&lt;/code&gt; constructor and allows &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; to locate the appropriate endpoint in the configuration file (multiple endpoints may be included).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;address&lt;/code&gt; attribute identifies the &lt;span class=&quot;caps&quot;&gt;URI&lt;/span&gt; for the chat server.  We are using the &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; NetTcp binding (more on this later), so the &lt;span class=&quot;caps&quot;&gt;URI&lt;/span&gt; scheme is &lt;code&gt;net.tcp&lt;/code&gt;.  Following this is the hostname and port number which indicate the chat server is running on &lt;code&gt;localhost&lt;/code&gt; and listening for connections at port 8080.  Finally, the path, &lt;code&gt;/ChatService&lt;/code&gt; identifies the name of the service (a single server can host multiple services that appear at different paths, &lt;code&gt;/ChatServiceVersion1&lt;/code&gt; and &lt;code&gt;/ChatServiceVersion2&lt;/code&gt;, for example).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;binding&lt;/code&gt; attribute identifies the binding type.  &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; supports a number of different communication protocols, which are referred to as &lt;em&gt;bindings&lt;/em&gt;.  In most of our cases, &lt;code&gt;netTcpBinding&lt;/code&gt; is the appropriate choice.  It&amp;#8217;s the most efficient implementation in terms of bandwidth and performance, but can only be used when all of your server and client instances are using &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; (which is our situation).&lt;/p&gt;
&lt;p&gt;Finally, the &lt;code&gt;contract&lt;/code&gt; attribute identifies the name of the interface being provided by the server.  The fully qualified name (including namespaces) is required.  In our case, this is &lt;code&gt;ChatInterfaces.IChatService&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Server&lt;/h4&gt;
&lt;p&gt;The chat server is composed of three pieces:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;The actual service implementation (the class that implements &lt;code&gt;IChatService&lt;/code&gt;)&lt;/li&gt;
	&lt;li&gt;The service host (the code that actually hosts the service, opens listening ports, etc.)&lt;/li&gt;
	&lt;li&gt;The configuration file&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&amp;#8217;s start with the &lt;code&gt;ChatServiceImpl&lt;/code&gt; class.  This is the class that implements the &lt;code&gt;IChatService&lt;/code&gt; interface.  The class is declared as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single)]
class ChatServiceImpl : IChatService
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The class itself is declared in the same manner as any other class that implements an interface.  The &lt;code&gt;ServiceBehavior&lt;/code&gt; attribute is the important part.  This attribute identifies to &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; that the class is implementing a &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; service, and also identifies how the service should behave.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ConcurrencyMode&lt;/code&gt; attribute indicates whether or not the service supports threading.  We specified &lt;code&gt;ConcurrencyMode.Single&lt;/code&gt;.  This means that the &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; framework will make sure only one thread is ever executing the methods on our object at a single point in time.  There is no need for thread-safety in our code.  For high-volume services, this would be a performance bottleneck, as two client requests could not be serviced simultaneously.  There are other options as well: &lt;code&gt;ConcurrencyMode.Reentrant&lt;/code&gt; and &lt;code&gt;ConcurrencyMode.Multiple&lt;/code&gt;.  Further descriptions of these modes can be found in the &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; documentation.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;InstanceContextMode&lt;/code&gt; attribute identifies whether this is a singleton service (one object serves all clients), or whether multiple instances are created.  In most of our situations, &lt;code&gt;InstanceContextMode.Single&lt;/code&gt; is the appropriate choice.  The class implements a service and all clients talk to the same object instance.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Login&lt;/code&gt; method is illustrative of how the class works overall.  It is defined as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
public void Login(string userName)
{
    var connection = OperationContext.Current.GetCallbackChannel&amp;lt;IChatClient&amp;gt;();
    var user = new ChatUser {UserName = userName, LogInTime = DateTime.Now};
    _users[connection] = user;   
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above code, &lt;code&gt;_users&lt;/code&gt; is declared as a class scope variable with the type &lt;code&gt;Dictionary&amp;lt;IChatClient, ChatUser&amp;gt;&lt;/code&gt;.  Most of this code is straightforward, except for the &lt;code&gt;OperationContext.Current.GetCallbackChannel&amp;lt;IChatClient&amp;gt;&lt;/code&gt; call.  This call will retrieve the &lt;code&gt;IChatClient&lt;/code&gt; interface used to communicate with the client calling the current method.  So, if the server was operating on ComputerA, and the client on ComputerB, this call would retrieve the interface that allows ComputerA to send messages back to ComputerB.  We place this &lt;code&gt;IChatClient&lt;/code&gt; in the dictionary for later use in broadcasting messages from &lt;code&gt;SendMessage&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;SendMessage&lt;/code&gt; method illustrates the usage of these collected &lt;code&gt;IChatClient&lt;/code&gt; interfaces.  Each time &lt;code&gt;SendMessage&lt;/code&gt; is called by a client, the server is supposed to broadcast the message to all &lt;em&gt;other&lt;/em&gt; clients (it should not repeat the message back to the sender).&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
public void SendMessage(string message)
{
    var connection = OperationContext.Current.GetCallbackChannel&amp;lt;IChatClient&amp;gt;();
    ChatUser user;
    if(!_users.TryGetValue(connection, out user))
        return;

    foreach (var otherConnection in _users.Keys)
    {
        if(otherConnection == connection)
            continue;
        otherConnection.ReceiveMessage(user.UserName, message);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, we retrieve the current &lt;code&gt;IChatClient&lt;/code&gt; interface using &lt;code&gt;OperationContext.Current.GetCallbackChannel&amp;lt;IChatClient&amp;gt;&lt;/code&gt;.  We then look up the username for this client, and finally iterate through all connected clients, calling &lt;code&gt;ReceiveMessage&lt;/code&gt; for each of them.  Note the use of the &lt;code&gt;if...then&lt;/code&gt; statement to prevent broadcasting the message back to the sender.&lt;/p&gt;
&lt;p&gt;As you can see, aside from the &lt;code&gt;ServiceBehavior&lt;/code&gt; attribute and the use of &lt;code&gt;OperationContext.Current.GetCallbackChannel&amp;lt;IChatClient&amp;gt;&lt;/code&gt;, this class is the same as other .&lt;span class=&quot;caps&quot;&gt;NET&lt;/span&gt; classes.  The remainder of the &lt;code&gt;ChatServiceImpl&lt;/code&gt; class should, therefore, be self-explanatory.&lt;/p&gt;
&lt;p&gt;Now that the chat server itself is implemented, we need to somehow host the service in an executable.  The ChatServer console program does just this.  The &lt;code&gt;Main&lt;/code&gt; method is defined as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
var chatService = new ChatServiceImpl();
var host = new ServiceHost(chatService);

host.Open();

Console.WriteLine(&quot;Server is running&quot;);
Console.WriteLine(&quot;Press any key to exit...&quot;);
Console.ReadKey();

host.Close();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the hosting executable, we create a new &lt;code&gt;ChatServiceImpl&lt;/code&gt; instance, and then pass this instance to a &lt;code&gt;ServiceHost&lt;/code&gt;.  &lt;code&gt;ServiceHost&lt;/code&gt; is a class provided by the &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; framework and is used for hosting &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; services.  Next, we &lt;code&gt;Open&lt;/code&gt; the &lt;code&gt;ServiceHost&lt;/code&gt;, which starts the service listening for connections.  The next three lines simply serve to prevent the console program from exiting until the user presses a key.  Then we call &lt;code&gt;Close&lt;/code&gt; to shut down the &lt;code&gt;ServiceHost&lt;/code&gt; and that&amp;#8217;s it.&lt;/p&gt;
&lt;p&gt;But wait, where is the port number and other details needed by the server?  How does &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; know all of this stuff?  Just like the client program, we place all of this information in the App.config file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;configuration&amp;gt;
  &amp;lt;system.serviceModel&amp;gt;
    &amp;lt;services&amp;gt;
      &amp;lt;service name=&quot;ChatServer.ChatServiceImpl&quot;&amp;gt;
        &amp;lt;endpoint address=&quot;net.tcp://localhost:8080/ChatService&quot;
                  binding=&quot;netTcpBinding&quot;
                  bindingConfiguration=&quot;BindingConfiguration&quot;
                  name=&quot;ChatServiceEndPoint&quot;
                  contract=&quot;ChatInterfaces.IChatService&quot;&amp;gt;
        &amp;lt;/endpoint&amp;gt;
      &amp;lt;/service&amp;gt;
    &amp;lt;/services&amp;gt;

    &amp;lt;bindings&amp;gt;
      &amp;lt;netTcpBinding&amp;gt;
        &amp;lt;binding name=&quot;BindingConfiguration&quot;
                 transferMode=&quot;Buffered&quot;/&amp;gt;
      &amp;lt;/netTcpBinding&amp;gt;
    &amp;lt;/bindings&amp;gt;
  &amp;lt;/system.serviceModel&amp;gt;
&amp;lt;/configuration&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This App.config file is &lt;em&gt;very&lt;/em&gt; similar to that of the client.  Again, we have an &lt;code&gt;endpoint&lt;/code&gt; element which works in a very similar manner to the client, save that &lt;code&gt;address&lt;/code&gt; is now used to open a &lt;span class=&quot;caps&quot;&gt;TCP&lt;/span&gt;/IP port for listening rather than connection.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;endpoint&lt;/code&gt; element is wrapped in a &lt;code&gt;service&lt;/code&gt; element.  This identifies to &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; that this endpoint is to be used by a service, rather than a client.  The &lt;code&gt;name&lt;/code&gt; attribute identifies the name of the class providing the service implementation, or &lt;code&gt;ChatServiceImpl&lt;/code&gt; in our case.  Just like the &lt;code&gt;contract&lt;/code&gt; attribute, the fully qualified name, including namespaces is required.&lt;/p&gt;
&lt;p&gt;The &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; framework, through the &lt;code&gt;ServiceHost&lt;/code&gt; constructor, knows that a &lt;code&gt;ChatServiceImpl&lt;/code&gt; has been passed as the service object.  It then looks through the App.config file to locate an &lt;code&gt;service&lt;/code&gt; element with a matching name.  If none is found, a runtime error will be generated.&lt;/p&gt;
&lt;h5&gt;A Note about Dead-Lock&lt;/h5&gt;
&lt;p&gt;Note that this code includes the possibility of creating a dead-lock.  A dead-lock could occur in the following situation:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;We remove the &lt;code&gt;IsOneWay&lt;/code&gt; attribute from &lt;code&gt;IChatClient.ReceiveMessage&lt;/code&gt;.&lt;/li&gt;
	&lt;li&gt;ClientA calls &lt;code&gt;IChatService.SendMessage&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Server calls &lt;code&gt;IChatClient.ReceiveMessage&lt;/code&gt; on ClientB&lt;/li&gt;
	&lt;li&gt;ClientB calls any method on &lt;code&gt;IChatService&lt;/code&gt; &lt;em&gt;from within&lt;/em&gt; the &lt;code&gt;IChatClient.ReceiveMessage&lt;/code&gt; method.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The reason for the dead-lock is that the service is declared with &lt;code&gt;ConcurrencyMode.Single&lt;/code&gt;.  Remember that this means the &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; framework prevents multiple threads from calling methods on the service object simultaneously.  In our above scenario, there is a call to &lt;code&gt;SendMessage&lt;/code&gt; being executed, which in turn calls out to &lt;code&gt;ReceiveMessage&lt;/code&gt;, which then tries to call back &lt;em&gt;into&lt;/em&gt; &lt;code&gt;IChatService&lt;/code&gt;.  The &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; framework will not execute this call until the original &lt;code&gt;SendMessage&lt;/code&gt; is completed, which means the client will not return, and thus the call to &lt;code&gt;ReceiveMessage&lt;/code&gt; will not return, and thus, the original &lt;code&gt;SendMessage&lt;/code&gt; call will not return.&lt;/p&gt;
&lt;p&gt;There are two ways to fix this deadlock.&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Keep the &lt;code&gt;IsOneWay&lt;/code&gt; attribute on &lt;code&gt;IChatClient.ReceiveMessage&lt;/code&gt;.  Recall that this means the server &lt;em&gt;does not have to wait&lt;/em&gt; for the client to return before continuing, thus no dead-lock can occur.&lt;/li&gt;
	&lt;li&gt;Replace the &lt;code&gt;ConcurrencyMode.Single&lt;/code&gt; with either &lt;code&gt;ConcurrencyMode.Reentrant&lt;/code&gt; or &lt;code&gt;ConcurrencyMode.Multiple&lt;/code&gt;.  Be sure to read the documentation on these modes, however, and be aware that you will have to manage multi-threaded access yourself (meaning the service implementation will need to be thread-safe).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is a complex situation, but it has already happened once in our NExT service implementations, so it is definitely something to be aware of.&lt;/p&gt;
&lt;h4&gt;Running the example&lt;/h4&gt;
&lt;p&gt;Download the code from the GitHub repository.  Open the solution in VS 2008 and build the solution.  The &lt;code&gt;bin\Debug&lt;/code&gt; or &lt;code&gt;bin\Release&lt;/code&gt; directory will contain both the &lt;code&gt;ChatServer&lt;/code&gt; and &lt;code&gt;ChatClient&lt;/code&gt; executables.  Try executing a single server ad two clients on your system to see everything in action.&lt;/p&gt;
&lt;h3&gt;Further Reading&lt;/h3&gt;
&lt;p&gt;These articles provide further information on &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; and include best practices for passing errors across the wire (exceptions don&amp;#8217;t come across the wire in &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt;), as well as further details on the items described in this tutorial.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://blogit.create.pt/blogs/marcosilva/archive/2008/05/18/Developing-a-WCF-Service-_2D00_-Fault-Exceptions-AND-FAULT-Contracts.aspx&quot;&gt;&lt;span class=&quot;caps&quot;&gt;DEVELOPING&lt;/span&gt; A &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;SERVICE&lt;/span&gt; &amp;#8211; &lt;span class=&quot;caps&quot;&gt;FAULT&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;EXCEPTIONS&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;FAULT&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;CONTRACTS&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/ef896836-dec1-4fa6-9956-e3a4958643ce&quot;&gt;Inheritance not supported on callback contracts?&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms733721.aspx&quot;&gt;Specifying and Handling Faults in Contracts and Services&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://blogs.msdn.com/brajens/archive/2007/04/23/exception-handling-in-wcf-web-service.aspx&quot;&gt;Exception Handling in &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; Web Service&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://stackoverflow.com/questions/992883/error-reporting-in-wcf-service&quot;&gt;Error Reporting in &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; Service?&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://realfiction.net/Content/Entry/113&quot;&gt;The no frills, bare-bones example to Duplex &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt;&lt;/a&gt;
	&lt;ul&gt;
		&lt;li&gt;This is another working example of &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; with callbacks.  It expects a little more working knowledge of &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; than this tutorial.&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://social.msdn.microsoft.com/forums/en-US/wcf/thread/9b73383c-2db9-4db6-87b4-67833075783d/&quot;&gt;Error in Net.Tcp + CallBack Contract + Streaming&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.code-magazine.com/articleprint.aspx?quickid=0701041&amp;amp;page=2&amp;amp;printmode=true&quot;&gt;Hosting &lt;span class=&quot;caps&quot;&gt;WCF&lt;/span&gt; Services&lt;/a&gt;
	&lt;ul&gt;
		&lt;li&gt;Note the WCFChatter example uses self-hosting.&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
		</entry>
	
		<entry>
			<title>The Podcast Flag and iTunes</title>
			<link href="http://dongola7.github.com/2009/04/29/podcast-flag-and-itunes.html"/>
			<updated>Wed Apr 29 00:00:00 -0700 2009</updated>
			<id>http://dongola7.github.com/2009/04/29/podcast-flag-and-itunes</id>
			<content type="html">&lt;p&gt;One of my favorite podcasts, &lt;a href=&quot;http://insomniaradio.net/category/ir-daily-dose/&quot;&gt;Insomnia Radio&amp;#8217;s Daily Dose&lt;/a&gt;, delivers a single MP3 containing a new track each day.  When I really like a track, I want to include it in my iTunes library as a standard music track.   The problem is that iTunes embeds a podcast flag in the ID3 tags of the file, making it difficult to treat the MP3 as a standard music track.&lt;/p&gt;
&lt;p&gt;After some investigation, I found that iTunes adds an extra ID3 frame with text label &lt;code&gt;PCST&lt;/code&gt; to the MP3 file header.&lt;/p&gt;
&lt;p&gt;I wrote a quick C program, &lt;a href=&quot;http://github.com/dongola7/strip_podcast/tree/master&quot;&gt;strip_podcast&lt;/a&gt;, to remove this ID3 frame from a named MP3 file.  After running the program, the file can be added back into iTunes as a standard MP3 file.&lt;/p&gt;
&lt;p&gt;See the included &lt;code&gt;README.textile&lt;/code&gt; file for a description of how to build and run the program.&lt;/p&gt;</content>
		</entry>
	
		<entry>
			<title>Removing the Digg Bar</title>
			<link href="http://dongola7.github.com/2009/04/13/remove-digg-bar.html"/>
			<updated>Mon Apr 13 00:00:00 -0700 2009</updated>
			<id>http://dongola7.github.com/2009/04/13/remove-digg-bar</id>
			<content type="html">&lt;p&gt;I really don&amp;#8217;t like the new Digg bar.  It&amp;#8217;s really more of a personal preference than anything related to the potential link stealing and what not.  As such, I wrote a quick Greasemonkey script to get rid of the new Digg short URLs while browsing the site.&lt;/p&gt;
&lt;p&gt;Hopefully someone finds it helpful.&lt;/p&gt;
&lt;p&gt;Just click &amp;#8220;View Raw&amp;#8221; in the below embedded gist to install.&lt;/p&gt;
&lt;script src=&quot;http://gist.github.com/94890.js&quot;&gt;&lt;/script&gt;</content>
		</entry>
	
		<entry>
			<title>git-bisect found my bug</title>
			<link href="http://dongola7.github.com/2009/01/05/git-bisect.html"/>
			<updated>Mon Jan 05 00:00:00 -0800 2009</updated>
			<id>http://dongola7.github.com/2009/01/05/git-bisect</id>
			<content type="html">&lt;p&gt;I had read about git-bisect a while ago, but since I&amp;#8217;ve just started using git in a full-time capacity, I hadn&amp;#8217;t had an opportunity to use it &amp;#8211; until today.&lt;/p&gt;
&lt;p&gt;An automated benchmarking tool showed our software was running more slowly than usual.  I had recently made a large number of changes to introduce some new features and figured I must have messed something up.  Since there were around twenty or so commits between the good build and when benchmarking problems showed up, I figured this was a good opportunity to try out git-bisect.&lt;/p&gt;
&lt;p&gt;If you don&amp;#8217;t know, git-bisect basically automates the process of performing a binary search through your project history in order to identify when a bug was introduced.  In order to run, you do the following:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;code&gt;git bisect start&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;git bisect bad&lt;/code&gt; &amp;#8211; Indicate the current version has the problem.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;git bisect good &amp;lt;rev&amp;gt;&lt;/code&gt; &amp;#8211; Indicate the rev in which the problem does not exist.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At this point, git-bisect will checkout the revision in the middle of the current revision and the last known good revision.  You can then test your code to see if the problem exists in this revision.  If so, simply run &lt;code&gt;git bisect good&lt;/code&gt;.  If not, run &lt;code&gt;git bisect bad&lt;/code&gt;.  Each time it&amp;#8217;s executed, git-bisect will tell you how many revisions remain to be tested.  Once you hit zero, git-bisect will tell you the exact revision in which the problem was introduced.&lt;/p&gt;
&lt;p&gt;Now clearly, you can do this with Subversion or most any other CM tool for that matter.  You could probably even automate it.  But, how cool is it that git supports this sort of thing out of the box?&lt;/p&gt;
&lt;p&gt;Needless to say, I was able to find &amp;#8211; and fix &amp;#8211; my performance problem.&lt;/p&gt;</content>
		</entry>
	
		<entry>
			<title>git-svn in a secure environment</title>
			<link href="http://dongola7.github.com/2009/01/03/git-svn-in-secure-environment.html"/>
			<updated>Sat Jan 03 00:00:00 -0800 2009</updated>
			<id>http://dongola7.github.com/2009/01/03/git-svn-in-secure-environment</id>
			<content type="html">&lt;p&gt;First, we need to create a new git repository from the &lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt; repository.  We&amp;#8217;ll do this using git-svn.&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Run the command &lt;code&gt;git svn clone &amp;lt;SVN-URL&amp;gt;&lt;/code&gt; (i.e., &lt;code&gt;git svn clone svn://server/trunk&lt;/code&gt;).  This may take a while depending on the size of the repository.&lt;/li&gt;
	&lt;li&gt;Set up your git ignore file based on the svn:ignore properties: &lt;code&gt;git svn show-ignore &amp;gt;&amp;gt; .git/info/exclude&lt;/code&gt;&lt;/li&gt;
	&lt;li&gt;Create a copy of this git repository on a thumb-drive, CD, etc&amp;#8230;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Next, we&amp;#8217;ll move to the secure environment where we&amp;#8217;ll be making changes without access to &lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt;.&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Copy the git repository from the removable media onto your work system.&lt;/li&gt;
	&lt;li&gt;Create a new git branch in which you&amp;#8217;ll record your changes.  You can do this with the command &lt;code&gt;git checkout -b &amp;lt;BRANCH-NAME&amp;gt;&lt;/code&gt; (i.e., &lt;code&gt;git checkout -b customer_site&lt;/code&gt;).&lt;/li&gt;
	&lt;li&gt;Modify your code as usual.  Whenever you want to record some changes, run the following commands:
	&lt;ol&gt;
		&lt;li&gt;&lt;code&gt;git add .&lt;/code&gt; &amp;#8211; Stages your changes in the git index&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;git commit&lt;/code&gt; &amp;#8211; Commits all changes in the index to the repository.  You&amp;#8217;ll be asked for a commit message.&lt;/li&gt;
	&lt;/ol&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once all of your changes are complete and your ready to move back to the &lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt; repository, we&amp;#8217;ll create a set of patches identifying the changes and apply these patches to our git repository in the insecure environment.&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Run the command &lt;code&gt;git format-patch master..&lt;/code&gt; &amp;#8211; This will generate a series of .patch files, one per commit, for all of the changes you&amp;#8217;ve made to your git branch.  The .patch files are in plaintext and can be examined by a third-party.&lt;/li&gt;
	&lt;li&gt;Take all of the .patch files back to the system in the insecure environment.  Copy the .patch files into your git working directory.&lt;/li&gt;
	&lt;li&gt;Run the command &lt;code&gt;git am *.patch&lt;/code&gt; to apply all of the patches.  After the patches are all applied, you can run &lt;code&gt;git log&lt;/code&gt; to see that they all show up.&lt;/li&gt;
	&lt;li&gt;Merge the latest changes from &lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt; into your git repository: &lt;code&gt;git svn rebase&lt;/code&gt;.  You&amp;#8217;ll have to fix any conflicts that may arise.&lt;/li&gt;
	&lt;li&gt;Finally, push your changes from git back into the &lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt; repository: &lt;code&gt;git svn dcommit&lt;/code&gt;.  And you&amp;#8217;re done.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;CAVEATS&lt;/span&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;If you&amp;#8217;re using the svn:externals property anywhere, git-svn won&amp;#8217;t handle it.  This will complicate matters.&lt;/li&gt;
	&lt;li&gt;Make sure you don&amp;#8217;t change anything on the &amp;#8216;master&amp;#8217; branch in git.  This will make it easier to move changes back and forth with the &lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt; repository since you&amp;#8217;ll only use the master branch for moving between &lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt; and git.&lt;/li&gt;
	&lt;li&gt;I have only loosely tested these instructions, so you&amp;#8217;ll want to try them out yourself before relying on them in a customer environment.  That being said, I think the basic workflow is sound.&lt;/li&gt;
&lt;/ol&gt;</content>
		</entry>
	
		<entry>
			<title>First Greasemonkey Script</title>
			<link href="http://dongola7.github.com/2007/06/27/my-first-greasemonkey-script.blog.html"/>
			<updated>Wed Jun 27 00:00:00 -0700 2007</updated>
			<id>http://dongola7.github.com/2007/06/27/my-first-greasemonkey-script.blog</id>
			<content type="html">&lt;p&gt;I just wrote my first greasemonkey script.  It&amp;#8217;s used to clean up the interface to &lt;a href=&quot;http://www.rememberthemilk.com&quot;&gt;Remember the Milk&lt;/a&gt;, an online Todo list.&lt;/p&gt;
&lt;p&gt;Just click &amp;#8220;View Raw&amp;#8221; in the below embedded gist to install.&lt;/p&gt;
&lt;script src=&quot;http://gist.github.com/49252.js&quot;&gt;&lt;/script&gt;</content>
		</entry>
	
		<entry>
			<title>Todo Manager (Tcl Style)</title>
			<link href="http://dongola7.github.com/2006/06/11/todo-manager-tcl-style.html"/>
			<updated>Sun Jun 11 00:00:00 -0700 2006</updated>
			<id>http://dongola7.github.com/2006/06/11/todo-manager-tcl-style</id>
			<content type="html">&lt;p&gt;&lt;a href=&quot;http://lifehacker.com&quot;&gt;Lifehacker&lt;/a&gt; had an interesting post about keeping track of a Todo list in a simple &lt;a href=&quot;http://www.lifehacker.com/software/to-do-managers/geek-to-live-readerwritten-todotxt-manager-173018.php&quot;&gt;&lt;span class=&quot;caps&quot;&gt;TXT&lt;/span&gt; file&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;They even went so far as to create a &lt;span class=&quot;caps&quot;&gt;UNIX&lt;/span&gt; shell script for managing said file.  I wanted to try it out at work, but we use Windows (not by choice), and I didn&amp;#8217;t want to bother installing Cygwin.  I rewrote the script as a small Tcl program, and posted it on &lt;a href=&quot;http://code.google.com/p/blairkitchen/source/browse/todo/trunk/todo.tcl&quot;&gt;Google Code&lt;/a&gt;.&lt;/p&gt;</content>
		</entry>
	
</feed>