<?xml version="1.0"?>
<rss version="2.0">
<channel>
    <title>Kirby T @thecave.com</title>
    <link>http://www.thecave.com/</link>
    <description>A collection of various ramblings on technology, life in Salem, and other useless topics.</description>
    <language>en-US</language>
    <copyright>Copyright 2005-2008 Kirby Turner</copyright>
    <generator>IP*Works! Version 6.0 RSS Component</generator>
    <item>
      <title>RAD Studio 2009 Is Coming</title>
      <description>&lt;div style=&quot;clear:both;&quot;&gt;&lt;/div&gt;I feel smart at the moment.  Or maybe &quot;wise&quot; is the better word.&lt;br /&gt;&lt;br /&gt;I subscribed to the Delphi RAD Studio Professional SA during a special pricing for the pre-order of 2007.  I pay $399 a year (plus or minus a few dollars - I don&apos;t remember the exact amount I pay each year).  I noticed the upgrade from 2007 to 2009 costs $624.  Assuming CodeGear continues the trend started in 2007 I should save more bones over time and stay current.  I like it when I feel like I have a good deal.&lt;br /&gt;&lt;br /&gt;Have you read about the new managed code version of Delphi called Prism?  It&apos;s actually not new.  It&apos;s RemObject&apos;s Oxygen compiler for Visual Studio.  I&apos;m actually looking forward to playing with this.  I was always interested in RemObject&apos;s Chrome (renamed to Oxygen earlier this year) but didn&apos;t want to spend the money.  But since it is included as part of RAD Studio I get it for no additional cost.&lt;br /&gt;&lt;br /&gt;Doubt I&apos;ll ever really use it.  I don&apos;t see converting my &lt;a href=&quot;http://www.whitepeaksoftware.com/killink-csv.aspx&quot;&gt;csv file editor&lt;/a&gt; to manage code and I doubt customers are not going to ask me to write their .NET apps in Object Pascal, though I do prefer Delphi programming over C#.  Also, I&apos;m moving my personal web sites to python, my new favorite scripting / programming language.  [Side note: I&apos;m starting to do more and more with python.  Mostly prototyping algorithms but I do have one program that &lt;a href=&quot;http://code.google.com/p/appdailysales/&quot;&gt;downloads daily sales reports for iPhone developers&lt;/a&gt; hosted at Google Code.  The program has been picked up and included in another open source project.  It&apos;s been fun to do.]&lt;br /&gt;&lt;br /&gt;So I&apos;m excited to play with Prism but honestly it&apos;s about 2 years too late for CodeGear in my opinion.  At least 2 years too late for me.  And even though RemObject&apos;s Chrome was available 2 years ago I didn&apos;t see spending the additional money on it at that time.  Still, I might use it to play with SilverLight.  Unlike CodeGear/Borland&apos;s past .NET attempts, Prism fully supports the latest .NET frameworks, libraries, and technologies coming out of Redmond.  Oh, and Mono too.  Though right now I will probably use python if I need to write something cross platform.&lt;div style=&quot;clear:both; padding-bottom:0.25em&quot;&gt;&lt;/div&gt;</description>
      <link>http://www.thecave.com/archive/2008/11/18/rad_studio_2009_is_coming.aspx</link>
      <author>Kirby</author>
      <pubDate>Tue, 18 Nov 2008 14:18:00 GMT</pubDate>
      <guid>178026256569928826</guid>
    </item>
    <item>
      <title>Hiking the Long Trail Division 1</title>
      <description>&lt;div style=&quot;clear:both;&quot;&gt;&lt;/div&gt;&lt;a href=&quot;http://photos.thecave.com/gallery/6462530_g93i8/1/409902560_U4g2h&quot;&gt;&lt;img src=&quot;http://photos.thecave.com/photos/409902136_ypvrA-Th.jpg&quot; align=&quot;left&quot; height=150 width=150 border=0 vspace=6 hspace=6&gt;&lt;/a&gt;Last month Shawn and I hiked Division 1 of the Long Trail.  The hike was mostly enjoyable - we had to cut the trip short which meant hiking in the dark with pouring rain and high winds.  That part was not enjoyable.  But the trail is clearly marked making the night hike easier than expect.&lt;br /&gt;&lt;br /&gt;Here are &lt;a href=&quot;http://photos.thecave.com/gallery/6462530_g93i8/1/409902560_U4g2h&quot;&gt;pictures&lt;/a&gt; from the trip.  If I have more time in the near future I will blog more about the trip.&lt;div style=&quot;clear:both; padding-bottom:0.25em&quot;&gt;&lt;/div&gt;</description>
      <link>http://www.thecave.com/archive/2008/11/11/hiking_the_long_trail_division_1.aspx</link>
      <author>Kirby</author>
      <pubDate>Tue, 11 Nov 2008 15:20:00 GMT</pubDate>
      <guid>487374699205076767</guid>
    </item>
    <item>
      <title>Halloween Pictures</title>
      <description>&lt;div style=&quot;clear:both;&quot;&gt;&lt;/div&gt;&lt;a href=&quot;http://photos.thecave.com/gallery/6426513_iFAfa//407100695_5YdnY&quot;&gt;&lt;img src=&quot;http://photos.thecave.com/photos/407101081_589Wo-Th.jpg&quot; vspace=6 hspace=6 align=&quot;left&quot; border=0 width=150 height=150&gt;&lt;/a&gt;Here are &lt;a href=&quot;http://photos.thecave.com/gallery/6426513_iFAfa//407100695_5YdnY&quot;&gt;pictures&lt;/a&gt; from our Halloween night in Salem.  Enjoy.&lt;div style=&quot;clear:both; padding-bottom:0.25em&quot;&gt;&lt;/div&gt;</description>
      <link>http://www.thecave.com/archive/2008/11/01/halloween_pictures.aspx</link>
      <author>Kirby</author>
      <pubDate>Sat, 01 Nov 2008 16:04:00 GMT</pubDate>
      <guid>8351473611192643952</guid>
    </item>
    <item>
      <title>Hug a Developer</title>
      <description>&lt;div style=&quot;clear:both;&quot;&gt;&lt;/div&gt;There are times when it is tough being a developer.  But you can help make a difference in a developer&apos;s life by simply giving him or her a hug.  &lt;br /&gt;&lt;br /&gt;Here&apos;s a great video by DevShop that shares some of the pains we developers go through on a regular basis.  Watch the video then give a developer a hug.&lt;br /&gt;&lt;br /&gt;&lt;embed src=&quot;http://blip.tv/play/gYwjwZJqjdEh&quot; type=&quot;application/x-shockwave-flash&quot; width=&quot;540&quot; height=&quot;320&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/embed&gt;&lt;div style=&quot;clear:both; padding-bottom:0.25em&quot;&gt;&lt;/div&gt;</description>
      <link>http://www.thecave.com/archive/2008/10/23/hug_a_developer.aspx</link>
      <author>Kirby</author>
      <pubDate>Fri, 24 Oct 2008 02:55:00 GMT</pubDate>
      <guid>6861995831944265039</guid>
    </item>
    <item>
      <title>Download iTunes Connect Sales Reports Using Python</title>
      <description>&lt;div style=&quot;clear:both;&quot;&gt;&lt;/div&gt;Apple publishes daily sales figures on their iTunes Connect website for software vendors who have applications for sale in the iPhone App Store.  I&apos;ve been making a point to download the daily file each morning but I know I cannot continue doing this manually.  What I need is an automated way to download the daily file.&lt;br /&gt;&lt;br /&gt;I searched the net for script code that will download the iTunes Connect daily sales report but I came up empty.  So I decided to write my own.&lt;br /&gt;&lt;br /&gt;I&apos;ve been interested in getting into Python programming and I thought what better way to learn Python programming than to write a script that will download the daily sales report from the iTunes Connect website.  It turned out to be a fairly easy task to complete using Python.  Guess it goes to show how powerful Python really is.&lt;br /&gt;&lt;br /&gt;So here is my very first Python script.  I&apos;m sure there are things I could do better in the script, but hey, it&apos;s my first script.  Enjoy.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:red;&quot;&gt;UPDATE:&lt;/span&gt; The original code had a problem with retaining cookies set by the iTunes Connect website. The code below has been updated with the correct, working code.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color:red;&quot;&gt;UPDATE 2:&lt;/span&gt; The Python script below is now hosted over at Google.  Just click &lt;a href=&quot;http://code.google.com/p/appdailysales/source/browse/trunk/appdailysales.py&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class=&quot;code&quot;&gt;&lt;br /&gt;#!/usr/bin/python&lt;br /&gt;#&lt;br /&gt;# appdailysales.py&lt;br /&gt;#&lt;br /&gt;# iTune Connect Daily Sales Reports Downloader&lt;br /&gt;# Copyright 2008 Kirby Turner&lt;br /&gt;#&lt;br /&gt;#&lt;br /&gt;# This script will download yesterday&apos;s daily sales report from&lt;br /&gt;# the iTunes Connect web site.  The downloaded file is stored&lt;br /&gt;# in the same directory containing the script file.  Note: if&lt;br /&gt;# the download file already exists then it will be overwritten.&lt;br /&gt;#&lt;br /&gt;# The iTunes Connect web site has dynamic urls and form field&lt;br /&gt;# names.  In other words, these values change from session to&lt;br /&gt;# session.  So to get to the download file we must navigate  &lt;br /&gt;# the site and webscrape the pages.  Joy, joy.&lt;br /&gt;#&lt;br /&gt;#&lt;br /&gt;# Permission is hereby granted, free of charge, to any person obtaining a copy&lt;br /&gt;# of this software and associated documentation files (the &quot;Software&quot;), to deal&lt;br /&gt;# in the Software without restriction, including without limitation the rights&lt;br /&gt;# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell&lt;br /&gt;# copies of the Software, and to permit persons to whom the Software is&lt;br /&gt;# furnished to do so, subject to the following conditions:&lt;br /&gt;# &lt;br /&gt;# The above copyright notice and this permission notice shall be included in&lt;br /&gt;# all copies or substantial portions of the Software.&lt;br /&gt;# &lt;br /&gt;# THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR&lt;br /&gt;# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,&lt;br /&gt;# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE&lt;br /&gt;# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER&lt;br /&gt;# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,&lt;br /&gt;# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN&lt;br /&gt;# THE SOFTWARE.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# -- Change the following to match your credentials --&lt;br /&gt;appleId = &apos;Your Apple Id&apos;&lt;br /&gt;password = &apos;Your Password&apos;&lt;br /&gt;# ----------------------------------------------------&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;import urllib&lt;br /&gt;import urllib2&lt;br /&gt;import cookielib&lt;br /&gt;import datetime&lt;br /&gt;import re&lt;br /&gt;&lt;br /&gt;urlWebsite = &apos;https://itunesconnect.apple.com/WebObjects/iTunesConnect.woa&apos;&lt;br /&gt;urlActionLogin = &apos;https://itunesconnect.apple.com%s&apos;&lt;br /&gt;urlActionSalesReport = &apos;https://itunesconnect.apple.com%s&apos;&lt;br /&gt;&lt;br /&gt;print &apos;-- begin script --&apos;&lt;br /&gt;&lt;br /&gt;# There is an issue with Python 2.5 where it assumes the &apos;version&apos;&lt;br /&gt;# cookie value is always interger.  However, itunesconnect.apple.com&lt;br /&gt;# returns this value as a string, i.e., &quot;1&quot; instead of 1.  Because&lt;br /&gt;# of this we need a workaround that &quot;fixes&quot; the version field.&lt;br /&gt;#&lt;br /&gt;# More information at: http://bugs.python.org/issue3924&lt;br /&gt;class MyCookieJar(cookielib.CookieJar):&lt;br /&gt; def _cookie_from_cookie_tuple(self, tup, request):&lt;br /&gt;  name, value, standard, rest = tup&lt;br /&gt;  version = standard.get(&apos;version&apos;, None)&lt;br /&gt;  if version is not None:&lt;br /&gt;   version = version.replace(&apos;&quot;&apos;, &apos;&apos;)&lt;br /&gt;   standard[&quot;version&quot;] = version&lt;br /&gt;  return cookielib.CookieJar._cookie_from_cookie_tuple(self, tup, request)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def showCookies(cj):&lt;br /&gt; for index, cookie in enumerate(cj):&lt;br /&gt;  print index, &apos; : &apos;, cookie&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;cj = MyCookieJar();&lt;br /&gt;opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Go to the iTunes Connect website and retrieve the&lt;br /&gt;# form action for logging into the site.&lt;br /&gt;urlHandle = opener.open(urlWebsite)&lt;br /&gt;html = urlHandle.read()&lt;br /&gt;match = re.search(&apos;action=&quot;(.*)&quot;&apos;, html)&lt;br /&gt;urlActionLogin = urlActionLogin % match.group(1)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Login to iTunes Connect web site and retrieve the&lt;br /&gt;# link to the sales report page.&lt;br /&gt;webFormLoginData = urllib.urlencode({&apos;theAccountName&apos;:appleId, &apos;theAccountPW&apos;:password})&lt;br /&gt;urlHandle = opener.open(urlActionLogin, webFormLoginData)&lt;br /&gt;html = urlHandle.read()&lt;br /&gt;match = re.search(&apos;href=&quot;(/WebObjects/iTunesConnect.woa/wo/.*)&quot;&amp;gt;&amp;lt;img&apos;, html)&lt;br /&gt;urlActionSalesReport = urlActionSalesReport % match.group(1)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Go to the sales report page, get the form action url and&lt;br /&gt;# form fields.  Note the sales report page will actually&lt;br /&gt;# load a blank page that redirects to the static URL. Best&lt;br /&gt;# guess here is that the server is setting some session&lt;br /&gt;# variables or something.&lt;br /&gt;urlHandle = opener.open(urlActionSalesReport)&lt;br /&gt;urlHandle = opener.open(&apos;https://itts.apple.com/cgi-bin/WebObjects/Piano.woa&apos;)&lt;br /&gt;html = urlHandle.read()&lt;br /&gt;match = re.findall(&apos;action=&quot;(.*)&quot;&apos;, html)&lt;br /&gt;urlDownload = &quot;https://itts.apple.com%s&quot; % match[1]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Get the form field names needed to download the report.&lt;br /&gt;match = re.findall(&apos;name=&quot;(.*?)&quot;&apos;, html)&lt;br /&gt;fieldNameReportType = match[3]&lt;br /&gt;fieldNameReportPeriod = match[4]&lt;br /&gt;fieldNameDayOrWeekSelection = match[6]&lt;br /&gt;fieldNameSubmitTypeName = match[7]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Ah...more fun.  We need to post the page with the form&lt;br /&gt;# fields collected so far.  This will give us the remaining&lt;br /&gt;# form fields needed to get the download file.&lt;br /&gt;webFormSalesReportData = urllib.urlencode({fieldNameReportType:&apos;Summary&apos;, fieldNameReportPeriod:&apos;Daily&apos;, fieldNameDayOrWeekSelection:&apos;Daily&apos;, fieldNameSubmitTypeName:&apos;ShowDropDown&apos;})&lt;br /&gt;urlHandle = opener.open(urlDownload, webFormSalesReportData)&lt;br /&gt;html = urlHandle.read()&lt;br /&gt;match = re.findall(&apos;action=&quot;(.*)&quot;&apos;, html)&lt;br /&gt;urlDownload = &quot;https://itts.apple.com%s&quot; % match[1]&lt;br /&gt;match = re.findall(&apos;name=&quot;(.*?)&quot;&apos;, html)&lt;br /&gt;fieldNameDayOrWeekDropdown = match[5]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Set report date to yesterday&apos;s date.  This will be the most&lt;br /&gt;# recent daily report available.  Another option would be to&lt;br /&gt;# webscrape the dropdown list of available report dates and&lt;br /&gt;# select the first item but setting the date to yesterday&apos;s&lt;br /&gt;# date is easier.&lt;br /&gt;today = datetime.date.today() - datetime.timedelta(1)&lt;br /&gt;reportDate = &apos;%i/%i/%i&apos; % (today.month, today.day, today.year)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# And finally...we&apos;re ready to download yesterday&apos;s sales report.&lt;br /&gt;webFormSalesReportData = urllib.urlencode({fieldNameReportType:&apos;Summary&apos;, fieldNameReportPeriod:&apos;Daily&apos;, fieldNameDayOrWeekDropdown:reportDate, fieldNameDayOrWeekSelection:&apos;Daily&apos;, fieldNameSubmitTypeName:&apos;Download&apos;})&lt;br /&gt;urlHandle = opener.open(urlDownload, webFormSalesReportData)&lt;br /&gt;filename = urlHandle.info().getheader(&apos;content-disposition&apos;).split(&apos;=&apos;)[1]&lt;br /&gt;filebuffer = urlHandle.read()&lt;br /&gt;urlHandle.close()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;print &apos; saving download file:&apos;, filename&lt;br /&gt;downloadFile = open(filename, &apos;w&apos;)&lt;br /&gt;downloadFile.write(filebuffer)&lt;br /&gt;downloadFile.close()&lt;br /&gt;&lt;br /&gt;print &apos;-- end of script --&apos;&lt;br /&gt;&lt;/pre&gt;&lt;div style=&quot;clear:both; padding-bottom:0.25em&quot;&gt;&lt;/div&gt;</description>
      <link>http://www.thecave.com/archive/2008/10/21/download_itunes_connect_sales_reports_using_python.aspx</link>
      <author>Kirby</author>
      <pubDate>Tue, 21 Oct 2008 17:50:00 GMT</pubDate>
      <guid>3769193385402891271</guid>
    </item>
    <item>
      <title>Lake Champlain Trip</title>
      <description>&lt;div style=&quot;clear:both;&quot;&gt;&lt;/div&gt;&lt;a href=&quot;http://photos.thecave.com/gallery/6203903_Hjvb9//391084401_CxMoY&quot;&gt;&lt;img src=&quot;http://photos.thecave.com/photos/391078189_x9RZo-Th.jpg&quot; width=150 height=150 border=0 alt=&quot;&quot;&gt;&lt;/a&gt;&lt;br /&gt;Here are &lt;a href=&quot;http://photos.thecave.com/gallery/6203903_Hjvb9//391084401_CxMoY&quot;&gt;pictures&lt;/a&gt; from our recent Lake Champlain trip with the Davis Clan.&lt;div style=&quot;clear:both; padding-bottom:0.25em&quot;&gt;&lt;/div&gt;</description>
      <link>http://www.thecave.com/archive/2008/10/10/lake_champlain_trip.aspx</link>
      <author>Kirby</author>
      <pubDate>Sat, 11 Oct 2008 03:10:00 GMT</pubDate>
      <guid>61142582060871701</guid>
    </item>
    <item>
      <title>Pictures from Recent Memphis Trip</title>
      <description>&lt;div style=&quot;clear:both;&quot;&gt;&lt;/div&gt;&lt;a href=&quot;http://photos.thecave.com/gallery/6199421_uQ27H//390879652_W8Ys8&quot;&gt;&lt;img src=&quot;http://photos.thecave.com/photos/390878752_rPELm-Th.jpg&quot; width=150 height=150 border=0 alt=&quot;&quot;&gt;&lt;/a&gt;&lt;br /&gt;I finally got around to posting &lt;a href=&quot;http://photos.thecave.com/gallery/6199421_uQ27H//390879652_W8Ys8&quot;&gt;pictures from our July trip to Memphis&lt;/a&gt;.  Well, Memphis, Jackson TN, and Olive Branch MS.  Fun times.  Fun times.&lt;div style=&quot;clear:both; padding-bottom:0.25em&quot;&gt;&lt;/div&gt;</description>
      <link>http://www.thecave.com/archive/2008/10/10/pictures_from_recent_memphis_trip.aspx</link>
      <author>Kirby</author>
      <pubDate>Fri, 10 Oct 2008 20:43:00 GMT</pubDate>
      <guid>3567812105491413101</guid>
    </item>
    <item>
      <title>Pictures from Dave, Lexi, and Lucy&apos;s Visit</title>
      <description>&lt;div style=&quot;clear:both;&quot;&gt;&lt;/div&gt;&lt;a href=&quot;http://photos.thecave.com/gallery/6192840_TuCdM//390539128_zL4DS&quot;&gt;&lt;img src=&quot;http://thecave.smugmug.com/photos/390537873_LRTQw-Th.jpg&quot; width=150 height=150 border=0 vspace=6 hspace=6&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;http://photos.thecave.com/gallery/6192840_TuCdM//390539128_zL4DS&quot;&gt;Pictures&lt;/a&gt; from Dave, Lexi, and Lucy&apos;s Salem visit in September 2008.&lt;div style=&quot;clear:both; padding-bottom:0.25em&quot;&gt;&lt;/div&gt;</description>
      <link>http://www.thecave.com/archive/2008/10/09/pictures_from_dave_lexi_and_lucys_visit.aspx</link>
      <author>Kirby</author>
      <pubDate>Fri, 10 Oct 2008 04:04:00 GMT</pubDate>
      <guid>924239507390459308</guid>
    </item>
    <item>
      <title>Wedding Pictures</title>
      <description>&lt;div style=&quot;clear:both;&quot;&gt;&lt;/div&gt;&lt;a href=&quot;http://photos.thecave.com/gallery/6192603_d997M//390526002_eeLnF&quot;&gt;&lt;img src=&quot;http://photos.thecave.com/photos/390526002_eeLnF-Th.jpg&quot; width=150 height=150 border=0 alt=&quot;&quot; vspace=&quot;6&quot; hspace=&quot;6&quot;&gt;&lt;/a&gt;&lt;br /&gt;Fun &lt;a href=&quot;http://photos.thecave.com/gallery/6192603_d997M//390526002_eeLnF&quot;&gt;pictures&lt;/a&gt; from Laura and Jason&apos;s wedding.&lt;div style=&quot;clear:both; padding-bottom:0.25em&quot;&gt;&lt;/div&gt;</description>
      <link>http://www.thecave.com/archive/2008/10/09/wedding_pictures.aspx</link>
      <author>Kirby</author>
      <pubDate>Fri, 10 Oct 2008 03:56:00 GMT</pubDate>
      <guid>1264816462936681301</guid>
    </item>
  </channel>
</rss>
