Jake Scruggs

writes ruby/wears crazy shirts

Fred Polgardy and I were looking up how to find out what path in the browser corresponds to what controller/action combination in a Rails application today and I realized that I've looked this up before... So I'm putting this information here so I can find it in the future:

(from inside the console)
>> ActionController::Routing::Routes.recognize_path '/seo/hotness/path/705105'
=> {:controller=>"products", :action=>"show", :id=>"705105"}

Yeah I know you can do a 'rake routes' and hunt around but this gets me where I need to be quicker.

Lately I've been working with this guy Felix who likes to rip the application into shreds when confronted with a problem. Initially, it's a bit scary. I know we have source control and we can get it all back, but ripping out large crucial swaths of code just seems so violent and yet it's a pretty effective strategy.

On this one project we've had a problem for well over a year of our tests not rolling back the database after each test. We've got all the configuration set up for that to happen, but it just doesn't and nobody could figure out why. One of the problems is that this is a Rails application that is 2.5ish years old and serves millions of users every day. So in order to make that happen back in the early days of Rails we had to extend and modify a lot of the Rails framework. Apparently one of those modification broke the mechanism for rolling back the database after every test.

Not rolling back the database means that one tests creation/updating of a model can break other tests so we have to remember to clean up after ourselves. Invariably someone forgets to and we get a lot of weird test failures that have to be worked out (or worse disabled with the comment "runs by itself but not with all the other tests").

Felix's solution to our tricky problem was to create a new crazy simple ActiveRecord model 'Foo' that one had one validation: Its name had to be unique. Then we wrote a crazy simple set of tests that tried to create and save a Foo object in separate tests with the same name. If the database was rolling back properly then there should be no problem. Of course they failed in our messed up environment. Now since this model Foo has no dependencies on any of our complicated models, we could delete lots of stuff without breaking it. And we did. We deleted every plugin and gem we had until we found the problem. Of course we did it pseudo-binary search style -- cutting out large sections of gems/plugins in one go to see it it had any effect and then narrowing it down when it worked. In a relatively short amount of time we had found the culprit: A plugin we had written that attempted to make Rails rollback multiple databases in nested transactions. Now the best solution would be to move up to a more modern version of Rails where this just works (or at least the internet says it does), but our solution was to make this particular plugin not load while in the testing environment. Not a perfect solution, but a good enough one.

The real take away from this exercise for me is that simplification and deletion are powerful tools in bug fixing toolkit.

May 25, 2009

Git isn't Chatty

Recently we deployed to production without a key bugfix and my assumptions about git were to blame.

We, like other people who use git, do a lot of our bug fixing in a branch and then merge it into master when it's time to release. So here's the procedure for the guy who's turn it is to do a deploy (which was me):

  1. Do a 'git pull origin master' in the master branch
  2. Get a local tracking branch of the bug-fixes branch
  3. Merge the bug fix branch into master
  4. Tag the master branch with the name of the release (our deployment keys on tags)
  5. Start the automated deploy script
Easy right? Except that my years with subversion have put in my brain this assumption that my source control will talk to the remote server all the time. But git's model is to use all your local info unless you specifically tell it to go over the wire. So when I told git to create a local tracking branch it did using the latest information it had locally about that branch. The last time I had done a general 'git pull' was a day ago so I got a version of the bug fix branch that was missing a commit that had happened the day of the deployment. And of course when I merged into master I was missing a crucial commit.

One of the cool things about git is the fact that you can do a lot of development without an internet connect, but I've found that a fair amount of the gotchas I've run into with git trace back to my expectation that it will talk to the remote server when it's preference is to stay local.

May 11, 2009


So my friend Leah has lots of ideas. And one of them was that people would pay money for a screeching cat sound on their iPhone.

