jordanhollinger (a web log) Ignorance more frequently begets confidence than does knowledge. - Charles Darwin

Deploying your own EtherPad on Ubuntu

There are lots of walkthroughs on setting up your own EtherPad instance running around out there, but many of them either stop after localhost:9000 (hardly useful for a collaborative editing tool) or just don’t quite fit your situation.

I wanted to set up a public instance running at etherpad.jordanhollinger.com running behind an Apache proxy on top of Ubuntu Server 9.04. If you want to do something very much like that, this may be the walk-through for you. Otherwise, keep searching.

Before we begin you should

  • be comfortable on the Linux command line
  • have some notion of configuring Apache
  • realize the EtherPad code base is in a state of flux
  • realize this walk-through is intended more for a hobby instance than a fully-secured and enterprise-ready installation
  • accept that your milage may vary

Also, note that the material for walk-through was culled from some wikis, several other EtherPad walkthroughs, and the Apache Web Server documentation. If at any point you run into trouble, you may want to peruse some of these source documents:

Prep your Env

First, open your apt repository list,
sudo vim /etc/apt/sources.list

add
deb http://archive.ubuntu.com/ubuntu hardy universe multiverse
deb-src http://archive.ubuntu.com/ubuntu hardy universe multiverse
deb http://us.archive.ubuntu.com/ubuntu/ hardy-updates universe multiverse
deb-src http://us.archive.ubuntu.com/ubuntu/ hardy-updates universe multiverse

and run sudo apt-get update.

Now that we have access to all the packages we need, we can install them.
sudo apt-get install sun-java6-jdk scala mysql-server mysql-client libmysql-java mercurial apache2

Download the MySQL Java connector from www.mysql.com/downloads/connector/j/ and move it to /usr/share/java/mysql-connector-java.jar.

We’ll need some environmental variables set. You can edit /etc/profile or create something like /etc/profile.d/etherpad.sh. Add the following:
export JAVA_HOME="/usr/lib/jvm/java-6-sun"
export SCALA_HOME="/usr/share/java"
export MYSQL_CONNECTOR_JAR="/usr/share/java/mysql-connector-java.jar"

You’ll need to restart your shell for these to take effect.

Grab the Pad

hg clone https://etherpad.googlecode.com/hg/ etherpad

cd etherpad/trunk/etherpad

Patch the Pad

For the installer to find everything it needs in Ubuntu, you’ll need to edit ../infrastructure/bin/makejar.sh:

-JARFILES=`echo $SCALA_HOME/lib/scala-library.jar lib/*.jar lib/manifest`
+JARFILES=`echo $SCALA_HOME/scala-library.jar lib/*.jar lib/manifest`

- $JAR xf $SCALA_HOME/lib/scala-library.jar
+ $JAR xf $SCALA_HOME/scala-library.jar

At this time, “etherpad.com” is still hard-coded in lots of places under src/. You’ll need to change this to your domain. To get a list of all the files you need to change, run
grep -irl "etherpad.com" src/

One particularly important file to change is src/etherpad/globals.js. Be sure to add your domain to the SUPERDOMAINS hash.

Now bin/setup-mysql-db.sh needs some patching:
Add mysql="mysql" right above db="etherpad".
Add -pMyPassword after -u root in the two mysql calls.

Configure the Pad

Open etc/etherpad.localdev-default.properties and change

  • devMode to false
  • etherpad.isProduction to true
  • listen to localhost:9000
  • etherpad.isPNE to true (only if you want to run in PNE mode – I don’t know what that means)
  • etherpad.adminPass to something better

Put it in a jar

bin/rebuildjar.sh

This may take awhile. You’ll only need to do it again if you ever change anything under ../infrastructure.

Run it

bin/run-local.sh

You should now be able to access your EtherPad locally through localhost:9000, but that won’t do anybody any good, especially since we’ve hardcoded your domain all through it.

Configure Apache to proxy

Setting up the proper DNS records and locking down your server is left as an exercise to the reader.

Create an apache virtual host file like /etc/apache/sites-enabled/001-etherpad

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<VirtualHost *:80>
  ServerName etherpad.yourdomain.com
  ServerSignature Off
  
  ErrorLog /var/log/apache2/etherpad.yourdomain.com/error.log
  LogLevel warn
  CustomLog /var/log/apache2/etherpad.yourdomain.com/access.log combined
  
  ProxyPass / http://localhost:9000/
  ProxyPassReverse / http://localhost:9000/
  ProxyPreserveHost on
  <Proxy *>
    Options FollowSymLinks MultiViews
    AllowOverride None
    Order deny,allow
    Allow from etherpad.yourdomain.com
  </Proxy>
