Planet Tech

Signal vs. NoiseBehind the scenes: Redesigning and coding the Highrise sidebar modules

I’ve wanted to redesign the Highrise sidebars for a long time. They’ve felt cluttered and messy to me, and as we add more features to Highrise the mess will only multiply. So I was glad to have the chance this week to redesign the sidebar modules. The visual side of the redesign was straightforward, but implementing the design in code required a few tricks. Here’s a look behind the scenes at the coding decisions we made for the new Highrise sidebars.

“Subjects” in Highrise

Which sidebar modules am I talking about? In Highrise you can keep track of People, Companies, and Cases. These all have the same basic code and UI. You can keep notes about them, set tasks for the future, and manage some common types of metadata. Since People, Companies and Cases share so much plumbing, we’ve abstracted them as subjects. A subject is anything in Highrise that you can attach notes and tasks to. When you look at a subject’s page, you see a sidebar with some modules for adding or editing metadata such as contact information, background information (a kind of static text description), dates to remember for that subject, and more. The screenshot below shows a subject page with the sidebar modules highlighted.

Redesigning the modules

Each module has a header like “Contact Bob” or “Dates to remember” and data below. In the original design, modules can be either “active” or “empty” based on whether they have any data in them. Empty modules have a grey header and an “add” link floated right. Active modules have a light blue header and an “edit” link on the right. We made this distinction so your eye would more easily catch active modules when you’re looking for information. The idea was good, but the original implementation looked messy with its mix of grey and blue, scattered red action links, and lack of separation between modules.

For the first redesign (above) we cleaned up the modules. Active modules are now wrapped entirely in a light grey box with a tiny drop shadow. We killed the blue header style, relying instead on the space between modules to separate them. Empty modules no longer have a header. They are grey boxes collapsed down to a single link to add the content relevant to that module. Finally we replaced all the red links with grey links in order to put the focus on the data within active modules rather than all the possible actions. One last tweak: we changed the text for “About [subject’s name]” to “Add background information.” We’ve gone back and forth a number of times on the language for this feature, and at this stage we decided to try “background info” on for size again.

The first redesign was a big improvement. But we didn’t like the way active and empty modules looked mixed together. The dim bar in between those two active modules creates a kind of striped look that we want to avoid. The problem was worse on subjects with more sidebar modules, like companies or cases. So we decided to group all the active modules together on the top, and then group the empty modules on the bottom. The result is much cleaner, and it’s easier to scan when you load up a subject in order to quickly grab some info like an email address or birthday.

The re-ordered sidebar was a winner. But it came at a price. We couldn’t just change the CSS and call it a day. Now we also had to write code to re-order the sidebar modules dynamically based on whether they were empty or active. Ruby’s power and flexibility really came in handy for this job.

The code

I said earlier that people, companies, and cases are handled by the same plumbing because we abstracted them as subjects. The result of this abstraction is that whether you are looking at a person, a company or a case, the sidebar is rendered by the same template: subjects/_sidebar.rhtml.

(This kind of “view polymorphism” has been subject to a lot of internal debate since we first released the app. It makes maintenance both easier and harder because the code has less repetition on one hand but on the other it is less intention-revealing due to the abstractions and indirection.)

This is what the original template code looked like to render the subject sidebars:

in app/views/subjects/_sidebar.rhtml:

  <% if @subject.is_a?(Party) %>
    <%= render(:partial => 'parties/contact_info') %>
  <% end %>

  <% if show_company_contact_info?(@subject) %>
    <%= render(:partial => 'parties/contact_info', :object => @subject.company) %>
  <% end %>

  <%= render :partial => 'backgrounds/show' %>
  <%= render :partial => 'contact_dates/index' %>

  <% if @subject.is_a?(Kase) %>
    <%= render :partial => 'kases/parties' %> 
  <% end %>

  <% if @subject.is_a?(Company) %>
    <%= render :partial => 'companies/people' %>
  <% end %>

Don’t worry too much about the individual partials and conditions. The key point is that each partial is a sidebar module, and each module is conditioned based on the particular subject we are rendering. A different mixture of partials will be rendered depending on whether the subject is a person, a company or a case, but they’ll always render in the same order.

