MySQLdb under OS X Leopard

•June 29, 2010 • Leave a Comment

Stubbed my toe on this earlier today: The MySQLdb adapter must be compiled using the same architecture as the python you want to use it with. OS X Leopard ships with 32-bit Python, so to install it I had to manually set ARCHFLAGS=”-arch i386″ before building.

Also, for some reason clean did not empty the build directories. If you see a very short build (i.e. no compiler messages), manually clear the ./build directory.

Improving the FB developer ecosystem

•May 31, 2010 • Leave a Comment

Facebook and its third-party developers have certainly had their conflicts, and I admire facebook for attempting to herd such a wild bunch of cats. Still, there are some minor features that could significantly improve the developer experience AND the quality of user statistics facebook is able to gather. Facebook desires true user statistics — what user behavior is by demographic, for instance. Facebook has made it known that it does not want developers to link their developer accounts to “real” accounts, and its recent moves to “auto-correct” email addresses that are close matches to known email addresses has presented a burden to developers that follow an account–1@mail.net, account–2@mail.net, etc pattern.

I would love to see Facebook designate developer accounts and integrate these into the app development interface. Facebook users that have the developer application installed, should be able to create new developer accounts from within the developer app. These special developer accounts would only be friend-able with other developer accounts, and would allow easy account switching from within the Facebook chrome. These accounts would have auto-generated passwords and derivative email address (e.g. original–fbdev1@originalmail.com) and that can be used to recreate the conventional log-in experience.

Facebook would get clean user statistics by delineating a clear fake-account population, and developers would have an easy way to manage their various developer personas when developing multi-user experiences.

As f8 has it, FB seems to hate map-reduce

•April 22, 2010 • Leave a Comment

With the new Facebook Connect API, a lot of cool things are possible — updating a user’s profile metadata (such as favorite books or movies), simplification of authentication and simpler permissions, but there has been one major step back that I haven’t heard much about.

It used to be possible (and still is, using the old APIs) to simply request all of a users’ friends, including their favorite movies, music, books, etc. This is powerful: For example, if you are planning a party using FB invites, and Pandora uses the FB Connect API, Pandora could make two calls to get the list of confirmed attendees’, and another to get the attendee’s favorite music — and generate a playlist that features at least some of their favorite tunes.

In the graph API, music is a ‘connection’ between users, and there’s no obvious way to query for connections for a set of users. So instead of two calls, it’s one call to get the list of attendees, and N calls to get the favorite artists for N attendees.

I understand if FB wants to simplify their API to reduce their computational cost, but doing what’s effectively map-reduce makes more sense on the side where the data is available locally, all other things being equal.

I’d love to get their official stance on this, but the FB Dev Forums are effectively down: The FB Connect button doesn’t respond, and a manual registration leads to a “could not open socket” 500 error.

Using onKeyDown to check for form submission is bad, mmk?

•March 4, 2009 • Leave a Comment

Virgin America ScreencapI’m a big fan of AJAX submission of forms. Recently I’ve gotten lazy and omitted the FORM tag for single (and dual) input interfaces, instead checking for enter-keypress form submission using the onKeyDown event on my form elements.

This lazyness is now biting me in the butt when using Virgin America, Washington Mutual, and many other commercial sites. When the user is entering text into a text input element, many browsers present a pull-down menu of previous inputs for similar fields.

Using latest FireFox on OS X, the enter event on the browser’s drop down menu is propagated to the HTML input element. Although I pressed enter in the context of a browser interface component, the event is propagated to the page element, where it triggers form submission.

Lesson learned: Always use onsubmit on your surrounding form element. Don’t have a form element? You might be unpleasantly surprised that IE6 will create one for you, using all input elements on the page as form elements and the page’s URL as the POST destination. Remove ambiguity, remove fail.

New Challenge: ID3v2.4 autotagging w/ cover art in Python

•March 4, 2009 • 2 Comments

