Ryan Kanno: The diary of an Enginerd in Hawaii

Everything you’ve ever thought, but never had the balls to say.

2007 Archives

I are edjamakated graduated!

Welcome, to the rest of my life.

Today, I officially received my Masters in Business Administration from the Shidler College of Business at the University of Hawaii. Though it took me four long years as a part time student, I’d like to thank everyone who made it possible. Thanks for all the late nighters, the fun times running student body, but most of all, thanks for the memories. Not to mention, thanks to everyone who came to see me graduate! Whee! Since I hadn’t participated in a graduation ceremony in a few years, it was quite exciting.

At least I can say I graduated with Colt!

Go Bows!

(I’ll post videos once I can figure out how to convert them from my camera!)

And as a parting thought, the proof is in the pudding!

CIMG0903


(Click on the diploma cover to see my flickr set!)

Tagged: , , , , , , , , .


Update: footerStickAlt w/ jQuery & Yahoo! UI Grids

A few months ago, I wrote a blog about implementing footerStickAlt using jQuery & Yahoo! UI Grids. Fast forward to the present and I have a small update to post. In my previous implementation, one of the required libraries was the jQuery Dimensions plugin because of its nifty window/document height() calculations. However, after reading the plugin’s changelog and seeing as how jQuery 1.2 core now supports the height function, this plugin is no longer required. So without further adieu, here’s the updated footerStickAlt implementation instructions.

It’s been tested in IE 5.5+ and Firefox 2.

*Note*: In this implementation, I don’t check for the margin on the ‘body’ element since we’ve set all our margins and padding on to 0. See the demos for details.

Requirements

  • Yahoo! UI Grids [download]
  • JQuery 1.2+ [uncompressed] [compressed]
  • Place the Javascript below in a file of your choosing! Don’t forget to include it in your page!
$(document).ready(function() {
     if ($(window).height() > $(document).height()) {
          $('#bd').css({
               height: $('#bd').height() +
                         ($(window).height() -
                          $(document).height()) + 'px'
          });
     }
});

Check out the demos here: page with short content, page with long content!

(Notice the pages no longer depend upon jQuery Dimensions! Wheee!)

Enjoy!

Tagged: , , , , , , , .


1 Retirement Party, 2 Alma Maters, and 2 BCS Bowl Games. Priceless.

For the record, today just might have been the best day of my entire life.

Retirement Party

After slaving away for months planning my parent’s *surprise* retirement party, everything came to full fruition today. Thinking that they were attending an awards ceremony for the University of Hawaii’s Shidler College of Business, my parents were completely taken aback as more than 150 of their closest friends and family gathered to celebrate their retirement.

(Thanks to me and my sister!)

There’s a lesson to be learned here. If you want to see the most bewildered look on your parent’s face as 150+ people scream “Surprise!”, shoot me an email. And trust me when I say this, but…

It was all worth it.

I’ll post some pics once I get them developed. Thanks to everyone who showed up as well as everyone who made it all possible.

I seriously <3 my family.

Illinois gets a whiff of the Roses

The Illinois seriously needed the moons and the stars aligned today for their hand to be dealt the right cards.

  1. Virginia Tech beating BC allowed Illinois to move into the top 14 of the BCS poll.
  2. Pittsburgh beating West Virginia and/or (whatever way you want to look at it) Oklahoma beating Mizzo allowed Ohio State to move into the BCS Championship Game.

(As much as I hate saying this… but “Go Buckeyes!”)

Since Ohio State was going to be the Big Ten’s representative to the Rose Bowl, moving into the BCS Championship Game means that another Big Ten school could be selected to take their place.

Enter Illinois

After a dismal 2-10 season last year, the Illinois came roaring back this year with wins over then number five, Wisconsin, and then number one, Ohio State. Featuring a potent running attack, an amazing freshman, Leman led defense, and a surprise resurgence of “Juice” Williams, a whiff of the Roses will be well deserved.

Hawaii says pass some Sugar, baby.

For those of you on the East Coast that couldn’t stay up to watch Hawaii’s wild win over Washington, please, please watch today’s replay. Not only does it exemplify Hawaii’s heart and soul displayed throughout the season, but it’ll show all you analysts what to watch out for on New Year’s day.

All I can say is…

If Colt Brennan isn’t a Heisman finalist, something is seriously dead wrong with the system.

