<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>shtylman.com</title>
	<atom:link href="http://www.shtylman.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.shtylman.com</link>
	<description>its not a bug, its a feature</description>
	<lastBuildDate>Mon, 13 Feb 2012 06:19:44 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>decisions and regrets</title>
		<link>http://www.shtylman.com/archives/275</link>
		<comments>http://www.shtylman.com/archives/275#comments</comments>
		<pubDate>Mon, 13 Feb 2012 06:19:44 +0000</pubDate>
		<dc:creator>shtylman</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.shtylman.com/?p=275</guid>
		<description><![CDATA[I often hear people talk about the decions they make and whether, given the opportunity, they would do it differently. This is often shortened to just &#8220;regrets&#8221;. Presented with the question myself, my response is almost always a resounding no! Now, this may at first seem foolish, it would basically mean one of two things. [...]]]></description>
			<content:encoded><![CDATA[<p>I often hear people talk about the decions they make and whether, given the opportunity, they would do it differently. This is often shortened to just &#8220;regrets&#8221;. Presented with the question myself, my response is almost always a resounding no! Now, this may at first seem foolish, it would basically mean one of two things. I either learned nothing from my experience (if things didn&#8217;t turn out great) or I am pleased with the outcome and would do the same thing desiring the same outcome. Since the latter is of little interest (why would you not desire a pleasant outcome except for sheer curiosity), lets talk about the former.</p>
<p>Now, obviously if things did not turn out well after you made some decision you can only wish for the chance to go back and do it differently. This would be only reasonable, who doesn&#8217;t want to improve their situation? The reason I usually answer in the negative is not one of stubbornness in refusing to believe I made a mistake, it is simply a matter of attitude. I believe that lingering on the past and lamenting a decision has far worse consequences on an outcome and your ability to adapt to the situation than (almost) any bad choice (a counterargument can be made to an extreme, but my topics are for basic life decisions, not ones that end in fatality or some other trauma). For me, the most important aspects of evaluating a poor choice are as follows (not novel in any way): maintaining control and understanding alternatives.</p>
<p>The worst thing you can do to turn an already bad situation into a worse one is lose control. I don&#8217;t mean in just a physical sense. Any situation can be salvaged (remember.. generalities, not absolutes) to glean something. The reason you can have thoughts like &#8220;regrets&#8221; is because you are able to evaluate changes in your life relative to one another. The critical thing is analyze and understand your reactions to the changes and note them for future use; learning from your mistakes (nothing fancy here, we have been told this from gradeschool). But in order to do that you have to make mistakes, that part somehow gets conveniently left out. No one is perfect! But your ability to adapt to a situation and proceed forward with an understanding that you still have control is a major factor in being able to deal with the majority of shit life can deal out.</p>
<p>Once you know you haven&#8217;t lost control, you have to understand that everything is relative. Good for one is bad for another. You may have a vague idea of &#8220;universal&#8221; truths, but overall, it is just societal influence that tends to guide our daily lives. Don&#8217;t let one person&#8217;s idea of &#8220;values&#8221; interfere with your ability to reason and determine your own values. And certainly don&#8217;t be afraid to change your perspective in light of new arguments. Everyone is at a different place in their lives and has their own (skewed) perspective on how they think things should be. Don&#8217;t try to make their reality your reality and vice versa.</p>
<p>While the last paragraph may seem a bit off topic, it is far from it. The reason understanding how others see your outcome is important is because we often judge ourselves from the perspective of society. We think about what is &#8220;expected&#8221; of us and what the norms are. This contributes to the feelings of regret. People often forget that their current situation has altered their understanding of themselves and the world around them. They then make the mistake of analyzing their original choice but in their current context. This is incorrect as the new information may not have been available at the time or understood to mean what it does now. Always analyze the past in the proper context and apply that analysis going forward to improve your situation.</p>
<p>If you life your life worrying about having regrets you will find it increasingly harder and harder to take the bold steps that can make life interesting. Always focus on the simple things: what did I learn about myself, how did I react, and what is my next step from here to where I want to be.</p>
<p>p.s. I don&#8217;t know why I wrote this. I have no real decisions to make or regrets <img src='http://www.shtylman.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Just wanted to share some thoughts; it is a blog isn&#8217;t it?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.shtylman.com/archives/275/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>scraping broken SSL pages with node.js</title>
		<link>http://www.shtylman.com/archives/264</link>
		<comments>http://www.shtylman.com/archives/264#comments</comments>
		<pubDate>Mon, 21 Nov 2011 22:34:31 +0000</pubDate>
		<dc:creator>shtylman</dc:creator>
				<category><![CDATA[courseoff]]></category>

		<guid isPermaLink="false">http://www.shtylman.com/?p=264</guid>
		<description><![CDATA[To collect the data for courseoff.com I scrape university websites on demand. This means that I have to perform http queries to the sites and then parse the resulting pages. Usually, this is not a problem as node.js has very simple APIs for performing both http and https requests. However, some schools have old webservers [...]]]></description>
			<content:encoded><![CDATA[<p>To collect the data for courseoff.com I scrape university websites on demand. This means that I have to perform http queries to the sites and then parse the resulting pages. Usually, this is not a problem as node.js has very simple APIs for performing both http and https requests. However, some schools have old webservers which make this task trickier.</p>
<p><span id="more-264"></span>Scraping a normal, up to date website, over SSL is not a problem; however, when you encounter a site like <a href="https://banweb.spsu.edu/pls/PROD/schedule.main">SPSU&#8217;s course schedules</a> you realize why web browsers are the magical things they are. At first glance, this looks like a normal site served up over ssl. It even has the green lock in chrome to indicate everything is &#8220;secure&#8221; and give me a warm fuzzy feeling. However, if I try to use &#8216;curl&#8217; on this page, it bawks with:</p>
<pre>curl https://banweb.spsu.edu/pls/PROD/schedule.main
curl: (35) error:14077417:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert illegal parameter</pre>
<p>This was strange to me as my browser loaded the page just fine. Chrome does however give a hint as to something being wrong. When I click on the green lock icon, I get the usual certificate notice as well as an additional piece of information:</p>
<blockquote><p>The connection had to be retried using SSL 3.0. This typically means that the server is using very old software and may have other security issues.</p></blockquote>
<p>Clearly something is not right with the webserver here and that is what is causing curl, and subsequently my nodejs requests, to fail.</p>
<p>Doing some basic digging, I was able to find this nice little tidbit in the openssl documentation:</p>
<blockquote><p><strong>SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION</strong></p>
<p>Allow legacy insecure renegotiation between OpenSSL and unpatched clients or servers. See the <strong>SECURE RENEGOTIATION</strong> section for more details.</p></blockquote>
<p>Now that I had this option to try, I had to figure out a way to make node.js use it. Reading some code led me to understand that the &#8216;Agent&#8217; is the object which handles the options for http(s) requests which are ultimately passed to the SSL context. When creating the agent, you pass in an options object, this object contains two fields which need to be used for this case: secureProtocol and secureOptions.<br />
<code><br />
secureProtocol specifies which negotiation method to use<br />
secureOptions are the flags passed to the context to change the behavior<br />
</code><br />
My final agent object had the following form:<br />
<code><br />
var agent = new Agent({<br />
  secureProtocol: 'SSLv3_method',<br />
  secureOptions: require('constants').SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS<br />
});<br />
</code></p>
<p>My https request options object just need to include the &#8216;agent&#8217; key and have it set to the agent object I created. This filtered down to the underlying ssl context and set the context options. The request was a success!</p>
<p>This will only work with node.js >= 0.6.3 because the constants are only available after that. Other constants from the bug workaround section of the openssl documentation are also available for your needs.</p>
<p><strong>References:</strong><br />
<em>ssl docs</em>: http://www.openssl.org/docs/ssl/SSL_CTX_set_options.html<br />
<em>nodejs docs</em>: http://nodejs.org/docs/v0.6.2/api/http.html#http.Agent</p>
]]></content:encoded>
			<wfw:commentRss>http://www.shtylman.com/archives/264/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>headphones for snowboarding</title>
		<link>http://www.shtylman.com/archives/248</link>
		<comments>http://www.shtylman.com/archives/248#comments</comments>
		<pubDate>Mon, 14 Nov 2011 00:50:36 +0000</pubDate>
		<dc:creator>shtylman</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.shtylman.com/?p=248</guid>
		<description><![CDATA[I recently bought a snowboarding helmet to get home and realize that it has cutouts in the earmuffs for headphones. Lucky for me I had a pair of headphones laying around that would be a perfect fit. Below are some pictures of the the headphones before and after my minor modifications. My thinking was to remove the [...]]]></description>
			<content:encoded><![CDATA[<p>I recently bought a snowboarding helmet to get home and realize that it has cutouts in the earmuffs for headphones. Lucky for me I had a pair of headphones laying around that would be a perfect fit. Below are some pictures of the the headphones before and after my minor modifications.</p>
<p><span id="more-248"></span></p>
<div id="attachment_250" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-250" title="before modification" src="http://www.shtylman.com/wp-content/uploads/2011/11/IMG_20111113_182102-300x225.jpg" alt="" width="300" height="225" /><p class="wp-caption-text">headphones before modification (one pad removed)</p></div>
<p>My thinking was to remove the wire connecting the two ear pieces. Then see if I could cut down the plastic part supporting the wire. Initially I had planned to also remove the actual driver from the plastic encasing but that proved unnecessary since the side with the plastic was perfect for the slot in the helmet.</p>
<div id="attachment_249" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-249 " title="headphones after modifications" src="http://www.shtylman.com/wp-content/uploads/2011/11/IMG_20111113_192257-300x225.jpg" alt="" width="300" height="225" /><p class="wp-caption-text">after modifications</p></div>
<p>After removing the plastic support, I plugged the hole with some hot glue and installed into the helmet. Result: awesome!</p>
<div id="attachment_251" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-251" title="headphones in helmet" src="http://www.shtylman.com/wp-content/uploads/2011/11/IMG_20111113_192540-300x225.jpg" alt="" width="300" height="225" /><p class="wp-caption-text">headphones installed</p></div>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.shtylman.com/archives/248/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>course/off visualization &#8211; gatech Spring 2012</title>
		<link>http://www.shtylman.com/archives/240</link>
		<comments>http://www.shtylman.com/archives/240#comments</comments>
		<pubDate>Tue, 01 Nov 2011 17:13:08 +0000</pubDate>
		<dc:creator>shtylman</dc:creator>
				<category><![CDATA[courseoff]]></category>

		<guid isPermaLink="false">http://www.shtylman.com/?p=240</guid>
		<description><![CDATA[Since I have all this data from course/off, I figured I would make some interesting visualizations with some of it. One of the first things that comes to mind is: how popular is a given course? Without further delay, I present the glorious bubble diagram of course popularity at Georgia Tech for Spring 2012. Full [...]]]></description>
			<content:encoded><![CDATA[<p>Since I have all this data from course/off, I figured I would make some interesting visualizations with some of it. One of the first things that comes to mind is: how popular is a given course? Without further delay, I present the glorious bubble diagram of course popularity at Georgia Tech for Spring 2012.</p>
<p><span id="more-240"></span></p>
<div id="attachment_243" class="wp-caption aligncenter" style="width: 535px"><img class="size-full wp-image-243" title="Georgia Tech - Spring 2012" src="http://www.shtylman.com/wp-content/uploads/2011/11/spring_2012.png" alt="" width="525" height="525" /><p class="wp-caption-text">Georgia Tech - Spring 2012</p></div>
<p>Full Res svg: <a href="http://www.shtylman.com/misc/courseoff/spring_2012.svg">http://www.shtylman.com/misc/courseoff/spring_2012.svg<br />
</a></p>
<p>Created using the d3 javascript library: <a href="http://mbostock.github.com/d3/">http://mbostock.github.com/d3/</a><a href="http://www.shtylman.com/misc/courseoff/spring_2012.svg"> </a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.shtylman.com/archives/240/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The tail of MongoDB</title>
		<link>http://www.shtylman.com/archives/217</link>
		<comments>http://www.shtylman.com/archives/217#comments</comments>
		<pubDate>Sun, 12 Jun 2011 18:10:52 +0000</pubDate>
		<dc:creator>shtylman</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.shtylman.com/?p=217</guid>
		<description><![CDATA[I recently gave a talk at MongoNYC 2011 about using MongoDB as a messaging layer. The rationale behind doing something like this would be to maintain a log of all the messages passed between two clients. While there are many different IPC schemes available, I thought it would be interesting to build something simple on top of [...]]]></description>
			<content:encoded><![CDATA[<p>I recently gave a talk at MongoNYC 2011 about using MongoDB as a messaging layer. The rationale behind doing something like this would be to maintain a log of all the messages passed between two clients. While there are many different IPC schemes available, I thought it would be interesting to build something simple on top of MongoDB using the tailable cursor feature. After giving the talk, I wanted to explore the performance characteristics of such a setup.</p>
<p><span id="more-217"></span></p>
<p>Before jumping into my benchmarking details, there are two important concepts to understand behind using MongoDB for message passing.</p>
<p>The <a title="tailable cursor" href="http://www.mongodb.org/display/DOCS/Tailable+Cursors" target="_blank">tailable cursor</a> gets its inspiration from the &#8220;tail -f&#8221; command in unix systems. For those unfamiliar with what that does, the idea is to open a file, listen for new additions to the end of the file, and print those. The program does not terminate when it reaches the end of the file, instead, it waits for more data. Using this approach, a simple message queue can be created with MongoDB. A producer creates messages and inserts them into MongoDB and then a consumer(s) is able to read those messages. While this can be simulated by keeping track of document IDs (in MongoDB and other database systems), in MongoDB the tailable cursor is actually supported server side and tracks the last returned document. This is much cheaper than having to constantly requery.</p>
<p>In MongoDB tailable cursors can only be opened on <a title="capped collections" href="http://www.mongodb.org/display/DOCS/Capped+Collections" target="_blank">capped collections</a>. This is because a capped collection is a fixed size and only allows insertions. This means that once the number of documents exhausts the collection size, newly written documents will start overwriting the first inserted documents. An important note about capped collections is that insertion order is the natural sort order. This means that when the tail cursor fetches documents, it will get them back in the order they were inserted. If you have more than one producer and insertion order matters, then you will need to either use separate collections or do your own reordering consumer side. For my examples, there is only one producer and thus natural (insertion) order is acceptable.</p>
<p>Now that we have some background on tailable cursors and capped collections, we can cover the benchmark setup. To perform the benchmark, I will have one producer and one consumer. The producer will get create a document of the format (Where the current time will have microsecond precision):</p>
<p style="padding-left: 30px;"><code> { time: (current time in seconds) }</code></p>
<p>The producer will generate 100,000 of these messages and insert them into the collection. To avoid dealing with a slow consumer, the collection will be made big enough to hold all of the possible messages:</p>
<p style="padding-left: 30px;"><code>db.createCollection("messages", { size: 100000000, capped: true })</code></p>
<p>The producer is a simple python application:</p>
<pre style="padding-left: 30px;" lang="python">#!/usr/bin/python

import time
from pymongo import Connection

conn = Connection()
db = conn.queues
coll = db.messages

start = time.time()

count = 100000
for i in range(0, count):
    coll.insert({ "time": time.time()})
    #This generates messages at a rate of about 3,900 msg/s
    time.sleep(0.0001)

end = time.time()
print("total: ", count)
print("msg/s: ", count/(end - start))</pre>
<p>The consumer is a c++ client modeled after the default c++ tailable cursor example on the MongoDB page. It gets the system time upon reading a document and computes the latency between insert and read. The consumer is started before the producer:</p>
<pre style="padding-left: 30px;" lang="cpp">#include &lt;sys/time.h&gt;

#include &lt;mongo/client/dbclient.h&gt;

using namespace mongo;                                                                                                  

int main(int argc, char* argv[])
{
    DBClientConnection conn;
    conn.connect("localhost");                                                                                          

    // minKey is smaller than any other possible value
    BSONElement lastId = minKey.firstElement();                                                                         

    // { $natural : 1 } means in forward capped collection insertion order
    Query query = Query().sort("$natural");                                                                             

    cout &lt;&lt; "loc,val" &lt;&lt; std::endl;
    uint32_t i = 0;
    struct timeval tv;
    while( true ) {
        auto_ptr c = conn.query("queues.messages", query, 0, 0, 0,
                QueryOption_CursorTailable);
        while( true ) {
            if( !c-&gt;more() ) {
                if( c-&gt;isDead() )
                    break;
                sleepsecs(1);
                continue; // we will try more() again
            }

            const BSONObj&amp; o = c-&gt;next();
            lastId = o["_id"];
            const double time = o["time"].Double();

            gettimeofday(&amp;tv, NULL);
            const double curr = tv.tv_sec + tv.tv_usec / 1000000.0;
            cout &lt;&lt; i++ &lt;&lt; ", " &lt;&lt; curr - time &lt;&lt; endl;
        }

        // prepare to requery from where we left off
        query = QUERY( "_id" &lt;&lt; GT &lt;&lt; lastId ).sort("$natural");
    }

    return 0;
}</pre>
<p>Running the consumer/producer pair generated the following latency graph:</p>
<div id="attachment_224" class="wp-caption aligncenter" style="width: 510px"><img class="size-full wp-image-224" title="Default c++ consumer" src="http://www.shtylman.com/wp-content/uploads/2011/06/simple_cpp1.png" alt="" width="500" height="400" /><p class="wp-caption-text">Default c++ consumer</p></div>
<p style="text-align: left;">The graph is not lines, but actually 100,000 points that represent the <em>N-th</em> packet versus the latency (<em>read time &#8211; write time</em>). The above graph has a standard deviation of: <em>0.29693s</em>. While these results are not horrible, the sawtooth nature of the graph would indicate that there is something strange going on and that ideally, we can do much better and decrease the latency. I ran a simple consumer (without clearing the producer data) to see if the bottleneck was in the write side or read side:</p>
<p style="text-align: center;">&nbsp;</p>
<div class="mceTemp mceIEcenter" style="text-align: center;">
<dl id="attachment_226" class="wp-caption aligncenter" style="width: 510px;">
<dt class="wp-caption-dt"><img class="size-full wp-image-226" title="pure_read" src="http://www.shtylman.com/wp-content/uploads/2011/06/pure_read1.png" alt="" width="500" height="400" /></dt>
<dd class="wp-caption-dd">Default c++ consumer &#8211; Read Only</dd>
</dl>
</div>
<p style="text-align: left;">Because the read only graph is essentially linear, it means that the consumer has no problem in reading all of the data if it is available and likewise, the producer did not have problems inserting the data. (The latency is irrelevant here as the data was inserted before the consumer had to read it). So given the above graph, we know the consumer can handle reading the data consistently if it is available, so the sawtooth pattern must emerge from what happens when new data is being inserted.</p>
<p style="text-align: left;">Taking another look at the Default C++ consumer graph, I noted that the consumer only goes back to ~1s latency when the previous latency was almost 0. This information, along with the c++ code which contains a sleep for 1 second was the &#8220;aha!&#8221; moment. When there are no more documents to read, the client waits for new documents to show up. Unfortunately, instead of being woken up when new documents are available, the default example uses a simple poll. This is expensive if our goal is to minimize latency. To test my theory I removed the sleep statement from the code and ran the consumer/producer pair again:</p>
<p style="text-align: left;">&nbsp;</p>
<div id="attachment_227" class="wp-caption aligncenter" style="width: 510px"><img class="size-full wp-image-227" title="no_sleep" src="http://www.shtylman.com/wp-content/uploads/2011/06/no_sleep.png" alt="" width="500" height="400" /><p class="wp-caption-text">No Sleep</p></div>
<p>This method produced a standard deviation of <em>0.000739s. </em>However, this is not the end solution as it has one major problem; it uses a tight loop which causes high CPU load locally and worse yet, thrashes the mongo server. Looking over the c++ driver API I found an interesting query option: <em>AwaitData </em>defined to: &#8220;If we are at the end of the data, block for a while rather than returning no data. After a timeout period, we do return as normal.&#8221;</p>
<p>The AwaitData option sounded like just the thing I needed. I modified the query code to the following:</p>
<pre style="padding-left: 30px;" lang="cpp">auto_ptr c = conn.query("queues.messages", query, 0, 0, 0, QueryOption_CursorTailable | QueryOption_AwaitData);</pre>
<p>It is important to note that this causes the &#8220;more&#8221; cursor method call to block for a short time. If you cannot afford to block, this will not be a solution for you (see conclusion about some thoughts about evented systems)</p>
<p>And sure enough, when there were no more records to read, the local CPU would not spin. Yet I still noticed a problem. Since I start my consumer before the producer, I found that a bunch of re-querying was happening until the first record was inserted. This is due to a &#8220;dead&#8221; cursor. When the capped collection is empty, MongoDB does not keep a cursor open server side and thus the whole &#8220;tail&#8221; process never starts until at least one record is available. Given that I did not want to spin the local CPU or thrash the server, I inserted a sleep before the &#8220;break&#8221; when the cursor was &#8220;dead&#8221;. This would cause a requery every 1 second until a cursor could be created (at least 1 record was inserted). While this did solve the spinning CPU problem, I found this solution caused a high initial latencies because of the sleep before the query:</p>
<div id="attachment_228" class="wp-caption aligncenter" style="width: 510px"><img class="size-full wp-image-228" title="sleep_on_dead" src="http://www.shtylman.com/wp-content/uploads/2011/06/sleep_on_dead.png" alt="" width="500" height="400" /><p class="wp-caption-text">Sleep before requery</p></div>
<p>Once the initial query happened, and a valid cursor obtained, then further queries were not needed and the latency remained very low. However the start up latencies were poor because we could be anywhere in the 1 second sleep before we are able to re-query.</p>
<p>To solve this problem, I used a dummy document to prime the collection and cursor. Given that even with a single document, a cursor would be created server side and the client would no longer have to query waiting for a valid cursor. While this solution is also not optimal, it does avoid having to keep querying the database in hopes of obtaining a valid cursor. So here with all the pieces in place (AwaitData, dummy document, and sleep before query):</p>
<div id="attachment_229" class="wp-caption aligncenter" style="width: 510px"><img class="size-full wp-image-229" title="final" src="http://www.shtylman.com/wp-content/uploads/2011/06/final.png" alt="" width="500" height="400" /><p class="wp-caption-text">using dummy document</p></div>
<p style="text-align: center;">This produced a standard deviation of <em>0.000662s</em>, and never spun the CPU. The final c++ client code to produce this result (just the outer while loop):</p>
<pre style="padding-left: 30px;" lang="cpp">while( true )
{
     auto_ptr c = conn.query("queues.messages", query, 0, 0, 0,
             QueryOption_CursorTailable | QueryOption_AwaitData);
     while( true ) {
         if( !c-&gt;more() ) {
             if( c-&gt;isDead() )
             {
                 // this sleep is important for collections that start out with no data
                 sleepsecs(1);
                 break;
             }
             continue;
         }

         const BSONObj&amp; o = c-&gt;next();
         lastId = o["_id"];
         const double time = o["time"].Double();

         // handle the dummy document {time: 0.0}
         // yes, not a great comparison for doubles, just an example
         if (time == 0)
             continue;

         gettimeofday(&amp;tv, NULL);
         const double curr = tv.tv_sec + tv.tv_usec / 1000000.0;
         cout &lt;&lt; i++ &lt;&lt; ", " &lt;&lt; curr - time &lt;&lt; endl;
     }

     // prepare to requery from where we left off
     query = QUERY( "_id" &lt;&lt; GT &lt;&lt; lastId ).sort("$natural");
 }</pre>
<p>You can see how I bypass the dummy document used to prime the cursor as an example. I ran a similar consumer/producer test with no time delay on the producer (producing ~24,000 msg/s) and also obtained similar results with a standard deviation of <em>0.000753s.</em></p>
<h3>Conclusions</h3>
<p>Given the above latency measurements, I found that MongoDB tail cursors and capped collections performed much better than I expected. I was hoping for latencies in the 10 to 100 millisecond range but instead often got sub millisecond latencies for standard deviation with peaks of 5 milliseconds for the last run. Depending on your definition of &#8220;low latency&#8221; using MongoDB for basic message passing is quite viable and gives the added benefit of logging all of the passed messages for things like replay or catch up (if you have sequence numbers).</p>
<p>In performing this benchmark I encountered some pain points. The biggest one that may lead users astray is the incomplete example on the mongodb.org page (as of this writing). It does not mention the very necessary AwaitData flag, and also incurs a high latency due to the use of sleep.</p>
<p>Another problem (and something I consider a bug) is the behavior when there are no items in the collection. Depending on your use case and consumer/producer startup times, this may be a hidden issue that is hogging CPU time until a valid cursor is created. From my point of view, a valid cursor should be created immediately (even with no documents) that can then behave properly under the AwaitData condition.</p>
<p>And finally,  it would be nice to expose an API that allows the c++ client to epoll (or some other notification scheme) when new documents are available. Since with the AwaitData call the &#8220;more&#8221; cursor method blocks for a bit, this becomes very unsafe in event driven systems which should not be blocking (or any system that should not block). Since there is a socket underlying the connection to the DB, this seems like a reasonable a﻿ddition that would solve such a problem.</p>
<h3>Additional Notes</h3>
<p>All testing was done on a <em>Core i7 920</em> running<em> Ubuntu 10.10 </em>and using <em>SSD</em> as the storage medium. I used the <a href="https://github.com/mongodb/mongo/commit/3d909045d30dcd6af39bf21dd62a379275262ccd" target="_blank">latest</a> of the MongoDB master github branch as of June 9th.</p>
<p>Initially, I tested a simple python consumer, but it too suffered from the sleep problems and did not expose query options in the same way the c++ driver did. I stuck with the c++ driver as an example given the clarity in demonstrating the various &#8220;gotchas&#8221; in doing the benchmark.</p>
<p>I toyed around with the node-mongodb-native driver and think that the &#8220;streaming&#8221; aspects could make the callback API work a bit better but would need to be flushed out more with how the &#8220;GET_MORE&#8221; operation to the server is handled. I found that I could lock up the server if I was not careful with how many GET_MORE ops were being sent for the cursor.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.shtylman.com/archives/217/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>re-tipping the cab</title>
		<link>http://www.shtylman.com/archives/210</link>
		<comments>http://www.shtylman.com/archives/210#comments</comments>
		<pubDate>Thu, 30 Dec 2010 04:04:31 +0000</pubDate>
		<dc:creator>shtylman</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.shtylman.com/?p=210</guid>
		<description><![CDATA[After having a brief discussion with some friends about my views on tipping I have come to give the idea of tipping some more thought. The gist of the discussion led me to realize that I had been looking at tipping from a somewhat wrong point of view and as such want to just make [...]]]></description>
			<content:encoded><![CDATA[<p>After having a brief discussion with some friends about my views on tipping I have come to give the idea of tipping some more thought. The gist of the discussion led me to realize that I had been looking at tipping from a somewhat wrong point of view and as such want to just make a few more comments on the matter and share a few random tidbits I ran across while looking into taxi cabs in NYC.</p>
<p><span id="more-210"></span>So why the change of heart on tipping (if you can really call it a change of heart)? When I wrote my first post on tipping, I was completely focused on the idea of tipping as something &#8220;extra&#8221; beyond the basic salary of the individual. I viewed tipping as a failure in that it was diluting good service (I will come back to this later) and basically making tipping become the &#8220;norm&#8221; or &#8220;expected&#8221; thing to get any service at all. I felt that I should be able to pay for a service and get that service performed (to the ability of the person) and pay for the service given a fixed and known cost. What I failed to realize was that tipping isn&#8217;t about the server getting money beyond what they should be making but that it is actually a way for the consumer to rate the server in a dynamic setting. Not giving a tip is the equivalent of a bad performance review (sort of like a negative tip if you will); and by tipping the &#8220;social norm&#8221; you are in effect paying the market price for the good. So a tip above the social norm is one that commends good service. By tying a portion of the salary to tips, the server and consumer can create a tighter feedback loop and ideally improve service faster for everyone. While there is the possibility of complaining to the cab company about poor service (or police if something illegal is happening) these type of things take time and are not always as clear to the driver who may benefit from more direct feedback.</p>
<p>However there was one thing that didn&#8217;t quite sit well with me and that was how the &#8220;social norm&#8221; number comes to be determined or even what it means. I could believe the argument about lower tip equating to bad performance, but how much tip equals &#8220;standard&#8221; performance (if  there really is such a thing). I felt strongly that even without a tip the drivers should be doing their jobs to their ability and that a tip should not warrant normal service. Unfortunately, it was pointed out to me that if all drivers knew they had fixed income and no tips, then there would be less incentive to perform better or give good rides. I will not tackle the social implications of this or my thoughts on it since I already conceded that I liked the idea of a tip being like a small performance evaluation; I just needed to know what that should be.</p>
<p>It is common knowledge that waiters/waitresses do not make minimum wage because tips are expected to bring their salary to the right level (again&#8230; how you are supposed to know how much to tip to make that happen is unclear); was the same true for taxi drivers? I figured that given the higher skill, longer hours, and more exhausting working conditions that taxi drivers would be making at least minimum living wage without tips. I found a website that listed the minimum living wage in NYC at $10 with benefits and $11.50 without [1]. Another amazing source (Taxicab Fact book), which I highly recommend browsing, listed that the average hours worked on a shift was 10 and that a full time driver (only about 40% of all licensed drivers) reported working 5 of the previous days [2]. Lets say that a full time driver works 5 days a week for a 10 hours a day. Given the requirement that they should at least make living wage that would mean $11.50 * 10 * 5 * 52 = $29,900. For living wage a full time driver should be making right under 30k a year. Clearly driving a car (especially well in NYC) requires some skill (we are not going to debate how much) so it would make sense that such a job would pay more than minimum wage, does it? Indeed it does! The average NYC cab driver salary is $49,532 [3] just under 50k. So clearly on average cab drivers are making more than the living wage. But, the interesting thing I found about this number and other wage estimates for cab drivers is that they take into account a 15% tip for fares. That&#8217;s right, built into the expected salary is a 15% tip. This means that without tips, drivers make slightly over 43k a year. This 43k comes to about $16.50 per hour given the hours I calculated before. Compare that with a rough estimate (google) for MTA bus drivers making about $26~$29 per hour. To me it seems reasonable that cab drivers make less, but not much less. Indeed at 50k a year (after putting the 15% tip back) they make closer to $20 per hour.</p>
<p>Now there isn&#8217;t a hard conclusion I am drawing from this; or saying that drivers make too much or too little. I was just interested in getting some rough numbers for comparison and finding how the &#8220;social norm&#8221; tip rate figured into the calculations. This just means that to calculate the real taxi rate you just need to add 15% to the posted rate. Ideally the &#8220;social norm&#8221; rate doesn&#8217;t change (as it seems to for restaurant servers) and thus allows the taxi companies to better price around such a rate. Why 15% was chosen versus 10% or some other arbitrary number I couldn&#8217;t say (at least not with way way more information). Given that NYC trips are pretty short and come in at under $10 [2] it would not be a hard leap to think that a smaller tip would just not carry the same weight.</p>
<p>Overall, I found the various articles interesting reading. The taxicab fact book [2] and a more dated (1995) overview [4] from the same company were by far the most informative. The cover such things as accident rates and how fares have changed over time. In the end, I feel comfortable settling on paying the &#8220;social norm&#8221; tip given that it figures in the income rate and is documented at a known 15%. Given that it stays constant at this percent, it is perfectly reasonable to treat it like a performance bonus rather than a specific tip.</p>
<p>[1] <a href="http://www.livingwagenyc.org/pagedetail.php?id=3">http://www.livingwagenyc.org/pagedetail.php?id=3</a></p>
<p>[2] <a href="http://www.schallerconsult.com/taxi/taxifb.pdf">http://www.schallerconsult.com/taxi/taxifb.pdf</a></p>
<p>[3] <a href="http://411newyork.org/guide/2008/03/30/new-york-taxi-cab-driver-salary/">http://411newyork.org/guide/2008/03/30/new-york-taxi-cab-driver-salary/</a></p>
<p>[4] <a href="http://www.schallerconsult.com/taxi/taxi1.htm">http://www.schallerconsult.com/taxi/taxi1.htm</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.shtylman.com/archives/210/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>tipping the cab</title>
		<link>http://www.shtylman.com/archives/192</link>
		<comments>http://www.shtylman.com/archives/192#comments</comments>
		<pubDate>Mon, 25 Oct 2010 23:37:45 +0000</pubDate>
		<dc:creator>shtylman</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.shtylman.com/?p=192</guid>
		<description><![CDATA[Recently (as it happens every once in a while) I decided to re-evaluate my views on tipping and see if I needed to add or remove anything from the &#8220;will tip&#8221; pool. Sure enough, after some [not so] deep thought I decided that tipping a cab driver for a ride is one of those things [...]]]></description>
			<content:encoded><![CDATA[<p>Recently (as it happens every once in a while) I decided to re-evaluate my views on tipping and see if I needed to add or remove anything from the &#8220;will tip&#8221; pool. Sure enough, after some [not so] deep thought I decided that tipping a cab driver for a ride is one of those things I can safely remove from the required tip pool.</p>
<p><span id="more-192"></span>Before you start to get all defensive and claim that the cab drivers depend on the tips for their wages and that they provide a service and you tip for a service..etc etc let me clarify my position and also state that me not tipping doesn&#8217;t mean you have to not tip; it&#8217;s your choice!</p>
<p>Sure, if the cab driver provided you with an abnormal taxi experience, or somehow otherwise stepped outside the &#8220;driver&#8221; role, then feel free to tip away. On the other hand, if they just picked you up, and drove you to your destination, then I would not tip and here is why. The product you paid for was the ride and the driver is a part of the product. Without the driver there is no product. I view this differently from a true service industry (like food) where you consume a product separate from the service provided by the staff. When I tip in a restaurant, I don&#8217;t just tip my waiter directly, I take into account the support staff that make up the entire experience (even though I know my food costs have taken that into account to some extent).</p>
<p>Another thing about cabs that differs from a normal service experience is how the costs can be figured in. In a NYC cab, the price is listed as per some fraction of a mile OR time elapsed. This means that the cab driver&#8217;s &#8220;time&#8221; can be figured in just as much as the operation costs of the taxi itself. The longer you sit in a cab, the longer the cabbie &#8220;serves&#8221; and the higher your fare goes. it grows with the time of service (or distance of service). The fact that there is an additional tip often given is just encouragement to not price the fare correctly. But I am sure the cab companies know the costs and have figured them into account.</p>
<p>I take the same stance on other services which cannot be separated in a meaningful way from the service giver, like a haircut for example. The haircut (product) and person doing the haircut cannot be separated, otherwise you won&#8217;t be getting a haircut anymore. Various haircuts have their own levels of complexity and can be priced accordingly (and often are). The stylist (or barber) will know the time taken for the haircut and effort involved in the requested style. But you have to be careful about future service investment.</p>
<p>Future service investment is the idea that by tipping today and being a repeat customer, you will get good service next time. While some may sneer at this concept, it is something valid to take into account when determining your tip amount. A taxi ride has a lack of future service investment with respect to tipping. By not tipping you do not run the risk of ruining the service for your next taxi ride simple because the chance that you will encounter the same taxi driver for your next ride are&#8230; well, small (discounting custom limo services or the like with a limited driver base). This means that (unlike a resaurant you frequent) tipping a taxi does not &#8220;invest&#8221; into your future with the taxi company. You may begin to think that you ruin the experience for the next person and so on, but you don&#8217;t. The driver will most likely shrug you not tipping off as a nothing, or better yet make an effort to be a better cabbie for the next person who will most likely provide a tip. But lets say that many people stop tipping cab drivers, then either the cost will rise to reflect the &#8220;true&#8221; cost (which I am confident is already in the price) or the cost won&#8217;t rise and cab drivers will no longer expect tips and drive as usual. Think of yourself as a foreigner who (probly well and good knows about US tipping customs) but still doesn&#8217;t tip because&#8230; well who cares, they won&#8217;t be back).</p>
<p>While my overall views on all tipping are negative, mostly because I don&#8217;t think it should be a socially common thing to do, I acknowledge that some jobs and wages are constructed with the idea of tipping in mind. Mostly, I don&#8217;t like to promote the idea that the price listed is not the real price. If there are costs involved, then those costs should be figured into the price of the good being consumed. But if the time and effort spect cannot be well predicted in advance, then you do have a genine opportunity for <em>some </em>tipping (not the expreme society has come to accept as the norm). Don&#8217;t always tip just because there is an are on the receipt for &#8220;tip&#8221; or because the option is there. Tipping should be something that is above and beyond, not boring and ordinary, otherwise, the whole notion is diluted.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.shtylman.com/archives/192/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>the internet, open 24/7</title>
		<link>http://www.shtylman.com/archives/181</link>
		<comments>http://www.shtylman.com/archives/181#comments</comments>
		<pubDate>Sun, 25 Apr 2010 16:42:03 +0000</pubDate>
		<dc:creator>shtylman</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.shtylman.com/?p=181</guid>
		<description><![CDATA[So just when you thought webpages were available 24/7 (or at least not when under maintenance), along comes the government to prove you wrong! www.socialsecurity.gov/onlineservices/ Check out the left side. The &#8220;Field Office Locator&#8221; is only available during certain hours. Note, this isn&#8217;t even a chat feature or anything like that&#8230; its a simple lookup [...]]]></description>
			<content:encoded><![CDATA[<p>So just when you thought webpages were available 24/7 (or at least not when under maintenance), along comes the government to prove you wrong!</p>
<p><a href="http://www.socialsecurity.gov/onlineservices/">www.socialsecurity.gov/onlineservices/</a></p>
<p>Check out the left side. The &#8220;Field Office Locator&#8221; is only available during certain hours. Note, this isn&#8217;t even a chat feature or anything like that&#8230; its a simple lookup service. On the right side, there are even more hours posted for what appears to be the site in general. I&#8217;m not sure why this is. Maybe they run out of RAM on a known schedule. Anyhow&#8230; no longer will I &#8220;assume&#8221; the internet is open.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.shtylman.com/archives/181/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>new kdm theme</title>
		<link>http://www.shtylman.com/archives/164</link>
		<comments>http://www.shtylman.com/archives/164#comments</comments>
		<pubDate>Wed, 10 Feb 2010 04:06:44 +0000</pubDate>
		<dc:creator>shtylman</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.shtylman.com/?p=164</guid>
		<description><![CDATA[For the longest time I found the default Kubuntu KDM theme &#8230; well&#8230; not very pretty. Besides having lots of &#8220;dead&#8221; space I felt that it didn&#8217;t work well at all with the default splash screen. The transition from one to the other was not very clean. It didn&#8217;t help that for Karmic the wallpaper/ksplash [...]]]></description>
			<content:encoded><![CDATA[<p>For the longest time I found the default Kubuntu KDM theme &#8230; well&#8230; not very pretty. Besides having lots of &#8220;dead&#8221; space I felt that it didn&#8217;t work well at all with the default splash screen. The transition from one to the other was not very clean. It didn&#8217;t help that for Karmic the wallpaper/ksplash were updated but the kdm was not. This caused it to look even worse; so I decided to come up with a new one.</p>
<p><span id="more-164"></span></p>
<p>When messing around with the some graphics one night I decided to dedicate some time to seeing how easy it would be to make a new kdm theme that would work a bit better with the ksplash and wallpaper that will be used in Kubuntu Lucid. After about an hour or two of messing around and pulling artwork from different places then tweaking it a bit I came up with:</p>
<div id="attachment_165" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.shtylman.com/wp-content/uploads/2010/02/kdm_latest.png"><img class="size-medium wp-image-165" title="Kubuntu Lucid KDM Theme" src="http://www.shtylman.com/wp-content/uploads/2010/02/kdm_latest-300x225.png" alt="" width="300" height="225" /></a><p class="wp-caption-text">Kubuntu Lucid KDM Theme</p></div>
<p style="text-align: left;">This will be the new default theme for Kubuntu in Lucid (10.04) when it releases. This will also be the default wallpaper. the main goal with the theme was to make the transition from kdm -&gt; ksplash (the splash screen showing kde loading progress) a bit smoother. This is accomplished by using the same center box graphic and wallpaper scalings that ksplash uses. Overall the effect is nice. I created a short [exciting] video to show off how it looks. Apologies for the sound&#8230; I had some recording difficulties&#8230;</p>
<p style="text-align: center;"><iframe title="YouTube video player" class="youtube-player" type="text/html" width="425" height="344" src="http://www.youtube.com/embed/k4JxGueJj7s" frameborder="0" allowFullScreen="true"> </iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://www.shtylman.com/archives/164/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>live assistant for ubuntu</title>
		<link>http://www.shtylman.com/archives/154</link>
		<comments>http://www.shtylman.com/archives/154#comments</comments>
		<pubDate>Mon, 30 Nov 2009 21:04:42 +0000</pubDate>
		<dc:creator>shtylman</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.shtylman.com/?p=154</guid>
		<description><![CDATA[Live assistant is an idea that I proposed at Ubuntu Developer Summit Lucid. The basic premise is to provide new Ubuntu users the same &#8220;live chat&#8221; experience that many large websites are starting to offer. The problem Imagine you are a new Ubuntu user. When you first encounter a problem, it may be very difficult [...]]]></description>
			<content:encoded><![CDATA[<p>Live assistant is an idea that I proposed at Ubuntu Developer Summit Lucid. The basic premise is to provide new Ubuntu users the same &#8220;live chat&#8221; experience that many large websites are starting to offer.</p>
<h3><span id="more-154"></span>The problem</h3>
<p>Imagine you are a new Ubuntu user. When you first encounter a problem, it may be very difficult to get your bearings and figure out where you need to go to get the best support. Most users will try to go to Google and search there, likely with limited success as they will not know the best query to use. Other users will navigate to Ubuntu.com and hopefully see the small &#8220;Support&#8221; link at the top. The user can now select from three choices: free documentation, paid support, and free community support. Let’s say this is a single user just trying things out and not really interested in paid support. This leaves them with two options.</p>
<p>The first option (documentation) takes them to pages where they have to click through lists and lists of various &#8220;categories&#8221; trying to find the topic that pertains to their problem. Granted, this documentation is up to date and of good quality, but again might not be the most welcoming environment to someone who is frustrated with a single problem and doesn&#8217;t know where to go.</p>
<p>This now brings me to the community support options. From those the user can pick any of: live IRC chat, web forums, mailing lists, and the answers system. Notice that for a user looking to solve a particular problem they now have to hunt through 4 very different systems for a solution. Mailing lists would be difficult to search and, for a new user posting to a list, would not necessarily be the most pleasant experience. There is also a signup process with posting to a list and responses are not immediate. The list topic can bounce around for a while until some conclusions are reached. The web forums will probably look familiar to many users. But again, you have to sign up. After that, you post your problem and check back (or get emailed) if someone responded. Then you respond back and this pseudo email exchange goes on until &#8230; well&#8230; who knows, hopefully a solution is reached (potentially days later). The user might then try the answers system. This system is geared towards just that, answering questions for users. A user posts a question, and others can comment on it and hopefully guide the user in the right direction. The different between answers and the forums is that answers live on Launchpad and can be linked to bug reports easily. But essentially the two are very similar. You post, and you wait.</p>
<p>The best &#8220;live&#8221; solution the user can pursue is to use something called IRC (Internet Relay Chat). For a new user, who might be very familiar with the idea of instant messaging, will most likely have never heard of IRC much less used it. Although the instructions are quite clear on how to connect (join a server, and go into #ubuntu, or #kubuntu&#8230;etc). Once the user is in that channel they are in what is basically a free for all. Being brave, they will post their question to the channel. It will be mixed with all of the channel traffic already there and hopefully seen by someone who can help with the problem. That person might give a few pointers and others might chime in at random times. Oh, and don&#8217;t forget that other channel conversations are still going on at the same time. A new user would be completely lost in this wave of messages (and probly not know common idioms like prefixing a message with the username of the person it is for). Hopefully the user will not become more frustrated that their question isn&#8217;t getting as much attention or that they can&#8217;t figure out what is going on in the channel. The user will get help, but who knows how pleasant an experience it will be for them. And once they do get help, the IRC logs are there but searching through them for that one user&#8217;s problem would be a nightmare for anyone wishing to follow-up. But! The user did get &#8220;live&#8221; assistance when they needed it most.</p>
<p>Hopefully by now I have shown you that for a new user, finding out where to get support and then actually getting that support in a reasonable manner is no small task. Yes, a person that is familiar with each system will obviously know how to find what they need or use each properly, but we have to approach this from the standpoint of a user who does NOT know.</p>
<h3>My Solution</h3>
<p>I now come to my actual idea. It originally started out in my mind as a simple one-on-one chat client but has since grown to hopefully be a one-stop-shop for a user in need of assistance and guidance. I will try to explain the evolution and reasons behind the idea.</p>
<p>A user has a problem and what’s to find the most efficient way to solve it. One of the fastest ways we can do this is to connect that user to another Human Being(tm) so they can &#8220;talk&#8221; about it. I know, this whole idea of actually having someone talk to someone else in real-time sounds crazy, but work with me. The feel of such a client would be minimalistic; think a simple one-on-one chat client. With one-on-one the new user would not feel as intimidated as in a massive IRC channel. Plus, they don&#8217;t even *have* to know it is an IRC channel. All they care about is that some is helping *them* with *their* problem; even if that someone is doing something as simple as guiding them in the right directions.</p>
<p>The workflow would be something as follows:</p>
<ol>
<li>User launches the live assistance application (it is already installed on their computer).</li>
<li>They type their question/problem into a dialog.</li>
<li>A chat window comes up notifying the user that their question has been posted and that hopefully someone will help them shortly.</li>
</ol>
<p>That’s it! No hunting through documentation, no new systems to learn, just a familiar IM chat interface.</p>
<p>&#8220;Well hold on there!&#8221; you may be wondering. &#8220;How can we ensure that the user gets help?&#8221; You ask. Well, we can&#8217;t I answer! But is this any different than the other methods I described previously? In all cases the user put their question out there and some kind souls decided to respond. Similarly, in this case, the client put the question out onto one of the many existing IRC support channels where people are listening 24/7. Another user on that channel sees the question and opts to start helping the user with their problem. The beauty here is that no party (supporter or supported) had to go anywhere new. The person on IRC stays on IRC and the person on the desktop didn&#8217;t need to stray anywhere new. The user with the problem didn’t have to hunt for anything.</p>
<p>This was the first part of my plans for such an application. Already I have a basic implementation in place for the chat client and supporting bot. But there are more things that can be done to extend this basic idea and really make it a big selling point for new users.</p>
<p>The first thing would be to give the user something to do while they wait for assistance. This could simply be a bot that tells the user about the various existing support options and provides links to each. This information would be presented to the user in the chat client so they would not need to go anywhere to hunt it down. In the future, the user&#8217;s problem may be queried against the forums or answers system to present them with possible things to look at while they wait. For now, the focus remains on having the user talk to someone that can help them.</p>
<p>Since all of the individual help sessions are logged. A simple web frontend could be created to be able to search through and even see which problems users are facing. These sessions could be tied to bug reports (much like answers are now). Both developers and usability people could benefit from the data as it would outline the actual process a user took to fix something or show holes in understanding.</p>
<p>I feel that having such a centralized, human centric, and user focused system is important for a large scale distribution which prides itself on being &#8220;Linux for human beings&#8221;.</p>
<p>Details and cool screenshots to come soon <img src='http://www.shtylman.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.shtylman.com/archives/154/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