We want to re-order these partials dynamically based on whether each module is active or empty. That means we need to represent the possible partials, the conditions for displaying them, and also the conditions for determining whether they are active or empty within some kind of data structure. So we popped open our Rails subjects_helper.rb and represented this information in an array.

in app/views/helpers/subjects_helper.rb:

  def sidebar_modules_to_sort
    returning [] do |m|
            # partial to render       module_is_active?                 options                          render the module for this subject? 
      m << ['parties/contact_info'  , show_contact_info_module_on_top?, {}                             ] if @subject.is_a?(Party)
      m << ['parties/contact_info'  , true                            , {:object => @subject.company}  ] if show_company_contact_info?(@subject)
                                        #necessarily true per the condition at right
      m << ['backgrounds/show'      , !@subject.background.blank?     , {}                             ]
      m << ['contact_dates/index'   , @contact_dates.any?             , {}                             ]
      m << ['collections/parties'   , @subject.parties.any?           , {}                             ] if looking_at_collection?
      m << ['companies/people'      , @subject.people.any?            , {}                             ] if @subject.is_a?(Company)
    end
  end

The helper method sidebar_modules_to_sort returns a parent array full of child arrays, one for each module with an element for the template path, a true/false value to show if it is active, and an options hash for the render method. The conditions that used to determine whether each partial should be rendered now determine whether each child array should be included in the parent array. Thanks to that boolean in the second element of each child array, we can partition the parent array into two groups: those where the second element which represents that the module is ‘active’ are true, and those were that element is false. We use another helper method to partition and reassemble the array into groups.

in app/views/helpers/subjects_helper.rb:

  def sidebar_modules_in_order
    active_group, empty_group  = sidebar_modules_to_sort.partition {|m| m[1]}
    active_group.concat empty_group
  end

Finally we return to our sidebar template to do the actual rendering.

in app/views/subjects/_sidebar.rhtml:

<%= sidebar_modules_in_order.map {|m| render sidebar_module_partial(m)}.join %>

This line in the template takes the sorted array of sidebar modules and replaces each element in the array with the rendered partial. Then the join method converts each element to a string and concatenates them. sidebar_module_partial is a call to one more helper. This helper assembles the arguments for render out of the elements provided in the array. It looks like this:

in app/helpers/subjects_helper.rb:

  def sidebar_module_partial(m)
    m[2].merge({:partial => m[0]})
  end

In the snippet above, sidebar_module_partial takes the third element of each module array, which is either an empty hash or some special options for render, and merges a key specifying the template path onto that hash.

We definitely could’ve hidden these rendering gymnastics behind a helper, perhaps called render_sidebar_modules or something similar. However we’ve decided for style reasons to avoid calling render from within our helpers. Therefore we decided to use a helper to merely fill in the arguments to the call to render within the template itself.

In the end, we have a new sidebar design and some clean and intention-revealing code. This was a fun chance for me to expand my Ruby knowledge by dipping into the nuts and bolts of arrays and hashes. Thanks to Jamis for reviews and advice when I knew there had to be “a better way.” We hope you enjoy the new sidebar modules in Highrise.

Related: What belongs in a helper method?

Riding RailsDemo of Rails 2.2 internationalization

Rails 2.2 is going to make it much, much easier to do internationalized sites. Check out Clemens Kofler’s sample app running live or peruse his code. Thread safety? Internationalization? What stock objections to Rails will we have left?!

Signal vs. NoiseActivation fees are obscene

Wanna feel ripped off today? Sign up for an online virtual service that charges a one-time activation fee. It’s a special feeling to hand over $35 for nothing.

I’d almost understand if there was actual work involved. Or hardware was manually set up. Or someone had to climb some stairs and walk down a few halls to flip something on.

But to charge me $35 to “activate” my account by adding a few records to a few databases, well, that feels like… You know what that feels like.

Giant RobotsUmbrella Today?

The Lone Star Ruby conference is about a week away. Chad, Jon, Matt, Tammer, Jared, and I will be running a training session on Thursday.

Our approach to teaching thoughtbot’s Rails Best Practices is to go through our development process for a real application called Umbrella Today?, which we began building two weeks ago. After each 45 minute lecture, we’ll give participants the chance to feel the process in 15 minute hands-on workshops.