All the ESPN and BCS committee haters can stop drinking the haterade because the University of Hawaii showed true heart and grit in its final four games of the season. Not many of the so called “experts” and “analysts” gave them a chance to be the only undefeated team in college football. Notice, I didn’t say all because there were a few here and there.

But 12 games and a 12-0 record later, here we are.

Since Boise really paved the way for non-BCS conferences last year with a wild win over Oklahoma in the Fiesta Bowl, the Rainbows are expected to get an at-large BCS selection to the Sugar Bowl.

Go Bows!

Now my only dilemma is what bowl game will I attend?

Tagged: , , , , , , , .


Installing MIT Simile’s Timeline locally (w/ Rails integration)

Update: 12/5/2007

Apparently, I’m still a rookie blogger and I forgot to mention that I was pulling from trunk (-r 8642). Don’t use the tags if you want the code below to work. :) Sorry about that neilo!

Since my past few blogs have been for the Django community, I’ll switch it up a little and talk about a visualization widget from those uber-smart kids at MIT.

Timeline

For one of my Rails prototypes at work, I decided to integrate Timeline; a pretty neat DHTML-based AJAXy widget for visualizing time-based events. Using a visual timeline is not only a lot ‘purrrrrtier’ than the mundane list-style displays, but it also gives a better relative perspective of how events overlap, their duration, etc.

In any case, I liked loved it, and I really wanted to use it.

Since I typically don’t have access to the Internet at work (I know, I know… a pseudo-developer without Internet access; welcome to my so-called life), I often have to download libraries and install them locally. Searching Timeline’s mailing list archives, I found one thread concerning the local installation of Exhibit.

Yet, nothing about Timeline.

So with that said, here’s the edits I made (kudos to Firebug developers). I would’ve created a patch file, but I was too lazy and the edits were too easy (sorry). :) Search for the following line in timeline-api.js (located in src/webapp/api directory in the downloadable distribution).

var url = useLocalResources ?
            "http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false" :
            "http://static.simile.mit.edu/ajax/api-2.0/simile-ajax-api.js";

and edit it to the following:

//var url = useLocalResources ?
//            "http://127.0.0.1:9999/ajax/api/simile-ajax-api.js?bundle=false" :
//            "http://static.simile.mit.edu/ajax/api-2.0/simile-ajax-api.js";
var url = (document.location.toString().indexOf('https://') != -1 ? "https" : "http") + "://" + window.location.href.split("/")[2] + "WEB_URL_TO /src/ajax/api/simile-ajax-api.js?bundle=false";

Basically, instead of using the supplied Jetty webserver, we’re just editing the url to your local installation of the file. Remember to change WEB_URL_TO to the path to the simile-ajax-api.js file in your own environment. Typically, one would put this file in a publicly accessible web folder named js, javascript, etc.

Voila!

As an added bonus, nowhere in Timeline’s documentation or examples does it indicate how to load inline event data. When I say inline, I mean dynamic data produced as a result of an action; in this case a search query. I want to be able to query on a set of dates and produce all event data points between those dates. Timeline’s typical use case is to load data from a javascript (.js) file. Personally, since the data is dynamic, I didn’t feel like writing a temp file publicly accessible by the web server or creating a REST action exposing the dynamic data; both of which are viable solutions, the latter more ideal than the former. I just wanted to write JSON inside of the rendered html file and load the Timeline. To do so, instead of coding the following (like in their cubism example):

      tl = Timeline.create(document.getElementById("tl"), bandInfos, Timeline.HORIZONTAL);
      tl.loadJSON("cubism.js", function(json, url) {
           eventSource.loadJSON(json, url);
      });

Using a rails example, this is what I included in my view:

