Thursday, November 24, 2016

Arduino Stepper with ULN2003 driver

// stepper1 -- repeat 1 CW and CCW revolution
5v 28YBJ-48 Stepper Motor with Gear Reduction
ULN2003 driver board


// internal motor steps per revolution in 4-step mode

// steps per OUTPUT SHAFT of gear reduction

//The pin connections need to be 4 pins connected
// to Motor Driver In1, In2, In3, In4  and then the pins entered
// here in the sequence 1-3-2-4 for proper sequencing
Stepper s(STEPS_PER_MOTOR_REVOLUTION, 8, 10, 9, 11);

void setup()
  s.setSpeed(500);  // 700 good max?

void loop()
  s.step(2 * STEPS_PER_OUTPUT_REVOLUTION);  // CW 1 turn

Friday, November 4, 2016

Perfect SSL Score with Go

Peter Lambert makes it look easy!

Arduino Encryption

I've been looking at encryption libraries that would run on an Arduino.  This looks like something worth looking into.
This library contains a cryptographic pseudo-random number generator, cryptographic hash and message authentication code (MAC) functions, can perform symmetric-key authenticated data encryption, and general-purpose functions for timing-safe comparison and wiping data from memory.

Monday, September 12, 2016

Vim + Go + Mac

There's a lot of notes written for getting Vim + Go up and running, but a lot of the notes assume you're already in modern Vim-land.  Here's what I did to get up and going from scratch.

0.  Start off with a totally clean vim configuration.

Save off your current files/setting if they're important to you.

    cd $HOME
    rm -rf .vim .vimrc .viminfo

1.  Install a vim with lua support.

I think the easiest way to do this is to install the latest macvim from Homebrew.  If you're a developer on Mac,  Homebrew is well worth looking into.

    brew install macvim --with-cscope --with-lua --override-system-vim
    brew linkapps macvim
    brew install vim --with-lua --override-system-vim

2.  Install Vundle

There's a couple of Vim package managers.  I don't know enough about Vim package management to recommend one over another, but Vundle seems to be pretty popular.

    git clone ~/.vim/bundle/Vundle.vim

Here's the minimal .vimrc needed to get bootstrapped.

    set nocompatible              
    filetype off                  

    set rtp+=~/.vim/bundle/Vundle.vim

    call vundle#begin()
    Plugin 'VundleVim/Vundle.vim'
    "Plugin 'Valloric/YouCompleteMe'    reserve for step 3 below
    "Plugin 'fatih/vim-go'              <------- font="" nbsp="">reserve for step 4 below
    call vundle#end()            

    filetype plugin indent on    

Restart vim and install the plugins with the command


3. Install YouCompleteMe

This require you install XCode from Apple.  Start off by installing cmake.

    brew install cmake

Install YouCompleteMe and pull in submodules.

    cd ~/.vim/bundle
    git clone
    cd ~/.vim/bundle/YouCompleteMe
    git submodule update --init --recursive

Build YouCompleteMe

    cd ~/.vim/bundle/YouCompleteMe
    ./ --gocode-completer

Make sure ~/.vimrc has the line

Plugin 'Valloric/YouCompleteMe'

Restart vim and install the plugin as we did above


4. Install Vim-Go

Download the latest release from and untar it.

    cd /tmp
    curl -s | tar xf -

And move all the directories into .vim.  It seems there should be and easier way to do this... ping me if you know what it is!

    (cd /tmp/vim-go-1.8; tar cf - autoload compiler doc \
       ftdetect ftplugin gosnippets indent plugin scripts syntax t templates) |
      (cd ~/.vim; tar xf -)

Then add to .vimrc

    Plugin 'fatih/vim-go'

Restart vim and run


Tuesday, August 30, 2016

Mapping Ctrl, CapsLock Tap to Esc

Now you can vi just as Bill Joy intended!  Here's an article that makes tapping the control key send an Esc.

Setting up ssh for github

On Mac and Linux, set up an ssh key in the usual way:

    cat $HOME/.ssh/

Copy that into the github ssh keylist.

Linux:  start the ssh agent.  This will be good for the duration of the session.

    exec ssh-agent bash

Mac: add the ssh key to the keychain. This only needs to be done once.


To test your connection to github.

    ssh -T

Thursday, June 23, 2016

GitHub based dotfiles