I’ve been ripping my CDs into directories for years, mostly keeping an Artist / Album structure. This has worked for almost a decade, as I’d invariably use a folder-based browser to choose music to listen to. I’ve recently migrated to using Apple products, including iTunes, and am missing out on a good portion of my archived music collection. I could go through the albums by hand, but would prefer a scalable solution.

Existing tools:

Mutagen: http://code.google.com/p/quodlibet/wiki/Mutagen
Reads and writes ID3v2 and parses ID3v2.4 tags. Well-documented, clean code. I have not seen any code samples for writing the frame that holds the image, but this seems to be the best library out. If it doesn’t support it out of the box, it’d provide a great starting point for the feature.

FreeDB: http://www.freedb.org/
FreeDB is the public-domain offshoot of CDDB, a database of CD-media information (metadata). People add CDs into the system by scanning the CD and entering the Artist/Album/Tracks/etc by hand. CDDB then matches the starting/ending times of the individual tracks to the information provided by the user, and the next person who scans their CD gets that information for free. Although CDDB was bought by Gracenote, the user-contributed information continues to be available through FreeDB.

Pymad and MAD: http://spacepants.org/src/pymad/ and http://www.underbit.com/products/mad/
Mpeg Audio Decoder and Python interface. Although I’m not terribly interested in playing MP3 files at the moment, this lets me measure the start and end times of each track. Since I ripped the tracks in full, I retrieve the album metadata using FreeDB.

My own directory parsing code: http://github.com/philippp/albumparser/tree/master
Parses a directory tree for groups of audio files and tries to infer Artist – Album information from the directory names.

Strategy:

Use my directory parser and mutagen to determine which albums need tagging
Use pymad and freedb to retrieve neccessary metadata
Use Amazon to retrieve cover art where available
Use mutagen to write new metadata

Day 7: User-side walkthrough

•June 22, 2007 • 2 Comments

The home view of the application presents two lists: People that are employed by Basecamp-account-owner company are shown on the left; Projects that exist in basecamp are listed on the right. Both lists have a special column that presents the link “View Time” for every row.

step-1_cropped.png
The “View Time” link triggers a view showing detailed time information for the selected row. If the user clicks on “View Time” for a Person, the total hours logged on each date, against each project is presented as a line graph. Each line (data series) represents one Project on which the person worked, and dates increase along the x-axis. The sum of hours logged is shown along the Y-axis.

A list of all timeentries for this Person AND this Project is shown below the graph. The Person and Project columns are hidden automatically by ActiveScaffold (they are filter criteria and therefore all the same).

step2_cropped.png

Lastly, clicking on “View Time” for a Project shows the total number of hours logged by each Person that worked on the Project, per date. As in the previous graph, the date increases along then x-axis and the y-axis shows the total number of hours worked. In this view, the lines (data series) correspond to individuals who worked on the Project.

step3_cropped.png

That’s it! There are a few things that need to be done before this project is “presentable,” but IMHO these are eventualities and do not invalidate my proof of concept:

  • Functional testing
    • Improve abstraction of controller functions
    • Subclassing the graphing controller from Person and Project
    • Automated Functional test scripts
  • Graph Readability
    • Resize, rotate, or filter the dates so they are readable
    • Resize the series legend so it fits on screen
  • Basecamp object support
    • Expand beyond current set
      • Milestone
      • Todo-list, Todo-item
    • Dynamic background (not at-once) caching
    • Logging/Study of bandwidth usage

…and many more. It’s not about that though –

I learned Ruby and Rails this week and am now ready to start a “real” project with it. Luckily I’ll be traveling for the next 3 weeks without a laptop and will have plenty of time to think of new challenges.

Day 7: The fix is in

•June 21, 2007 • Leave a Comment

Got back from Sumeet’s at 11:15 PM, determined to resolve the last issue barring me from displaying proper basecamp data. Discovered that “breakpointer” is un-officially broken in Ruby 1.8.5 — The official answer is that Ruby 1.8.5 fixes a bug that allowed breakpointer to work.

Using script/console I was able to produce the following, which could explain my problem:

