<?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>Bryce Boe</title>
	<atom:link href="http://www.bryceboe.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.bryceboe.com</link>
	<description>The Adventures of a UCSB Computer Science Ph.D. Student</description>
	<lastBuildDate>Tue, 13 Mar 2012 17:36:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Bypassing Gogo&#8217;s Inflight Internet Authentication</title>
		<link>http://www.bryceboe.com/2012/03/12/bypassing-gogos-inflight-internet-authentication/</link>
		<comments>http://www.bryceboe.com/2012/03/12/bypassing-gogos-inflight-internet-authentication/#comments</comments>
		<pubDate>Tue, 13 Mar 2012 00:19:29 +0000</pubDate>
		<dc:creator>Bryce Boe</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://www.bryceboe.com/?p=1025</guid>
		<description><![CDATA[Two weeks ago I attended SIGCSE 2012 in Raleigh, NC. The plane on my return flight had Internet access through Gogo&#8217;s Inflight Internet. While I think it&#8217;s incredibly awesome that Internet access is readily available to those who travel by plane, I personally feel it is not worth $12.95 for a few hours of access. [...]]]></description>
			<content:encoded><![CDATA[<p>Two weeks ago I attended <a href="http://www.sigcse.org/sigcse2012/">SIGCSE 2012</a> in Raleigh, NC. The plane on my return flight had Internet access through <a href="http://www.gogoair.com/">Gogo&#8217;s Inflight Internet</a>. While I think it&#8217;s incredibly awesome that Internet access is readily available to those who travel by plane, I personally feel it is not worth $12.95 for a few hours of access. Nevertheless, I figured I&#8217;d simply connect to Gogo&#8217;s network to see what sort of access was permitted to non-authenticated, i.e.,  non-paying, users. What I discovered surprised me: I was able to gain access to the entire Internet.</p>
<p>Immediately from links on their landing page it was apparent that Gogo permitted access to its own website, as well as the airline&#8217;s website and a few other third-party sites such as <a href="livingsocial.com">Living Social</a>, and <a href="http://eventful.com/">Eventful</a>. Attempting to access any other website resulted in a redirect to Gogo&#8217;s landing page. Gogo appears to accomplish this by responding with an HTTP redirect to any standard HTTP request, i.e., port 80, that is sent to a non-permitted IP address.</p>
<p>Two common techniques for bypassing pay-for-wireless providers are <a href="http://www.cs.uit.no/~daniels/PingTunnel/">TCP-over-ICMP</a> and <a href="http://analogbit.com/tcp-over-dns_howto">TCP-over-DNS</a>. In a nutshell, TCP is the protocol required to browse the web, ICMP is the protocol used by the command `ping` to determine if a host is available, and DNS is required to resolve domain names like <a href="http://www.google.com">www.google.com</a> to an IP address. When TCP is not completely available yet either ICMP or DNS is, then it is possible to encapsulate TCP connections over the other available protocol. Gogo blocked my ping attempts, hence TCP-over-ICMP was not possible. However, while Gogo doesn&#8217;t permit direct access to external DNS servers, Gogo&#8217;s DNS server recursively resolved the DNS queries I made. Therefore, Gogo appears to be susceptible to TCP-over-DNS. Despite not being able to verify this finding, I will simply state that Gogo can remedy this, if necessary, by only responding to white-listed DNS queries for non-authenticated users.</p>
<p>As a quick aside, I would like to mention I made an attempt to responsibly disclose this information to Gogo prior to posting this article [<a href="http://www.bryceboe.com/wordpress/wp-content/uploads/2012/03/gogo_dm.png" target="_blank">1</a>, <a href="https://twitter.com/#!/Gogo/status/176504298967015424">2</a>]. I contacted one of their twitter representatives via email who informed me the right person would contact me. After a few days with no response, I sent a follow up email to the same twitter representative. While that representative has continued to tweet since my followup, I have received no replies. Thus, I have come to the conclusion that Gogo is uninterested. I proceed with the knowledge that this authentication bypass in no way compromises Gogo&#8217;s security; therefore, it is of negligible importance to Gogo&#8217;s existing customers. Finally, I proceed knowing very well that Gogo&#8217;s sysadmins can correct the underlying problem in a very brief period of time and I even present them with the solution.</p>
<p>♫<a href="http://www.youtube.com/watch?v=GI6CfKcMhjY&#038;t=1m37s">Now back to the good part</a>!♫</p>
<p>I use <a href="https://www.google.com/chrome">Google Chrome</a> as my primary browser and along with it I have installed a few extensions that depend on connections to various Google services. When Chrome is open and does not have a connection to the Internet, some of these extensions, such as the <a href="https://chrome.google.com/webstore/detail/apflmjolhbonpkbkooiamcnenbmbjcbf">Google Reader Notifier</a>, adjust their icon to indicate their disconnected status. As expected, the Google Reader Notifier extension indicated that I was not connected to the Internet. However, as I was browsing around Gogo&#8217;s landing page and permitted sites, I was shocked when the <a href="https://chrome.google.com/webstore/detail/kcnhkahnjcbndmmehfkdnkjomaanaooo">Google Voice</a> extension notified me of a new text message and shocked again when I successfully replied. I had mistakenly stumbled across a hole in Gogo&#8217;s access policies and decided to dig deeper.</p>
<p>As I previously mentioned, Gogo redirected to their landing page upon any standard HTTP request. However, the same was not true for HTTPS connections, which by default occur on TCP port 443. Thus, for some unknown reason, my computer was able to connect to <a href="http://www.google.com">www.google.com</a> via HTTPS. Immediately I tried other Google services, like <a href="http://mail.google.com">mail.google.com</a> for Gmail, and <a href="http://docs.google.com">docs.google.com</a> for Google docs; neither worked. Nevertheless, any Google service accessible via HTTPS and addressed under the <a href="http://www.google.com">www.google.com</a> domain worked flawlessly.</p>
<p>After poking around to find a list of Google services meeting these requirements, I had an epiphany. While I probably learned this information at some point in my past, I had a hunch that Google&#8217;s front-end web servers would likely provide the correct response to any Google web service. Hence, I opened up my /etc/hosts file on my OS X machine, and added the following line:</p>
<p><code>74.125.225.40 mail.google.com</code></p>
<p>Voila! Immediately, I was able to access Gmail. The IP address, 74.125.225.40, corresponds to the IP address my computer was successfully able to connect to in order to access services under the <a href="http://www.google.com">www.google.com</a> domain. By adding this manual entry to my hosts file, I informed my operating system to use the provided IP address when attempting to connect to mail.google.com. In order to additionally receive successful access to <a href="http://plus.google.com">Google+</a>, <a href="http://youtube.com">YouTube</a>, <a href="http://docs.google.com">Google Docs</a>, <a href="http://code.google.com">Google Code</a>, and Google&#8217;s chat interface, I updated the line to the following:</p>
<p><code>74.125.225.40 mail.google.com plus.google.com youtube.com docs.google.com code.google.com chatenabled.mail.google.com</code></p>
<p>What I previously described is how I was able to bypass Gogo&#8217;s Inflight Internet Authentication in order to access a number of Google services for free. What remains is how to utilize this information to access the entire Internet. The answer to this question lies with <a href="http://code.google.com/appengine/">Google AppEngine</a>.</p>
<p>Google AppEngine (GAE) is a cloud-based web application hosting service provided by Google. Anyone can run a GAE application on Google&#8217;s servers. As I previously described, Google&#8217;s front-end web servers respond to requests for any Google web service, including third-party GAE applications. The final piece of the puzzle is that GAE allows its applications to themselves make web requests. Therefore, a well written GAE application can operate as a proxy server. In fact, there are a number of available packages for running simple GAE proxy servers. <a href="http://www.labnol.org/internet/setup-proxy-server/12890/">Digital Inspiration</a> and <a href="http://mintywhite.com/software-reviews/security-software/set-proxy-google-app-engine/">Windows Guides</a> each provide tutorials for setting up such proxies. The Windows Guides tutorial even links to a working example at <a href="https://jttm-server-prox.appspot.com/">https://jttm-server-prox.appspot.com/</a>. A user of Gogo&#8217;s Inflight Internet need only add jttm-server-prox.appspot.com to their hosts file in order to utilize this proxy to access much of the Internet.</p>
<p>I have previously described how Gogo&#8217;s Inflight Internet authentication can be bypassed through the combination of a custom hosts file and a GAE proxy server. The remainder of this article will detail how Gogo can fix this problem.</p>
<p>The root question, is: why does Gogo allow non-authenticated access to some Google IPs? While my answer to this question is purely speculation, the solution I offer will absolutely solve the problem. I speculate that Gogo allows access to some Google IPs because of <a href="http://www.google.com/analytics/">Google Analytics</a> and <a href="https://www.google.com/adsense/">Google Adsense</a>, indicated in client scripts by the domains www.google-analytics.com and ad.doubleclick.net respectively. If correct, Gogo&#8217;s sysadmins simply white-listed a few too many IP addresses. Regardless, the point is moot because any Google front-end web server IP address, including those for Analytics and Adsense, will serve the reply for all Google web services, most notably GAE applications. Hence, by white-listing any single Google front-end web server IP address, Gogo is essentially providing access to the entire Internet. It follows, that the simplest solution to this bypass is for Gogo to completely disable direct access to Google IPs from non-authenticated users.</p>
<p>While the above solution absolutely works, it prevents Gogo from tracking users and serving ads using Google services. Of course, serving ads is pointless when non-authenticated users cannot visit the target site of the advertisement, so let&#8217;s forget about Google Adsense. Google Analytics on the other hand, is a useful tool for monitoring users&#8217; access to a website. Let&#8217;s now proceed under the assumption that it is essential for Gogo&#8217;s non-authenticated users to have access to whatever Google service Gogo intended to allow, and for simplicity assume it is the Google Analytics tracking service. The question now is: how can Gogo allow access to the Google Analytics tracking service without allowing access to all other Google services? This answer partially lies with <a href="http://en.wikipedia.org/wiki/Server_Name_Indication">Server Name Indication</a>.</p>
<p>Server Name Indication (SNI) is implemented on most modern web browsers and allows a web server with a single IP address to serve multiple TLS certificates. The proper certificate is returned in response to the hostname provided in the TLS client handshake. The use of SNI is why, despite using the same IP address for all the aforementioned services, Google is able to return the appropriate domain-specific TLS certificate. Therefore, Gogo can additionally white-list on the SNI-hostname in order to prevent the authentication bypass and still allow access to Google Analytics. However, things are not so simple, as Google&#8217;s servers do not depend on the presence of the SNI-hostname in the TLS client handshake.</p>
<p>In the absence of SNI, Google&#8217;s front-end web servers return the default TLS certificate for that particular server, yet, the server still responds with the requested content as indicated in the HTTP host header. Because the HTTP host header is encrypted, as well as the entire response, it is not possible to discern desired requests from undesired requests. One solution is to only allow such access to Google Analytics if the client supports SNI and the SNI-hostname is in the white-list. While this approach would work, it appears it would restrict access to Google Analytics for some browsers that are <a href="http://en.wikipedia.org/wiki/Server_Name_Indication#No_support">still commonly used</a>.</p>
<p>Regardless, I suspect that Google&#8217;s front-end web servers do not verify consistency between the SNI-hostname and the HTTP host header. Under that assumption, it would still be possible, in the presence of an SNI-hostname white-list, to bypass Gogo&#8217;s authentication with a custom browser (or local proxy server) that negotiates TLS handshakes using only the expected SNI-hostname yet still makes the desired Google web service request. While I don&#8217;t believe anything is readily accessible to make this process easy for 99.9% of Gogo&#8217;s potential customers, it only requires a single person&#8217;s determination to make it so. Thus, the only be-all-end-all solution to prevent this bypass is for Gogo to completely disable direct access to Google IPs from non-authenticated users.</p>
<p>There is, of course, one other possible solution: Gogo could <a href="http://en.wikipedia.org/wiki/Man-in-the-middle_attack">man-in-the-middle</a> the desired Google web services in order to perform filtering on the HTTP host header. However, this approach could have unforeseen consequences. Therefore, I do not recommend it.</p>
<p>In conclusion, I have described how one can currently bypass Gogo&#8217;s Inflight Internet authentication to access much of the Internet using a custom host file and a Google AppEngine proxy. I have also described how Gogo can somewhat block this bypass by supplementing their IP white-list with both an SNI requirement and an SNI-hostname white-list. Finally, I speculated that even with the aforementioned solution, it would still be possible for a determined user to bypass their authentication. Thus, I stated the only real solution is for Gogo to not allow any direct access between non-authenticated users and Google web servers.</p>
<p>Happy &#8220;free&#8221; surfing, for now anyway <img src='http://www.bryceboe.com/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.bryceboe.com/2012/03/12/bypassing-gogos-inflight-internet-authentication/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>My Major Area Exam Announcement</title>
		<link>http://www.bryceboe.com/2012/03/06/my-major-area-exam-announcement/</link>
		<comments>http://www.bryceboe.com/2012/03/06/my-major-area-exam-announcement/#comments</comments>
		<pubDate>Wed, 07 Mar 2012 06:14:18 +0000</pubDate>
		<dc:creator>Bryce Boe</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[phd]]></category>
		<category><![CDATA[teaching]]></category>

		<guid isPermaLink="false">http://www.bryceboe.com/?p=1015</guid>
		<description><![CDATA[Major Area Exam Bryce Boe March 12, 2012 2:00 PM HFH 1132 Committee: Diana Franklin (chair), Tim Sherwood, Kevin Almeroth Title: Automated Feedback and Assessment of Student Submitted Code Abstract: Increases in class sizes pose a problem for computer science instructors. With a larger number of students to educate, instructors are forced to choose between [...]]]></description>
			<content:encoded><![CDATA[<p>Major Area Exam<br />
Bryce Boe</p>
<p>March 12, 2012<br />
2:00 PM<br />
HFH 1132</p>
<p>Committee:<br />
Diana Franklin (chair), Tim Sherwood, Kevin Almeroth</p>
<p>Title: Automated Feedback and Assessment of Student Submitted Code</p>
<p>Abstract:<br />
Increases in class sizes pose a problem for computer science instructors. With a larger number of students to educate, instructors are forced to choose between assigning fewer assignments and devoting more of their time to satisfying the additional demands of larger class sizes. The first option, reducing the number of assignments, decreases the overall quality of a course, whereas the latter option, working more, scales only so far. Fortunately, a variety of tools exists which provides instructors with a third option. Automated feedback and assessment systems can provide significantly more detailed feedback to large numbers of students than instructors are capable of providing, and do so nearly instantaneously. The use of such systems allows instructors to continue to assign a similar number of comprehensive assignments despite growing class sizes, and also makes it possible for instructors to focus their time on students who require additional assistance with coursework.</p>
<p>In this talk I will provide a brief history of automated feedback and assessment systems, followed by an in-depth analysis of state-of-the-art automated feedback and assessment systems. Finally, I will provide an overview of additional research opportunities provided in other areas of computer science as a byproduct of using automated feedback and assessment systems.</p>
<p>Everyone is welcome to attend!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bryceboe.com/2012/03/06/my-major-area-exam-announcement/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Implementation of a Process-Based Job Management System in C</title>
		<link>http://www.bryceboe.com/2012/02/23/implementation-of-a-process-based-job-management-system-in-c/</link>
		<comments>http://www.bryceboe.com/2012/02/23/implementation-of-a-process-based-job-management-system-in-c/#comments</comments>
		<pubDate>Fri, 24 Feb 2012 07:03:54 +0000</pubDate>
		<dc:creator>Bryce Boe</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.bryceboe.com/?p=998</guid>
		<description><![CDATA[A few days ago I wrote about a few differences between using C and python to handle a process-based job management system. My discussion covered performance, development time, dependencies, and portability. I ended with the conclusion that despite C being vastly superior in performance, the relative difference in performance between various job management systems is [...]]]></description>
			<content:encoded><![CDATA[<p>A few days ago I wrote about <a href="http://www.bryceboe.com/2012/02/20/process-based-job-management-in-c-and-python/" title="Process-Based Job Management in C and Python">a few differences between using C and python to handle a process-based job management system</a>. My discussion covered performance, development time, dependencies, and portability. I ended with the conclusion that despite C being vastly superior in performance, the relative difference in performance between various job management systems is irrelevant when considering the job processing time. Therefore, I recommended using python for such a task due to faster development times, built-in support for multiprocessing (no need for third-party libraries), and the portability one immediately gains by using python.</p>
<p>In spite of my continuing recommendation to use python for such a task, I was curious what a C solution might look like. Thus, I set out to write, and did write, a simple process-based job management system in C that offers similar functionality as python&#8217;s <a href="http://docs.python.org/library/multiprocessing.html#module-multiprocessing.pool">multiprocessing.Pool</a> class. Take note that writing this system required more time than the equivalent python code would have, however, the point is moot because python has the multiprocessing.Pool class. Furthermore, whoever wants to use this system must manually include it in their project, thus introducing a third-party dependency in their code. Finally, this code will not compile in the typical Windows development environment as it relies on <a href="http://en.wikipedia.org/wiki/POSIX">POSIX-based</a> system calls. Hence, for all the reasons I previously mentioned, this C implementation is quite inferior to python&#8217;s multiprocessing.Pool class.</p>
<p>The source that I reference throughout the remainder of this post can be <a href="https://gist.github.com/1894848">found and downloaded in entirety</a>. On a POSIX-based machine the code can be compiled via <code class="inline">gcc main.c job_management.c</code> and the test program can be run via <code class="inline">./a.out</code>.</p>
<p>The system, or library, is contained in two files: <strong>job_management.h</strong> and <strong>job_management.c</strong>. Anyone familiar with C or C++ development knows that <strong>job_management.h</strong> is a header file which contains the structures and function prototypes whereas <strong>job_management.c</strong> contains the implementation. The entire library functionality is exposed through three functions: <code class="inline">manager_init</code>, <code class="inline">manager_run_jobs</code>, and <code class="inline">manager_destruct</code>.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span> manager_init<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> manager <span style="color: #339933;">*</span>manager<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> num_workers<span style="color: #339933;">,</span>
		  <span style="color: #993333;">void</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>input_callback<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
		  <span style="color: #993333;">void</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>output_callback<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
		  <span style="color: #993333;">void</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">*</span>work_function<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> <span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Aside from the pre-allocated <em>manager</em> structure that all the functions require as their first parameter, the <code class="inline">manager_init</code> function requires four other parameters: <em>num_workers</em>, <em>input_callback</em>, <em>output_callback</em>, and <em>work_function</em>. The <em>num_workers</em> parameter specifies an upper bound on how many worker processes to start. Each of the remaining parameters are function pointers to functions that must each have a single char pointer parameter and return no value. I will describe the purpose of these functions in the order that they execute when considering only a single job.</p>
<p>The <em>input_callback</em> function is called by the master process, once per job, in order to fetch the input for the job. The callback function stores the job input in the provided buffer before returning. The <em>work_function</em> function is the reason for the entire system as this function performs the job processing. In this function, the provided buffer serves both as job input and job output. On invocation, the buffer contains the result of a prior call to <em>input_callback</em> which has been sent over a pipe between the master process and worker process. On return, the buffer should contain the job output which will then be sent back to the master process. The <em>output_callback</em> function is called by the master process as each job is completed. In this case, the buffer contains the output of a completed job.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">int</span> manager_run_jobs<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> manager <span style="color: #339933;">*</span>manager<span style="color: #339933;">,</span> <span style="color: #993333;">int</span> num_jobs<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Once the manager has been properly set up, a number of jobs can be started via <code class="inline">manager_run_jobs</code> which takes one additional argument, <em>num_jobs</em>. Intuitively this parameter represents the number of jobs to process. This function contains the most complicated piece of the system as it is responsible for forking the processes, setting up the pipes between the master and workers, cleaning up the address space and file descriptor table for the workers, and properly using I/O multiplexing in order to both send job input and receive job output.</p>
<p>One additional complication that the <code class="inline">manger_run_jobs</code> function has to handle is <a href="http://www.bryceboe.com/2010/08/26/python-multiprocessing-and-keyboardinterrupt/" title="Python Multiprocessing and KeyboardInterrupt">the issue</a> that started this entire series of blog posts; that is, the want to gracefully exit the job management system when a keyboard interrupt (SIGINT), occurs. Gracefully exiting means any jobs that are running at the time of the keyboard interrupt will successfully complete prior to exiting, thus giving the master process the chance to save partial results. This function handles the desired behavior through the combination of a global <a href="http://en.wikipedia.org/wiki/Volatile_variable">volatile</a> value that&#8217;s periodically checked within this function&#8217;s primary loop, and a SIGINT handler function that updates the value. Worker processes are unaffected by SIGINT as they are set to ignore it.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">void</span> manager_destruct<span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> manager <span style="color: #339933;">*</span>manager<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>The last function, <code class="inline">manager_destruct</code>, conveniently frees the contents of the <em>manager</em> structure. It is important to note that this function is also called by each worker as part of its address space and file descriptor table clean up. For this reason, the <code class="inline">manager_destruct</code> function handles the closing of some <em>FILE</em> structures. Otherwise, this function is incredibly simple.</p>
<p>As previously mentioned, my job_management library is simple and thus is no where near as flexible as python&#8217;s multiprocessing.Pool class. Furthermore, my library has no support for data serialization as it relies on messages being no larger than <em>MAX_MESSAGE</em> bytes in size, and has a limitation that the message contents span only a single line. These restrictions were chosen for simplicity and are, by no means, a limitation of C. However, again, I must point out that object serialization is provided by default with python, and is built into the multiprocess.Pool class.</p>
<p>Below is an example program that demonstrates using my process-based job management system. Note that this code really isn&#8217;t that complicated, especially when compared to <a href="http://www.bryceboe.com/2012/02/14/python-multiprocessing-pool-and-keyboardinterrupt-revisited/" title="Python Multiprocessing Pool and KeyboardInterrupt Revisited">the python solution that gracefully handles the keyboard interrupt</a>. Of course, the python solution is without dependencies and much more portable. <img src='http://www.bryceboe.com/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Happy coding!</p>
<div id="gist-1894848" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="cp">#include &lt;stdio.h&gt;</span></div><div class='line' id='LC2'><span class="cp">#include &lt;string.h&gt;</span></div><div class='line' id='LC3'><span class="cp">#include &quot;job_manager.h&quot;</span></div><div class='line' id='LC4'><br/></div><div class='line' id='LC5'><span class="kt">int</span> <span class="n">job_num</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span></div><div class='line' id='LC6'><br/></div><div class='line' id='LC7'><span class="cm">/* This function is a worker function that does the work. On invocation, buffer</span></div><div class='line' id='LC8'><span class="cm">   contains a single line containing the input for the job. When complete,</span></div><div class='line' id='LC9'><span class="cm">   buffer should store the result of the job. The contents of the result must</span></div><div class='line' id='LC10'><span class="cm">   fit on a single line that ends with a single &#39;\n&#39;. */</span></div><div class='line' id='LC11'><span class="kt">void</span> <span class="nf">do_work</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC12'>&nbsp;&nbsp;<span class="kt">int</span> <span class="n">job</span> <span class="o">=</span> <span class="n">atoi</span><span class="p">(</span><span class="n">buffer</span><span class="p">);</span></div><div class='line' id='LC13'>&nbsp;&nbsp;<span class="n">printf</span><span class="p">(</span><span class="s">&quot;%d started on job %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">getpid</span><span class="p">(),</span> <span class="n">job</span><span class="p">);</span></div><div class='line' id='LC14'>&nbsp;&nbsp;<span class="n">sleep</span><span class="p">(</span><span class="mi">3</span> <span class="o">+</span> <span class="n">getpid</span><span class="p">()</span> <span class="o">%</span> <span class="mi">3</span><span class="p">);</span></div><div class='line' id='LC15'>&nbsp;&nbsp;<span class="n">snprintf</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">MAX_MESSAGE</span><span class="p">,</span> <span class="s">&quot;%d Success</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">job</span><span class="p">);</span></div><div class='line' id='LC16'><span class="p">}</span></div><div class='line' id='LC17'><br/></div><div class='line' id='LC18'><span class="cm">/* The message to send to the worker must be stored in the provided buffer of</span></div><div class='line' id='LC19'><span class="cm">   size MAX_MESSAGE. The contents must fit on a single line that ends with a</span></div><div class='line' id='LC20'><span class="cm">   single &#39;\n&#39; */</span></div><div class='line' id='LC21'><span class="kt">void</span> <span class="nf">prepare_job</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC22'>&nbsp;&nbsp;<span class="n">snprintf</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">MAX_MESSAGE</span><span class="p">,</span> <span class="s">&quot;%d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">job_num</span><span class="o">++</span><span class="p">);</span></div><div class='line' id='LC23'><span class="p">}</span></div><div class='line' id='LC24'><br/></div><div class='line' id='LC25'><span class="cm">/* Process the single line result returned from the worker */</span></div><div class='line' id='LC26'><span class="kt">void</span> <span class="nf">process_result</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC27'>&nbsp;&nbsp;<span class="n">printf</span><span class="p">(</span><span class="s">&quot;%s&quot;</span><span class="p">,</span> <span class="n">buffer</span><span class="p">);</span></div><div class='line' id='LC28'><span class="p">}</span></div><div class='line' id='LC29'><br/></div><div class='line' id='LC30'><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span></div><div class='line' id='LC31'>&nbsp;&nbsp;<span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">num_jobs</span><span class="p">;</span></div><div class='line' id='LC32'>&nbsp;&nbsp;<span class="k">struct</span> <span class="n">manager</span> <span class="n">manager</span><span class="p">;</span></div><div class='line' id='LC33'><br/></div><div class='line' id='LC34'>&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="n">argc</span> <span class="o">!=</span> <span class="mi">3</span><span class="p">)</span> <span class="p">{</span></div><div class='line' id='LC35'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">printf</span><span class="p">(</span><span class="s">&quot;Usage: %s workers jobs</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span></div><div class='line' id='LC36'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="mi">1</span><span class="p">;</span></div><div class='line' id='LC37'>&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC38'>&nbsp;&nbsp;<span class="n">num_jobs</span> <span class="o">=</span> <span class="n">atoi</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span></div><div class='line' id='LC39'><br/></div><div class='line' id='LC40'>&nbsp;&nbsp;<span class="n">manager_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">manager</span><span class="p">,</span> <span class="n">atoi</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="n">prepare_job</span><span class="p">,</span> <span class="n">process_result</span><span class="p">,</span> <span class="n">do_work</span><span class="p">);</span></div><div class='line' id='LC41'>&nbsp;&nbsp;<span class="n">i</span> <span class="o">=</span> <span class="n">manager_run_jobs</span><span class="p">(</span><span class="o">&amp;</span><span class="n">manager</span><span class="p">,</span> <span class="n">num_jobs</span><span class="p">);</span></div><div class='line' id='LC42'>&nbsp;&nbsp;<span class="n">manager_destruct</span><span class="p">(</span><span class="o">&amp;</span><span class="n">manager</span><span class="p">);</span></div><div class='line' id='LC43'>&nbsp;&nbsp;<span class="n">printf</span><span class="p">(</span><span class="s">&quot;%d of %d jobs completed</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="n">num_jobs</span><span class="p">);</span></div><div class='line' id='LC44'>&nbsp;&nbsp;<span class="k">return</span> <span class="mi">0</span><span class="p">;</span></div><div class='line' id='LC45'><span class="p">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1894848/1ac13cdf3575dc66eb468b5351cb0d8cbe047304/main.c" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1894848#file_main.c" style="float:right;margin-right:10px;color:#666">main.c</a>
            <a href="https://gist.github.com/1894848">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

]]></content:encoded>
			<wfw:commentRss>http://www.bryceboe.com/2012/02/23/implementation-of-a-process-based-job-management-system-in-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Process-Based Job Management in C and Python</title>
		<link>http://www.bryceboe.com/2012/02/20/process-based-job-management-in-c-and-python/</link>
		<comments>http://www.bryceboe.com/2012/02/20/process-based-job-management-in-c-and-python/#comments</comments>
		<pubDate>Mon, 20 Feb 2012 23:56:41 +0000</pubDate>
		<dc:creator>Bryce Boe</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.bryceboe.com/?p=944</guid>
		<description><![CDATA[I had an interesting discussion with my buddy Ali after he read my previous post, Python Multiprocessing Pool and KeyboardInterrupt Revisited. The discussion was around the question, &#8220;what are the benefits of using the python multiprocessing.Pool class over writing a simple process-based job management system in C?&#8221; We started with a discussion of performance. It’s [...]]]></description>
			<content:encoded><![CDATA[<p>I had an interesting discussion with my buddy Ali after he read my previous post, <a href="http://www.bryceboe.com/2012/02/14/python-multiprocessing-pool-and-keyboardinterrupt-revisited/">Python Multiprocessing Pool and KeyboardInterrupt Revisited</a>. The discussion was around the question, &#8220;what are the benefits of using the python <a href="http://docs.python.org/library/multiprocessing.html#module-multiprocessing.pool">multiprocessing.Pool</a> class over writing a simple process-based job management system in C?&#8221;</p>
<p>We started with a discussion of performance. It’s no secret that C will outperform python in any task; after all python is an interpreted language and the standard python implementation is written in C. However, Ali and my discussion was not focused on the performance of the jobs themselves, but rather on the performance of a job management system that could be gracefully interrupted. In such a system, where the majority of work is done in job processing, the question of the job management system&#8217;s performance is irrelevant; it makes little difference if C can launch all the workers thirty times faster when python still does it in well under a second. As an aside, it&#8217;s trivial to call a C program from python, or even to write a <a href="http://www.bryceboe.com/2010/09/14/properly-handling-the-keyboard-interrupt-exception-sigint-within-a-python-c-module/" title="Properly Handling the Keyboard Interrupt Exception (SIGINT) within a Python C Module">python C module</a> for fast job processing performance.</p>
<p>Once the irrelevance of the job management performance was agreed upon, Ali and I discussed development time, dependencies and portability. Having written both a significant amount of C and python code pertaining to <a href="http://cs.ucsb.edu/~bboe/p/cv#teaching">operating system concepts</a>, I know that anyone with equivalent experience can much more efficiently code a process-based job management system in python than in C. This holds true, even without the multiprocessing module and when using only the low level features provided by the <a href="http://docs.python.org/library/os.html">os package</a>. The two primary reasons for faster development time are dynamic types, and garbage collection. Additionally, python provides a lot more out-of-the-box functionality, e.g., string manipulation and basic data structures such as lists and dictionaries; all features that contribute to faster development time.</p>
<p>Of course, if one had all the needed libraries in C, then my only argument in favor of python is the lack of types and implicit memory management. The choice between C and python in this case is simply up to personal preference. However, having the required C libraries is a problem on its own. This is where my lack of real-world C experience appears as I’m not familiar with well-written C libraries that provide python-like string manipulation and basic data structures, nor am I familiar with a well written process-based job management library. Nevertheless, even if these libraries were easily available, they are additional dependencies that must be present in order to run any code utilizing them.</p>
<p>Managing dependencies can be a pain, especially in the absence of an automated process for obtaining them. For example, I wrote some code for a computer graphics class a few years ago that I recently wanted to compile. As I recall, it took me a few hours to find and install all the required OpenGL dependencies before I could compile my own code. Compare that to the 90%+ of python programs I’ve written which have no external dependencies. This vast amount of code <em>still</em> works out-of-the-box across multiple platforms.</p>
<p>Portability is my final argument in favor of python over C. While <a href="http://en.wikipedia.org/wiki/ANSI_C">ANSI-C</a> based libraries should work across multiple platforms, dealing with process management is a whole other can of worms as this <em>drastically</em> differs between operating systems. Again, my inexperience shows as I am not familiar with any process management libraries that are compatible with both Windows and <a href="http://en.wikipedia.org/wiki/POSIX">POSIX-based</a> systems. Moreover, I am not even sufficiently familiar with the Windows API to know its equivalent functions to <a href="http://pubs.opengroup.org/onlinepubs/009604599/functions/fork.html">fork</a>, <a href="http://pubs.opengroup.org/onlinepubs/009604499/functions/exec.html">exec</a>, <a href="http://pubs.opengroup.org/onlinepubs/009604599/functions/pipe.html">pipe</a> and <a href="http://pubs.opengroup.org/onlinepubs/007904975/functions/dup.html">dup</a> that are needed to write a process-based job management system for Windows. Nevertheless, with python, one needn’t worry about such things because the majority of the functionality in the os package is supported on both Windows and POSIX-based systems. Most importantly the multiprocessing module is supported on both, and thus <em>anyone</em> who installs python, independent of their operating system, can run the multiprocessing examples I previously provided [<a href="http://www.bryceboe.com/2010/08/26/python-multiprocessing-and-keyboardinterrupt/" title="Python Multiprocessing and KeyboardInterrupt">1</a>, <a href="http://www.bryceboe.com/2011/01/28/the-python-multiprocessing-queue-and-large-objects/" title="The Python Multiprocessing Queue and Large Objects">2</a>].</p>
<p>While Ali and I had a great discussion going, we still hadn’t gotten to the root of his question. Ali didn’t care about development time, nor portability. The problem was that he didn’t see any significant advantages to using the multiprocessing.Pool class when he could instead quickly write a process-based job management system in C utilizing fork to spawn processes and pipe to handle the <a href="http://en.wikipedia.org/wiki/Inter-process_communication">inter-process communication</a> (IPC). As it turns out, Ali wasn’t aware that the python multiprocessing.Pool class internally handles all the IPC. Without the built-in IPC support, Ali’s concerns would be valid as some other communication mechanism would need to be explicitly written to communicate between the master process and its workers. Fortunately, in python we get all that for free with both the multiprocessing.Pool and <a href="http://docs.python.org/library/multiprocessing.html#exchanging-objects-between-processes">multiprocessing.Queue</a> classes.</p>
<p>Personally, the choice of using python for such a task is a no-brainer because I can develop the system faster without the need for external dependencies and have confidence that it will work on any operating system that python runs on. Nevertheless, my curiosity peaked and I set out to write a <em>simple</em> process-based job management system in C. The system is complete, <del datetime="2012-02-24T07:02:59+00:00">though I&#8217;ve yet to write about it</del><ins datetime="2012-02-24T07:02:59+00:00"> and I&#8217;ve now written about it. Read the followup: <a href="http://www.bryceboe.com/2012/02/23/implementation-of-a-process-based-job-management-system-in-c/" title="Implementation of a Process-Based Job Management System in C">Implementation of a Process-Based Job Management System in C</a></ins></p>
]]></content:encoded>
			<wfw:commentRss>http://www.bryceboe.com/2012/02/20/process-based-job-management-in-c-and-python/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Python Multiprocessing Pool and KeyboardInterrupt Revisited</title>
		<link>http://www.bryceboe.com/2012/02/14/python-multiprocessing-pool-and-keyboardinterrupt-revisited/</link>
		<comments>http://www.bryceboe.com/2012/02/14/python-multiprocessing-pool-and-keyboardinterrupt-revisited/#comments</comments>
		<pubDate>Tue, 14 Feb 2012 21:54:28 +0000</pubDate>
		<dc:creator>Bryce Boe</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.bryceboe.com/?p=916</guid>
		<description><![CDATA[Earlier today I was in the process of cleaning out some Chrome bookmarks when I came across a post by John M. Reese I bookmarked titled, Python: Using KeyboardInterrupt with a Multiprocessing Pool. I had bookmarked John&#8217;s post a number of months ago as it referenced my previous post, Python Multiprocessing and KeyboardInterrupt, however, not [...]]]></description>
			<content:encoded><![CDATA[<p>Earlier today I was in the process of cleaning out some Chrome bookmarks when I came across a post by John M. Reese I bookmarked titled, <a href="http://noswap.com/blog/python-multiprocessing-keyboardinterrupt/">Python: Using KeyboardInterrupt with a Multiprocessing Pool</a>. I had bookmarked John&#8217;s post a number of months ago as it referenced my previous post, <a href="http://www.bryceboe.com/2010/08/26/python-multiprocessing-and-keyboardinterrupt/">Python Multiprocessing and KeyboardInterrupt</a>, however, not until today had I been able to look at his findings.</p>
<p>John suggests that by having the worker processes ignore SIGINT, the signal that results in python&#8217;s KeyboardInterrupt, the entire problem can be solved. Astute readers will note that I actually used the same approach in my <a href="http://www.bryceboe.com/2010/08/26/python-multiprocessing-and-keyboardinterrupt/#georges">second update</a> to my aforementioned post, which suffered from the problem that intermediate results could not be processed, i.e., jobs that completed prior to the keyboard interrupt. While, John&#8217;s solution did educate me as to the existence of the initializer and initargs parameters to the <a href="http://docs.python.org/library/multiprocessing.html#module-multiprocessing.pool">multiprocessing.Pool</a> function, his solution in-fact does not work. The only reason it appears to work is due to the <code class="inline">time.sleep(10)</code> in his try block. In most code this <code class="inline">sleep</code> call would not exist, rather the code would immediately call <code class="inline">join()</code> on the pool object.</p>
<p>In the absence of the delay introduced by the <code class="inline">sleep</code> call, John&#8217;s code still suffers from the original problem which is the KeyboardInterrupt exception does not reach the main process until all of the jobs have completed. The proper solution to the problem would be to fix the multiprocessing library to allow the <code class="inline">join</code> function to be interrupted. Until then, my suggestion of rolling your own pool functionality is the best solution I am aware of.</p>
<p>Below is a verbatim copy of my original solution for your convenience:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #ff7700;font-weight:bold;">import</span> multiprocessing, <span style="color: #dc143c;">os</span>, <span style="color: #dc143c;">signal</span>, <span style="color: #dc143c;">time</span>, <span style="color: #dc143c;">Queue</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> do_work<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Work Started: %d'</span> <span style="color: #66cc66;">%</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">getpid</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #dc143c;">time</span>.<span style="color: black;">sleep</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">'Success'</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> manual_function<span style="color: black;">&#40;</span>job_queue, result_queue<span style="color: black;">&#41;</span>:
    <span style="color: #dc143c;">signal</span>.<span style="color: #dc143c;">signal</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">signal</span>.<span style="color: black;">SIGINT</span>, <span style="color: #dc143c;">signal</span>.<span style="color: black;">SIG_IGN</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #ff7700;font-weight:bold;">not</span> job_queue.<span style="color: black;">empty</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">try</span>:
            job = job_queue.<span style="color: black;">get</span><span style="color: black;">&#40;</span>block=<span style="color: #008000;">False</span><span style="color: black;">&#41;</span>
            result_queue.<span style="color: black;">put</span><span style="color: black;">&#40;</span>do_work<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #dc143c;">Queue</span>.<span style="color: black;">Empty</span>:
            <span style="color: #ff7700;font-weight:bold;">pass</span>
        <span style="color: #808080; font-style: italic;">#except KeyboardInterrupt: pass</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    job_queue = multiprocessing.<span style="color: #dc143c;">Queue</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    result_queue = multiprocessing.<span style="color: #dc143c;">Queue</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">6</span><span style="color: black;">&#41;</span>:
        job_queue.<span style="color: black;">put</span><span style="color: black;">&#40;</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>
&nbsp;
    workers = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">3</span><span style="color: black;">&#41;</span>:
        tmp = multiprocessing.<span style="color: black;">Process</span><span style="color: black;">&#40;</span>target=manual_function,
                                      args=<span style="color: black;">&#40;</span>job_queue, result_queue<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        tmp.<span style="color: black;">start</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        workers.<span style="color: black;">append</span><span style="color: black;">&#40;</span>tmp<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">for</span> worker <span style="color: #ff7700;font-weight:bold;">in</span> workers:
            worker.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">KeyboardInterrupt</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'parent received ctrl-c'</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> worker <span style="color: #ff7700;font-weight:bold;">in</span> workers:
            worker.<span style="color: black;">terminate</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            worker.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #ff7700;font-weight:bold;">not</span> result_queue.<span style="color: black;">empty</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span> result_queue.<span style="color: black;">get</span><span style="color: black;">&#40;</span>block=<span style="color: #008000;">False</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://www.bryceboe.com/2012/02/14/python-multiprocessing-pool-and-keyboardinterrupt-revisited/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tethering OS X Lion to Android</title>
		<link>http://www.bryceboe.com/2011/10/20/tethering-os-x-lion-to-android/</link>
		<comments>http://www.bryceboe.com/2011/10/20/tethering-os-x-lion-to-android/#comments</comments>
		<pubDate>Thu, 20 Oct 2011 21:24:10 +0000</pubDate>
		<dc:creator>Bryce Boe</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[mac]]></category>

		<guid isPermaLink="false">http://www.bryceboe.com/?p=887</guid>
		<description><![CDATA[I&#8217;m currently in Chicago, having just attended the 18th ACM Conference on Computer and Communications Security, where Adam Doupé presented our paper, Fear the EAR: Discovering and Mitigating Execution After Redirect Vulnerabilities. As always, when I&#8217;m traveling, the problem of how to connect to the Internet arises. Fortunately, we were provided with Internet access via [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m currently in Chicago, having just attended the <a href="http://www.sigsac.org/ccs/CCS2011/">18th ACM Conference on Computer and Communications Security</a>, where <a href="http://adamdoupe.com/">Adam Doupé</a> presented our paper, <a href="http://cs.ucsb.edu/~bboe/public/pubs/fear-the-ear-ccs2011.pdf">Fear the EAR: Discovering and Mitigating Execution After Redirect Vulnerabilities</a>. As always, when I&#8217;m traveling, the problem of how to connect to the Internet arises. Fortunately, we were provided with Internet access via WiFi in our rooms throughout the duration of the conference, however, now that the conference is over we&#8217;ll have to pay for the access ourselves. Hotels, like many airports, charge absurd amounts for Internet access simply because they can. $8 a day for an <em>unreliable</em> and <em>slow</em> connection is typical and is <em>absurd</em> considering I&#8217;m already paying $30 a month for an unlimited data plan on my cell phone. Of course I can check my email, read <a href="http://reddit.com">reddit</a>, and maybe look up some places on <a href="http://yelp.com">yelp</a> using my Android phone, however, it is simply more efficient to use my laptop.</p>
<p>Naturally, the obvious solution is to tether your laptop to your phone and if you have an Android phone the process is incredibly simple. In fact, there are a number of pages on the Internet that tell you exactly how to do it. Primarily, there is an <a href="http://androidforums.com/droid-how-tips/18532-mac-os-x-droid-tethering-usb-wired.html">Android Forums post</a> from November, 2009 that recommends using an Android application, <a href="http://code.google.com/p/azilink/">Azilink</a>, in combination with an OS X application <a href="http://code.google.com/p/tunnelblick/">Tunnelblick</a>, and a <a href="http://pastie.org/701122">shell script</a> to configure the tether correctly. There is also a <a href="http://www.morninj.com/2011/03/howto-tether-an-android-phone-on-mac-os-x/">great blog post</a> from March of this year that is a bit more user friendly than the forum post in describing how to tether your OS X machine to your Android phone.</p>
<p>Despite the last guide being fairly recent, it unfortunately is slightly out of date due in part to OS X Lion. The older versions of Tunnelblick seemingly don&#8217;t work with OS X Lion, thus an update to a newer version of Tunnelblick is required. The newer version (currently 3.2beta32) of Tunnelblick breaks the shell script that the previous guide uses, thus I am writing this post simply to provide the Internet with an update to that shell script. Please note that everything else mentioned on the blog post currently works as described.</p>
<p>The fix to the shell script is actually really simple, just replace the line shown in the first block of code below, with the line shown in the second:<br />
<code>    sudo /Applications/Tunnelblick.app/Contents/Resources/openvpn --dev tun \</code><code>    sudo /Applications/Tunnelblick.app/Contents/Resources/openvpn/openvpn-2.2.1/openvpn --dev tun \</code></p>
<p>Finally for your convenience, I created a github gist with the updated shell script. Observant readers will notice that I updated some of the comments in the script. Happy tethering!</p>
<div id="gist-1302227" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="c">#!/bin/bash</span></div><div class='line' id='LC2'><span class="c">#</span></div><div class='line' id='LC3'><span class="c"># azilink for OS X Lion</span></div><div class='line' id='LC4'><span class="c"># based on http://pastie.org/405289 but works with Tunnelblick only</span></div><div class='line' id='LC5'><span class="c"># (no need to install a separate copy of OpenVPN2 from macports </span></div><div class='line' id='LC6'><span class="c"># or building from source by hand, thankfully)</span></div><div class='line' id='LC7'><span class="c"># Requires: </span></div><div class='line' id='LC8'><span class="c"># - azilink running on android phone (http://code.google.com/p/azilink/)</span></div><div class='line' id='LC9'><span class="c">#   (run the app and check the box to start the service).</span></div><div class='line' id='LC10'><span class="c"># - adb on system path (comes with the Android SDK; </span></div><div class='line' id='LC11'><span class="c">#   add its tools folder to your PATH in ~/.profile or </span></div><div class='line' id='LC12'><span class="c">#   place or symlink the sdk&#39;s tools/adb file in e.g. usr/local/bin or somewhere else on the PATH)</span></div><div class='line' id='LC13'><span class="c"># - Tunnelblick, a nice OS X packaging of OpenVPN (http://code.google.com/p/tunnelblick/)</span></div><div class='line' id='LC14'><span class="c">#   Install Tunnelblick to Applications. Tested with Tunnelblick 3.2beta32 (build 2817)</span></div><div class='line' id='LC15'><br/></div><div class='line' id='LC16'>init<span class="o">()</span> <span class="o">{</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;adb forward tcp:41927 tcp:41927</div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;sudo /Applications/Tunnelblick.app/Contents/Resources/openvpn/openvpn-2.2.1/openvpn --dev tun <span class="se">\</span></div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--script-security 2<span class="se">\</span></div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--remote 127.0.0.1 41927 <span class="se">\</span></div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--proto tcp-client <span class="se">\</span></div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--ifconfig 192.168.56.2 192.168.56.1 <span class="se">\</span></div><div class='line' id='LC23'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--route 0.0.0.0 128.0.0.0 <span class="se">\</span></div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--route 128.0.0.0 128.0.0.0 <span class="se">\</span></div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--keepalive 10 30 <span class="se">\</span></div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--up <span class="s2">&quot;$0 up&quot;</span> <span class="se">\</span></div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--down <span class="s2">&quot;$0 down&quot;</span></div><div class='line' id='LC28'><span class="o">}</span></div><div class='line' id='LC29'><br/></div><div class='line' id='LC30'><br/></div><div class='line' id='LC31'>up<span class="o">()</span> <span class="o">{</span></div><div class='line' id='LC32'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nv">tun_dev</span><span class="o">=</span><span class="nv">$1</span></div><div class='line' id='LC33'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nv">ns</span><span class="o">=</span>192.168.56.1</div><div class='line' id='LC34'>&nbsp;&nbsp;&nbsp;&nbsp;sudo /usr/sbin/scutil <span class="s">&lt;&lt; EOF</span></div><div class='line' id='LC35'><span class="s">open</span></div><div class='line' id='LC36'><span class="s">d.init</span></div><div class='line' id='LC37'><span class="s">get State:/Network/Interface/$tun_dev/IPv4</span></div><div class='line' id='LC38'><span class="s">d.add InterfaceName $tun_dev</span></div><div class='line' id='LC39'><span class="s">set State:/Network/Service/openvpn-$tun_dev/IPv4</span></div><div class='line' id='LC40'><br/></div><div class='line' id='LC41'><span class="s">d.init</span></div><div class='line' id='LC42'><span class="s">d.add ServerAddresses * $ns</span></div><div class='line' id='LC43'><span class="s">set State:/Network/Service/openvpn-$tun_dev/DNS</span></div><div class='line' id='LC44'><span class="s">quit</span></div><div class='line' id='LC45'><span class="s">EOF</span></div><div class='line' id='LC46'><span class="o">}</span></div><div class='line' id='LC47'><br/></div><div class='line' id='LC48'><br/></div><div class='line' id='LC49'>down<span class="o">()</span> <span class="o">{</span></div><div class='line' id='LC50'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nv">tun_dev</span><span class="o">=</span><span class="nv">$1</span></div><div class='line' id='LC51'>&nbsp;&nbsp;&nbsp;&nbsp;sudo /usr/sbin/scutil <span class="s">&lt;&lt; EOF</span></div><div class='line' id='LC52'><span class="s">open</span></div><div class='line' id='LC53'><span class="s">remove State:/Network/Service/openvpn-$tun_dev/IPv4</span></div><div class='line' id='LC54'><span class="s">remove State:/Network/Service/openvpn-$tun_dev/DNS</span></div><div class='line' id='LC55'><span class="s">quit</span></div><div class='line' id='LC56'><span class="s">EOF</span></div><div class='line' id='LC57'><span class="o">}</span></div><div class='line' id='LC58'><br/></div><div class='line' id='LC59'><br/></div><div class='line' id='LC60'><span class="k">case</span> <span class="nv">$1</span> in</div><div class='line' id='LC61'>&nbsp;&nbsp;&nbsp;&nbsp;up  <span class="o">)</span> up <span class="nv">$2</span> ;;  <span class="c"># openvpn will pass tun/tap dev as $2</span></div><div class='line' id='LC62'>&nbsp;&nbsp;&nbsp;&nbsp;down<span class="o">)</span> down <span class="nv">$2</span> ;;</div><div class='line' id='LC63'>&nbsp;&nbsp;&nbsp;&nbsp;*   <span class="o">)</span> init ;;</div><div class='line' id='LC64'><span class="k">esac</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1302227/d2e23c6754017f865cb742667ce73852661a0e64/tether.sh" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1302227#file_tether.sh" style="float:right;margin-right:10px;color:#666">tether.sh</a>
            <a href="https://gist.github.com/1302227">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

]]></content:encoded>
			<wfw:commentRss>http://www.bryceboe.com/2011/10/20/tethering-os-x-lion-to-android/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Moving Images in 3D Space with Pyglet</title>
		<link>http://www.bryceboe.com/2011/10/08/moving-images-in-3d-space-with-pyglet/</link>
		<comments>http://www.bryceboe.com/2011/10/08/moving-images-in-3d-space-with-pyglet/#comments</comments>
		<pubDate>Sat, 08 Oct 2011 23:04:16 +0000</pubDate>
		<dc:creator>Bryce Boe</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[visualization]]></category>

		<guid isPermaLink="false">http://www.bryceboe.com/?p=858</guid>
		<description><![CDATA[Yesterday, October 7, 2011, the graduate students of UCSB&#8217;s Computer Science department, including myself, hosted the 6th annual Graduate Student Workshop on Computing (GSWC). The workshop is a great opportunity for other students, faculty, and industry professionals to get an overview of the work performed by our department. Part of organizing the workshop is obtaining [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday, October 7, 2011, the graduate students of UCSB&#8217;s Computer Science department, including myself, hosted the <a href="http://gswc.cs.ucsb.edu/2011/">6th annual Graduate Student Workshop on Computing (GSWC)</a>. The workshop is a great opportunity for other students, faculty, and industry professionals to get an overview of the work performed by our department. Part of organizing the workshop is obtaining gift or sponsorship money in order to pay for the facilities, food, proceedings, and all other costs associated with running a workshop.</p>
<p>In exchange for event sponsorship, we include each company&#8217;s logo on our website, in the conference proceedings, and in a visible display at the workshop itself. For many of the previous GSWCs, we created and printed up an expensive poster with the theme of the event as well as logos of all the corporate sponsors. While that worked well, it required a decent effort to design the poster, and, as I said before, was considerably expensive to print. Thus, when I was the chair of the GSWC last year, I decided to take a different approach to how we display the corporate logos during the workshop. Rather than using a static poster, I created an animated display that was projected on one of the room&#8217;s walls during the conference.</p>
<p>I occasionally provide consulting for a local Santa Barbara company, <a href="http://www.worldviz.com/">Worldviz</a> who makes a product, <a href="http://www.worldviz.com/products/vizard4/index.html">Vizard</a>, that allows one to quickly construct 3D environments in python. Using Vizard I was able to quickly create a 3D logo display in which the logos follow a circular path along the z-axis, as shown in the following photos. While this worked well, Vizard unfortunately only works on Windows and thus could not be run easily from my Mac laptop.</p>
<p><a href="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/10/animator0.png"><img src="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/10/animator0-150x150.png" alt="" title="animator0" width="150" height="150" class="alignnone size-thumbnail wp-image-860" /></a><a href="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/10/animator1.png"><img src="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/10/animator1-150x150.png" alt="" title="animator1" width="150" height="150" class="alignnone size-thumbnail wp-image-861" /></a><a href="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/10/animator2.png"><img src="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/10/animator2-150x150.png" alt="" title="animator2" width="150" height="150" class="alignnone size-thumbnail wp-image-862" /></a><a href="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/10/animator4.png"><img src="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/10/animator4-150x150.png" alt="" title="animator4" width="150" height="150" class="alignnone size-thumbnail wp-image-863" /></a></p>
<p>We wanted to use the same display for this year&#8217;s GSWC so I sought to rewrite the display in a cross platform and free manor. While I have some previous opengl experience in C, I really wanted to write the display in python so I looked at the various python opengl options. From the StackOverflow thread, <a href="http://stackoverflow.com/questions/242059/opengl-with-python">OpenGL with Python</a>, I quickly settled on <a href="http://pyglet.org/">pyglet</a>. Since I already knew the equation to move points around in a circular path, my only challenge was to figure out how to map a texture to a quad so that I could position the quad in 3D space. I quickly asked a StackOverflow question, <a href="http://stackoverflow.com/questions/7681899/moving-an-image-around-in-3d-space">Moving an image around in 3D space</a> in hopes that while I was in the process of figuring it out, someone would provide me with the solution. Unfortunately, <a href="http://en.wikipedia.org/wiki/Crowdsourcing">crowdsourcing</a> didn&#8217;t pay off, nevertheless, I eventually found the solution and wrote a simple cross platform logo animation program.</p>
<p>In order to run the following program, you will first need to install the required libraries (an exercise left to the reader), create a folder &#8220;imgs&#8221; and place whatever images you want in that folder and then run the following script (<a href="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/10/animator.py">download animator.py</a>). Note: If you want to run this script on 64-bit OS X you&#8217;ll need to run it via: <code>VERSIONER_PYTHON_PREFER_32_BIT=yes ./animator.py</code></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">math</span>, <span style="color: #dc143c;">os</span>, pyglet, <span style="color: #dc143c;">sys</span>
<span style="color: #ff7700;font-weight:bold;">from</span> pyglet.<span style="color: #dc143c;">gl</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> World<span style="color: black;">&#40;</span>pyglet.<span style="color: black;">window</span>.<span style="color: black;">Window</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, scale=<span style="color: #ff4500;">10</span>, center_pos=<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">0</span>, -<span style="color: #ff4500;">15</span><span style="color: black;">&#41;</span>, speed=<span style="color: #ff4500;">1.0</span>,
                 <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">super</span><span style="color: black;">&#40;</span>World, <span style="color: #008000;">self</span><span style="color: black;">&#41;</span>.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">scale</span> = scale
        <span style="color: #008000;">self</span>.<span style="color: black;">center_pos</span> = center_pos
        <span style="color: #008000;">self</span>.<span style="color: black;">speed</span> = speed
        glClearColor<span style="color: black;">&#40;</span><span style="color: #ff4500;">1.0</span>, <span style="color: #ff4500;">1.0</span>, <span style="color: #ff4500;">1.0</span>, <span style="color: #ff4500;">0.0</span><span style="color: black;">&#41;</span>
        glEnable<span style="color: black;">&#40;</span>GL_DEPTH_TEST<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">textures</span> = <span style="color: #008000;">self</span>.<span style="color: black;">load_textures</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">clock</span> = <span style="color: #ff4500;">0</span>
        pyglet.<span style="color: black;">clock</span>.<span style="color: black;">schedule_interval</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">update</span>, <span style="color: #ff4500;">1</span> / <span style="color: #ff4500;">60.0</span><span style="color: black;">&#41;</span>
&nbsp;
    @<span style="color: #008000;">staticmethod</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> load_textures<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
        img_dir = <span style="color: #483d8b;">'imgs'</span>
        textures = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">isdir</span><span style="color: black;">&#40;</span>img_dir<span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Could not find directory &quot;%s&quot; under &quot;%s&quot;'</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>img_dir,
                                                                <span style="color: #dc143c;">os</span>.<span style="color: black;">getcwd</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
            <span style="color: #dc143c;">sys</span>.<span style="color: black;">exit</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> image <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">listdir</span><span style="color: black;">&#40;</span>img_dir<span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">try</span>:
                image = pyglet.<span style="color: black;">image</span>.<span style="color: black;">load</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>img_dir, image<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">except</span> pyglet.<span style="color: black;">image</span>.<span style="color: #dc143c;">codecs</span>.<span style="color: black;">dds</span>.<span style="color: black;">DDSException</span>:
                <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'&quot;%s&quot; is not a valid image file'</span> <span style="color: #66cc66;">%</span> image
                <span style="color: #ff7700;font-weight:bold;">continue</span>
            textures.<span style="color: black;">append</span><span style="color: black;">&#40;</span>image.<span style="color: black;">get_texture</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
            glEnable<span style="color: black;">&#40;</span>textures<span style="color: black;">&#91;</span>-<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>.<span style="color: black;">target</span><span style="color: black;">&#41;</span>
            glBindTexture<span style="color: black;">&#40;</span>textures<span style="color: black;">&#91;</span>-<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>.<span style="color: black;">target</span>, textures<span style="color: black;">&#91;</span>-<span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>.<span style="color: #008000;">id</span><span style="color: black;">&#41;</span>
            glTexImage2D<span style="color: black;">&#40;</span>GL_TEXTURE_2D, <span style="color: #ff4500;">0</span>, GL_RGB, image.<span style="color: black;">width</span>, image.<span style="color: black;">height</span>,
                         <span style="color: #ff4500;">0</span>, GL_RGBA, GL_UNSIGNED_BYTE,
                         image.<span style="color: black;">get_image_data</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">get_data</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'RGBA'</span>,
                                                         image.<span style="color: black;">width</span> <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">4</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>textures<span style="color: black;">&#41;</span> == <span style="color: #ff4500;">0</span>:
            <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'Found no textures to load. Exiting'</span>
            <span style="color: #dc143c;">sys</span>.<span style="color: black;">exit</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> textures
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> update<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, _<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">on_draw</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">clock</span> += .01
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> on_draw<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        glClear<span style="color: black;">&#40;</span>GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT<span style="color: black;">&#41;</span>
        glLoadIdentity<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">draw_images</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> draw_images<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        angle_base = <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">clock</span> <span style="color: #66cc66;">*</span> <span style="color: #008000;">self</span>.<span style="color: black;">speed</span> <span style="color: #66cc66;">*</span> <span style="color: #ff4500;">50</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">%</span> <span style="color: #ff4500;">360</span>
        angle_delta = <span style="color: #ff4500;">360</span>. / <span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">textures</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #ff7700;font-weight:bold;">for</span> i, texture <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">enumerate</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">textures</span><span style="color: black;">&#41;</span>:
            angle = <span style="color: #dc143c;">math</span>.<span style="color: black;">radians</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>angle_base + i <span style="color: #66cc66;">*</span> angle_delta<span style="color: black;">&#41;</span> <span style="color: #66cc66;">%</span> <span style="color: #ff4500;">360</span><span style="color: black;">&#41;</span>
            dx = <span style="color: #dc143c;">math</span>.<span style="color: black;">sin</span><span style="color: black;">&#40;</span>angle<span style="color: black;">&#41;</span> <span style="color: #66cc66;">*</span> <span style="color: #008000;">self</span>.<span style="color: black;">scale</span>
            dz = <span style="color: #dc143c;">math</span>.<span style="color: black;">cos</span><span style="color: black;">&#40;</span>angle<span style="color: black;">&#41;</span> <span style="color: #66cc66;">*</span> <span style="color: #008000;">self</span>.<span style="color: black;">scale</span>
&nbsp;
            <span style="color: #ff7700;font-weight:bold;">if</span> texture.<span style="color: black;">width</span> <span style="color: #66cc66;">&gt;</span> texture.<span style="color: black;">height</span>:
                rect_w = texture.<span style="color: black;">width</span> / <span style="color: #008000;">float</span><span style="color: black;">&#40;</span>texture.<span style="color: black;">height</span><span style="color: black;">&#41;</span>
                rect_h = <span style="color: #ff4500;">1</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                rect_w = <span style="color: #ff4500;">1</span>
                rect_h = texture.<span style="color: black;">height</span> / <span style="color: #008000;">float</span><span style="color: black;">&#40;</span>texture.<span style="color: black;">width</span><span style="color: black;">&#41;</span>
&nbsp;
            glPushMatrix<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            glTranslatef<span style="color: black;">&#40;</span>dx + <span style="color: #008000;">self</span>.<span style="color: black;">center_pos</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>, <span style="color: #008000;">self</span>.<span style="color: black;">center_pos</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>,
                         dz + <span style="color: #008000;">self</span>.<span style="color: black;">center_pos</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
            glBindTexture<span style="color: black;">&#40;</span>texture.<span style="color: black;">target</span>, texture.<span style="color: #008000;">id</span><span style="color: black;">&#41;</span>
            glBegin<span style="color: black;">&#40;</span>GL_QUADS<span style="color: black;">&#41;</span>
            glTexCoord2f<span style="color: black;">&#40;</span><span style="color: #ff4500;">0.0</span>, <span style="color: #ff4500;">0.0</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span> glVertex3f<span style="color: black;">&#40;</span>-rect_w, -rect_h, <span style="color: #ff4500;">0.0</span><span style="color: black;">&#41;</span>
            glTexCoord2f<span style="color: black;">&#40;</span><span style="color: #ff4500;">1.0</span>, <span style="color: #ff4500;">0.0</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span> glVertex3f<span style="color: black;">&#40;</span> rect_w, -rect_h, <span style="color: #ff4500;">0.0</span><span style="color: black;">&#41;</span>
            glTexCoord2f<span style="color: black;">&#40;</span><span style="color: #ff4500;">1.0</span>, <span style="color: #ff4500;">1.0</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span> glVertex3f<span style="color: black;">&#40;</span> rect_w,  rect_h, <span style="color: #ff4500;">0.0</span><span style="color: black;">&#41;</span>
            glTexCoord2f<span style="color: black;">&#40;</span><span style="color: #ff4500;">0.0</span>, <span style="color: #ff4500;">1.0</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">;</span> glVertex3f<span style="color: black;">&#40;</span>-rect_w,  rect_h, <span style="color: #ff4500;">0.0</span><span style="color: black;">&#41;</span>
            glEnd<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            glPopMatrix<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> on_resize<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, width, height<span style="color: black;">&#41;</span>:
        glViewport<span style="color: black;">&#40;</span><span style="color: #ff4500;">0</span>, <span style="color: #ff4500;">0</span>, width, height<span style="color: black;">&#41;</span>
        glMatrixMode<span style="color: black;">&#40;</span>GL_PROJECTION<span style="color: black;">&#41;</span>
        glLoadIdentity<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        gluPerspective<span style="color: black;">&#40;</span><span style="color: #ff4500;">65.0</span>, width / <span style="color: #008000;">float</span><span style="color: black;">&#40;</span>height<span style="color: black;">&#41;</span>, <span style="color: #ff4500;">0.1</span>, <span style="color: #ff4500;">1000.0</span><span style="color: black;">&#41;</span>
        glMatrixMode<span style="color: black;">&#40;</span>GL_MODELVIEW<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">&quot;__main__&quot;</span>:
    window = World<span style="color: black;">&#40;</span>width=<span style="color: #ff4500;">800</span>, height=<span style="color: #ff4500;">600</span><span style="color: black;">&#41;</span>
    pyglet.<span style="color: black;">app</span>.<span style="color: black;">run</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

]]></content:encoded>
			<wfw:commentRss>http://www.bryceboe.com/2011/10/08/moving-images-in-3d-space-with-pyglet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Defcon 19 Quals Forensics 100 and Forensics 300 Solution</title>
		<link>http://www.bryceboe.com/2011/06/05/defcon-19-quals-forensics-100-and-forensics-300-solution/</link>
		<comments>http://www.bryceboe.com/2011/06/05/defcon-19-quals-forensics-100-and-forensics-300-solution/#comments</comments>
		<pubDate>Mon, 06 Jun 2011 02:18:30 +0000</pubDate>
		<dc:creator>Bryce Boe</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.bryceboe.com/?p=821</guid>
		<description><![CDATA[For the third year, I competed with team Shellphish in the Defcon quals. We pulled through with some amazing points at the end to finish in 8th place. My successful contributions, however, were really only with respect to Forensics 100 and 300. My write up for the following are below: Forensics 100 The forensics 100 [...]]]></description>
			<content:encoded><![CDATA[<p>For the third year, I competed with team Shellphish in the Defcon quals. We pulled through with some amazing points at the end to finish in <a href="http://stalkr.net/defcon/graph.htm">8th place</a>. My successful contributions, however, were really only with respect to Forensics 100 and 300. My write up for the following are below:</p>
<p><strong>Forensics 100</strong><br />
The forensics 100 challenge indicated to find the key, and <a href="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/06/f100.png">provided a png file</a> that was 19025&#215;1 in resolution. Immediately our team thought we could simply change the resolution to <a href="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/06/f100_25_761.png">25&#215;761</a> and would be on to something. After working with the resulting image for sometime I finally thought about converting it to <a href="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/06/f100_761_25.png">761&#215;25</a>. That was our first break through when we read some text along the lines of &#8220;ILoveMeSomesheepysheepies&#8221; followed by binary that includes capital &#8216;O&#8217;s in place of some of the &#8217;0&#8242;s. After no success with different permutations of that message we incorporated an idea the other team members had about the blue offset pixels that occur at regular intervals. Our first attempt at wrapping the image at the blue pixel boundaries (every 450 pixels) <a href="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/06/f100_solution.png">resulted in success</a>! The key &#8220;thankYouSirPleasemayIhaveAnother&#8221; appeared and worked. The following is my simple python solution for Forensics 100:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>, Image
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    orig = Image.<span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'f100.png'</span><span style="color: black;">&#41;</span>
    img = Image.<span style="color: #dc143c;">new</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'RGBA'</span>, <span style="color: black;">&#40;</span><span style="color: #ff4500;">450</span>, <span style="color: #ff4500;">43</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    img.<span style="color: black;">putdata</span><span style="color: black;">&#40;</span>orig.<span style="color: black;">getdata</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    img.<span style="color: black;">show</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    <span style="color: #dc143c;">sys</span>.<span style="color: black;">exit</span><span style="color: black;">&#40;</span>main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p><strong>Forensics 300</strong><br />
Forensics 300 was quite an interesting challenge. I don&#8217;t have the original file, nevertheless, one had to extract the initial file with a password to get a dmg containing a dump from an iphone. I came into the challenge a little late, after one of my teammates had gone through all the images, videos, and audio files looking for Waldo and &#8216;grep&#8217;ing for various relevant keywords. Further more, my teammates had previously used the <a href="http://petewarden.github.com/iPhoneTracker/">iPhoneTracker</a> on the consolidated.db file to see where the phone had been, however San Antonio didn&#8217;t prove to be very useful.</p>
<p>While the iPhoneTracker app seemed pretty cool, I wanted to programmatically see where the phone had been the most. Thus, after figuring out what was what with respect to the consolidated.db file I wrote a little python script to find the most visited places rounded to less precision to account for some variance. The top three results were the following where the first number represents the number of occurrences in that location, and the two numbers between the parenthesis represent the latitude and longitude respectfully.</p>
<ul>
<li>30 (&#8216;-77.846&#8242;, &#8217;166.677&#8242;)</li>
<li>18 (&#8217;0.000&#8242;, &#8217;0.000&#8242;)</li>
<li>10 (&#8217;36.106&#8242;, &#8216;-115.173&#8242;)</li>
</ul>
<p>When I did a <a href="http://maps.google.com/maps?f=q&#038;source=s_q&#038;hl=en&#038;geocode=&#038;q=-77.846+166.677&#038;sll=-77.578778,167.409668&#038;sspn=1.030596,5.218506&#038;ie=UTF8&#038;t=h&#038;z=15">google search for the coordinates -77.846 166.667</a> I knew immediately that it was no coincidence that I was centered in a small town in Antarctica. Unfortunately, Google maps doesn&#8217;t have a name for this location so I had to <a href="http://www.bing.com/maps/?v=2&#038;where1=-77.846%20166.677">revert to Bing</a> (for the first time ever) to figure out that this location is called Ross Island. From that point we simply attempted different &#8220;places&#8221; listed <a href="http://en.wikipedia.org/wiki/Ross_Island">Ross Island&#8217;s wikpiedia page</a> until &#8220;McMurdo Station&#8221; submitted successfully. Below is the script I used to find the coordinates from the <a href="http://www.bryceboe.com/wordpress/wp-content/uploads/2011/06/consolidated.db">consolodated.db input file</a>:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>, <span style="color: #dc143c;">sys</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #dc143c;">os</span>.<span style="color: black;">system</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'sqlite3 consolidated.db &quot;select Latitude, Longitude '</span>
              <span style="color: #483d8b;">'from CellLocation;&quot; &gt; tmp'</span><span style="color: black;">&#41;</span>
&nbsp;
    uniq = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'tmp'</span><span style="color: black;">&#41;</span>:
        pos = <span style="color: #008000;">tuple</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'%.3f'</span> <span style="color: #66cc66;">%</span> <span style="color: #008000;">float</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> line.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'|'</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span>:<span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> pos <span style="color: #ff7700;font-weight:bold;">in</span> uniq:
            uniq<span style="color: black;">&#91;</span>pos<span style="color: black;">&#93;</span> += <span style="color: #ff4500;">1</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            uniq<span style="color: black;">&#91;</span>pos<span style="color: black;">&#93;</span> = <span style="color: #ff4500;">1</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">for</span> pos, count <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">sorted</span><span style="color: black;">&#40;</span>uniq.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>, key=<span style="color: #ff7700;font-weight:bold;">lambda</span> x:x<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span> count, pos
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    <span style="color: #dc143c;">sys</span>.<span style="color: black;">exit</span><span style="color: black;">&#40;</span>main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>You can find links to solutions to other Defcon 19 Quals challenges at the following locations: <a href="http://rogunix.com/defconquals19.html">Rogunix</a>, <a href="http://t.negativefoo.org/post/6235620215/dc19-ctf-quals-writeups">negative foo</a>, <a href="http://www.vnsecurity.net/2011/05/defcon-19-ctf-quals-writeups-collection/">VNSecurity site</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bryceboe.com/2011/06/05/defcon-19-quals-forensics-100-and-forensics-300-solution/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>More on the Execution After Redirect Vulnerability</title>
		<link>http://www.bryceboe.com/2011/04/21/more-on-the-execution-after-redirect-vulnerability/</link>
		<comments>http://www.bryceboe.com/2011/04/21/more-on-the-execution-after-redirect-vulnerability/#comments</comments>
		<pubDate>Fri, 22 Apr 2011 01:53:39 +0000</pubDate>
		<dc:creator>Bryce Boe</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[EAR]]></category>
		<category><![CDATA[teaching]]></category>

		<guid isPermaLink="false">http://www.bryceboe.com/?p=818</guid>
		<description><![CDATA[Last night Adam Doupe wrote up his description on our Execution After Redirect Vulnerability which I wanted to link my followers to. Adam&#8217;s primary focus on this project has been adapting a static ruby analyzer to find instances of the EAR vulnerability in thousands of Ruby-On-Rails projects from github. It&#8217;s rather exciting. In other news [...]]]></description>
			<content:encoded><![CDATA[<p>Last night Adam Doupe wrote up <a href="http://adamdoupe.com/overview-of-execution-after-redirect-web-appl">his description</a> on our Execution After Redirect Vulnerability which I wanted to link my followers to. Adam&#8217;s primary focus on this project has been adapting a static ruby analyzer to find instances of the EAR vulnerability in thousands of Ruby-On-Rails projects from github. It&#8217;s rather exciting.</p>
<p>In other news I was one of four recipients of the <a href="http://senate.ucsb.edu/awards/2010.11/">2010-2011 UCSB Academic Senate Outstanding Teaching Assistant Award</a>. Today there was an awards ceremony where I received my <a href="http://twitpic.com/4ns4m7">first pre-framed certificate</a>. I am very honored to have won this award especially given that I am the first student in the Computer Science Department to win it. It&#8217;s a very cool feeling, however, as Nichole put it, with great acknowledgement come greater expectations. I hope to exceed those expectations.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bryceboe.com/2011/04/21/more-on-the-execution-after-redirect-vulnerability/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using StackOverflow&#8217;s API to Find the Top Web Frameworks</title>
		<link>http://www.bryceboe.com/2011/02/21/using-stackoverflows-api-to-find-the-top-web-frameworks/</link>
		<comments>http://www.bryceboe.com/2011/02/21/using-stackoverflows-api-to-find-the-top-web-frameworks/#comments</comments>
		<pubDate>Tue, 22 Feb 2011 02:09:43 +0000</pubDate>
		<dc:creator>Bryce Boe</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[EAR]]></category>

		<guid isPermaLink="false">http://www.bryceboe.com/?p=739</guid>
		<description><![CDATA[Update 2011/02/23 11:02 PST Added the lift tag and updated the list. Update 2011/02/22 13:19 PST Added the jsf tag (java server faces) and updated the total question count for each item on the list. Update 2011/02/22 11:14 PST Adding spring-mvc as that was what I originally was originally supposed to have. Update 2011/02/22 10:36 [...]]]></description>
			<content:encoded><![CDATA[<p><ins datetime="2011-02-23T19:02:00+00:00"><strong>Update 2011/02/23 11:02 PST</strong><br />
Added the lift tag and updated the list.</ins></p>
<p><ins datetime="2011-02-22T21:18:48+00:00"><strong>Update 2011/02/22 13:19 PST</strong><br />
Added the jsf tag (java server faces) and updated the total question count for each item on the list.</ins></p>
<p><ins datetime="2011-02-22T19:13:29+00:00"><strong>Update 2011/02/22 11:14 PST</strong><br />
Adding spring-mvc as that was what I originally was originally supposed to have.</ins></p>
<p><ins datetime="2011-02-22T18:31:36+00:00"><strong>Update 2011/02/22 10:36 PST</strong><br />
For the interested, <a href="https://spreadsheets0.google.com/pub?key=0AtdxNnTLM0xddDIwRTFlR25PQkprQUF6SHZKQ2xMSUE&#038;output=html">here is the table</a> used to generate the graph.</ins></p>
<p><ins datetime="2011-02-22T18:05:43+00:00"><strong>Update 2011/02/22 10:05 PST</strong><br />
As per comments on this post, I updated the list by removing hibernate, spring, and sass and added gwt and grails. I also updated the chart reflecting this information, and created an additional chart which plots the frameworks as a percentage of the questions asked each week to hide stackoverflows&#8217;s growing popularity.</ins></p>
<p><a href="http://adamdoupe.com/">Adam</a> and I are currently in the process of working on our research about the Execution After Redirect, or EAR, Vulnerability which I previously discussed in my blog post about the <a href="http://www.bryceboe.com/2010/12/09/ucsbs-international-capture-the-flag-competition-2010-challenge-6-fear-the-ear/">2010 iCTF</a>. While Adam is working on a static analyzer to detect EARs in <a href="http://rubyonrails.org/">ruby on rails</a> projects, I am testing how simple it is for a developer to introduce an EAR vulnerability in several popular web frameworks. In order to do that, I first needed to come up with a mostly unbiased list of popular web frameworks.</p>
<p>My first thought was to perform a search on the top web frameworks hoping that the information I seek may already be available. This search provided a few interesting results, such as the site, <a href="http://www.bestwebframeworks.com/">Best Web-Frameworks</a> as well as the page <a href="http://trends.builtwith.com/framework">Framework Usage Statistics</a> by the group BuiltWith. The Best Web-Frameworks page lists and compares various web frameworks by language, however it offers no means to compare the adoption of each. The Framework Usage Statistics page caught my eye as its usage statistics are generated by crawling and fingerprinting various websites in order to determine what frameworks are in use. Their fingerprinting technique, however, is too generic in some cases thus resulting in the labeling of languages like php and perl as frameworks. While these results were a step in the right direction, what I was really hoping to find was a list of top web frameworks that follow the <a href="http://en.wikipedia.org/wiki/Model%E2%80%93View%E2%80%93Controller">model, view, controller</a>, or MVC, architecture.</p>
<p>After a bit more consideration I realized it wouldn&#8217;t be very simple to get a list of frameworks by usage, thus I had to consider alternative metrics. I thought how I could measure the popularity of the framework by either the number of developers using or at least interested in the framework. It was this train of thought that lead me to both <a href="http://www.google.com/trends">Google Trends</a> and <a href="http://stackoverflow.com/">StackOverflow</a>. Google Trends allows one to perform a direct comparison of various search queries over time, such as <a href="http://www.google.com/trends?q=ruby+on+rails,+python">ruby on rails compared to python</a>. The problem, as evidenced by the former link, is that some of the search queries don&#8217;t directly apply to the web framework; in this case not all the people searching for django are looking for the web framework. Because of this problem, I decided a more direct approach was needed.</p>
<p>StackOverflow is a website geared towards developers where they can go to ask questions about various programing languages, development environments, algorithms, and, yes, even web frameworks. When someone asks a question, they can add tags to the question to help guide it to the right community. Thus if I had a question about redirects in ruby on rails, I might add the tag ruby-on-rails. Furthermore if I was interested in questions other people had about ruby on rails I might follow the ruby-on-rails tag.</p>
<p>Between the number of questions per tag,  the number of answers per tag, and the number of followers per tag, StackOverflow provides a few metrics for measuring the relative level of developer interest in various web frameworks. Success! The next step was to extract these numbers for the tags of various frameworks. For this, I attempted to find StackOverflow tags corresponding to all the frameworks listed on the Best Web-Frameworks site I previously found. I skipped the framework languages CSS and Javascript as they aren&#8217;t server side frameworks. I then narrowed the list down to the frameworks which had at least 100 questions asked.</p>
<p>This produced the following frameworks sorted by total number of questions asked:</p>
<ol>
<li>(31156) <a href="http://stackoverflow.com/tags/ruby-on-rails">ruby-on-rails</a></li>
<li>(20587) <a href="http://stackoverflow.com/tags/asp.net-mvc">asp.net-mvc</a></li>
<li>(14951) <a href="http://stackoverflow.com/tags/django">django</a></li>
<li>(4726) <a href="http://stackoverflow.com/tags/zend-framework">zend-framework</a></li>
<li>(3510) <a href="http://stackoverflow.com/tags/jsf">jsf</a></li>
<li>(3336) <a href="http://stackoverflow.com/tags/gwt">gwt</a></li>
<li>(3296) <a href="http://stackoverflow.com/tags/cakephp">cakephp</a></li>
<li>(3127) <a href="http://stackoverflow.com/tags/codeigniter">codeigniter</a></li>
<li>(2731) <a href="http://stackoverflow.com/tags/grails">grails</a></li>
<li>(1976) <a href="http://stackoverflow.com/tags/spring-mvc">spring-mvc</a></li>
<li>(1603) <a href="http://stackoverflow.com/tags/symfony">symfony</a></li>
<li>(912) <a href="http://stackoverflow.com/tags/struts">struts</a></li>
<li>(538) <a href="http://stackoverflow.com/tags/kohana">kohana</a></li>
<li>(515) <a href="http://stackoverflow.com/tags/pylons">pylons</a></li>
<li>(514) <a href="http://stackoverflow.com/tags/sinatra">sinatra</a></li>
<li>(506) <a href="http://stackoverflow.com/tags/dotnetnuke">dotnetnuke</a></li>
<li>(420) <a href="http://stackoverflow.com/tags/wicket">wicket</a></li>
<li>(227) <a href="http://stackoverflow.com/tags/lift">lift</a></li>
<li>(194) <a href="http://stackoverflow.com/tags/yii">yii</a></li>
<li>(163) <a href="http://stackoverflow.com/tags/cherrypy">cherrypy</a></li>
<li>(126) <a href="http://stackoverflow.com/tags/web2py">web2py</a></li>
<li>(106) <a href="http://stackoverflow.com/tags/catalyst">catalyst</a></li>
</ol>
<ul>
<li><del datetime="2011-02-22T18:05:43+00:00">(6609) <a href="http://stackoverflow.com/tags/hibernate">hibernate</a> (note: not a web framework)</del></li>
<li><del datetime="2011-02-22T18:05:43+00:00">(5765) <a href="http://stackoverflow.com/tags/spring">spring</a> (note: not a web framework)</del></li>
<li><del datetime="2011-02-22T18:05:43+00:00">(178) <a href="http://stackoverflow.com/tags/sass">sass</a> (note: not a web framework)</del></li>
</ol>
<p>This list alone seems to work fairly well, however, I wanted to take it one step further which was to see the number of questions asked on a per week basis since the start of StackOverflow. Using the <a href="http://api.stackoverflow.com/">StackOverflow API</a> (I used the API to generate the previous list too) I wrote a script to generate a CSV file containing this information. The information is depicted in the interactive chart below for the top 10 frameworks according to total number of StackOverflow questions. Each point in the chart represents the number of questions asked in a one week period starting on the date of the data point (protip: hover over chart to get the exact values).</p>
<p><script type="text/javascript" src="//ajax.googleapis.com/ajax/static/modules/gviz/1.0/chart.js"> {"chartType":"AreaChart","chartName":"Top 10 Web Frameworks","dataSourceUrl":"//spreadsheets0.google.com/tq?key=0AtdxNnTLM0xddDIwRTFlR25PQkprQUF6SHZKQ2xMSUE&#038;range=A1%3AK134&#038;gid=0&#038;transpose=0&#038;headers=1&#038;pub=1","options":{"displayAnnotations":true,"showTip":true,"reverseCategories":false,"titleY":"# of stack over flow questions","dataMode":"markers","titleX":"week starting on","maxAlternation":1,"pointSize":"0","colors":["#3366CC","#DC3912","#FF9900","#109618","#990099","#0099C6","#DD4477","#66AA00","#B82E2E","#316395"],"smoothLine":false,"lineWidth":"2","labelPosition":"right","is3D":false,"logScale":false,"hasLabelsColumn":true,"wmode":"opaque","title":"Top 10 Web Frameworks","legend":"right","allowCollapse":true,"reverseAxis":false,"isStacked":false,"mapType":"hybrid","width":600,"height":400},"refreshInterval":60} </script></p>
<p>Note: if the above graph doesn&#8217;t load, try <a href="https://spreadsheets0.google.com/oimg?key=0AtdxNnTLM0xddDIwRTFlR25PQkprQUF6SHZKQ2xMSUE&#038;oid=12&#038;zx=vn515z2t7lj8">this static image</a>.</p>
<p>The data confirms my previous suspicion that ruby on rails is the number one MVC and that django and cakePHP would also appear in the top 10. I must admit that I had never before heard of asp.net MVC, however considering that stackoverflow and all other stackexchange sites run on asp.net MVC, it makes sense that it would rank quite high.</p>
<p><ins datetime="2011-02-22T18:50:07+00:00">I added the below chart to show the relative percentage of questions per tag over time as per Big Daveâ€™s Gusset&#8217;s comment. This hides the growing popularity of stackoverflow.</ins></p>
<p><img src="https://spreadsheets1.google.com/oimg?key=0AtdxNnTLM0xddDIwRTFlR25PQkprQUF6SHZKQ2xMSUE&#038;oid=14&#038;zx=1n411uq4n9w4" /><br />
(<a href="https://spreadsheets1.google.com/pub?hl=en&#038;key=0AtdxNnTLM0xddDIwRTFlR25PQkprQUF6SHZKQ2xMSUE&#038;hl=en&#038;gid=11">Interactive version</a>)</p>
<p>The data for the above chart was extracted using the following script. The script requires the python package <a href="http://stackapps.com/questions/198/py-stackexchange-an-api-wrapper-for-python">py-stackexchange</a> in order to run and can be easily modified to add additional tags or change the filtering methods.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
</pre></td><td class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python                                                           </span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">datetime</span>, <span style="color: #dc143c;">sys</span>, <span style="color: #dc143c;">time</span>
<span style="color: #ff7700;font-weight:bold;">from</span> stackexchange <span style="color: #ff7700;font-weight:bold;">import</span> Site, StackOverflow
&nbsp;
frameworks = <span style="color: black;">&#91;</span><span style="color: #808080; font-style: italic;"># php                                                             </span>
              <span style="color: #483d8b;">'zend-framework'</span>, <span style="color: #483d8b;">'cakephp'</span>, <span style="color: #483d8b;">'symfony'</span>, <span style="color: #483d8b;">'codeigniter'</span>, <span style="color: #483d8b;">'seagull'</span>,
              <span style="color: #483d8b;">'prado'</span>, <span style="color: #483d8b;">'solar'</span>, <span style="color: #483d8b;">'ezcomponents'</span>, <span style="color: #483d8b;">'kohana'</span>, <span style="color: #483d8b;">'jelix'</span>, <span style="color: #483d8b;">'flow3'</span>,
	      <span style="color: #483d8b;">'modx'</span>, <span style="color: #483d8b;">'sapphire'</span>, <span style="color: #483d8b;">'yii'</span>, <span style="color: #483d8b;">'limonade'</span>, <span style="color: #483d8b;">'tekuna'</span>, <span style="color: #483d8b;">'doophp'</span>,
              <span style="color: #483d8b;">'fat-free'</span>, <span style="color: #483d8b;">'akelos'</span>, <span style="color: #483d8b;">'php-on-trax'</span>, <span style="color: #483d8b;">'atk'</span>,
	      <span style="color: #808080; font-style: italic;"># ruby                                                            </span>
              <span style="color: #483d8b;">'ruby-on-rails'</span>, <span style="color: #483d8b;">'merb'</span>, <span style="color: #483d8b;">'ramaze'</span>, <span style="color: #483d8b;">'halcyon'</span>, <span style="color: #483d8b;">'sinatra'</span>, <span style="color: #483d8b;">'webby'</span>,
              <span style="color: #483d8b;">'sass'</span>,
	      <span style="color: #808080; font-style: italic;"># perl                                                            </span>
              <span style="color: #483d8b;">'catalyst'</span>, <span style="color: #483d8b;">'interchange'</span>, <span style="color: #483d8b;">'mason'</span>, <span style="color: #483d8b;">'cgi-application'</span>, <span style="color: #483d8b;">'jifty'</span>,
              <span style="color: #483d8b;">'gantry'</span>, <span style="color: #483d8b;">'dancer'</span>, <span style="color: #483d8b;">'mojolicious'</span>,
              <span style="color: #808080; font-style: italic;"># java                                                            </span>
	      <span style="color: #483d8b;">'struts'</span>, <span style="color: #483d8b;">'hibernate'</span>, <span style="color: #483d8b;">'spring'</span>, <span style="color: #483d8b;">'wicket'</span>, <span style="color: #483d8b;">'play'</span>, <span style="color: #483d8b;">'stripes'</span>,
	      <span style="color: #808080; font-style: italic;"># python                                                          </span>
	      <span style="color: #483d8b;">'django'</span>, <span style="color: #483d8b;">'pylons'</span>, <span style="color: #483d8b;">'grok'</span>, <span style="color: #483d8b;">'turbogears'</span>, <span style="color: #483d8b;">'web2py'</span>, <span style="color: #483d8b;">'cherrypy'</span>,
	      <span style="color: #808080; font-style: italic;"># coldfusion                                                      </span>
              <span style="color: #483d8b;">'cfwheels'</span>, <span style="color: #483d8b;">'coldspring'</span>, <span style="color: #483d8b;">'model-glue'</span>,
              <span style="color: #808080; font-style: italic;"># asp.net                                                         </span>
              <span style="color: #483d8b;">'asp.net-mvc'</span>, <span style="color: #483d8b;">'dotnetnuke'</span>, <span style="color: #483d8b;">'monorail'</span>, <span style="color: #483d8b;">'vici'</span><span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> TagStats<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    DATE_START = <span style="color: #ff4500;">1217540572</span>
    WEEK_SECONDS = <span style="color: #ff4500;">604800</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, tag_names<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">so</span> = Site<span style="color: black;">&#40;</span>StackOverflow, <span style="color: #483d8b;">'LzYJwh19o0WCIvXK9q6k6g'</span><span style="color: black;">&#41;</span>
	<span style="color: #008000;">self</span>.<span style="color: black;">tag_names</span> = tag_names
        <span style="color: #008000;">self</span>.<span style="color: black;">tags</span> = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">stats</span> = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> output_counts<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, html=<span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
        tmp = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
	<span style="color: #ff7700;font-weight:bold;">for</span> tag <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">sorted</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">tags</span>, key=<span style="color: #ff7700;font-weight:bold;">lambda</span> x:x.<span style="color: black;">count</span>, reverse=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>:
            tmp.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: black;">&#40;</span>tag.<span style="color: black;">count</span>, tag.<span style="color: black;">name</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> html:
            <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'&lt;ol&gt;'</span>
            <span style="color: #ff7700;font-weight:bold;">for</span> count, name <span style="color: #ff7700;font-weight:bold;">in</span> tmp:
                <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'&lt;li&gt;(%d) &lt;a href=&quot;http://stackoverflow.com/tags/%s&quot;&gt;'</span>
                       <span style="color: #483d8b;">'%s&lt;/a&gt;&lt;/li&gt;'</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span>count, name, name<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'&lt;/ol&gt;'</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'%8d %s'</span> <span style="color: #66cc66;">%</span> x <span style="color: #ff7700;font-weight:bold;">for</span> x <span style="color: #ff7700;font-weight:bold;">in</span> tmp<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> get_tags<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, min_size<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">for</span> name <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">tag_names</span>:
            query = <span style="color: #008000;">self</span>.<span style="color: black;">so</span>.<span style="color: black;">tags</span><span style="color: black;">&#40;</span><span style="color: #008000;">filter</span>=name<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">for</span> tmp <span style="color: #ff7700;font-weight:bold;">in</span> query:
                <span style="color: #ff7700;font-weight:bold;">if</span> name == tmp.<span style="color: black;">name</span>:
                    <span style="color: #ff7700;font-weight:bold;">break</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                <span style="color: #dc143c;">sys</span>.<span style="color: black;">stderr</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Not found: %s<span style="color: #000099; font-weight: bold;">\n</span>'</span> <span style="color: #66cc66;">%</span> name<span style="color: black;">&#41;</span>
                <span style="color: #ff7700;font-weight:bold;">continue</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> tmp.<span style="color: black;">count</span> <span style="color: #66cc66;">&lt;</span> min_size:
                <span style="color: #dc143c;">sys</span>.<span style="color: black;">stderr</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Too few questions: %s<span style="color: #000099; font-weight: bold;">\n</span>'</span> <span style="color: #66cc66;">%</span> name<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>:
                <span style="color: #008000;">self</span>.<span style="color: black;">tags</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>tmp<span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">stats</span> = <span style="color: #008000;">dict</span><span style="color: black;">&#40;</span><span style="color: #008000;">zip</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>tag.<span style="color: black;">name</span> <span style="color: #ff7700;font-weight:bold;">for</span> tag <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">tags</span><span style="color: black;">&#93;</span>,
                              <span style="color: black;">&#91;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">*</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">tags</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> output_stats_by_week<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, start_week=<span style="color: #ff4500;">0</span><span style="color: black;">&#41;</span>:
        now = <span style="color: #008000;">int</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">datetime</span>.<span style="color: #dc143c;">datetime</span>.<span style="color: black;">now</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">strftime</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'%s'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        num_weeks = <span style="color: black;">&#40;</span>now - <span style="color: #008000;">self</span>.<span style="color: black;">DATE_START</span><span style="color: black;">&#41;</span> / <span style="color: #008000;">self</span>.<span style="color: black;">WEEK_SECONDS</span>
        <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">', '</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>tag.<span style="color: black;">name</span> <span style="color: #ff7700;font-weight:bold;">for</span> tag <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">tags</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">range</span><span style="color: black;">&#40;</span>start_week, num_weeks<span style="color: black;">&#41;</span>:
            <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">flush</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            start = <span style="color: #008000;">self</span>.<span style="color: black;">DATE_START</span> + i <span style="color: #66cc66;">*</span> <span style="color: #008000;">self</span>.<span style="color: black;">WEEK_SECONDS</span>
            end = <span style="color: #008000;">self</span>.<span style="color: black;">DATE_START</span> + <span style="color: black;">&#40;</span>i + <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">*</span> <span style="color: #008000;">self</span>.<span style="color: black;">WEEK_SECONDS</span>
            counts = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
            <span style="color: #ff7700;font-weight:bold;">for</span> tag <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">tags</span>:
                <span style="color: #ff7700;font-weight:bold;">try</span>:
                    count = <span style="color: #008000;">self</span>.<span style="color: black;">so</span>.<span style="color: black;">questions</span><span style="color: black;">&#40;</span>tagged=<span style="color: #008000;">str</span><span style="color: black;">&#40;</span>tag.<span style="color: black;">name</span><span style="color: black;">&#41;</span>,
                                              fromdate=start,
                                              todate=end<span style="color: black;">&#41;</span>.<span style="color: black;">total</span>
                <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">Exception</span>, e:
                    <span style="color: #dc143c;">sys</span>.<span style="color: black;">stderr</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'Stopped at week %d<span style="color: #000099; font-weight: bold;">\n</span>'</span> <span style="color: #66cc66;">%</span> i<span style="color: black;">&#41;</span>
                    <span style="color: #dc143c;">sys</span>.<span style="color: black;">exit</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
                <span style="color: #008000;">self</span>.<span style="color: black;">stats</span><span style="color: black;">&#91;</span>tag.<span style="color: black;">name</span><span style="color: black;">&#93;</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span>count<span style="color: black;">&#41;</span>
                counts.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span>count<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">', '</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>counts<span style="color: black;">&#41;</span>
&nbsp;
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        start_week = <span style="color: #008000;">int</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">sys</span>.<span style="color: black;">argv</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">IndexError</span>:
        start_week = <span style="color: #ff4500;">0</span>
    tag_stats = TagStats<span style="color: black;">&#40;</span>frameworks<span style="color: black;">&#41;</span>
    tag_stats.<span style="color: black;">get_tags</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">100</span><span style="color: black;">&#41;</span>
    <span style="color: #808080; font-style: italic;">#tag_stats.output_counts(html=True)                                         </span>
    tag_stats.<span style="color: black;">output_stats_by_week</span><span style="color: black;">&#40;</span>start_week<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    <span style="color: #dc143c;">sys</span>.<span style="color: black;">exit</span><span style="color: black;">&#40;</span>main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>

<p>Happy web-framework coding!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bryceboe.com/2011/02/21/using-stackoverflows-api-to-find-the-top-web-frameworks/feed/</wfw:commentRss>
		<slash:comments>34</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.861 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2012-05-14 17:25:06 -->
<!-- Compression = gzip -->
