<?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>feisley &#187; Python</title>
	<atom:link href="http://feisley.com/category/coding/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://feisley.com</link>
	<description>programming with a side of life</description>
	<lastBuildDate>Thu, 15 Apr 2010 07:33:58 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Blackberry eScreen Keygen</title>
		<link>http://feisley.com/2009/09/26/blackberry-escreen-keygen/</link>
		<comments>http://feisley.com/2009/09/26/blackberry-escreen-keygen/#comments</comments>
		<pubDate>Sat, 26 Sep 2009 23:19:35 +0000</pubDate>
		<dc:creator>Jacob Feisley</dc:creator>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[BlackBerry]]></category>
		<category><![CDATA[eScreen]]></category>
		<category><![CDATA[reverse engineering]]></category>

		<guid isPermaLink="false">http://feisley.com/?p=3548</guid>
		<description><![CDATA[As an avid BlackBerry user I always love to see what new things I can make it do.  One of the more interesting parts is the Engineering Screen or &#8220;eScreen&#8221; within the OS. However you need a special key to unlock it.
RIM has the keygen published on their website but you need a password to [...]]]></description>
			<content:encoded><![CDATA[<p>As an avid BlackBerry user I always love to see what new things I can make it do.  One of the more interesting parts is the Engineering Screen or &#8220;eScreen&#8221; within the OS. However you need a special key to unlock it.</p>
<p>RIM has the keygen published on their website but you need a password to get to it (Perhaps it is for partners only?) You can see the site here: <a href="https://www.blackberry.com/EngineeringScreens/">https://www.blackberry.com/EngineeringScreens/</a></p>
<p>Earlier this year a few websites published their own keygen to compute the unlock code. Much to my dismay, however, none of them decided to share exactly how they did this. With that, I decided to discover the unlock code myself and publish the results. <span id="more-3548"></span></p>
<p>The unlock code is actually a simple HMAC digest with a SHA1 variant. The trick is knowing what data to throw at the algorithm to produce the proper unlock code. The data used includes:</p>
<ol>
<li>The BlackBerry device PIN</li>
<li>The application version (including parentheses if provided)</li>
<li>The current uptime of the device in seconds</li>
<li>The unlock duration</li>
<li>The secret sauce</li>
</ol>
<p>The relevant data needed was found by inspecting &#8220;net.rim.device.internal.EScreens.EngScreenSecurity&#8221;, however, I will not go into the details of that here. Once I found the unlock duration codes and the secret key, it was just a matter of putting them into a standard HMAC hash function and out came the unlock code.</p>
<p>In order to use an unlock code, you simply visit the &#8220;Help Me!&#8221; screen by pressing alt+shift+H on your BlackBerry device to get the necessary information, generate a code, and then type it directly into the Help Me screen. No characters will be echoed, but if you enter it correctly, the screen with change over to the &#8220;Engineering Screen&#8221; main page. Do note it is possible to make some changes in the &#8220;eScreen&#8221; that could cause your phone to operate improperly or even break completely so do proceed with changing values at your own risk.</p>
<p>Now I wont point fingers at the various people that have already discovered how this is done but refused to share the code or details with anyone. They are what prompted me to undertake this project in the first place. With that, I give you the Python source code to my basic unlock code keygen:</p>
<p><br class="spacer_" /></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">hmac</span>
<span style="color: #ff7700;font-weight:bold;">import</span> hashlib
&nbsp;
pin = <span style="color: #483d8b;">'ffaa0000'</span>            <span style="color: #808080; font-style: italic;"># Device PIN                [XXXXXXXX]</span>
app = <span style="color: #483d8b;">'4.6.0.100 (233)'</span>     <span style="color: #808080; font-style: italic;"># OS Application version    [n.n.n.n (n)]</span>
uptime = <span style="color: #483d8b;">'12345'</span>            <span style="color: #808080; font-style: italic;"># Uptime in seconds             </span>
duration = <span style="color: #ff4500;">30</span>               <span style="color: #808080; font-style: italic;"># Duration for key to last  [1, 3, 6, 15, or 30]</span>
&nbsp;
lifetime = <span style="color: black;">&#123;</span>
 <span style="color: #ff4500;">1</span>: <span style="color: #483d8b;">&quot;&quot;</span>,
 <span style="color: #ff4500;">3</span>: <span style="color: #483d8b;">&quot;Hello my baby, hello my honey, hello my rag time gal&quot;</span>,
 <span style="color: #ff4500;">7</span>: <span style="color: #483d8b;">&quot;He was a boy, and she was a girl, can I make it any more obvious?&quot;</span>,
 <span style="color: #ff4500;">15</span>: <span style="color: #483d8b;">&quot;So am I, still waiting, for this world to stop hating?&quot;</span>,
 <span style="color: #ff4500;">30</span>: <span style="color: #483d8b;">&quot;I love myself today, not like yesterday. I'm cool, I'm calm, I'm gonna be okay&quot;</span>
<span style="color: black;">&#125;</span>
&nbsp;
secret = <span style="color: #483d8b;">'Up the time stream without a TARDIS'</span>
&nbsp;
data = pin + app + uptime + lifetime<span style="color: black;">&#91;</span>duration<span style="color: black;">&#93;</span>
<span style="color: #008000;">hash</span> = <span style="color: #dc143c;">hmac</span>.<span style="color: #dc143c;">new</span><span style="color: black;">&#40;</span>secret, data, digestmod = hashlib.<span style="color: black;">sha1</span><span style="color: black;">&#41;</span>
key = <span style="color: #008000;">hash</span>.<span style="color: black;">hexdigest</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span>:<span style="color: #ff4500;">8</span><span style="color: black;">&#93;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">print</span> key</pre></div></div>

<p>Weighing in at only 25 lines, this shows how simple the algorithm actually is if one only knows how to put it together. If you want a packaged online tool, then by all means check out the other published keygens, but if you are curious how the codes actually are generated (like I was) feel free to take, use, and share this code at your will.</p>
]]></content:encoded>
			<wfw:commentRss>http://feisley.com/2009/09/26/blackberry-escreen-keygen/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Google Voice and Asterisk</title>
		<link>http://feisley.com/2009/07/29/google-voice-and-asterisk/</link>
		<comments>http://feisley.com/2009/07/29/google-voice-and-asterisk/#comments</comments>
		<pubDate>Wed, 29 Jul 2009 17:27:56 +0000</pubDate>
		<dc:creator>Jacob Feisley</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[asterisk]]></category>
		<category><![CDATA[Gizmo5]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[SIP]]></category>
		<category><![CDATA[voip]]></category>

		<guid isPermaLink="false">http://feisley.com/?p=3436</guid>
		<description><![CDATA[Many months back Paul Marks and I looked into how to integrate Google Voice and Asterisk. Inbound calling was simple as you direct your Google Voice account to a Gizmo5 number and Asterisk integrates with the open SIP standard that Gizmo5 uses.
However, our task was to be able to make outbound calls without the need [...]]]></description>
			<content:encoded><![CDATA[<p>Many months back <a href="http://pmarks.net">Paul Marks</a> and I looked into how to integrate Google Voice and Asterisk. Inbound calling was simple as you direct your Google Voice account to a Gizmo5 number and Asterisk integrates with the open SIP standard that Gizmo5 uses.</p>
<p>However, our task was to be able to make outbound calls without the need to use the web interface to place the call. What essentially had to happen is when you dialed a number on your SIP phone, Asterisk would have to talk to the Google Voice site and handle the call setup for you.</p>
<p><span id="more-3436"></span></p>
<p><strong>***UPDATE***: I worked with Ward Mundy of <a href="http://nerdvittles.com/">Nerd Vittles</a> who put togeather a complete solution for both Asterisk 1.4 and 1.6. Additionally we are now using<a href="http://code.google.com/p/pygooglevoice/"> pyGoogleVoice</a> which is a more complete library than Paul&#8217;s script below. For the full write up, check out: <a href="http://nerdvittles.com/?p=635">http://nerdvittles.com/?p=635</a></strong></p>
<p>Paul then created a Python AGI (Asterisk Gateway Interface) script. It integrates into your dial plan and allows for the call to be made. The logic flow is as follows:</p>
<ol>
<li>You pick up your SIP phone and make a call.</li>
<li>Asterisk receives your call and the google-voice-dialout.agi script is called.</li>
<li>The script contacts Google Voice and initiates a call based on the number passed to asterisk.</li>
<li>Google Voice then dials your Gizmo5 number which rings into Asterisk.</li>
<li>Asterisk identifies this call by its caller id and the script binds your outbound call and the incoming call from Google</li>
<li>Google proceeds to call out to your destination.</li>
<li>Call is connected!</li>
</ol>
<p>Now a few caveats to this approach. As Paul&#8217;s script is essentially<span style="text-decoration: line-through;"> screen scraping</span> using unpublished API&#8217;s to the Google Voice application, any changes made to their web API could break this script. (As he notes in the script comments) At any rate, at the time of writing it works and the script is available for download here, <a href="http://feisley.com/wp-content/uploads/2009/07/google-voice-dialout.agi">google-voice-dialout.agi</a>, or shown below for reference.</p>
<p>When I get some more time, I will post details how to integrate this into an Asterisk dialplan and other features.</p>
<p><br class="spacer_" /></p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># google-voice-dialout.agi</span>
<span style="color: #808080; font-style: italic;"># Paul Marks (http://pmarks.net)</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># This is an Asterisk 1.6 script to place outgoing calls through Google Voice.</span>
<span style="color: #808080; font-style: italic;"># It will automatically sign into the web interface, and submit a click2call</span>
<span style="color: #808080; font-style: italic;"># request through your registered Gizmo number.  Asterisk can then answer</span>
<span style="color: #808080; font-style: italic;"># the incoming call, and Bridge() it into your original outgoing call.</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># I deduced the click2call sequence by using the &quot;Live HTTP Headers&quot; Firefox</span>
<span style="color: #808080; font-style: italic;"># plugin.  If the website changes too much, this script will probably stop</span>
<span style="color: #808080; font-style: italic;"># working, so don't use it for anything too important.</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># This assumes you've already configured Asterisk to receive Gizmo calls.</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># This rule will redirect outbound calls to this script:</span>
<span style="color: #808080; font-style: italic;">#   exten =&gt; _1NXXNXXXXXX,1,AGI(google-voice-dialout.agi)</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># This rule will connect the inbound GV/Gizmo calls:</span>
<span style="color: #808080; font-style: italic;">#   exten =&gt; s/6502650000,1,Bridge(${DB_DELETE(gv_dialout/channel)}, p)</span>
<span style="color: #808080; font-style: italic;">#              ^-- Put your 10-digit Google Voice number here.</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;"># To test this script from the command line without Asterisk, type the</span>
<span style="color: #808080; font-style: italic;"># following.  Be sure to type a few linefeeds at the end:</span>
<span style="color: #808080; font-style: italic;">#</span>
<span style="color: #808080; font-style: italic;">#   $ ./google-voice-dialout.agi</span>
<span style="color: #808080; font-style: italic;">#   agi_channel:</span>
<span style="color: #808080; font-style: italic;">#   agi_dnid: 18004664411</span>
<span style="color: #808080; font-style: italic;">#</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Put your Google login and Gizmo number here:</span>
USERNAME = <span style="color: #483d8b;">&quot;username@gmail.com&quot;</span>
PASSWORD = <span style="color: #483d8b;">&quot;password&quot;</span>
GIZMO_NUMBER = <span style="color: #483d8b;">&quot;17475555555&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">httplib</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">urllib</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">re</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">sys</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">time</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Error<span style="color: black;">&#40;</span><span style="color: #008000;">Exception</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> ReadAgiEnvironment<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    env = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> <span style="color: #ff4500;">1</span>:
        line = <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdin</span>.<span style="color: #dc143c;">readline</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> line:
            <span style="color: #ff7700;font-weight:bold;">break</span>
        key, data = line.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">':'</span><span style="color: black;">&#41;</span>
        env<span style="color: black;">&#91;</span>key.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> = data.<span style="color: black;">strip</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> env
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> SendAgi<span style="color: black;">&#40;</span><span style="color: #dc143c;">cmd</span><span style="color: black;">&#41;</span>:
    <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">write</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;%s<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: #dc143c;">cmd</span><span style="color: black;">&#41;</span>
    <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdout</span>.<span style="color: black;">flush</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #dc143c;">sys</span>.<span style="color: black;">stdin</span>.<span style="color: #dc143c;">readline</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> SimpleCookieJar<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    cookie_re = <span style="color: #dc143c;">re</span>.<span style="color: #008000;">compile</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">&quot;(?i)set-cookie: (<span style="color: #000099; font-weight: bold;">\w</span>+)=([^;]+).*&quot;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">cookies</span> = <span style="color: black;">&#123;</span><span style="color: black;">&#125;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> addCookies<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, response<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">for</span> header <span style="color: #ff7700;font-weight:bold;">in</span> response.<span style="color: black;">msg</span>.<span style="color: black;">headers</span>:
            m = <span style="color: #008000;">self</span>.<span style="color: black;">cookie_re</span>.<span style="color: black;">match</span><span style="color: black;">&#40;</span>header<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> m:
                <span style="color: #ff7700;font-weight:bold;">continue</span>
            <span style="color: #008000;">self</span>.<span style="color: black;">cookies</span><span style="color: black;">&#91;</span>m.<span style="color: black;">group</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span> = m.<span style="color: black;">group</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">def</span> get<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">&quot;; &quot;</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;%s=%s&quot;</span> <span style="color: #66cc66;">%</span> kv <span style="color: #ff7700;font-weight:bold;">for</span> kv <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">self</span>.<span style="color: black;">cookies</span>.<span style="color: black;">iteritems</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> GVClickToCall<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    USER_AGENT = <span style="color: #483d8b;">&quot;google-voice-dialout.agi/1.1&quot;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> <span style="color: #0000cd;">__init__</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, username, password, via, dial<span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">username</span> = username
        <span style="color: #008000;">self</span>.<span style="color: black;">password</span> = password
        <span style="color: #008000;">self</span>.<span style="color: black;">via</span> = via
        <span style="color: #008000;">self</span>.<span style="color: black;">dial</span> = dial
        <span style="color: #008000;">self</span>.<span style="color: black;">cj</span> = SimpleCookieJar<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">h</span> = <span style="color: #dc143c;">httplib</span>.<span style="color: black;">HTTPSConnection</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;www.google.com&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">login</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">placeCall</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">logout</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> login<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #66cc66;">&gt;&gt;</span>sys.<span style="color: black;">stderr</span>, <span style="color: #483d8b;">&quot;Logging in.&quot;</span>
        postdata = <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span> <span style="color: #483d8b;">&quot;Email&quot;</span>: <span style="color: #008000;">self</span>.<span style="color: black;">username</span>,
                                      <span style="color: #483d8b;">&quot;Passwd&quot;</span>: <span style="color: #008000;">self</span>.<span style="color: black;">password</span> <span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">doRequest</span><span style="color: black;">&#40;</span>
            method=<span style="color: #483d8b;">&quot;POST&quot;</span>, url=<span style="color: #483d8b;">&quot;/accounts/ServiceLoginAuth&quot;</span>,
            body=postdata,
            headers=<span style="color: black;">&#123;</span> <span style="color: #483d8b;">&quot;Content-Type&quot;</span>: <span style="color: #483d8b;">&quot;application/x-www-form-urlencoded&quot;</span> <span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Start at https://www.google.com/voice, and collect cookies as we</span>
        <span style="color: #808080; font-style: italic;"># follow all the redirects.</span>
        PREFIX = <span style="color: #483d8b;">&quot;https://www.google.com/&quot;</span>
        location = <span style="color: #483d8b;">&quot;/voice&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">5</span><span style="color: black;">&#41;</span>:
            response, html = <span style="color: #008000;">self</span>.<span style="color: black;">doRequest</span><span style="color: black;">&#40;</span>
                method=<span style="color: #483d8b;">&quot;GET&quot;</span>, url=location,
                headers=<span style="color: black;">&#123;</span><span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
&nbsp;
            location = response.<span style="color: black;">getheader</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;location&quot;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> location:
                <span style="color: #808080; font-style: italic;"># No more redirects, yay!</span>
                <span style="color: #ff7700;font-weight:bold;">break</span>
&nbsp;
            <span style="color: #808080; font-style: italic;"># All redirects should fall within the same domain.</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> location.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span>PREFIX<span style="color: black;">&#41;</span>:
                <span style="color: #ff7700;font-weight:bold;">raise</span> Error<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Unexpected redirect: %s&quot;</span> <span style="color: #66cc66;">%</span> location<span style="color: black;">&#41;</span>
            location = location<span style="color: black;">&#91;</span><span style="color: #008000;">len</span><span style="color: black;">&#40;</span>PREFIX<span style="color: black;">&#41;</span>-<span style="color: #ff4500;">1</span>:<span style="color: black;">&#93;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Scrape magic _rnr_se value from the HTML.</span>
        m = <span style="color: #dc143c;">re</span>.<span style="color: black;">search</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'name=&quot;_rnr_se&quot; type=&quot;hidden&quot; value=&quot;([^&quot;]+)&quot;'</span>, html<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> m:
            <span style="color: #ff7700;font-weight:bold;">raise</span> Error<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Can't find _rnr_se.  Not logged in?&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">magic_rnr_se</span> = m.<span style="color: black;">group</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> placeCall<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #66cc66;">&gt;&gt;</span>sys.<span style="color: black;">stderr</span>, <span style="color: #483d8b;">&quot;Calling %s via %s&quot;</span> <span style="color: #66cc66;">%</span> <span style="color: black;">&#40;</span><span style="color: #008000;">self</span>.<span style="color: black;">dial</span>, <span style="color: #008000;">self</span>.<span style="color: black;">via</span><span style="color: black;">&#41;</span>
        postdata = <span style="color: #dc143c;">urllib</span>.<span style="color: black;">urlencode</span><span style="color: black;">&#40;</span><span style="color: black;">&#123;</span> <span style="color: #483d8b;">&quot;outgoingNumber&quot;</span>: <span style="color: #008000;">self</span>.<span style="color: black;">dial</span>,
                                      <span style="color: #483d8b;">&quot;forwardingNumber&quot;</span>: <span style="color: #008000;">self</span>.<span style="color: black;">via</span>,
                                      <span style="color: #483d8b;">&quot;_rnr_se&quot;</span>: <span style="color: #008000;">self</span>.<span style="color: black;">magic_rnr_se</span> <span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
        response, http = <span style="color: #008000;">self</span>.<span style="color: black;">doRequest</span><span style="color: black;">&#40;</span>
            method=<span style="color: #483d8b;">&quot;POST&quot;</span>, url=<span style="color: #483d8b;">&quot;/voice/call/connect&quot;</span>,
            body=postdata,
            headers=<span style="color: black;">&#123;</span> <span style="color: #483d8b;">&quot;Content-Type&quot;</span>: <span style="color: #483d8b;">&quot;application/x-www-form-urlencoded&quot;</span> <span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #66cc66;">&gt;&gt;</span>sys.<span style="color: black;">stderr</span>, <span style="color: #483d8b;">&quot;Dial response:&quot;</span>, http
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> logout<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #008000;">self</span>.<span style="color: black;">doRequest</span><span style="color: black;">&#40;</span>
            method=<span style="color: #483d8b;">&quot;GET&quot;</span>, url=<span style="color: #483d8b;">&quot;/accounts/Logout&quot;</span>,
            headers=<span style="color: black;">&#123;</span> <span style="color: #483d8b;">&quot;Connection&quot;</span>: <span style="color: #483d8b;">&quot;close&quot;</span> <span style="color: black;">&#125;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #66cc66;">&gt;&gt;</span>sys.<span style="color: black;">stderr</span>, <span style="color: #483d8b;">&quot;Logged out.&quot;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> doRequest<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, headers, <span style="color: #66cc66;">**</span>kw<span style="color: black;">&#41;</span>:
        headers<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;User-agent&quot;</span><span style="color: black;">&#93;</span> = <span style="color: #008000;">self</span>.<span style="color: black;">USER_AGENT</span>
        headers<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;Cookie&quot;</span><span style="color: black;">&#93;</span> = <span style="color: #008000;">self</span>.<span style="color: black;">cj</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">h</span>.<span style="color: black;">request</span><span style="color: black;">&#40;</span>headers=headers, <span style="color: #66cc66;">**</span>kw<span style="color: black;">&#41;</span>
        response = <span style="color: #008000;">self</span>.<span style="color: black;">h</span>.<span style="color: black;">getresponse</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
        <span style="color: #008000;">self</span>.<span style="color: black;">cj</span>.<span style="color: black;">addCookies</span><span style="color: black;">&#40;</span>response<span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> response, response.<span style="color: black;">read</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    env = ReadAgiEnvironment<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">print</span> <span style="color: #66cc66;">&gt;&gt;</span>sys.<span style="color: black;">stderr</span>, env
&nbsp;
    agi_channel = env<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;agi_channel&quot;</span><span style="color: black;">&#93;</span>
    agi_dnid = env<span style="color: black;">&#91;</span><span style="color: #483d8b;">&quot;agi_dnid&quot;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Write the channel ID to Asterisk's database, so it can be accessed</span>
    <span style="color: #808080; font-style: italic;"># by the incoming call when it arrives.</span>
    SendAgi<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;database put gv_dialout channel %s&quot;</span> <span style="color: #66cc66;">%</span> agi_channel<span style="color: black;">&#41;</span>
&nbsp;
    SendAgi<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;answer&quot;</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        GVClickToCall<span style="color: black;">&#40;</span>username=USERNAME, password=PASSWORD,
                      dial=agi_dnid, via=GIZMO_NUMBER<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Asterisk should patch in the incoming call while we're asleep.</span>
        <span style="color: #dc143c;">time</span>.<span style="color: black;">sleep</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">finally</span>:
        SendAgi<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;hangup&quot;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> __name__ == <span style="color: #483d8b;">'__main__'</span>:
    main<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://feisley.com/2009/07/29/google-voice-and-asterisk/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Kindle Books, without the Kindle&#8230;</title>
		<link>http://feisley.com/2009/03/05/kindle-books-without-the-kindle/</link>
		<comments>http://feisley.com/2009/03/05/kindle-books-without-the-kindle/#comments</comments>
		<pubDate>Thu, 05 Mar 2009 14:47:20 +0000</pubDate>
		<dc:creator>Jacob Feisley</dc:creator>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[drm]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[iPod]]></category>
		<category><![CDATA[kindle]]></category>
		<category><![CDATA[mobipocket]]></category>

		<guid isPermaLink="false">http://feisley.com/?p=2375</guid>
		<description><![CDATA[As everyone is well aware, Amazon has one of the largest eBook libraries available for sale. The only caveat to this was that you had to purchase their $350 Kindle / Kindle 2 Reader before you could take advantage of these books. All that has changed now with the release of the iPod/iPhone app for [...]]]></description>
			<content:encoded><![CDATA[<p>As everyone is well aware, Amazon has one of the largest eBook libraries available for sale. The only caveat to this was that you had to purchase their $350 Kindle / Kindle 2 Reader before you could take advantage of these books. All that has changed now with the release of the iPod/iPhone app for Kindle books. Now you can register your iPod or iPhone with Amazon and purchase Kindle books for it. But there is more&#8230; You can also manage to extract the purchased books from the iPod / iPhone and take off the DRM so you can use your book on any of your other readers.</p>
<p><span id="more-2375"></span></p>
<p><em>DISCLAIMER: Stripping DRM from eBooks treads heavily on the DMCA. Any instructions here should be considered to be for educational purposes only. Therefore you are responsible for how you use this information.</em></p>
<p>Here were the steps I followed to free my books from my iPod:</p>
<p><strong>Step 1</strong></p>
<p>First you need an iPod or iPhone. I find it is easiest and most cross-platform to use a jailbroken device as that makes this process all the easier.</p>
<p><strong>Step 2</strong></p>
<p>Install the Kindle app from the App Store</p>
<p><strong>Step 3</strong></p>
<p>When you open the app for the first time, you will be prompted for your Amazon.com username and password. Once you enter this your device will be registered and you can purchase books from the Amazon Kindle Book Store.</p>
<p><strong>Step 4</strong></p>
<p><em><strong>UPDATE</strong>: A</em><em>mazon has taken the &#8220;security by obscurity&#8221; route and removed the UUID from the website. You can still find it easily by connecting your iPod/iPhone to iTunes and when you see the Serial Number, click on the word &#8220;Serial Number&#8221; and it will change to &#8220;Identifier&#8221; this is the string you are looking for. Here is a picture for clarity.</em></p>
<p><strong><img class="alignnone size-full wp-image-2391" title="ipod-serial-uuid" src="http://feisley.com/wp-content/uploads/2009/03/ipod-serial-uuid.png" alt="ipod-serial-uuid" width="530" height="296" /><br />
 </strong></p>
<p><strong>Step 5</strong></p>
<p>Purchase your favorite book from the Store ;-) Your purchase will be automatically downloaded by the app once you are connected to the internet.</p>
<p><strong>Step 6</strong></p>
<p>This is the tricky part. Now that you have the books purchased and on your iPod/iPhone you will need to get them off. There are two routes here. A few folks over at <a href="http://mobileread.com">MobileRead.com</a> mentioned that you can use the <a href="http://supercrazyawesome.com/">iPhone Backup Extractor</a>, however, at this time it is only for Mac OS X.</p>
<p><em><strong>UPDATE</strong></em><em>: fugislider informed me there is also a <a href="http://www.reincubate.com/labs/iphone-backup-extractor-how-extract-files-iphone-backup-windows/">iPhone Backup Extractor version for Windows and Linux</a> you can use as well if you don&#8217;t want to jailbreak your device.</em></p>
<p>The better solution in my opinion is to use a jailbroken phone and copy the books direct from the device using SCP or similar mechanism. I wont go into the details of how to jailbreak or SCP files as that is covered by several other articles&#8230;</p>
<p>The eBooks are stored as .prc files which are DRM&#8217;d MobiPocket format. (Same as the Kindle, no surprises there) You can find all of them in this folder on the iPod / iPhone:</p>
<p><br class="spacer_" /></p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="" style="font-family:monospace;">/var/mobile/Applications/<span class="br0">&#123;</span>Appplication UUID<span class="br0">&#125;</span>/Documents/eBooks</pre></td></tr></table></div>

<p>There are also some .mbp files in the directory, which seem to be unneeded for extracting the books. Also note they have some crazy names that don&#8217;t appear to correlate to their actual title, so you will have to rely on software such as <a href="http://calibre.kovidgoyal.net/">Calibre</a> to read the headers and tell you what files you have.</p>
<p><strong>Step 7</strong></p>
<p>Well, there is no longer a Step 7. Sorry.</p>
<p>On March 11, I received notice from Amazon.com to remove the instructions relating to removal of the DRM from the books. I left the first 6 steps intact since they do not relate to breaking any portion of the DRM and are in full compliance with the DMCA. If you want to remove the DRM from these books you will have to find instructions elsewhere.</p>
<p><strong>The End!</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://feisley.com/2009/03/05/kindle-books-without-the-kindle/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>PyAMF 0.4</title>
		<link>http://feisley.com/2009/01/05/pyamf-04/</link>
		<comments>http://feisley.com/2009/01/05/pyamf-04/#comments</comments>
		<pubDate>Tue, 06 Jan 2009 04:56:28 +0000</pubDate>
		<dc:creator>Jacob Feisley</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[PyAMF]]></category>

		<guid isPermaLink="false">http://feisley.com/?p=2211</guid>
		<description><![CDATA[Well almost&#8230;
We just release PyAMF 0.4-RC2 yesterday! While it is not quite the final version, this is a huge step for the project and includes a ton of updates and features.
Some highlighted features include:

cPyAMF &#8211; An implementation of PyAMF serialization that results in tremendous speedups.
SQLAlchemy Adapter &#8211; Adapter for the popular Python Database ORM.
Improved Google [...]]]></description>
			<content:encoded><![CDATA[<p>Well almost&#8230;</p>
<p>We just release PyAMF 0.4-RC2 yesterday! While it is not quite the final version, this is a huge step for the project and includes a ton of updates and features.</p>
<p>Some highlighted features include:</p>
<ul>
<li>cPyAMF &#8211; An implementation of PyAMF serialization that results in tremendous speedups.</li>
<li>SQLAlchemy Adapter &#8211; Adapter for the popular Python Database ORM.</li>
<li>Improved Google AppEngine Adapter &#8211; makes deploying Flex/Flash apps on Google&#8217;s new service even easier.</li>
</ul>
<p>You can see our official announcement on the <a href="http://blog.pyamf.org/archives/pyamf-04rc2-released">PyAMF Blog</a>.</p>
<p>Currently PyAMF 0.4 is in the Release Candidate stage so we are testing and getting feedback. The release candidate and final version (when it is ready) are available for download <a href="http://pyamf.org/wiki/Download#Download">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://feisley.com/2009/01/05/pyamf-04/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google App Engine</title>
		<link>http://feisley.com/2008/04/08/google-app-engine/</link>
		<comments>http://feisley.com/2008/04/08/google-app-engine/#comments</comments>
		<pubDate>Wed, 09 Apr 2008 03:41:19 +0000</pubDate>
		<dc:creator>Jacob Feisley</dc:creator>
				<category><![CDATA[Google]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[App Engine]]></category>
		<category><![CDATA[PyAMF]]></category>

		<guid isPermaLink="false">http://feisley.com/?p=32</guid>
		<description><![CDATA[
Last night, Google launched App Engine which allows developers to create web applications and publish them on Google&#8217;s infrastructure. The exciting part of the App Engine in my eyes is that the language you use to develop on it is Python. Google provides many API&#8217;s to interface the Python programming language with the various services [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignnone size-thumbnail wp-image-33" title="Google App Engine" src="http://feisley.com/wp-content/uploads/2008/04/app-engine-150x150.png" alt="" width="150" height="150" /></p>
<p>Last night, Google launched <a href="http://appengine.google.com">App Engine</a> which allows developers to create web applications and publish them on Google&#8217;s infrastructure. The exciting part of the App Engine in my eyes is that the language you use to develop on it is Python. Google provides many API&#8217;s to interface the Python programming language with the various services they offer. You can authenticate via Google accounts, use Bigtable to store data, and use Google Aps to bind your application to your own domain. They opened the initial &#8220;Preview Release&#8221; to the first 10,000 developers to sign up. From the looks of it, those 10,000 spots filled up within the first few hours of the launch.</p>
<p>I was fortunate to be one of the first to sign up and got my account last night. I created a basic hello world application to test and overall the system seems very easy to use. My demo is at <a href="http://labs.appspot.com">http://labs.appspot.com</a>.</p>
<p>I also created an account for the <a href="http://pyamf.org">PyAMF</a> project and we were able to get a PyAMF echo server running on App Engine. It is currently located at: <a href="http://ae.pyamf.org">http://ae.pyamf.org</a> We are continuing to work with it today and tomorrow to write up some examples and a How-to to get people started quickly. We will continue to add more examples to the site as time progresses and we get everything documented.</p>
]]></content:encoded>
			<wfw:commentRss>http://feisley.com/2008/04/08/google-app-engine/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Hydra Preview</title>
		<link>http://feisley.com/2008/04/01/hydra-preview/</link>
		<comments>http://feisley.com/2008/04/01/hydra-preview/#comments</comments>
		<pubDate>Tue, 01 Apr 2008 19:06:34 +0000</pubDate>
		<dc:creator>Jacob Feisley</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[Hydra Labs]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Hydra]]></category>
		<category><![CDATA[PyAMF]]></category>
		<category><![CDATA[RIA]]></category>
		<category><![CDATA[Twisted]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://feisley.com/?p=29</guid>
		<description><![CDATA[With the public announcement of Hydra EMS being announced any day now, I thought I would give those of you that have been following its development a sneak preview of the UI and some of the new features we have added recently.

The most noticeable addition to Hydra recently has been the addition of the Flex [...]]]></description>
			<content:encoded><![CDATA[<p>With the public announcement of Hydra EMS being announced any day now, I thought I would give those of you that have been following its development a sneak preview of the UI and some of the new features we have added recently.</p>
<p><span id="more-29"></span></p>
<p>The most noticeable addition to Hydra recently has been the addition of the Flex UI. <a href="http://www.adobe.com/go/flex">Flex</a> is an open source Flash framework from Adobe that allows for rapid development of Rich Internet Applications (RIAs). Behind the Flex UI is the powerful <a href="http://twistedmatrix.com">Twisted</a> framework that powers the data back end. Communication between Flex and Twisted is handled by the <a href="http://pyamf.org/">PyAMF</a> library. PyAMF is an implementation of Adobe&#8217;s Action Message Format (AMF) for Python. This library allows for data to be exchanged in a binary form which is many times faster than the traditional XML mechanism.</p>
<p>Enough talk, lets get to the show! Here is a shot of the CPE LiveGrid module from Hydra. LiveGrid handles adding, searching, modifying, and deleting of CPE&#8217;s and assets withing the system. This module was originally based on an XML API, however, after changing to PyAMF speeds over doubled when running:</p>
<p><a href="http://feisley.com/wp-content/uploads/2008/04/live_grid.png"><img class="alignnone size-full wp-image-30" title="CPE LiveGrid" src="http://feisley.com/wp-content/uploads/2008/04/live_grid.png" alt="Hydra CPE LiveGrid" width="500" height="276" /></a></p>
<p>The second example here is of the CPE LiveDiag module. This allows for real time graphing and analysis of a CPE&#8217;s performance in the network and will allow network administrators to make faster diagnostics when problems occur. This module was also a port from its original XML interface to the PyAMF library:</p>
<p><a href="http://feisley.com/wp-content/uploads/2008/04/live_diag.png"><img class="alignnone size-full wp-image-31" title="CPE LiveDiag" src="http://feisley.com/wp-content/uploads/2008/04/live_diag.png" alt="Hydra CPE LiveGrid" width="500" height="276" /></a></p>
<p>These are just a few of the new interfaces coming in the release of Hydra EMS.</p>
]]></content:encoded>
			<wfw:commentRss>http://feisley.com/2008/04/01/hydra-preview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PyAMF</title>
		<link>http://feisley.com/2008/02/21/pyamf/</link>
		<comments>http://feisley.com/2008/02/21/pyamf/#comments</comments>
		<pubDate>Fri, 22 Feb 2008 02:45:35 +0000</pubDate>
		<dc:creator>Jacob Feisley</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[AMF]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[PyAMF]]></category>
		<category><![CDATA[Pylons]]></category>
		<category><![CDATA[Twisted]]></category>

		<guid isPermaLink="false">http://feisley.com/?p=3</guid>
		<description><![CDATA[
Back in January I discovered the PyAMF project. This project&#8217;s goal is to create an implementation of AMF (Action Message Format) for the Python Programming language. Last week they released version 0.1.0, their first stable release.
So far, I have been extremely impressed with this project. The library offers integration with popular Python web frameworks including [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://feisley.com/wp-content/uploads/2008/02/pyamf4.jpg" alt="PyAMF Logo" /></p>
<p>Back in January I discovered the <a href="http://pyamf.org">PyAMF project</a>. This project&#8217;s goal is to create an implementation of AMF (Action Message Format) for the <a href="http://python.org">Python</a> Programming language. Last week they released version 0.1.0, their first stable release.</p>
<p>So far, I have been extremely impressed with this project. The library offers integration with popular Python web frameworks including Twisted, Django, and Pylons. The performance is excellent and will only improve as the team intends to annex their Python code, with C for faster serialization of requests. In addition to an excellent library, the developers have also provided a number of <a href="http://pyamf.org/wiki/Examples">examples</a> which attempt to cover every major area of the library. I have already begun using it in various projects including Hydra, which will be released this month.</p>
<p>Look for more info and updates on the PyAMF project in the coming weeks.</p>
]]></content:encoded>
			<wfw:commentRss>http://feisley.com/2008/02/21/pyamf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

