the startup academy

Switching to Octopress

I’ve decided to switch over to Octopress for blogging. Follow me here: http://www.pote.to

0 Notes

Designing a theme for Shopify on Ubuntu Linux (non-OSX) and Sublime Text 2

So it turns out developing locally with Vision is unsupported, and the Shopify wiki unhelpfully suggests I use Textmate2 on my Ubuntu machine. Before trying to drop the tmbundle into my packages directory, I found a thread stating that it didn’t work and that pointed me to dwarburton's ST2 port, which works pretty well.

Working from Sublime Text 2 only

Here are the steps to install and use in case you’re wondering:

  1. Make sure you have an API key for your store: https://your-store.myshopify.com/admin/api
  2. If you use Mercurial for version control, just follow the steps outlined in the readme
  3. If you don’t, just download a zip or tarball and extract to ~/.config/sublime-text-2/Packages
  4. To config, start ST2 and press Ctrl + Shift + P to bring up your command palette
  5. Type shopify and it should autocomplete to show you 4 commands
  6. Start with Shopify: Edit store information and follow the steps outlined in the wiki

Now you can use Shopify: Edit asset to download, edit and re-upload a file automatically on save.

Working from terminal

If you want to grab all the files of an existing theme or you prefer working in the command line, I recommend using Shopify’s own shopify_theme gem. Very easy to use, just follow the instructions in the readme.

Using Liquid

Liquid looks and feels pretty much like erb, so if you’re familiar with that you won’t have any trouble using Liquid for templating on Shopify. Here’s the documentation and a handy cheatsheet.

Apps

If you want to develop an app for Shopify then check out their API documentation and install the shopify_api gem.

0 Notes

Making a backup of your installed software on Ubuntu 12.04

On my old laptop I still run Windows and Ubuntu (using wubi) as a dual boot, and occasionally I get the mysterious disappearing root.disk bug, which is fairly annoying. I keep backups of my root.disk file periodically but sometimes there are gaps of a few days in between backups, so a disappearing root.disk could potentially be a huge time waster if I had spent some time say installing a particularly tricky library.

To scratch my own itch, I wrote this shell script to run as a daily cron job. It basically exports a list of all your installed software on Ubuntu which you can later use as a backup. Restoring your software just takes a few commands (or you can put this in a script):

