<?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>blog.humaneguitarist.org &#187; scripts</title>
	<atom:link href="http://blog.humaneguitarist.org/category/scripts/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.humaneguitarist.org</link>
	<description>discoveries in digital audio, music notation, and information encoding</description>
	<lastBuildDate>Tue, 07 Feb 2012 03:33:53 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>the serpent, the apple, and Joe</title>
		<link>http://blog.humaneguitarist.org/2012/01/07/the-serpent-the-apple-and-joe/</link>
		<comments>http://blog.humaneguitarist.org/2012/01/07/the-serpent-the-apple-and-joe/#comments</comments>
		<pubDate>Sat, 07 Jan 2012 15:22:41 +0000</pubDate>
		<dc:creator>nitin</dc:creator>
				<category><![CDATA[scripts]]></category>
		<category><![CDATA[technophilia]]></category>
		<category><![CDATA[cross-platform]]></category>
		<category><![CDATA[Jython]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[PubMed2XL]]></category>
		<category><![CDATA[PyQT]]></category>
		<category><![CDATA[Swing]]></category>

		<guid isPermaLink="false">http://blog.humaneguitarist.org/?p=3775</guid>
		<description><![CDATA[For better or worse, the one application of mine that people actually use is the one I wrote pretty casually with Python over a couple weekends from bed because I was too lazy or hungover to get moving on those days. That software, PubMed2XL, lets people do a few things with downloaded citations from PubMed.gov [...]]]></description>
			<content:encoded><![CDATA[<p>For better or worse, the one application of mine that people actually use is the one I wrote pretty casually with Python over a couple weekends from bed because I was too lazy or hungover to get moving on those days.</p>
<p>That software, <a href="http://blog.humaneguitarist.org/projects/pubmed2xl">PubMed2XL</a>, lets people do a few things with downloaded citations from PubMed.gov that isn&#39;t currently offered directly from the site. I&#39;ve gotten some nice feedback from librarians, researchers, and information-y people at companies that have found it useful.</p>
<p>This post isn&#39;t a plug though; it&#39;s more an acknowledgement of something that I didn&#39;t really realize in full at the time. And that is when one writes software that people go on to actually use, one better be prepared to support it. Now, the software&#39;s simple enough that there haven&#39;t been real bugs <a href="http://blog.humaneguitarist.org/2011/03/16/dealing-with-a-pubmed2xl-bug/">save one</a>, but it does eat at me that I can&#39;t offer a simple way for it to work on multiple platforms.</p>
<p>While the Windows version is really easy to setup &#8211; thanks to <a href="http://www.py2exe.org/">py2exe</a> and <a href="http://www.youtube.com/watch?v=wP9HcD4oPDw">Inno Setup</a> &#8211; getting it running on Linux is a bit more work, given all the distro variations and dependency installation. But getting it running on a Mac &#8211; particularly with an easy to use installer &#8211; isn&#39;t going to be possible unless I can find someone to compile it for a Mac who will also test it and compile future versions. Sure, there&#39;s the possibility of using <a href="http://www.winehq.org/">Wine</a>, but that&#39;s still asking a lot from end users.</p>
<p>Normally, I wouldn&#39;t care. Apple doesn&#39;t make it easy for people to develop for Macs unless you fork over the change for a Mac &#8211; and I ain&#39;t buying a copy of OSX and doing the Hackintosh bit. But, since the software is ultimately about health-related research, I do care.</p>
<p>Unfortunately I made &#8211; with the advantage of hindsight &#8211; two coding decisions that create problems.</p>
<p>First, I chose <a href="http://www.riverbankcomputing.co.uk/software/pyqt/intro">PyQT</a> as the GUI toolkit for the software simply because it looks prettier than Python&#39;s native Tkinter. My reasoning at the time was the people were more likely to trust better looking software even though it&#39;s just a small window with some basic menu options. Eventually, I added a progress bar, too, so downgrading to Tkinter has become less of an option.</p>
<p>Second (and this is the big one), I used <a href="http://lxml.de/">lxml</a> since the <a href="http://blog.humaneguitarist.org/projects/pubmed2xl/#Changing">PubMed2XL setup files</a> employ XSL to tell the software what data to put in a spreadsheet cell. Granted, lxml is freakin&#39; fantastic, but since it&#39;s not a pure Python module I can&#39;t just distribute it in a folder and import the module locally. Not that I had much of a choice: there&#39;s no built in XSLT-capable module that ships with Python &#39;far as I know.</p>
<p>So I&#39;ve been asking myself how to make the serpent (Python) and the apple (OSX) get along.</p>
<p>I&#39;ve consider just making PubMed2XL a web-app, but that will entail expenses for me that simply offering people a desktop app doesn&#39;t entail.</p>
<p>So, I think the solution lies in a cup of <a href="http://h2g2.com/dna/h2g2/A1300410">Joe</a>. That&#39;s to say that a Java app is the obvious solution, specifically using <a href="http://www.jython.org/">Jython</a>.</p>
<p>That would leave me to replace PyQT with Swing. I&#39;m fine with that. It&#39;s not like PyQT is all that <a href="http://www.python.org/dev/peps/pep-0020/">Pythonic</a> in the first place. There&#39;s a nice Jython/Swing tutorial <a href="http://zetcode.com/tutorials/jythonswingtutorial/">here</a>.</p>
<p>And as for the XSLT component, <a href="http://jython.xhaus.com/transforming-with-xslt-on-google-appengine-and-jython/">this</a> tutorial on XSLT with Jython and native Java libraries should help immensely.</p>
<p>So, I <em>should</em> be able to use Jython to make a cross-platform version of PubMed2XL. I don&#39;t necessarily want to, but given the type of research I&#39;d like to help facilitate (in a very small way, I know), I think I probably should.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.humaneguitarist.org/2012/01/07/the-serpent-the-apple-and-joe/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>bidi bidi bidi and more on pOAIndexter-ing metadata</title>
		<link>http://blog.humaneguitarist.org/2011/10/15/bidi-bidi-bidi-and-more-on-poaindexter-ing-metadata/</link>
		<comments>http://blog.humaneguitarist.org/2011/10/15/bidi-bidi-bidi-and-more-on-poaindexter-ing-metadata/#comments</comments>
		<pubDate>Sat, 15 Oct 2011 13:05:55 +0000</pubDate>
		<dc:creator>nitin</dc:creator>
				<category><![CDATA[scripts]]></category>
		<category><![CDATA[metadata harvesting]]></category>
		<category><![CDATA[OAI]]></category>
		<category><![CDATA[pOAIndexter]]></category>
		<category><![CDATA[Twiki]]></category>

		<guid isPermaLink="false">http://blog.humaneguitarist.org/?p=3381</guid>
		<description><![CDATA[It&#39;s shaping up to be a sunny day and this means I need to go on a long walk. But before I do that, I&#39;ll follow up to this post about grabbing OAI metadata from an online source and throwing the metadata into Solr for searching purposes, etc. Last night &#8211; while watching streaming the [...]]]></description>
			<content:encoded><![CDATA[<p>It&#39;s shaping up to be a sunny day and this means I need to go on a long walk.</p>
<p>But before I do that, I&#39;ll follow up to <a href="http://blog.humaneguitarist.org/2011/10/02/poaindexter-grabbing-and-indexing-online-metadata/">this</a> post about grabbing OAI metadata from an online source and throwing the metadata into Solr for searching purposes, etc.</p>
<p>Last night &#8211; while <strike>watching</strike> streaming the Gil Gerard iteration of <a href="http://www.imdb.com/title/tt0078579/">Buck Rogers</a> &#8211; I wrote a small PHP script to grab <a href="http://memory.loc.gov/cgi-bin/oai2_0?verb=ListRecords&amp;metadataPrefix=oai_dc&amp;set=papr">this</a> OAI metadata from the Library of Congress&#39; site. BTW: <a href="http://memory.loc.gov/ammem/oamh/oai_request.html">this</a> is a cool page of theirs that helps one get started with OAI feeds, etc.</p>
<p><i>Aside: Is it only since the advent of hypertext that the word &quot;this&quot; began appearing in a referential context within documents?</i></p>
<p>As I mentioned in the previous post, an XML config file will instruct the code where to get the metadata and which XSL file will be used to transform the data into something Solr can chew on. I haven&#39;t bothered with the config file yet, so for now I just tested it on the specific metadata linked to above since the config file aspect of this is the most trivial component of the whole thing.</p>
<p>Anyway, below is the PHP file, the OAI to Solr XSL file, and a snippet of the output. Last is a Python script that does the same thing as the PHP. It&#39;s not OO like the PHP file, but I just whipped it up this morning for <a href="http://www.urbandictionary.com/define.php?term=shiggles">shiggles</a>.</p>
<p>Here&#39;s the PHP &#8230;</p>
<pre class="brush:php">&lt;?php

function grabMetadata($urlArg) {
    $ch = curl_init(); // see: http://php.net/manual/en/book.curl.php
    curl_setopt($ch, CURLOPT_URL, $urlArg);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $curlOut = curl_exec($ch);
    return $curlOut;
    curl_close($ch);
}

// See &quot;http://www.php.net/manual/en/xsltprocessor.transformtoxml.php&quot; for instructions re: XSL processing as below.
function useXSL($output) {
    $search_results = new DOMDocument;
    $search_results-&gt;loadXML($output);
    // If you just use &quot;load&quot; instead of &quot;loadXML&quot; it won&#39;t work unless you first stored the XML results in a file (boo!).
    // For info on &quot;loadXML&quot; see: http://www.php.net/manual/en/domdocument.loadxml.php
    $proc = new XSLTProcessor;
    $xsl = new DOMDocument;
    $xsl-&gt;load(&#39;OAI_to_solr.xsl&#39;);
    $proc-&gt;importStyleSheet($xsl);
    $processed = $proc-&gt;transformToXML($search_results);
    return $processed;
}

function writeSOLR($solrXML) {
    $myFile = &quot;for_solr-PHP.xml&quot;;
    $fh = fopen($myFile, &#39;w&#39;) or die(&quot;can&#39;t open file&quot;);
    fwrite($fh, utf8_encode($solrXML)); // For UTF-8, see: http://www.php.net/manual/en/function.fwrite.php#73764
    fclose($fh);
}

// Do stuff ...
$output = grabMetadata(&#39;http://memory.loc.gov/cgi-bin/oai2_0?verb=ListRecords&amp;metadataPrefix=oai_dc&amp;set=papr&#39;);
writeSOLR(useXSL($output));
?&gt;
</pre>
<div>The XSL file &hellip;</div>
<pre class="brush:xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;
xmlns:oai_dc=&quot;http://www.openarchives.org/OAI/2.0/oai_dc/&quot;
xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot;
exclude-result-prefixes=&quot;oai_dc dc&quot;&gt;
  &lt;xsl:output method=&quot;xml&quot; indent=&quot;yes&quot; encoding=&quot;UTF-8&quot;/&gt;
  &lt;xsl:template match=&quot;/&quot;&gt;
    &lt;add&gt;
      &lt;xsl:for-each select=&quot;//oai_dc:dc&quot;&gt;
        &lt;doc&gt;
          &lt;field name=&quot;identifier&quot;&gt;
            &lt;xsl:value-of select=&quot;dc:identifier&quot; /&gt;
          &lt;/field&gt;
          &lt;field name=&quot;title&quot;&gt;
            &lt;xsl:value-of select=&quot;dc:title&quot; /&gt;
          &lt;/field&gt;
          &lt;field name=&quot;creator&quot;&gt;
            &lt;xsl:value-of select=&quot;dc:creator&quot; /&gt;
          &lt;/field&gt;
          &lt;xsl:for-each select=&quot;dc:subject&quot;&gt;
            &lt;field name=&quot;subject&quot;&gt;
              &lt;xsl:value-of select=&quot;.&quot; /&gt;
            &lt;/field&gt;
          &lt;/xsl:for-each&gt;
          &lt;field name=&quot;description&quot;&gt;
            &lt;xsl:value-of select=&quot;dc:description&quot; /&gt;
          &lt;/field&gt;
        &lt;/doc&gt;
      &lt;/xsl:for-each&gt;
    &lt;/add&gt;
  &lt;/xsl:template&gt;
&lt;/xsl:stylesheet&gt;
</pre>
<div>The Millionare and his wife &hellip; er, <a href="http://www.imdb.com/title/tt0057751/">wrong show</a>. I mean the sample Solr XML snippet &#8230;</div>
<pre class="brush:xml">&lt;add&gt;
  &lt;doc&gt;
    &lt;field name=&quot;identifier&quot;&gt;http://hdl.loc.gov/loc.mbrsmi/amrlv.4007&lt;/field&gt;
    &lt;field name=&quot;title&quot;&gt;[Theater commercial--electric refrigerators]. Buy an electric refrigerator /&lt;/field&gt;
    &lt;field name=&quot;creator&quot;&gt;AFI/Kalinowski (Eugene) Collection (Library of Congress)&lt;/field&gt;
    &lt;field name=&quot;subject&quot;&gt;Refrigerators.&lt;/field&gt;
    &lt;field name=&quot;subject&quot;&gt;Advertising--Electric household appliances--Pennsylvania--Pittsburgh.&lt;/field&gt;
    &lt;field name=&quot;subject&quot;&gt;Trade shows--Pennsylvania--Pittsburgh.&lt;/field&gt;
    &lt;field name=&quot;subject&quot;&gt;Silent films.&lt;/field&gt;
    &lt;field name=&quot;subject&quot;&gt;Pittsburgh (Pa.)--Manufactures.&lt;/field&gt;
    &lt;field name=&quot;description&quot;&gt;Largely graphic commercial for electric refrigerators in general and a refrigerator show, presumably in Pittsburgh, in particular.&lt;/field&gt;
  &lt;/doc&gt;

...

&lt;/add&gt;
</pre>
<div>Some Python for fun &#8230;</div>
<pre class="brush:python">import codecs
import urllib
from lxml import etree, _elementpath # see: http://lxml.de/
from lxml.etree import XSLT,fromstring

## some OAI metadata from the Library of Congress
url = &#39;http://memory.loc.gov/cgi-bin/oai2_0?verb=ListRecords&amp;metadataPrefix=oai_dc&amp;set=papr&#39;
metadata = urllib.urlopen(url).read()
metadata = etree.XML(metadata)

## the XSL file that will transform the OAI metadata to Solr
xsl = open(&#39;OAI_to_solr.xsl&#39;, &#39;r&#39;)
xsl = xsl.read()
xsl = etree.XML(xsl)

## XSL transformation
style = XSLT(xsl)
result = style.apply(metadata)

## the outputted Solr XML
fw = codecs.open(&#39;for_solr-PY.xml&#39;, &#39;w&#39;, &#39;utf-8-sig&#39;)
utf8_result = unicode(str(result), encoding=&#39;utf8&#39;)
fw.write(utf8_result)
fw.close()
</pre>
<p>And most importantly, the introduction to Buck Rogers in the 25<sup>th</sup> Century &#8211; Season 1, of course! I couldn&#39;t even make it through the first ten minutes of the Season 2 opener. I mean they changed the introduction which was brilliant and brilliantly narrated &#8211; as you shall see!</p>
<p><embed allowfullscreen="true" allowscriptaccess="always" id="VideoPlayback" src="http://video.google.com/googleplayer.swf?docid=663313548897022933&amp;hl=en&amp;fs=true" style="width:400px;height:326px" type="application/x-shockwave-flash"></embed></p>
<p>I&#39;d prefer to watch the South Park spoof over the Season 2 insult-to-perfection any day of the week.</p>
<p><embed allowfullscreen="true" allowscriptaccess="always" base="." flashvars="" height="293" src="http://media.mtvnservices.com/mgid:cms:item:southparkstudios.com:155394" type="application/x-shockwave-flash" width="360"></embed></p>
<p>And here&#39;s a bad-ass fan trailer that I think respects the greatness of the first season.</p>
<p><iframe allowfullscreen="" frameborder="0" height="315" src="http://www.youtube.com/embed/4szGxaKF8Qw" width="420"></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.humaneguitarist.org/2011/10/15/bidi-bidi-bidi-and-more-on-poaindexter-ing-metadata/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>pOAIndexter: grabbing and indexing online metadata</title>
		<link>http://blog.humaneguitarist.org/2011/10/02/poaindexter-grabbing-and-indexing-online-metadata/</link>
		<comments>http://blog.humaneguitarist.org/2011/10/02/poaindexter-grabbing-and-indexing-online-metadata/#comments</comments>
		<pubDate>Sun, 02 Oct 2011 15:20:09 +0000</pubDate>
		<dc:creator>nitin</dc:creator>
				<category><![CDATA[scripts]]></category>
		<category><![CDATA[faceting]]></category>
		<category><![CDATA[indexing]]></category>
		<category><![CDATA[metadata harvesting]]></category>
		<category><![CDATA[OAI]]></category>
		<category><![CDATA[pOAIndexter]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[Solr]]></category>

		<guid isPermaLink="false">http://blog.humaneguitarist.org/?p=3315</guid>
		<description><![CDATA[As per usual, a good bit of my computer-y stuff at home relates to something that&#39;s come up at work. And as usual, I&#39;m pretty ignorant of what I&#39;m getting myself into, but I don&#39;t mind. The other week, my boss and I met with some great people at digitalnc.org and we started talking about [...]]]></description>
			<content:encoded><![CDATA[<p>As per usual, a good bit of my computer-y stuff at home relates to something that&#39;s come up at work. And as usual, I&#39;m pretty ignorant of what I&#39;m getting myself into, but I don&#39;t mind.</p>
<p>The other week, my boss and I met with some great people at <a href="http://digitalnc.org/">digitalnc.org</a> and we started talking about the idea of having a super simple, lightweight approach to providing a one-stop-shop search interface for collections across the state &#8211; provided those collections expose their metadata somehow. For now, we talked about limiting this to people who do so with an OAI feed and grabbing that metadata. But eventually, this thing should be metadata agnostic &#8211; in the sense that it isn&#39;t about a metadata format, but just the data itself.</p>
<p>By the way, I guess &quot;grabbing&quot; and &quot;feed&quot; aren&#39;t what I typically see with OAI &#8211; about which I admittedly don&#39;t know much &#8211; but I don&#39;t care. Same difference.</p>
<p>Of course, there&#39;s nothing new to this. I guess one could use <a href="http://projectblacklight.org/">Blacklight</a> or <a href="http://vufind.org">VuFind</a> to do this kind of thing, but I&#39;m not sure, though even those are existing open souce projects, that doing so isn&#39;t overkill and won&#39;t in turn increase dependencies and maintenance overhead.</p>
<p>Actually, that&#39;s a topic for another time &#8211; I mean the idea that just because <em>part of</em> something is capable of doing what you want doesn&#39;t necessarily make it a better option than rolling one&#39;s own if using and updating said something entails more cost in the long run. Paved roads often get you there faster, but a willingness to get lost now and then is how you learn where all the really cool local bars are &#8230;</p>
<p><img alt=";)" src="http://blog.humaneguitarist.org/wp-content/plugins/fckeditor-for-wordpress-plugin/ckeditor/plugins/smiley/images/wink_smile.gif" title=";)" /></p>
<p>Anyway, here&#39;s what I&#39;m thinking. A small script would simply look at an XML setup file from which it would know which places to go grab metadata from, the type of feed, the last time the metadata was requested, and stuff like the <a href="http://www.oaforum.org/tutorial/english/page4.htm#section17">resumptionToken</a> if applicable. It would also store the appropriate XSL file to process the metadata with so that the metadata could be passed into <a href="http://lucene.apache.org/solr/#intro">Solr</a> to be indexed and searchable. Anyone who&#39;s site doesn&#39;t provide metadata as XML could simply create a web service that does so, e.g. a RESTful MySQL to XML thingamajig. The outputted XML just needs to have an XSL that will facilitate passing it to Solr for that data to be part of the shared metadata store. And since XSL is the <a href="http://en.wikipedia.org/wiki/Universal_translator#Star_Trek">universal translator</a> in this context, other metadata types such as RSS/ATOM feeds could be grabbed, too. All one needs to do is add to the XML config file so the script knows to retrieve metadata from that site and make sure there&#39;s an XSL file that can be used to facilitate passing the data into Solr. So in the end all this should take in terms of coding is a small script, one XML config file, and as many XSL files as needed.</p>
<p>For fun and to start learning about Solr, I just manually grabbed some <a href="http://oralhistories.library.caltech.edu/perl/oai2?verb=ListRecords&amp;set=7375626A656374733D737562:68756D&amp;metadataPrefix=oai_dc">OAI metadata from CalTech</a> yesterday &#8211; it was for some oral histories. And then I ran them through an XSL file and then posted them to Solr. Within no time I had a searchable, local metadata store to play around with (screenshot below). Since I was using all the defaults from the <a href="http://lucene.apache.org/solr/tutorial.html">Solr tutorial</a> I had to map the &lt;dc:creator&gt; field to things like manufacturer, since the default is set up for an electronics store.</p>
<p><a href="http://blog.humaneguitarist.org/uploads/solrUI_screenshot.png"><img alt="Solr screenshot" border="1" height="381" src="http://blog.humaneguitarist.org/uploads/solrUI_screenshot.png" width="640" /></a></p>
<p>BTW if we use this, at some point I won&#39;t be able to call it &quot;pOAIndexter&quot; but for now I can.</p>
<p>Since I don&#39;t know if I&#39;ll do this in Python or PHP and since OAI is what we&#39;ll work on first, I guess it stands for &quot;Python or PHP OAI Indexer&quot;.</p>
<p>Yes, I&#39;m a dork.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.humaneguitarist.org/2011/10/02/poaindexter-grabbing-and-indexing-online-metadata/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HammerFlix 3: Village of the DOMed</title>
		<link>http://blog.humaneguitarist.org/2011/09/25/hammerflix-3-village-of-the-domed/</link>
		<comments>http://blog.humaneguitarist.org/2011/09/25/hammerflix-3-village-of-the-domed/#comments</comments>
		<pubDate>Sun, 25 Sep 2011 15:00:13 +0000</pubDate>
		<dc:creator>nitin</dc:creator>
				<category><![CDATA[scripts]]></category>
		<category><![CDATA[Hammer Films]]></category>
		<category><![CDATA[HammerFlix]]></category>

		<guid isPermaLink="false">http://blog.humaneguitarist.org/?p=3291</guid>
		<description><![CDATA[Update, November 27, 2011: If you&#39;re looking for a live list of Hammer Films streaming on Netflix you can see it here. To read more about the HammerFlicks project, click here. &#8230; Grrr. Obsession is a good ally for creativity, but it&#39;s still annoying. I woke up today and decided to have a decent breakfast [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update, November 27, 2011:</strong> If you&#39;re looking for a live list of <a href="http://www.hammerfilms.com/">Hammer Films</a> streaming on Netflix you can see it <a href="http://blog.humaneguitarist.org/uploads/HammerFlicks/currentVersion/HammerFlicks.php">here</a>.</p>
<p>To read more about the HammerFlicks project, click <a href="http://blog.humaneguitarist.org/projects/hammerflicks/">here</a>.</p>
<p>&#8230;</p>
<p>Grrr. Obsession is a good ally for creativity, but it&#39;s still annoying.</p>
<p>I woke up today and decided to have a decent breakfast and do some <u>very</u> light work on <a href="http://blog.humaneguitarist.org/tag/hammerflix/">HammerFlix</a> &ndash; a small project to use the Netflix API to discover which Hammer Films movies are available on Netflix&#39;s Watch Instantly.</p>
<p>Basically, I just added some buttons/Javascript that will allow one to filter out the non-matches, show only Hammer films that HammerFlix thinks are on Netflix, or show only the ones that are apparently available for streaming.</p>
<p>Sure, there&#39;s still some work to be done to improve the reliability of the results as I mentioned <a href="http://blog.humaneguitarist.org/2011/09/24/in-the-can-another-hammerflix-update/">yesterday</a>, but I&#39;m not too worried about it for now.</p>
<p>If you&#39;re wondering why the search for &quot;The House Across the Lake&quot; from 1954 shows &quot;<a href="http://www.imdb.com/title/tt0047573/">Them!</a>&quot; as a streaming match it&#39;s because &quot;The House Across the Lake&quot; isn&#39;t on Netflix and &quot;Them!&quot; is the first match the API returns. In this case, both movies happen to share 1954 as the release year. Currently, if HammerFlix sees that the first API returned result matches the release year, it reports the movie as available on Netflix. So, I need to make it a little smarter than that, but not this weekend.</p>
<p>Anyway, you can see the latest results <a href="http://blog.humaneguitarist.org/uploads/HammerFlix/dev/0.03/HammerFlix.html">here</a>.</p>
<p>Dorks can view the source files in <a href="http://blog.humaneguitarist.org/uploads/HammerFlix/dev/0.03/">this</a> folder. The best thing in there is the MIT license generated by the <a href="http://www.bnj.com/spiteful-open-source-license-generator/">Spiteful Open Source License Generator</a>.</p>
<p><img alt=":P" src="http://blog.humaneguitarist.org/wp-content/plugins/fckeditor-for-wordpress-plugin/ckeditor/plugins/smiley/images/tounge_smile.gif" title=":P" /></p>
<p>No more coding this weekend &#8230; time for a long walk sans electronics.</p>
<p>&#8230;</p>
<p><strong>Update: </strong>OK, so I lied. I couldn&#39;t resist. I just added a score for how reliable the match is.</p>
<p>Go <a href="http://blog.humaneguitarist.org/uploads/HammerFlix/dev/0.03/HammerFlix.html">here</a> to see the HammerFlix results from about 10pm EST <strike>tonight.</strike> on September 26, 2011.</p>
<p>There&#39;s now a &quot;match score&quot; under each thing HammerFlix claims is on Netflix. This is done by comparing the title from the Wikipedia filmography against the &quot;short&quot; and &quot;regular&quot; titles from the Netflix API XML result (i.e. two scores). I used the PHP <a href="http://php.net/manual/en/function.similar-text.php">similar_text()</a> function to get the score for each and then averaged them for the &quot;match score&quot;.</p>
<p>There&#39;s occasionally a PHP &quot;undefined offset&quot; error for a couple of films. That&#39;s no big deal and I&#39;ll fix it later by just making sure I test for some stuff before printing to screen. But it seems to work pretty well. The &quot;The House Across the Lake&quot; &nbsp;vs. &quot;Them!&quot; mismatch only gets a 20% rating, so that tells me it might not actually be the same movie.</p>
<p>And as a reward, I&#39;m watching &quot;<a href="http://www.imdb.com/title/tt0075334/">To the Devil, a Daughter</a>&quot; now &#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.humaneguitarist.org/2011/09/25/hammerflix-3-village-of-the-domed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>in the can: another HammerFlix update</title>
		<link>http://blog.humaneguitarist.org/2011/09/24/in-the-can-another-hammerflix-update/</link>
		<comments>http://blog.humaneguitarist.org/2011/09/24/in-the-can-another-hammerflix-update/#comments</comments>
		<pubDate>Sat, 24 Sep 2011 19:24:04 +0000</pubDate>
		<dc:creator>nitin</dc:creator>
				<category><![CDATA[scripts]]></category>
		<category><![CDATA[HammerFlix]]></category>
		<category><![CDATA[Klingons]]></category>
		<category><![CDATA[Netflix]]></category>

		<guid isPermaLink="false">http://blog.humaneguitarist.org/?p=3272</guid>
		<description><![CDATA[Update, November 27, 2011: If you&#39;re looking for a live list of Hammer Films streaming on Netflix you can see it here. To read more about the HammerFlicks project, click here. &#8230; Last night while streaming Star Trek: TOS on NetFlix or Qwikster or whatever, I finished up this Python file around 3am that makes [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update, November 27, 2011:</strong> If you&#39;re looking for a live list of <a href="http://www.hammerfilms.com/">Hammer Films</a> streaming on Netflix you can see it <a href="http://blog.humaneguitarist.org/uploads/HammerFlicks/currentVersion/HammerFlicks.php">here</a>.</p>
<p>To read more about the HammerFlicks project, click <a href="http://blog.humaneguitarist.org/projects/hammerflicks/">here</a>.</p>
<p>&#8230;</p>
<p>Last night while streaming Star Trek: TOS on NetFlix or Qwikster or whatever, I finished up <a href="http://blog.humaneguitarist.org/uploads/HammerFlix/dev/0.02/HammerFlix_filmographyParser.pytxt">this</a> Python file around 3am that makes <a href="http://blog.humaneguitarist.org/uploads/HammerFlix/dev/0.02/HammerFlix_filmography.txt">this</a> semicolon delimited file of Hammer Films and their production year if you throw it at a local copy of <a href="http://en.wikipedia.org/wiki/Hammer_filmography">this</a> Wikipedia/Hammer Films filmography page.</p>
<p>Had enough of &quot;<a href="http://en.wikipedia.org/wiki/This">this</a>&quot;? Well, there&#39;s more where that, I mean this, came from.</p>
<p><img alt="" src="http://blog.humaneguitarist.org/wp-content/plugins/fckeditor-for-wordpress-plugin/ckeditor/plugins/smiley/images/embaressed_smile.gif" title="" /></p>
<p>So, I woke up at about 9am and worked on <a href="http://blog.humaneguitarist.org/uploads/HammerFlix/dev/0.02/HammerFlix.phptxt">this</a> PHP version on HammerFlix.</p>
<p>And finally, about 12 hours after going to bed, I&#39;ve got <a href="http://blog.humaneguitarist.org/uploads/HammerFlix/dev/0.02/HammerFlix.html">this</a> list of Hammer Films on Netflix and whether they stream or not.&nbsp; I should mention that I tested with both the &quot;UK&quot; and &quot;US&quot; versions of the titles if both were present in Wikipedia, so there are a few duplicate items in the list.</p>
<p>Eventually, I&#39;ll make the PHP file clickable so anyone can run it and get a current report. But as of right now, I&#39;ve used up all my Netflix API allowance for the day.</p>
<p>Now, as I mentioned in <a href="http://blog.humaneguitarist.org/2011/09/10/a-hammerflix-update/">this</a> post I was only testing to see if a movie title and its production year matched the Wikipedia filmography data in order to determine if the movie was available on Netflix and whether it streamed.</p>
<p>Testing that way isn&#39;t perfect. For example, the Wikipedia page lists 2011 as the year for &quot;<a href="http://www.imdb.com/title/tt1596365/">The Woman in Black</a>&quot; but IMDB and Netflix say it&#39;s 2012. So that movie isn&#39;t reported correctly by HammerFlix.</p>
<p>I&#39;m noticing a few other things, too, but I&#39;ll work on it later. Seriously, I need to get on with my weekend &#8230;</p>
<p>Maybe I&#39;ll watch a Hammer film tonight!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.humaneguitarist.org/2011/09/24/in-the-can-another-hammerflix-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>a HammerFlix update</title>
		<link>http://blog.humaneguitarist.org/2011/09/10/a-hammerflix-update/</link>
		<comments>http://blog.humaneguitarist.org/2011/09/10/a-hammerflix-update/#comments</comments>
		<pubDate>Sat, 10 Sep 2011 17:16:10 +0000</pubDate>
		<dc:creator>nitin</dc:creator>
				<category><![CDATA[scripts]]></category>
		<category><![CDATA[APIs]]></category>
		<category><![CDATA[HammerFlix]]></category>

		<guid isPermaLink="false">http://blog.humaneguitarist.org/?p=3121</guid>
		<description><![CDATA[Update, November 27, 2011: If you&#39;re looking for a live list of Hammer Films streaming on Netflix you can see it here. To read more about the HammerFlicks project, click here. &#8230; Principal photography has begun on HammerFlix &#8211; a small project to use the Netflix API to discover which Hammer Films movies are available [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update, November 27, 2011:</strong> If you&#39;re looking for a live list of <a href="http://www.hammerfilms.com/">Hammer Films</a> streaming on Netflix you can see it <a href="http://blog.humaneguitarist.org/uploads/HammerFlicks/currentVersion/HammerFlicks.php">here</a>.</p>
<p>To read more about the HammerFlicks project, click <a href="http://blog.humaneguitarist.org/projects/hammerflicks/">here</a>.</p>
<p>&#8230;</p>
<p>Principal photography has begun on <a href="http://blog.humaneguitarist.org/tag/hammerflix/">HammerFlix</a> &#8211; a small project to use the Netflix API to discover which Hammer Films movies are available on Netflix&#39;s Watch Instantly.</p>
<p>So far, I&#39;ve got a PHP file that has two functions.</p>
<p>The first one, named Igor, takes two arguments: a movie title and its release year. Igor then sends this to the Netflix API and retrieves only the first result for searching against that given title. Then Igor sends the XML version of the API results to another function, Master.</p>
<p>Master, aka Dr. Frankenstein, then evaluates the result. If the Netflix release date for the movie returned by the API matches the year value sent to Igor, then Master will display the link to that movie on Netflix. If the movie is available via Watch Instantly, Master will also display the link to the streaming movie. If the year doesn&#39;t match, Master reports that no results were found.</p>
<p>Testing against just the first match and using release year as the only qualifier might not be the best, but I think it might work pretty decently. If not, I&#39;ll have Igor retrieve more results and then Master can evaluate more results and use more test criteria before assuming the movie isn&#39;t on Netflix.</p>
<p>The next step is to get all the Hammer titles from the <a href="http://en.wikipedia.org/wiki/List_of_Hammer_films">Hammer Filmography</a> on Wikipedia and send each title and release year to HammerFlix. There might be some open/linked data opportunities later down the road with <a href="http://dbpedia.org">dbPedia</a>, but that&#39;s not important for now.</p>
<p>You can see this very basic test of HammerFlix 0.01 <a href="http://blog.humaneguitarist.org/uploads/HammerFlix/dev/0.01/hammerflix-0.01.php">here</a>.</p>
<p>Anyway, here&#39;s the code for the development version of 0.01.</p>
<pre class="brush:php">&lt;?php

//Igor does the hard work of hitting up the Netflix API for movies matching $title.
//The code is mainly from: http://developer.netflix.com/page/resources/sample_php
function Igor($title, $year) {

    include (&#39;../authentication/myAPI.php&#39;); //this includes my Netflix API key and shared secret as $apiKey and $sharedSecret.

    //build stuff to send to API.
    $arguments = Array(
        &#39;term&#39; =&gt; $title,
        &#39;expand&#39; =&gt; &#39;formats&#39;,
        &#39;max_results&#39; =&gt; &#39;1&#39;,
        &#39;output&#39; =&gt; &#39;xml&#39;
    );

    $path = &quot;http://api.netflix.com/catalog/titles&quot;;
    $oauth = new OAuthSimple();
    $signed = $oauth-&gt;sign(Array(&#39;path&#39; =&gt; $path,
                &#39;parameters&#39; =&gt; $arguments,
                &#39;signatures&#39; =&gt; Array(&#39;consumer_key&#39; =&gt; $apiKey,
                    &#39;shared_secret&#39; =&gt; $sharedSecret
                    )));

    //hit up API via CURL.
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $signed[&#39;signed_url&#39;]);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    //curl_setopt($curl, CURLOPT_SETTIMEOUT, 2); //Nitin commented this out on 2/5/2011 to prevent a PHP error message.
    $buffer = curl_exec($curl);
    if (curl_errno($curl)) {
        die(&quot;An error occurred:&quot; . curl_error());
    }

    Master($buffer, $title, $year); //send XML results to Master().
}

//Master (Dr. Frankenstein) parses/returns the Netflix XML results retrieved by Igor.
function Master($buffer, $title, $year) {

    $xml = simplexml_load_string($buffer);
    $movieInfo = ($xml-&gt;catalog_title);
    $short = &quot;short&quot;;
    $movieTitle_short = ($movieInfo-&gt;title-&gt;attributes()-&gt;$short);
    $regular = &quot;regular&quot;;
    $movieTitle_regular = ($movieInfo-&gt;title-&gt;attributes()-&gt;$regular);
    $movieLink = ($movieInfo-&gt;id);
    $movieId = str_replace(&quot;http://api.netflix.com/catalog/titles/movies/&quot;, &quot;&quot;, $movieLink);
    $movieYear = ($movieInfo-&gt;release_year);

    //test if movie is available for Watch Instantly/streaming.
    $streaming = $xml-&gt;xpath(&#39;//availability/category/@label&#39;);
    foreach ($streaming as $instantTest) {
        if ($instantTest == &#39;instant&#39;) {
            $streams = &#39;&#39;;
        }
    }

    //output findings.
    echo &quot;&lt;li&gt;&lt;p&gt;Testing:&lt;em&gt; &quot; . $title . &quot; &lt;/em&gt;from the year:&lt;em&gt; &quot; . $year . &quot;&lt;/em&gt;&lt;br /&gt;&quot;;
    if ($movieYear == $year) {
        echo &quot;&lt;a href=&#39;http://movies.netflix.com/WiMovie/&quot; . $movieId . &quot;&#39;&gt;&quot; . $movieTitle_short . &quot;&lt;/a&gt;&quot;;

        //IT&#39;S ALIVE!!!
        //aka: show user the Watch Instantly link if it exists.
        if (isset($streams)) {
            echo &quot;&lt;br /&gt;&lt;strong&gt;&lt;a href=&#39;http://movies.netflix.com/WiPlayer?movieid=&quot; . $movieId . &quot;&#39;&gt;Watch Instantly&lt;/a&gt;&lt;/strong&gt;&quot;;
        }
    } else {
        echo &quot;No match.&quot;;
    }
    echo &quot;&lt;/p&gt;&lt;/li&gt;&quot;;
}

//Create life!
//aka: start doing things.
include (&#39;../authentication/OAuthSimple.php&#39;);

echo &quot;&lt;ul&gt;&quot;; //put results in unordered list; send arguments to Igor().
Igor(&quot;The Brides of Dracula&quot;, &quot;1960&quot;);
Igor(&quot;The Brides of Dracula&quot;, &quot;1961&quot;);
Igor(&quot;Dracula Has Risen from the Grave&quot;, &quot;1968&quot;);
Igor(&quot;Vampire Circus&quot;, &quot;1972&quot;);
echo &quot;&lt;/ul&gt;&quot;;
?&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.humaneguitarist.org/2011/09/10/a-hammerflix-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SAVS: a Simple Audio/Video Synchronizer</title>
		<link>http://blog.humaneguitarist.org/2011/09/05/savs-a-simple-audiovideo-synchronizer/</link>
		<comments>http://blog.humaneguitarist.org/2011/09/05/savs-a-simple-audiovideo-synchronizer/#comments</comments>
		<pubDate>Mon, 05 Sep 2011 13:39:59 +0000</pubDate>
		<dc:creator>nitin</dc:creator>
				<category><![CDATA[digital audio]]></category>
		<category><![CDATA[scripts]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[SAVS]]></category>
		<category><![CDATA[streaming media]]></category>
		<category><![CDATA[timed text]]></category>

		<guid isPermaLink="false">http://blog.humaneguitarist.org/?p=3089</guid>
		<description><![CDATA[About a year ago I did some text to audio synchronization tests with HTML5 and Flash. The tests were partially successful, but I think what really mattered is that I set four goals that I felt needed to be met before the word &#34;synchronization&#34; could truly be used: The user should be able to click [...]]]></description>
			<content:encoded><![CDATA[<p>About a year ago I did some text to audio <a href="http://blog.humaneguitarist.org/uploads/SAVS/AVsink/">synchronization tests</a> with HTML5 and Flash.</p>
<p>The tests were partially successful, but I think what really mattered is that I set four goals that I felt needed to be met before the word &quot;synchronization&quot; could truly be used:</p>
<ol>
<li>The user should be able to click on a line of text and hear the related media.</li>
<li>The user should be able to &quot;scrub&quot; ahead on the media player and the text should follow.</li>
<li>The page should report where in the document the user is.</li>
<li>The page should automatically keep the media/text synchronized without user intervention.</li>
</ol>
<p>Basically, I&#39;ve seen a few people make it so that you could watch media while the transcript text was also on the page (scrollable as opposed to overlaid closed captions) and the user could click on a line and have the movie/audio skip ahead to that moment (goal #1). That&#39;s great and all, but that&#39;s not synchronization.</p>
<p><img alt=";)" src="http://blog.humaneguitarist.org/wp-content/plugins/fckeditor-for-wordpress-plugin/ckeditor/plugins/smiley/images/wink_smile.gif" title=";)" /></p>
<p>Synchronization is a two way street and I&#39;ve been working this past week during what I&#39;m calling &quot;4 days of madness&quot; to come up with a really simple solution to real synchronization. I did run across this really cool <a href="http://hyper-audio.org/r/">RadioLab page</a> that achieves goal #1, but as much as I like it I want more features with less flash (as in &quot;flash and dash&quot; not Adobe Flash!) and less code. No mistake: it looks fantastic and I also appreciate that they&#39;ve got the text timed to clusters of a couple of words rather than by line but the only thing I&#39;ve seen that gets it all &quot;right&quot; per my perspective was a subscription resource by <a href="http://alexanderstreet.com/">Alexander St. Press</a>. It achieved all the goals above using a Flash player and the rest appeared to by done with Javascript and some jQuery smooth scrolling. It was also timed by clusters of words and not just by line or by paragraph. Of course, conceptually it&#39;s the same whether one marks up their text &#8211; in the temporal sense &#8211; by line or by word, but it&#39;s a little more work to do it by word of course. Unfortunately, I&#39;ve seen people do the opposite: they use a static unit of time like 60 seconds and only mark up the text every minute. That&#39;s taking the easy way out and also misses the point entirely since it makes the text subservient to an arbitrary unit of time. Would it be acceptable if closed captioning and subtitles on your foreign films only showed up in large chunks every minute? I would hope not, and in the case of the former it would violate the the spirit if not the letter of the &quot;law&quot; in regard to accessibility. If done right, you can use the same timed text file to both serve up captions in addition to showing the full text on the page. It&#39;s more time and cost efficient to re-purpose the same data for two needs.</p>
<p>Anyway, let&#39;s get back to Alexander St. Press. I loved what I saw when my boss (I work at <a href="http://nclive.org/">NC Live</a>) showed it to me. I got really excited and said something like, &quot;This is what I&#39;ve been waiting to see!&quot;. In addition to the great and true syncing, they also had a feature that would let the user make and share clips, much the way you can on sites like NBC&#39;s <a href="http://www.msnbc.msn.com/id/3032608/">Meet The Press</a>. The Alexander St. Press site also allowed you to annotate that clip, which is a great feature for teachers and librarians, etc. Alexander St. Press also has this with their classical music streaming subscription service, which in the spirit of full disclosure I pay for. They ALSO had a cool timeline where you could see what I call &quot;hot spots&quot; &#8211; places where others had made clips. The idea, I guess, is that spots on the timeline with more clusters would indicate a particular point of interest. Nothing new, because you see that all the time with streaming sports like the <a href="http://www.usopen.org/en_US/index.html">US Open&#39;s site</a> where you can go back and watch previous moments in matches and then &quot;go live&quot; at any time. But the difference is, of course, that&nbsp;Alexander St. Press was using user-contributed clips.</p>
<p>So long story short (or just not as long), in a few weeks I need to present these ideas to some people and talk about how we think these features could be useful for our users. And the more I struggled with how to talk about these concepts without a prototype the more I thought I would a) sound like I&#39;m crazy and b) like I&#39;m full of hot air.</p>
<p>	I decided that it was time to go back to some earlier tests of mine from early April and just build a prototype so we could just show it to people and not have to talk theoretical speak. I think it&#39;s generally easier to explain and convince people of the utility of software by showing it rather than telling it. Actions &gt; words, right?</p>
<p>
	Well, early tests are working and only required me to add one line of Actionscript to our current Flash player and about only 50 lines of Javascript code are needed to keep the text and media synced. The tests I did were for some PBS videos we purchased along with closed captioning files.</p>
<p>	I was so excited that it was finally working that I went home during those &quot;4 days of madness&quot; to write an HTML5 version which is virtually identical to the Flash version. It&#39;s got basic clip making features as well as a very basic tool inspired by this <a href="http://blog.humaneguitarist.org/2011/01/09/videoscores-from-the-musescore-gang/">video score</a> tutorial to make timed text files provided you have the audio and full text in hand. Eventually, I&#39;ll comment the code up and improve some options and post a download to the source for the HTML5 version. At work, we&#39;ll probably eventually offer the code as it&#39;s tweaked to meet our aesthetic needs, etc. As you&#39;ll see in the demo video below, I have no aesthetics!</p>
<p>	I&#39;ll shut up now and leave you to the video if you&#39;re interested. I recommend watching it in HD so you can read the words on the page.</p>
<p>As my friend whom the HTML5 version is kinda named after likes to say:</p>
<p>More later &#8230;</p>
<p><iframe frameborder="0" height="225" src="http://player.vimeo.com/video/28582024?byline=0&amp;portrait=0" width="400"></iframe></p>
<p><a href="http://vimeo.com/28582024">SAVS: a Simple Audio/Verse Synchronizer</a> from <a href="http://vimeo.com/user3665532">nitin arora</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
<p>&#8230;</p>
<p><strong>Update, September 20, 2011:</strong> To avoid confusion as to what this does, I&#39;m renaming this from &quot;Simple Audio/Video Synchronizer&quot; to &quot;Simple Audio/Verse Synchronizer&quot; or something &#8230;</p>
<p><img alt=":)" src="http://blog.humaneguitarist.org/wp-content/plugins/fckeditor-for-wordpress-plugin/ckeditor/plugins/smiley/images/regular_smile.gif" title=":)" /></p>
<p><strong>Update, October 16, 2011:</strong> Cool, I found one more thing that meets all the four goals at <a href="http://www.dinglabs.com">http://www.dinglabs.com</a>. They&#39;re pitching it as a foreign language learning tool, but same difference. Also, that site led me to <a href="http://transag.sourceforge.net/">TranscriberAG</a>, a tool for transcribing audio.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.humaneguitarist.org/2011/09/05/savs-a-simple-audiovideo-synchronizer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>making a DOT graph for PHP include statements</title>
		<link>http://blog.humaneguitarist.org/2011/07/30/making-a-dot-graph-for-php-include-statements/</link>
		<comments>http://blog.humaneguitarist.org/2011/07/30/making-a-dot-graph-for-php-include-statements/#comments</comments>
		<pubDate>Sat, 30 Jul 2011 17:03:02 +0000</pubDate>
		<dc:creator>nitin</dc:creator>
				<category><![CDATA[scripts]]></category>
		<category><![CDATA[technophilia]]></category>
		<category><![CDATA[DOT]]></category>
		<category><![CDATA[Graphviz]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[sinuses]]></category>
		<category><![CDATA[visualization]]></category>

		<guid isPermaLink="false">http://blog.humaneguitarist.org/?p=2960</guid>
		<description><![CDATA[A couple of months ago, I posted about my experience with making a Python dependency graph. Of course, as the post states, I was originally looking for a way to make a graph showing the relationship among PHP files in regard to include statements. Well, I&#39;m home sick and after a few hours of trying [...]]]></description>
			<content:encoded><![CDATA[<p>A couple of months ago, I <a href="http://blog.humaneguitarist.org/2011/05/07/making-my-first-dependency-graph/">posted</a> about my experience with making a Python dependency graph.</p>
<p>Of course, as the post states, I was originally looking for a way to make a graph showing the relationship among PHP files in regard to <code>include</code> statements.</p>
<p>Well, I&#39;m home sick and after a few hours of trying to find an easy, out-of-box solution I gave up and rolled my own Python script to make me a <a href="http://en.wikipedia.org/wiki/DOT_language">DOT</a> graph file.</p>
<p>I didn&#39;t have anything better to do.</p>
<p><img alt=":(" src="http://blog.humaneguitarist.org/wp-content/plugins/fckeditor-for-wordpress-plugin/ckeditor/plugins/smiley/images/sad_smile.gif" title=":(" /></p>
<p>The results are pretty simplistic, but I&#39;m happy enough with it for now.</p>
<p>The Python script takes three arguments: the directory in which the PHP files exist, whether to search recursively or not (0=no, 1=yes), and the name of the output file as such:</p>
<p><code>$ python makeDOT.py blog/wordpress 1 wordpressIncludes.dot<br />
	</code></p>
<pre class="brush:python">#####
#importing modules
import glob, re, sys, os, fnmatch
br = &quot;\n&quot;
tab = &quot;\t&quot;

#####
#exiting if all 3 arguments are not passed via command line
def fail():
    print (&quot;ERROR: &quot; + str(len(sys.argv)-1) + &quot; of 3 required arguments provided.&quot;)
    sys.exit()

#####
#getting arguments passed via command line

#testing for root DIRECTORY string
try: myDir = sys.argv[1]
except: fail()

#testing for RECURSION boolean
try: myRec = sys.argv[2]
except: fail()

#testing for OUTPUT filename string
try: myFile = sys.argv[3]
except: fail()

#####
#making list of PHP files within DIRECTORY
if myRec == &quot;0&quot;: #without recursion
    myDir2 = myDir + &quot;/*.php&quot;
    PHP_list = glob.glob(myDir2)
elif myRec == &quot;1&quot;: #with recursion
    PHP_list = []
    for dirname, dirnames, filenames in os.walk(myDir):
        for filename in filenames:
            if fnmatch.fnmatch (filename,(&quot;*.php&quot;)):
                match = os.path.join(dirname,filename)
                PHP_list.append(match)

#make an empty list;
#tuples will go in the list;
#each tuple will contain a PHP filename and a PHP filename it includes
includeList = []

#iterate through each PHP file and place tuples in the list
for phpFile in PHP_list:
    fileOpen = open(phpFile, &quot;r&quot;)
    #for each line in a PHP file
    for line in fileOpen:
            m = re.match(r&quot;(.*)include(.*\()(.*)\)&quot;, line) #for include(),include_once()
            if m:
                matchFile = m.group(3)[1:-1]
                if matchFile[-4::] == &quot;.php&quot;: #only PHP files
                    phpFile = phpFile.replace(&quot;\\&quot;,&quot;/&quot;)
                    matchFile = matchFile.replace(&quot;\\&quot;,&quot;/&quot;)
                    matchFile = matchFile.replace(&quot;\&quot;&quot;,&quot;&quot;)
                    matchFile = matchFile.replace(&#39;\&#39;&#39;,&quot;&quot;)
                    includeList.append([phpFile[len(myDir)+1:], matchFile])
            else: pass

            m = re.match(r&#39;(.*)require(.*\()(.*)\)&#39;, line) #for require(), require_once()
            if m:
                matchFile = m.group(3)[1:-1]
                if matchFile[-4::] == &#39;.php&#39;: #only PHP files
                    phpFile = phpFile.replace(&quot;\\&quot;,&quot;/&quot;)
                    matchFile = matchFile.replace(&quot;\\&quot;,&quot;/&quot;)
                    matchFile = matchFile.replace(&quot;\&quot;&quot;,&quot;&quot;)
                    matchFile = matchFile.replace(&#39;\&#39;&#39;,&quot;&quot;)
                    includeList.append([phpFile[len(myDir)+1:], matchFile])
            else: pass

#####
#creating DOT file
dot = open(myFile, &quot;w&quot;)

#writing to DOT file
dot.write(&quot;digraph {&quot; + br)
for a,b in includeList:
    dot.write(tab)
    dot.write(&quot;\&quot;&quot;)
    dot.write(a)
    dot.write(&quot;\&quot;&quot;)
    dot.write(&quot; -&gt; &quot;)
    dot.write(&quot;\&quot;&quot;)
    dot.write(b)
    dot.write(&quot;\&quot;&quot;)
    dot.write(&quot;;&quot;)
    dot.write(br)
dot.write(&quot;}&quot;)
dot.close()

#####
#exiting
sys.exit()
</pre>
<p>I ran the Python script on the PHP scripts for <a href="http://blog.humaneguitarist.org/projects/mxmliszt/">MXMLiszt</a>.</p>
<p>Then I used the &quot;circo&quot; layout engine in <a href="http://en.wikipedia.org/wiki/Graphviz">Graphviz</a> &#8211; specifically the Gvedit.exe application &#8211; on <a href="http://blog.humaneguitarist.org/uploads/MXMLisztIncludeGraph.dot.txt">this</a> resultant DOT file.</p>
<p>Here&#39;s the result:</p>
<p><a href="http://blog.humaneguitarist.org/uploads/MXMLisztIncludeGraph.gif"><img alt="" height="303" src="http://blog.humaneguitarist.org/uploads/MXMLisztIncludeGraph.gif" width="320" /></a><a href="http://blog.humaneguitarist.org/uploads/MXMLisztIncludeGraph.gif"><br />
	</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.humaneguitarist.org/2011/07/30/making-a-dot-graph-for-php-include-statements/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AudioRegent 1.3.1 released</title>
		<link>http://blog.humaneguitarist.org/2011/07/28/audioregent-1-3-1-released/</link>
		<comments>http://blog.humaneguitarist.org/2011/07/28/audioregent-1-3-1-released/#comments</comments>
		<pubDate>Thu, 28 Jul 2011 22:31:52 +0000</pubDate>
		<dc:creator>nitin</dc:creator>
				<category><![CDATA[digital audio]]></category>
		<category><![CDATA[scripts]]></category>
		<category><![CDATA[apathy]]></category>
		<category><![CDATA[AudioRegent]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.humaneguitarist.org/?p=2954</guid>
		<description><![CDATA[I&#39;ve updated AudioRegent to version 1.3.1. You can read an overview of the software and get the download link to the new version here. The only reason I updated the software is because, as I&#39;ve mentioned before, I&#39;ve been having problems with Windows (and only recently at that) in terms of calling executables from the [...]]]></description>
			<content:encoded><![CDATA[<p>I&#39;ve updated AudioRegent to version 1.3.1.</p>
<p>You can read an overview of the software and get the download link to the new version <a href="http://blog.humaneguitarist.org/projects/audioregent/">here</a>.</p>
<p>The only reason I updated the software is because, as I&#39;ve mentioned <a href="http://blog.humaneguitarist.org/2011/04/26/dot-dot-slash-slash/">before</a>, I&#39;ve been having problems with Windows (and only recently at that) in terms of calling executables from the command line.</p>
<p>What seems to have helped is to no longer pass a command as a string a la:</p>
<pre class="brush:python">RunSoxString = SoxPath + &quot; ./outWavs/&quot; + OggArray[cnt] + ws + &quot;--comment-file comment.txt ./outOggs/&quot; + str(OggArray[cnt])[:-4] + &quot;.&quot; + outputType + ws + SoxOptions
RunSox = subprocess.Popen([RunSoxString], shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
RunSox.wait() #wait until the subprocess finishes
</pre>
<p>Now, it seems I have to pass it as a Python list (aka an array):</p>
<pre class="brush:python">RunSoxString = SoxPath + &quot; ./outWavs/&quot; + OggArray[cnt] + ws + &quot;--comment-file comment.txt ./outOggs/&quot; + str(OggArray[cnt])[:-4] + &quot;.&quot; + outputType + ws + SoxOptions
import shlex
RunSoxList = shlex.split(RunSoxString)
RunSox = subprocess.Popen(RunSoxList, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
RunSox.wait() #wait until the subprocess finishes
</pre>
<p>By the way, I totally haven&#39;t tested this new version enough to distribute it and I haven&#39;t tested it at all on a Linux box. But since no one&#39;s using it, I&#39;m not too worried.</p>
<p><img alt="" src="http://blog.humaneguitarist.org/wp-content/plugins/fckeditor-for-wordpress-plugin/ckeditor/plugins/smiley/images/devil_smile.gif" title="" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.humaneguitarist.org/2011/07/28/audioregent-1-3-1-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MXMLiszt version 0.9.2 released</title>
		<link>http://blog.humaneguitarist.org/2011/07/23/mxmliszt-version-0-9-2-released/</link>
		<comments>http://blog.humaneguitarist.org/2011/07/23/mxmliszt-version-0-9-2-released/#comments</comments>
		<pubDate>Sat, 23 Jul 2011 14:29:18 +0000</pubDate>
		<dc:creator>nitin</dc:creator>
				<category><![CDATA[music notation]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[scripts]]></category>
		<category><![CDATA[MusicXML]]></category>
		<category><![CDATA[MXMLiszt]]></category>

		<guid isPermaLink="false">http://blog.humaneguitarist.org/?p=2922</guid>
		<description><![CDATA[If anyone&#39;s interested, MXMLiszt version 0.9.2 is now available for download. MXMLiszt is a web-based delivery and search/retrieval environment for MusicXML files and their manifestations. The documentation and source-code download links are available here. Here&#39;s the changelog: 0.9.2 - included Bach and Schubert MusicXML files from MusicSQL project (http://musicsql.googlecode.com/). - For the Bach, cleaned up [...]]]></description>
			<content:encoded><![CDATA[<p>If anyone&#39;s interested, MXMLiszt version 0.9.2 is now available for download.</p>
<p><font size="2">MXMLiszt is a web-based delivery and search/retrieval environment for </font><a href="http://www.recordare.com/musicxml"><font size="2">MusicXML</font></a><font size="2"> files and their manifestations. </font></p>
<p>The documentation and source-code download links are available <a href="http://blog.humaneguitarist.org/projects/mxmliszt/">here</a>.</p>
<p>Here&#39;s the changelog:</p>
<pre class="brush:text">0.9.2
- included Bach and Schubert MusicXML files from MusicSQL project (http://musicsql.googlecode.com/).
    - For the Bach, cleaned up diacritics (in titles only) and changed &quot;Soprano&quot;, etc. to &quot;Soprano&quot;, etc.
        - diacritics are still messed up in lyrics. I&#39;m too lazy to fix them. :]
    - For the Schubert, changed &quot;Part_1&quot; through &quot;Part_4&quot; to &quot;Violin 1&quot;, &quot;Violin 2&quot;, &quot;Viola&quot;, and &quot;Cello&quot;.
    - original files available here:

http://musicsql.googlecode.com/files/Bach_SATB-1.0.zip

http://musicsql.googlecode.com/files/Schubert_quartets-1.0.zip

- adjusted &lt;hr&gt; rules in style.css to accomodate Internet Explorer 9
    - Removed &quot;optimized for Firefox&quot; in welcome.php since MXMLiszt now works well in IE, Firefox, Chrome, Safari, and Opera (see below).
- fixed generateIndex.php so the &lt;img&gt; tag now closes in this line:
        echo nl2br(&#39;&lt;img src=&quot;png/&#39; . $filenamePlain . &#39;.pre.png&quot; /&gt;&#39;); //line #12
    - This was the only reason the Index view wasn&#39;t working in Opera.
        - Opera was the only browser that caught this error. :]
- made &quot;Results&quot; header for search results an &lt;h2&gt;, just as with the MIR results header.
- added two modules: startWatch.php and stopWatch.php to reduce coding redundancy in regard to reporting the time it takes for actions to finish.
- changed mxml2mods.xsl to output the MODS namespace.
    - adjusted mods.xsl, loadMODSasDC.php, and XQuery syntax as needed.
    - Sample XQueries using a namespace prefix:

        This is a Faust query example:
                    declare namespace mods = &quot;http://www.loc.gov/mods/v3&quot;;
                    for $x in doc(&quot;../concat/concatMODS.xml&quot;)/hyperMODS/hypoMODS/mods:mods
                    let $x1 := $x//mods:subTitle
                    return $x1

        This is a Dante example:
                    declare namespace mods = &quot;http://www.loc.gov/mods/v3&quot;;
                    for $x in doc(&quot;../concat/concatMODS.xml&quot;)/hyperMODS/hypoMODS
                    let $x1 := $x/mods:mods
                    where $x1//mods:subTitle contains text &quot;You&quot;
                    return data($x/@file)

- simplified some of the built in MODS related XQueries (same functionality, just less wordy).
- changed order of MODS search drop down terms on Search page.
- changed &lt;i&gt; and &lt;b&gt; to &lt;em&gt; and &lt;strong&gt;, respectively.
- replaced &quot;pop1&quot;, etc. with better-named CSS variables like stickyNote and IndexPopup, etc. in style.css.
- added a streamed comment in each module with a one or two sentence description of what it does.
- added .htaccess file.
    - to hide root folder.
    - to make the &quot;/~foo.xml&quot; forward (with masking) to:&quot;transmuteMXML.php$fname=musicXML/foo.xml&quot;.
        - adjusted mxml2mods.xsl accordingly.
    - to hide directory icons.
    - to use fancy indexing.
- changed displayMODS.php to display MODS files via an &lt;iframe&gt; only as a fallback if PHP XSL processing not available on server.
_______________________________________________________________________
0.9.1
- created mods.css file to display MODS on a transparent background.
- changed displayMODS.php to display MODS files via an &lt;iframe&gt;.
    - The previous version was using the mods.xsl stylesheet to parse the MODS element values in real-time.
_______________________________________________________________________
0.9.0
- this was the first version - that worked!
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.humaneguitarist.org/2011/07/23/mxmliszt-version-0-9-2-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