>> date_hash = {}
=> {}
>> (0..30).step(1) do |day_offset|
?> date_hash[(Date.today-day_offset).to_s] = 0
>> end
=> 0..30
>> date_hash
=> {"2007-05-22"=>0, "2007-06-01"=>0, "2007-06-12"=>0, "2007-05-23"=>0, "2007-06-02"=>0, "2007-06-13"=>0, "2007-05-24"=>0, "2007-06-03"=>0, "2007-06-14"=>0, "2007-05-25"=>0, "2007-06-04"=>0, "2007-06-15"=>0, "2007-05-26"=>0, "2007-06-05"=>0, "2007-06-16"=>0, "2007-05-27"=>0, "2007-06-06"=>0, "2007-06-17"=>0, "2007-05-28"=>0, "2007-06-07"=>0, "2007-06-18"=>0, "2007-05-29"=>0, "2007-05-30"=>0, "2007-06-08"=>0, "2007-06-19"=>0, "2007-06-20"=>0, "2007-05-31"=>0, "2007-06-09"=>0, "2007-06-10"=>0, "2007-06-21"=>0, "2007-06-11"=>0}
>>

The date strings are not stored in the order that they are set (or sorted), but that is fixed easily enough with the Hash sort method.

This is the total time logged by a gentleman who works 8 hours a day and took a few days off — the different color lines are different projects he logged time to.

correct.png

The next graph shows the time logged to a single project by everyone who logged time against it:

project_correct.png

Day 7: One last issue

•June 21, 2007 • Leave a Comment

I’ve written the controller logic to generate the graph. The controller filters the model data and configures the graph and tabulated time data for the view. One issue remains before I can call this a success: 0 values are generated for certain dates in the graph, although time data does not exhibit this pattern.

extra0.png

I’ll figure this out tonight with breakpoint (about time I learned that tool, anyway ;] ); right now I need to whip up some Dolmades for a dinner party and refresh my mind with good company. =)

Day 6: ActiveScaffold Snag: config.actions.exclude :edit vs. :update

•June 21, 2007 • Leave a Comment

This is kind of annoying: To hide the “delete” button, exclude :delete; to hide the “search” button, disable :search; to hide the “show” button, exclude :show; to hide the “edit” button, disable :update. Come on guys!

Day 6: Custom action_links in ActiveScaffold

•June 20, 2007 • Leave a Comment

The Basecamp visualization application will provide time views for each Person and Project. The user selects the Person or Project from a table (rendered by ActiveScaffold) and indicates that statistics are to be shown by clicking a link in the cell.

To link this view change to the ActiveScaffold row, we will use the action_link property of our configuration. The API is regrettably sparse, but a little bit of digging brought up this ActiveScaffold wiki entry and an example at the end of the newbie guide.

To keep things simple, I am currently presenting the data as a seperate barebones view. My Person controller code is:

app/controllers/people_controller.rb

class PeopleController < ApplicationControllerlayout "activescaffold"
  active_scaffold(:person) do |config|
    config.label = "People"
    config.columns = [:first_name, :last_name, :title, :im_handle]
    config.columns[:im_handle].label = "IM Handle"
    config.actions.exclude :create, :delete, :edit, :show, :search
    config.action_links.add 'time_per_person', :label => "Time", :type => :record, :page => true
    list.columns.exclude :timeentries
    list.sorting = {:last_name => 'ASC'}
  end

  def time_per_person
    @buns = "foo"
  end

end

config.action_links.add breaks down like this:
Parameter 0: String of the controller method to invoke (Ex: ‘time_per_person’)
:label : Displayed label for the link (Ex: “Time”)
:type : Is this link shown once per :record (row) or once per :table?
:page : Load the result as a new view?
time_per_person currently sets a test variable that is shown in the view:

app/views/people/time_per_person.rhtml

<%= @buns %>

This variable will hold my generated image’s filename and will be presented as an embedded image.

 
Follow

Get every new post delivered to your Inbox.