Umbrella Today home page

The concept of the app is simple: enter your zip code, get a yes or no answer to the question “Do I need an umbrella today?”

Umbrella Today SMS subscription page

Sign up to receive SMS alerts on days when you’ll need an umbrella.

Hidden complexity

Seems like a simple app, right? Famous last words. Simple enough to take from concept to launch in a few weeks there’s always hidden complexity until development begins.

For Lone Star purposes, we’re happy about the complexity. In addition to best practices like CI, TDD, MVC, and TLC, it gives us a chance to share many small but collectively powerful topics such as:

Umbrella Today confirmation text message

  • attr_readonly
  • Rails template to get things like Factory Girl “for free”
  • modules vs. classes
  • security bugs
  • shoulda_macros directory
  • timezones
  • SMS
  • rake tasks and cron
  • confirmation codes that don’t suck
  • the importance of database indexes

Lone Star to Boston

thoughtbot’s Ruby on Rails training formally kicks off October 14th in Boston. We’ll be building upon our Lone Star/Umbrella Today experience so if you can’t join us in Austin next week, come visit Boston, which is beautiful in the fall. I recommend making a week of it and staying for the Head of the Charles.

Note: register for Boston training by August 31st and get $100 off.

Boston is beautiful

Sam RubyES Decimal Updates

10

A summary of changes to ECMAScript decimal support, based on input from the committee in the last week or so:

  • Operations (e.g., addition, subtraction, multiplication, ...) between 64-bit binary floating point and 128-bit decimal floating point quantities will proceed by first converting the 64-bit binary floating point number to 128-bit decimal floating point to the maximum required precision and then proceeding with the operation.  Previously the proposal was to convert the other way, resulting in a 64-bit binary result.
  • “strict” equality operations (===, !==) will no longer return false when comparing two decimal values with different precisions (e.g., 1.10m and 1.1m)
  • typeof(1.1m) is now "object" (was "decimal")

Output and a summary of the run of the small but growing unit test suite.

Pivotal BlabsTracker in agile project tool review post

Bruno Miranda posted a review of various agile project management tools including Mingle, VersionOne, TargetProcess, and Tracker. Check it out here.

We've let Bruno know that Tracker is actually under active development. One of the first new features that we'll be rolling out soon is a REST API, followed by various usability improvements that will make it easier to work with larger projects.

We're also looking for more suggestions on how to make Tracker better, especially in the area of higher level planning. Send your ideas to tracker@pivotallabs.com, or post them on Satisfaction.

And if you haven't tried it yet, the Tracker beta is fully open to the public, feel free to sign up.

Signal vs. NoiseProduct Blog update: Highrise boosts magic site, flooring company uses Backpack, etc.

Some recent posts at the 37signals Product Blog:

Highrise
Top magic site thrives due to Highrise and Getting Real
“The real crux of our system is Highrise. We use it in managing projects, production, post-production, and marketing. We use it to stay organized. We use it to manage our authorized retailer clients around the world. And we couldn’t breathe as well or sleep as well without it.”

Backpack
All about tags in Backpack
A tag is a simple label or keyword you can use to categorize your Backpack pages any way you want. Then when you click a tag you can see all the other pages that have that tag. It’s a great way to keep your pages loosely grouped in ways that make sense to you.

Scottish wood floor company runs its business using Backpack
“Our first task was to store documents that we use on to our ‘Important Documents’ page. Traditionally these documents were stored on our company server but it was sometimes problematic accessing these via a VPN if we were working from home or abroad. Accessing them on the cloud via Backpack has simplified this task and we are now working faster and with less hassle.”

gallery
McKay Hardwood Flooring, a Backpack customer, installed the flooring throughout the National Galleries of Scotland.

Basecamp
Embedding a tutorial video into a Basecamp project
“I used the same idea to embed our Camtasia videos into our Tutorials project… solves a huge issue for me since before I could only add a link to the video … I have attached a image of how it looks. It was a great help.”

Subscribe to the Product Blog RSS feed.

