Sunday, October 25, 2009

Flash video player stutters and drops frames...

Why, oh why do Flash video players not work properly? I mean, I'm on a reasonably powerful Mac Book Pro running the latest browsers and Flash plug-in and still YouTube videos are almost unwatchable (for reasons other than the content :). Can no one save us from the horror that is Flash video? Am I missing something somewhere that makes video smooth and watchable? The audio works just fine but the video breaks and jumps like crazy.

Its not a buffering issue, because no matter where I view it (home DLS, work T1) it still has the same performance. I have also fully buffered the videos before viewing them and even that didn't help things. Its also not a Mac problem as the same thing happens under Linux (no surprise) and Windows.

I realize that HTML 5 has a video tag built-in, but I don't think I can wait that long. :/

Tuesday, October 20, 2009

The International Council of Manlaws, Ltd.

I found this in an old email today and thought I would repost. :)



The International Council of Manlaws, Ltd.

  1. Under no circumstances may two men share an umbrella.

  2. It is OK for a man to cry ONLY under the following circumstances:
    1. When a heroic dog dies to save its master.
    2. The moment Angelina Jolie starts unbuttoning her blouse.
    3. After wrecking your boss's car.
    4. When she is using her teeth.

  3. Any man who brings a camera to a bachelor party may be legally killed and eaten by his buddies.

  4. Unless he murdered someone in your family, you must bail a friend out of jail within 12 hours.

  5. If you've known a man for more than 24 hours, his sister is off limits forever unless you actually marry her.

  6. Moaning about the brand of free beer in a mate's fridge is forbidden. However complain at will if the temperature is unsuitable.

  7. No man shall ever be required to buy a birthday present for another man. In fact, even remembering your mate's birthday is strictly optional. At that point, you must celebrate at a strip bar of the birthday boy's choice.

  8. On a road trip, the strongest bladder determines pit stops, not the weakest.

  9. When stumbling upon other guys watching a sporting event, you may ask the score of the game in progress, but you may never ask who's playing.

  10. You may flatulate in front of a woman only after you have brought her to climax. If you trap her head under the covers for the purpose of flatulent entertainment, she's officially your Girlfriend.

  11. It is permissible to drink a fruity alcohol drink only when you're sunning on a tropical beach ... and it's delivered by a topless model ... and it's free.

  12. Only in situations of moral and/or physical peril are you allowed to kick or punch another guy in the nuts.

  13. Unless you're in prison, never fight naked.

  14. Friends don't let friends wear Speedos. Ever. Issue closed.

  15. If a man's fly is down, that's his problem, you didn't see anything.

  16. Women who claim they "love to watch sports" must be treated as spies until they demonstrate knowledge of the game and the ability to drink as much as the other sports watchers.

  17. A man in the company of a hot, suggestively dressed woman must remain sober enough to fight.

  18. Never hesitate to reach for the last beer or the last slice of pizza, but not both, that's just greedy.

  19. If you compliment a man on his six-pack, you'd better be talking about his choice of beer.

  20. Never join your girlfriend or wife in discussing a friend of yours, except if she's withholding sex pending your response.

  21. Phrases that may NOT be uttered to another man while lifting weights:
    1. Yeah, Baby, Push it!
    2. C'mon, give me one more! Harder!
    3. Another set and we can hit the showers!

  22. Never talk to a man in a bathroom unless you are on equal footing: i.e., both urinating, both waiting in line, etc. For all other situations, an almost imperceptible nod is all the conversation you need.

  23. Never allow a telephone conversation with a woman to go on longer than you are able to have sex with her. Keep a stopwatch by the phone. Hang up if necessary.

  24. It is acceptable for you to drive her car. It is not acceptable for her to drive yours.

  25. Thou shalt not buy a car in the colors of brown, pink, lime green, orange or sky blue.

  26. The girl who replies to the question "What do you want for Christmas?" with "If you loved me, you'd know what I want!" gets an XBox 360. End of story.

  27. There is no reason for guys to watch Ice Skating or Men's Gymnastics. Ever.

  28. We've all heard about people having guts or balls. But do you really know the difference between them? In an effort to keep you informed, the definition of each is listed below:

    "GUTS"
    is arriving home late after a night out with your mates, being assaulted by your wife with a broom, and having the guts to say, "are you still cleaning or are you flying somewhere?"

    "BALLS"
    is coming home late after a night out with you mates smelling of perfume and beer, lipstick on your collar, slapping your wife on the arse and having the balls to say, "You're next!"