Not much new here, this is just my take on StreakyCobra's excellent work, with these differences:

  • I made two repos, one for dotfiles, one for scripts that go into $HOME/bin.
  • I made two commands dotf and binf that correspond to StreakyCobra's config.
  • incorporated github repos dotf and binf as noted.

# create github repo "dotf"
git init --bare $HOME/.dotf
alias dotf='/usr/bin/git --git-dir=$HOME/.dotf/ --work-tree=$HOME'
dotf config status.showUntrackedFiles no
dotf add .bash_profile

dotf commit -m "first import"
dotf remote add origin
dotf push -u origin master

# create github repo "binf"

git init --bare $HOME/.binf
alias binf='/usr/bin/git --git-dir=$HOME/.binf --work-tree=$HOME/bin'
# binf config status.showUntrackedFiles no  ## want to track unused files

cd $HOME/bin
dotf add some-file
dotf commit -m "first import"
binf remote add origin
binf push -u origin master

Wednesday, June 15, 2016

Do you have a restless urge to program?

I finally found a scan advertising the Famous Programmers' School which originally appeared in the April 1982 of BYTE, page 384.

"Top down programming for the masses."

Friday, May 13, 2016

Adding a git commit template

So I find myself constantly forgetting to add the jira ticket number to commits that need them.

echo JIRA >~/txt/git-commit-template.txt

And one of these commands

git config commit.template ~/txt/git-commit-template.txt
git config --global commit.template ~/txt/git-commit-template.txt

or put in in .git/config (per repo) or $HOME/.gitconfig (global):

            template = /Users/mh/txt/git-commit-template.txt

Don't forget to manage your git commit template in git!

blogodex = {"toc" : "git", "idx" : "commit template"};

Friday, April 29, 2016

Python: virtualenv quickstart


pip install virtualenv


mkdir myproject
cd myproject
virtualenv foo
source foo/bin/activate
pip install hjson       # install packages...
import hjson

Getting pip if necessary

curl -o
python get-pip

Getting ssl if necessary in order to get pip on your linux box

symptom:    ImportError: cannot import name HTTPSHandler

yum install openssl openssl-devel
apt-get install openssl openssl-devel


Wednesday, April 27, 2016

Encrypting UDP Game Traffic

not only encryption protects your players from classical attacks, it also protects your games against cheaters too.
As a side bonus, with proper encryption you can be sure that network errors which corrupt your packets are not going undetected (and with unencrypted UDP those 16-bit UDP checksums can detect only one out of 60’000 in-transit corruptions, which means that with all those millions of packets you’re sending out each second, some corruptions WILL go undetected, causing all kinds of trouble).

Tuesday, April 19, 2016

Classic Programmer Paintings!

My Favorite:

Hieronymus Bosch “A visual guide to the Scala language”  oil on oak panels, 1490-1510.

The left panel shows the functional features, the main one describes the type system, and the right the object oriented parts.

Friday, March 18, 2016

brewing mysql / binlog reader

Here's what I did to set up MySQL 5.6 on my Mac in binlog row mode, prepping to talk to Aurora.
+1 for brew services!

Install and Test

brew install mysql56
brew tap homebrew/services
brew services start mysql56

mysqladmin -uroot create mh
mysql -uroot

Find my.cnf

/usr/local/bin/mysqld --verbose --help 2>/dev/null | grep -A 1 "Default options" 
Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf /usr/local/etc/my.cnf ~/.my.cnf

Configuring binary logging

$ cat /usr/local/etc/my.cnf 

binlog status

Restart mysql and you can see the logs and current position.

mysql> show binary logs;
| Log_name         | File_size |
| mysql-bin.000001 |       143 |
| mysql-bin.000002 |       120 |

mysql> show master status;
| File           | Position | 
+----------------+----------+- . . . 
| mysql-bin.000002 |     1309 


Tailing the binlog

mysqlbinlog --read-from-remote-server --host=localhost  mysql-bin.000001 -uroot -v --stop-never

Insert some data like this

mysql> insert into t values(99);

and you'll see it come out like this

