When cache is king

Caching is a fine thing. Except when its not.

After updating some audio that is played to people who phone our Twilio app, we ran into an issue with callers still hearing the old prompts. Our app manages jillions of prompts, and for a variety of reasons we chose to make the prompt filenames static, adhering to a naming convention that uniquely identifies each of our customers. In our case, customers sometimes add static links to ‘their’ audio and we don’t want those links to ever change. (Web browsers, for example, grab the updated audio just fine.)

We don’t update prompts that often, but when we do, we need them to go ‘live’ immediately.

The issue is that Twilio (reasonably) caches remote audio urls to avoid having to reload them every single time an audio is played.

Twilio technical support offered a very workable solution… their urls are cached with the query string in the url, so if we add ?version=XXX at the end of our audio urls, each time we bump XXX it forces a reload of the “new” file into Twilio’s cache.

In our case, we added a single system-wide counter that we bump when anything changes. We’ll eventually get around to maintaining a version number for each file.

Using Heroku ENV config vars with Settings.yml

The crew discovered today how to include Heroku config variables in the settings.yml file. It was working for simple constants like 10, but was crashing the app when the constant was something more complex, like a URL.

There are a lot of reasons to deploy Heroku apps with certain constants in Heroku’s config variables. Keeping passwords or backoffice urls out of the source code is one reason. Or if you deploy the same source code to multiple Heroku instances, such as a staging server.

Suppose you have a Heroku config variable called MYAPP_FOO.

This works ‘sometimes’:

# settings.yml:  
my_foo_simple: < %= ENV['MYAPP_FOO'] %>

However, if MYAPP_FOO is a url such as http://mydomain/mypath/ it will crash your app.

This works ‘always’:

# settings.yml:  
my_foo_simple: "< %= ENV['MYAPP_FOO'] %>"

My favorite guerilla marketing story (so far)

I get asked if there was a truly pivotal moment that led to my last IPO, a moment where everything hung in the balance, when sheer determination tipped the scale. Here’s the moment that comes to mind…

Once upon a time, around ’95, I got this crazy idea that the still-nascent internet would be the best medium for training since chalk. At the time, CBT (computer based training) was the end-all for corporations, and Asymetrix was the king of CBT tools. We were out to disrupt the whole notion of shipping CDROMs and having people mail (not email, mail) the training results back to someone who then more or less manually compiled the results.

So my small team built the world’s first internet-based training system for authoring and publishing interactive training courses on the internet. But… how to market it?

Back in the day, before google ad words (heck, before google, before webex, before most corporate training departments even used email) a poor startup had a harder time getting any meaningful customer traction on a shoestring. You hopefully got a little press to get them to call you. You visited them. You demoed. Old school. And hitting the road to talk to customers was pretty expensive.

But I’ve always been a “bring the mountain to me” kinda guy, so I started thinking “where is one place I could meet a lot of the people I wanted as customers?” And the annual Asymetrix User Group seemed like the perfect place, seeing as how they were precisely the people who needed our product. So I registered as a vendor, paid the exhibitor fee. Our registration was accepted. So for the next couple of months we got ready… booth, cool demos, sexy new features, the works.

About a week before the conference I got a call from the Asymetric VP of marketing who politely, but firmly, explained that even though they did not have internet tools, we were clearly competitive, and no way would we be permitted to exhibit at their user group, and our refund check was in the mail. Period. Two voicemails appealing to the CEO went unreturned.

My first reaction was, as The Dude says, “This will not stand.”

I’d sunk every marketing nickel into getting ready for the show. The thought of so many of ‘my’ fortune 500 training directors being in the same building at the same time, so close yet deprived of the chance to see my world-changing invention, was unacceptable.

So we immediately
1) Secured a permit from the city to hand out flyers on the sidewalk outside the convention center where the Asymetrix User Group was held
2) Hired a enough actors to cover all the entrances
3) Gave each actor a big stack of flyers that said “Welcome to Seattle! After you enjoy the Asymetrix User Group today, walk right across the street and see the new training technology that Asymetrix refused to let exhibit, while you enjoy some great Pacific Northwest salmon and wines.”
4) We also gave each actor a copy of our permit (just in case, which turned out to be useful, since Asymetrix did in fact try to tell them they were illegally handing out flyers).

Turns out, using actors was a fantastic idea my sales guy John suggested. We used actors because, well, they work cheap, and are able to really get into “the role” of being articulate, fun, energetic, engaging, polite, and slightly mischievous.

And that little stunt is how we got Boeing as one of our first customers. Which is how we got two brand-name VC’s to invest. Which is how Docent.com went public.