I hope this clears up any confusion, The International Council of Manlaws, Ltd

Sunday, September 06, 2009

Debian Squeeze and an old Dell PE1650

Debian logoI recently had to put Debian testing (Squeeze) on an old Dell PowerEdge 1650 server. Here's a little tip to save you some time if your ever in the same situation: upgrade the BIOS first!

Its kind of a long story but my original PE1650 was running BIOS A10 when it died due to memory slot failure. So I borrowed a friend's unused PE1650 until I could get a "new" one on-site. Well, the new one was even older than mine and was running BIOS A05. I didn't think it was a big deal and installed Lenny (stable) and then upgraded to Squeeze (testing). And then the problems began. Let's just say that I spent a week of sleepless nights and frustrating days trying to figure out why the machine would just suddenly, and without any notice at all, freeze. And it wasn't your normal hang either as there was no kernel panic messages, no messages in the syslog, not even anything on the console.

I upgraded the BIOS to A11 (the latest available) and rebooted the machine; its been running now for almost 12 hours. This post may be a little premature as I've thought the problem was solved several times before, but everything was pointing to a hardware failure and the BIOS qualifies as hardware in my book. Regardless, I am still a little gun shy and will feel much better when it stays running for at least a whole day. A week would be better. :)

Sunday, August 23, 2009

Ruby-AAWS & Rails

On August 15, 2009 Amazon begin requiring all calls to their AWS servers to be cryptographically signed. This caused MynaStuff, our home inventory website, to gradually break and stop serving pages. This post is to help me remember details about what I did this weekend and to help anyone else out who might be in the same boat.

Because we use memcached on our servers the actual degradation of the service was quite slow and intermittent. However it soon became clear that we had a major problem and after a few seconds of investigation I knew what I had to do. We had built MynaStuff pretty quickly and had just thrown together a home grown connection to the AWS service. It was time to either add crypto signing to our code or use someone elses code. Never a big fan or build over buy I downloaded Ruby-AAWS and started hacking.

I can't say enough good things about Ruby-AAWS, it was easy to install and pretty easy to work with. Even though it wasn't designed to work with Ruby on Rails everything went pretty smoothly until I tried to get the data out of the memcache. The problem centered around how Ruby-AAWS builds classes on the fly to contain the data coming back from AWS. The way it works is really slick, however Ruby doesn't like the virtual classes too much so AAWS has to provide a factory method (of sorts). Just a simple call to Amazon::AWS::AWSObject.load() with the string that you retrieved from your memcache system and your good to go. Or so I thought.

It turns out that Ruby-AAWS depends on the marshal.load() method to throw an ArgumentError when it has a problem reading some data and Rails somehow changes that exception to something else. So, no matter what I tried it always failed. The good thing about Open Source code is the ability to find out exactly what is wrong and then fix it (for your system or for the whole world). After changing the aws.rb file to check for any exception (i.e. Exception) the code worked again. However, checking for any exception is like killing a fly with a sledgehammer and is not a good idea. I am currently looking for the reason that the exception thrown by marshal.load() changed and how I can fix me code to accept this and deal with it.

Anyway, here is the patch I submitted to the Ruby-AAWS author. Happy hunting!


*** aws.rb.ORIG 2009-08-22 14:44:39.000000000 -0400
--- aws.rb 2009-08-22 14:44:51.000000000 -0400
***************
*** 230,236 ****
def AWSObject.load(io)
begin
Marshal.load( io )
! rescue ArgumentError => ex
m = ex.to_s.match( /Amazon::AWS::AWSObject::([^ ]+)/ )
const_set( m[1], Class.new( AWSObject ) )

--- 230,236 ----
def AWSObject.load(io)
begin
Marshal.load( io )
! rescue Exception => ex
m = ex.to_s.match( /Amazon::AWS::AWSObject::([^ ]+)/ )
const_set( m[1], Class.new( AWSObject ) )

Thursday, July 23, 2009

Backing up your database with logrotate

I use BoxBackup in lazy mode to back up my systems. This works well for things like normal files and directories but not so well for databases. I wanted to periodically dump my database to a file and then have BoxBackup come along and do its thing. The only problem was how to name each backup file and how to clean up after so many backups had been done. Since it runs in lazy mode I can't know ahead of time exactly when the backup will happen and which files it will backup.

I looked at generating files with timestamps and then doing some calculations about cleaning up old files but that just seemed messy and I was sure that someone must have run into this type of situation before. Then I thought about log files and how they are backed up. It turns out the the standard Linux logrotate command knows how to rename files and get rid of old ones automagically. It even has script functionality that allows you to run commands before and after the rotate happens. Sounds perfect. Here's what I did.

