<?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>A Little Off &#187; Code</title>
	<atom:link href="http://www.bemasher.net/archives/category/technology/code/feed" rel="self" type="application/rss+xml" />
	<link>http://www.bemasher.net</link>
	<description>Code, Computers, Photography and Guns</description>
	<lastBuildDate>Mon, 21 Nov 2011 06:38:44 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Decoding DVD Subtitles with Golang</title>
		<link>http://www.bemasher.net/archives/1106?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=decoding-dvd-subtitles-with-golang</link>
		<comments>http://www.bemasher.net/archives/1106#comments</comments>
		<pubDate>Mon, 21 Nov 2011 06:38:44 +0000</pubDate>
		<dc:creator>bemasher</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[dvd]]></category>
		<category><![CDATA[Elementary]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[MPEG]]></category>
		<category><![CDATA[Packetized]]></category>
		<category><![CDATA[PES]]></category>
		<category><![CDATA[Program Stream]]></category>
		<category><![CDATA[PS]]></category>
		<category><![CDATA[SPU]]></category>
		<category><![CDATA[SRT]]></category>
		<category><![CDATA[Stream]]></category>
		<category><![CDATA[Subpicture]]></category>
		<category><![CDATA[Subtitle]]></category>
		<category><![CDATA[VOBsub]]></category>

		<guid isPermaLink="false">http://www.bemasher.net/?p=1106</guid>
		<description><![CDATA[I've always been very fond of subtitles but I'm not sure of the reason why. When transcoding my DVD's to play them on my network media player I realized I needed a good way to keep the subtitles without burning them into the video. The MPEG-4 container will happily include VOBSUB and SRT subtitle streams [...]]]></description>
			<content:encoded><![CDATA[<p>I've always been very fond of subtitles but I'm not sure of the reason why. When transcoding my DVD's to play them on my network media player I realized I needed a good way to keep the subtitles without burning them into the video. The MPEG-4 container will happily include VOBSUB and SRT subtitle streams and my network media player handles this nicely.</p>
<p>The problem though is that including the VOBSUB's exactly as they appeared on the DVD is somewhat problematic, they're almost never the same style between movies, and sometimes they're just plain difficult to read. Converting them to SRT involves a fairly lengthy process of going through and indicating to an OCR program what each character is as it reads all of the subtitles and writes an SRT file. This is also difficult to correct if you mess up one character in the process of encoding.</p>
<p>So now that I've got the itch I decided to scratch it. I decided to write my own subtitle decoder that would write subtitles to images and a pseudo-OCR program to convert those images into individual character files. From there it would be fairly easy to write a quick interface that presents you with a list of letters at which point you can just fill in the character for each one. Once you've done this you can export it as your favorite text subtitle format in one shot instead of doing it as you go along.</p>
<p>The language I decided to write it in is Golang as I've been learning it for a few weeks now and It's currently my favorite language for a large number of reasons I won't get into here.</p>
<p>The first major challenge I ran into is that there's not really any standardized information about decoding DVD subtitles. I did find maybe 3-4 sites that have varying levels of detail into decoding DVD subtitles but there were still a lot of gaps in the information.</p>
<p>To start with, we need to decode MPEG Program Stream packets (PS), these contain MPEG Packetized Elementary Stream packets (PES). The PS header doesn't contain any information we need to decode subtitles. The PES header contains size of the packet's payload, offset to the payload and the length of the additional headers. <em>SubStream</em> refers to the stream id of the subtitle we're decoding. <em>DataSize</em> is the size of the subtitle payload. ControlPtr is the offset to the control sequences for describing the subtitle's payload.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">type Packet struct {<br />
&nbsp; &nbsp; PSHeader [14]uint8<br />
&nbsp; &nbsp; PESHeader [4]uint8<br />
&nbsp; &nbsp; PacketSize uint16<br />
&nbsp; &nbsp; Extension uint16<br />
&nbsp; &nbsp; HeaderSize uint8<br />
&nbsp; &nbsp; SubStream uint8<br />
&nbsp; &nbsp; DataSize uint16<br />
&nbsp; &nbsp; ControlPtr uint16<br />
}</div></td></tr></tbody></table></div>
<p>To read data into this structure I've written the following method:</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">func (p *Packet) Read(r io.Reader) {<br />
&nbsp; &nbsp; binary.Read(r, binary.BigEndian, &amp;amp;p.PSHeader)<br />
&nbsp; &nbsp; binary.Read(r, binary.BigEndian, &amp;amp;p.PESHeader)<br />
&nbsp; &nbsp; binary.Read(r, binary.BigEndian, &amp;amp;p.PacketSize)<br />
&nbsp; &nbsp; binary.Read(r, binary.BigEndian, &amp;amp;p.Extension)<br />
&nbsp; &nbsp; binary.Read(r, binary.BigEndian, &amp;amp;p.HeaderSize)<br />
&nbsp; &nbsp; r.(io.ReadSeeker).Seek(int64(p.HeaderSize), os.SEEK_CUR)<br />
&nbsp; &nbsp; binary.Read(r, binary.BigEndian, &amp;amp;p.SubStream)<br />
&nbsp; &nbsp; binary.Read(r, binary.BigEndian, &amp;amp;p.DataSize)<br />
&nbsp; &nbsp; binary.Read(r, binary.BigEndian, &amp;amp;p.ControlPtr)<br />
<br />
&nbsp; &nbsp; p.PacketSize -= uint16(p.HeaderSize) + 4<br />
<br />
&nbsp; &nbsp; // Back up; DataSize and ControlPtr are part of the payload<br />
&nbsp; &nbsp; r.(io.ReadSeeker).Seek(-4, os.SEEK_CUR)<br />
}</div></td></tr></tbody></table></div>
<p>We read each of the structure's fields in order. We skip the additional headers of the PES packet since we don't care about the data in it. We also compensate for the given packet size since we went ahead and read the <em>SubStream</em> and <em>DataSize</em> seperately. Before leaving this function we back up so that the file cursor is at the right position to start reading data from the offsets.</p>
<p>Subtitles may span more than one packet so we need to be sure to read packets until we've read the entire length of the subtitle given by <em>Packet.DataSize</em>.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">func ReadSubtitle(s *os.File) (head Packet, data bytes.Buffer) {<br />
&nbsp; &nbsp; for i := 0; ; i++ {<br />
&nbsp; &nbsp; &nbsp; &nbsp; var pack Packet<br />
&nbsp; &nbsp; &nbsp; &nbsp; pack.Read(s)<br />
&nbsp; &nbsp; &nbsp; &nbsp; if i == 0 {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; head = pack<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; ReadFrom(s, &amp;amp;data, int64(pack.PacketSize))<br />
&nbsp; &nbsp; &nbsp; &nbsp; if data.Len() == int(head.DataSize) {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; return<br />
}</div></td></tr></tbody></table></div>
<p>Now that the headers and information like payload size and offsets have been read we can start to decode the subtitle. The first things we need to decode are the control sequences. These sequences give us information about how long to display the current subtitle, it's color and other information like offsets to even and odd fields since the image data is interlaced.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">type ControlHeader struct {<br />
&nbsp; &nbsp; Date uint16<br />
&nbsp; &nbsp; Next uint16<br />
}</div></td></tr></tbody></table></div>
<p><em>ControlHeader</em> represents the start time and offset to the next control sequence. Once we've got this information we can read the controls.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">func ReadControlSequences(head Packet, data *bytes.Buffer) (rect Rect, payload Payload, &nbsp;even, odd uint16) {<br />
&nbsp; &nbsp; payload.Read(data, head)<br />
<br />
&nbsp; &nbsp; for {<br />
&nbsp; &nbsp; &nbsp; &nbsp; var header ControlHeader<br />
&nbsp; &nbsp; &nbsp; &nbsp; err := ReadInto(&amp;amp;payload.Control, &amp;amp;header)<br />
&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf(&quot;%+v\n&quot;, header)<br />
&nbsp; &nbsp; &nbsp; &nbsp; end := false<br />
&nbsp; &nbsp; &nbsp; &nbsp; for !end {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cmd, err := payload.Control.ReadByte()<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err != nil {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; switch cmd {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 0x00: fmt.Println(&quot;\tForced&quot;)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 0x01: fmt.Printf(&quot;\tStart:\t\t%dms\n&quot;, 1024 * header.Date / 90)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 0x02: fmt.Printf(&quot;\tStop:\t\t%dms\n&quot;, 1024 * header.Date / 90)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 0x03:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf(&quot;\tPalette:\t%04X\n&quot;, payload.Control.Next(2))<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 0x04:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf(&quot;\tAlpha:\t\t%X\n&quot;, payload.Control.Next(2))<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 0x05:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; buf := payload.Control.Next(6)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rect = Rect{((uint16(buf[1]) &amp;amp; 0xF) &amp;lt;&amp;lt; 8) | uint16(buf[2]) - (uint16(buf[0]) &amp;lt;&amp;lt; 4) | (uint16(buf[1]) &amp;gt;&amp;gt; 4) + 1, ((uint16(buf[4]) &amp;amp; 0xF) &amp;lt;&amp;lt; 8) | uint16(buf[5]) - (uint16(buf[3]) &amp;lt;&amp;lt; 4) | (uint16(buf[4]) &amp;gt;&amp;gt; 4) + 1}<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf(&quot;\tDimensions:\t%+v\n&quot;, rect)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 0x06:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; buf := payload.Control.Next(4)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; even = uint16(buf[0]) &amp;lt;&amp;lt; 8 | uint16(buf[1])<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; odd = uint16(buf[2]) &amp;lt;&amp;lt; 8 | uint16(buf[3])<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf(&quot;\tOffsets:\t%d, %d\n&quot;, even, odd)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf(&quot;\tField Len:\t%d, %d\n&quot;, odd - even, uint16(payload.Data.Len()) - odd)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case 0xFF:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end = true<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; return<br />
}</div></td></tr></tbody></table></div>
<p>The control command is 1 byte and is followed by any parameters necessary for that particular control. The different controls are described below:</p>
<ul>
<li><em>0x00</em> - Forced: subtitle displayed whether or not subtitles are selected//enabled. This is typically used for foreign language segments. Takes no arguments.</li>
<li><em>0x01</em> - Start: The time at which to start displaying the subtitle, this uses the <em>Date</em> field of <em>ControlHeader</em>. The time in milliseconds to start displaying the subtitle is given by the function: <em>1024 * ControlHeader.Date / 90</em>. Takes no arguments.</li>
<li><em>0x02</em> - Stop: The time at which to stop displaying the subtitle, takes no arguments.</li>
<li><em>0x03</em> - Palette: Defines the four colors used for the subtitle. I've decided to ignore implementing this as I will be converting the subtitles to text. Takes 2 bytes of arguments, each color is one nibble.</li>
<li><em>0x04</em> - Alpha: Alpha channel information, determines which colors are opaque and which are transparent. Useful for determining the main color as the background will likely have complete transparency. Takes 2 bytes of arguments, each alpha is one nibble.</li>
<li><em>0x05</em> - Dimensions: Gives the dimensions of the subtitle image. Takes 6 bytes of arguments, each dimension value is 3 nibbles. Dimensions in pixels is given by the equation: <em>(X1 - X0 + 1) x (Y1 - Y0 + 1)</em>
<ul>
<li><em>0x***</em> - X0: Left-most x-axis bound.</li>
<li><em>0x***</em> - X1: Right-most x-axis bound.</li>
<li><em>0x***</em> - Y0: Top-most y-axis bound.</li>
<li><em>0x***</em> - Y1: Bottom-most y-axis bound.</li>
</ul>
</li>
<li><em>0x06</em> - Field Offsets: Gives the offsets to the even and odd fields of the image. Takes 4 bytes of arguments, the first byte is the even field offset, the second byte the odd field offset. This will be useful for rendering each field line in the proper order.</li>
<li><em>0xFF</em> - End Control: Signals the end of a control sequence.</li>
</ul>
<p>Now that we've got some information about the dimensions and locations of the subtitle image we can look at decoding and drawing it. Subtitle images are run-length-encoded (RLE). The basic idea behind RLE is to compress the image data into a pixel color and a number of pixels to draw in that color. Using the format for subtitles each pixel is defined by the following alphabet where <em>*</em> represents a wildcard nibble:</p>
<ul>
<li><em>0x4</em>, <em>0x5</em>, <em>0x6</em>, <em>0x7</em>, <em>0x8</em>, <em>0x9</em>, <em>0xA</em>, <em>0xB</em>, <em>0xC</em>, <em>0xD</em>, <em>0xE</em>, <em>0xF</em></li>
<li><em>0x1*</em>, <em>0x2*</em>, <em>0x3*</em></li>
<li><em>0x04*</em>, <em>0x05*</em>, <em>0x06*</em>, <em>0x07*</em>, <em>0x08*</em>, <em>0x09*</em>, <em>0x0A*</em>, <em>0x0B*</em>, <em>0x0C*</em>, <em>0x0D*</em>, <em>0x0E*</em>, <em>0x0F*</em></li>
<li><em>0x01**</em>, <em>0x02**</em>, <em>0x03**</em></li>
<li><em>0x000*</em></li>
</ul>
<p>To determine the color and number of pixels to draw we need to do a little bitwise arithmatic. The number of pixels to draw is given by the operation: <em>X &gt;&gt; 2</em>. The color is given by <em>X &amp; 0x03</em>.</p>
<p>There is one character in the alphabet which has a special meaning and neither of the above operations apply to it. That is <em>0x000*</em> which is a sort of carriage return character. It means simply fill the rest of the line with the given color. After every carriage return we need to read a line from the opposite field and reset the <em>x</em> position in the image to 0 and increment the <em>y</em> position.</p>
<p>Before we get into the code about drawing images I should mention one of the problems I ran into while writing this. The problem is that Golang doesn't provide any mechanism for reading nibble-aligned data. So I went ahead and wrote a small structure and a few methods for accomplishing this.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">type Nibbler struct {<br />
&nbsp; &nbsp; r *bytes.Buffer<br />
&nbsp; &nbsp; Current uint8<br />
&nbsp; &nbsp; Aligned uint8<br />
}<br />
<br />
func NewNibbler(r *bytes.Buffer) Nibbler {<br />
&nbsp; &nbsp; return Nibbler{r, 0, 0}<br />
}<br />
<br />
func (n *Nibbler) GetNibble() (b uint8, err os.Error) {<br />
&nbsp; &nbsp; if n.Aligned == 0 {<br />
&nbsp; &nbsp; &nbsp; &nbsp; err = ReadInto(n.r, &amp;amp;n.Current)<br />
&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return 0, err<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; n.Aligned ^= 4<br />
&nbsp; &nbsp; b = (n.Current &amp;gt;&amp;gt; n.Aligned) &amp;amp; 0x0F<br />
&nbsp; &nbsp; return b, err<br />
}</div></td></tr></tbody></table></div>
<p>The basic functionality is achieved by using some bitwise operations to switch which nibble we return each time the <em>GetNibble</em> method is called and reading a new byte every time we've read the 2nd nibble of the current byte. Access is provided to the <em>Aligned</em> field to determine if we're byte-aligned or not since we need to use this in the function that draws the subtitle images.</p>
<p>The following code decodes the RLE image and draws all of the pixels to an image of dimensions specified in the control sequence.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">func DrawPixels(s *image.Gray, x uint16, y uint16, n uint16, c uint8) {<br />
&nbsp; &nbsp; for i := 0; i &amp;lt; int(n); i++ {<br />
&nbsp; &nbsp; &nbsp; &nbsp; s.SetGray(int(x) + i, int(y), image.GrayColor{(c + 1) &amp;lt;&amp;lt; 6})<br />
&nbsp; &nbsp; }<br />
}<br />
<br />
func ReadRLEImage(rect Rect, payload *Payload, even, odd uint16) (*image.Gray) {<br />
&nbsp; &nbsp; subImg := image.NewGray(int(rect.w), int(rect.h))<br />
&nbsp; &nbsp; bData := payload.Data.Bytes()<br />
&nbsp; &nbsp; evenNibbler := NewNibbler(bytes.NewBuffer(bData[even:odd]))<br />
&nbsp; &nbsp; oddNibbler := NewNibbler(bytes.NewBuffer(bData[odd:]))<br />
<br />
&nbsp; &nbsp; var x, y uint16<br />
&nbsp; &nbsp; done := false<br />
&nbsp; &nbsp; field := true <br />
<br />
&nbsp; &nbsp; for !done {<br />
&nbsp; &nbsp; &nbsp; &nbsp; var b uint16<br />
&nbsp; &nbsp; &nbsp; &nbsp; var t uint8<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; var currentNibbler *Nibbler<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; if field {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentNibbler = &amp;amp;evenNibbler<br />
&nbsp; &nbsp; &nbsp; &nbsp; } else {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentNibbler = &amp;amp;oddNibbler<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; t, _ = currentNibbler.GetNibble()<br />
&nbsp; &nbsp; &nbsp; &nbsp; b = (b &amp;lt;&amp;lt; 4) | uint16(t)<br />
&nbsp; &nbsp; &nbsp; &nbsp; if b &amp;gt;= 0x4 {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; run := b &amp;gt;&amp;gt; 2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DrawPixels(subImg, x, y, run, uint8(b &amp;amp; 0x3))<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x += run<br />
&nbsp; &nbsp; &nbsp; &nbsp; } else {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t, _ := currentNibbler.GetNibble()<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b = (b &amp;lt;&amp;lt; 4) | uint16(t)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if b &amp;gt;= 0x10 {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; run := b &amp;gt;&amp;gt; 2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DrawPixels(subImg, x, y, run, uint8(b &amp;amp; 0x3))<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x += run<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t, _ := currentNibbler.GetNibble()<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b = (b &amp;lt;&amp;lt; 4) | uint16(t)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if b &amp;gt;= 0x40 {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; run := b &amp;gt;&amp;gt; 2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DrawPixels(subImg, x, y, run, uint8(b &amp;amp; 0x3))<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x += run<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t, _ := currentNibbler.GetNibble()<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b = (b &amp;lt;&amp;lt; 4) | uint16(t)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if b &amp;gt;= 0x100 {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; run := b &amp;gt;&amp;gt; 2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DrawPixels(subImg, x, y, run, uint8(b &amp;amp; 0x3))<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x += run<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DrawPixels(subImg, x, y, rect.w - x, uint8(b &amp;amp; 0x3))<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x = 0<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; y += 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; field = !field<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if y &amp;gt;= rect.h {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; done = true<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if currentNibbler.Aligned != 0 {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; currentNibbler.GetNibble()<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; }<br />
&nbsp; &nbsp; return subImg<br />
}</div></td></tr></tbody></table></div>
<p>You'll notice I used the even and odd field offsets to create buffers for both the even and odd fields of the image. Then to switch between them, the pointer <em>currentNibbler</em> is switched between each field whenever we encounter a carriage return. I've also done some basic math in the <em>DrawPixels</em> function to evenly space the colors used in the subtitle throughout the greyscale range from 0 to 128.</p>
<p>The next step for this project is to write a program which can detect and separate images of each character from a subtitle image. After this I'll write a user interface for the user to give character meanings to each character image. From that an SRT file can be written using this character matrix. This is the same basic operation of most VOBSUB to SRT converters except that I aim to make it easier to use.</p>
<p>The complete source for this program can be found at: <a href="https://gist.github.com/1381809">Gist: 1381809</a>. Note that this program will read and decode only the first subtitle in the subtitle file. More work will be done on this when I've got time to make a more automated version that will read and decode all subtitles from a file. At some point in the future when I find that GeSHi supports Golang syntax highlighting, I'll update this post to make it more readable.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bemasher.net/archives/1106/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Newegg&#8217;s JSON API</title>
		<link>http://www.bemasher.net/archives/1002?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=neweggs-json-quasi-api</link>
		<comments>http://www.bemasher.net/archives/1002#comments</comments>
		<pubDate>Thu, 17 Mar 2011 05:11:22 +0000</pubDate>
		<dc:creator>bemasher</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Computers]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[CherryPy]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[lxml]]></category>
		<category><![CDATA[Newegg]]></category>
		<category><![CDATA[Product List]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Script]]></category>

		<guid isPermaLink="false">http://www.bemasher.net/?p=1002</guid>
		<description><![CDATA[For the longest time I've wanted access to Newegg's product list. For me they've been one of the better and more structured websites for buying computer hardware. So naturally they're usually my first choice when it comes to finding a good deal on a particular piece of hardware. They're also rather useful for seeing what's [...]]]></description>
			<content:encoded><![CDATA[<p>For the longest time I've wanted access to Newegg's product list. For me they've been one of the better and more structured websites for buying computer hardware. So naturally they're usually my first choice when it comes to finding a good deal on a particular piece of hardware. They're also rather useful for seeing what's out there since their product catalog is fairly complete.</p>
<p>A while back I had started wanting to sort through items to heuristically pick the best deal based on a number of features Newegg generally provides for each item. This method works pretty well on SSD's and system memory. But until a recent discovery I was limited to scraping Newegg's website in order to get any kind of information from them. If you've ever tried this sort of thing you know that it is messy and generally a bad idea because every single time Newegg changes the structure of their website or any minute detail this will almost always break your scraping script.</p>
<p>The discovery came in the form of a mobile application for Android<sup>[<a href="http://www.bemasher.net/archives/1002#footnote_0_1002" id="identifier_0_1002" class="footnote-link footnote-identifier-link" title="And iOS devices I assume as well.">1</a>]</sup>. The mobile app lets you browse their website in a clean and fast manner. But what got me thinking is that unlike some other mobile applications out there that are just application wrappers for the mobile version of their websites this one operates directly through the native GUI. Now this is where it got interesting. I knew that if Newegg had written the app to use the native GUI then they had to be providing the data to it somehow and I knew it had to be more structured than HTML scraping like what I've been doing<sup>[<a href="http://www.bemasher.net/archives/1002#footnote_1_1002" id="identifier_1_1002" class="footnote-link footnote-identifier-link" title="Because lets face it, that would be stupid.">2</a>]</sup>. You have no idea how happy I was to discover that I was right.</p>
<p>First thing I did was connect my Droid 2 Global to my home network via WiFi in order to sniff some of the traffic going to and from the mobile app. This was accomplished by mounting a CIFS drive from my Windows 7 desktop to my router running Tomato based firmware. The share had a binary for TCPDump which I then used to sniff for traffic originating or going to my phone's IP address. After setting this up and performing all of the basic operations I would need in order to "reverse engineer" the data source I got to work on filtering the important bits.</p>
<p>In WireShark I immediately discovered that they had a sub-domain they were using for these operations. All of the web requests that weren't images or for customer metrics and tracking went to this host:</p>
<p><a href="http://www.ows.newegg.com/">http://www.ows.newegg.com/</a></p>
<p>Because this API is structured more or less the same as navigating their site and the identifiers are different I decided to start with writing a query builder. Basically the purpose was to allow me to browse to the particular category I was interested in analyzing and filter it down to just a few simple requirements to simplify the analysis.</p>
<p>The first major entry point in the process of browsing to what you're interested in pulling is:</p>
<p><a href="http://www.ows.newegg.com/Stores.egg/Menus">http://www.ows.newegg.com/Stores.egg/Menus</a></p>
<p>This takes no parameters and provides the main menu:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br /></div></td><td><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#91;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreDepa&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;ComputerHardware&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ShowSeeAllDeals&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Title&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Computer Hardware&quot;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreDepa&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;PCNotebook&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ShowSeeAllDeals&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Title&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;PCs &amp;amp; Laptops&quot;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreDepa&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Electronics&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">10</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ShowSeeAllDeals&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Title&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Electronics&quot;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; ...</div></td></tr></tbody></table></div>
<p>Once you've selected a store to browse the next uri is:</p>
<p><a href="http://www.ows.newegg.com/Stores.egg/Categories/{StoreID}">http://www.ows.newegg.com/Stores.egg/Categories/{StoreID}</a></p>
<p>The only parameter it takes is StoreID which you'll find in the first query. This will return all of the categories within a store. I haven't really explored this very much as I'm only really interested in browsing system memory and SSD's. Using the Computer Hardware store the output is as follows:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br /></div></td><td><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#91;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Description&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Backup Devices &amp;amp; Media&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;NodeId&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">6642</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ShowSeeAllDeals&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryType&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">2</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Description&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Barebone / Mini Computers&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;NodeId&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">6668</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ShowSeeAllDeals&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryType&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">3</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Description&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;CD / DVD Burners &amp;amp; Media&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;NodeId&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">6646</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ShowSeeAllDeals&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryType&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">10</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; ...</div></td></tr></tbody></table></div>
<p>StoreID is included from the parameters of the request. I'm not exactly sure how to describe the purpose of NodeID but it appears to be a distinguishing feature of a category or subcategory. CategoryID is used for filtering results down to a specific category and can be either a root category or a subcategory. CategoryType determines whether CategoryID is a root category or if it contains subcategories. A value of 1 for CategoryType indicates that it is the root category.</p>
<p>Now depending on CategoryType you either move straight to the search query or onto a navigation query. The navigation query is used if there are subcategories:</p>
<p><a href="http://www.ows.newegg.com/Stores.egg/Navigation/{StoreID}/{CategoryID}/{NodeID}">http://www.ows.newegg.com/Stores.egg/Navigation/{StoreID}/{CategoryID}/{NodeID}</a></p>
<p>This query takes StoreID, CategoryID and NodeID, which you can get from the category listing of a particular store. It will return a subcategory list. Below is the subcategory listing for the memory category.</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br /></div></td><td><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#91;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Description&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Desktop Memory&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;NodeId&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">7611</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ShowSeeAllDeals&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryType&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">147</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Description&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Flash Memory&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;NodeId&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">8038</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ShowSeeAllDeals&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryType&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">68</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Description&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Laptop Memory&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;NodeId&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">7609</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ShowSeeAllDeals&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryType&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">381</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; ...</div></td></tr></tbody></table></div>
<p>From here you will go to the search query<sup>[<a href="http://www.bemasher.net/archives/1002#footnote_2_1002" id="identifier_2_1002" class="footnote-link footnote-identifier-link" title="... or get to the search query from selecting a root category in the main category listing for a store">3</a>]</sup>. At this point it does get a little tricky as the parameters for the query are no longer sent via GET they are instead sent using POST<sup>[<a href="http://www.bemasher.net/archives/1002#footnote_3_1002" id="identifier_3_1002" class="footnote-link footnote-identifier-link" title="At least this is the method used by the mobile app.">4</a>]</sup> which basically will require a programmatic method for making a search query. The search query given a category, store and node will list quite a lot of things. The first thing in the list is search filtering parameters, these will allow you to limit the products shown in the listing.</p>
<p>Data being posted is necessary to receive a non-404 response from the server, if you really wanted to you could just send an empty dictionary as this would just query newegg's entire product list. Any of the query options can be omitted, integer values may be omitted by substituting their value with -1.</p>
<p>The parameters you should concern yourself with are as follows along with the URL the data should be posted in JSON format to:</p>
<p><a href="http://www.ows.newegg.com/Search.egg/Advanced">http://www.ows.newegg.com/Search.egg/Advanced</a></p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">data <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #3366CC;">&quot;SubCategoryId&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">147</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #3366CC;">&quot;NValue&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreDepaId&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #3366CC;">&quot;NodeId&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">7611</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #3366CC;">&quot;BrandId&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #3366CC;">&quot;PageNumber&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryId&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">17</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>NValue is a space separated list of NValues from the search parameters. Mind you, you cannot filter against more than one item in any category of search filters. For example in system memory you can't select <strong>DDR3 1333 (PC3 10600)</strong>, <strong>DDR3 1333 (PC3 10660)</strong> and <strong>DDR3 1333 (PC3 10666)</strong>. The query will return an unsucessful search result. The rest of the parameters are fairly self-explanatory.</p>
<p>The result returned will contain the following elements: RelatedLinkList, CoremetricsInfo, NavigationContentList, PaginationInfo, ProductListItems. CoremetricsInfo and RelatedLinkList can usually be ignored, the elements we're interested in are the NavigationContentList which is a list of search parameters//filters you can apply to the search. PaginationInfo describes how many elements were returned, what page we're on and how many elements there are per page. Last but not least the ProductListItems which provides a list of the products returned by the query along with some basic listing info for each one.</p>
<p>Below is a portion of the NavigationContentList:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br /></div></td><td><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #3366CC;">&quot;NavigationContentList&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;NavigationItemList&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;SubCategoryId&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Description&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Free Shipping&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreDepaId&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">94</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;NValue&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;100007611 600006050 600052012 4808&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;BrandId&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreType&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ItemCount&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">194</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryId&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ElementValue&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;4808&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;SubCategoryId&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Description&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Top Sellers&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreDepaId&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;NValue&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;100007611 600006050 600052012 4802&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;BrandId&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreType&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ItemCount&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">39</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryId&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ElementValue&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;4802&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...</div></td></tr></tbody></table></div>
<p>This section will also contain a group name:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;TitleItem&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;SubCategoryId&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Description&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Useful Links&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreDepaId&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;NValue&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;4800&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;BrandId&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;StoreType&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">2</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ItemCount&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;CategoryId&quot;</span><span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ElementValue&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;4800&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...</div></td></tr></tbody></table></div>
<p>The PaginationInfo and ProductListItem elements will look like the following:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br /></div></td><td><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; ...<br />
&nbsp; &nbsp; <span style="color: #3366CC;">&quot;PaginationInfo&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;TotalCount&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">233</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;PageNumber&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;PageSize&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">20</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #3366CC;">&quot;ProductListItems&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;SellerId&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ItemOwnerType&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Title&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Crucial Ballistix 4GB (2 x 2GB) 240-Pin DDR3 SDRAM DDR3 2133 (PC3 17000) Desktop Memory with Thermal Sensor Model BL2KIT25664FN2139&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ItemGroupID&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ReviewSummary&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Rating&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">5</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;TotalReviews&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;[1]&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;IsCellPhoneItem&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Discount&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;FinalPrice&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;$104.99&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ItemNumber&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;20-148-372&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;MappingFinalPrice&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;$104.99&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;FreeShippingFlag&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;OriginalPrice&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;$104.99&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;IsComboBundle&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;MailInRebateText&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ProductStockType&quot;</span><span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Model&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;BL2KIT25664FN2139&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ShowOriginalPrice&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Image&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;FullPath&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;http://images17.newegg.com/is/image/newegg/20-148-372-TS?$S125W$&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;SmallImagePath&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ThumbnailImagePath&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Title&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">null</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;SellerName&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;ParentItem&quot;</span><span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">null</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ...</div></td></tr></tbody></table></div>
<p>At this point you might be wondering what good will all this do me if I can't get specifications on an item? Well, you can and here's how: In each ProductListItems element you'll find an ItemNumber, this is essentially the primary key that each product is related to within this interface to newegg's product list. Using the following url you can obtain the full details page on any given item using it's ItemNumber:</p>
<p><a href="http://www.ows.newegg.com/Products.egg/{ItemNumber}/Specification">http://www.ows.newegg.com/Products.egg/{ItemNumber}/Specification</a></p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br /></div></td><td><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #3366CC;">&quot;SpecificationGroupList&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;GroupName&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Model&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;SpecificationPairList&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Crucial&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Brand&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Ballistix&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Series&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;BL2KIT25664FN2139&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Model&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;240-Pin DDR3 SDRAM&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Type&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;GroupName&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Tech Spec&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;SpecificationPairList&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;4GB (2 x 2GB)&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Capacity&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;DDR3 2133 (PC3 17000)&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Speed&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;9&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Cas Latency&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;9-10-9-24&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Timing&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;1.65V&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Voltage&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;No&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;ECC&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Unbuffered&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Buffered/Registered&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Dual Channel Kit&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Multi-channel Kit&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;GroupName&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Manufacturer Warranty&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;SpecificationPairList&quot;</span><span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Lifetime limited&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Parts&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Value&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Lifetime limited&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #3366CC;">&quot;Key&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Labor&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #3366CC;">&quot;NeweggItemNumber&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;N82E16820148372&quot;</span><span style="color: #339933;">,</span> <br />
&nbsp; &nbsp; <span style="color: #3366CC;">&quot;Title&quot;</span><span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Crucial Ballistix 4GB (2 x 2GB) 240-Pin DDR3 SDRAM DDR3 2133 (PC3 17000) Desktop Memory with Thermal Sensor Model BL2KIT25664FN2139&quot;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>From this point on you can grab all of the features and specifications of any particular item you're interested in. In the near future I'll be writing a new post for both my memory and SSD analysis scripts using this interface.</p>
<p>The full code for my query builder is as follows, though you should note this was a quick script and is in no way complete or fully functional. As soon as it was to a useable point I moved onto the main point of this whole ordeal. You should also note that this requires CherryPy<sup>[<a href="http://www.bemasher.net/archives/1002#footnote_4_1002" id="identifier_4_1002" class="footnote-link footnote-identifier-link" title="CherryPy: CherryPy is a pythonic, object-oriented HTTP framework.">5</a>]</sup> and lxml<sup>[<a href="http://www.bemasher.net/archives/1002#footnote_5_1002" id="identifier_5_1002" class="footnote-link footnote-identifier-link" title="lxml: A Pythonic binding for the C libraries libxml2 and libxslt.">6</a>]</sup>. The end result of this program is a query which you can use to retrieve a list of products matching the options you've selected. This is mainly to simplify product list selection and to minimalize the need to hardcode in certain values as newegg as a tendency to change things around on a regular basis.</p>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br />89<br />90<br />91<br />92<br />93<br />94<br />95<br />96<br />97<br />98<br />99<br />100<br />101<br />102<br />103<br />104<br />105<br />106<br />107<br />108<br />109<br />110<br />111<br />112<br />113<br />114<br />115<br />116<br />117<br />118<br />119<br />120<br />121<br />122<br />123<br />124<br />125<br />126<br />127<br />128<br />129<br />130<br />131<br />132<br />133<br />134<br />135<br />136<br />137<br />138<br />139<br />140<br />141<br />142<br />143<br />144<br />145<br />146<br />147<br />148<br />149<br />150<br />151<br />152<br />153<br />154<br />155<br />156<br />157<br />158<br />159<br />160<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> cherrypy<span style="color: #66cc66;">,</span> json<span style="color: #66cc66;">,</span> <span style="color: #dc143c;">urllib</span><span style="color: #66cc66;">,</span> <span style="color: #dc143c;">urllib2</span><br />
<span style="color: #ff7700;font-weight:bold;">from</span> lxml <span style="color: #ff7700;font-weight:bold;">import</span> etree<br />
<span style="color: #ff7700;font-weight:bold;">from</span> lxml.<span style="color: black;">builder</span> <span style="color: #ff7700;font-weight:bold;">import</span> E<br />
<br />
<span style="color: #ff7700;font-weight:bold;">class</span> QueryBuilder<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> index<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; request <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://www.ows.newegg.com/Stores.egg/Menus&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; response <span style="color: #66cc66;">=</span> request.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; data <span style="color: #66cc66;">=</span> json.<span style="color: black;">loads</span><span style="color: black;">&#40;</span>response<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; body <span style="color: #66cc66;">=</span> E.<span style="color: black;">body</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; ul <span style="color: #66cc66;">=</span> E.<span style="color: black;">ul</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> store <span style="color: #ff7700;font-weight:bold;">in</span> data:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ul.<span style="color: black;">append</span><span style="color: black;">&#40;</span>E.<span style="color: black;">li</span><span style="color: black;">&#40;</span>E.<span style="color: black;">a</span><span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; store<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Title'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; href<span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'/Store?StoreID={}'</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>store<span style="color: black;">&#91;</span><span style="color: #483d8b;">'StoreID'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; page <span style="color: #66cc66;">=</span> E.<span style="color: black;">html</span><span style="color: black;">&#40;</span>E.<span style="color: black;">body</span><span style="color: black;">&#40;</span>ul<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> etree.<span style="color: black;">tostring</span><span style="color: black;">&#40;</span>page<span style="color: #66cc66;">,</span> pretty_print<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; index.<span style="color: black;">exposed</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">True</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> Store<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> StoreID<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> StoreID <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; request <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://www.ows.newegg.com/Stores.egg/Categories/{}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>StoreID<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response <span style="color: #66cc66;">=</span> request.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data <span style="color: #66cc66;">=</span> json.<span style="color: black;">loads</span><span style="color: black;">&#40;</span>response<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; body <span style="color: #66cc66;">=</span> E.<span style="color: black;">body</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ul <span style="color: #66cc66;">=</span> E.<span style="color: black;">ul</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> category <span style="color: #ff7700;font-weight:bold;">in</span> data:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> category<span style="color: black;">&#91;</span><span style="color: #483d8b;">'CategoryType'</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">1</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ul.<span style="color: black;">append</span><span style="color: black;">&#40;</span>E.<span style="color: black;">li</span><span style="color: black;">&#40;</span>E.<span style="color: black;">a</span><span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; category<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Description'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; href<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'/Search?StoreID={}&amp;CategoryID={}&amp;NodeID={}'</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>StoreID<span style="color: #66cc66;">,</span> category<span style="color: black;">&#91;</span><span style="color: #483d8b;">'CategoryID'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> category<span style="color: black;">&#91;</span><span style="color: #483d8b;">'NodeId'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ul.<span style="color: black;">append</span><span style="color: black;">&#40;</span>E.<span style="color: black;">li</span><span style="color: black;">&#40;</span>E.<span style="color: black;">a</span><span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; category<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Description'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; href<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'/Category?StoreID={}&amp;CategoryID={}&amp;NodeID={}'</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>StoreID<span style="color: #66cc66;">,</span> category<span style="color: black;">&#91;</span><span style="color: #483d8b;">'CategoryID'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> category<span style="color: black;">&#91;</span><span style="color: #483d8b;">'NodeId'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; page <span style="color: #66cc66;">=</span> E.<span style="color: black;">html</span><span style="color: black;">&#40;</span>E.<span style="color: black;">body</span><span style="color: black;">&#40;</span>ul<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> etree.<span style="color: black;">tostring</span><span style="color: black;">&#40;</span>page<span style="color: #66cc66;">,</span> pretty_print<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">&quot;Invalid parameters.&quot;</span><br />
&nbsp; &nbsp; Store.<span style="color: black;">exposed</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">True</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> Category<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> StoreID<span style="color: #66cc66;">,</span> CategoryID<span style="color: #66cc66;">,</span> NodeID<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#91;</span>StoreID<span style="color: #66cc66;">,</span> CategoryID<span style="color: #66cc66;">,</span> NodeID<span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; request <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://www.ows.newegg.com/Stores.egg/Navigation/{}/{}/{}&quot;</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>StoreID<span style="color: #66cc66;">,</span> CategoryID<span style="color: #66cc66;">,</span> NodeID<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response <span style="color: #66cc66;">=</span> request.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data <span style="color: #66cc66;">=</span> json.<span style="color: black;">loads</span><span style="color: black;">&#40;</span>response<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; body <span style="color: #66cc66;">=</span> E.<span style="color: black;">body</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ul <span style="color: #66cc66;">=</span> E.<span style="color: black;">ul</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> subcategory <span style="color: #ff7700;font-weight:bold;">in</span> data:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ul.<span style="color: black;">append</span><span style="color: black;">&#40;</span>E.<span style="color: black;">li</span><span style="color: black;">&#40;</span>E.<span style="color: black;">a</span><span style="color: black;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subcategory<span style="color: black;">&#91;</span><span style="color: #483d8b;">'Description'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; href<span style="color: #66cc66;">=</span> <span style="color: #483d8b;">'/Search?StoreID={}&amp;CategoryID={}&amp;SubCategoryID={}&amp;NodeID={}'</span>.<span style="color: black;">format</span><span style="color: black;">&#40;</span>StoreID<span style="color: #66cc66;">,</span> CategoryID<span style="color: #66cc66;">,</span> subcategory<span style="color: black;">&#91;</span><span style="color: #483d8b;">'CategoryID'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> subcategory<span style="color: black;">&#91;</span><span style="color: #483d8b;">'NodeId'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; page <span style="color: #66cc66;">=</span> E.<span style="color: black;">html</span><span style="color: black;">&#40;</span>E.<span style="color: black;">body</span><span style="color: black;">&#40;</span>ul<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> etree.<span style="color: black;">tostring</span><span style="color: black;">&#40;</span>page<span style="color: #66cc66;">,</span> pretty_print<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">&quot;Invalid parameters.&quot;</span><br />
&nbsp; &nbsp; Category.<span style="color: black;">exposed</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">True</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> Search<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> StoreID<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> CategoryID<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> SubCategoryID<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> NodeID<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; url <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;http://www.ows.newegg.com/Search.egg/Advanced&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; data <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;IsUPCCodeSearch&quot;</span>:&nbsp; &nbsp; &nbsp; <span style="color: #008000;">False</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;IsSubCategorySearch&quot;</span>:&nbsp; <span style="color: #008000;">True</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;isGuideAdvanceSearch&quot;</span>: <span style="color: #008000;">False</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;StoreDepaId&quot;</span>:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; StoreID<span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;CategoryId&quot;</span>: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CategoryID<span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;SubCategoryId&quot;</span>:&nbsp; &nbsp; &nbsp; &nbsp; SubCategoryID<span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;NodeId&quot;</span>: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NodeID<span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;BrandId&quot;</span>:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -<span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;NValue&quot;</span>: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;Keyword&quot;</span>:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;Sort&quot;</span>: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;FEATURED&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;PageNumber&quot;</span>: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: black;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; params <span style="color: #66cc66;">=</span> json.<span style="color: black;">dumps</span><span style="color: black;">&#40;</span>data<span style="color: black;">&#41;</span>.<span style="color: black;">replace</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;null&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;-1&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; request <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>url<span style="color: #66cc66;">,</span> params<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; response <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>request<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; data <span style="color: #66cc66;">=</span> json.<span style="color: black;">loads</span><span style="color: black;">&#40;</span>response.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> data<span style="color: black;">&#91;</span><span style="color: #483d8b;">'NavigationContentList'</span><span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> etree.<span style="color: black;">tostring</span><span style="color: black;">&#40;</span>E.<span style="color: black;">pre</span><span style="color: black;">&#40;</span>json.<span style="color: black;">dumps</span><span style="color: black;">&#40;</span>data<span style="color: #66cc66;">,</span> indent<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: #66cc66;">,</span> pretty_print<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; body <span style="color: #66cc66;">=</span> E.<span style="color: black;">body</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; form <span style="color: #66cc66;">=</span> E.<span style="color: black;">form</span><span style="color: black;">&#40;</span>name<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'PowerSearch'</span><span style="color: #66cc66;">,</span> action<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'GenerateURL'</span><span style="color: #66cc66;">,</span> method<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'GET'</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; table <span style="color: #66cc66;">=</span> E.<span style="color: black;">table</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; form.<span style="color: black;">append</span><span style="color: black;">&#40;</span>table<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> section <span style="color: #ff7700;font-weight:bold;">in</span> data<span style="color: black;">&#91;</span><span style="color: #483d8b;">'NavigationContentList'</span><span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tr <span style="color: #66cc66;">=</span> E.<span style="color: black;">tr</span><span style="color: black;">&#40;</span>E.<span style="color: black;">td</span><span style="color: black;">&#40;</span>section<span style="color: black;">&#91;</span><span style="color: #483d8b;">'TitleItem'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'Description'</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> colspan<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'3'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; table.<span style="color: black;">append</span><span style="color: black;">&#40;</span>tr<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> option <span style="color: #ff7700;font-weight:bold;">in</span> section<span style="color: black;">&#91;</span><span style="color: #483d8b;">'NavigationItemList'</span><span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> index % <span style="color: #ff4500;">3</span> <span style="color: #66cc66;">==</span> <span style="color: #ff4500;">0</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tr <span style="color: #66cc66;">=</span> E.<span style="color: black;">tr</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; table.<span style="color: black;">append</span><span style="color: black;">&#40;</span>tr<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; checkbox <span style="color: #66cc66;">=</span> E.<span style="color: black;">td</span><span style="color: black;">&#40;</span>E.<span style="color: #008000;">input</span><span style="color: black;">&#40;</span>option<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Description&quot;</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">type</span><span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;checkbox&quot;</span><span style="color: #66cc66;">,</span> name<span style="color: #66cc66;">=</span>section<span style="color: black;">&#91;</span><span style="color: #483d8b;">'TitleItem'</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'Description'</span><span style="color: black;">&#93;</span>.<span style="color: black;">replace</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot; &quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;&quot;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> value<span style="color: #66cc66;">=</span>option<span style="color: black;">&#91;</span><span style="color: #483d8b;">'NValue'</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tr.<span style="color: black;">append</span><span style="color: black;">&#40;</span>checkbox<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> param<span style="color: #66cc66;">,</span> value <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#91;</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'StoreID'</span><span style="color: #66cc66;">,</span> StoreID<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'CategoryID'</span><span style="color: #66cc66;">,</span> CategoryID<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'SubCategoryID'</span><span style="color: #66cc66;">,</span> SubCategoryID<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">'NodeID'</span><span style="color: #66cc66;">,</span>NodeID<span style="color: black;">&#41;</span><span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">try</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; form.<span style="color: black;">append</span><span style="color: black;">&#40;</span>E.<span style="color: #008000;">input</span><span style="color: black;">&#40;</span><span style="color: #008000;">type</span><span style="color: #66cc66;">=</span><span style="color: #483d8b;">'hidden'</span><span style="color: #66cc66;">,</span> name<span style="color: #66cc66;">=</span>param<span style="color: #66cc66;">,</span> value<span style="color: #66cc66;">=</span>value<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">KeyError</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">pass</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; form.<span style="color: black;">append</span><span style="color: black;">&#40;</span>E.<span style="color: #008000;">input</span><span style="color: black;">&#40;</span><span style="color: #008000;">type</span><span style="color: #66cc66;">=</span><span style="color: #483d8b;">'submit'</span><span style="color: #66cc66;">,</span> value<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'Submit'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; page <span style="color: #66cc66;">=</span> E.<span style="color: black;">html</span><span style="color: black;">&#40;</span>E.<span style="color: black;">body</span><span style="color: black;">&#40;</span>form<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> etree.<span style="color: black;">tostring</span><span style="color: black;">&#40;</span>page<span style="color: #66cc66;">,</span> pretty_print<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; Search.<span style="color: black;">exposed</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">True</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> GenerateURL<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: #66cc66;">,</span> StoreID<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> CategoryID<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> SubCategoryID<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> NodeID<span style="color: #66cc66;">=</span><span style="color: #008000;">None</span><span style="color: #66cc66;">,</span> **kwargs<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; NValue <span style="color: #66cc66;">=</span> <span style="color: #008000;">set</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> arg <span style="color: #ff7700;font-weight:bold;">in</span> kwargs:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">type</span><span style="color: black;">&#40;</span>kwargs<span style="color: black;">&#91;</span>arg<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">==</span> <span style="color: #008000;">list</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> value <span style="color: #ff7700;font-weight:bold;">in</span> kwargs<span style="color: black;">&#91;</span>arg<span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NValue.<span style="color: black;">add</span><span style="color: black;">&#40;</span>value<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NValue.<span style="color: black;">add</span><span style="color: black;">&#40;</span>kwargs<span style="color: black;">&#91;</span>arg<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; NValue <span style="color: #66cc66;">=</span> <span style="color: #008000;">list</span><span style="color: black;">&#40;</span>NValue<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; NValue.<span style="color: black;">sort</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> StoreID <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; StoreID <span style="color: #66cc66;">=</span> -<span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> CategoryID <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CategoryID <span style="color: #66cc66;">=</span> -<span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> SubCategoryID <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SubCategoryID <span style="color: #66cc66;">=</span> -<span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> NodeID <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NodeID <span style="color: #66cc66;">=</span> -<span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; data <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;StoreDepaId&quot;</span>:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>StoreID<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;CategoryId&quot;</span>: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>CategoryID<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;SubCategoryId&quot;</span>:&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>SubCategoryID<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;NodeId&quot;</span>: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>NodeID<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;BrandId&quot;</span>:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -<span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;NValue&quot;</span>: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">' '</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>NValue<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;PageNumber&quot;</span>: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: black;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> etree.<span style="color: black;">tostring</span><span style="color: black;">&#40;</span>E.<span style="color: black;">pre</span><span style="color: black;">&#40;</span>json.<span style="color: black;">dumps</span><span style="color: black;">&#40;</span>data<span style="color: #66cc66;">,</span> indent<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: #66cc66;">,</span> pretty_print<span style="color: #66cc66;">=</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; GenerateURL.<span style="color: black;">exposed</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">True</span><br />
&nbsp; &nbsp; <br />
cherrypy.<span style="color: black;">quickstart</span><span style="color: black;">&#40;</span>QueryBuilder<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<ol class="footnotes"><li id="footnote_0_1002" class="footnote">And iOS devices I assume as well.</li><li id="footnote_1_1002" class="footnote">Because lets face it, that would be stupid.</li><li id="footnote_2_1002" class="footnote">... or get to the search query from selecting a root category in the main category listing for a store</li><li id="footnote_3_1002" class="footnote">At least this is the method used by the mobile app.</li><li id="footnote_4_1002" class="footnote"><a href="http://www.cherrypy.org/">CherryPy</a>: CherryPy is a pythonic, object-oriented HTTP framework.</li><li id="footnote_5_1002" class="footnote"><a href="http://lxml.de/">lxml</a>: A Pythonic binding for the C libraries libxml2 and libxslt.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.bemasher.net/archives/1002/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Choosing an SSD (A more different S)</title>
		<link>http://www.bemasher.net/archives/927?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=choosing-an-ssd-a-more-different-s</link>
		<comments>http://www.bemasher.net/archives/927#comments</comments>
		<pubDate>Mon, 13 Dec 2010 06:14:14 +0000</pubDate>
		<dc:creator>bemasher</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Computers]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[ElementTree]]></category>
		<category><![CDATA[etree]]></category>
		<category><![CDATA[G.SKILL]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[lxml]]></category>
		<category><![CDATA[Newegg]]></category>
		<category><![CDATA[ocz]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RevoDrive]]></category>
		<category><![CDATA[SSD]]></category>
		<category><![CDATA[TRIM]]></category>
		<category><![CDATA[XHTML]]></category>
		<category><![CDATA[xml]]></category>
		<category><![CDATA[XPath]]></category>

		<guid isPermaLink="false">http://www.bemasher.net/?p=927</guid>
		<description><![CDATA[I've been periodically going back and revisiting the results for my SSD analysis script for newegg.com. The last few times I ran it I noticed that it was broken. It looks like newegg has modified a few things in their power search results page. One thing which is a little obnoxious[1] is that they no [...]]]></description>
			<content:encoded><![CDATA[<p>I've been periodically going back and revisiting the results for my SSD analysis script for newegg.com. The last few times I ran it I noticed that it was broken. It looks like newegg has modified a few things in their power search results page. One thing which is a little obnoxious<sup>[<a href="http://www.bemasher.net/archives/927#footnote_0_927" id="identifier_0_927" class="footnote-link footnote-identifier-link" title="I&#039;ve already sent feedback to them suggesting that they fix this.">1</a>]</sup> is that they no longer include the capacity in the description of the item or as a feature in the feature list when viewing the results page. This only seems to be an issue on the SSD page although I can't figure out why they decided it didn't need to be there in the first place. I see it this way: SSD's are first and foremost a storage device, you'd think that one of the most important features that should be listed with <em>every</em> SSD is the capacity at least.</p>
<p>Anyway, this change broke my script which I had been meaning to rewrite since regular expressions are definitely not the most efficient or cleanest way to parse HTML. I've been working with XML a more often lately despite my original prejudice against it for being a really bloated way to transfer data. One thing I discovered that makes XML a lot less painful is XPath<sup>[<a href="http://www.bemasher.net/archives/927#footnote_1_927" id="identifier_1_927" class="footnote-link footnote-identifier-link" title="Only if the XML parser you&#039;re using supports it, which it seems is not a whole lot of them. At least not all of them support the full specification which is annoying since nobody really seems to document which bits and pieces they support and which whey don&#039;t.">2</a>]</sup> which is an incredibly useful "language" for selecting data from an XML document.</p>
<p>Once I had gone through and read several tutorials and references about XPath I set out to use it in writing a show calendar script which parses data from tvrage.com's XML API. After that useful exercise I realized I could very easily and cleanly apply it to my SSD analysis script. Since HTML is similar in nature to XML<sup>[<a href="http://www.bemasher.net/archives/927#footnote_2_927" id="identifier_2_927" class="footnote-link footnote-identifier-link" title="Although not necessarily XML depending on the particular doctype you&#039;ve chosen, Newegg&#039;s is transitional HTML.">3</a>]</sup> I set out to parse Newegg's results page using XPath. This presented the first problem: Newegg's page isn't strictly XML or even XHTML for that matter. After a great deal of googling and research I landed on the lxml<sup>[<a href="http://www.bemasher.net/archives/927#footnote_3_927" id="identifier_3_927" class="footnote-link footnote-identifier-link" title="lxml: http://codespeak.net/lxml/">4</a>]</sup> website which as it turns out has an HTML parser for navigating and extracting data from HTML in the same way you would from an xml.etree.ElementTree<sup>[<a href="http://www.bemasher.net/archives/927#footnote_4_927" id="identifier_4_927" class="footnote-link footnote-identifier-link" title="xml.etree.ElementTree: http://docs.python.org/library/xml.etree.elementtree.html">5</a>]</sup>. With this in mind I immediately began rewriting the script.</p>
<p>First off lets consider my criteria for a "good" SSD on Newegg. The SSD can be either the typical 2.5" form factor, or a PCI-Express card<sup>[<a href="http://www.bemasher.net/archives/927#footnote_5_927" id="identifier_5_927" class="footnote-link footnote-identifier-link" title="Some of the PCI-Express SSD&#039;s are stupidly fast and more expensive except that it doesn&#039;t look like any of them support TRIM yet which is a major problem for me.">6</a>]</sup>. The interface can be SATAII, SATAIII or PCI-Express. Capacity must be greater than or equal to 120GB<sup>[<a href="http://www.bemasher.net/archives/927#footnote_6_927" id="identifier_6_927" class="footnote-link footnote-identifier-link" title="It is rare that I have a matured (read: haven&#039;t reformatted in a while) install of windows along with all of my most commonly used programs and games that exceeds 60GB so I estimate that doubling this should accommodate for any sudden urges to install really big things.">7</a>]</sup>. Last but not least, the disk should be sub $300<sup>[<a href="http://www.bemasher.net/archives/927#footnote_7_927" id="identifier_7_927" class="footnote-link footnote-identifier-link" title="I can&#039;t really justify spending much more than $300 on a single storage device. It had better be one hell of a storage device if I ever find myself spending more than $300 on it.">8</a>]</sup>.</p>
<p>The above requirements give us the following power search<sup>[<a href="http://www.bemasher.net/archives/927#footnote_8_927" id="identifier_8_927" class="footnote-link footnote-identifier-link" title="This will likely need to be updated at least once a month as Newegg is constantly adding new criteria and changing things.">9</a>]</sup> which we will be using as the source for the script:</p>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">url <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;http://www.newegg.com/Product/ProductList.aspx?Submit=Property&amp;N=100008&quot;</span> + \<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;120&amp;IsNodeId=1&amp;maxPrice=300&amp;OEMMark=1,0&amp;PropertyCodeValue=4213:30854,421&quot;</span> + \<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;3:41472,4213:47725,4214:46019,4214:72313,4214:57574,4214:58118,4214:3941&quot;</span> + \<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;6,4214:47732,4214:30849,4214:47171,4214:46300,4214:77918,4214:72311,4214&quot;</span> + \<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;:77919,4214:55178,4214:47733,4214:57755,4214:44038,4215:55552,4215:47726&quot;</span> + \<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;,4215:41071&amp;bop=And&amp;Pagesize=100&quot;</span></div></td></tr></tbody></table></div>
<p>Now the first thing that made me cringe as I was rewriting this was the fact that I would basically have no choice but to load each individual product page from the results page as capacity is no longer included in either the description or the features list of each product in the results page. Eventually I will get around to multi-threading this to make it a little less painful, or I'll get lucky and Newegg will add the capacity feature back to the item listing in power searches for SSD's. The following is the full source code of the parser:</p>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">re</span><span style="color: #66cc66;">,</span> <span style="color: #dc143c;">math</span><br />
<span style="color: #ff7700;font-weight:bold;">from</span> lxml <span style="color: #ff7700;font-weight:bold;">import</span> etree<br />
<br />
url <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;http://www.newegg.com/Product/ProductList.aspx?Submit=Property&amp;N=100008&quot;</span> + \<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;120&amp;IsNodeId=1&amp;maxPrice=300&amp;OEMMark=1,0&amp;PropertyCodeValue=4213:30854,421&quot;</span> + \<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;3:41472,4213:47725,4214:46019,4214:72313,4214:57574,4214:58118,4214:3941&quot;</span> + \<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;6,4214:47732,4214:30849,4214:47171,4214:46300,4214:77918,4214:72311,4214&quot;</span> + \<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;:77919,4214:55178,4214:47733,4214:57755,4214:44038,4215:55552,4215:47726&quot;</span> + \<br />
&nbsp; &nbsp; <span style="color: #483d8b;">&quot;,4215:41071&amp;bop=And&amp;Pagesize=100&quot;</span><br />
<br />
featureMap <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #483d8b;">'Capacity'</span>: <span style="color: #483d8b;">'capacity'</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: #483d8b;">'Sequential Access - Write:'</span>: <span style="color: #483d8b;">'write'</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: #483d8b;">'Sequential Access - Write'</span>: <span style="color: #483d8b;">'write'</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: #483d8b;">'Sequential Access - Read:'</span>: <span style="color: #483d8b;">'read'</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: #483d8b;">'Sequential Access - Read'</span>: <span style="color: #483d8b;">'read'</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: #483d8b;">'Interface Type'</span>: <span style="color: #483d8b;">'interface'</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: #483d8b;">'Brand'</span>: <span style="color: #483d8b;">'brand'</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: #483d8b;">'Model'</span>: <span style="color: #483d8b;">'model'</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; <span style="color: #483d8b;">'Series'</span>: <span style="color: #483d8b;">'series'</span><br />
<span style="color: black;">&#125;</span><br />
<br />
speed_re <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">re</span>.<span style="color: #008000;">compile</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'(<span style="color: #000099; font-weight: bold;">\d</span>+)<span style="color: #000099; font-weight: bold;">\s</span>?MB/s'</span><span style="color: black;">&#41;</span><br />
capacity_re <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">re</span>.<span style="color: #008000;">compile</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'(<span style="color: #000099; font-weight: bold;">\d</span>+)GB'</span><span style="color: black;">&#41;</span><br />
<br />
<span style="color: #dc143c;">parser</span> <span style="color: #66cc66;">=</span> etree.<span style="color: #dc143c;">HTMLParser</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<span style="color: #808080; font-style: italic;"># tree = etree.parse(&quot;temp.html&quot;, parser)</span><br />
tree <span style="color: #66cc66;">=</span> etree.<span style="color: black;">parse</span><span style="color: black;">&#40;</span>url<span style="color: #66cc66;">,</span> etree.<span style="color: #dc143c;">HTMLParser</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
root <span style="color: #66cc66;">=</span> tree.<span style="color: black;">getroot</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<br />
items <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">for</span> node <span style="color: #ff7700;font-weight:bold;">in</span> root.<span style="color: black;">findall</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;.//div[@class='itemCell']&quot;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; item <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get link</span><br />
&nbsp; &nbsp; link <span style="color: #66cc66;">=</span> node.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;.//a[@title='View Details']&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;link&quot;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> link.<span style="color: black;">attrib</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;href&quot;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get feature list (loads each item's url, should multi-thread this in the future)</span><br />
&nbsp; &nbsp; itemPage <span style="color: #66cc66;">=</span> etree.<span style="color: black;">parse</span><span style="color: black;">&#40;</span>item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;link&quot;</span><span style="color: black;">&#93;</span><span style="color: #66cc66;">,</span> etree.<span style="color: #dc143c;">HTMLParser</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>.<span style="color: black;">getroot</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; featureList <span style="color: #66cc66;">=</span> <span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> n: n.<span style="color: black;">text</span><span style="color: #66cc66;">,</span> itemPage.<span style="color: black;">findall</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;.//fieldset/dl/dt&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; valueList <span style="color: #66cc66;">=</span> <span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> n: n.<span style="color: black;">text</span><span style="color: #66cc66;">,</span> itemPage.<span style="color: black;">findall</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;.//fieldset/dl/dd&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; features <span style="color: #66cc66;">=</span> <span style="color: #008000;">zip</span><span style="color: black;">&#40;</span>featureList<span style="color: #66cc66;">,</span> valueList<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> feature<span style="color: #66cc66;">,</span> value <span style="color: #ff7700;font-weight:bold;">in</span> features:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> value <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #008000;">None</span> <span style="color: #ff7700;font-weight:bold;">and</span> feature <span style="color: #ff7700;font-weight:bold;">in</span> featureMap:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># If it's a speed feature parse out the speed</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> featureMap<span style="color: black;">&#91;</span>feature<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;read&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;write&quot;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; item<span style="color: black;">&#91;</span>featureMap<span style="color: black;">&#91;</span>feature<span style="color: black;">&#93;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">min</span><span style="color: black;">&#40;</span><span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> speed_re.<span style="color: black;">findall</span><span style="color: black;">&#40;</span>value<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># If it's a capacity feature, parse out the capacity</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">elif</span> featureMap<span style="color: black;">&#91;</span>feature<span style="color: black;">&#93;</span> <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">&quot;capacity&quot;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; item<span style="color: black;">&#91;</span>featureMap<span style="color: black;">&#91;</span>feature<span style="color: black;">&#93;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">min</span><span style="color: black;">&#40;</span><span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> capacity_re.<span style="color: black;">findall</span><span style="color: black;">&#40;</span>value<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># If the value doesn't need to be parsed, just store the value in item</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; item<span style="color: black;">&#91;</span>featureMap<span style="color: black;">&#91;</span>feature<span style="color: black;">&#93;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> value.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get price</span><br />
&nbsp; &nbsp; price <span style="color: #66cc66;">=</span> <span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> n: n.<span style="color: black;">text</span><span style="color: #66cc66;">,</span> node.<span style="color: black;">findall</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;.//li[@class='priceFinal']/*&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;price&quot;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">float</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>price<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: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Only add the item if it has the features we need in it</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">&quot;read&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> item <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #483d8b;">&quot;write&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> item <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #483d8b;">&quot;capacity&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> item <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #483d8b;">&quot;series&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> item:<br />
&nbsp; &nbsp; &nbsp; &nbsp; score <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span>item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;read&quot;</span><span style="color: black;">&#93;</span> * item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;write&quot;</span><span style="color: black;">&#93;</span> * item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;capacity&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span> / <span style="color: black;">&#40;</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">math</span>.<span style="color: black;">log</span><span style="color: black;">&#40;</span><span style="color: #008000;">abs</span><span style="color: black;">&#40;</span>item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;read&quot;</span><span style="color: black;">&#93;</span> - item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;write&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span> + <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span> + item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;price&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;score&quot;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> score<br />
&nbsp; &nbsp; &nbsp; &nbsp; items.<span style="color: black;">append</span><span style="color: black;">&#40;</span>item<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <br />
<span style="color: #008000;">sorted</span> <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><br />
<span style="color: #ff7700;font-weight:bold;">for</span> item <span style="color: #ff7700;font-weight:bold;">in</span> items:<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Open addressing like in a hash table, so we don't wind</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># up with any collisions, unlikely but good practice anyway</span><br />
&nbsp; &nbsp; score <span style="color: #66cc66;">=</span> item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;score&quot;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> score <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">sorted</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; score +<span style="color: #66cc66;">=</span> <span style="color: #ff4500;">1</span><br />
&nbsp; &nbsp; <span style="color: #008000;">sorted</span><span style="color: black;">&#91;</span>score<span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> item<br />
<br />
sortOrder <span style="color: #66cc66;">=</span> <span style="color: #008000;">sorted</span>.<span style="color: black;">keys</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
sortOrder.<span style="color: black;">sort</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
sortOrder.<span style="color: black;">reverse</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<br />
headers <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: #483d8b;">'brand'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'series'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'model'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'link'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'interface'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'price'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'capacity'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'read'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'write'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'score'</span><span style="color: black;">&#93;</span><br />
<span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\t</span>'</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>headers<span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">for</span> key <span style="color: #ff7700;font-weight:bold;">in</span> sortOrder:<br />
&nbsp; &nbsp; item <span style="color: #66cc66;">=</span> <span style="color: #008000;">sorted</span><span style="color: black;">&#91;</span>key<span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\t</span>'</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>item<span style="color: black;">&#91;</span>x<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> headers<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>At this point if you've gone through and read the entire script you'll probably notice that I've made a slight change to the scoring equation, it has been changed from the following:</p>
<p><center><img src='http://s0.wp.com/latex.php?latex=%5Cfrac%7B%5Ctext%7BRead%7D+%5Ctimes+%5Ctext%7BWrite%7D+%5Ctimes+%5Ctext%7BCapacity%7D%7D%7B%5Ctext%7BPrice%7D%7D&#038;bg=ffffff&#038;fg=000&#038;s=0' alt='&#92;frac{&#92;text{Read} &#92;times &#92;text{Write} &#92;times &#92;text{Capacity}}{&#92;text{Price}}' title='&#92;frac{&#92;text{Read} &#92;times &#92;text{Write} &#92;times &#92;text{Capacity}}{&#92;text{Price}}' class='latex' /></center><br />
To the following:<br />
<center><img src='http://s0.wp.com/latex.php?latex=%5Cfrac%7B%5Ctext%7BRead%7D+%5Ctimes+%5Ctext%7BWrite%7D+%5Ctimes+%5Ctext%7BCapacity%7D%7D%7B%28%5Clog_%7B10%7D%28%7C%5Ctext%7BRead%7D+-+%5Ctext%7BWrite%7D%7C%29+%2B+1%29+%5Ctimes+%5Ctext%7BPrice%7D%7D&#038;bg=ffffff&#038;fg=000&#038;s=0' alt='&#92;frac{&#92;text{Read} &#92;times &#92;text{Write} &#92;times &#92;text{Capacity}}{(&#92;log_{10}(|&#92;text{Read} - &#92;text{Write}|) + 1) &#92;times &#92;text{Price}}' title='&#92;frac{&#92;text{Read} &#92;times &#92;text{Write} &#92;times &#92;text{Capacity}}{(&#92;log_{10}(|&#92;text{Read} - &#92;text{Write}|) + 1) &#92;times &#92;text{Price}}' class='latex' /></center></p>
<p>I discovered that using the difference in read//write speed <em>heavily</em> penalized drives with anything greater than 10MB/s difference. So I figured that it may be a little more subtle to simply penalize drives based on the magnitude of the difference.</p>
<p>Now you're probably wondering: "When is this blathering idiot going to get to the damned results already?". And you'd be pleasantly surprised to know that I'm getting to them as you waste your time reading this.</p>
<p><center><br />
<img src="http://lh3.ggpht.com/_67X_BsG0Kiw/TQW3hjXnkdI/AAAAAAAAH3Y/K2iIOU7s0yg/Output.png"></img></p>
<table>
<tr>
<td>Manufacturer:</td>
<td>OCZ</td>
<td>OCZ</td>
<td>G.Skill</td>
<td>OCZ</td>
</tr>
<tr>
<td>Series:</td>
<td>RevoDrive</td>
<td>Vertex 2</td>
<td>Phoenix Pro Series</td>
<td>Agility 2</td>
</tr>
<tr>
<td>Capacity:</td>
<td>120GB</td>
<td>180GB</td>
<td>120GB</td>
<td>120GB</td>
</tr>
<tr>
<td>Read:</td>
<td>540MB/s</td>
<td>285MB/s</td>
<td>285MB/s</td>
<td>285MB/s</td>
</tr>
<tr>
<td>Write:</td>
<td>490MB/s</td>
<td>275MB/s</td>
<td>275MB/s</td>
<td>275MB/s</td>
</tr>
<tr>
<td>Item:</td>
<td>N82E16820227578<sup>[<a href="http://www.bemasher.net/archives/927#footnote_9_927" id="identifier_9_927" class="footnote-link footnote-identifier-link" title="OCZ RevoDrive">10</a>]</sup></td>
<td>N82E16820227602<sup>[<a href="http://www.bemasher.net/archives/927#footnote_10_927" id="identifier_10_927" class="footnote-link footnote-identifier-link" title="OCZ Vertex 2">11</a>]</sup></td>
<td>N82E16820231378<sup>[<a href="http://www.bemasher.net/archives/927#footnote_11_927" id="identifier_11_927" class="footnote-link footnote-identifier-link" title="G.SKILL Phoenix Pro Series">12</a>]</sup></td>
<td>N82E16820227593<sup>[<a href="http://www.bemasher.net/archives/927#footnote_12_927" id="identifier_12_927" class="footnote-link footnote-identifier-link" title="OCZ Agility 2">13</a>]</sup></td>
</tr>
<tr>
<td>Price:</td>
<td>$299.99</td>
<td>$294.99</td>
<td>$214.99</td>
<td>$214.99</td>
</tr>
</table>
<p></center></p>
<p>As you can see the RevoDrive far out-scores all the rest of the SSD's considered in this analysis. The main reason is that they've essentially included two 60GB SSD's on the same card and you're expected to perform software raid on them in your own system<sup>[<a href="http://www.bemasher.net/archives/927#footnote_13_927" id="identifier_13_927" class="footnote-link footnote-identifier-link" title="They show up as two separate physical devices despite being located on the same card.">14</a>]</sup>. Despite the incredible speeds they boast I don't think I would purchase one of these to use as my OS//Program disk because compatibility is a major limitation. You must be sure that your motherboard's BIOS supports booting via PCI-Express cards. And last but not least, the main reason I would pass up this card is the lack of TRIM support. As far as I can tell these cards do not support TRIM which is a major downside as far as I'm concerned.</p>
<p>The second disk in the list is the OCZ Vertex 2 180GB version. I'd probably skip this one just because I don't really consider the extra 60GB worth the extra $80.</p>
<p>Which leaves me with the last two disks which are as far as my analysis is concerned, identical. If you take into account the detailed features you'll notice that the G.Skill claims 50k IOPS on the 4k Random write test which seems a bit... optimistic. The OCZ makes no such claim and as far as I'm concerned both disks are more less the same thing. So it's pretty much up to brand preference at this point.</p>
<ol class="footnotes"><li id="footnote_0_927" class="footnote">I've already sent feedback to them suggesting that they fix this.</li><li id="footnote_1_927" class="footnote">Only if the XML parser you're using supports it, which it seems is not a whole lot of them. At least not all of them support the full specification which is annoying since nobody really seems to document which bits and pieces they support and which whey don't.</li><li id="footnote_2_927" class="footnote">Although not necessarily XML depending on the particular doctype you've chosen, Newegg's is transitional HTML.</li><li id="footnote_3_927" class="footnote">lxml: <a href="http://codespeak.net/lxml/">http://codespeak.net/lxml/</a></li><li id="footnote_4_927" class="footnote">xml.etree.ElementTree: <a href="http://docs.python.org/library/xml.etree.elementtree.html">http://docs.python.org/library/xml.etree.elementtree.html</a></li><li id="footnote_5_927" class="footnote">Some of the PCI-Express SSD's are stupidly fast and more expensive except that it doesn't look like any of them support TRIM yet which is a major problem for me.</li><li id="footnote_6_927" class="footnote">It is rare that I have a matured (read: haven't reformatted in a while) install of windows along with all of my most commonly used programs and games that exceeds 60GB so I estimate that doubling this should accommodate for any sudden urges to install <em>really big things</em>.</li><li id="footnote_7_927" class="footnote">I can't really justify spending much more than $300 on a single storage device. It had better be one hell of a storage device if I ever find myself spending more than $300 on it.</li><li id="footnote_8_927" class="footnote">This will likely need to be updated at least once a month as Newegg is constantly adding new criteria and changing things.</li><li id="footnote_9_927" class="footnote"><a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16820227578">OCZ RevoDrive</a></li><li id="footnote_10_927" class="footnote"><a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16820227602">OCZ Vertex 2</a></li><li id="footnote_11_927" class="footnote"><a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16820231378">G.SKILL Phoenix Pro Series</a></li><li id="footnote_12_927" class="footnote"><a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16820227593">OCZ Agility 2</a></li><li id="footnote_13_927" class="footnote">They show up as two separate physical devices despite being located on the same card.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.bemasher.net/archives/927/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Automagic TV Show Calendar</title>
		<link>http://www.bemasher.net/archives/914?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=automagic-tv-show-calendar</link>
		<comments>http://www.bemasher.net/archives/914#comments</comments>
		<pubDate>Sat, 04 Dec 2010 13:11:57 +0000</pubDate>
		<dc:creator>bemasher</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[Calendar]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[ElementTree]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[iCal]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[JSON-C]]></category>
		<category><![CDATA[Protocol]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Show]]></category>
		<category><![CDATA[Thread]]></category>
		<category><![CDATA[Threading]]></category>
		<category><![CDATA[tv]]></category>
		<category><![CDATA[tvrage]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://www.bemasher.net/?p=914</guid>
		<description><![CDATA[A little while ago I was browsing the web and discovered a website called tvrage.com[1] which seems to be the definitive online TV guide. I didn't originally enter the site on the main index but on a page describing the functionality of an XML API[2] they host for accessing their database of TV shows. To [...]]]></description>
			<content:encoded><![CDATA[<p>A little while ago I was browsing the web and discovered a website called tvrage.com<sup>[<a href="http://www.bemasher.net/archives/914#footnote_0_914" id="identifier_0_914" class="footnote-link footnote-identifier-link" title="http://tvrage.com/">1</a>]</sup> which seems to be the definitive online TV guide. I didn't originally enter the site on the main index but on a page describing the functionality of an XML API<sup>[<a href="http://www.bemasher.net/archives/914#footnote_1_914" id="identifier_1_914" class="footnote-link footnote-identifier-link" title="http://services.tvrage.com/">2</a>]</sup> they host for accessing their database of TV shows.</p>
<p>To me, this is like opening presents on christmas day. Just imagine the possibilities! I immediately began exploring the kind of data they provide. The very first idea I had was to use this to create events on my google calendar automatically for unaired episodes of my favorite TV shows.</p>
<p>I've previously written python scripts that interface with gdata but I find their implementation for python to be kind of cumbersome to deal with so I began researching their Protocol API<sup>[<a href="http://www.bemasher.net/archives/914#footnote_2_914" id="identifier_2_914" class="footnote-link footnote-identifier-link" title="Data API Developer&#039;s Guide: The Protocol">3</a>]</sup>. At first I wasted a lot of time attempting to build the necessary XML structures to add events and the like. This got old very fast and I decided to just give JSON-C<sup>[<a href="http://www.bemasher.net/archives/914#footnote_3_914" id="identifier_3_914" class="footnote-link footnote-identifier-link" title="Google&#039;s own flavor of JSON which is almost identical to plain old JSON.">4</a>]</sup> a try. Turns out you can use the built-in JSON module in python for creating the necessary structures.</p>
<p>For parsing the results I got from tvrage I ended up using python's xml.etree.ElementTree which was simple enough to setup to retrieve only the information for each episode I was interested in.<sup>[<a href="http://www.bemasher.net/archives/914#footnote_4_914" id="identifier_4_914" class="footnote-link footnote-identifier-link" title="I only really needed the  original air date, title, season number and episode number.">5</a>]</sup></p>
<p>I had a bit of trouble initially with adding events to google calendar. This stemmed from the fact that google often will return an HTTP Redirect which includes a url with an appended gsession attribute which you're supposed to resubmit the exact data from the first request to. Once I figured this out it was turtles all the way down. I even managed to get the whole script multi-threaded to speed things up since it's impossible to perform batch-requests with JSON-C.</p>
<p>I should note that for the configuration file the calendar should be the "Calendar ID" for the calendar that can be found by looking at the settings page for the individual calendar, it is grouped with the XML and iCal feeds.</p>
<p>ShowList.txt:<sup>[<a href="http://www.bemasher.net/archives/914#footnote_5_914" id="identifier_5_914" class="footnote-link footnote-identifier-link" title="You can find the show_id via the show search found on their XML API page.">6</a>]</sup></p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Castle&nbsp; 19267<br />
House &nbsp; 3908<br />
Bones &nbsp; 2870<br />
Big Bang Theory, The&nbsp; &nbsp; 8511<br />
Mentalist, The&nbsp; 18967<br />
Rizzoli &amp; Isles 24996<br />
Venture Bros., The&nbsp; 6270<br />
Top Gear&nbsp; &nbsp; 6753<br />
Mythbusters 4605<br />
Archer&nbsp; 23354<br />
NCIS&nbsp; &nbsp; 4628<br />
Community &nbsp; 22589</div></td></tr></tbody></table></div>
<p>Config.cfg:</p>
<div class="codecolorer-container ini default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="ini codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000066; font-weight:bold;"><span style="">&#91;</span>Credentials<span style="">&#93;</span></span><br />
<span style="color: #000099;">username</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> someuser@gmail.com</span><br />
<span style="color: #000099;">password</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> somebase64encodedpassword</span><br />
<span style="color: #000099;">calendar</span> <span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;"> somecalendarid@group.calendar.google.com</span></div></td></tr></tbody></table></div>
<p>AirDate.py:</p>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br />89<br />90<br />91<br />92<br />93<br />94<br />95<br />96<br />97<br />98<br />99<br />100<br />101<br />102<br />103<br />104<br />105<br />106<br />107<br />108<br />109<br />110<br />111<br />112<br />113<br />114<br />115<br />116<br />117<br />118<br />119<br />120<br />121<br />122<br />123<br />124<br />125<br />126<br />127<br />128<br />129<br />130<br />131<br />132<br />133<br />134<br />135<br />136<br />137<br />138<br />139<br />140<br />141<br />142<br />143<br />144<br />145<br />146<br />147<br />148<br />149<br />150<br />151<br />152<br />153<br />154<br />155<br />156<br />157<br />158<br />159<br />160<br />161<br />162<br />163<br />164<br />165<br />166<br />167<br />168<br />169<br />170<br />171<br />172<br />173<br />174<br />175<br />176<br />177<br />178<br />179<br />180<br />181<br />182<br />183<br />184<br />185<br />186<br />187<br />188<br />189<br />190<br />191<br />192<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib2</span><span style="color: #66cc66;">,</span> <span style="color: #dc143c;">urllib</span><span style="color: #66cc66;">,</span> json<span style="color: #66cc66;">,</span> <span style="color: #dc143c;">ConfigParser</span><span style="color: #66cc66;">,</span> <span style="color: #dc143c;">base64</span><br />
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">datetime</span> <span style="color: #ff7700;font-weight:bold;">import</span> date<br />
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">xml</span>.<span style="color: black;">etree</span> <span style="color: #ff7700;font-weight:bold;">import</span> ElementTree<br />
<span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">threading</span> <span style="color: #ff7700;font-weight:bold;">import</span> Thread<br />
<br />
<span style="color: #dc143c;">calendar</span> <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;&quot;</span><br />
header <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><br />
<br />
<span style="color: #808080; font-style: italic;"># Thread for retrieving a list of episodes for a given show_id</span><br />
<span style="color: #ff7700;font-weight:bold;">class</span> airDate<span style="color: black;">&#40;</span>Thread<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Initialize thread and set some local attributes</span><br />
&nbsp; &nbsp; <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><span style="color: #66cc66;">,</span> show_name<span style="color: #66cc66;">,</span> show_id<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; Thread.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">show_name</span> <span style="color: #66cc66;">=</span> show_name<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">show_id</span> <span style="color: #66cc66;">=</span> show_id<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get episode list from tvrage.com based on the show_id</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> run<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Retrieve XML episode_list from tvrage.com</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; xml_data <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://services.tvrage.com/feeds/episode_list.php?sid=%s&quot;</span> % <span style="color: #008000;">self</span>.<span style="color: black;">show_id</span><span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Pares XML into ElementTree.Element()</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; xml_tree <span style="color: #66cc66;">=</span> ElementTree.<span style="color: black;">fromstring</span><span style="color: black;">&#40;</span>xml_data<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">result</span> <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># For each season</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> season <span style="color: #ff7700;font-weight:bold;">in</span> xml_tree.<span style="color: black;">findall</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Episodelist/Season&quot;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get the season number</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; season_num <span style="color: #66cc66;">=</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>season.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;no&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># For each episode in the episode list</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> episode <span style="color: #ff7700;font-weight:bold;">in</span> season.<span style="color: black;">findall</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;episode&quot;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get episode number and title</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; episode_num <span style="color: #66cc66;">=</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>episode.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;seasonnum&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">text</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; episode_title <span style="color: #66cc66;">=</span> episode.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;title&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">text</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Build the episode code S##E##</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; episode_code <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;S%02dE%02d&quot;</span> % <span style="color: black;">&#40;</span>season_num<span style="color: #66cc66;">,</span> episode_num<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Parse the airdate into year, month and day</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; year<span style="color: #66cc66;">,</span> month<span style="color: #66cc66;">,</span> day <span style="color: #66cc66;">=</span> <span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> episode.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;airdate&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">text</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;-&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">try</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; episode_airdate <span style="color: #66cc66;">=</span> date<span style="color: black;">&#40;</span>year<span style="color: #66cc66;">,</span> month<span style="color: #66cc66;">,</span> day<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; today <span style="color: #66cc66;">=</span> date.<span style="color: black;">today</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># If episode hasn't aired yet </span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> episode_airdate <span style="color: #66cc66;">&gt;=</span> today:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Add episode to results list</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">result</span>.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;%s %s - %s&quot;</span> % <span style="color: black;">&#40;</span><span style="color: #008000;">str</span><span style="color: black;">&#40;</span>episode_airdate<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">self</span>.<span style="color: black;">show_name</span><span style="color: #66cc66;">,</span> episode_code<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">ValueError</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># If the airdate is invalid (tvrage.com sometimes</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># includes 00's for unknown sections of the date</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">pass</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">class</span> addEvent<span style="color: black;">&#40;</span>Thread<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Thread for adding events to google calendar</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Initialize thread and set local episode variable</span><br />
&nbsp; &nbsp; <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><span style="color: #66cc66;">,</span> episode<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; Thread.<span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">self</span>.<span style="color: black;">episode</span> <span style="color: #66cc66;">=</span> episode<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Add new entry to google calendar</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">def</span> run<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Build entry structure</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; entry <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: #483d8b;">&quot;data&quot;</span>: <span style="color: black;">&#123;</span><span style="color: #483d8b;">&quot;details&quot;</span>: <span style="color: #008000;">self</span>.<span style="color: black;">episode</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;quickAdd&quot;</span>: <span style="color: #008000;">True</span><span style="color: black;">&#125;</span><span style="color: black;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Convert to JSON</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; entry <span style="color: #66cc66;">=</span> json.<span style="color: black;">dumps</span><span style="color: black;">&#40;</span>entry<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Build request including necessary headers and data</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; calReq <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;http://www.google.com/calendar/feeds/%s/private/full?alt=jsonc&quot;</span> % <span style="color: black;">&#40;</span><span style="color: #dc143c;">calendar</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> entry<span style="color: #66cc66;">,</span> header<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Execute the request</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; calRes <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>calReq<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get the redirect url (gsession appended)</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; redirectReq <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>calRes.<span style="color: black;">geturl</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> entry<span style="color: #66cc66;">,</span> header<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">try</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; redirectRes <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>redirectReq<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">except</span> HTTPError:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># If we get some sort of HTTP error code</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># skip entry, can always run again</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">pass</span><br />
&nbsp; &nbsp; <br />
<span style="color: #808080; font-style: italic;"># Get list of events already added to</span><br />
<span style="color: #808080; font-style: italic;"># the calendar from previous executions</span><br />
<span style="color: #ff7700;font-weight:bold;">def</span> getExistingEpisodes<span style="color: black;">&#40;</span>header<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get JSON-C representation of calendar</span><br />
&nbsp; &nbsp; calReq <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">Request</span><span style="color: black;">&#40;</span>url<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;https://www.google.com/calendar/feeds/%s/private/full?alt=jsonc&quot;</span> % <span style="color: black;">&#40;</span><span style="color: #dc143c;">calendar</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> headers<span style="color: #66cc66;">=</span>header<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; calRes <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span>calReq<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Parse JSON-C</span><br />
&nbsp; &nbsp; data <span style="color: #66cc66;">=</span> json.<span style="color: black;">loads</span><span style="color: black;">&#40;</span>calRes.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># If the calendar has events on it</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">&quot;items&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> data<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;data&quot;</span><span style="color: black;">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get the list of events</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; events <span style="color: #66cc66;">=</span> data<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;data&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;items&quot;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; existing_episodes <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># For each event</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> event <span style="color: #ff7700;font-weight:bold;">in</span> events:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Append just the title of the event to the results</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; existing_episodes.<span style="color: black;">append</span><span style="color: black;">&#40;</span>event<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;title&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> existing_episodes<br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># We don't have any events on this calendar</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># so just return an empty list</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ <span style="color: #66cc66;">==</span> <span style="color: #483d8b;">'__main__'</span>:<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Open the configuration file and get the necessary</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># credentials and settings</span><br />
&nbsp; &nbsp; config <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">ConfigParser</span>.<span style="color: #dc143c;">ConfigParser</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; config.<span style="color: black;">readfp</span><span style="color: black;">&#40;</span><span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Config.cfg&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; username <span style="color: #66cc66;">=</span> config.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Credentials&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;username&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; password <span style="color: #66cc66;">=</span> config.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Credentials&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;password&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Password is stored as base64 encoded string just so</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># we don't have our password sitting out in plain sight</span><br />
&nbsp; &nbsp; password <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">base64</span>.<span style="color: black;">b64decode</span><span style="color: black;">&#40;</span>password<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #dc143c;">calendar</span> <span style="color: #66cc66;">=</span> config.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Credentials&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;calendar&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Build loginData structure, this is used to get</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># authentication data from google</span><br />
&nbsp; &nbsp; loginData <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;Email&quot;</span>: username<span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;Passwd&quot;</span>: password<span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;source&quot;</span>: <span style="color: #483d8b;">&quot;BeMasher-ETR-2&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;service&quot;</span>: <span style="color: #483d8b;">&quot;cl&quot;</span><br />
&nbsp; &nbsp; <span style="color: black;">&#125;</span><br />
<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Encode the loginData for usage in a url</span><br />
&nbsp; &nbsp; loginData <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span>loginData<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get authentication data</span><br />
&nbsp; &nbsp; gdataLogin <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">urllib2</span>.<span style="color: black;">urlopen</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;https://www.google.com/accounts/ClientLogin&quot;</span><span style="color: #66cc66;">,</span> data<span style="color: #66cc66;">=</span>loginData<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; SID<span style="color: #66cc66;">,</span> LSID<span style="color: #66cc66;">,</span> Auth <span style="color: #66cc66;">=</span> gdataLogin.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">splitlines</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Build header structure, this will be used for</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># all requests to google calendar from now on</span><br />
&nbsp; &nbsp; header <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;Authorization&quot;</span>: <span style="color: #483d8b;">&quot;GoogleLogin %s&quot;</span> % <span style="color: black;">&#40;</span>Auth<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;GData-Version&quot;</span>: <span style="color: #ff4500;">2</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #483d8b;">&quot;Content-Type&quot;</span>: <span style="color: #483d8b;">&quot;application/json&quot;</span><br />
&nbsp; &nbsp; <span style="color: black;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Open a list of the shows we're interested in</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Stored as &quot;show_name\tshow_id&quot;, one per line</span><br />
&nbsp; &nbsp; show_list <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;ShowList.txt&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; jobs <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> show_list:<br />
&nbsp; &nbsp; &nbsp; &nbsp; show <span style="color: #66cc66;">=</span> line.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\t</span>&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; jobs.<span style="color: black;">append</span><span style="color: black;">&#40;</span>show<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get a list of existing events from previous</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># executions so we don't wind up with duplicates</span><br />
&nbsp; &nbsp; existingEpisodes <span style="color: #66cc66;">=</span> getExistingEpisodes<span style="color: black;">&#40;</span>header<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; threadQueue <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># For each episode we've retrieved that is unaired</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> job <span style="color: #ff7700;font-weight:bold;">in</span> jobs:<br />
&nbsp; &nbsp; &nbsp; &nbsp; show_name<span style="color: #66cc66;">,</span> show_id <span style="color: #66cc66;">=</span> job<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Create an instance of the airDate thread</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">thread</span> <span style="color: #66cc66;">=</span> airDate<span style="color: black;">&#40;</span>show_name<span style="color: #66cc66;">,</span> show_id<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Start it</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">thread</span>.<span style="color: black;">start</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Add it to the threadQueue</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; threadQueue.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">thread</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; episodes <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># While we've still got running threads</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>threadQueue<span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">0</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get a thread from the queue</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">thread</span> <span style="color: #66cc66;">=</span> threadQueue.<span style="color: black;">pop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Block until it completes</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">thread</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># For each episode in the results</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> episode <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">thread</span>.<span style="color: black;">result</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># If it hasn't already been added to google calendar</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> episode<span style="color: black;">&#91;</span><span style="color: #ff4500;">11</span>:<span style="color: black;">&#93;</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> existingEpisodes:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> episode<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Add to list of episodes that need events created</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; episodes.<span style="color: black;">append</span><span style="color: black;">&#40;</span>episode<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># For each episode that doesn't have an</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># event on google calendar already</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> episode <span style="color: #ff7700;font-weight:bold;">in</span> episodes:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Create an addEvent thread, start it</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># and add it to the threadQueue</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">thread</span> <span style="color: #66cc66;">=</span> addEvent<span style="color: black;">&#40;</span>episode<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">thread</span>.<span style="color: black;">start</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; threadQueue.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">thread</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># While we still have threads running</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>threadQueue<span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">0</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get a thread from the queue</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">thread</span> <span style="color: #66cc66;">=</span> threadQueue.<span style="color: black;">pop</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Block until it completes</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #dc143c;">thread</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>This was all done shortly before I discovered that tvrage.com also provides iCal feeds for your favorite shows provided that you register and add some to your list. Unfortunately the iCal feed they generate creates events for exact air times of each episode which I'm not really all that concerned about. So I use this script still to add all-day events for each episode which is easier to view//see when there's a new episode.</p>
<p>I did write another script using their XML API but that will have to wait for another post.</p>
<ol class="footnotes"><li id="footnote_0_914" class="footnote"><a href="http://tvrage.com/">http://tvrage.com/</a></li><li id="footnote_1_914" class="footnote"><a href="http://services.tvrage.com/">http://services.tvrage.com/</a></li><li id="footnote_2_914" class="footnote"><a href="http://code.google.com/apis/calendar/docs/2.0/developers_guide_protocol.html">Data API Developer's Guide: The Protocol</a></li><li id="footnote_3_914" class="footnote">Google's own flavor of JSON which is almost identical to plain old JSON.</li><li id="footnote_4_914" class="footnote">I only really needed the  original air date, title, season number and episode number.</li><li id="footnote_5_914" class="footnote">You can find the show_id via the show search found on their XML API page.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.bemasher.net/archives/914/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Choosing an SSD (Update)</title>
		<link>http://www.bemasher.net/archives/895?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=choosing-an-ssd-update</link>
		<comments>http://www.bemasher.net/archives/895#comments</comments>
		<pubDate>Sun, 10 Oct 2010 02:42:58 +0000</pubDate>
		<dc:creator>bemasher</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Computers]]></category>
		<category><![CDATA[agility]]></category>
		<category><![CDATA[G.SKILL]]></category>
		<category><![CDATA[Newegg]]></category>
		<category><![CDATA[ocz]]></category>
		<category><![CDATA[phoenix]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[sandforce]]></category>
		<category><![CDATA[SSD]]></category>
		<category><![CDATA[vertex]]></category>

		<guid isPermaLink="false">http://www.bemasher.net/?p=895</guid>
		<description><![CDATA[My brother is in the planning stages of building a new desktop. One of the things he's planning on doing differently from his last build[1] is using an SSD for OS + Programs. I had mentioned to him previously that I a wrote a program for helping to choose an SSD based on what SSD's [...]]]></description>
			<content:encoded><![CDATA[<p>My brother is in the planning stages of building a new desktop. One of the things he's planning on doing differently from his last build<sup>[<a href="http://www.bemasher.net/archives/895#footnote_0_895" id="identifier_0_895" class="footnote-link footnote-identifier-link" title="Which incidentally was right when SSD&#039;s were just becoming available to the average consumer.">1</a>]</sup> is using an SSD for OS + Programs.</p>
<p>I had mentioned to him previously that I a wrote a program for helping to choose an SSD based on what SSD's are meant for and are good at doing. So he asked if I could recommend him one. Below are the results of the latest run of my script based on the most current listings<sup>[<a href="http://www.bemasher.net/archives/895#footnote_1_895" id="identifier_1_895" class="footnote-link footnote-identifier-link" title="As of this date 10/09/2010.">2</a>]</sup> of SSD's newegg offers.<br />
<center><br />
<img src="http://lh4.ggpht.com/_67X_BsG0Kiw/TLEno4pTg5I/AAAAAAAAH2Y/sYifab5pRgI/s800/Output.png"></img></p>
<table>
<tr>
<td>Manufacturer:</td>
<td>OCZ</td>
<td>G.Skill</td>
<td>OCZ</td>
</tr>
<tr>
<td>Series:</td>
<td>Agility 2</td>
<td>Phoenix Pro</td>
<td>Vertex 2</td>
</tr>
<tr>
<td>Capacity:</td>
<td>120GB</td>
<td>120GB</td>
<td>120GB</td>
</tr>
<tr>
<td>Read:</td>
<td>285MB/s</td>
<td>285MB/s</td>
<td>285MB/s</td>
</tr>
<tr>
<td>Write:</td>
<td>275MB/s</td>
<td>275MB/s</td>
<td>275MB/s</td>
</tr>
<tr>
<td>Item:</td>
<td>N82E16820227543<sup>[<a href="http://www.bemasher.net/archives/895#footnote_2_895" id="identifier_2_895" class="footnote-link footnote-identifier-link" title="OCZ Agility 2">3</a>]</sup></td>
<td>N82E16820231378<sup>[<a href="http://www.bemasher.net/archives/895#footnote_3_895" id="identifier_3_895" class="footnote-link footnote-identifier-link" title="G.Skill Phoenix Pro">4</a>]</sup></td>
<td>N82E16820227551<sup>[<a href="http://www.bemasher.net/archives/895#footnote_4_895" id="identifier_4_895" class="footnote-link footnote-identifier-link" title="OCZ Vertex 2">5</a>]</sup></td>
</tr>
<tr>
<td>Price:</td>
<td>$235.99</td>
<td>$239.99</td>
<td>$240.00</td>
</tr>
</table>
<p></center><br />
It looks like OCZ has two of the top three places this run and G.Skill is still maintaining one of the top three from before. Between the 3 of them I think i would likely still go for the G.Skill just because of personal preference despite there not really being any significant differences between the three. Excepting price of course.</p>
<ol class="footnotes"><li id="footnote_0_895" class="footnote">Which incidentally was right when SSD's were just becoming available to the average consumer.</li><li id="footnote_1_895" class="footnote">As of this date 10/09/2010.</li><li id="footnote_2_895" class="footnote"><a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16820227543">OCZ Agility 2</a></li><li id="footnote_3_895" class="footnote"><a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16820231378">G.Skill Phoenix Pro</a></li><li id="footnote_4_895" class="footnote"><a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16820227551">OCZ Vertex 2</a></li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.bemasher.net/archives/895/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Choosing an SSD</title>
		<link>http://www.bemasher.net/archives/836?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=choosing-an-ssd</link>
		<comments>http://www.bemasher.net/archives/836#comments</comments>
		<pubDate>Thu, 12 Aug 2010 06:02:27 +0000</pubDate>
		<dc:creator>bemasher</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Computers]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[A-Data]]></category>
		<category><![CDATA[G.SKILL]]></category>
		<category><![CDATA[matplotlib]]></category>
		<category><![CDATA[Newegg]]></category>
		<category><![CDATA[Patriot]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Read]]></category>
		<category><![CDATA[Sequential]]></category>
		<category><![CDATA[SSD]]></category>
		<category><![CDATA[Western Digital]]></category>
		<category><![CDATA[Write]]></category>

		<guid isPermaLink="false">http://www.bemasher.net/?p=836</guid>
		<description><![CDATA[Before I started my new job I had an inordinate amount of free time and for a majority of that time, nothing to spend it doing[1]. I was still thinking about my desktop wishlist[2] and about choosing a better SSD than the one I had previously selected[3]. A long time ago when I was following [...]]]></description>
			<content:encoded><![CDATA[<p>Before I started my new job I had an inordinate amount of free time and for a majority of that time, nothing to spend it doing<sup>[<a href="http://www.bemasher.net/archives/836#footnote_0_836" id="identifier_0_836" class="footnote-link footnote-identifier-link" title="Nothing worth-while anyway">1</a>]</sup>. I was still thinking about my desktop wishlist<sup>[<a href="http://www.bemasher.net/archives/836#footnote_1_836" id="identifier_1_836" class="footnote-link footnote-identifier-link" title="See previous post: Wishlist.">2</a>]</sup> and about choosing a better SSD than the one I had previously selected<sup>[<a href="http://www.bemasher.net/archives/836#footnote_2_836" id="identifier_2_836" class="footnote-link footnote-identifier-link" title="Western Digital SiliconEdge 128GB SSD">3</a>]</sup>.</p>
<p>A long time ago when I was following the HDD market since I was looking to buy some bulk storage I wrote a php script which loaded newegg's product list based on some search parameters you provided newegg's productlist.xml<sup>[<a href="http://www.bemasher.net/archives/836#footnote_3_836" id="identifier_3_836" class="footnote-link footnote-identifier-link" title="Which no longer exists in it&#039;s original form.">4</a>]</sup>. The script would then parse the list and produce a list sorted based on price per gigabyte. Which is useful when you're in the market for capacity<sup>[<a href="http://www.bemasher.net/archives/836#footnote_4_836" id="identifier_4_836" class="footnote-link footnote-identifier-link" title="Which I was.">5</a>]</sup>.</p>
<p>I decided to do more or less the same thing with SSD's except this time I did it in python since I'm rusty on PHP and I didn't want to mess with setting up a web server to test on. So I got started by doing a power search on newegg for the specific flavor of SSD I was looking for.</p>
<p>The search parameters are as follows:</p>
<ul>
<li>2.5" Form Factor</li>
<li>SATA II/III</li>
<li>120GB or Greater</li>
<li>Less than $300</li>
<li>Retail or OEM</li>
<li>Support TRIM Command</li>
</ul>
<p>As of this writing those particular search parameters narrows the result to 17 SSD's. Now comes the code. Before I started coding I needed some way to sort them according to what I thought was important. The metric is as follows:</p>
<p><center>$$\frac{\text{Read} \times \text{Write} \times \text{Capacity}}{|\text{Read} - \text{Write}| \times \text{Price}}$$</center></p>
<p>After looking closer at the scores this produces I noticed that it <em>heavily</em> penalizes drives with huge differences between read and write speeds which effectively weeds out drives that still have acceptable read//write speeds. So I removed that section of the metric producing:</p>
<p><center><img src='http://s0.wp.com/latex.php?latex=%5Cfrac%7B%5Ctext%7BRead%7D+%5Ctimes+%5Ctext%7BWrite%7D+%5Ctimes+%5Ctext%7BCapacity%7D%7D%7B%5Ctext%7BPrice%7D%7D&#038;bg=ffffff&#038;fg=000&#038;s=0' alt='&#92;frac{&#92;text{Read} &#92;times &#92;text{Write} &#92;times &#92;text{Capacity}}{&#92;text{Price}}' title='&#92;frac{&#92;text{Read} &#92;times &#92;text{Write} &#92;times &#92;text{Capacity}}{&#92;text{Price}}' class='latex' /></center></p>
<p>The basic idea behind this scoring measure is that sequential read and write speeds are important, as well as capacity. Price and difference between sequential read//write are considered bad<sup>[<a href="http://www.bemasher.net/archives/836#footnote_5_836" id="identifier_5_836" class="footnote-link footnote-identifier-link" title="Although we&#039;re excluding read//write speed difference.">6</a>]</sup>. In the equation read and write refer to sequential read and write speeds. The ratio of these will produce a score of the SSD's overall performance for capacity, read//write speeds and price.</p>
<p>The code is relatively simple in purpose. Load the data and parse it into a dictionary then sort based on the metric above.</p>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib2</span><span style="color: #66cc66;">,</span> <span style="color: #dc143c;">re</span><br />
<br />
<span style="color: #808080; font-style: italic;"># url = &quot;</span><br />
<span style="color: #808080; font-style: italic;"># http://www.newegg.com/Product/ProductList.aspx?Submit=Property&amp;Subcatego </span><br />
<span style="color: #808080; font-style: italic;"># ry=636&amp;Description=&amp;Type=&amp;N=100008120&amp;IsNodeId=1&amp;srchInDesc=&amp;MinPrice=&amp;M </span><br />
<span style="color: #808080; font-style: italic;"># axPrice=&amp;OEMMark=1&amp;OEMMark=0&amp;PropertyCodeValue=4213:30854&amp;PropertyCodeVa </span><br />
<span style="color: #808080; font-style: italic;"># lue=4214:30848&amp;PropertyCodeValue=4214:39416&amp;PropertyCodeValue=4214:30849 </span><br />
<span style="color: #808080; font-style: italic;"># &amp;PropertyCodeValue=4214:39415&amp;PropertyCodeValue=4215:55552&amp;PropertyCodeV </span><br />
<span style="color: #808080; font-style: italic;"># alue=4215:41071&amp;PropertyCodeValue=4215:46319&quot;</span><br />
<br />
<span style="color: #808080; font-style: italic;"># data = open(&quot;temp.html&quot;, &quot;w&quot;)</span><br />
<span style="color: #808080; font-style: italic;"># data.write(urllib2.urlopen(url).read())</span><br />
<span style="color: #808080; font-style: italic;"># data.close()</span><br />
raw <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;temp.html&quot;</span><span style="color: black;">&#41;</span>.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<br />
item_re <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">re</span>.<span style="color: #008000;">compile</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'&lt;div class=&quot;itemCell&quot;.*?&gt;(.*?)&lt;br class=&quot;clear&quot;.*?&lt;/div&gt;'</span><span style="color: black;">&#41;</span><br />
feature_re <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">re</span>.<span style="color: #008000;">compile</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">&quot;&lt;li&gt;&amp;nbsp;(.*?)&lt;/li&gt;&quot;</span><span style="color: black;">&#41;</span><br />
feature_list_re <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">re</span>.<span style="color: #008000;">compile</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'&lt;b&gt;(.*?)<span style="color: #000099; font-weight: bold;">\s</span>?<span style="color: #000099; font-weight: bold;">\#</span>?<span style="color: #000099; font-weight: bold;">\s</span>?:<span style="color: #000099; font-weight: bold;">\s</span>?&lt;/b&gt;<span style="color: #000099; font-weight: bold;">\s</span>?(.*?)&lt;/li&gt;'</span><span style="color: black;">&#41;</span><br />
speed_re <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">re</span>.<span style="color: #008000;">compile</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">&quot;(up to )?(<span style="color: #000099; font-weight: bold;">\d</span>+).*?MB/s&quot;</span><span style="color: black;">&#41;</span><br />
capacity_re <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">re</span>.<span style="color: #008000;">compile</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">&quot;(<span style="color: #000099; font-weight: bold;">\d</span>+)GB&quot;</span><span style="color: black;">&#41;</span><br />
price_re <span style="color: #66cc66;">=</span> <span style="color: #dc143c;">re</span>.<span style="color: #008000;">compile</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">&quot;&lt;/span&gt;<span style="color: #000099; font-weight: bold;">\$</span>&lt;strong&gt;(<span style="color: #000099; font-weight: bold;">\d</span>+)&lt;/strong&gt;&lt;sup&gt;.(<span style="color: #000099; font-weight: bold;">\d</span>+)&lt;/sup&gt;&quot;</span><span style="color: black;">&#41;</span><br />
<br />
item_list <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
valid <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: #483d8b;">'Read'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Item'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Interface'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Capacity'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Model'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Write'</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">'Size'</span><span style="color: black;">&#93;</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">for</span> item <span style="color: #ff7700;font-weight:bold;">in</span> item_re.<span style="color: black;">findall</span><span style="color: black;">&#40;</span>raw<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; current <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><br />
&nbsp; &nbsp; no_label <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; features <span style="color: #66cc66;">=</span> feature_re.<span style="color: black;">findall</span><span style="color: black;">&#40;</span>item<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; current<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Size&quot;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> features<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; current<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Capacity&quot;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> features<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; current<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Interface&quot;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> features<span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> feature <span style="color: #ff7700;font-weight:bold;">in</span> feature_list_re.<span style="color: black;">findall</span><span style="color: black;">&#40;</span>item<span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> feature<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>.<span style="color: black;">find</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\r</span>&quot;</span><span style="color: black;">&#41;</span> <span style="color: #66cc66;">!=</span> -<span style="color: #ff4500;">1</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; current<span style="color: black;">&#91;</span>feature<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> feature<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\r</span>&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; current<span style="color: black;">&#91;</span>feature<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> feature<span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; current<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Read&quot;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>speed_re.<span style="color: black;">findall</span><span style="color: black;">&#40;</span>current<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Sequential Access - Read&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</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><br />
&nbsp; &nbsp; current<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Write&quot;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>speed_re.<span style="color: black;">findall</span><span style="color: black;">&#40;</span>current<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Sequential Access - Write&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</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><br />
&nbsp; &nbsp; current<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Capacity&quot;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">int</span><span style="color: black;">&#40;</span>capacity_re.<span style="color: black;">findall</span><span style="color: black;">&#40;</span>current<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Capacity&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">for</span> feature <span style="color: #ff7700;font-weight:bold;">in</span> current.<span style="color: black;">keys</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> feature <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #ff7700;font-weight:bold;">in</span> valid:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">del</span> current<span style="color: black;">&#91;</span>feature<span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; current<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Price&quot;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #008000;">float</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'.'</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>price_re.<span style="color: black;">findall</span><span style="color: black;">&#40;</span>item<span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; current<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Item&quot;</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #483d8b;">&quot;http://www.newegg.com/Product/Product.aspx?Item=%s&quot;</span> % <span style="color: black;">&#40;</span>current<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Item&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; item_list.<span style="color: black;">append</span><span style="color: black;">&#40;</span>current<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
<span style="color: #008000;">sorted</span> <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><br />
<span style="color: #ff7700;font-weight:bold;">for</span> item <span style="color: #ff7700;font-weight:bold;">in</span> item_list:<br />
&nbsp; &nbsp; ratio <span style="color: #66cc66;">=</span> <span style="color: black;">&#40;</span>item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Read&quot;</span><span style="color: black;">&#93;</span> * item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Write&quot;</span><span style="color: black;">&#93;</span> * item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Capacity&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span> / <span style="color: black;">&#40;</span>item<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Price&quot;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">sorted</span><span style="color: black;">&#91;</span>ratio<span style="color: black;">&#93;</span> <span style="color: #66cc66;">=</span> item<br />
&nbsp; &nbsp; <br />
sort_order <span style="color: #66cc66;">=</span> <span style="color: #008000;">sorted</span>.<span style="color: black;">keys</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
sort_order.<span style="color: black;">sort</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
sort_order.<span style="color: black;">reverse</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">for</span> key <span style="color: #ff7700;font-weight:bold;">in</span> sort_order:<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">#print '\t'.join(map(lambda x: str(x), sorted[key].keys()))</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #483d8b;">'<span style="color: #000099; font-weight: bold;">\t</span>'</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x: <span style="color: #008000;">str</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #008000;">sorted</span><span style="color: black;">&#91;</span>key<span style="color: black;">&#93;</span>.<span style="color: black;">values</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>Now given that there is quite a lot of data to present and analyze all at once I've decided it would be easiest to just provide you with a pretty graph<sup>[<a href="http://www.bemasher.net/archives/836#footnote_6_836" id="identifier_6_836" class="footnote-link footnote-identifier-link" title="Scores have been normalized to 100%.">7</a>]</sup>:<br />
<center><img src="http://lh5.ggpht.com/_67X_BsG0Kiw/TGOKY0sqJKI/AAAAAAAAHyQ/nAVB8GIDJXQ/s800/Output.png"></img></center><br />
If you look closely at the scores of all the disks in the query, you'll notice that this is a noticeable gap between the top 3 and the rest. They are as follows:<br />
<center><br />
<table>
<tr>
<td>Manufacturer:</td>
<td>A-DATA</td>
<td>Patriot</td>
<td>G.Skill</td>
</tr>
<tr>
<td>Series:</td>
<td>S599</td>
<td>Inferno</td>
<td>Phoenix Series</td>
</tr>
<tr>
<td>Capacity:</td>
<td>128GB</td>
<td>120GB</td>
<td>120GB</td>
</tr>
<tr>
<td>Read:</td>
<td>280MB/s</td>
<td>285MB/s</td>
<td>285MB/s</td>
</tr>
<tr>
<td>Write:</td>
<td>270MB/s</td>
<td>275MB/s</td>
<td>275MB/s</td>
</tr>
<tr>
<td>Item:</td>
<td>N82E16820211471<sup>[<a href="http://www.bemasher.net/archives/836#footnote_7_836" id="identifier_7_836" class="footnote-link footnote-identifier-link" title="A-Data S599">8</a>]</sup></td>
<td>N82E16820220510<sup>[<a href="http://www.bemasher.net/archives/836#footnote_8_836" id="identifier_8_836" class="footnote-link footnote-identifier-link" title="Patriot Inferno">9</a>]</sup></td>
<td>N82E16820231372<sup>[<a href="http://www.bemasher.net/archives/836#footnote_9_836" id="identifier_9_836" class="footnote-link footnote-identifier-link" title="G.Skill Phoenix Series">10</a>]</sup></td>
</tr>
<tr>
<td>Price:</td>
<td>$295.99</td>
<td>$289.99</td>
<td>$299.00</td>
</tr>
</table>
<p></center><br />
I noticed that if you ignore capacity in the metric then the Patriot Inferno is the clear winner here. So as it turns out the Western Digital SiliconEdge I had selected when I first wrote the wishlist wasn't the best drive for my needs. But then I've always had a soft-spot for Western Digital. But now I'm convinced that the Patriot Inferno is the SSD I'll be getting unless by the time I get around to buying one there are better options<sup>[<a href="http://www.bemasher.net/archives/836#footnote_10_836" id="identifier_10_836" class="footnote-link footnote-identifier-link" title="Which there probably will be.">11</a>]</sup>.</p>
<ol class="footnotes"><li id="footnote_0_836" class="footnote">Nothing worth-while anyway</li><li id="footnote_1_836" class="footnote">See previous post: <a href="http://www.bemasher.net/archives/804">Wishlist</a>.</li><li id="footnote_2_836" class="footnote"><a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16820250002&#038;cm_re=Western_Digital_Silicon_Edge-_-20-250-002-_-Product">Western Digital SiliconEdge 128GB SSD</a></li><li id="footnote_3_836" class="footnote">Which no longer exists in it's original form.</li><li id="footnote_4_836" class="footnote">Which I was.</li><li id="footnote_5_836" class="footnote">Although we're excluding read//write speed difference.</li><li id="footnote_6_836" class="footnote">Scores have been normalized to 100%.</li><li id="footnote_7_836" class="footnote"><a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16820211471">A-Data S599</a></li><li id="footnote_8_836" class="footnote"><a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16820220510">Patriot Inferno</a></li><li id="footnote_9_836" class="footnote"><a href="http://www.newegg.com/Product/Product.aspx?Item=N82E16820231372">G.Skill Phoenix Series</a></li><li id="footnote_10_836" class="footnote">Which there probably will be.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.bemasher.net/archives/836/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Matplotlib and Live Data: A Tale of Two Technologies</title>
		<link>http://www.bemasher.net/archives/813?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=matplotlib-and-live-data-the-tale-of-two-technologies</link>
		<comments>http://www.bemasher.net/archives/813#comments</comments>
		<pubDate>Thu, 29 Jul 2010 04:46:53 +0000</pubDate>
		<dc:creator>bemasher</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Arduino]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[DS18B20]]></category>
		<category><![CDATA[DS18S20]]></category>
		<category><![CDATA[DS18X20]]></category>
		<category><![CDATA[gtk]]></category>
		<category><![CDATA[Live]]></category>
		<category><![CDATA[matplotlib]]></category>
		<category><![CDATA[OneWire]]></category>
		<category><![CDATA[pySerial]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[temperature]]></category>

		<guid isPermaLink="false">http://www.bemasher.net/?p=813</guid>
		<description><![CDATA[Being unemployed over the summer is never usually a good thing for me. I get bored very easily if I don't have something to occupy myself with. This last bout of boredom led me to unpack some of my electronics. Dusted off my multimeter, Arduino and a digital thermometer I bought a little while ago. [...]]]></description>
			<content:encoded><![CDATA[<p>Being unemployed over the summer is never usually a good thing for me. I get bored very easily if I don't have something to occupy myself with. This last bout of boredom led me to unpack some of my electronics. Dusted off my multimeter, Arduino and a digital thermometer I bought a little while ago. Figured I could use these to solve one of my current problems.</p>
<p>Living in Laramie usually subjects people to harsh winters which leaves most housing developments without central air conditioning installed since, well it's never really needed except maybe one or two days over the summer where it gets above 85 <sup>o</sup>F. This summer has apparently been hotter than previous summers and It's left my condo in an "uncomfortable state". Mind you I'm used to living in hot weather so this isn't such a terrible thing to me, I'm used to it. </p>
<p>What I'm not used to is not having AC and it cooling off enough at night that it's worthwhile to open a few windows and stick a fan in one of them. Which leaves me with this problem: When is the optimal time to open the windows and turn on the fan to get my condo cooled off earliest//fastest?</p>
<p>In comes my Arduino + digital thermometer<sup>[<a href="http://www.bemasher.net/archives/813#footnote_0_813" id="identifier_0_813" class="footnote-link footnote-identifier-link" title="DS18S20 Digital Thermometer Datasheet">1</a>]</sup>. Once I rigged up the proper power//data connections on a breadboard for my Arduino I set out to find code for the thermometer. I've setup the thermometer with a sketch on my Arduino before I just didn't feel like wasting a few hours trying to do it from scratch again. Soon enough I found some code<sup>[<a href="http://www.bemasher.net/archives/813#footnote_1_813" id="identifier_1_813" class="footnote-link footnote-identifier-link" title="Temperature Measurement using the Dallas DS18B20 by Peter H. Anderson">2</a>]</sup> that worked perfectly. So I trimmed out some code I didn't need for the project and set it up to just write the temperature as fast as possible<sup>[<a href="http://www.bemasher.net/archives/813#footnote_2_813" id="identifier_2_813" class="footnote-link footnote-identifier-link" title="Somewhere in the range of 750ms between readings since it is in parasite mode, may change this later to run in non-parasite mode.">3</a>]</sup> to the serial port it's connected to.</p>
<p>After that I wrote a logging program on my desktop in Python to record temperatures sent via serial to my desktop. The program is incredibly simple and uses the pySerial library<sup>[<a href="http://www.bemasher.net/archives/813#footnote_3_813" id="identifier_3_813" class="footnote-link footnote-identifier-link" title="pySerial Python Library">4</a>]</sup> to read temperatures from the serial port of my desktop and append them to a temperature log. I used a simple windows command to do this since it wouldn't lock the file so I could read data from it simultaneously. There are still occasionally collisions with the processing program locking the file and the logger not being able to write the data to the file but these are rare enough that it's negligible in my situation.</p>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> serial<span style="color: #66cc66;">,</span> <span style="color: #dc143c;">os</span><br />
<br />
ser <span style="color: #66cc66;">=</span> serial.<span style="color: black;">Serial</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span><br />
<span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #008000;">True</span>:<br />
&nbsp; &nbsp; <span style="color: #dc143c;">os</span>.<span style="color: black;">system</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;echo %s&gt;&gt;out.txt&quot;</span> % <span style="color: black;">&#40;</span>ser.<span style="color: #dc143c;">readline</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>The next step in this project was visualizing the data. I've used matplotlib<sup>[<a href="http://www.bemasher.net/archives/813#footnote_4_813" id="identifier_4_813" class="footnote-link footnote-identifier-link" title="matplotlib Python Library">5</a>]</sup> before and I was thinking this time I would like to see if I could write the program to update data live as it recieves it. My first foray into this goal was a miserable disaster. Most of the solutions I could find involved just setting up an infinite loop with a short time delay in it. Which works great except that it sleeps the thread running the plot which makes it impossible to resize the plot or do anything at all with the GUI for that matter. So obviosly this wouldn't work at all.</p>
<p>After poking around for different solutions to this and crashing my computer once from spawning an infinite number of instances of the plot I gave up for a bit, only to discover that there was an example in the documentation which wasn't obviously named. I quickly discovered the best way to do this. I even added some pretty annotations and such.</p>
<div class="codecolorer-container python default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br /></div></td><td><div class="python codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #ff7700;font-weight:bold;">import</span> gobject<br />
<span style="color: #ff7700;font-weight:bold;">import</span> matplotlib<br />
matplotlib.<span style="color: black;">use</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'GTKAgg'</span><span style="color: black;">&#41;</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">import</span> matplotlib.<span style="color: black;">pyplot</span> <span style="color: #ff7700;font-weight:bold;">as</span> plt<br />
<br />
current_pos <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">0</span><br />
temps <span style="color: #66cc66;">=</span> <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span><br />
pad <span style="color: #66cc66;">=</span> <span style="color: #ff4500;">5.0</span><br />
<br />
f <span style="color: #66cc66;">=</span> plt.<span style="color: black;">figure</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
<br />
<span style="color: #ff7700;font-weight:bold;">def</span> update<span style="color: black;">&#40;</span><span style="color: #008000;">vars</span><span style="color: black;">&#41;</span>:<br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Unpack variables that need to be persistent between</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># executions of this method.</span><br />
&nbsp; &nbsp; temps <span style="color: #66cc66;">=</span> <span style="color: #008000;">vars</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; current_pos <span style="color: #66cc66;">=</span> <span style="color: #008000;">vars</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; pad <span style="color: #66cc66;">=</span> <span style="color: #008000;">vars</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Open the data file and get any new data points since</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># the last time we read from this file</span><br />
&nbsp; &nbsp; data <span style="color: #66cc66;">=</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;out.txt&quot;</span><span style="color: #66cc66;">,</span> <span style="color: #483d8b;">&quot;r&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; data.<span style="color: black;">seek</span><span style="color: black;">&#40;</span>current_pos<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; new_temps <span style="color: #66cc66;">=</span> <span style="color: #008000;">map</span><span style="color: black;">&#40;</span><span style="color: #ff7700;font-weight:bold;">lambda</span> x:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">float</span><span style="color: black;">&#40;</span>x<span style="color: black;">&#41;</span> * <span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span> + <span style="color: #ff4500;">4.0</span>/<span style="color: #ff4500;">5.0</span><span style="color: black;">&#41;</span> + <span style="color: #ff4500;">32.0</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; data.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: black;">&#41;</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><br />
&nbsp; &nbsp; current_pos <span style="color: #66cc66;">=</span> data.<span style="color: black;">tell</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; data.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># If we got new data then append it to the list of</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># temperatures and trim to 750 points</span><br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>new_temps<span style="color: black;">&#41;</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #ff4500;">0</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; temps.<span style="color: black;">extend</span><span style="color: black;">&#40;</span>new_temps<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; temps <span style="color: #66cc66;">=</span> temps<span style="color: black;">&#91;</span>-<span style="color: #ff4500;">750</span>:<span style="color: black;">&#93;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; f.<span style="color: black;">clear</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; f.<span style="color: black;">suptitle</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Live Temperature&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; a <span style="color: #66cc66;">=</span> f.<span style="color: black;">add_subplot</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">111</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; a.<span style="color: black;">grid</span><span style="color: black;">&#40;</span><span style="color: #008000;">True</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; l<span style="color: #66cc66;">,</span> <span style="color: #66cc66;">=</span> a.<span style="color: black;">plot</span><span style="color: black;">&#40;</span>temps<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; plt.<span style="color: black;">xlabel</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Time (Seconds)&quot;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; plt.<span style="color: black;">ylabel</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'Temperature $^{<span style="color: #000099; font-weight: bold;">\c</span>irc}$F'</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Get the minimum and maximum temperatures these are</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># used for annotations and scaling the plot of data</span><br />
&nbsp; &nbsp; min_t <span style="color: #66cc66;">=</span> <span style="color: #008000;">min</span><span style="color: black;">&#40;</span>temps<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; max_t <span style="color: #66cc66;">=</span> <span style="color: #008000;">max</span><span style="color: black;">&#40;</span>temps<span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Add annotations for minimum and maximum temperatures</span><br />
&nbsp; &nbsp; a.<span style="color: black;">annotate</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'Min: %0.2f$^{<span style="color: #000099; font-weight: bold;">\c</span>irc}$F'</span> % <span style="color: black;">&#40;</span>min_t<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; xy<span style="color: #66cc66;">=</span><span style="color: black;">&#40;</span>temps.<span style="color: black;">index</span><span style="color: black;">&#40;</span>min_t<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> min_t<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> <br />
&nbsp; &nbsp; &nbsp; &nbsp; xycoords<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'data'</span><span style="color: #66cc66;">,</span> xytext<span style="color: #66cc66;">=</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">20</span><span style="color: #66cc66;">,</span> -<span style="color: #ff4500;">20</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; textcoords<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'offset points'</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; bbox<span style="color: #66cc66;">=</span><span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>boxstyle<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;round&quot;</span><span style="color: #66cc66;">,</span> fc<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;0.8&quot;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; arrowprops<span style="color: #66cc66;">=</span><span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>arrowstyle<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;-&gt;&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; shrinkA<span style="color: #66cc66;">=</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> shrinkB<span style="color: #66cc66;">=</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; connectionstyle<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;angle,angleA=0,angleB=90,rad=10&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
<br />
&nbsp; &nbsp; a.<span style="color: black;">annotate</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'Max: %0.2f$^{<span style="color: #000099; font-weight: bold;">\c</span>irc}$F'</span> % <span style="color: black;">&#40;</span>max_t<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; xy<span style="color: #66cc66;">=</span><span style="color: black;">&#40;</span>temps.<span style="color: black;">index</span><span style="color: black;">&#40;</span>max_t<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> max_t<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; xycoords<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'data'</span><span style="color: #66cc66;">,</span> xytext<span style="color: #66cc66;">=</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">20</span><span style="color: #66cc66;">,</span> <span style="color: #ff4500;">20</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; textcoords<span style="color: #66cc66;">=</span><span style="color: #483d8b;">'offset points'</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; bbox<span style="color: #66cc66;">=</span><span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>boxstyle<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;round&quot;</span><span style="color: #66cc66;">,</span> fc<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;0.8&quot;</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; arrowprops<span style="color: #66cc66;">=</span><span style="color: #008000;">dict</span><span style="color: black;">&#40;</span>arrowstyle<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;-&gt;&quot;</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; shrinkA<span style="color: #66cc66;">=</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span> shrinkB<span style="color: #66cc66;">=</span><span style="color: #ff4500;">1</span><span style="color: #66cc66;">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; connectionstyle<span style="color: #66cc66;">=</span><span style="color: #483d8b;">&quot;angle,angleA=0,angleB=90,rad=10&quot;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Set the axis limits to make the data more readable</span><br />
&nbsp; &nbsp; a.<span style="color: black;">axis</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: #66cc66;">,</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>temps<span style="color: black;">&#41;</span><span style="color: #66cc66;">,</span> min_t - pad<span style="color: #66cc66;">,</span>max_t + pad<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; f.<span style="color: black;">canvas</span>.<span style="color: black;">draw_idle</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># Repack variables that need to be persistent between</span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;"># executions of this method</span><br />
&nbsp; &nbsp; <span style="color: #008000;">vars</span> <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: #ff4500;">0</span>: temps<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span>: current_pos<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span>: pad<span style="color: black;">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">True</span><br />
<br />
<span style="color: #008000;">vars</span> <span style="color: #66cc66;">=</span> <span style="color: black;">&#123;</span><span style="color: #ff4500;">0</span>: temps<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">1</span>: current_pos<span style="color: #66cc66;">,</span> <span style="color: #ff4500;">2</span>: pad<span style="color: black;">&#125;</span><br />
<br />
<span style="color: #808080; font-style: italic;"># Execute update method every 500ms</span><br />
gobject.<span style="color: black;">timeout_add</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">500</span><span style="color: #66cc66;">,</span> update<span style="color: #66cc66;">,</span> <span style="color: #008000;">vars</span><span style="color: black;">&#41;</span><br />
<br />
<span style="color: #808080; font-style: italic;"># Display the plot</span><br />
plt.<span style="color: black;">show</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></td></tr></tbody></table></div>
<p>This code generates a plot which updates every 500ms. This is based on an example in the matplotlib examples<sup>[<a href="http://www.bemasher.net/archives/813#footnote_5_813" id="identifier_5_813" class="footnote-link footnote-identifier-link" title="Animation example code: simple_anim_gtk.py">6</a>]</sup>. An example of the program's output can be seen below.</p>
<p><center><img src="http://lh4.ggpht.com/_67X_BsG0Kiw/TFEFttg0AlI/AAAAAAAAHxk/mwXxOtaC_tQ/s800/Output.png" /></center></p>
<p>I imagine that I could have made this simpler by not using the GTK libraries which are a pain to install since there are 3 or 4 modules you have to install in order to make all this work including the GTK+ runtime. I may come back later and post a version written using TK since it can be used without installing extra modules and stuff.</p>
<ol class="footnotes"><li id="footnote_0_813" class="footnote"><a href="http://datasheets.maxim-ic.com/en/ds/DS18S20.pdf">DS18S20 Digital Thermometer Datasheet</a></li><li id="footnote_1_813" class="footnote"><a href="http://www.phanderson.com/arduino/ds18b20_1.html">Temperature Measurement using the Dallas DS18B20 by Peter H. Anderson</a></li><li id="footnote_2_813" class="footnote">Somewhere in the range of 750ms between readings since it is in parasite mode, may change this later to run in non-parasite mode.</li><li id="footnote_3_813" class="footnote"><a href="http://pyserial.sourceforge.net/">pySerial Python Library</a></li><li id="footnote_4_813" class="footnote"><a href="http://matplotlib.sourceforge.net/">matplotlib Python Library</a></li><li id="footnote_5_813" class="footnote"><a href="http://matplotlib.sourceforge.net/examples/animation/simple_anim_gtk.html">Animation example code: simple_anim_gtk.py</a></li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.bemasher.net/archives/813/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WriteMonkey and Markdown</title>
		<link>http://www.bemasher.net/archives/781?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=writemonkey-and-markdown</link>
		<comments>http://www.bemasher.net/archives/781#comments</comments>
		<pubDate>Mon, 28 Jun 2010 03:14:01 +0000</pubDate>
		<dc:creator>bemasher</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Download Squad]]></category>
		<category><![CDATA[Markdown]]></category>
		<category><![CDATA[WriteMonkey]]></category>

		<guid isPermaLink="false">http://www.bemasher.net/?p=781</guid>
		<description><![CDATA[Recently Download Squad had a post[1] about a practical way to get features and support for open-source programs, specifically through donations. The post was about a program called WriteMonkey which is a minimalistic writing program that the author had originally written about previously[2]. Think of the best code editing program you know of, mine is [...]]]></description>
			<content:encoded><![CDATA[<p>Recently Download Squad had a post<sup>[<a href="http://www.bemasher.net/archives/781#footnote_0_781" id="identifier_0_781" class="footnote-link footnote-identifier-link" title="Download Squad: Amazing software tip: Pay free software developers to get stuff fixed!">1</a>]</sup> about a practical way to get features and support for open-source programs, specifically through donations. The post was about a program called WriteMonkey which is a minimalistic writing program that the author had originally written about previously<sup>[<a href="http://www.bemasher.net/archives/781#footnote_1_781" id="identifier_1_781" class="footnote-link footnote-identifier-link" title="Download Squad: WriteMonkey is an unbelievable full-screen text editor">2</a>]</sup>. Think of the best code editing program you know of, mine is Notepad++<sup>[<a href="http://www.bemasher.net/archives/781#footnote_2_781" id="identifier_2_781" class="footnote-link footnote-identifier-link" title="Notepad++">3</a>]</sup>. Now take that program and refactor it specifically for writing articles or blog posts, you've just created WriteMonkey<sup>[<a href="http://www.bemasher.net/archives/781#footnote_3_781" id="identifier_3_781" class="footnote-link footnote-identifier-link" title="WriteMonkey">4</a>]</sup>.</p>
<p>Something that interested me about WriteMonkey was the Download Squad author's post specifically mentioned writing posts using Markdown<sup>[<a href="http://www.bemasher.net/archives/781#footnote_4_781" id="identifier_4_781" class="footnote-link footnote-identifier-link" title="Markdown">5</a>]</sup> syntax. Markdown is a simple plain-text syntax which is parsed into html removing the need to tediously enter html<sup>[<a href="http://www.bemasher.net/archives/781#footnote_5_781" id="identifier_5_781" class="footnote-link footnote-identifier-link" title="HTML: HyperText Markup Language, is the predominant markup language for web pages.">6</a>]</sup> as  you write. At first glance it didn't really seem like it would really help all that much when it came to writing blog posts. But I was completely wrong and am better off for it. Now the especially useful part is that WriteMonkey supports this completely as well as having a very useful shortcut for parsing and copying html straight from Markdown source. This is incredibly useful since I can then just go to my website and paste the resulting html into a blog post and hit save and be done with it.</p>
<p>As I looked through the program I realized, this is much much more than just a Markdown IDE. It includes all sorts of useful features like a "progress bar" which tells you how far along you are in a certain quota you specify in the preferences. This led me to write a little bit of SQL<sup>[<a href="http://www.bemasher.net/archives/781#footnote_6_781" id="identifier_6_781" class="footnote-link footnote-identifier-link" title="SQL: Structured Query Language">7</a>]</sup> to calculate the average word-count of posts in my blog. Excluding the outliers it came out to ~350 words per post. So I just set the quota to 350 words and it displays a bar at the top or bottom of the screen depending on what you choose showing your current progress on the quota.</p>
<p>It also does several other useful things like displaying current battery life as a percentage in the progress bar, showing the file you're writing in. There's also this feature called repository//main. This allows you to store text clippings in repository and then write the blog post in main. When exported as html the repository is ignored and only main is copied. Makes it useful to write notes and such in the middle of authoring a post to keep with everything you write and it's easy enough to switch between the two to make it useful. For this post I just made a list of points I wanted to cover.</p>
<p>After using WriteMonkey for an hour or so I think I've found the new environment I'll be writing all my posts in for the foreseeable future.</p>
<ol class="footnotes"><li id="footnote_0_781" class="footnote"><a href="http://www.downloadsquad.com/2010/06/25/amazing-software-tip-pay-free-software-developers-to-get-stuff/">Download Squad</a>: Amazing software tip: Pay free software developers to get stuff fixed!</li><li id="footnote_1_781" class="footnote"><a href="http://www.downloadsquad.com/2010/04/21/writemonkey-is-an-unbelievable-full-screen-text-editor/">Download Squad</a>: WriteMonkey is an unbelievable full-screen text editor</li><li id="footnote_2_781" class="footnote"><a href="http://notepad-plus-plus.org/">Notepad++</a></li><li id="footnote_3_781" class="footnote"><a href="http://writemonkey.com/">WriteMonkey</a></li><li id="footnote_4_781" class="footnote"><a href="http://daringfireball.net/projects/markdown/">Markdown</a></li><li id="footnote_5_781" class="footnote"><a href="http://en.wikipedia.org/wiki/Html">HTML</a>: HyperText Markup Language, is the predominant markup language for web pages.</li><li id="footnote_6_781" class="footnote"><a href="http://en.wikipedia.org/wiki/Sql">SQL</a>: Structured Query Language</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.bemasher.net/archives/781/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FreeNAS Users Rejoice!</title>
		<link>http://www.bemasher.net/archives/735?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=freenas-users-rejoice</link>
		<comments>http://www.bemasher.net/archives/735#comments</comments>
		<pubDate>Tue, 04 May 2010 06:06:10 +0000</pubDate>
		<dc:creator>bemasher</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[freenas]]></category>
		<category><![CDATA[install]]></category>
		<category><![CDATA[Live]]></category>
		<category><![CDATA[Stick]]></category>
		<category><![CDATA[syslinux]]></category>
		<category><![CDATA[Thumbdrive]]></category>
		<category><![CDATA[unetbootin]]></category>
		<category><![CDATA[USB]]></category>

		<guid isPermaLink="false">http://www.bemasher.net/?p=735</guid>
		<description><![CDATA[Unetbootin[1] now supports FreeNAS! Take a look at these awesome little snippets of code: 1234567891011121314//distrolst.cpp if &#40;nameDistro == &#34;FreeNAS&#34;&#41; &#123; &#160; &#160; if &#40;isarch64&#41; &#123; &#160; &#160; &#160; &#160; cpuarch = &#34;amd64&#34;; &#160; &#160; &#125; else &#123; &#160; &#160; &#160; &#160; cpuarch = &#34;i386&#34;; &#160; &#160; &#125; &#160; &#160; instIndvfl&#40;&#34;memdisk&#34;, QString&#40;&#34;%1ubnkern&#34;&#41;.arg&#40;targetPath&#41;&#41;; &#160; &#160; if &#40;islivecd&#41; [...]]]></description>
			<content:encoded><![CDATA[<p>Unetbootin<sup>[<a href="http://www.bemasher.net/archives/735#footnote_0_735" id="identifier_0_735" class="footnote-link footnote-identifier-link" title="http://unetbootin.sourceforge.net/">1</a>]</sup> now supports FreeNAS! Take a look at these awesome little snippets of code:</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666;">//distrolst.cpp</span><br />
<span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>nameDistro <span style="color: #000080;">==</span> <span style="color: #FF0000;">&quot;FreeNAS&quot;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>isarch64<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; cpuarch <span style="color: #000080;">=</span> <span style="color: #FF0000;">&quot;amd64&quot;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; cpuarch <span style="color: #000080;">=</span> <span style="color: #FF0000;">&quot;i386&quot;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; &nbsp; instIndvfl<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;memdisk&quot;</span>, QString<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;%1ubnkern&quot;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">arg</span><span style="color: #008000;">&#40;</span>targetPath<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>islivecd<span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; downloadfile<span style="color: #008000;">&#40;</span>QString<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;http://downloads.sourceforge.net/sourceforge/lubi/FreeNAS-%1-LiveCD-%2.img.gz&quot;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">arg</span><span style="color: #008000;">&#40;</span>cpuarch, relname<span style="color: #008000;">&#41;</span>, QString<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;%1ubninit&quot;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">arg</span><span style="color: #008000;">&#40;</span>targetPath<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; downloadfile<span style="color: #008000;">&#40;</span>QString<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;http://sourceforge.net/projects/freenas/files/stable/0.7/FreeNAS-%1-embedded-%2.img/download&quot;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">arg</span><span style="color: #008000;">&#40;</span>cpuarch, relname<span style="color: #008000;">&#41;</span>, QString<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;%1ubninit&quot;</span><span style="color: #008000;">&#41;</span>.<span style="color: #007788;">arg</span><span style="color: #008000;">&#40;</span>targetPath<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; <span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666;">//distrover.cpp</span><br />
distroselect<span style="color: #000040;">-</span><span style="color: #000080;">&gt;</span>addItem<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;FreeNAS&quot;</span>, <span style="color: #008000;">&#40;</span>QStringList<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;0.7.4919&quot;</span> <span style="color: #000080;">&lt;&lt;</span><br />
unetbootin<span style="color: #008080;">::</span><span style="color: #007788;">tr</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;&lt;b&gt;Homepage:&lt;/b&gt; &lt;a href=<span style="color: #000099; font-weight: bold;">\&quot;</span>http://freenas.org/<span style="color: #000099; font-weight: bold;">\&quot;</span>&gt;http://www.freenas.org&lt;/a&gt;&lt;br/&gt;&quot;</span><br />
&nbsp; &nbsp; <span style="color: #FF0000;">&quot;&lt;b&gt;Description:&lt;/b&gt; FreeNAS is an embedded open source NAS (Network-Attached Storage) distribution based on FreeBSD.&lt;br/&gt;&quot;</span><br />
&nbsp; &nbsp; <span style="color: #FF0000;">&quot;&lt;b&gt;Install Notes:&lt;/b&gt; The LiveCD version creates a RAM drive for FreeNAS, and uses a FAT formatted floppy disk or USB key for saving the configuration file. The embedded version allows installation to hard disk.&quot;</span><span style="color: #008000;">&#41;</span> <span style="color: #000080;">&lt;&lt;</span><br />
<span style="color: #FF0000;">&quot;0.7.4919&quot;</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;0.7.4919_x64&quot;</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;0.7.1.5024_Live&quot;</span> <span style="color: #000080;">&lt;&lt;</span> <span style="color: #FF0000;">&quot;0.7.1.4997_Live_x64&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>Segue:<br />
I'm actually considering forking the unetbootin project to add support for a master distro list which can be updated remotely eliminating the requirement for users to download a new copy of the program if they wish to get the latest version of the list of pre-configured distros.</p>
<p>This has a little bit to do with the fact that I'll be required to take a few C++ courses at the University of Wyoming since Java is the standard language taught at the University of Arizona while I was there and I've never used C++ before. Can't be that hard right?</p>
<ol class="footnotes"><li id="footnote_0_735" class="footnote"><a href="http://unetbootin.sourceforge.net/">http://unetbootin.sourceforge.net/</a></li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.bemasher.net/archives/735/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Quote of the Day and Something Cool</title>
		<link>http://www.bemasher.net/archives/654?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=quote-of-the-day-and-something-cool</link>
		<comments>http://www.bemasher.net/archives/654#comments</comments>
		<pubDate>Fri, 11 Sep 2009 03:19:47 +0000</pubDate>
		<dc:creator>bemasher</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[1911]]></category>
		<category><![CDATA[college]]></category>
		<category><![CDATA[discrete structures]]></category>
		<category><![CDATA[grey area]]></category>
		<category><![CDATA[gun]]></category>
		<category><![CDATA[pornography]]></category>
		<category><![CDATA[pro-gun]]></category>
		<category><![CDATA[professor]]></category>
		<category><![CDATA[pseudo-code]]></category>
		<category><![CDATA[student]]></category>

		<guid isPermaLink="false">http://www.bemasher.net/?p=654</guid>
		<description><![CDATA[So I was sitting in my discrete structures analysis class today when a student asked a question about the homework. It went a little like this: Student: How should we format pseudo-code in the homework? Professor: Ah see pseudo-code is in that grey area. It's somewhere in between code and english. Professor: You see me [...]]]></description>
			<content:encoded><![CDATA[<p>So I was sitting in my discrete structures analysis class today when a student asked a question about the homework. It went a little like this:</p>
<blockquote><p>
Student: How should we format pseudo-code in the homework?<br />
Professor: Ah see pseudo-code is in that grey area. It's somewhere in between code and english.<br />
Professor: You see me do it one way in class, the book does it another way and the homework assignment does it an even different way.<br />
Professor: Think of it this way, pseudo-code is a lot like pornography: you'll know it when you see it.<br />
Professor: So I'm not very worried about how you do your pseudo-code as long as I understand it.
</p></blockquote>
<p>The other cool thing that happened today was that I found out the owner of my favorite coffee shop is a pro-gun person. Apparently some of his relatives own a gun shop and he's done some shooting competitions. All very cool. It definitely explains why none of the employees ever freak out about me carrying my 1911 which looks giant on my hip compared to others. I'm a tall skinny guy if you didn't already know.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.bemasher.net/archives/654/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