Pivotal BlabsStandup 08/27/2008

  • Does anyone have any experiences with one of the object mother libraries like object daddy? (Answers at standup were "no, we always wrote our own object mothers in a domain-specific way"). The appeal of a library is that it might help keep track of what needs to be done to make an object pass rails validation.

  • Clock.zone now has exists. (Background, pivotal has a Clock class which has a now method which can be implemented either by a call to Time.now for production, or a mock clock which lets tests specify the "time"). This is so that the rails 2.1 features like Time.zone.now have an analog in Clock.

buckblogSQLite3-Ruby 1.2.3

SQLite3-Ruby version 1.2.3 is now available. It is a maintenance release, fixing just a few things:

  • The permissions on the database.rb and translator.rb files in 1.2.2 were incorrect, resulting in broken sqlite3-ruby installations for many *nix users. This is now fixed.
  • A few more Ruby 1.9 compatibility issues were patched.
  • Some optimizations were applied to speed up iterating over result sets.

To install or upgrade:


  gem install sqlite3-ruby

Thanks!

Signal vs. NoiseThe danger of laughing at your customers

The other day I went to sell some books at The Strand bookstore. They have a separate desk in the back for selling books. I brought in a bag and two clerks started sorting through them.

Then another guy lined up behind me. One of the clerks said to him, “You here to sell books?” He said, “Yes.” The clerk responded, “Wait in the line outside.” The guy went outside.

Thirty seconds later he was back. The clerk repeated, “Wait in the line outside.” The guy said meekly, “There is no line outside.”

The clerk sighed, looked at the other clerk, and sarcastically said, “There is no line outside.” The other clerk said gruffly, “If you can’t figure out the line, then you can’t sell books here.” The potential seller walked back outside meekly.

A minute later, a girl walked up with books. “Wait in the line outside,” said the clerk again. She walked outside. A few moments later, she was back. “What are you doing?” She said, “Selling books.” He said, “The line is outside.” She walked outside again. The clerks laughed. “Let’s see if the Mensa society out there can figure out how the line works!” And they laughed some more. As if both these customers were complete morons.

Lucky for me, I had arrived moments before these other two. Because I sure had no idea there was a place outside to wait in line. Or that “there’s a line outside” actually means “form a line outside.”

I think a lot of people who work in customer service make a similar mistake in laughing at customers or making fun of them behind their backs (PEBKAC comes to mind).

It can be a dangerous trap. Sure, any one customer might be stupid. But if multiple customers are repeatedly making the same mistake, maybe it’s not a mistake on their part. Maybe it’s a mistake on your part. If no one can figure out where to wait in line, maybe that’s a sign that you’re not doing a good enough job explaining it.

Riding RailsJuggernaut: Server-side push for Rails

Juggernaut is a combination of a small Ruby server, a Flash bridge, and a plugin that makes it easy to do server-side push systems in Rails. I played with this idea with Rich Killmer a few years ago and even made a small demo system to present at a conference, but never made it to the finish line of something releasable. So it’s fantastic to see that the guys behind Juggernaut did.

RoR SecurityDoS vulnerability in REXML

Here is a security announcement for the REXML library (links by me) in the Ruby news:

There is a DoS vulnerability in the REXML library used by Rails to parse incoming XML requests. A so-called "XML entity explosion" attack technique can be used for remotely bringing down (disabling) any application which parses user-provided XML. Most Rails applications will be vulnerable to this attack.

Impact

An attacker can cause a denial of service by causing REXML to parse a document containing recursively nested entities such as:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE member [
 <!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;">
 <!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;">
 <!ENTITY c "&d;&d;&d;&d;&d;&d;&d;&d;&d;&d;">
 <!ENTITY d "&e;&e;&e;&e;&e;&e;&e;&e;&e;&e;">
 <!ENTITY e "&f;&f;&f;&f;&f;&f;&f;&f;&f;&f;">
 <!ENTITY f "&g;&g;&g;&g;&g;&g;&g;&g;&g;&g;">
 <!ENTITY g "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
]>
<member>
&a;
</member>

M. Koziarski provides a Rails-specific solution to the problem:

The announcement contains details describing a monkeypatch which can
be applied to prevent the risk.  These instructions are reproduced
below with more rails specific information:

** Versions 2.0.2 and earlier

# Copy the fix file into RAILS_ROOT/lib
# Require the file from environment.rb require 'rexml-expansion-fix'

** Versions 2.1.0 and edge

Copy the fix file into RAILS_ROOT/config/initializers, it will berequired automatically.

There is also a gem available which includes the fix file:

gem install rexml-expansion-fix

Once that command has completed add the following line to the bottom
of your environment.rb file:

require 'rexml-expansion-fix'

Start Up Blogstevie


As webpreneurs we all now employ offshore coders to develop sites using super cool resources like Odesk and Elance. The process is a simple one. But just like all things good, there are some catches. Here’s some advice from someone whose done, does it and occasionally avoids it.

The main thing you need is patience and very considered briefs. When there is a language barrier, ideas and words can be taken very literally.

Our experience is that some (not all) offshore IT practioners are indifferent with ‘visual’ requirements. Maybe it’s a cultural implication. And there are many things we’ve had done much better offshore, like finding creative solutions to technical problems. We’ve worked with some great creative bootstrappers. But it’s clear that more developed markets put a much higher value on ‘aesthetics‘. So we get all our rentoid visuals done locally, while we outsource alot of our backend work. It’s akin to a convenience store you might see in India, there just not quite as pretty as those in Australia and the USA. See below.

Western Convenience Store

Convenience Store India

LachieCan code be art?

For some reason an emasculated twitter-debate flared yesterday, on whether code is art.

Of course, the question is intractable. Art is always elusive, otherwise there wouldn’t be any point to creating it in the first place.

However I’ve been thinking on this subject a bit lately. Toby has an insatiable hunger for drawings of animals, to be wrought by whomever is available/closest. This hunger is so strong that he now associates Daddy’s Computer with the drawing of Elephants:

efant

Of course I now have it on good authority that my credentials on the subject of art and code are inadequate. But I’ve still been thinking about it enough to raise a slew of illustrative questions.

Is art available to everyone?

Is a child capable of detecting art? At what age do people become sensible of art? Can all people appreciate art?

If No, then who decides? Is there a gold standard, at least a committee?

If code could be art, who would decide if it actually was?

What is art?

For example, is anything within the realm of industrial design art?

Is a beautifully designed car art? I had this discussion with Dad the other day, and you’d be hard pressed to persuade him that car design is anything lower than the height of human sophistication and art.

Obviously this is completely subjective, even inside art’s own walls.

Is literature art? Its not much to look at, but it can certainly manifest as art inside your head. Is a play art? Is its script art, or only a production thereof? And is an amdram production less arty than a big name one?

Maybe code’s concepts or manifestation could be considered to be art. Or maybe code is only art if you do it like _why.

Science

Programming is part of computer science, but I’m fairly sure we don’t usually treat it as such (though maybe unit tests are moving us back towards the scientific method). There’s abundant beauty in science but it’s not art.

For example, is Flickr more the result of computer science, or the imagination of a small group of people?

Apples, oranges & elephants

Ultimately I think that comparing code and art is an impedance mismatch, but that perhaps the manifestation of code as an application could be considered as art.

And, even if code is art, I think that we’re all still at the stage of kiddies who daub their masterworks with arbitrary parts of their body. Kiddies who appreciate most pictures as art, as long as they have elephants.

raganwaldLinks for 2008-08-26 [del.icio.us]

Robot Has No HeartYou don't need view logic in models

Jake Scruggs wrote about moving view logic into his models

It’s hard to tell without knowing the full dataset, but my approach to these sort of problems is to reduce the data down to the simplest possible form (usually a hash), and then use an algorithm to extract what I need.

One commenter tried this and I think it’s heading in the right direction. There is potentially quite a lot of duplication here – the repetition of the layouts and scripts. To ease this it can sometimes be easier to inverse the key/values, for a more concise representation. You could reduce this even further if there were sensible defaults (if 90% of cars used a two_column layout, for instance) – just replace the raise in the following code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# See original post for context
# Data
layouts = {
  'two_column'   => [Toyota, Saturn],
  'three_column' => [Hyundai],
  'ford'         => [Ford]
}