P.S. Oh, one more thing. After my company’s IPO, Asymetrix merged with us.

Multiple subdomains, multiple apps in Heroku

For a variety of reasons we sometimes want to have multiple subdomains point to one heroku app, and then have another ‘main’ app or webpage pointed to by www. It’s easy to configure. The other explanations I read are a little general, here are the specifics…

The explanation at heroku is very good, at : http://docs.heroku.com/custom-domains (there’s even a very good screencast shows step by step)

the key thing is if your ROOT domain (mycoolsite.com) is at Heroku you want to create THREE “A” records, because they do some fault-tolerant crossover magic. So you’d have an A record for

Now for each subdomain you create a C record

www -> proxy.heroku.com
client1 -> proxy.heroku.com
client2 -> proxy.heroku.com
client3 -> proxy.heroku.com

NOW on the Heroku side, you have two apps right? The ‘main app’ and the saas app.

Login, and for each app go to Resources -> Addon -> Get More Addons ->Custom Domains (free)

for the main app, add ONE domain: www.mycoolsite.com

for the saas app, add each of the clients, eg:


Hack: Roasting peppers w/o open flame

It’s Mother’s Day. You’re making breakfast. Naturally, it includes freshly roasted Pasilla (or Poblano) peppers. But you don’t have access to an open flame.

Enter the trusty toaster oven.

  1. Toast the pepper right on the rack of the toaster oven (mine didn’t ooze at all) until slightly charred, about 5-7 minutes.
  2. Immediately put pepper in a small bowl and cover with a plate or lid. The pepper will steam itself.
  3. In about 5 minutes, remove pepper and run under cold water for 30 seconds. (Pepper will still be warm, but this loosens the skin even more.)
  4. Using fingers, remove the skin… it should pretty much slide right off by itself.

Hack: “Best Thing Since Sliced Bread 2.0” – Twilio Twimlets (simple business phone receptionist for $1/month)

Did you know Twilio comes with a collection of mix n match components (called Twimlets) that lets anyone build in a few minutes a simple “phone receptionist/menu” for inbound calls (you can build a lot of other things too!) that’ll cost $1/month plus a penny per minute for calls?

My friend John was getting ready to signup for Toktumi, which I’d found quite disappointing in several regards. So here’s what I helped him do instead. (You can do a lot more with Twimlets, but all my friend needed was a “receptionist” to accept and route calls to different people. This project is not a full featured phone system, although Twilio does offer an open source PBX you can download and host if you need such a thing.)

It took John and I about 15 minutes to get a new phone number and receptionist up and running thanks to the magic of Twimlets, and we did not need any website hosting (Twilio came with everything we needed).

Here’s a quick step-by-step to implement a main receptionist menu that tells the caller to “press 1 for Sales, 2 for Support, or 0 to leave a message.” It requires NO web hosting account, just a Twilio account and a Browser!

  1. Create a Twilio account if you don’t have one. It comes with a $30 credit which would give you a phone number in almost any area code for a year, plus 1800 minutes of calls at a penny a minute. Free. (When you sign-up you enter a credit card number, but immediately after you signup you can if you wish remove your card and go to manual recharge to prevent unexpected bills.)

  2. Grab a phone number. Twilio makes that easy, although you have to use their web API if you want to “browse” available numbers. Update: you can now browse phone numbers, even looking for patterns like “1234”.

  3. At the bottom of the screen click on Twilio Labs. Then Click **Twimlets **in the menubar. Then click **Access Your Twimlets **on the right side of the screen.

we’ll do the “lower level” menu options first, then do the main receptionist menu.

  1. Create a voicemail box. The Voicemail twimlet lets you provide a prompt (text-to-speech, or an audio file), get a voicemail from the user, then email it to you. Automatically. For prompts we’ll use text to speech for now, but then we can use our voicemail box to record real prompts later!

Select Voicemail from the drop down menu, then click Create New Twimlet.

Enter the email address you want voicemail to go to, and whatever prompt callers will hear. (You can also turn on or off the transcription feature, although I find it’s not accurate enough to reply upon it’s still kind of neat.)

Click save. All of your Twimlets will have the same prefix URL, and you provide the shortcut name for your Twimlet. Call this one “voicemail” and click OK.

Click the **My Twimlets **bread crumb to return to the main menu.

  1. Create a “find me” twimlet to try to route a call to whoever handles Sales. You can have it try multiple people in succession (they also have a Twmlet to try several people at once and the first one who answers gets the call.) In my case we just had one person to handle calls. Select Find Me **from the drop down menu, then click **Create New Twimlet. Enter the phone, and the message that they will hear (telling them to press a key if they want to accept the call). (BTW the person called will see the caller ID of the caller, not your Twilio phone number.)

