static void DynamicRouter()
        {
            //Scenario 1: A greedy dynamic router that routes jobs to different processors based on
            //            the pressure feedbacks it receives from the control channel. It will pick
            //            the processor that is least pressured. The pressure by default is the
            //            number of jobs in processing queue, but it can be overridden by custom
            //            logics.

            int nodeNumber = 2;
            int taskNumber = 10;

            double[] processingTime = new double[nodeNumber];

            List <SBMessage> tasks     = generateTasks(taskNumber);
            double           totalSize = getTotalProcessingTime(tasks);

            var host = ProcessingUnitHost.FromConfiguration((MessagePipelineSection)ConfigurationManager.GetSection("Scenario1"));

            host.Open();

            var pipeline = host.GetProcessingUnit("loadbalancer");

            int processedTasks = 0;

            pipeline.OutputChannels.MessageReceivedOnChannel += new EventHandler <ChannelMessageEventArgs>((obj, e) =>
            {
                IMessage task = (IMessage)e.Message;
                Trace.TraceInformation(string.Format("Received [{0}]", task.Body));

                Thread.Sleep((int)((double)task.Headers[HeaderName.PressureValue] * 1000)); //simulate processing time
                int id              = pipeline.OutputChannels.IndexOf(e.Channel);
                processingTime[id] += (double)task.Headers[HeaderName.PressureValue];
                Interlocked.Increment(ref processedTasks);
                Trace.TraceInformation(string.Format("Processed [{0}]", task.Body));

                Message msg = new Message("");  //provide feedback to report reduced pressure on the channel
                msg.Headers.Add(HeaderName.PressureValue, -(double)task.Headers[HeaderName.PressureValue]);
                ((GreedyDynamicRouter)pipeline).ControlChannels[0].Send(msg);
            });

            foreach (var task in tasks)
            {
                Trace.TraceInformation(string.Format("Sending [{0}]", task.Body));
                pipeline.InputChannels[0].Send(task);
                Thread.Sleep(rand.Next(100, 1000));
            }

            while (processedTasks < taskNumber)
            {
                Thread.Sleep(1000);
            }
            host.Close();
            cprintln(ConsoleColor.Yellow, "Total workload: " + totalSize);
            cprintln(ConsoleColor.Yellow, "  Ideal processing time      : " + totalSize / nodeNumber);
            cprintln(ConsoleColor.Yellow, "  Round-robin processing time: " + getRoundRobinProcessingTime(tasks, nodeNumber));
            cprintln(ConsoleColor.Yellow, "  Greedy load-balancing processing time: " + maxItem(processingTime));
        }
        static void ContentBasedRouter()
        {
            //Scenario 2: A content-based router that routes  messages with "ProductType" header equals to "Cars"
            //            to channel 0 and other messages to channel 2.
            int taskNumber = 10;

            List <SBMessage> tasks = generateTasks(taskNumber);

            var host = ProcessingUnitHost.FromConfiguration((MessagePipelineSection)ConfigurationManager.GetSection("Scenario2"));

            host.Open();

            var pipeline = host.GetProcessingUnit("contentbasedrouter");

            int processedTasks = 0;

            pipeline.OutputChannels.MessageReceivedOnChannel += new EventHandler <ChannelMessageEventArgs>((obj, e) =>
            {
                if ((string)e.Message.Headers["ProductType"] == "Cars")
                {
                    cprintln(ConsoleColor.Red, e.Channel.Name + " processing " + (string)e.Message.Headers["ProductType"]);
                }
                else
                {
                    cprintln(ConsoleColor.Green, e.Channel.Name + " processing " + (string)e.Message.Headers["ProductType"]);
                }
                Interlocked.Increment(ref processedTasks);
            });

            foreach (var task in tasks)
            {
                pipeline.InputChannels[0].Send(task);
                Thread.Sleep(rand.Next(100, 1000));
            }

            while (processedTasks < taskNumber)
            {
                Thread.Sleep(1000);
            }
            host.Close();
        }