scripts => {
  'discount' => [Hyundai, Ford],
  'poll'     => [Saturn]
}

# Algorithm
find_key = lambda {|hash, car| 
  (
    hash.detect {|key, types| 
      types.any? {|type| car.is_a?(type)}
      # types.include?(car.class) if you're not using inheritance
    } || raise("No entry for car: #{car}")
  ).first
}

layout = find_key[layouts, @car]
script = find_key[scripts, @car]

@stylesheets += ['layout', 'theme'].collect {|suffix| "#{layout}_#{suffix}.css" }
@scripts     += ["#{script}.js"]

render :action => find_view, :layout => layout

This is preferable to putting this data in your object hierarchy for all the normal reasons, especially since it keeps view logic where you expect to find it and doesn’t muddy up your models.

Pat AllanRails Camp UK Report

Just over a week ago, the first Rails Camp in the UK was held in Downe, outside Orpington – and I think it was a fantastic success (having been the organiser though, obviously there is some bias).

We had quite an international flavour to the weekend. Of the 30 or so who attended, several were from around Europe, alongside the local British, and a few of us Australians to round it out.

The Beer Disappears

In true Rails Camp style, around the beer, pizza and games, much hacking and discussion was had – assisted by the *jour gems, twetter and SubEthaEdit. Plenty of cool projects were displayed and created – topics ranging from RSpec to EXTJS to in-memory models to plugins to CouchDB to approaches for better browser-server polling (with a neat browser game as an example).

Railscamp UK 2008 (8 of 12)

One of the cool creations of this Rails Camp has gone live. The collective talent of the RailsLove guys and Rany Keddo produced a forkable lists web app called Don’t Forget The Wurst – and features William Shatner, which just adds several levels of awesomeness to an already neat idea.

Werewolf

Massive thanks to all who came along and made it such a fantastic weekend – I’m looking forward to hearing about another Rails Camp in this part of the world (even if I won’t be able to attend it).

Matt and Simon

Also, if you’re in Europe, you might want to check out the German and Danish Rails Camps, which will be happening later this year. Australians, Rails Camp #4 will be happening in November (details are almost finalised). Everyone else: I highly recommend making one happen near you. There’s now a group of us who have dabbled in the organisation of them, and we’re more than happy to help however we can to get more of them happening around the world. It’s not too hard, and it’s an awesome way of strengthening your local Ruby community.

Balancing

Joel on SoftwareHow I Learned to Love Middle Managers

Inc. Magazine“Another programmer came to us. ‘I thought you should know that people are really unhappy,’ he said bluntly, ‘and it’s starting to make it so that people just complain all day, instead of doing their work, and that’s not good.’”

From my latest Inc. column: How I Learned to Love Middle Managers

Not loving your job? Visit the Joel on Software Job Board: Great software jobs, great people.

Pivotal BlabsHow to tell Apple/DotMac/MobleMe Backup that .Trash is trash

First of all, fie on Apple for giving both their cloud storage service and their backup program names that are almost completely google-proof. They've recently corrected one of those by renaming "dot mac" to "MobileMe" but calling your backup program "Backup" is a great way to make it really hard to investigate. It's like, imagine how hard it would be to do a background check on someone named John Doe.

So I use the Dot Mac Backup and it works pretty smoothly, which is the second most important feature in a backup program. (The most important feature is the ability to actually restore files.) But then one day it said that to incrementally back up my "Home Minus Media" set -- the set containing my Home Folder, but excluding big-ticket items like Music, Movies, Backups, Downloads, and so on -- would require 63 DVDs. WTF?

It turned out that the problem occurred after I trashed a few old DVD rips that I had finished watching, and the culprit was the directory /Users/chaffee/.Trash. Seems like the UI was helpfully excluding it from the list of subdirectories of /Users/chaffee, it being a system file and all, so I couldn't mark it to exclude. That's OK, I think, I'm a power user, so I'll just check the box that says "Show invisible system files."

Except there's no such box. Try as I might, I can't find a way to exclude the Trash folder from the UI. I had to dig into the file system and edit Backup's own data file, as follows.

  • In Backup, create a backup set and exclude at least one item in it
  • Quit the Backup app
  • In Finder, open up ~/Library/Application Support/Backup/BackupSets
  • There will be a list of randomly named .backupset folders. Each contains a folder named Contents. For each, use Quick Look (hit Space) on and a file named InfoPlist.strings to find the one containing your set.