</VirtualHost>

Create your logs directory:
sudo mkdir /var/log/apache2/etherpad.yourdomain.com

Make apache the owner:
sudo chown www-data:www-data /var/log/apache2/etherpad.yourdomain.com

Enable mod_proxy:
sudo a2enmod proxy
sudo a2enmod proxy_http

Restart Apache:
sudo /etc/init.d/apache restart

That’s it!

Collaboration is just a website away, all in the comfort of your own domain. Some features will be disabled, like email (unless you set up SMTP on your server) and a few of the export formats. Some have had success enabling more features. Try it out if you’re brave. It will be exciting to see how this develops as an open-source project.

EtherPad

Late in 2009 Google acquired AppJet, the company responsible for the popular collaberative Web-based text editing tool, Etherpad.

Presumably this is to beef up Wave’s feature set, which is way cool. Uncool though, was the announcement that free public “pads” could no longer be created, and the entire service would be discontinued on March 31, 2010. After much uproar, Google and EtherPad revised their stance, promising to leave the site up and free to the public until the entirety of the source code (and the AppJet platform running it) could be opened to the public, allowing anyone to host his or her own Etherpad instance.

Though the process is still in the early stages, many are already setting up their own EtherPad instances, getting ready for the day Google pulls the plug. I’m among these hordes, and I’ll probably toss up an Ubuntu server walk-through once I get mine fully working at etherpad.jordanhollinger.com.

Unobtrusive in-field text labels

Warning: This post concerns Web interface development and may be appear as arcane to many. It also contains HTML and JavaScript examples that may not render properly in feed readers or importers like Facebook. Follow the link back to the original post if you’re having trouble.

In HTML user-input forms, it is not uncommon to see text fields with “labels” as grayed-out text in the field itself which disappear when clicked.

My search for “best practices” on this technique left me…wanting. Firstly, I wasn’t sure what to call it. Secondly, many implementations were riddled with problems, paramount of which was abominable degradation. I am no accessibility expert, but these solutions didn’t even try. Here are two of the most common, and unfortunately, the worst.

Trickle-down

Initially this method looked promising. You explicitly set the value of the field to your label string which trickles down to the defaultValue attribute. You can then use defaultValue to determine when to clear or reset the label. Problems:


  • Mean to screen-readers, non-JavaScript browsers, and those who use them
  • Mean to your controller/form processing code (it somehow has to know to ignore your labels when they’re posted as values)
  • Mean to forms that edit existing data (did defaultValue come from the label or from real data? If it’s real, there is no way to default back to the label if the user removes the value)
  • Depending on the implementation it can be obtrusive

Some of these issues can be resolved through code, but it’s not going to be pretty.

Hidden fields

This, uh, solution, displays a “throw-away” text field as the label. On click, it’s replaced by the real field. To the user it appears that the text just disappeared. This has all the problems above plus some:


  • Really really mean to screen readers and non-JavaScript browsers (there will be duplicate fields with text already in them for no apparent reason)
  • Really mean to controller/form processing code (it has to arbitrarily ignore entire fields, not just values)
  • It’s unbelievably intrusive
  • It’s just a horrible idea on par with suggesting users place and remove labeled Post-it notes when moving from field to field

A better way

First, there may be an Even Better Way, but I believe this address all of the problems above, both practical and conceptual. In a nutshell, you set the field’s title, which you should be doing for accessibility reasons anyway. Optionally add a “real” label tag linked by id to it’s input field. JavaScript then looks for titled fields with blank values, hides their labels, sets the value to the title, and binds focus and blur events to the field. These respectively clear and reset the label (by comparing the value to the title) when users click on or off. On form submit, if any of these fields’ values match their titles, they are cleared by some JavaScript. Benefits:


  • Unobtrusive
  • Graceful degradation (screen-readers and non-JS browsers can fall back on the real label or title attribute)
  • Uses all field attributes for their intended purposes
  • Places all responsibility/logic in one location, removing the need for controllers to treat certain values or fields specially
  • No Post-it notes

A possible draw-back is that users cannot submit a value that matches the field’s title. If that’s a real problem, you could probably add some more checks to hack around it. But how often is someone’s first name First?

