<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:wfw="http://wellformedweb.org/CommentAPI/"
     >
  <channel>
    <title>EnigmaCurry</title>
    <link>http://www.enigmacurry.com/</link>
    <description>The Curry Enigma</description>
    <pubDate>Thu, 07 Feb 2013 01:43:41 GMT</pubDate>
    <generator>Blogofile</generator>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Searching GameFAQs within Steam games</title>
      <link>http://www.enigmacurry.com/2010/09/22/searching-gamefaqs-within-steam-games</link>
      <pubDate>Wed, 22 Sep 2010 20:30:00 EDT</pubDate>
      <category><![CDATA[python]]></category>
      <category><![CDATA[games]]></category>
      <guid>l7Yc2FQrBl4u4SIraAfpZSBtXAM=</guid>
      <description>Searching GameFAQs within Steam games</description>
      <content:encoded><![CDATA[<p>To take the edge off work, I've been playing Fallout 3 this week. Let me just say this: post apocalyptic Washington DC is huge! Thankfully, there's <a href="http://www.gamefaqs.com">GameFAQs</a>, because I don't have 40 hours a week to devote to playing games the hard way. </p>
<p>The problem is, 3D games are notoriously bad at recovering after you Alt-Tab out of the game to use your web browser. Luckily, <a href="http://store.steampowered.com/about/">Steam</a> has a built in web browser, so that you don't need to leave the game in order to check GameFAQs, which is great... <strong>except for the fact that the Steam browser is totally lame</strong>.</p>
<p>See, GameFAQs are plain text files. I think that's cool; plain text is an <a href="http://www.textfiles.com/">age old geek tradition</a>, plus it's the ultimate portable file format. However, that also makes things difficult when you're talking about a guide that is over 1MB and broken into hundreds of sections with no hyperlinks to help navigate. GameFAQ authors are a smart bunch though, they have the habit of creating unique codes for each section, essentially creating ad-hoc hyperlinks. You just use your browser's search feature to search for the code and you go right to the section you want.</p>
<p>And what browser doesn't have a search feature?</p>
<p>Oh... right, the Steam browser.</p>
<p>Seriously?</p>
<p><em>Seriously!?</em></p>
<p>Alright fine, I'm a <a href="http://catb.org/~esr/faqs/hacker-howto.html">hacker</a>, I can get around this. My solution was to write a GameFAQs proxy that downloads FAQs and injects them into a page that uses the <a href="http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html">jQuery highlight plugin</a>. Slapping on a header to every page for easy navigation, gives us our very own search-in-the-browser add-on for the feature-gimped Steam browser.</p>
<p>Download a <a href="http://static.enigmacurry.com/apps/steam_gamefaqs/steam_gamefaqs_1.0.exe">standalone executable</a> and try it yourself. Yea, I probably could have made a public server, but I didn't want to get into a copyright hassle, so for now you'll just need to run it yourself on your own computer. I've tried to make it as easy as possible. If you're a Python geek and want to check out the source (or just paranoid about running a pre-compiled exe), <a href="http://github.com/EnigmaCurry/Steam-GameFAQs">it's over on github</a>. If you're interested in how I compiled the Pylons application into a standalone executable with <a href="http://pypi.python.org/pypi/bbfreeze/">bbfreeze</a>, checkout <a href="http://github.com/EnigmaCurry/Steam-GameFAQs/blob/master/make.py">make.py</a> (although it's pretty cludgy).</p>
<p>One more thing, this proxy is essentially scraping the GameFAQs.com website, so it's possible things could break if they change their site too much. Let me know in the comments if this thing doesn't work anymore.</p>
<p>Instructions for the standalone executable:</p>
<ul>
<li><a href="http://static.enigmacurry.com/apps/steam_gamefaqs/steam_gamefaqs_1.0.exe">Download the exe</a> (Tested on Windows 7, 32 &amp; 64 bit)</li>
<li>Run the application. It's a self extracting archive, extract it wherever you want. The desktop is fine (it's just one .bat file and a directory.)</li>
<li>Run start_steam_gamefaqs.bat and wait for the window to pop up.</li>
<li>Leaving that window open, start your steam game.</li>
<li>In the game, press Shift-Tab to bring up the Steam community page.</li>
<li>Click on the web browser.</li>
<li>Enter the URL : http://localhost:5000</li>
<li>Search for your desired game and FAQ.</li>
<li>Search the page by pressing Ctrl-F and typing in the "Search This Page" box. Pressing Enter multiple times in that box will find the next match for that search term.</li>
</ul>
<p><center><a href="/blog-post-images/steam_gamefaqs_fallout3.png"><img src="/blog-post-images/steam_gamefaqs_fallout3_small.jpg"></a></center></p>]]></content:encoded>
    </item>
    <item>
      <title>Audacious Dynamic Playlist powered by inotify</title>
      <link>http://www.enigmacurry.com/2010/07/13/audacious-dynamic-playlist-powered-by-inotify</link>
      <pubDate>Tue, 13 Jul 2010 00:22:00 EDT</pubDate>
      <category><![CDATA[python]]></category>
      <category><![CDATA[linux]]></category>
      <guid>FYrZgxyDsO6L0_qvkaQplbmCPAE=</guid>
      <description>Audacious Dynamic Playlist powered by inotify</description>
      <content:encoded><![CDATA[<p>I was playing around with <a href="http://streamripper.sourceforge.net/">StreamRipper</a> today to record a shoutcast stream I enjoy, and I thought to myself: wouldn't it be nice to be able to continuously play all the files I've downloaded without having to manually queue the new files in <a href="http://audacious-media-player.org/">Audacious</a>?</p>
<p>So, I scratched an itch. With a little DBUS, pyinotify, and an optparse wrapper, I now have a tool to automatically add the tracks to my Audacious playlist. You can grab the <a href="http://github.com/EnigmaCurry/audacious-plugins">latest version on github</a>.</p>
<p>Streamripper does have a relay option (-r) to allow you to listen to the same stream as you're ripping it, and if that's what you want, the following script is superfluous. However, what I wanted was something slightly different: I didn't necessarily want to just listen to the stream live, instead, I wanted the ability to jump around between the tracks already downloaded, exploring different songs, but with the list of tracks ever expanding. That's what this script allows.</p>
<p>You'll need python-dbus and setuptools installed, then just install with:</p>
<div class="pygments_murphy"><pre>easy_install http://github.com/EnigmaCurry/audacious-plugins/zipball/master
</pre></div>

<p>Startup <a href="http://streamripper.sourceforge.net/">StreamRipper</a> with your favorite audio stream and point the tool at your target directory:</p>
<div class="pygments_murphy"><pre>python -m ec_audacious.dynamic_filesystem_playlist /path/to/your/streamripper_location
</pre></div>

<p>Now when StreamRipper creates a new file, it will get automatically (instantaeneously actually, thanks to inotify!) to your Audacious playlist.</p>
<p>Alternatively, you can use the streamripper wrapper script that I've included to start both the filesystem monitor as well as streamripper in one go:</p>
<p>Put the following in your .bashrc file or somewhere equivalent:</p>
<div class="pygments_murphy"><pre><span class="nb">alias </span><span class="nv">streamripper</span><span class="o">=</span><span class="s2">&quot;python -m ec_audacious.streamripper&quot;</span>
</pre></div>

<p>Then whenever you run streamripper, you'll actually be running the wrapper script instead:</p>
<div class="pygments_murphy"><pre>streamripper http://your-cool-stream.com:8000 --audacious
</pre></div>

<p>By aliasing streamripper to point to the ec_audacious.streamripper wrapper script, we're effectively adding a new option to streamripper called --audacious which spawns our filesystem monitor.</p>]]></content:encoded>
    </item>
    <item>
      <title>Writing an OpenOffice.org Calc extension in Python</title>
      <link>http://www.enigmacurry.com/2009/12/13/writing-an-openoffice.org-calc-extension-in-python</link>
      <pubDate>Sun, 13 Dec 2009 10:08:00 EST</pubDate>
      <category><![CDATA[python]]></category>
      <category><![CDATA[openoffice.org]]></category>
      <guid>http://www.enigmacurry.com/2009/12/13/writing-an-openoffice.org-calc-extension-in-python</guid>
      <description>Writing an OpenOffice.org Calc extension in Python</description>
      <content:encoded><![CDATA[<p>A very well organized group of thugs steals my money every day. I'm getting really tired of it, but I found a way to save at least some of my money so they don't steal nearly as much of it, nearly as often. For whatever reason, this gang hasn't devised a way to steal gold and silver nearly as efficiently as these little green pieces of paper that they call money. So I buy gold and silver whenever I can as a hedge against 'inflation' (which is really just their gang-speak for the wholesale-theft of my money.)</p>
<p>I want to keep track of how much gold and silver I've bought, when I bought it, and inevitably I'll still want to know how many green pieces of paper I could theoretically trade it all in for.</p>
<p>The easiest way to track all this information was to create a spreadsheet in OpenOffice.org's Calc. I created a sheet for gold purchases and another sheet for silver purchases. Everytime I make a purchase, I record the number of ounces, what form it is in (coins, bars, junk etc), who I bought it from, when I bought it, and the price I paid in FRNs (Federal Reserve Notes, aka green pieces of paper.) On another sheet I total the number of ounces I own and multiply it by the current spot price for the metal, which gives me the current price I could get if I sold it for FRNs. When tallying this total, I reference a special cell on the sheet, one that has the current spot price for gold, and another for silver.</p>
<p>But checking the spot price myself and manually updating those cells was just too tedious for my programmer's heart. I wanted OpenOffice.org to automatically retrieve this information for me. So, I started researching OpenOffice.org extensions (plugins).</p>
<p>Turns out, OpenOffice.org extensions can be written in my favorite programming language, Python (yea!), so I wrote the following extension a few weekends ago. It's <a href="http://github.com/EnigmaCurry/SpotMetal">on github</a> and can be downloaded with git:</p>
<div class="pygments_murphy"><pre>  git clone git://github.com/EnigmaCurry/SpotMetal.git
</pre></div>

<p>If you just want the pre-compiled extension, it can be downloaded here locally:</p>
<p><a href="/blog-post-files/SpotMetal-0.1.oxt">SpotMetal-0.1.oxt</a></p>
<p>You install it inside OpenOffice.org by going to <code>Tools -&gt; Extension Manager</code> and clicking on <code>Add</code> and browsing to the <code>SpotMetal-0.1.oxt</code> file you downloaded or built yourself.</p>
<p>Once you have it installed, you now have a new Calc function available called <code>SPOTMETAL</code> which takes two arguments:</p>
<ul>
<li><em>metal</em> - Which metal you want to look up. Can be one of <code>"gold", "silver", "platinum",</code> or <code>"palladium"</code></li>
<li><em>bidAsk</em> - Whether you want the bid or the ask price. Can be either <code>"bid"</code> or <code>"ask"</code>.</li>
</ul>
<p>The price will automatically be refreshed every 5 minutes by default, but you can also force a refresh with the Calc function called <code>SPOTMETALREFRESH</code>.</p>
<p>Here's an <a href="/blog-post-files/MetalTrackerExample.ods">example OpenOffice.org spreadhseet</a> that shows how you might track your own precious metal investment portfolio. The big button labeled "Refresh Spot Price" does what it says it does, but requires a bit more boiler-plate code in order for it to actually display on screen. In OpenOffice.org, you can see another macro called doReCalculate:</p>
<ul>
<li><code>Tools-&gt;Macros-&gt;Organize Macros-&gt;OpenOffice.org Basic</code> </li>
<li><code>MetalTrackerExample.ods-&gt;Standard-&gt;SpotMetal-&gt;doReCalculate</code>. </li>
</ul>
<p>This extra macro is necessary to actually force the spreadsheet to request new data from the extension when you click the "Refresh Spot Price" button.</p>
<p>While this extension might be of use to you if you also invest in precious metals, I guess the main reason I posted this is because it took a good deal of time researching how to write a Python extension for OpenOffice.org. Check out <a href="http://github.com/EnigmaCurry/SpotMetal">the source code on github</a> if you're looking to write your own extension, it's got it's own Makefile and hopefully it's documented well enough for it be useful for someone in the future.</p>]]></content:encoded>
    </item>
    <item>
      <title>Distributing Jython Apps in a Single JAR file</title>
      <link>http://www.enigmacurry.com/2009/05/20/distributing-jython-apps-in-a-single-jar-file/</link>
      <pubDate>Wed, 20 May 2009 14:20:51 EDT</pubDate>
      <category><![CDATA[python]]></category>
      <category><![CDATA[java]]></category>
      <guid>http://www.enigmacurry.com/?p=440</guid>
      <description>Distributing Jython Apps in a Single JAR file</description>
      <content:encoded><![CDATA[
<p>I've been writing a lot of one-off type applications at work lately, which is always kind of a joy for me because these sorts of applications don't need to be maintained or supported in any way, which means I can write them however I want.</p>

<p>So I write them in Python :)</p>

<p>Jython allows me to interface with all the plethora of Java libraries that we use at work, and it lets me program in a language that not only I can tolerate, but one that I respect and love.</p>

<p>But even though these are one-off applications, they still need to be easy to use, and in some cases I won't even be the one running the application. I want these applications to just work damnit.</p>

<p>So, packaging my Jython application into a single executable jar file that contains all of the third party dependancies inside is my goal. I want to send the user the jar file, have them double click on it, and have it immediately start running. It can't get a whole lot easier than that.</p>

<p>The <a href="http://wiki.python.org/jython/JythonFaq/DistributingJythonScripts">Jython wiki has a page</a> about doing something along these lines. The recipe there called the <a href="http://wiki.python.org/jython/JythonFaq/DistributingJythonScripts#UsingtheJarMethod">Jar Method</a> works quite well. The one drawback that it has is that all of the Java dependancies need to be exploded into the main jar root, which when you're dealing with dozens of jar dependancies, it can start to get tedious, messy, and in some cases will even violate the license of a particular library.</p>

<p><a href="http://one-jar.sourceforge.net/">One-Jar</a> is a special class loader that can load a jar file that is inside of another jar file, something that the regular class loader from Sun is incapable of doing. Using One-Jar lets my application reside inside of a jar file and contain all my dependancies as seperate jar files inside the main jar file.</p>

<p>I've created a sample project that shows how I normally create a new Jython project hosted inside a single jar file with One-Jar. You'll need the following tools to check out the project:</p>

<ul>
    <li>A Java SDK (tested with <a href="http://openjdk.java.net/">OpenJDK 1.6</a>)</li>
    <li><a href="http://ant.apache.org/">Apache Ant</a> (tested with version 1.7)</li>
    <li><a href="http://git-scm.com/">Git</a> (to checkout the project)</li>
</ul>
<p>Check out the project like so:</p>

<div class="pygments_murphy"><pre> git clone git://github.com/EnigmaCurry/Single-JAR-Jython-Example.git
</pre></div>



<p>Build the project:</p>

<div class="pygments_murphy"><pre><span class="nb">cd </span>single-jar-jython-example

ant
</pre></div>



<p> Run the example by double clicking it or via the command line:</p>

<div class="pygments_murphy"><pre> java -jar JythonExcelExample.jar
</pre></div>



<p>This is just a demonstration app, it doesn't do a whole lot, it outputs an excel file in the current directory listing some computer parts. The point of the application is to show how Jython can integrate with existing Java third-party libraries (in this case Apache POI.)</p>

<p>Instructions for basing your own application on this example are contained inside the README.txt file.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Jython Shell Server -- Adding a REPL to any Java app</title>
      <link>http://www.enigmacurry.com/2009/03/01/jython-shell-server-adding-a-repl-to-any-java-app/</link>
      <pubDate>Sun, 01 Mar 2009 14:10:02 EST</pubDate>
      <category><![CDATA[python]]></category>
      <category><![CDATA[java]]></category>
      <guid>http://www.enigmacurry.com/?p=430</guid>
      <description>Jython Shell Server -- Adding a REPL to any Java app</description>
      <content:encoded><![CDATA[
<p>I love programming in Python. I get paid to write Java though. Due to <a href="/2007/04/20/python-vs-java/">Java's verboseness</a>, and lack of a REPL, this can be very frustrating for me. </p>

<p>In Python, the usual way I explore a new library or mock up a new idea is to immediately start coding in Python's interactive interpreter (or <a href="http://www.wikipedia.com/wiki/REPL">REPL</a>). This is often times more efficient than reading (let alone finding) the documentation for the library. I can quickly see if something is going to work before I code inside my larger application.</p>

<p>Java doesn't have an interactive interpreter.. but <a href="http://www.jython.org">Jython</a> does! However, setting up Jython, especially interfacing with an already large Java application, can be difficult. One such difficult situation I deal with at work is in Weblogic. With Weblogic, I deploy my application directly to a running Weblogic server, and I never get to see a console in this process, so how am I ever going to run a Jython interactive interpreter?</p>

<p>This morning I got bored and wrote up a quick solution: <a href="http://github.com/EnigmaCurry/jython-shell-server/tree">JythonShellServer</a>. JythonShellServer embeds into any Java application and starts a Telnet server that serves up Jython interactive shells. You can push any Java object that you want to manipulate into Jython's local environment. Run "telnet localhost 7000" and you can use Python code to explore your entire application's running environment.</p>

<p>JythonShellServer works, but I only just wrote it this morning, so consider it alpha quality at the moment. Check out the <a href="http://github.com/EnigmaCurry/jython-shell-server/tree">project page on github.</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>AutoComplete.el : Python Code Completion in Emacs</title>
      <link>http://www.enigmacurry.com/2009/01/21/autocompleteel-python-code-completion-in-emacs/</link>
      <pubDate>Wed, 21 Jan 2009 22:01:10 EST</pubDate>
      <category><![CDATA[python]]></category>
      <category><![CDATA[emacs]]></category>
      <category><![CDATA[linux]]></category>
      <guid>http://www.enigmacurry.com/?p=401</guid>
      <description>AutoComplete.el : Python Code Completion in Emacs</description>
      <content:encoded><![CDATA[
<center><img src="/blog-post-images/PythonCodeCompletion_Rope_Autocomplete.png" /></center>

<p>A <a href="http://www.travishartwell.net/blog">friend of mine</a> and I like to show off to each other little Emacs tips and tricks we learn. Today, he introduced to me the very cool <a href="http://www.emacswiki.org/emacs/AutoComplete">AutoComplete.el package</a>.  AutoComplete.el is intriguing to me because, unlike ropemacs mode <a href="/2008/05/09/emacs-as-a-powerful-python-ide/">which I've blogged about before</a>, the completions AutoComplete.el provides are inline with your code in a dropdown box instead of in a seperate window (windows in Emacs are what most people call frames). However, AutoComplete is only a completion framework, it doesn't know anything about Python. Instead, it allows the user to plug into it, feeding it whatever sorts of intelligent completion you want, including <a href="http://rope.sourceforge.net">Rope</a>.</p>

<h2 class="intrablog">Setup</h2>

<p>The two most important completions I want to integrate into it are <a href="http://rope.sourceforge.net">Rope</a> and <a href="http://code.google.com/p/yasnippet/">yasnippet.</a> AutoComplete can handle both of them nicely. You'll need to install the <b><em>very latest development version</em></b> (as of December '08) of Rope, Ropemacs and Ropemode:</p>


<div class="pygments_murphy"><pre>sudo apt-get install mercurial
mkdir /tmp/rope <span class="o">&amp;&amp;</span> <span class="nb">cd</span> /tmp/rope
hg clone http://bitbucket.org/agr/rope
hg clone http://bitbucket.org/agr/ropemacs
hg clone http://bitbucket.org/agr/ropemode
sudo easy_install rope
ln -s ../ropemode/ropemode ropemacs/
sudo easy_install ropemacs
</pre></div>




<p>You'll also need to install <a href="http://pymacs.progiciels-bpi.ca/">Pymacs</a>  and <a href="http://code.google.com/p/yasnippet">Yasnippet</a> if you haven't already: </p>


<div class="pygments_murphy"><pre>mkdir -p ~/.emacs.d/vendor <span class="o">&amp;&amp;</span> <span class="nb">cd</span> ~/.emacs.d/vendor
wget http://pymacs.progiciels-bpi.ca/archives/Pymacs-0.23.tar.gz
tar xfv Pymacs-0.23.tar.gz
<span class="nb">cd </span>Pymacs-0.23
make
sudo easy_install .
<span class="nb">cd</span> ~/.emacs.d/vendor
wget http://yasnippet.googlecode.com/files/yasnippet-0.5.9.tar.bz2
tar xfv yasnippet-0.5.9.tar.bz2
<span class="nb">cd</span> ~/.emacs.d
ln -s vendor/yasnippet-0.5.9/snippets/ .
</pre></div>




<p>Make sure Pymacs and Yasnippet get into your load path, in your .emacs:</p>

<div class="pygments_murphy"><pre><span class="p">(</span><span class="nv">add-to-list</span> <span class="ss">&#39;load-path</span> <span class="s">&quot;~/.emacs.d/vendor&quot;</span><span class="p">)</span>
<span class="p">(</span><span class="k">progn</span> <span class="p">(</span><span class="nv">cd</span> <span class="s">&quot;~/.emacs.d/vendor&quot;</span><span class="p">)</span>
       <span class="p">(</span><span class="nv">normal-top-level-add-subdirs-to-load-path</span><span class="p">))</span>
</pre></div>




<p>Install AutoComplete.el 0.1.0 (0.2.0 is now out, and is not compatible with this post, I'll try and update later):</p>


<div class="pygments_murphy"><pre><span class="nb">cd</span> ~/.emacs.d/vendor
wget http://www.emacswiki.org/emacs/?action<span class="o">=</span>browse;id<span class="o">=</span>auto-complete.el;raw<span class="o">=</span>1;revision<span class="o">=</span>5
</pre></div>




<p>Now to add some more elisp to your .emacs somewhere:</p>


<div class="pygments_murphy"><pre><span class="p">(</span><span class="nb">require</span> <span class="ss">&#39;python</span><span class="p">)</span>
<span class="p">(</span><span class="nb">require</span> <span class="ss">&#39;auto-complete</span><span class="p">)</span>
<span class="p">(</span><span class="nb">require</span> <span class="ss">&#39;yasnippet</span><span class="p">)</span>

<span class="p">(</span><span class="nv">autoload</span> <span class="ss">&#39;python-mode</span> <span class="s">&quot;python-mode&quot;</span> <span class="s">&quot;Python Mode.&quot;</span> <span class="no">t</span><span class="p">)</span>
<span class="p">(</span><span class="nv">add-to-list</span> <span class="ss">&#39;auto-mode-alist</span> <span class="o">&#39;</span><span class="p">(</span><span class="s">&quot;\\.py\\&#39;&quot;</span> <span class="o">.</span> <span class="nv">python-mode</span><span class="p">))</span>
<span class="p">(</span><span class="nv">add-to-list</span> <span class="ss">&#39;interpreter-mode-alist</span> <span class="o">&#39;</span><span class="p">(</span><span class="s">&quot;python&quot;</span> <span class="o">.</span> <span class="nv">python-mode</span><span class="p">))</span>

<span class="c1">;; Initialize Pymacs                                                                                           </span>
<span class="p">(</span><span class="nv">autoload</span> <span class="ss">&#39;pymacs-apply</span> <span class="s">&quot;pymacs&quot;</span><span class="p">)</span>
<span class="p">(</span><span class="nv">autoload</span> <span class="ss">&#39;pymacs-call</span> <span class="s">&quot;pymacs&quot;</span><span class="p">)</span>
<span class="p">(</span><span class="nv">autoload</span> <span class="ss">&#39;pymacs-eval</span> <span class="s">&quot;pymacs&quot;</span> <span class="no">nil</span> <span class="no">t</span><span class="p">)</span>
<span class="p">(</span><span class="nv">autoload</span> <span class="ss">&#39;pymacs-exec</span> <span class="s">&quot;pymacs&quot;</span> <span class="no">nil</span> <span class="no">t</span><span class="p">)</span>
<span class="p">(</span><span class="nv">autoload</span> <span class="ss">&#39;pymacs-load</span> <span class="s">&quot;pymacs&quot;</span> <span class="no">nil</span> <span class="no">t</span><span class="p">)</span>
<span class="c1">;; Initialize Rope                                                                                             </span>
<span class="p">(</span><span class="nv">pymacs-load</span> <span class="s">&quot;ropemacs&quot;</span> <span class="s">&quot;rope-&quot;</span><span class="p">)</span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">ropemacs-enable-autoimport</span> <span class="no">t</span><span class="p">)</span>

<span class="c1">;; Initialize Yasnippet                                                                                        </span>
<span class="c1">;Don&#39;t map TAB to yasnippet                                                                                    </span>
<span class="c1">;In fact, set it to something we&#39;ll never use because                                                          </span>
<span class="c1">;we&#39;ll only ever trigger it indirectly.                                                                        </span>
<span class="p">(</span><span class="k">setq</span> <span class="nv">yas/trigger-key</span> <span class="p">(</span><span class="nv">kbd</span> <span class="s">&quot;C-c &lt;kp-multiply&gt;&quot;</span><span class="p">))</span>
<span class="p">(</span><span class="nv">yas/initialize</span><span class="p">)</span>
<span class="p">(</span><span class="nv">yas/load-directory</span> <span class="s">&quot;~/.emacs.d/snippets&quot;</span><span class="p">)</span>



<span class="c1">;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                                         </span>
<span class="c1">;;; Auto-completion                                                                                            </span>
<span class="c1">;;;  Integrates:                                                                                               </span>
<span class="c1">;;;   1) Rope                                                                                                  </span>
<span class="c1">;;;   2) Yasnippet                                                                                             </span>
<span class="c1">;;;   all with AutoComplete.el                                                                                 </span>
<span class="c1">;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                                         </span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">prefix-list-elements</span> <span class="p">(</span><span class="nb">list</span> <span class="nv">prefix</span><span class="p">)</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">(</span><span class="nv">value</span><span class="p">)</span>
    <span class="p">(</span><span class="nb">nreverse</span>
     <span class="p">(</span><span class="nb">dolist</span> <span class="p">(</span><span class="nv">element</span> <span class="nb">list</span> <span class="nv">value</span><span class="p">)</span>
      <span class="p">(</span><span class="k">setq</span> <span class="nv">value</span> <span class="p">(</span><span class="nb">cons</span> <span class="p">(</span><span class="nb">format</span> <span class="s">&quot;%s%s&quot;</span> <span class="nv">prefix</span> <span class="nv">element</span><span class="p">)</span> <span class="nv">value</span><span class="p">))))))</span>
<span class="p">(</span><span class="nb">defvar</span> <span class="nv">ac-source-rope</span>
  <span class="o">&#39;</span><span class="p">((</span><span class="nv">candidates</span>
     <span class="o">.</span> <span class="p">(</span><span class="k">lambda</span> <span class="p">()</span>
         <span class="p">(</span><span class="nv">prefix-list-elements</span> <span class="p">(</span><span class="nv">rope-completions</span><span class="p">)</span> <span class="nv">ac-target</span><span class="p">))))</span>
  <span class="s">&quot;Source for Rope&quot;</span><span class="p">)</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">ac-python-find</span> <span class="p">()</span>
  <span class="s">&quot;Python `ac-find-function&#39;.&quot;</span>
  <span class="p">(</span><span class="nb">require</span> <span class="ss">&#39;thingatpt</span><span class="p">)</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nc">symbol</span> <span class="p">(</span><span class="nv">car-safe</span> <span class="p">(</span><span class="nv">bounds-of-thing-at-point</span> <span class="ss">&#39;symbol</span><span class="p">))))</span>
    <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">null</span> <span class="nc">symbol</span><span class="p">)</span>
        <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">string=</span> <span class="s">&quot;.&quot;</span> <span class="p">(</span><span class="nv">buffer-substring</span> <span class="p">(</span><span class="nb">-</span> <span class="p">(</span><span class="nv">point</span><span class="p">)</span> <span class="mi">1</span><span class="p">)</span> <span class="p">(</span><span class="nv">point</span><span class="p">)))</span>
            <span class="p">(</span><span class="nv">point</span><span class="p">)</span>
          <span class="no">nil</span><span class="p">)</span>
      <span class="nc">symbol</span><span class="p">)))</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">ac-python-candidate</span> <span class="p">()</span>
  <span class="s">&quot;Python `ac-candidates-function&#39;&quot;</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">(</span><span class="nv">candidates</span><span class="p">)</span>
    <span class="p">(</span><span class="nb">dolist</span> <span class="p">(</span><span class="nv">source</span> <span class="nv">ac-sources</span><span class="p">)</span>
      <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">symbolp</span> <span class="nv">source</span><span class="p">)</span>
          <span class="p">(</span><span class="k">setq</span> <span class="nv">source</span> <span class="p">(</span><span class="nb">symbol-value</span> <span class="nv">source</span><span class="p">)))</span>
      <span class="p">(</span><span class="k">let*</span> <span class="p">((</span><span class="nv">ac-limit</span> <span class="p">(</span><span class="nb">or</span> <span class="p">(</span><span class="nv">cdr-safe</span> <span class="p">(</span><span class="nv">assq</span> <span class="ss">&#39;limit</span> <span class="nv">source</span><span class="p">))</span> <span class="nv">ac-limit</span><span class="p">))</span>
             <span class="p">(</span><span class="nv">requires</span> <span class="p">(</span><span class="nv">cdr-safe</span> <span class="p">(</span><span class="nv">assq</span> <span class="ss">&#39;requires</span> <span class="nv">source</span><span class="p">)))</span>
             <span class="nv">cand</span><span class="p">)</span>
        <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">or</span> <span class="p">(</span><span class="nb">null</span> <span class="nv">requires</span><span class="p">)</span>
                <span class="p">(</span><span class="nb">&gt;=</span> <span class="p">(</span><span class="nb">length</span> <span class="nv">ac-target</span><span class="p">)</span> <span class="nv">requires</span><span class="p">))</span>
            <span class="p">(</span><span class="k">setq</span> <span class="nv">cand</span>
                  <span class="p">(</span><span class="nv">delq</span> <span class="no">nil</span>
                        <span class="p">(</span><span class="nb">mapcar</span> <span class="p">(</span><span class="k">lambda</span> <span class="p">(</span><span class="nv">candidate</span><span class="p">)</span>
                                  <span class="p">(</span><span class="nv">propertize</span> <span class="nv">candidate</span> <span class="ss">&#39;source</span> <span class="nv">source</span><span class="p">))</span>
                                <span class="p">(</span><span class="nb">funcall</span> <span class="p">(</span><span class="nb">cdr</span> <span class="p">(</span><span class="nv">assq</span> <span class="ss">&#39;candidates</span> <span class="nv">source</span><span class="p">)))))))</span>
        <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">and</span> <span class="p">(</span><span class="nb">&gt;</span> <span class="nv">ac-limit</span> <span class="mi">1</span><span class="p">)</span>
                 <span class="p">(</span><span class="nb">&gt;</span> <span class="p">(</span><span class="nb">length</span> <span class="nv">cand</span><span class="p">)</span> <span class="nv">ac-limit</span><span class="p">))</span>
            <span class="p">(</span><span class="nv">setcdr</span> <span class="p">(</span><span class="nb">nthcdr</span> <span class="p">(</span><span class="nb">1-</span> <span class="nv">ac-limit</span><span class="p">)</span> <span class="nv">cand</span><span class="p">)</span> <span class="no">nil</span><span class="p">))</span>
        <span class="p">(</span><span class="k">setq</span> <span class="nv">candidates</span> <span class="p">(</span><span class="nb">append</span> <span class="nv">candidates</span> <span class="nv">cand</span><span class="p">))))</span>
    <span class="p">(</span><span class="nv">delete-dups</span> <span class="nv">candidates</span><span class="p">)))</span>
<span class="p">(</span><span class="nv">add-hook</span> <span class="ss">&#39;python-mode-hook</span>
          <span class="p">(</span><span class="k">lambda</span> <span class="p">()</span>
                 <span class="p">(</span><span class="nv">auto-complete-mode</span> <span class="mi">1</span><span class="p">)</span>
                 <span class="p">(</span><span class="nb">set</span> <span class="p">(</span><span class="nv">make-local-variable</span> <span class="ss">&#39;ac-sources</span><span class="p">)</span>
                      <span class="p">(</span><span class="nb">append</span> <span class="nv">ac-sources</span> <span class="o">&#39;</span><span class="p">(</span><span class="nv">ac-source-rope</span><span class="p">)</span> <span class="o">&#39;</span><span class="p">(</span><span class="nv">ac-source-yasnippet</span><span class="p">)))</span>
                 <span class="p">(</span><span class="nb">set</span> <span class="p">(</span><span class="nv">make-local-variable</span> <span class="ss">&#39;ac-find-function</span><span class="p">)</span> <span class="ss">&#39;ac-python-find</span><span class="p">)</span>
                 <span class="p">(</span><span class="nb">set</span> <span class="p">(</span><span class="nv">make-local-variable</span> <span class="ss">&#39;ac-candidate-function</span><span class="p">)</span> <span class="ss">&#39;ac-python-candidate</span><span class="p">)</span>
                 <span class="p">(</span><span class="nb">set</span> <span class="p">(</span><span class="nv">make-local-variable</span> <span class="ss">&#39;ac-auto-start</span><span class="p">)</span> <span class="no">nil</span><span class="p">)))</span>

<span class="c1">;;Ryan&#39;s python specific tab completion                                                                        </span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">ryan-python-tab</span> <span class="p">()</span>
  <span class="c1">; Try the following:                                                                                         </span>
  <span class="c1">; 1) Do a yasnippet expansion                                                                                </span>
  <span class="c1">; 2) Do a Rope code completion                                                                               </span>
  <span class="c1">; 3) Do an indent                                                                                            </span>
  <span class="p">(</span><span class="nv">interactive</span><span class="p">)</span>
  <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nb">eql</span> <span class="p">(</span><span class="nv">ac-start</span><span class="p">)</span> <span class="mi">0</span><span class="p">)</span>
      <span class="p">(</span><span class="nv">indent-for-tab-command</span><span class="p">)))</span>

<span class="p">(</span><span class="nv">defadvice</span> <span class="nv">ac-start</span> <span class="p">(</span><span class="nv">before</span> <span class="nv">advice-turn-on-auto-start</span> <span class="nv">activate</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">set</span> <span class="p">(</span><span class="nv">make-local-variable</span> <span class="ss">&#39;ac-auto-start</span><span class="p">)</span> <span class="no">t</span><span class="p">))</span>
<span class="p">(</span><span class="nv">defadvice</span> <span class="nv">ac-cleanup</span> <span class="p">(</span><span class="nv">after</span> <span class="nv">advice-turn-off-auto-start</span> <span class="nv">activate</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">set</span> <span class="p">(</span><span class="nv">make-local-variable</span> <span class="ss">&#39;ac-auto-start</span><span class="p">)</span> <span class="no">nil</span><span class="p">))</span>

<span class="p">(</span><span class="nv">define-key</span> <span class="nv">python-mode-map</span> <span class="s">&quot;\t&quot;</span> <span class="ss">&#39;ryan-python-tab</span><span class="p">)</span>
<span class="c1">;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                                         </span>
<span class="c1">;;; End Auto Completion                                                                                        </span>
<span class="c1">;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</span>
</pre></div>




<h2 class="intrablog">Github</h2>

<p>These changes are also applied to my <a href="http://www.github.com/EnigmaCurry/emacs">Emacs environment on Github.</a> I'm continuously trying to improve my emacs setup, so if you're reading this a few months/years after this post was made, you may want to check there for improvements.</p>

<p><b>Update Jan 30 2009:</b> I made some modifications to the tab complete order, a regular indent is applied first before autocompletion. Autocompletion is also not applied unless you are at the end of a word. This is useful when you press Tab at the beginning of a line to indent/outdent.</p>

<h2 class="intrablog">Usage</h2>
<p>Once you got everything setup, usage is real easy:</p>
<ol>
<li>Open up a python (.py) file</li>
<li>Press TAB when you want to use code completion or to insert a snippet.</li>
</ol>

<p>The first time you attempt to use code completion you'll be prompted to enter the root of your project directory.</p>

<h2 class="intrablog">Future</h2>
<p>It wasn't too long ago when Python code completion inside Emacs was just a pipedream. So now that we have it, let's make some more pipedreams: I'd like to popup some nice contextual help for method arguments as well as python documentation for the current method/class being completed. </p>

<p>The possibilities are pretty much endless. I love Emacs.</p>
]]></content:encoded>
    </item>
    <item>
      <title>My Emacs config on Github</title>
      <link>http://www.enigmacurry.com/2009/01/19/my-emacs-config-on-github/</link>
      <pubDate>Mon, 19 Jan 2009 17:01:56 EST</pubDate>
      <category><![CDATA[python]]></category>
      <category><![CDATA[emacs]]></category>
      <guid>http://www.enigmacurry.com/?p=376</guid>
      <description>My Emacs config on Github</description>
      <content:encoded><![CDATA[
<p>The most popular post on this blog is <a href="/2008/05/09/emacs-as-a-powerful-python-ide/">Emacs as a powerful Python IDE</a>. I get quite a few emails regarding that post and I realized the other day that I've done a lot of customizations to my .emacs, and subsequently that post is starting to get a little dated. Time is a curious creature, it seems like yesterday that I wrote that post, but it's been almost 9 months now.</p>

<p>I've been learning and playing around with <a href="http://git-scm.com">git</a> recently, so I've decided to post my <a href="http://www.github.com/EnigmaCurry/emacs">entire .emacs config on github</a>. </p>

<p>Here are the latest instructions for emulating my Emacs environment on Ubuntu 8.10:</p>
<ul>
  <li>Enable the <a href="http://help.ubuntu.com/community/Repositories/Ubuntu">universe repository</a></li>
  <li>sudo apt-get update</li>
  <li>sudo apt-get install emacs-snapshot git-core automake libgconf2-dev texinfo python-setuptools</li>
  <li>cd ~</li>
  <li>git clone git://github.com/EnigmaCurry/emacs .emacs.d</li>
  <li>cd ~/.emacs.d</li>
  <li>git submodule init</li>
  <li>git submodule update</li>
  <li>cd ~/.emacs.d/vendor</li>
  <li>./vendor-compile.sh</li>
  <li>sudo easy_install "http://downloads.sourceforge.net/rope/rope-0.9.1.tar.gz?modtime=1225268769&big_mirror=0"</li>
  <li>sudo easy_install "http://downloads.sourceforge.net/rope/ropemacs-0.6.tar.gz?modtime=1223039342&big_mirror=0"</li>  
</ul>

<p>I've done some reorganization of the directory structure: </p>
<ol>
  <li>There actually is no ~/.emacs file anymore, having realized that Emacs looks for ~/.emacs.d/init.el. Convenient! </li>
  <li>All third party packages are now installed in ~/.emacs.d/vendor. This was a great tip I saw in the <a href="http://peepcode.com/products/meet-emacs">Emacs Peepcode screencast</a>. (it's $9, but worth it).</li>
  <li>I've taken the suggestion that greg made in the comments to use submodules for some of the vendor packages. The vendor-compile.sh script does the compiling of those packages.</li>
<li>All private code goes in ~/.emacs.private. This lets me keep passwords and such outside of the main git repository and allows me to publish my config more easily. Before I did this I had to spend time sanitizing the code before each release.</li>
</ol>

<p>I have appreciated your many encouraging Emails and comments. :)</p>]]></content:encoded>
    </item>
    <item>
      <title>Shortened URLs in Emacs using is.gd (like tinyurl)</title>
      <link>http://www.enigmacurry.com/2008/09/15/shortened-urls-in-emacs-using-isgd-like-tinyurl/</link>
      <pubDate>Mon, 15 Sep 2008 11:11:20 EDT</pubDate>
      <category><![CDATA[python]]></category>
      <category><![CDATA[emacs]]></category>
      <guid>http://www.enigmacurry.com/?p=156</guid>
      <description>Shortened URLs in Emacs using is.gd (like tinyurl)</description>
      <content:encoded><![CDATA[
<p>I've casually been teaching myself emacs lisp lately. Today I wrote a utility that shortens long urls within regions using the <a href="http://is.gd">http://is.gd</a> URL shortening service. There's plenty of <a href="http://www.emacswiki.org/cgi-bin/wiki/tinyurl.el">existing code</a> out there that is more lisp like, but this is supposed to be a learning experience for me so I did it myself. I like python and so I used python for most of the heavy lifting.</p>

<p>I created a directory to hold all of my emacs specific python functions: ~/.emacs.d/ryan-pymacs-extensions</p>

<p>I wrote the following python function, shorten_url.py in that directory:</p>


<div class="pygments_murphy"><pre><span class="err">!</span><span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="nb">bin</span><span class="o">/</span><span class="n">env</span> <span class="n">python</span>
<span class="c"># -*- coding: utf-8 -*-</span>

<span class="n">__author__</span> <span class="o">=</span> <span class="s">&quot;Ryan McGuire (ryan@enigmacurry.com)&quot;</span>
<span class="n">__date__</span>   <span class="o">=</span> <span class="s">&quot;Mon Sep 15 12:27:14 2008&quot;</span>

<span class="kn">import</span> <span class="nn">doctest</span>
<span class="kn">import</span> <span class="nn">urllib2</span>
<span class="kn">import</span> <span class="nn">re</span>

<span class="k">def</span> <span class="nf">shorten_with_is_gd</span><span class="p">(</span><span class="n">url</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Shorten a URL with is.gd</span>

<span class="sd">    &gt;&gt;&gt; shorten_with_is_gd(&#39;http://www.enigmacurry.com&#39;)</span>
<span class="sd">    &#39;http://is.gd/FFP&#39;</span>

<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">u</span> <span class="o">=</span> <span class="n">urllib2</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="s">&quot;http://is.gd/api.php?longurl=&quot;</span><span class="o">+</span><span class="n">url</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">u</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>

<span class="k">def</span> <span class="nf">shorten_in_text</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Shorten all the urls found inside some text</span>

<span class="sd">    &gt;&gt;&gt; shorten_in_text(&#39;Hi from http://www.enigmacurry.com&#39;)</span>
<span class="sd">    &#39;Hi from http://is.gd/FFP&#39;</span>
<span class="sd">    </span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">replacements</span> <span class="o">=</span> <span class="p">{}</span> <span class="c">#URL -&gt; is.gd URL</span>
    <span class="c">#Only check for urls that start with &quot;http://&quot; for now</span>
    <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">re</span><span class="o">.</span><span class="n">finditer</span><span class="p">(</span><span class="s">&quot;http://[^ </span><span class="se">\n\r</span><span class="s">]*&quot;</span><span class="p">,</span> <span class="n">text</span><span class="p">):</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="n">replacements</span><span class="p">[</span><span class="n">m</span><span class="o">.</span><span class="n">group</span><span class="p">()]</span> <span class="o">=</span> <span class="n">shorten_with_is_gd</span><span class="p">(</span><span class="n">m</span><span class="o">.</span><span class="n">group</span><span class="p">())</span>
        <span class="k">except</span><span class="p">:</span>
            <span class="n">replacements</span><span class="p">[</span><span class="n">m</span><span class="o">.</span><span class="n">group</span><span class="p">()]</span> <span class="o">=</span> <span class="n">m</span><span class="o">.</span><span class="n">group</span><span class="p">()</span>
    <span class="k">for</span> <span class="n">url</span><span class="p">,</span><span class="n">replacement</span> <span class="ow">in</span> <span class="n">replacements</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
        <span class="n">text</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">replacement</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">text</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="n">doctest</span><span class="o">.</span><span class="n">testmod</span><span class="p">(</span><span class="n">verbose</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</pre></div>




<p>and the following lisp makes "M-x shorten-url" do the rest of the replacement work:</p>


<div class="pygments_murphy"><pre><span class="c1">;add ~/.emacs.d/ryan-python-extensions to python path</span>
<span class="p">(</span><span class="nv">pymacs-exec</span> <span class="s">&quot;import sys, os&quot;</span><span class="p">)</span>
<span class="p">(</span><span class="nv">pymacs-exec</span> <span class="s">&quot;sys.path.append(os.path.join(os.path.expanduser(&#39;~&#39;),&#39;.emacs.d&#39;,&#39;ryan-pymacs-extensions&#39;))&quot;</span><span class="p">)</span>

<span class="c1">;;Shorten URLs with is.gd</span>
<span class="p">(</span><span class="nv">pymacs-exec</span> <span class="s">&quot;import shorten_url&quot;</span><span class="p">)</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">shorten-url</span> <span class="p">(</span><span class="nv">start</span> <span class="nv">end</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">interactive</span> <span class="s">&quot;r&quot;</span><span class="p">)</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">region</span> <span class="p">(</span><span class="nv">buffer-substring</span> <span class="nv">start</span> <span class="nv">end</span><span class="p">)))</span>
    <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">rt</span> <span class="p">(</span><span class="nv">pymacs-eval</span> <span class="p">(</span><span class="nb">format</span> <span class="s">&quot;shorten_url.shorten_in_text(&#39;&#39;&#39;%s&#39;&#39;&#39;)&quot;</span> <span class="nv">region</span><span class="p">))))</span>
      <span class="p">(</span><span class="nv">kill-region</span> <span class="nv">start</span> <span class="nv">end</span><span class="p">)</span>
      <span class="p">(</span><span class="nv">insert</span> <span class="nv">rt</span><span class="p">)</span>
      <span class="p">)</span>
  <span class="p">))</span>
</pre></div>



]]></content:encoded>
    </item>
    <item>
      <title>Importing foreign (non-iCal) calendars into Google Calendar</title>
      <link>http://www.enigmacurry.com/2008/08/19/importing-foreign-non-ical-calendars-into-google-calendar/</link>
      <pubDate>Tue, 19 Aug 2008 15:24:06 EDT</pubDate>
      <category><![CDATA[python]]></category>
      <category><![CDATA[free state project]]></category>
      <guid>http://www.enigmacurry.com/?p=152</guid>
      <description>Importing foreign (non-iCal) calendars into Google Calendar</description>
      <content:encoded><![CDATA[
<p><a href="http://calendar.google.com">Google Calendar</a> is highly useful. I use it to keep track of all my appointments and due dates and I get helpful reminders when dates approach via email and SMS. Not only that, but it allows me to collaborate with other people's calendars as well, and they don't even have to use Google Calendar because Google supports the industry standard <a href="http://en.wikipedia.org/wiki/ICalendar">iCalendar format</a>. Things are great.</p>

<p>Unfortunately, iCalendar format is pretty new, and not everyone is using it. </p>

<p>Because Google Calendar is so useful, it is annoying when you find a calendar that is not in iCal format. Two of note that I want to follow are</p>
<ul>
	<li><a href="http://nhunderground.com/forum/index.php?action=calendar">New Hampshire Underground</a></li>
	<li><a href="http://forum.freekeene.com/index.php?action=calendar">Free Keene</a></li>

</ul>

<p>Both of these calendars are running Simple Machines Forum, version 1.x which does not support iCalendar format (presumably they will in 2.0). </p>

<p>So I wrote an exporter: <a href="/blog-post-files/smf_ical_converter.2.tar.gz">Download SMF iCal exporter</a></p>

<p>The exporter scrapes the calendar page on an SMF enabled site and dumps out an iCal compatible file.</p>

<pre>
Usage: smf_ical_converter.py -u http://yourforum.com/index.php -o cal.ics

Download a SMF 1.x forum calendar and dump in iCal format

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -u URL, --url=URL     URL of forum (up to and including /index.php)
  -n Name, --name=Name  Name of the Forum / Calendar (name goes in .ics file)
  -i EXPR, --ignore-re=EXPR
                        Ignore any event containing this regular expression
                        (specify as many -i as you want)
  -o File, --output=File
                        iCal filename to write
  -v, --verbose         Be verbose about process
  --months-backward=NUM
                        Number of months to go backward
  --months-forward=NUM  Number of months to go forward
</pre>

<p>I have this tool running in a cron job to keep up to date with the two above mentioned calendars. You can import these URLs directly into your Google Calendar:</p>
<ul>
	<li><a href="/external-calendars/nh-underground.ics">NHUnderground.com iCal calendar</a></li> (Includes just events, I use "-i 'Birthdays:'" for this one)

	<li><a href="/external-calendars/free-keene.ics">FreeKeene.com iCal calendar</a></li>
</ul>

<p><strong>Update 09/16/08:</strong> I uploaded version 2 of this application. It has a better README and it now supports user specific date ranges.</p>

]]></content:encoded>
    </item>
    <item>
      <title>Emacs IRC (ERC) with Noticeable Notifications</title>
      <link>http://www.enigmacurry.com/2008/08/07/emacs-irc-erc-with-noticeable-notifications/</link>
      <pubDate>Thu, 07 Aug 2008 00:35:50 EDT</pubDate>
      <category><![CDATA[python]]></category>
      <category><![CDATA[lisp]]></category>
      <category><![CDATA[emacs]]></category>
      <category><![CDATA[linux]]></category>
      <guid>http://www.enigmacurry.com/?p=151</guid>
      <description>Emacs IRC (ERC) with Noticeable Notifications</description>
      <content:encoded><![CDATA[
<p>I use <a href="http://www.emacswiki.org/cgi-bin/wiki?action=browse;oldid=EmacsIRCClient;id=ERC">ERC </a> for all my IRC chatting. I finally got fed up with not noticing someones message because I didn't have emacs focused. So I spent my evening concocting a more noticeable messaging system through Pymacs and libnotify.</p>

<p>Half way though implementing this, wouldn't you know it, I found <a href="http://www.emacswiki.org/cgi-bin/wiki/ErcPageMe">ErcPageMe</a> which does exactly what I wanted. I figured I was learning quite a bit and I continued writing my own version. I expanded on their code and (at least for me) made some improvements. So kudos go to whoever wrote ErcPageMe :)</p>

<p>The following code will pop up a message on your gnome desktop alerting you whenever you receive a personal message or when someone mentions your nickname in a channel. It also avoids notification for the same user in the same channel if they triggered a message within the last 30 seconds.</p>

<center> <img src="/blog-post-images/Emacs-ERC-Notification.png" alt="Emacs ERC Notification through libnotify" /></center>

<p>Here is my lisp and embedded python/pymacs code:</p>


<div class="pygments_murphy"><pre><span class="p">(</span><span class="nb">defun</span> <span class="nv">notify-desktop</span> <span class="p">(</span><span class="nv">title</span> <span class="nv">message</span> <span class="k">&amp;optional</span> <span class="nv">duration</span> <span class="k">&amp;optional</span> <span class="nv">icon</span><span class="p">)</span>
  <span class="s">&quot;Pop up a message on the desktop with an optional duration (forever otherwise)&quot;</span>
  <span class="p">(</span><span class="nv">pymacs-exec</span> <span class="s">&quot;import pynotify&quot;</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">pymacs-exec</span> <span class="s">&quot;pynotify.init(&#39;Emacs&#39;)&quot;</span><span class="p">)</span>
  <span class="p">(</span><span class="k">if</span> <span class="nv">icon</span> 
      <span class="p">(</span><span class="nv">pymacs-exec</span> <span class="p">(</span><span class="nb">format</span> <span class="s">&quot;msg = pynotify.Notification(&#39;%s&#39;,&#39;%s&#39;,&#39;%s&#39;)&quot;</span>
                           <span class="nv">title</span> <span class="nv">message</span> <span class="nv">icon</span><span class="p">))</span>
    <span class="p">(</span><span class="nv">pymacs-exec</span> <span class="p">(</span><span class="nb">format</span> <span class="s">&quot;msg = pynotify.Notification(&#39;%s&#39;,&#39;%s&#39;)&quot;</span> <span class="nv">title</span> <span class="nv">message</span><span class="p">))</span>
    <span class="p">)</span> 
  <span class="p">(</span><span class="k">if</span> <span class="nv">duration</span> 
      <span class="p">(</span><span class="nv">pymacs-exec</span> <span class="p">(</span><span class="nb">format</span> <span class="s">&quot;msg.set_timeout(%s)&quot;</span> <span class="nv">duration</span><span class="p">))</span>
    <span class="p">)</span>
  <span class="p">(</span><span class="nv">pymacs-exec</span> <span class="s">&quot;msg.show()&quot;</span><span class="p">)</span>
  <span class="p">)</span>

<span class="c1">;; Notify me when someone wants to talk to me.</span>
<span class="c1">;; Heavily based off of ErcPageMe on emacswiki.org, with some improvements.</span>
<span class="c1">;; I wanted to learn and I used my own notification system with pymacs</span>
<span class="c1">;; Delay is on a per user, per channel basis now.</span>
<span class="p">(</span><span class="nb">defvar</span> <span class="nv">erc-page-nick-alist</span> <span class="no">nil</span>
  <span class="s">&quot;Alist of &#39;nickname|target&#39; and last time they triggered a notification&quot;</span>
  <span class="p">)</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">erc-notify-allowed</span> <span class="p">(</span><span class="nv">nick</span> <span class="nv">target</span> <span class="k">&amp;optional</span> <span class="nv">delay</span><span class="p">)</span>
  <span class="s">&quot;Return true if a certain nick has waited long enough to notify&quot;</span>
  <span class="p">(</span><span class="nb">unless</span> <span class="nv">delay</span> <span class="p">(</span><span class="k">setq</span> <span class="nv">delay</span> <span class="mi">30</span><span class="p">))</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">cur-time</span> <span class="p">(</span><span class="nv">time-to-seconds</span> <span class="p">(</span><span class="nv">current-time</span><span class="p">)))</span>
        <span class="p">(</span><span class="nv">cur-assoc</span> <span class="p">(</span><span class="nb">assoc</span> <span class="p">(</span><span class="nb">format</span> <span class="s">&quot;%s|%s&quot;</span> <span class="nv">nick</span> <span class="nv">target</span><span class="p">)</span> <span class="nv">erc-page-nick-alist</span><span class="p">))</span>
        <span class="p">(</span><span class="nv">last-time</span><span class="p">))</span>
    <span class="p">(</span><span class="k">if</span> <span class="nv">cur-assoc</span>
        <span class="p">(</span><span class="k">progn</span>
          <span class="p">(</span><span class="k">setq</span> <span class="nv">last-time</span> <span class="p">(</span><span class="nb">cdr</span> <span class="nv">cur-assoc</span><span class="p">))</span>
          <span class="p">(</span><span class="nv">setcdr</span> <span class="nv">cur-assoc</span> <span class="nv">cur-time</span><span class="p">)</span>
          <span class="p">(</span><span class="nb">&gt;</span> <span class="p">(</span><span class="nb">abs</span> <span class="p">(</span><span class="nb">-</span> <span class="nv">cur-time</span> <span class="nv">last-time</span><span class="p">))</span> <span class="nv">delay</span><span class="p">))</span>
      <span class="p">(</span><span class="nb">push</span> <span class="p">(</span><span class="nb">cons</span> <span class="p">(</span><span class="nb">format</span> <span class="s">&quot;%s|%s&quot;</span> <span class="nv">nick</span> <span class="nv">target</span><span class="p">)</span> <span class="nv">cur-time</span><span class="p">)</span> <span class="nv">erc-page-nick-alist</span><span class="p">)</span>
      <span class="no">t</span><span class="p">)</span>
    <span class="p">)</span>
  <span class="p">)</span>
<span class="p">(</span><span class="nb">defun</span> <span class="nv">erc-notify-PRIVMSG</span> <span class="p">(</span><span class="nv">proc</span> <span class="nv">parsed</span><span class="p">)</span>
  <span class="p">(</span><span class="k">let</span> <span class="p">((</span><span class="nv">nick</span> <span class="p">(</span><span class="nb">car</span> <span class="p">(</span><span class="nv">erc-parse-user</span> <span class="p">(</span><span class="nv">erc-response.sender</span> <span class="nv">parsed</span><span class="p">))))</span>
	<span class="p">(</span><span class="nv">target</span> <span class="p">(</span><span class="nb">car</span> <span class="p">(</span><span class="nv">erc-response.command-args</span> <span class="nv">parsed</span><span class="p">)))</span>
	<span class="p">(</span><span class="nv">msg</span> <span class="p">(</span><span class="nv">erc-response.contents</span> <span class="nv">parsed</span><span class="p">)))</span>
    <span class="c1">;;Handle true private/direct messages (non channel)</span>
    <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nb">and</span> <span class="p">(</span><span class="nb">not</span> <span class="p">(</span><span class="nv">erc-is-message-ctcp-and-not-action-p</span> <span class="nv">msg</span><span class="p">))</span>
               <span class="p">(</span><span class="nv">erc-current-nick-p</span> <span class="nv">target</span><span class="p">)</span>
	       <span class="p">(</span><span class="nv">erc-notify-allowed</span> <span class="nv">nick</span> <span class="nv">target</span><span class="p">)</span>
	       <span class="p">)</span>
      <span class="c1">;Do actual notification</span>
      <span class="p">(</span><span class="nv">ding</span><span class="p">)</span>
      <span class="p">(</span><span class="nv">notify-desktop</span> <span class="p">(</span><span class="nb">format</span> <span class="s">&quot;%s - %s&quot;</span> <span class="nv">nick</span>
                              <span class="p">(</span><span class="nv">format-time-string</span> <span class="s">&quot;%b %d %I:%M %p&quot;</span><span class="p">))</span>
                      <span class="nv">msg</span> <span class="mi">0</span> <span class="s">&quot;gnome-emacs&quot;</span><span class="p">)</span>
      <span class="p">)</span>
    <span class="c1">;;Handle channel messages when my nick is mentioned</span>
    <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nb">and</span> <span class="p">(</span><span class="nb">not</span> <span class="p">(</span><span class="nv">erc-is-message-ctcp-and-not-action-p</span> <span class="nv">msg</span><span class="p">))</span>
               <span class="p">(</span><span class="nv">string-match</span> <span class="p">(</span><span class="nv">erc-current-nick</span><span class="p">)</span> <span class="nv">msg</span><span class="p">)</span>
               <span class="p">(</span><span class="nv">erc-notify-allowed</span> <span class="nv">nick</span> <span class="nv">target</span><span class="p">)</span>
	       <span class="p">)</span>
      <span class="c1">;Do actual notification</span>
      <span class="p">(</span><span class="nv">ding</span><span class="p">)</span>
      <span class="p">(</span><span class="nv">notify-desktop</span> <span class="p">(</span><span class="nb">format</span> <span class="s">&quot;%s - %s&quot;</span> <span class="nv">target</span>
                              <span class="p">(</span><span class="nv">format-time-string</span> <span class="s">&quot;%b %d %I:%M %p&quot;</span><span class="p">))</span>
                      <span class="p">(</span><span class="nb">format</span> <span class="s">&quot;%s: %s&quot;</span> <span class="nv">nick</span> <span class="nv">msg</span><span class="p">)</span> <span class="mi">0</span> <span class="s">&quot;gnome-emacs&quot;</span><span class="p">)</span>
      <span class="p">)</span>
    <span class="p">)</span>
      
  <span class="p">)</span>

<span class="p">(</span><span class="nv">add-hook</span> <span class="ss">&#39;erc-server-PRIVMSG-functions</span> <span class="ss">&#39;erc-notify-PRIVMSG</span><span class="p">)</span>
</pre></div>



]]></content:encoded>
    </item>
  </channel>
</rss>