$ sudo apt-key add Repo.keys
$ sudo cp sources.list /etc/apt/sources.list
$ sudo cp -r sources.list.d/* /etc/apt/sources.list.d/
$ dpkg --set-selections < installed-software.list
$ apt-get update
$ dselect

Install the backup script as a daily cron job

View on Github

$ git clone git@github.com:poteto/ubuntu_backup.git
$ cd ubuntu_backup
$ st backup.sh
$ sh backup.sh

You should see something like this in your terminal prompt:

Running backup.sh...
     [ SUCCESS ] Created /home/poteto/Dropbox/ubuntu-backups/2012-08-22-0121
     [ SUCCESS ] installed-software.list
     [ SUCCESS ] sources.list
     [ SUCCESS ] sources.list.d
     [ SUCCESS ] Repo.keys
5 successes and 0 failures
Exiting backup.sh
$ sudo cp backup.sh /etc/cron.daily/

And that’s it. See the Github page for more detailed usage.

2 Notes

Eating the cold porridge

'You must eat the cold porridge,' he told me once.

It’s a Chinese expression. Cantonese, I guess, because although he carried an old-fashioned blue British passport and was happy to call himself an Englishman, he was born in Hong Kong and sometimes you could tell that all the important things he believed were formed long ago and far away. Like the importance of eating the cold porridge.

I stopped what I was doing and stared at him. What was he going on about now? ‘Eat the cold porridge.’

The way he explained it, eating the cold porridge means working at something for so long that when you get home there is nothing left to eat but cold porridge.

That’s how you get good at something, he told me. That’s how you get good at anything. You eat the cold porridge.

You work at it when the others are playing. You work at it when the others are watching television. You work at it when the others are sleeping.

To become the master of something, you must eat the cold porridge.

- Tony Parsons

1 Notes

Wensing, M.: The Anatomy of Profitable Freemium

wensing:

Choosing the freemium business model can be brilliant or deadly. The difference lies not only in the execution of the marketing, but also in the nature of your product and the design of your business. Can you coordinate all three to become sustainably freemium by making a profit?

Summary

38 Notes

Batch trace geolocation from many IPs

My co-founder recently wanted to check out geolocations from a large bunch of IP addresses, but there wasn’t an easy way to batch process it. Here’s a quick Python script to do just that:

#!/usr/bin/python
# ip_lookup.py by poteto
#
# Batch processes many IP addresses, and traces their geolocation.
# The script outputs a .txt file which is then renamed to .csv, and is usable in Excel
#
# Use:
#   1. Save your user email and IP addresses in a .csv file
#        -  Each email and IP should be in its own column in Excel (or separated by commas)
#        -  Enter the name of your .csv file:
#
batch_filename = "batch.csv"
#
#   2. Go to http://www.ipinfodb.com/ip_location_api.php and get your own API key
#   3. Update the config with your API key:
#
key = "f1158e2461279f5b9076fc8c3d1d4dc41304d6e2bdebe42943241cd26d4b6dbb"
#
#   4. Run the script:
#   $ python ip_lookup.py


import xml.etree.ElementTree as ET
import urllib
import csv
import os


# Process batch csv into list 'current_batch'
def get_batch(batch_filename):
    "Creates list containing all the email and IP addresses from your batch file"
    batch = csv.reader(open(batch_filename, 'rb'), delimiter=',')
    return [[email, ip_addr] for email, ip_addr in batch]


def batch_process(batch):
    "Runs your batch file through the IPInfoDB API"
    try:
        i = 0
        output = open('output.txt', 'a')
        for email, ip_addr in batch:
            response = urllib.urlopen(url + "&ip=" + str(ip_addr)).read()
            tree = ET.fromstring(response)

            output.write(str(email) + ",")
            for child in tree:
                if child.tag == 'ipAddress':
                    output.write(str(child.text) + ",")
                if child.tag == 'countryCode':
                    output.write(str(child.text) + ",")
                if child.tag == 'timeZone':
                    output.write(str(child.text) + "\n")
            i += 1
            print "\t" + str(i) + " of " + str(len(batch)) + ":\t" + str(email)
        output.close()
        os.rename('output.txt', 'output.csv')
        print "Complete."
    except KeyboardInterrupt:
        output.close()
        print "\nExiting..."

base_url = "http://api.ipinfodb.com/v3/ip-city/?format=xml&key="
url = base_url + key
current_batch = get_batch(batch_filename)

print "Added " + str(len(current_batch)) + " entries from " + str(batch_filename) + "\n"
print "Working... This may take a while, please be patient.\n"

batch_process(current_batch)

0 Notes

Doing It Right, Not First

Elegantly said. Too many put an emphasis on being the first to think of an idea. So much so that they never actually create anything, they just keep trying to think of an idea that doesn’t yet exist. The most iconic companies in the world weren’t the first, they were simply the best. MySpace beat Facebook to the punch, HP hit the market before Apple, PicPlz existed before Instagram.

It didn’t matter.​ They succeeded because they did it right.

0 Notes

Python: Don't reinvent the wheel

0 Notes

Extract specific filetypes from many .zip files

I recently downloaded all the Mailchimp guides, and found that the filetype I wanted (PDFs) were buried inside each .zip file. I’ve been doing Udacity lessons and learning programming for a while now, so I decided to put my new skills to use.

I whipped up this little Python utility script that extracts all files of a specific filetype from many .zip files. It’s not very pretty, but it works. It also helpfully ignores fake files in the __MACOSX folder (why would you do this Apple?).

# extract_filetype_from_zip.py
# A simple script to extract all files of a certain filetype from many .zip files
# * Requires Python installed on local computer
VERSION = 0.1
# 
# Place this file in the folder where you have all your zipfiles.
# Example use:
# - To extract only PDFs: extract_filetype('.pdf', '/folder') where folder (with the /) is the dir you store your zipfiles
# - 2nd argument is optional (defaults to root)

import zipfile
import os


# to do: target directory for extraction, zip file passwords
def extract_filetype(filetype, directory='root'):
    "Extracts files of filetype from a directory of zipfiles."
    if directory == 'root':
        working_dir = './'
    else:
        working_dir = '.' + str(directory) + '/'
    zipfile_list = zipfile_array(working_dir)

    if zipfile_list:
        print "Working to extract " + str(filetype) + " files from " + str(directory) + "...\n"
        for zips in zipfile_list:
            print "  Found " + str(len(zips)) + " .zip files \n"
            for f in zips:
                with zipfile.ZipFile(f) as curr_zip:
                    for target_filepath in curr_zip.namelist():
                        if target_filepath.endswith(filetype) and not target_filepath.startswith('__MACOSX/'):
                            print "  Extracting... " + str(target_filepath)
                            curr_zip.extract(target_filepath)
        print "\nExtraction complete."
    else:
        print "No .zip files to extract from " + str(directory)


def zipfile_array(directory): # this needs fixing to avoid empty arrays
    "Creates array of zipfile paths and names in the directory."
    return [[os.path.join(root, name) for name in files if name.endswith('.zip')] for root, dirs, files in os.walk(directory)]


extract_filetype('.pdf', '/zip')
# print filename_array('./zip')

1 Notes

Can’t install rmagick gem (Ubuntu 11.10)

Ruby 1.9.2, Rails 3.2.2

Problem:

Installing rmagick (2.13.1) with native extensions 
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.

        /home/poteto/.rvm/rubies/ruby-1.9.2-p290/bin/ruby extconf.rb 
checking for Ruby version >= 1.8.5... yes
checking for gcc... yes
checking for Magick-config... no
Can't install RMagick 2.13.1. Can't find Magick-config in /home/poteto/.rvm/gems/ruby-1.9.2-p290/bin:/home/poteto/.rvm/gems/ruby-1.9.2-p290@global/bin:/home/poteto/.rvm/rubies/ruby-1.9.2-p290/bin:/home/poteto/.rvm/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.

Provided configuration options:
    --with-opt-dir
    --with-opt-include
    --without-opt-include=${opt-dir}/include
    --with-opt-lib
    --without-opt-lib=${opt-dir}/lib
    --with-make-prog
    --without-make-prog
    --srcdir=.
    --curdir
    --ruby=/home/poteto/.rvm/rubies/ruby-1.9.2-p290/bin/ruby


Gem files will remain installed in /home/poteto/.rvm/gems/ruby-1.9.2-p290/gems/rmagick-2.13.1 for inspection.
Results logged to /home/poteto/.rvm/gems/ruby-1.9.2-p290/gems/rmagick-2.13.1/ext/RMagick/gem_make.out
An error occured while installing rmagick (2.13.1), and Bundler cannot continue.
Make sure that `gem install rmagick -v '2.13.1'` succeeds before bundling.

Solution:

$ sudo apt-get install libmagickwand-dev imagemagick

0 Notes

The default state of a startup is failure

While it’s easy to daydream about your startup’s eventual billion dollar IPO, the reality is a lot less happy. People are resistant to change and mostly happy with the status quo, so why should they give your new product a try? You’ll really need to communicate your value proposition to get your potential users to see why your product helps solve their problem. And when all else fails, A/B test everything.

On the flip side, first-time entrepreneurs often fail to realize that when you build something new, no one will care. People won’t use your product, won’t tell people about it, and almost certainly won’t pay for it. (There are exceptions – but these are as rare as winning the lottery). This doesn’t mean you’ll fail. It means you need to be smarter and harder working, and surround yourself with extraordinary people.

0 Notes

Import Heroku production Postgres db to local development db

Useful if you want to import some production data into your local database so you can do proper testing. I assume you already have the pgbackups addon enabled on your Heroku app. If not, add it first.

$ heroku pgbackups --app yourapp
#=> ID   | Backup Time         | Size  | Database               
#=> -----+---------------------+-------+------------------------
#=> a226 | 2012/02/22 20:02.19 | 5.3KB | DATABASE_URL           
#=> a227 | 2012/02/23 20:02.19 | 5.3KB | DATABASE_URL           
#=> b251 | 2012/02/24 16:08.02 | 5.3KB | HEROKU_POSTGRESQL_BLACK
#=> b252 | 2012/02/24 16:08.53 | 5.3KB | HEROKU_POSTGRESQL_PINK 

$ heroku pgbackups:url b004
#=> "http://s3.amazonaws.com/hkpgbackups/app1234567@heroku.com/b004.dump?AWSAccessKeyId=ABCD1234&Expires=1289261668&Signature=3mMBeKISewgEUDT%2FL5mRz4EYS4M%3D"

$ curl -o latest.dump `heroku pgbackups:url`

$ pg_restore --verbose --clean --no-acl --no-owner -h localhost -U your_db_username -d your_database latest.dump
# Change localhost, your_db_username and your_database as necessary

0 Notes

Heroku shared db down

If you see this, the Heroku shared database is down.

2012-05-19T16:12:55+00:00 app[web.2]: /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:1194:in `initialize': could not connect to server: Connection timed out (PG::Error)

2012-05-19T16:12:55+00:00 app[web.2]:   Is the server running on host "ec2-23-23-203-225.compute-1.amazonaws.com" and accepting

2012-05-19T16:12:55+00:00 app[web.2]:   TCP/IP connections on port 5432?

This happened to us on a Saturday, and submitting a ticket to the Heroku support team yielded this unhelpful email:

We’ve received your support request (#52462), but it is currently outside of our regular support hours. Support hours are from 6:00 AM to 6:00 PM PST Monday through Friday, excluding U.S. holidays. You can expect a response within 1 business day.

Luckily, I checked the #heroku hashtag on Twitter and found out about their IRC channel. @asenchi, who claims to not know what the definition of a holiday is, helpfully booted up a new server for those affected.

All is good now. It’s probably time for us to look at the Crane or Kappa PG plans, which @asenchi told me was more reliable than the shared db.

0 Notes

brycedotvc:

Apple’s welcome letter for new hires.

Can the same be said of the company you’re building?

via @m

brycedotvc:

Apple’s welcome letter for new hires.
Can the same be said of the company you’re building?
via @m

111 Notes

Alejandro Burato: Yays and Nays of Financial Modeling

aburato:

Over the last few years I have made and seen many spreadsheets with financial models, projections and valuations. The list below shows some suggestions and tips on how to make credible, easier to understand and maintain, conservative financial models. It is by no means a definitive list, so I will…

(via aburato-deactivated20120806)

1 Notes