<% if @include_timeline %>
    <%= javascript_include_tag 'PATH_TO/timeline-api.js?timeline-use-local-resources=true' %> 
    <script>
      var tl;
 
      var events = {
        <% if @events %>
        'dateTimeFormat': 'iso8601',
        'events': [
          <% @events.each_with_index do |event, i| %>
          {
            <% if event.start and event.end %>
             'start': '<%= event.start.iso8601 %>',
             'end'  : '<%= event.end.iso8601 %>',
            <% else %>
             'start': '<%= event.occurred.iso8601 %>',
            <% end %>
            'title': '<%= event.headline %>',
            'description': '<%= event.description %>'
          }<% if i != @events.length - 1 -%>, <% end -%>
          <% end %>
        ]
        <% end %>       
      };
 
      function onLoad() {
        var eventSource = new Timeline.DefaultEventSource(); 
        var theme = Timeline.ClassicTheme.create();
        theme.event.label.width = 250;
        theme.event.bubble.width=320;
        theme.event.bubble.height=220;
        var bandInfos = [
          Timeline.createBandInfo({
              width: "20%",
              intervalUnit: Timeline.DateTime.DAY,
              intervalPixels: 100,
              eventSource: eventSource,
              theme:theme
          }),
          Timeline.createBandInfo({
              width: "50%",
              intervalUnit: Timeline.DateTime.MONTH,
              intervalPixels: 100,
              eventSource: eventSource,
              theme:theme
          }),
          Timeline.createBandInfo({
              width: "30%",
              intervalUnit: Timeline.DateTime.YEAR,
              intervalPixels: 200,
              eventSource: eventSource,
              theme:theme
          })
        ];
        bandInfos[1].syncWith = 0;
        bandInfos[2].syncWith = 0;
        bandInfos[2].highlight = true;
        tl = Timeline.create(document.getElementById("timeline"), bandInfos);
        eventSource.loadJSON(events, '');
      }
      var resizeTimerID = null;
      function onResize() {
          if (resizeTimerID == null) {
              resizeTimerID = window.setTimeout(function() {
                  resizeTimerID = null;
                  tl.layout();
              }, 500);
          }
      }
    </script>
  <% end %>

Things that you should take note of:

  • I used Ruby’s DateTime iso8601 message to help pass a date that Timeline could understand.
  • I called eventSource.loadJSON(events, ”); where I passed in the events JSON array.

Hopefully, these two pointers can help you save some time integrating Timeline into your project! Since this is on my blog, feel totally free to take/use/steal/distribute/copy/modify any code you see fit. All I ask is if you find any bugs, have any comments, or can think of ways to make my ugly code cleaner - I’d love to hear from you. :)

Enjoy!

Tagged: , , , , , , , .


Using the extra() QuerySet modifier in Django for WeGoEat

Since I actually used this method to reduce the number of Update:”explicit” SQL calls made in WeGoEat, I figured I’d write a little blog explaining the context in which it was used, and maybe, just maybe, it’ll help shed some light on how others can take advantage of this neat little function.

Background