Everyone within earshot thought about it and the consensus was that, yeah, I might pay a dollar for that. So Leah and I set about working on the iMeow application but the iPhone development one-two punch of dragging/clicking and Objective-C soon drove us to despair. I, the lessor developer, gave up but she stuck with it (and pulled in some other Obtivians with iPhone knowledge such as Turner, Nate, and others who I'm probably forgetting) so I'm proud to present iMeow (iTunes link).

It's a silly little good time.

Last night I chose quantity over quality and ate at a Brazilian steak house. Good times.

Webrat: Rails Acceptance Testing Evolved Bryan Helmkamp (weplay)

Bryan started out his presentation by handing out Tylenol for those who went out last night and Budwiser for those who didn't. The crowd was appreciative.

Bryan show some typical Rails integration testing (simulating clicking through the app without opening up the browser) and compared it to the same test in Webrat. The difference between the integration test and the webrat enabled test was pretty dramatic. The Webrat test was much cleaner and easier to read.

Webrat parses the returned html with Nokogiri (which he highly recommends) and so can do some pretty interesting stuff. click_link, fill_in, check (and uncheck), choose, select, attach_file, and click_button all have a simple syntax.

Webrat automatically is checking for the success of the request so you don't have to assert success everywhere. It also verifies that form fields are there when you try to fill them in. Nice.

There is a Selenium adapter for Webrat so that you can flip your tests over from simulating the browser to actually firing up a browser and clicking through.

good talk.

When to Tell Your Kids About Client Caching Matthew Deiters (Inc.)

This was another talk that had a lot of good content but went pretty fast, so the following are excerpts I managed get into TextMate:

Why should you care about client (browser) caching? Well, 80% of the total time to pull up a webpage is spent on the wire or the client side.

Entity Tags:
When configured, the server sends an E-Tag to client (browser). Then the next time they look for it the browser sends the E-tag back and if the server determines nothing has changed then it send the super small "304 Not Modified" and browser re-renders the page super fast.

Rails can calculate the hash of a page and compare the last time sent to the current and if there is no change then "304 Not Modified"

Don't use etags on static content -- you can set up your apache config to not look again for 10 years.

use commit times for the cache buster
image.jpg?3123123 <- not just the time but use the commit time of the file

To stop ajax from being cached (which can cause problems):
(try not to use method post -- it generates 2 requests)
Use HTTP-Headers => http://github.com/dancroak/no_cache helps you do this

Less requests are better so combine/minifi/compress your javascript and css files for fewer asset requests. There's a lot of tools to do this.

bundle_fu (http://code.google.com/p/bundle-fu/) is one of them.

Let Google host your javascript. Google hosts most popular javascript frameworks so you can rely on them to serve up these assets for you. include_google_js does this for you (http://github.com/chriswarren/include_google_js)

Automated Code Quality Checking In Ruby And Rails Marty Andrews (Cogent Consulting Pty Ltd)

This was the other code metrics talk at Rails Conf. Turns out Marty Andrews is also a former ThoughtWorker. He was (and still is) in Australia during my time at ThoughtWorks so we just met at Rails Conf. Nice guy.

There was a fair amount of overlap between our talks so I'll limit my comments to things that were not mentioned in my talk.

Static analysis is when you analyze the code without running it. No app runtime required.

Feedback for your developers is key to continual improvement.

Marty is a big fan of failing the build on poor Flog, Flay, and Roodi results. I've resisted putting that functionality into metric_fu in the past because I wanted metric_fu to be more about collecting data than judgment. But maybe I was wrong. I opened up a new thread for discussion of this on the metric_fu Google group (http://groups.google.com/group/metric_fu). If you have an opinion on this please comment on the thread.

He showed a bunch of examples of poor Flog/Flay/Reek/Roodi results from the Rails source code -- Not to bash on Rails but to say that even awesome developers we all respect can check in some problematic stuff. We could all use some watching over.

Marty also has a tendency to call "metric_fu" "metrics_fu." Which is funny to me.

All right then, I gotta go catch a flight so this is where Rails Conf 2009 ends for me. Hope you enjoyed these write-ups.

If you're looking for the slides from my talk, you can find them (and everyone else's) here:

I feel like I must confess to you, faithful blog readers, that last night I ate a $240 steak at CraftSteak. But I do not apologize -- It was worth it.

Before I give anyone at Obtiva a heart attack I should point out that I will not be expensing that meal.

Also, have you seen Toby Tripp's Meeting Ticker? (http://tobytripp.github.com/meeting-ticker/) You enter your billable hourly rate, the number of people in the meeting, and press start. It then counts up the amount of money wasted, er, spent. Useful for those clients who are addicted to meetings.

Now on to the keynote:

What Killed Smalltalk Could Kill Ruby Too Robert Martin (Object Mentor Inc.)

First of all it's probably worth tracking down the video of this talk and watching it. Uncle Bob is a crazy talented speaker who knows way too much about software.

What was it that killed Smalltalk? Kent Beck -- "It was just too easy to make a mess"
Also it was written on top of a database (All the code went in there).
And Java was free.
But mostly the mess.

Boy scout rule: Leave the campground cleaner than when you found it.

Perform a random act of kindness on your code every time your check it out.

TDD can be a solution to the mess. (I would also add that code metrics are another.)

The tests allow you to clean the code.

Professionalism: The disciplined handling of power.
Just because you can do a thing does not mean you should do a thing.

What is it that might save rails:
Discipline (TDD)
Humility (Try not to make everyone hate us by snickering too much about other languages)
Acceptance of solving the dirty problems. (ugly database schemas in the enterprise)

If you're tempted to ignore these warnings -- Remember the fate of the most powerful and influential language of the 70s and 80s.

My talk (Using MetricFu to make your Rails code better) went well. I'd say there were 200ish people in the crowd and they all seemed to enjoy it. There were a bunch of questions and some verbal commitments to contribute to MetricFu.

Rails in the Large: How We're Developing the Largest (Enterprise) Rails Project in the World Neal Ford (ThoughtWorks), Paul Gross

Full disclosure: Paul and Neal are friends of mine from my ThoughtWorks days.

The talked about the trials and tribulations of developing a very large Rails project over a few years. The project is called Online Vehicle Exchange (OVE) and it's a sort of EBay for car dealers (it isn't open to the public).

The have 11 dev pairs (22 devs). And started out with mac minis but later switched to mac pros -- they probably should have switched over earlier.

Fully disconnected unit tests. They use UnitRecord (which reads your schema.rb file to). If you accidentally hit the db then UnitRecord fails the test

They run 9000 unit tests in 41 seconds.

The run 4000 functional tests in 248 seconds. There is no mocking the db in functional tests. Now tests that hit the db are slow so they had to invent some strategies for

They use Deep Test (open sourced) to parallelize your test suites. 8 cores on a mac pro -- so 8 parallel test runners. They also used Distributed Deep test (also open sourced) - to run the tests on another computer. They had 3 linux boxes in the corner that just ran tests from developer mac minis.

Selenium grid (more open source) was used to spilt selenium across multiple cores and machines. As many boxes as you want to parallelize out the tests.

Always fight the battle to keep tests fast.

They used a projector to throw Mingle up on the wall so they can keep an eye on the cards and the progress of the iteration.

They wrote cc_board -- an open source project that aggregates multiple cc.rb instances to give an overall view.

jukebox.rb -- plays a song when the build breaks and random music other times.

No email installed on the pairing stations -- giant time sink.

Software is more about communication than technology.
Co-location Rocks (war room style programming)
Pairing is vital to this large project so that everyone has some idea of what's going on.

One click deployment to any environment. Rake commit to check in (runs all tests then commits for you).

They used radmind to keep all of their mac's software identical to each other.

Monkey patches for the project live in a specific folder and are modularized.

It took 1 pair 6 weeks to upgrade from Rails 1.2.3 to 2.2 -- Large projects can be tough to upgrade.

Interfaces are Dumb (and that's a Very Good Thing) Erik Kastner (Wine Library / Meta | ateM)

Electricity -- has a dead simple interface. Plug it in and it works.

Your APIs should be the same way.

Why expose an API? You are not as smart as the collective intelligence of all your users.

Twitter and Flickr both have really easy to use APIs. It's probably responsible for some of their explosive growth.

GitHub has a webhook that will post every time someone pushes to a repo.

Keep in mind that the map is not the territory. A developers mental map often does not match the users mental map. This leads to API confusion. Make pains to keep your API simple and solicit lots of outside feedback when people start using it.

Time for Uncle Bob's Keynote now...

Sponsor Keynote: Agility in Deployment - Rails in the Cloud Jon Crosby (Engine Yard)

During the morning session Engine Yard announced their new Rails on EC2 (Amazon's compute cloud) solution: Flex

You can one button deploy to the cloud. It is a self healing cluster: Each node is in a load balancing pool. If one fails they automatically startup a new one to take over.

It can use a web interface or capistrano.

You can create a clone of the whole production environment with the data. So you can practice deploying to your cluster. Then you can blow away the staging environment when you're done with it. Nice. Keeping a staging environment around all the time is very costly if you want it to accurately simulate your production environment.

Flex will be available in June

Chad Fowler then introduced Chris Wanstrath for his keynote. While introducing him he mentioned that when he first saw git he didn't like it much. But he, and a lot of others, adopted it because of Github. I agree.

Chris Wanstrath (GitHub) Keynote

Some of his thoughts:

It's not too hard to become a famous Rails Blogger/Speaker, but the people he respects are the coders who contribute year after year and blog as an afterthought (or even not at all).

Do you want to be Kid Rock or a good programmer?

The inspiration for GitHub was all the friction in the open source project community. GitHub is all about making open source and collaboration easy. You can start an open source project in a few minutes instead of applying to SourceForge which takes days.

Time to go give my talk...

Ruby Heroes Award Ceremony Gregg Pollack (Rails Envy)

Gregg gave out the Ruby Heroes Awards:

Brian Helmkamp for Webrat
Aman Gupta for EventMachine and AMPQ
Luis Lavena for One-click Ruby Installer (for Windows)
Pat Allen for Rails Camp and thinking_sphinx
Dan Kubb for DataMapper
John Nunemaker for HTTParty and RailsTips (the blog)

Keynote Timothy Ferriss (The 4-hour Workweek)

The keynote was run as a conversation between David Heinemeier Hansson and Tim Ferriss.

Tim worked from 7am to 9pm when he realized that his income had no meaning. He took some time off and during that time he limited his work to 2 hours every Monday of checking his email. Profits went up 30%. Turns he was way over managing everything.

I've read the 4-hour work week and it's a fun and wild ride. The title is a bit of an eye-grabbing misnomer. It's more about viewing time as valuable commodity.

Tim practices an information diet. There's way more information in this digital world than you can possibly consume. He limits his consumption severely and it hasn't affected his performance at his job.

"You want to have rituals and conventions for everything that is not part of your core competencies."

The sound was a little low, so it was kinda hard to hear and I think that made the crowd a little restless. Oh well, I'm glad they keep trying to bring in outside people every year.

If you're a Tim Ferriss hater, here's an funny rant against him and his practices:

Did you know the Las Vegas Hilton charges you 3 dollars to print out a boarding pass? Jerks.

JavaScript Testing in Rails: Fast, Headless, In-Browser. Pick Any Three. Larry Karnowski

So blue_ridge is a javascript testing tool that mashes up a bunch of other tools to make testing javascript more or less like writing RSpec test. It's pretty cool. It uses Screw.Unit for the RSpec like lingo, Smoke for mocking, and Rhino to run the javascript tests without a browser (so you can integrate it into your Cruise Control build).


Blue-ridge is JQuery opinionated but can use Prototype without too much trouble.

It has a textmate bundle so you can run your javascript tests with command-r

You can have multiple describe blocks like RSpec.

Definitely worth a look.

Smacking Git Around - Advanced Git Tricks with Scott Chacon (GitHub)

Scott is very smart and really funny but he talked very fast so if you want to see the full slide deck you can go to:

or here for the cheat sheet:

Here's some selected tips I was able to jot down:

You can use partial sha1's to look up commits.

master^1 is parent of master
master~2 is two commits ago on master

ce04.. Means everything since then

git log orgin/master.. What am I going to push?
git log master ^orign/master Same as above

git log master bacon ^origin/master What is in the 'bacon' and 'master' branches that is not in origin master.

git log --graph Produces an ascii graph
gitk Produces visual graphs and takes pretty much the same arguments things as git log

git diff topic Means how do I make topic look like head -- probably not what you want

git diff HEAD...topic What happens if I merge in the topic branch -- useful

No rebasing on any commit you've pushed upstream! It messes everything up.

Subtree merging is an alternate to submodules. Tim Dysinger has a write-up on how to use it. Find it at: http://www.tinyurl.com/braidgit

git blame -C a_file.rb If a line was moved from another file then give me the last time it was changed from another file. Cool. You can even adjust how hard it looks for that line in another file.

git bisect is a binary search where a bug was introduced

git bisect start
git bisect bad The current commit is bad
git bisect good ae03efg... The last time you know it worked

Bisect will now take the range and check out the middle one, you run the code to see if the bug is there. If it still is:
git bisect bad And you get a new commit

if the bug isn't there:
git bisect good And you get a new commit

It keeps doing a binary search of commits (using your feedback) until you narrow it down to exactly the commit that caused the problem. Neat.

Then 'git bisect reset' to get back to normal.

git config --global color.ui auto For Colors

There's a way to set up git to diff word docs. Which is cool. See the link to the slides to see how (it went by rather fast).

Excellent talk.

Quick note: What's up with all the moths in this convention hall? They keep wandering over to see what I'm typing. Odd.

David Heinemeier Hansson's Keynote:

Here are some thoughts expressed by David during his keynote:
You can win argument merely based on the strength of your arguments, most often it just takes some time for good ideas to sink in.

7 Reasons I switched back to php (Derek Silvers) and the Twitter Fail whale (Twitter's scaling problems with Rails) were pretty big issues -- for about 2 days on Digg/slashdot. His strategy with this is to relax, read the credible info and learn. Criticisms about Rails scaling will never go away despite all the high profile successes.

Merb was the most credible internal (from inside the community) competitor/critic. And now they are merging in Rails 3.

Philosophy of Rails 3:
Lock up the unicorns... huh? You can't get every feature you want and still release before the end of the world.

No sacred cows. If you want to break every Rails app out there with your idea: it's still on the table. You have to have an overwhelming argument to get it accepted, but they will listen.

Rails is still committed to getting everything by default. But now you can have less if you need it.

Progress of Rails 3:
New Router:
route by subdomains, user agents, etc.
route to rack machinery

Cross site scripting protection:
Previously not automatically escaped.
The convention will be reversed

<%= comment.body %> escaped
<%= raw comment.body %> not escaped
The rails helpers will automatically escape
You can mark a sting as html safe Ex. "I'm safe!".html_safe

Javascript - unobtrusive and agnostic
Not so much included javascript in the template, but will pull it out into a file. The javascript that Rails used to put on the page when your did, say, link_to_remote will now be abstracted into a file that looks for 'data-remote' attribute on the anchor tag.

More Agnosticism
Action ORM (so you can use form_for a data mapper object)
Generators are now more open to plugging in stuff

The great Refactoring
Cleaning up a bunch of internals to make them less cluttered and speedier.

The real secret of high productivity:
Renegotiate requirements. If you look at requirements as set in stone you will leave a lot of productivity on the floor. Most of the time the business will take an 80 or even 60 percent solution if it takes a lot less time. Resist gold-plating.
Are you a programmer or a partner?

The GitHub Panel with Chris Wanstrath (GitHub), Tom Preston-Werner (GitHub), PJ Hyett (GitHub), Scott Chacon (GitHub), Jon Maddox (Mustache, Inc.):

The entire GitHub team answered questions from the internet and the audience. Here's some of the highlights:

They open source grit, but not the whole application. Because they want to make money and they want it to be their own vision. Maybe someday in the future.

One of the devs said he wished they had never built the rubygems system. It takes a ton of work and it doesn't make any money. Chris Wanstrath piped up that it's an effort of goodwill. I would say so. I've never got around to putting the MetricFu gem on Rubyforge and rely solely on GitHub to provide my gems. Maybe I should change that.

They are planning to introduce more sociableness like groups and customizing your feed with weighting. Which would be very cool.

They are profitable and are able to pay themselves nice salaries. This was not the case 6 months ago. Chris Wanstrath said that he spent 6 months living on savings and writing code every day. It was the best time of his life.

They have no office. But they do have a cafe they hang out at a lot.

Off the cuff comment when asked about crashing firefox: "The site is optimized for Safari." Ouch. Before you get bent out of shape -- they were joking. They plan to re-do the project page to better deal with lots of branches or tags.

The network data (used to make the network graph) is all available from the api.

They use 9 slices on Engine Yard.

Discussion Panel: Women in Rails with Desi McAdam (Hashrocket Inc and DevChix Inc), Sarah Mei (LookSmart), Lori Olson (Dragon Sharp Consulting):

Desi declared that they would only spend 5 minutes on the Couch DB Pr0n scandal. They wanted to spend most of the time talking about getting more women into the community.

One way is to create groups for women. Example: DevChix (http://www.devchix.com/)

Also being more visible so that women know you're out there. One of the panelist said that she feels like that's hard for a lot of women but that it's important to have a blog or twitter or whatever.

There's a lot of women who drop out when they have kids. And when they try to come back there's a gap in their resume' so they can't even get an interview.

You don't see a lot women in the Rails community (vs Java) because of the lack of maternity leave in small companies (which tend to adopt Rails more easily). The cutting edge languages and companies tend to lose out on women candidates through their lack of benefits.

In the 80's 25-30% of CS students were women. It's since gone way down. During the tech boom most CS programs made their first 2 classes super hard to weed out people as everyone was trying to be a programmer. This had the effect of driving female enrollment way down.

Desi talked about the need for sponsorship of women going to Rails conferences. Her organization, DevChix, has sent people to Rails Conf at reduced prices. Child care is another issue.

There are a lot of women who are developers in javascript/flash and call themselves designers. But they are really developers who just get paid a lot less.

Even women who develop often see another women at a conference and tend to assume she is a vendor salesperson.

One of the panelists said that she thought Matt Aimonetti (of the Couch DB pr0n scandal) made a mistake in just not thinking about the female developer community. Another said that you can't argue with someone about how they feel. Desi pointed out that had Matt just apologized (and not said I'm sorry that you were offended). And also that David's (DHH) tweet ("Do you think porn is an appropriate metaphor to be used in business presentations?" -- Absolutely. Especially in jest.) did not help.

First off, I'm going spend a minute in non-technical land and say that my wife and I had a fabulous time in Vegas over the weekend. She got to be part of a magic trick at the Penn and Teller show and won 50 bucks from a Wizard of Oz slot machine. Here's some pics of our trip in case you want to see: http://www.flickr.com/photos/7589554@N02/sets/72157617613438444/

The first tutorial I attended was "Running the Show: Configuration Management with Chef" by Edd Dumbill. Poor Edd had a demo involving talking to machines across a network and it didn't go well early. Live coding, combined with installing through the internet, and setting up a local intranet was sort of a triple threat. Any one of those is hard to pull off in front of a few hundred people and all three proved too much. We took a break an hour and a half in and the network issues were mostly worked out.

Chef seems to be sort of a very intense Capistrano. What if you wanted to deploy your app to a bare unbuntu install? Or any other bare install. Well Chef can help you write recipes to set up Apache (and it's config files), Passenger, and any gems you need. The machines you set up (called nodes) will call back in to the Chef server periodically to see if you've changed the configuration. If you have they will update themselves automatically.

Next up was "Solving the Riddle of Search: Using Sphinx with Rails" by Pat Allan. Pat started out with a brief overview of Sphinx (a text search engine) and thinking_sphinx (the plugin/gem that integrates sphinx with Rails). Then he showed a little bit of queries and indexing logic. And then the tutorial sort of ground to a halt as everyone tried to install sphinx (which needs to be built from source via make for OSX). There had to be at least an hour of Pat wandering around trying to help people install it. Which was a little frustrating to the people who had read the email from a week ago and had already installed sphinx. Yes, I was one of those frustrated nerds. Anyway, it gave me some time to work on my slides.

And they needed some work! MetricFu has changed a lot since I last gave a talk about it at Ruby Conf. Since then we've integrated Flay, Reek, Roodi, and re-written almost the whole gem to support yaml serialization. The metric_fu community has been busy.

Whoops, Pat has started up the tutorial again. We're using a project located at: http://github.com/freelancing-god/sphinx-tute/tree/master to try out sphinx live.

Good news, my Sphinx install works!

Sphinx does delta index updates -- where you update only the changes.

>> Place.create :name => "Whatever"
>> Place.search "Blank"
=> [Place id: 484, name: "Whatever", address: nil, city: nil, state: nil, country: nil, lat: nil, lng: nil, description: nil, created_at: "2009-05-04 22:43:15", updated_at: "2009-05-04 22:43:15", delta: true]

See how the delta column is true -- that guy needs to be updated.

Geo-Searching for models that have Latitude and Longitude is pretty cool:

@places = Place.search :geo => [0.630713104998402, -2.00979852231013],
:order => "@geodist ASC"

@places.each_with_geodist do |result, distance|
#distance is in meters

And then Pat said he was done with the tutorial about an hour early. He seems like a nice guy and all but there just wasn't a lot of content for a 3.5 hour session.

To sum up today's tutorials I'd say that I'm happy that, as a speaker, I didn't have to pay for them.