# at 1309
#160318 11:40:42 server id 1235 end_log_pos 1379 CRC32 0xaf303ba0 Query thread_id=7 exec_time=0 error_code=0
SET TIMESTAMP=1458326442/*!*/;
# at 1379
#160318 11:40:42 server id 1235 end_log_pos 1421 CRC32 0xb302b235 Table_map: `mh`.`t` mapped to number 70
# at 1421
#160318 11:40:42 server id 1235 end_log_pos 1461 CRC32 0x4d9e5013 Write_rows: table id 70 flags: STMT_END_F

### INSERT INTO `mh`.`t`
### SET
###   @1=99
# at 1461
#160318 11:40:42 server id 1235  end_log_pos 1492 CRC32 0x94dcc720 Xid = 73

blogodex = {"toc" : "MySQL binlog", "idx" : ["MySQL","binlog","configuration"]};

Thursday, March 17, 2016

brew services

You can use brew to interface with launchservices.  It's great!


  • brew tap homebrew/services

  • brew services list
  • brew services start etcd
  • brew services restart etcd
  • brew services stop etcd
Lots of details over at thoughtbot!

blogodex = {"toc" : "brew", "idx" : ["services", "launchd"]};

Tuesday, March 8, 2016

Animating an OpenSCAD Figure

First, let's draw a cube:


Now, let's animate a 360 degree turntable view of the cube:


$t is filled in when the animation is in process.  You can see it in action like this:

    rotate([0,0,$t*360]) {

To enable the animation:

  • View/Animate to fill in the animation parameters
  • fill in FPS and Steps.  Good values are 24 and 240
  • don't fill in Time.  It is derived from the other parameters.  This is the value of $t in the code.
  • To grab the frames, click the Dump Pictures box.  This will create files frameXXXXX.png in the same directory as your SCAD file.  Note that this implies you've saved your file.

Once you've got the files, you can string them together into an animation.  There's a ton of ways of doing that; I use QuickTime Player 7 on my Mac:

  • File / New Player
  • File / Open Image Sequence - navigate to your folder, and select the first generated file (frame00000.png).  QuickTime will figure out the list of frames from there.
  • Frame Rate: 24
  • You should have a quicktime movie of your animation.  Save it out and you're good to go!

blogodex = {"toc" : "OpenSCAD", "idx" : ["animation", "turntable"]};

Monday, February 29, 2016

Some Raft References
Raft is a consensus algorithm designed to be easier to understand than Paxos. To measure Raft's understandability, we conducted an experimental study using CS students at two universities. We recorded a video lecture of Raft and another of Paxos, and created corresponding quizzes. This page makes our materials available for anyone interested. We think these are valuable resources for anyone learning consensus (whether Raft or Paxos or both).
Raft is a consensus algorithm for managing a replicated log. It produces a result equivalent to (multi-)Paxos, and it is as efficient as Paxos, but its structure is different from Paxos; this makes Raft more understandable than Paxos and also provides a better foundation for build- ing practical systems. In order to enhance understandabil- ity, Raft separates the key elements of consensus, such as leader election, log replication, and safety, and it enforces a stronger degree of coherency to reduce the number of states that must be considered. Results from a user study demonstrate that Raft is easier for students to learn than Paxos. Raft also includes a new mechanism for changing the cluster membership, which uses overlapping majori- ties to guarantee safety.
Raft lecture (Raft user study) - YouTube
Tech Talk - Raft, In Search of an Understandable Consensus Algorithm

Raft Consensus Algorithm
    Consul is a new product by HashiCorp which aims to solve the core issues of service discovery and configuration. As part of that it needs to maintain a strongly consistent catalog shared between multiple servers for availability. Raft was used as the consensus protocol for Consul because it was the most readily understandable and simple algorithm available.
    The simplicity of Raft reduced our time to market, and now Consul powers HashiCorp, a number of customers using our on-premise product, and hopefully soon many thousands of other clients through our open source efforts.
    We've open sourced our Raft library as well, allowing others to use it independently of Consul. The library fully implements the protocol as described, following the paper as closely as possible.
Raft - secret lives of data

blogodex = {"toc" : "Raft"};

Saturday, February 6, 2016

jq -- lightweight flexible JSON processor

"jq is like sed for JSON data - you can use it to slice and filter and map and transform structured data with the same ease that sed, awk, grep and friends let you play with text."

brew install jq

blogodex: jq / json

Friday, February 5, 2016

Installing Consolas font on Mac

Courtesy of ikato blog:

brew install cabextract
cd ~/Downloads
mkdir consolas
cd consolas
curl -O
cabextract PowerPointViewer.exe

blogodex: / fonts, consolas, mac

Friday, January 22, 2016

Three options for a new blogodex

The current blogodex is fine, except it's a bit tedious to type.  I'm OK with it, but it may bother other people.  In addition, it depends on a certain amount of care to not introduce syntax errors.

Thinking about it, three alternatives going forward:

  • stick with current blogodex.  pros and cons as per above.
  • switch blogodex to YAML.  I really liked this idea, until I saw that blogger would put extra formatting cruft in a multi-line block.  Additionally, blogger labels aren't multi-line friendly.
  • Make a new blogodex format, a bit more forgiving typing-wise.
Ideas for new blogodex to try:
  • maintain backwards compatibility.  lines that begin with "blogodex =" are 1.0, lines that begin with "blogodex:" are 2.0
  • format something like this:  blogodex:  optional-TOC / optional-Index Entries
  • B: my toc topic
  • B: toc topic / index topic 1, index topic 2
  • B: toc topic (no index)
  • B: / index topic (no toc)
  • what delimiters are best?
blogodex: blogodex / blogodex 2.0

TechCrunch: The Stack Fallacy

A coworker pointed me to this article which meshes well with my experience:

my takeaways:

  • It's easier to build pieces below your level in the stack than above, because you are your own customer and know what you want.
  • "Product management is the art of knowing what to build."
  • "the what is 100 times more important than the how."

blogodex = {"idx" : ["Stack Fallacy", "building software"];

Friday, December 25, 2015

Spotify Apollo: new Microservice libary

public final class App {

    public static void main(String[] args) throws LoadingException {
        HttpService.boot(App::init, "my-app", args);

    static void init(Environment environment) {
            .registerAutoRoute(Route.sync("GET", "/", rc -> "hello world"));

blogodex = {"toc" : "Apollo", "idx" : ["microservice", "java"]};

Saturday, December 19, 2015

Getting a classpath out of Maven

Got the classpath blues? Here's some maven incantations:

$ mvn dependency:build-classpath

$ mvn dependency:build-classpath -Dmdep.outputFile=classpath.txt
[INFO] Wrote classpath file '/Users/mh/g/javalogic/ggprocessor/classpath.txt'.

And some more maven magic here, including copying jar files and building an executable directly.

blogodex = {"toc" : "Maven", "idx" : "classpath"]};

Tuesday, December 15, 2015

Centos requires these packages to build Python2.7

yum groupinstall -y "Development tools"
yum install -y zlib-devel
yum install -y bzip2-devel
yum install -y openssl-devel
yum install -y ncurses-devel
yum install -y sqlite-devel
yum install -y readline-devel.x86_64

leaving a few leftovers:

Python build finished, but the necessary bits to build 
these modules were not found:

_bsddb             _tkinter           bsddb185        
dbm                dl                 gdbm            
imageop            sunaudiodev                        

Tuesday, December 1, 2015

Awesome Forth Tutorial

I've always loved Forth, so I was really happy to discover Nick Morgan's online tutorial "Easy Forth."  Not only does he do a great job introducing the concepts, he's wrote an embeddable Forth interpreter in Javascript so that all the examples can be typed into a live interpreter.  He wraps it up by writing the Snake game in Forth running in an interpreter window.

And if this whet's your retro-enthusiasm, he's got got an Easy 6502 book as well!

blogodex = {"toc" : "Forth", "idx" : ["online emulators"]};

Sunday, November 29, 2015

Java: Two ways to glob

Two ways of globbing.

First, using a DirectoryStream.  This is the better way.

    static List xglob(String filePath, String wc) {
        List result = new ArrayList();

        Path dir = FileSystems.getDefault().getPath(filePath);
        DirectoryStream stream = null;
        try {
            stream = Files.newDirectoryStream(dir, wc);
            for (Path path : stream) {

        } catch (IOException e) {
            // glob of something that does not exist is empty
        return result;

Second, using File().

    static List glob2(String dirname_s, String wc) {
        PathMatcher matcher = FileSystems.getDefault()
        List result = new ArrayList();

        File dircontents = new File(dirname_s);
        String[] paths = dircontents.list();

        for (String ps : paths) {
            Path p = Paths.get(ps);
            if (matcher.matches(p)) {
        return result;

blogodex = {"idx" : ["glob", "java"]};

Sunday, November 22, 2015

Mac Installing Consolas font

I thought installing Office would install it in the Font Book.  Apparently not!

Here's how to get it into the Font Book.  Be sure and do this in a scratch directory as it creates a lot of files.

brew install cabextract
curl -O
cabextract PowerPointViewer.exe

blogodex = {"idx" : ["Consolas", "fonts", "Mac setup"]};

Friday, November 13, 2015

Saving Youtube Audio for iPhone playback

I'm watching a lot of tutorials these days on Youtube.  A lot of these are fine audio-only, and it would be nice to listen to them on the daily commute.

BUT, unlike the various audio players, the Youtube player pauses when you lock the screen.  So, here's some incantations to grab the audio.

I think an mp3 codec can be added to ffmpeg.  If anybody knows an easy incantation give me a shout! This may be it:

  • ffmpeg -i foo.mp4 -c:a libmp3lame -ac 2 -q:a 2 foo.mp3
blogodex = {"idx" : ["video conversion", "audio extraction", "Youtube"]};

Thursday, November 12, 2015

Kafka Training Deck

  • Introducing Kafka: history, Kafka at LinkedIn, Kafka adoption in the industry, why Kafka
  • Kafka core concepts: topics, partitions, replicas, producers, consumers, brokers
  • Operating Kafka: architecture, hardware specs, deploying, monitoring, performance and scalability tuning
  • Developing Kafka apps: writing to Kafka, reading from Kafka, testing, serialization, compression, example apps (with kafka-storm-starter)
  • Playing with Kafka using Wirbelsturm

blogodex = {"idx" : ["kafka", "tutorials"]};

Tuesday, November 10, 2015

Oracle: quick AS OF demo

First, let's check our current SCN

    scott@orcl> select current_scn from v$database;

And see how many rows we have in table FOO

    scott@orcl> select count(*) from foo;

Delete everything from FOO

    scott@orcl> delete from foo;
    (33 rows, 0.011 sec)

    scott@orcl> select count(*) from foo;

What's our SCN now?

    scott@orcl> select current_scn from v$database;

What was the count as of yesterday?

    scott@orcl> select count(*) from foo as of timestamp sysdate-1;

And as of the SCN at the start of our session?

    (1 rows, 0.010 sec)
    scott@orcl> select count(*) from foo as of scn 7559499070893;

blogodex = {"toc" : "Oracle SCN", "idx" : ["Oracle", "SCN", "System Change Number", "as of"]};

Friday, November 6, 2015

Installing Maven

Pretty simple:

This was on a Mac.

blogodex = {"idx" : ["maven", "installation"]};

SQL Developer Keepalive plugin

When you start SQL Developer, click on the icon.  Pressing enter gives you the default of sending a message every 600 seconds.

blogodex = {"idx" : {"SQL Developer", "Oracle connection timeout", "ORA-03135"]};

Thursday, November 5, 2015

What if your name is actually Null?

Interesting comments by Mr. Christopher Null!

I'm adding "null" to the blogodex, will it come back to bite me?

blogodex = {"idx" : ["problem areas", "null"]};

Wednesday, November 4, 2015

Nice article on The Log

"Each working data pipeline is designed like a log; each broken data pipeline is broken in its own way."—Count Leo Tolstoy (translation by Jay Kreps)
Here's an excellent manifesto about "the data log".  You might be familiar with this concept in the guise of database journals, or with event sequences in distributed systems.

Jay starts from there and writes (pretty comprehensively!) about how this idea is used in several modern systems, and talks about his experience at linkedin using this approach.  Lots of interesting references at the end.  I was happy to see John Ousterhout mentioned there!

The Log: What every software engineer should know about real-time data's unifying abstraction

blogodex = {"idx" : ["logging", "Jay Kreps", "Kafka", "fundamentals", "scalability"]};

Tuesday, June 23, 2015

Monitoring Oracle Dataguard Status

Received a tip from the gurus:
v$dataguard_stats - various stats, including apply lag.
v$dataguard_status - status messages related to dataguard.
v$managed_standby - info on the standby 

v$archive_gap - shows the # of archived redo logs the standby is
behind.  Since we're shipping in real-time, this should nearly always be 0.

Monday, June 22, 2015

Saturday, June 6, 2015

Setting a Sphinx theme

To set a theme in Sphinx:

  • find a theme you want to copy.  It will generally be a directory full of files.
  • copy the directory under your project's _templates directory.
  • set the html_theme in
  • some docs mention setting html_theme_path as well, but it doesn't seem necessary if it's under _templates.
  • There's some nice themes at

$ ls _templates/

$ diff
< html_theme = 'alabaster'
> html_theme = "sphinx_rtd_theme"
> html_theme_path = ["_themes", ]    ### probably not necessary

"git push" to Github wants me to log in!

If git prompts you for a username when you push:

$ git push


Check your remote settings.

$ git remote -v
origin (fetch)
origin (push)

If it's an https reference, you can change it to an ssh reference as follows. 

$ git remote set-url origin

And everything is great!

$ git push
Everything up-to-date

Saturday, May 16, 2015

Mathematical Theory of Claude Shannon

Claude Shannon is well-known for having pioneered information theory and switching theory.  Here's a great overview of his approach to these and other areas he studied.

Sunday, May 10, 2015

Software: Pagegen Static Site Generator

Pagegen converts a directory tree of RST docs into a static site.  "Aims to generate a fully featured site ready for CSS styling," according to the docs.

blogodex = {"toc" : "PageGen", "idx" = ["Software"]};

Book: The Three Body Problem, Liu Cixin

When I was in China, I met some Sci Fi enthusiasts and asked who their favorite authors were.  I wasn't sure who might have been translate, and how the various political points of view might have affected what was brought in to the country.

To my surprise, they had a lot of authors, all of them Chinese.  It turns out that the country's enthusiasm for science led to Science Fiction being very popular in the country.

I hadn't heard of any of them, and none of the works seem to have been translated into English. Perhaps this is going to change, starting with this book?

Amazon link and their blurb:
The Three-Body Problem is the first chance for English-speaking readers to experience this multiple award winning phenomenon from China's most beloved science fiction author, Liu Cixin. 
Set against the backdrop of China's Cultural Revolution, a secret military project sends signals into space to establish contact with aliens. An alien civilization on the brink of destruction captures the signal and plans to invade Earth. Meanwhile, on Earth, different camps start forming, planning to either welcome the superior beings and help them take over a world seen as corrupt, or to fight against the invasion. The result is a science fiction masterpiece of enormous scope and vision.
blogodex = {"idx" : ["Books", "Science Fiction", "Three Body Problem", "Liu Cixin"]};

Requests Notes: Python HTTP API

A very pleasant HTTP library for Python.
"Requests takes all of the work out of Python HTTP/1.1 — making your integration with web services seamless. There’s no need to manually add query strings to your URLs, or to form-encode your POST data. Keep-alive and HTTP connection pooling are 100% automatic, powered by urllib3, which is embedded within Requests."


blogodex = {"toc" : "requests", "idx" = ["python", "http"]};

Wednesday, November 12, 2014

Good post on testing server failures

tl;dr: make your system "pressure tolerant" by using system tools to simulate failures.
If there's one thing to know about distributed systems, it's that they have to be designed with the expectation of failure. It's also safe to say that most software these days is, in some form, distributed—whether it's a database, mobile app, or enterprise SaaS. If you have two different processes talking to each other, you have a distributed system, and it doesn't matter if those processes are local or intergalactically displaced. 
Marc Hedlund recently had a great post on Stripe's game-day exercises where they block off an afternoon, take a blunt instrument to their servers, and see what happens. We're talking like abruptly killing instances here—kill -9, ec2-terminate-instances, yanking on the damn power cord—that sort of thing. Everyone should be doing this type of stuff. You really don't know how your system behaves until you see it under failure conditions.

Wednesday, July 16, 2014

Building RESTful APIs with Tornado

Nice Tornado Article.

from datetime import date
import tornado.escape
import tornado.ioloop
import tornado.web
class VersionHandler(tornado.web.RequestHandler):
    def get(self):
        response = { 'version': '3.5.1',
                     'last_build': }
class GetGameByIdHandler(tornado.web.RequestHandler):
    def get(self, id):
        response = { 'id': int(id),
                     'name': 'Crazy Game',
                     'release_date': }
application = tornado.web.Application([
    (r"/getgamebyid/([0-9]+)", GetGameByIdHandler),
    (r"/version", VersionHandler)
if __name__ == "__main__":