As a Django “proof-of-concept”, I’m working on a local restaurant review site for my home state of Hawai`i. (I actually just released it yesterday). For each restaurant, I want to be able to calculate the average of all reviews and display this listing in a paginated view. (Yes, I do realize there’s no average rating, but that has to do with there being no users. ;P).

The Problem

Having a serious “wtf was I thinking moment”, I initially wrote a Restaurant model function that returned the average (review) rating for each restaurant instance. Little did I realize that when I actually displayed the restaurant’s average reviews, I would be making an additional SQL avg() call for every restaurant. Though I’m paging “n” records at a time, this function added an additional “n” SQL calls for every view that contained a restaurant listing, just to name a few.

In pseudo-code, my initial naive function resembled the following: (I’m sure we’re all guilty of writing something of the sort… ok, fine, I know I was. ;P)

1
2
3
4
5
6
     def get_average_review(self):
         query = 'QUERY TO GET AVERAGE (SELECT AVG(rating)...); (I have the query below)'
         # Get cursor from connection
        cursor = connection.cursor()
        cursor.execute(query)
        return cursor.fetchall()

Duh.

Here’s a picture of the number of queries it took:

Duh

The “extra()” solution

After profiling my application and realizing what a bone-headed mistake I made, I began researching the extra() Queryset modifier. Yes, I realize that these extra lookups aren’t the most portable and often violate the DRY principle, but it’ll probably suffice for most of all my personal projects. :)

Since I’m already retrieving a list of Restaurants and filtering them via letter, island, and what not, I figured I could add an average rating subquery. The entire call looks as such:

1
2
3
4
5
6
7
     restaurants = Restaurant.objects.filter(name__istartswith = letter).extra(
             select={'<strong>avg_rating</strong>': 'SELECT AVG(overall_rating) FROM restaurants_restaurant as res, reviews_review, django_content_type \
                                          WHERE restaurants_restaurant.id = res.id \
                                          AND res.id = reviews_review.object_id \
                                          AND reviews_review.content_type_id = django_content_type.id \
                                          AND django_content_type.model = \'restaurant\''},
                       )

As you can see, I’m exploiting the fact that restaurants_restaurant will be available from the Restaurant.objects.filter() call. (I know, I know… bad for portability).

But voila!

Now, in my templates, when I iterate over the restaurants, I can get issue the following:

1
2
3
4
5
6
7
8
9
10
11
{% for restaurant in restaurant_list %}
&lt;tr&gt;
    &lt;td&gt;&lt;a href="{{restaurant.get_absolute_url}}"&gt;{{ restaurant.name }}&lt;/a&gt;&lt;/td&gt;
    &lt;td&gt;{% if restaurant.avg_rating %}
	   {% load show_stars %} 
           &lt;span class="average-rating"&gt;
	   {% show_stars <strong>restaurant.avg_rating</strong> of 5 round to quarter %}
           &lt;/span&gt;
           {% endif %}&lt;/td&gt;
&lt;/tr&gt;
{% endfor %}

Notice how I used my show_stars template tag that I blogged about a few weeks ago to display the average restaurant rating. (Cheap shameless plug, but damn effective! :P) I’d link to a page in action, but since I just opened up my site to a few select users, I’ll update this post when I actually have any reviews. :P

Oh, and before I forget, thanks to my co-worker Stephen for assisting me with my SQL issues! :)

Here’s a picture of the final result:

Yay

Note:

As an added bonus, I also realized a few other ’spots’ where the .extra() Queryset modifier would come in handy. Since I’m also using the wonderful django-voting application from Jonathan Buchanan, I came across this post about accessing a dictionary via a template in the Django-users Google Group.

Basically, I had come across the same issue as the poster. Since I allow users to vote on reviews (similar to Amazon, Yelp, etc.), I wanted to retrieve the score of each Review instance to display on a paginated listing of all Reviews. Using the same extra() modifier, I was able to inject the total number of votes and the score when I retrieved all Reviews as such:

Btw, I just injected most of the code from Jonathan’s template tag. :)

1
2
3
4
5
6
7
8
9
10
11
.extra(select={'total_votes': 'SELECT COUNT(vote) FROM votes as v, reviews_review as rev, django_content_type \
                                        WHERE reviews_review.id = rev.id \
                                        AND v.object_id = reviews_review.id \
                                        AND v.content_type_id = django_content_type.id \
                                        AND django_content_type.model = \'review\'', 
 
                                        'score': 'SELECT SUM(vote) FROM votes as v, reviews_review as rev, django_content_type \
                                        WHERE reviews_review.id = rev.id \
                                        AND v.object_id = reviews_review.id \
                                        AND v.content_type_id = django_content_type.id \
                                        AND django_content_type.model = \'review\''},)

Pretty neat right?

Now, when iterating through the reviews, I can use the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
{% for review in object_list %}
	&lt;tr&gt;
		&lt;td&gt;&lt;a href="{{review.content_object.get_absolute_url}}"&gt;{{ review.content_object.name }}&lt;/a&gt;&lt;/td&gt;
		&lt;td&gt;&lt;a href="{% url profile-detail username=review.user.username %}"&gt;{{ review.user.username }}&lt;/a&gt;&lt;/td&gt;
		&lt;td&gt;&lt;nobr&gt;{% load show_stars %}
			&lt;span class="rating"&gt;{% show_stars review.overall_rating of 5 round to half %}&lt;/span&gt;
			&lt;/nobr&gt;
		&lt;/td&gt;
		&lt;td&gt;"&lt;span style="font-weight:bold; color:#092e20;"&gt;{{ review.get_recommendation_display }}&lt;/span&gt;"&lt;/td&gt;
		&lt;td&gt;&lt;span style="font-size:.875em;"&gt;{{ review.submit_date|timesince }} ago&lt;/span&gt;&lt;/td&gt;
		<strong>&lt;td&gt;Total of {{ review.score|default:0 }} from {{ review.total_votes }} {{  review.total_votes|pluralize:"person,people" }}.&lt;/td&gt;</strong>
	&lt;/tr&gt;
{% endfor %}

Hope y’all learned something like I did! :) Oh, and before I forget my standard disclaimer, “since this is on my blog, feel free to take/use/steal/distribute/copy/modify any code you see fit, but if you find any bugs, have any comments, or think the code can be cleaner, I’d love to hear from you.”

Enjoy!

Tagged: , , , , , , .


Powered by Wordpress. Stalk me.