My implementation uses >= jQuery 1.3. Since we’re on the Web anyway, I thought I’d throw in a working example below:

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<form id="form_field_label_example" action="" method="post">
  <p>
    <label for="first_name">First</label>
    <input id="first_name" name="first" size="15" title="First" type="text" />
    <label for="middle_name">Middle</label>
    <input id="middle_name" name="middle" size="8" title="Middle" type="text" />
    <label for="last">Last</label>
    <input id="last" name="last" size="25" title="Last" type="text" />
</p>
</form>
<script type="text/javascript">
$(document).ready(function() {
  auto_label("form#form_field_label_example input[title][type=text]")
})

function auto_label(str) {
  $(str).each(function() {
    // Hide the field's real label
    $('label[for=' + this.id + ']').hide()

    // Set the label text and color for blank fields
    if ( !this.value || this.value == this.title ) {
      this.value = this.title
      $(this).css('color', '#999')
    } 
      
    // On focus of blank fields, clear the label text and reset the color
    $(this).focus(function() {
      if ( this.value == this.title ) {
        this.value = ''
        $(this).css('color', 'inherit')
      } 
    })
      
    // On unfocus of blank fields, restore the label text and color
    $(this).blur(function() {
      if ( !this.value ) {
        this.value = this.title
        $(this).css('color', '#999')
      }
    })
  })    
        
  // Clear label text when submitting form
  $(str).closest('form').submit(function() {
    $(str).each(function() {
      if ( this.title && this.value == this.title ) { this.value = '' }
    })
  })
}
</script>

Here's irony for you

So my hard drive just bought the farm. I always tell people to back up their data, and fortunately I was smart enough to listen to my own advice. In fact I wrote my own backup program because I wasn’t fond of the existing solutions.

Pat on the back, right? Unfortunately the most recent backup is about a month old, so I’ve lost some recent work. The irony is of course that the recent work I lost was a major refactoring of the backup program.

What's your car's ringtone, man?

Bloomberg reports electric cars are too quite and are running down the unsuspecting blind, young, and elderly. Clearly this is bad for business.

An early idea was for electric cars to re-create the sound of combustion engines, but fortunately Nissan has taken a stand for aesthetics and is moving towards a “beautiful” and “futuristic” sound, like Blade Runner’s flying cars. The sound is completely artificial, I imagine emanating from an unobtrusive external speaker system.

While that’s awesome, the next logical step is even cooler: custom “ringtones” for your car. Don’t like the flying car loop that came bundled with your Chevy Volt? Upload an mp3 of the Enterprise warp core or George Jetson’s car.

And has anyone thought about what the blind are going to do when we have real flying cars? They won’t know whether to duck or run. This isn’t a solution, people!

Plains, Rails, and Automobiles

I am sitting the Dallas-Fort Worth airport, having happily found a data port and an Ethernet cable in my laptop bag. (Apparently air travel profiteering precludes the possibility of free wireless access here.)

RailsConf 2009 was definitely a success in my book. Among my favorites sessions were talks on testing, automated code quality checking, user-interface design principles, caching, Metal and Rack, and a brief introduction to Sinatra.

During the final keynote, an informal poll was taken concerning the Las Vegas venue. Surprisingly, quite a few didn’t think it was that great. Personally, I enjoyed it more than I expected. I spent one night walking the 6.6 miles up and down the Strip taking pictures, another watching the new Star Trek movie at an IMax, and a third at Blue Man Group. Most of Saturday I hiked around Red Rock Canyon, again with my camera. I don’t understand how or why someone would come to that part of the world spend all their time at a poker table, or walking up and down a few blocks of pavement. There is no doubt in my mind that what’s out of doors in Vegas is of much more worth than what’s inside them. But maybe that’s just me.

The District

Got back to Kentucky last night after an 8 hour drive from D.C. Went to visit some friends and see the sights…again. I think this makes three visits in the past two years. But there was still plenty to see, including the White House and a private tour of the Capitol Building.

For a city, D.C. has a surprising number of parks and greenery in general. I’d like to go back sometime and focus a little more on that side than the stone. In particular Theodore Roosevelt Island and some of the jogging trails around it.

This was the first trip I’ve taken with my new camera, which I love. I tried to capture a little stone, a little nature, and a little…color.