First I created a directory in my web apps directory to hold all the database information and backup files. I'm using PostgreSQL, but you could do the same thing for MySQL or even Oracle. Just change the names of the directories and commands to something more suitable for your environment.


$ mkdir /var/www/postgres


Next we have to create a status file for logrotate to use. Since we will be running this as a non-root user we don't want to pollute the system status file with our non-log database backup stuff.


$ touch /var/www/postgres/logrotate.status


We also want to create a "fake" dump file so that logrotate will have something to start working with. If this file doesn't exist logrotate will refuse to rotate it. In this case we are backing up a Postgres database called "mydatabase".


$ touch /var/www/postgres/mydatabase.dump


Now we get to the heart of the matter; the logroate script itself. This tells logrotate to keep 10 copies of our dump but don't compress it and dont copy it. It will also complain if there is no original file to backup and it will create a blank "dump" for next time.


# /var/www/postgres/logrotate.pg_dump
# Dump PostgreSQL databases and prepare them for backup
/var/www/postgres/mydatabase.dump {
rotate 10
nomissingok
create
nocompress
nocopy
prerotate
test -x /usr/bin/pg_dump || exit 0
/usr/bin/pg_dump mydatabase -F c > /var/www/postgres/mydatabase.dump
endscript
}


One final step and we're done. The pg_dump command connects to the database as the user who runs it and the postgres user has access to all the databases by default (on Debian anyway). So running the logrotate command as the postgres user allows us to backup any database on the system without a password. And in order to allow the postgres user access to our new setup we have to change the owner on the files in /var/www/postgres.


$ chown -R postgres:postgres /var/www/postgres


Now, whenever you want to generate a new database dump just run the following command. You can put this is a crontab or just run it by hand. Remember to use the -f flag to force the backup to happen.


$/usr/sbin/logrotate -f /var/www/postgres/logrotate.pg_dump -s /var/www/postgres/logrotate.status

Friday, July 17, 2009

Generating PDFs in Rails using Prawn

In my current Rails projects (Gradesheet & MynaStuff) I have the need to create reports as PDFs. Prawn is a relatively new library that does just what I need in pure Ruby. There are a couple of really good tutorials on how to integrate Prawn into your Rails project on the web but I wanted to do something a little different. There's even a plugin (PrawnTo) that makes Prawn look like a native Rails construct and allows you build PDFs without leaving your views. Neat!

However, this is not really how I wanted to implement reporting in my applications. So I created a directory in lib and filled it with self-contained reports. In my view, this makes reports easier to build and maintain. Let's get started. First, you need a Rails project.


strutter$ rails HelloPrawn
create
create app/controllers
...
create log/server.log
create log/production.log
create log/development.log
create log/test.log

Now, we need to get the Prawn & Prawn-layout plugins. Since they are pretty new and constantly changing I like to get the latest version straight from GitHub. Just clone them in the usual way. Note that you have to get a couple of subcollections when you get Prawn this way.

$cd vendor/plugins
$git clone git://github.com/sandal/prawn.git
Initialized empty Git repository in /Rails/HelloPrawn/vendor/plugins/prawn/.git/
remote: Counting objects: 6716, done.
remote: Compressing objects: 100% (2762/2762), done.
Receiving objects: 21% (1459/6716), 6.31 MiB | 220 KiB/s
...
$git clone git://github.com/sandal/prawn-layout.git
Initialized empty Git repository in /Rails/HelloPrawn/vendor/plugins/prawn-layout/.git/
remote: Counting objects: 271, done.
remote: Compressing objects: 100% (232/232), done.
remote: Total 271 (delta 111), reused 0 (delta 0)
...

Since we are running Prawn from Git we have to do a couple of extra things.