For “failover” select your voicemail box from the dropdown list of your Twimlets (that’s why we created it first).

Save your Twimlet, calling it “find_sales”.

  1. Repeat the previous step creating a “find_support” Twimlet, using whatever phone number you want to route support calls to.

  2. Now create the main “receptionist” menu. Back on the main menu, select “Simple Menu” and click **Create New Twimlet.

Fill in your main greeting, and create options 1, 2, 0 as shown, with each option pointing ot a different Twimlet.

Save it as “main_menu”

  1. Point your Twilio Phone number to your “main_menu” twimlet.

a. Copy the URL for your main_menu Twimlet (on the main menu, click “show URL” then select & copy the URL, it should look like http://twimlets.com/youraccountcodegoeshere/main_menu

b. Paste it into the “voice” settings for your Twilio number. Go to your main account page, click Numbers. Click the phone number. Paste the URL into the Voice text box (and make sure the checkbox is checked) then save.

That’s it. Call your number and you’ll hear your menu.

  1. Want to replace your main menu prompt with your friendly voice instead of text-to-speech?

Simply call your number, press 0, and record your prompt as a voicemail. In a few seconds, Twilio will email the audio’s URL to you (already hosted at Twilio for you!).

Go back to your Twimlets menu, click the main_menu Twimlet to edit it. Replace your text message “Thanks for calling…” with the audio URL (probably best to add a .wav extension). Re-save the Twimlet.

Now do the same thing to record a real voice prompt for the “voicemail” Twimlet.

Now how cool is that?

Buzzbeeper.com is open for business

Buzzbeeper is a simple, easy-to-use, low-cost cloud-based service that gives your customers a fun, 10-second survey to find out how you’re doing (via text message, twitter, or telephone). And when a customer isn’t happy, it “beeps” you before they even leave the store so you can fix the issue on the spot. Plus an integrated social network referral system. Plus coupons. Plus text message campaigns. Some very exciting “beta site” deployments suggest this is a real “game changer” for retail businesses.

Buzzbeeper is a new cloud-based telephony app built upon Heroku, Amazon AWS, Twilio, and Tropo.

“Baba Pardner’s Yoga-in-a-cup Chai”

Sometimes I bring a thermos of chai to yoga class (or meetings).

According to my scientific guesstimates, drinking one cup of chai is equivalent to 23.4 sun salutations.

Here’s my recipe that makes 8 cups.

In 8 cups of cold water, add:

  • 8 Cinnamon sticks about 4″ long
  • 1 TBSP shell-less Cardomon seeds (whole, not ground, but crushed a little bit if you have a mortar and pestle)
  • 2 TBSP whole black peppercorn
  • 10 whole Star Anise seeds
  • 10 thinnest-possible slices fresh Ginger
  • 1 TBSP cloves
  • 2 TBSP real vanilla extract
  • 1 TBSP fennel seed (optional, but I like it)

Bring to a light boil, cover, simmer on lowest setting for 4 hours or more (I do 6 hours).

Add 8 TSP good loose tea (I use half green jasmine and half black assam).

Simmer covered (still lowest setting) 60 minutes. Stir once or twice. Simmered so long, the tea itself will be slightly bitter, which nicely (and authentically) offsets the spices and the honey and milk.

Add 1 cup cold whole milk. Simmer (lowest setting) covered another 20-30 minutes. Stir once or twice.

Turn off heat. Add 1/2 cup honey. Use the good stuff. Stir in. Taste. Add a little more milk and/or honey to taste. It needs to be sweet… experiment with adding even a little more honey to a cup of chai and find out for yourself what the “sweet spot” is.

Pour through strainer into glass jar. Serve and enjoy.

Stays great for 5 days or more if you refrigerate it promptly. Easy to reheat, or, on a hot day enjoy over ice.

Adding SSL to an app hosted at Heroku


A friend needed some help adding SSL to their custom-domain-name app hosted at Heroku, and it wasn’t entirely trivial. We found bits and pieces in several places, but never found clear and complete instructions.

I previously recommended rapidssl.com even though their docs are pretty abysmal. $49 for one year for a single-domain certificate, and it took them about 1 hour to generate and email the certificate. However, a year later we bought a rapidssl certificate from cheapssls.com for under $10

Suppose your app domain is myapp.mydomain.com, your

  1. Generate the command that generates the “CSR”

This wizard worked fine and has clear directions on what goes into each field.

However, you’ll need to change their default country code from “us” to “USA” the lowercase ‘us’ isn’t correct. Click Generate. That creates the Unix command needed to generate the CSR.

  1. “cd” to whatever directory you want to save your keys in. We put them in the “allmyapps” parent directory of the Heroku app.

  2. Copy the command and paste it onto the command line of your unix shell (we used Mac terminal). It looks something like openssl req -new -newkey rsa:2048 -nodes -out myapp_mydomain_com.csr -keyout myapp_mydomain_com.key -subj "/C=US /ST=Washington /L=Spokane /O=myco inc /CN=myapp.mydomain.com"

  3. that generates a text file called myapp_mydomain_com.csr and one called myapp_mydomain_com.key Copy the .csr file to your clipboard. Type
    cat myapp_mydomain_com.csr
    then copy everything between and including the lines that start —–BEGIN and —–END

Note: Heroku won’t let you have a passphrase in your key file, so don’t add one. Using the command shown, we weren’t prompted for one, so it wasn’t a problem. I have seen blogs that refer to removing the passphrase.

  1. Go to cheapssls.com [ we discovered cheapssls.com resells rapidssl certs at a fraction of the price] and click the button to get a single-domain certificate and choose the rapidssl option for under $10. Select “one year” assuming that’s what you want. Click Continue.

  2. Paste the .csr file you created/copied to your clipboard in steps 3/4 into the big text box and click Continue.

  3. The website will parse the CSR file and display the information encoded in it… be sure you have the domain name right, etc., then click Continue.

  4. Fill out your admin/tech/billing contact info, which unless you’re doing this for a corporation will likely be you in all three cases.

  5. Complete the order process on rapidssl.com. It includes entering a phone number so their automated system can call you to confirm you draw breath. The onscreen instructions are simple. The order process takes maybe a minute or two.

They will give you a list of possible email addresses to send your certificate, receipt, etc. One of them should already work for you (the email contact for the domain name), if not, you have to create a new email address and get it working BEFORE you go any further. In our case, we had to go to Godaddy and create a postmaster@mydomain.com forwarding address since we could not get email at any of the choice listed.

  1. After 49 minutes (in our case) rapidssl.com emailed our certificate. Two actually… one is a ‘chain’ certificate which we deal with soon.

  2. You need to take the certificate text from the email and save it into a .CRT text file in the same directory you used earlier. I suggest using the same naming convention as the CRT generator used, so you’d
    (a) copy to your clipboard the FIRST certificate text (including those begin/end dashed lines) then
    (b) type into your unix shell: cat > myapp_mydomain_com.crt then Enter
    (c) paste the certificate text then
    (d) hit Enter then
    (e) press control-D to terminate the file.
    Verify it: At the command prompt type cat myapp_mydomain_com.crt (NO > this time) and verify the file got created correctly.

  3. Do the same thing for the intermediate ‘chain’ certificate (the second certificate in the email from rapidssl) using cat > myapp_mydomain_com_<b>chain</b>.crt

  4. There is NO step #13. It’s bad luck.

  5. Now create the .PEM file. Near as I can tell, it simply has your main .crt, then your chain .crt file appended to each other in that order. Here’s the sequence of commands we used:

openssl x509 -in myapp_mydomain_com.crt -out myapp_mydomain_com.pem

openssl x509 -in myapp_mydomain_com_chain.crt >> myapp_mydomain_com.pem

  1. You need to enable the SSL ENDPOINT addon with: heroku addons:add ssl

  2. Now, finally, you get to use the heroku gem to schlep the key etc over to your heroku app. That means (which I never saw documented) you need to cd into the directory with your heroku app. In our case that’s one directory “down” from where we’ve been working… which measn onc ein that directory when we refer to the .key or .pem file we need ot point ‘up’ 1 directory… In your case, adjust the path to the .key and .pem files according to where you store them.

heroku certs:add ../ssldir/myapp_mydomain_com.pem ../ssldir/myapp_mydomain_com_chain.key

  1. Heroku instantly displays a message telling you to add a CNAME to your DNS that points to some long name similar to appid-1234.herokussl.com

Since the CNAME already existed in his DNS, we edited it, changing it form proxy.heroku.com to the long domainname they specified.

  1. A few minutes later, it was all working… going to https://myapp.mydomain.com worked fine, no certificate warnings, etc. (DNS can take a while to propagate, but I’ve found it usually happens within 5 minutes.)

FINAL TIP: you may need to reboot your PC (or flush your dns cache) for your PC to “see” the new DNS settings because the old settings (proxy.heroku.com) are probably cached on your PC. On a Mac OSX 10.5 you’d typedscacheutil -flushcache then type host myapp.mydomain.com to see if the DNS changes have taken effect.