The Jefferson Memorial, one of the more aesthetically pleasing of the monuments. Reminds me of Monticello, which I can only imagine is intentional.

Tulips, which threaten to displace humans as the city’s dominant population.

Lightsaber Dude. I don’t know what this guy’s deal was, but he kept hanging around the World War II memorial. “These are not the monuments you are looking for.”

Breakfast at Tudor's

I met a friend for breakfast this morning at Tudor’s Biscut World. If you’re not from West Virginia, you probably haven’t heard of Tudor’s. And you’re probably at less risk for heart disease.

To paint this picture, we’ll need plenty of bitter coffee, heavy accents, and cholesterol. It will be an oil-based painting. Lots of grease. This morning’s special was the “Big Tater,” an amalgam of fried potatoes, bacon, eggs, and sausage gravy topped with cheese. There are three of these greasy spoons in my hometown of 11,000. As their patrons steadily die off from massive coronaries, Tudor’s will eventually run themselves out of business.

I went with a simple sausage biscuit, but still left feeling as though I had put a brick in my stomach. Unless I don’t make it to tomorrow, Merry Christmas!

Bent keys don't start cars

That was my morning. Hopefully bent keys can be copied.

Newman!

I just walked into my local Post Office to buy stamps. I always go after hours and have to use the stamp vending machine. So I walked in counting my change, lifted my hand to drop in some quarters, and discovered that the machine was gone. No “Out of service,” signs, no “Sorry for the inconvenience.” Just a big empty wall. Frustrated, I walk outside and see that they’ve also removed those blue mail boxes which dot American cities like Lady Bird Johnson’s Interstate wildflowers. What kind of two-pony circus is running this?

These jokers have been over-saturating the market for decades. Think of all the places you can buy stamps and mail letters: grocery stores, post offices, pharmacies, adult book stores (just a guess, but why not?). They’ve been steadily increasing the price of stamps for years to pay for all this cruft, and people have been cutting back their stamp usage, which only adds to their financial woes! Now they’ve gone and hired some efficiency expert from Circuit City, and he’s telling them to start selling off their assets!

They’re creating this stamp shortage to inflate demand and artificially drive up prices so they can stop flushing money down the commode! How is Obama expecting to implement a national health care system when the government can’t cost-effectively send a piece of paper across the country?

Ok, I’m not really serious about most of that, but I am very curious why my Post Office has gotten rid of all its stamps and mail boxes.

Web pizza

I just ordered a pizza online for the first time. It’s an incredible concept. I fill out a Web form, type in my credit card number (another unsettling concept), and expect a pizza to show up. I actually selected “pickup” which seems even more strange. In a few minutes I’ll blindly drive off with utter confidence in Papa John’s IT infrastructure, expecting humans with whom I’ve had no contact to hand me a piping hot pizza and let me walk off with it.

Tolstoy goes to NASCAR

First, let me say that NASCAR is the largest convention of drunken, sunburned southerners in the nation. (Not that there’s anything wrong with that.) Yes, there are some cars there too, but they play second fiddle to the $7 cans of Bud.

This past weekend I took a trip to Dover, Delaware to see a NASCAR race. I’ve never been to a NASCAR race. I’ve never watched a NASCAR race on television. I don’t like NASCAR. But according to my roommates, that’s no reason not to go. In case it proved as boring as I supposed, I brought along Tolstoy’s War and Peace, through which I’ve slowly been plowing this past year. I believe it was the first and only time any literature was within 20 miles of the track.

Arriving with no tickets, we hoped to find a deal from season ticket-holders or fans trying to cut their losses. The first joker we approached tried to sell us his $90 tickets for $100. After understanding we wouldn’t bite, he replied, “I’m a doctor. Tell me your symptoms.” We tried “the walk-away,” and he immediately dropped to $50, but no lower. He was obviously staking out first-timer yahoos who’s opening line would be “I’m new in town” or “What’s your rock-bottom price?” Finally we got ahold of a few for around $20.

The race wasn’t too bad. There was a nice crash in lap 17, but the other 382 laps were all about the same. My driver (McMurray, whom I picked at random) finished in the top 10, saving me from losing the bet. (Loser bought everyone soft serve at McDonald’s.)

I can’t see ever going to another race, but it was worth it this once. The 10 hour trip back to Wilmore, Kentucky was largely uneventful. High points included running over a dead deer and free soft serve refills at McDonald’s. It was a good weekend.