$cd vendor/plugins/prawn
$git submodule init
Submodule 'vendor/pdf-inspector' (git://github.com/sandal/pdf-inspector.git) registered for path 'vendor/pdf-inspector'
Submodule 'vendor/ttfunk' (git://github.com/sandal/ttfunk.git) registered for path 'vendor/ttfunk'
$git submodule update
Initialized empty Git repository in /Users/richardhurt/Rails/HelloPrawn/vendor/plugins/prawn/vendor/pdf-inspector/.git/
remote: Counting objects: 16, done.
remote: Compressing objects: 100% (14/14), done.
...

Now we have to tell Rails to load Prawn-layout as well as Prawn. I do this with a simple initializer.

# config/initializers/prawn.rb
require "prawn/core"
require "prawn/layout"

Next we'll create a report. First build a new directory to hold all your reports.

mkdir lib/reports

Then add this new path to your Rails load_path. Look for the following section in you config/environment.rb file and make it look similar to this.

# Add additional load paths for your own custom dirs config.load_paths += %W({RAILS_ROOT}/extras )
config.load_paths += %W( #{RAILS_ROOT}/lib/reports )

and add a new PDF mime type.

#config/initializers/mime_types.rb
Mime::Type.register_alias "application/pdf", :pdf

Now that most of the setup is out of the way we're ready to get to work. Let's create a simple report and then show the controller that goes along with it. This report doesn't do much but it shows the basics.


# lib/reports/hello_prawn.rb
class HelloPrawn

# Build the parameter screen for this report.
def self.get_params()
# This report has no parameters
end

# Build the report in PDF form and sent it to the users browser
def self.draw(params)
# Create a new document
pdf = Prawn::Document.new(:page => "LETTER")

# Make it so we don't have to use pdf. everywhere. :)
pdf.instance_eval do
# Print something
text "Hello Prawn", :align => :center, :size => 20

# Render the page and send it back to the controller
render
end

end
end

Finally we'll build a controller to either build the parameter screen or render the PDF itself.

class ReportsController < ApplicationController

def show
# Since we are building the report object on the fly we need to make sure
# that it is a valid report before we try to build/show it.
begin
# Try to make the report into an 'object'
@report = params[:id].classify.constantize
rescue NameError
# This is not a valid report or some other error happened
flash[:error] = "Unknown Report '#{params[:id]}'"
redirect_to :action => :index
else

respond_to do |format|
format.html do
# display the parameters screen
end

format.pdf do
# Send the PDF back to the browser for viewing
send_data @report.draw(params),
:filename => params[:id].titleize + '.pdf',
:type => 'application/pdf',
:disposition => 'inline'
end
end
end
end
end

Lets test it out. Start up your Rails server and go to http://localhost:3000/reports/hello_prawn.pdf and you should get an inline PDF report in return. The cool thing about this is that each report can generate its own parameters screen on demand. See that self.get_params() function up in the report? That's where you can put your ERB stuff and have it render when you hit http://localhost:3000/reports/hello_prawn. Neato!

def self.get_params()
# Get the homeroom information
homerooms = Student.find_homerooms()

# Build the parameter screen
params = <<-EOS



Student Roster









EOS

Thursday, May 21, 2009

Why would I give up my iPhone for a Palm Prē?

With the recent announcement that the Palm Prē is going on sale June 6th for $300 $200, I am very excited and can't wait to try it in the store. I currently own a 1st generation iPhone and I have to say that I have become disillusioned with it. Sure it does some things really well (dialing a number from a map search) but other things are a complete disaster (integrating with online apps, ToDo lists). I've realized that the iPhone is nothing but a computer accessory and it will always require a computer to be useful. This is something that I don't really want or need right now.

I want a portable computer in its own right; something that doesn't need a tether to a desktop to work. The iPhone is completely dependent on its host system for important things like system updates. This is where I really miss my T-Mobile Sidekick (aka Danger HipTop). Everything it did was OTA (Over The Air); from system updates, to syncing. Heck you could even lose your phone and not worry about your data because it was stored on the web! It didn't do everything perfectly (the online web interface was atrocious) but it got close.

Some features that I'm looking forward to on the Prē are OTA updates, online syncing, and background apps. After using Google calendar quite a bit I've realized that it's much better than Apples iCal program. Google makes it easier to have multiple calendars, share information with others, and generally navigate the system. I also love to use SSH to manage my servers, but the iPhone makes this hard if not impossible because of the lack of background apps. When I switch out of my SSH program to check an email, the iPhone closes the SSH app thus terminating my connection. Not cool.

One thing I wont miss on my iPhone is the music playing function. For one, I already have an iPod that works really well as a music player. But the biggest problem is that the iPhone makes a terrible iPod. The original intent of the iPod was to make it very simple to listen to your music and the iPhone screws that up royally. Its very confusing to control the music playing in the background while at the same time switching between other applications. For some reason I can't seem to do it. And forget about playing online music while doing something else (see the part about background apps). I was really looking forward to Pandora Radio or Last.Fm on my iPhone when it was first announced only to be disappointed.

I'm not saying that the Palm Prē will be the end all be all system for me. Its not even been released yet. But I think it will come close and I am looking forward to giving it a shot.