Finding your backup set

  • Open its sibling named User.quickpick in a text editor like TextMate.
  • Find the section "Prune Paths" and add an entry for ~/.Trash

Prune Paths

  • Save the file and relaunch Backup.

You should see the ".Trash" entry excluded as if you had clicked on it -- which you would have if they had showed you the silly thing in the first place.

No Trash

As you can see from the screenshot, I've still got some excess gigabytes to hunt down and exclude, but at least I won't get burned the next time I erase a metric buttload of pr0n-- uh, I mean, content I legally acquired and temporarily transferred onto my personal computer in compliance with the DMCA.

Sam RubyW3C HTML 5 Conformance Checker

Karl Dubost: We are happy to announce that W3C has integrated a version of HTML 5 conformance checker into a beta instance of the W3C Markup validator. That will help us to detect bugs, improve the user interface, and benefit from the large W3C communities.

Gotta love the “random” page that Olivier Théreaux chose to mention in his announcement.

Pivotal BlabsStandup 08/26/2008

  • Looking for options to maintain a website of technical documentation with the following:

    • A somewhat technical person, but not a programmer, must be able to maintain the site (think a technical manager or a tech writer).
    • I need to display code samples, so this should be easy/convenient
    • Somewhat skinnable (custom logo, custom fonts & colors)

    The ideal examples would be the google chart api or google maps api

    A possible solution is a wiki (mediawiki?). Something google-code-like gets extra points for the issue tracker. Google groups gets points for the mailing list. Google sites seems like is might be a decent basic option (it's easy to point a CNAME at it too).

    Experience reports/recommendations appreciated.

  • Rails hackfest is on through the end of August. Get points for getting patches accepted, and win prizes.

buckblogCap 1.4.1? Go 1.4.2. Now.

Are you currently using Capistrano 1.4.1? If so, drop everything (I mean it, do this RIGHT NOW) and install Capistrano 1.4.2.

Why, you ask?

Capistrano 1.4.1 will work just fine, right up until you decide you want to experiment with Capistrano 2. When you do that, Cap 2.3+ will install net-ssh 2.x, which kills Capistrano 1.4.1 in all kinds of really obscure ways.

The good news is that Cap 1.4.2 is completely compatible with Cap 1.4.1. It adds no new features. The only “bug” it fixes is that if you ever install net-ssh 2.x, Cap 1.4.2 will still happily continue to work.

Ultimately, an upgrade to Cap 2 is recommended, but I understand it’s not feasible for everyone. So, if you’re one of those who can’t go cap2 yet, please please please PLEASE PLEASE FOR THE LOVE OF ALL THAT IS HOLY upgrade to Cap 1.4.2. It’ll make your life easier, and it’ll make my life easier (because I won’t have to keep troubleshooting the same issues over and over). Thanks!

Ola BiniMoving away from blogspot

This will be my last post on this blog. For several reasons I like the idea of keeping more in control over my blog and the environment surrounding it. I also have some things I'd like to publish that isn't well suited for the blog format, and moving to another location means that I can keep all my content in the same place. More long term I'm planning on migrating information about my open source projects there to.

But what you need to know is this: This blog ends. A new blog is born. All my old entries have been migrated. The important addresses for the new blog is:
And that's it. The new content will obviously be available at http://olabini.com, but right now this site just redirects to the blog.

The blog is dead, long live the blog.

Signal vs. NoiseArchitects: 1998 called and it wants its web sites back

I’ve been poking around a lot of architects’ web sites lately and I’m thoroughly surprised at how bad they are. It seems almost without fail that they are either blowing my browser window up full size, asking me to read light grey 9px text, overflowing with obfuscatory flashterbation, teasing me with custom designed scrollbars that don’t behave as you’d expect, or asking me to evaluate their work based on postage stamp sized photographs. It really feels like 1998. I see I’m not alone in this observation.

Architects have so much to gain from the web. Big huge photographs of their work, clear statements of who they are and what they believe in, easily linkable and sharable portfolio pages, daily links of interest.

As it stands today, if you want to show someone an interesting piece of work you usually have to give them a step-by-step guide on how to get there: First go to the home page, wait for the countdown timer to expire, then hover over the logo, then grab a magnifying glass, then squint, then click the 4th tiny icon on the left (I can’t really tell what it is), then use that custom scrollbar that looks like an elevator, then take a screenshot, then pull that screenshot into Photoshop, then zoom in about 8 times so it’s all nice and big on your screen, then take about 10 steps back from your computer, then look.

I’m only half kidding.

Come on, architects, get with it! Anyone got any links to a great architect’s site that bucks this trend?

raganwaldLinks for 2008-08-25 [del.icio.us]

Start Up Blogstevie


Here’s an insight from web polymath Chris Sacca straight from his twitter page.

Timely advice during the movement to hand held devices.

LachStockLocal Government on the Open Web

Lachlan

Photo: Ben Buchanan

The Presentation

The awesome team of Diana Mounter and Reem Abdelaty from the LGwebnetwork asked if I would deliver the closing keynote for their first ever web conference, WE Believe in Community. I was honoured to accept.

I wanted to show people what I see in the web. What I see happening. Where I think everything is going. But I’m a firm believer in showing people techniques and technologies they can use right now. All of which made it very easy for me to talk about the Open Web. There’s an entire blog post I’ve been meaning to write for a long time about that, so we won’t get into it here. This is just to post my slides and to say that video and a podcast will be forthcoming at some point in the future. (I hear end of the week.)

The conference

Put together in only a few months to meet a pressing need for stronger networking and more formal professional development for local government web workers, the entire experience was amazing. Both Reem and Diana radiate energy and passion and they communicated this to every attendee. There was a huge buzz of engagement and involvement. It was a real privilege to be a part of it!

The other big win of the two days was the outstanding quality of the content. John Allsopp delivered a stirring opening keynote of what constitutes the web and how you can expect to access it going forward. He delivered some concepts I’m going to be thinking about for a long time. I particularly enjoyed these quotes too:

  • “the web just connects stuff together, do you really think you need a screen?”; and
  • “local government should be be building the networks, they’re the sewers of the 21st century”.

Another presentation that I really enjoyed was Matthew Hodgson on the death and rebirth of intranets. He had a clever premise and great solid content that intertwined really well. He also managed to record himself, so he has audio up already! Unfortunately, I missed Ruth Ellison’s as she was just before me (and I was in the tea room doing the obsessive compulsive slide check), but she has her (and Adrian’s) slides up already along with a great summation of each presentation she saw. There were lots of other great speakers, so hopefully they’ll be putting their slides up soon too.

My very first Apple product

Photo: Ruth Ellison

All up, a fantastic couple of days. Thanks to all the great new people I met for arguing with me over drinks about the open web and why it’s important. And thanks again to Diana and Reem for creating such a charged event! Not to mention the incredibly generous gift thanking speakers &emdash a customised iPod Shuffle.

See more photos and tweets on the Open Web.

Signal vs. Noise37signals Live: Wednesday, August 26 at 11:00am central time

The next 37signals Live will be tomorrow, August 26th at 11am central time.

The first two Live shows were general Q&As. This time we’re going to narrow down the focus to chapter 13 of Getting Real: Promotion. Generating buzz, getting press, promotion without a budget, launch, etc.

Come armed with questions and we’ll fire back answers. We’ll see you tomorrow at 37signals Live!

Signal vs. Noise37signals Live: Tuesday, August 26 at 11:00am central time

The next 37signals Live will be tomorrow, August 26th at 11am central time.

The first two Live shows were general Q&As. This time we’re going to narrow down the focus to chapter 13 of Getting Real: Promotion. Generating buzz, getting press, promotion without a budget, launch, etc.

Come armed with questions and we’ll fire back answers. We’ll see you tomorrow at 37signals Live!

Start Up Blogstevie


One of my favourite business maxims is the Single Minded Proposition. The retailer below ‘used’ to have a single minded proposition as a $2 shop. They’ve had a recent name change…

If you’re going to be very specific in your business model - make sure it’s timeless.

Footnotes