Browse Source

use nrsc to pack static data into the binaries, making adding assets easier and simplifying the build process

Alan Shreve 12 years ago
parent
commit
0b7ceda198

+ 1 - 0
.gitignore

@@ -3,6 +3,7 @@ bin/
 pkg/
 src/code.google.com
 src/github.com
+src/bitbucket.org
 src/ngrok/client/views/web/static/*.html.go
 src/ngrok/client/views/web/static/*.css.go
 src/ngrok/client/views/web/static/*.js.go

+ 7 - 24
Makefile

@@ -1,48 +1,31 @@
-.PHONY: default server client deps clean all release-client release-server bindata
+.PHONY: default server client deps fmt clean all release-client release-server release-all
 BUILDTAGS=
 export GOPATH:=$(shell pwd)
 
 default: all
 
 deps:
-	go get -d -v ngrok/...
+	go get -tags '$(BUILDTAGS)' -d -v ngrok/...
 
 server: deps
-	go install -tags '$(BUILDTAGS)' main/ngrokd
+	go install -tags '$(BUILDTAGS)' ngrok/server/main
 
 fmt:
 	go fmt ngrok/...
 
 client: deps
-	go install -tags '$(BUILDTAGS)' main/ngrok
+	go install -tags '$(BUILDTAGS)' ngrok/client/main
 
 release-client: BUILDTAGS=release
-release-client: bindata-client client
+release-client: client
+	./nrsc ./bin/ngrok ./assets/client
 
 release-server: BUILDTAGS=release
 release-server: server
+	./nrsc ./bin/ngrokd ./assets/server
 
 release-all: release-client release-server
 
-certs:
-	go get github.com/inconshreveable/go-bindata
-	./bin/go-bindata -i assets/tls/snakeoil.crt -o src/ngrok/server/tls/snakeoil.crt.go -m -p tls -f snakeoilCrt
-	./bin/go-bindata -i assets/tls/snakeoil.key -o src/ngrok/server/tls/snakeoil.key.go -m -p tls -f snakeoilKey
-	./bin/go-bindata -i assets/tls/snakeoilca.crt -o src/ngrok/client/tls/snakeoilca.crt.go -m -p tls -f snakeoilCaCrt
-	./bin/go-bindata -i assets/tls/ngrokroot.crt -o src/ngrok/client/tls/ngrokroot.crt.go -m -p tls -f ngrokRootCrt
-
-bindata-client:
-	go get github.com/inconshreveable/go-bindata
-	./bin/go-bindata -b release -i assets/page.html -o src/ngrok/client/views/web/static/page.html.go -m -p static -f PageHtml
-	./bin/go-bindata -b release -i assets/highlight.min.css -o src/ngrok/client/views/web/static/highlight.css.go -m -p static -f HighlightCss
-	./bin/go-bindata -b release -i assets/highlight.min.js -o src/ngrok/client/views/web/static/highlight.js.go -m -p static -f HighlightJs
-	./bin/go-bindata -b release -i assets/bootstrap.min.css -o src/ngrok/client/views/web/static/bootstrap.css.go -m -p static -f BootstrapCss
-	./bin/go-bindata -b release -i assets/jquery-1.9.1.min.js -o src/ngrok/client/views/web/static/jquery-1.9.1.js.go -m -p static -f JqueryJs
-	./bin/go-bindata -b release -i assets/vkbeautify.js -o src/ngrok/client/views/web/static/vkbeautify.js.go -m -p static -f VkBeautifyJs
-	./bin/go-bindata -b release -i assets/angular.js -o src/ngrok/client/views/web/static/angular.js.go -m -p static -f AngularJs
-	./bin/go-bindata -b release -i assets/ngrok.js -o src/ngrok/client/views/web/static/ngrok.js.go -m -p static -f NgrokJs
-	./bin/go-bindata -b release -i assets/base64.js -o src/ngrok/client/views/web/static/base64.js.go -m -p static -f Base64Js
-
 all: fmt client server
 
 clean:

+ 8 - 8
assets/page.html → assets/client/page.html

@@ -1,14 +1,14 @@
 <html>
     <head>
         <title>ngrok</title>
-        <link href="/static/highlight.min.css" rel="stylesheet">
-        <link href="/static/bootstrap.min.css" rel="stylesheet">
-        <script src="/static/highlight.min.js"></script>
-        <script src="/static/vkbeautify.js"></script>
-        <script src="/static/jquery-1.9.1.min.js"></script>
-        <script src="/static/angular.js"></script>
-        <script src="/static/base64.js"></script>
-        <script src="/static/ngrok.js"></script>
+        <link href="/static/css/highlight.min.css" rel="stylesheet">
+        <link href="/static/css/bootstrap.min.css" rel="stylesheet">
+        <script src="/static/js/highlight.min.js"></script>
+        <script src="/static/js/vkbeautify.js"></script>
+        <script src="/static/js/jquery-1.9.1.min.js"></script>
+        <script src="/static/js/angular.js"></script>
+        <script src="/static/js/base64.js"></script>
+        <script src="/static/js/ngrok.js"></script>
         <script type="text/javascript">
             window.data = JSON.parse({% . %});
         </script>

+ 0 - 0
assets/bootstrap.min.css → assets/client/static/css/bootstrap.min.css


+ 0 - 0
assets/highlight.min.css → assets/client/static/css/highlight.min.css


+ 0 - 0
assets/angular.js → assets/client/static/js/angular.js


+ 0 - 0
assets/base64.js → assets/client/static/js/base64.js


+ 0 - 0
assets/highlight.min.js → assets/client/static/js/highlight.min.js


+ 0 - 0
assets/jquery-1.9.1.min.js → assets/client/static/js/jquery-1.9.1.min.js


+ 0 - 0
assets/ngrok.js → assets/client/static/js/ngrok.js


+ 0 - 0
assets/vkbeautify.js → assets/client/static/js/vkbeautify.js


+ 0 - 0
assets/tls/ngrokroot.crt → assets/client/tls/ngrokroot.crt


+ 0 - 0
assets/tls/snakeoilca.crt → assets/client/tls/snakeoilca.crt


+ 0 - 0
assets/tls/snakeoil.crt → assets/server/tls/snakeoil.crt


+ 0 - 0
assets/tls/snakeoil.key → assets/server/tls/snakeoil.key


+ 46 - 0
nrsc

@@ -0,0 +1,46 @@
+#!/bin/bash
+# Pack assets as zip payload in go executable
+
+# Idea from Carlos Castillo (http://bit.ly/SmYXXm)
+
+case "$1" in
+    -h | --help )
+        echo "usage: $(basename $0) EXECTABLE RESOURCE_DIR [ZIP OPTIONS]";
+        exit;;
+    --version )
+        echo "nrsc version 0.3.1"; exit;;
+esac
+
+if [ $# -lt 2 ]; then
+    $0 -h
+    exit 1
+fi
+
+exe=$1
+shift
+root=$1
+shift
+
+if [ ! -f "${exe}" ]; then
+    echo "error: can't find $exe"
+    exit 1
+fi
+
+if [ ! -d "${root}" ]; then
+    echo "error: ${root} is not a directory"
+    exit 1
+fi
+
+# Exit on 1'st error
+set -e
+
+tmp="/tmp/nrsc-$(date +%s).zip"
+trap "rm -f ${tmp}" EXIT
+
+# Create zip file
+(zip -r "${tmp}" ${root} $@)
+
+# Append zip to executable
+cat "${tmp}" >> "${exe}"
+# Fix zip offset in file
+zip -q -A "${exe}"

+ 11 - 0
src/ngrok/assets/debug.go

@@ -0,0 +1,11 @@
+// +build !release
+
+package assets
+
+import (
+	"io/ioutil"
+)
+
+func ReadAsset(path string) (b []byte, err error) {
+	return ioutil.ReadFile(path)
+}

+ 28 - 0
src/ngrok/assets/release.go

@@ -0,0 +1,28 @@
+// +build release
+
+package assets
+
+import (
+	"bitbucket.org/tebeka/nrsc"
+	"fmt"
+	"io/ioutil"
+)
+
+func init() {
+	nrsc.Initialize()
+}
+
+func ReadAsset(path string) (b []byte, err error) {
+	resource := nrsc.Get(path)
+	if resource == nil {
+		err = fmt.Errorf("Asset %s not compiled into package", path)
+		return
+	}
+
+	rd, err := resource.Open()
+	if err != nil {
+		return
+	}
+
+	return ioutil.ReadAll(rd)
+}

+ 2 - 3
src/ngrok/client/main.go

@@ -6,7 +6,6 @@ import (
 	"io/ioutil"
 	"math"
 	"net/http"
-	"ngrok/client/tls"
 	"ngrok/client/ui"
 	"ngrok/client/views/term"
 	"ngrok/client/views/web"
@@ -39,7 +38,7 @@ const (
  */
 func proxy(proxyAddr string, s *State, ctl *ui.Controller) {
 	start := time.Now()
-	remoteConn, err := conn.Dial(proxyAddr, "pxy", tls.Config)
+	remoteConn, err := conn.Dial(proxyAddr, "pxy", tlsConfig)
 	if err != nil {
 		// XXX: What is the proper response here?
 		// display something to the user?
@@ -193,7 +192,7 @@ func control(s *State, ctl *ui.Controller) {
 	}()
 
 	// establish control channel
-	conn, err := conn.Dial(s.opts.server, "ctl", tls.Config)
+	conn, err := conn.Dial(s.opts.server, "ctl", tlsConfig)
 	if err != nil {
 		panic(err)
 	}

+ 0 - 0
src/main/ngrok/client.go → src/ngrok/client/main/ngrok.go


+ 16 - 4
src/ngrok/client/tls/load.go → src/ngrok/client/tls.go

@@ -1,18 +1,30 @@
-package tls
+package client
 
 import (
 	"crypto/tls"
 	"crypto/x509"
 	"encoding/pem"
+	"ngrok/assets"
 )
 
 var (
-	Config *tls.Config
+	tlsConfig *tls.Config
 )
 
 func init() {
 	pool := x509.NewCertPool()
-	for _, b := range [][]byte{ngrokRootCrt(), snakeoilCaCrt()} {
+
+	ngrokRootCrt, err := assets.ReadAsset("assets/client/tls/ngrokroot.crt")
+	if err != nil {
+		panic(err)
+	}
+
+	snakeoilCaCrt, err := assets.ReadAsset("assets/client/tls/snakeoilca.crt")
+	if err != nil {
+		panic(err)
+	}
+
+	for _, b := range [][]byte{ngrokRootCrt, snakeoilCaCrt} {
 		pemBlock, _ := pem.Decode(b)
 		if pemBlock == nil {
 			panic("Bad PEM data")
@@ -26,7 +38,7 @@ func init() {
 		pool.AddCert(certs[0])
 	}
 
-	Config = &tls.Config{
+	tlsConfig = &tls.Config{
 		RootCAs:    pool,
 		ServerName: "tls.ngrok.com",
 	}

+ 0 - 102
src/ngrok/client/tls/addtrust.key.go

@@ -1,102 +0,0 @@
-package tls
-
-import (
-	"bytes"
-	"compress/gzip"
-	"io"
-	"reflect"
-	"unsafe"
-)
-
-var _addTrustCrt = "" +
-	"\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x74\x94\x5b\xcf\xaa\x38" +
-	"\x14\x86\xef\xf9\x15\x73\x6f\x26\xa2\x82\xca\xc5\x5c\xb4\xa5\x40" +
-	"\xd1\x02\xe5\x28\xdc\x71\x12\x04\xf1\x88\x16\xf9\xf5\xe3\xe7\xb7" +
-	"\x33\xd9\x33\x7b\x76\x93\x26\xcd\xdb\x64\xad\xb7\x5d\xcf\x5a\x7f" +
-	"\x7e\x2d\x88\x75\x62\xfd\x81\xb0\xeb\x13\x8d\x20\xe0\xe3\x8f\x2a" +
-	"\x50\x42\xb0\xd5\x20\x04\x86\x65\x05\x38\x81\xa0\x7a\x6f\x1f\x58" +
-	"\xb0\x6a\xaf\x75\x7b\xd0\x15\x2e\x42\xc0\x02\x0d\xa8\xf0\x49\xd9" +
-	"\x9d\x23\x16\xab\x21\x63\x3a\xe6\xa6\xef\xfa\x38\x10\x28\x24\x3a" +
-	"\x98\x05\x18\xd5\x74\xcb\x22\xb7\x0d\x0d\x73\x96\x2f\x58\xc5\x02" +
-	"\x32\x98\x0d\x68\x61\x65\x85\x10\xdc\x7d\x23\xd0\xda\x44\x73\x5f" +
-	"\xc5\xce\x12\x09\x0e\xa5\x42\x0f\x5f\x59\xa7\xdd\x05\xa2\xb9\x41" +
-	"\x80\xa0\x9d\xec\xdc\x45\xb6\x30\x6f\xd4\x23\x9c\x80\x4f\x16\x15" +
-	"\x0f\x47\x98\xe8\x6e\x90\x9f\xc2\xb1\x40\x50\x2b\x0d\xf7\x98\x77" +
-	"\x72\x9d\x21\xa8\x32\x0f\x7a\xd9\x5c\x11\xdf\x0e\xa4\x9d\xea\x03" +
-	"\x4e\xd5\x60\xa4\x2a\xe6\x96\x5a\x8d\xb6\x76\x7e\x6b\xe4\xbf\x1a" +
-	"\xcf\x46\xbc\xa5\xa0\xfd\x38\x86\x35\x45\x81\x18\x0c\x82\xa6\x02" +
-	"\xef\xdb\xe6\xd9\x47\xe2\xcf\x36\x35\x44\xbd\x98\x9b\xdf\x6e\xb6" +
-	"\x78\x98\xfd\xaf\x1b\xe1\x6d\x27\x08\x35\x50\xf9\x5d\x28\x16\x73" +
-	"\xe5\x95\x8e\xf8\x40\x11\xf8\x64\x01\x03\x4d\x7e\xfe\x17\x77\x57" +
-	"\x8b\xc9\xce\x7c\xc4\x11\xaf\x98\x88\xab\xa0\x53\x9e\x42\xa1\xbe" +
-	"\x2b\xf0\x7e\xb7\xca\x62\x73\x73\x4e\x48\xfd\xcc\x2d\xc0\x30\x84" +
-	"\x0c\xa8\x55\x85\x1d\xf0\x75\xcf\xce\xe8\x7d\x86\x60\xbb\x5f\xe8" +
-	"\x8d\xd3\xad\x2b\x80\xb7\xfe\xa9\xf2\x8f\xcf\x5e\x30\x56\xc3\x5d" +
-	"\x5d\xcf\x67\x93\x83\x3d\x1f\xfb\x65\x86\x7d\x7b\x77\x41\x47\xba" +
-	"\x4f\xec\xfd\x33\xb8\xae\xdb\x89\xa8\xea\x0f\xdb\x19\x27\x61\x1f" +
-	"\x68\xb7\xe8\xf8\xea\x82\xe8\x8c\xb8\xb7\xbb\x65\xdb\xcb\x4e\x11" +
-	"\x1e\xf4\x3a\xb5\xc6\xaa\x37\x9a\xa5\xcb\xd2\x19\x0f\xef\x7b\xee" +
-	"\x8f\xd3\x33\xbd\xc8\xe2\xeb\x7e\x60\xa1\x7d\xd2\x77\x5c\x91\x4e" +
-	"\xc9\x05\x38\x60\x79\x8f\xd3\x4b\xa9\x91\x49\x59\x2f\xb5\x6b\x60" +
-	"\x8d\x3b\xa1\x6b\x97\x4f\x98\xd9\x5d\x9e\x78\x79\x9e\x59\x2c\x06" +
-	"\x37\x03\xcb\xa2\x04\xa5\x18\x5d\xed\xee\x9c\x7a\x71\xdc\x6e\x7a" +
-	"\x7a\xc7\xeb\xe6\x3a\x5e\x9c\xda\x6a\xf6\xe3\x65\x5a\xa7\xd1\x64" +
-	"\x35\x13\xb7\x3b\x21\x15\xfd\x76\x58\x2e\x1e\x59\xa0\xed\xf3\xe3" +
-	"\x65\x40\x6a\x39\x96\x51\xd4\x46\x29\x0a\xac\x69\x0e\xb6\x7c\x81" +
-	"\xda\xd3\x36\x15\xd5\xfa\x35\x1f\xbc\xb3\x9b\xbb\xc5\xe6\x34\x5f" +
-	"\xf4\x56\x86\x57\xd7\xd1\x12\xb0\xe8\x2d\x5e\xde\xb3\x60\x1c\x1c" +
-	"\x27\x9d\x2e\xa7\xd1\x25\x26\x83\xbe\xb8\x8c\xb6\x13\x9e\xc2\x44" +
-	"\xc9\xc5\xcb\x4c\x4c\x17\xe8\xd0\x1f\xfb\xde\x42\xd9\x10\xbd\x1e" +
-	"\xc6\x73\xb5\x9a\x1c\x8b\x40\x09\x44\x21\x3a\xe4\x08\x70\x0c\x40" +
-	"\x6a\xc3\x85\x8a\xe0\xdc\x07\xc5\x17\x17\x06\x93\xb0\xf6\x06\xfa" +
-	"\x96\xcd\xe3\xb2\xf1\x44\xf3\xb9\x5f\x0e\x28\x09\x56\xdc\x56\x24" +
-	"\xe4\x6f\x43\x78\xe6\x88\xc7\xaa\x10\xba\xa2\xf3\xee\x16\x15\x54" +
-	"\x58\xa7\x60\xfd\x55\xff\x02\x73\x0c\xa7\x9c\x69\x14\x50\x08\xf6" +
-	"\x6b\x5e\x25\x1f\xfa\x0a\xc2\x3d\xd8\xfa\x08\x36\x67\xf0\x4f\x60" +
-	"\xe1\xd7\xc8\xd7\x3a\x5f\xba\x03\xd5\xd7\x03\x1a\x81\xf9\x4d\x69" +
-	"\xec\x83\xa3\xa5\x51\x97\x71\x5c\x7d\xc8\xdc\x60\xde\x7f\xc8\x14" +
-	"\x7e\xa0\x09\x59\x83\x3b\x8a\xd8\x77\x67\x0e\xb4\xf8\x1d\x81\xa1" +
-	"\xe6\x32\x82\xe5\x63\x61\x14\xcf\xbc\xbb\x0f\x02\x69\x40\xf5\x9d" +
-	"\x85\xfa\xfa\x6f\x5a\xf6\x3d\x31\x20\xd1\xcc\x67\xb6\xf0\xde\x54" +
-	"\xe2\x7f\x51\x2b\xbc\x05\xed\x07\xb6\x6f\x54\x51\x26\x91\xe0\xc8" +
-	"\xfb\xb8\x91\xaa\x49\x04\x2f\x9b\x82\x25\x87\x7c\x1e\xbb\x72\x55" +
-	"\xb4\x65\x34\x30\x83\x8c\xc9\xb1\x59\xa9\x71\xb1\x7a\xdc\x59\x34" +
-	"\x18\x42\x4c\x2c\xf7\xee\xb4\x2f\xa7\xdc\xaf\x95\x43\xec\x0f\x12" +
-	"\x88\x2e\x99\x92\x4e\xc9\xde\x29\x8d\xce\x24\xc9\xed\xe0\x83\x7c" +
-	"\x53\x37\xd1\x7a\xdd\xcb\xee\x60\x6d\xa2\x5e\x19\x26\xfe\x43\xe6" +
-	"\x53\x97\xcb\xc2\x92\x73\x14\xb8\xac\x6f\x6e\x62\x24\x51\x63\xef" +
-	"\x9e\x76\x27\x73\xb3\xb8\x2b\x78\x23\xd6\x89\xc5\xb1\x5e\x2e\x4f" +
-	"\x2c\x9e\x79\x75\xe3\x6f\x16\x37\x1a\x04\x9b\xba\xec\x1c\x57\xbe" +
-	"\x3d\xea\xc1\x7b\x22\xc1\xba\x49\xbe\x5a\xa6\x4a\xbc\x90\xe5\x72" +
-	"\x99\x9b\x6a\x80\x6e\x69\x3f\x77\x0e\x77\x67\xae\x9c\x79\xca\xaa" +
-	"\xd0\x9d\xe1\xdd\xec\xb4\x2c\x0e\x24\xaa\x42\x82\xe9\xba\x2b\x8b" +
-	"\xf5\xd3\xf3\xe3\x6b\x82\x77\x42\x2e\x55\xd3\xb0\xbe\x0f\x36\x3c" +
-	"\x88\x39\x9b\xa4\x63\x5e\xd9\xa7\xb3\xf4\xd0\x27\x3a\xed\x88\xb3" +
-	"\x35\x46\x63\x70\xf1\xa8\x43\xc3\x32\x8b\x0e\x38\xc3\xf4\xa0\x68" +
-	"\x12\xbc\x6d\x1f\x27\xea\x03\x39\x15\xba\x53\xeb\x10\x70\x7e\xcc" +
-	"\x12\xb9\x31\x6b\x39\x6c\x2f\x7e\x5c\xd5\x45\x5a\x2a\x68\x3d\x48" +
-	"\x8a\x5d\x57\xec\x2f\xe1\x33\xc0\xb1\xa5\xfe\x3a\xd4\xff\x0e\x00" +
-	"\x00\xff\xff\x8b\x62\x79\xeb\xf1\x05\x00\x00"
-
-// addTrustCrt returns raw, uncompressed file data.
-func addTrustCrt() []byte {
-	var empty [0]byte
-	sx := (*reflect.StringHeader)(unsafe.Pointer(&_addTrustCrt))
-	b := empty[:]
-	bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-	bx.Data = sx.Data
-	bx.Len = len(_addTrustCrt)
-	bx.Cap = bx.Len
-
-	gz, err := gzip.NewReader(bytes.NewBuffer(b))
-
-	if err != nil {
-		panic("Decompression failed: " + err.Error())
-	}
-
-	var buf bytes.Buffer
-	io.Copy(&buf, gz)
-	gz.Close()
-
-	return buf.Bytes()
-}

+ 0 - 102
src/ngrok/client/tls/ngrokroot.crt.go

@@ -1,102 +0,0 @@
-package tls
-
-import (
-	"bytes"
-	"compress/gzip"
-	"io"
-	"reflect"
-	"unsafe"
-)
-
-var _ngrokRootCrt = "" +
-	"\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x74\x94\x5b\xcf\xaa\x38" +
-	"\x14\x86\xef\xf9\x15\x73\x6f\x26\xa2\x82\xca\xc5\x5c\xb4\xa5\x40" +
-	"\xd1\x02\xe5\x28\xdc\x71\x12\x04\xf1\x88\x16\xf9\xf5\xe3\xe7\xb7" +
-	"\x33\xd9\x33\x7b\x76\x93\x26\xcd\xdb\x64\xad\xb7\x5d\xcf\x5a\x7f" +
-	"\x7e\x2d\x88\x75\x62\xfd\x81\xb0\xeb\x13\x8d\x20\xe0\xe3\x8f\x2a" +
-	"\x50\x42\xb0\xd5\x20\x04\x86\x65\x05\x38\x81\xa0\x7a\x6f\x1f\x58" +
-	"\xb0\x6a\xaf\x75\x7b\xd0\x15\x2e\x42\xc0\x02\x0d\xa8\xf0\x49\xd9" +
-	"\x9d\x23\x16\xab\x21\x63\x3a\xe6\xa6\xef\xfa\x38\x10\x28\x24\x3a" +
-	"\x98\x05\x18\xd5\x74\xcb\x22\xb7\x0d\x0d\x73\x96\x2f\x58\xc5\x02" +
-	"\x32\x98\x0d\x68\x61\x65\x85\x10\xdc\x7d\x23\xd0\xda\x44\x73\x5f" +
-	"\xc5\xce\x12\x09\x0e\xa5\x42\x0f\x5f\x59\xa7\xdd\x05\xa2\xb9\x41" +
-	"\x80\xa0\x9d\xec\xdc\x45\xb6\x30\x6f\xd4\x23\x9c\x80\x4f\x16\x15" +
-	"\x0f\x47\x98\xe8\x6e\x90\x9f\xc2\xb1\x40\x50\x2b\x0d\xf7\x98\x77" +
-	"\x72\x9d\x21\xa8\x32\x0f\x7a\xd9\x5c\x11\xdf\x0e\xa4\x9d\xea\x03" +
-	"\x4e\xd5\x60\xa4\x2a\xe6\x96\x5a\x8d\xb6\x76\x7e\x6b\xe4\xbf\x1a" +
-	"\xcf\x46\xbc\xa5\xa0\xfd\x38\x86\x35\x45\x81\x18\x0c\x82\xa6\x02" +
-	"\xef\xdb\xe6\xd9\x47\xe2\xcf\x36\x35\x44\xbd\x98\x9b\xdf\x6e\xb6" +
-	"\x78\x98\xfd\xaf\x1b\xe1\x6d\x27\x08\x35\x50\xf9\x5d\x28\x16\x73" +
-	"\xe5\x95\x8e\xf8\x40\x11\xf8\x64\x01\x03\x4d\x7e\xfe\x17\x77\x57" +
-	"\x8b\xc9\xce\x7c\xc4\x11\xaf\x98\x88\xab\xa0\x53\x9e\x42\xa1\xbe" +
-	"\x2b\xf0\x7e\xb7\xca\x62\x73\x73\x4e\x48\xfd\xcc\x2d\xc0\x30\x84" +
-	"\x0c\xa8\x55\x85\x1d\xf0\x75\xcf\xce\xe8\x7d\x86\x60\xbb\x5f\xe8" +
-	"\x8d\xd3\xad\x2b\x80\xb7\xfe\xa9\xf2\x8f\xcf\x5e\x30\x56\xc3\x5d" +
-	"\x5d\xcf\x67\x93\x83\x3d\x1f\xfb\x65\x86\x7d\x7b\x77\x41\x47\xba" +
-	"\x4f\xec\xfd\x33\xb8\xae\xdb\x89\xa8\xea\x0f\xdb\x19\x27\x61\x1f" +
-	"\x68\xb7\xe8\xf8\xea\x82\xe8\x8c\xb8\xb7\xbb\x65\xdb\xcb\x4e\x11" +
-	"\x1e\xf4\x3a\xb5\xc6\xaa\x37\x9a\xa5\xcb\xd2\x19\x0f\xef\x7b\xee" +
-	"\x8f\xd3\x33\xbd\xc8\xe2\xeb\x7e\x60\xa1\x7d\xd2\x77\x5c\x91\x4e" +
-	"\xc9\x05\x38\x60\x79\x8f\xd3\x4b\xa9\x91\x49\x59\x2f\xb5\x6b\x60" +
-	"\x8d\x3b\xa1\x6b\x97\x4f\x98\xd9\x5d\x9e\x78\x79\x9e\x59\x2c\x06" +
-	"\x37\x03\xcb\xa2\x04\xa5\x18\x5d\xed\xee\x9c\x7a\x71\xdc\x6e\x7a" +
-	"\x7a\xc7\xeb\xe6\x3a\x5e\x9c\xda\x6a\xf6\xe3\x65\x5a\xa7\xd1\x64" +
-	"\x35\x13\xb7\x3b\x21\x15\xfd\x76\x58\x2e\x1e\x59\xa0\xed\xf3\xe3" +
-	"\x65\x40\x6a\x39\x96\x51\xd4\x46\x29\x0a\xac\x69\x0e\xb6\x7c\x81" +
-	"\xda\xd3\x36\x15\xd5\xfa\x35\x1f\xbc\xb3\x9b\xbb\xc5\xe6\x34\x5f" +
-	"\xf4\x56\x86\x57\xd7\xd1\x12\xb0\xe8\x2d\x5e\xde\xb3\x60\x1c\x1c" +
-	"\x27\x9d\x2e\xa7\xd1\x25\x26\x83\xbe\xb8\x8c\xb6\x13\x9e\xc2\x44" +
-	"\xc9\xc5\xcb\x4c\x4c\x17\xe8\xd0\x1f\xfb\xde\x42\xd9\x10\xbd\x1e" +
-	"\xc6\x73\xb5\x9a\x1c\x8b\x40\x09\x44\x21\x3a\xe4\x08\x70\x0c\x40" +
-	"\x6a\xc3\x85\x8a\xe0\xdc\x07\xc5\x17\x17\x06\x93\xb0\xf6\x06\xfa" +
-	"\x96\xcd\xe3\xb2\xf1\x44\xf3\xb9\x5f\x0e\x28\x09\x56\xdc\x56\x24" +
-	"\xe4\x6f\x43\x78\xe6\x88\xc7\xaa\x10\xba\xa2\xf3\xee\x16\x15\x54" +
-	"\x58\xa7\x60\xfd\x55\xff\x02\x73\x0c\xa7\x9c\x69\x14\x50\x08\xf6" +
-	"\x6b\x5e\x25\x1f\xfa\x0a\xc2\x3d\xd8\xfa\x08\x36\x67\xf0\x4f\x60" +
-	"\xe1\xd7\xc8\xd7\x3a\x5f\xba\x03\xd5\xd7\x03\x1a\x81\xf9\x4d\x69" +
-	"\xec\x83\xa3\xa5\x51\x97\x71\x5c\x7d\xc8\xdc\x60\xde\x7f\xc8\x14" +
-	"\x7e\xa0\x09\x59\x83\x3b\x8a\xd8\x77\x67\x0e\xb4\xf8\x1d\x81\xa1" +
-	"\xe6\x32\x82\xe5\x63\x61\x14\xcf\xbc\xbb\x0f\x02\x69\x40\xf5\x9d" +
-	"\x85\xfa\xfa\x6f\x5a\xf6\x3d\x31\x20\xd1\xcc\x67\xb6\xf0\xde\x54" +
-	"\xe2\x7f\x51\x2b\xbc\x05\xed\x07\xb6\x6f\x54\x51\x26\x91\xe0\xc8" +
-	"\xfb\xb8\x91\xaa\x49\x04\x2f\x9b\x82\x25\x87\x7c\x1e\xbb\x72\x55" +
-	"\xb4\x65\x34\x30\x83\x8c\xc9\xb1\x59\xa9\x71\xb1\x7a\xdc\x59\x34" +
-	"\x18\x42\x4c\x2c\xf7\xee\xb4\x2f\xa7\xdc\xaf\x95\x43\xec\x0f\x12" +
-	"\x88\x2e\x99\x92\x4e\xc9\xde\x29\x8d\xce\x24\xc9\xed\xe0\x83\x7c" +
-	"\x53\x37\xd1\x7a\xdd\xcb\xee\x60\x6d\xa2\x5e\x19\x26\xfe\x43\xe6" +
-	"\x53\x97\xcb\xc2\x92\x73\x14\xb8\xac\x6f\x6e\x62\x24\x51\x63\xef" +
-	"\x9e\x76\x27\x73\xb3\xb8\x2b\x78\x23\xd6\x89\xc5\xb1\x5e\x2e\x4f" +
-	"\x2c\x9e\x79\x75\xe3\x6f\x16\x37\x1a\x04\x9b\xba\xec\x1c\x57\xbe" +
-	"\x3d\xea\xc1\x7b\x22\xc1\xba\x49\xbe\x5a\xa6\x4a\xbc\x90\xe5\x72" +
-	"\x99\x9b\x6a\x80\x6e\x69\x3f\x77\x0e\x77\x67\xae\x9c\x79\xca\xaa" +
-	"\xd0\x9d\xe1\xdd\xec\xb4\x2c\x0e\x24\xaa\x42\x82\xe9\xba\x2b\x8b" +
-	"\xf5\xd3\xf3\xe3\x6b\x82\x77\x42\x2e\x55\xd3\xb0\xbe\x0f\x36\x3c" +
-	"\x88\x39\x9b\xa4\x63\x5e\xd9\xa7\xb3\xf4\xd0\x27\x3a\xed\x88\xb3" +
-	"\x35\x46\x63\x70\xf1\xa8\x43\xc3\x32\x8b\x0e\x38\xc3\xf4\xa0\x68" +
-	"\x12\xbc\x6d\x1f\x27\xea\x03\x39\x15\xba\x53\xeb\x10\x70\x7e\xcc" +
-	"\x12\xb9\x31\x6b\x39\x6c\x2f\x7e\x5c\xd5\x45\x5a\x2a\x68\x3d\x48" +
-	"\x8a\x5d\x57\xec\x2f\xe1\x33\xc0\xb1\xa5\xfe\x3a\xd4\xff\x0e\x00" +
-	"\x00\xff\xff\x8b\x62\x79\xeb\xf1\x05\x00\x00"
-
-// ngrokRootCrt returns raw, uncompressed file data.
-func ngrokRootCrt() []byte {
-	var empty [0]byte
-	sx := (*reflect.StringHeader)(unsafe.Pointer(&_ngrokRootCrt))
-	b := empty[:]
-	bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-	bx.Data = sx.Data
-	bx.Len = len(_ngrokRootCrt)
-	bx.Cap = bx.Len
-
-	gz, err := gzip.NewReader(bytes.NewBuffer(b))
-
-	if err != nil {
-		panic("Decompression failed: " + err.Error())
-	}
-
-	var buf bytes.Buffer
-	io.Copy(&buf, gz)
-	gz.Close()
-
-	return buf.Bytes()
-}

+ 0 - 121
src/ngrok/client/tls/snakeoilca.crt.go

@@ -1,121 +0,0 @@
-package tls
-
-import (
-	"bytes"
-	"compress/gzip"
-	"io"
-	"reflect"
-	"unsafe"
-)
-
-var _snakeoilCaCrt = "" +
-	"\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x6c\x95\xc7\x0e\xab\xce" +
-	"\x92\xc6\xf7\x3c\xc5\xec\xd1\x08\x0c\x26\x2d\x66\xd1\x34\x4d\x06" +
-	"\x93\x31\xec\x8c\x03\x98\x9c\xd3\xd3\x8f\xff\xe7\x48\x23\xcd\xbd" +
-	"\xb7\x57\xad\xaf\x5a\xbf\x2e\x95\xea\xab\xfa\xef\x7f\x8e\x88\x14" +
-	"\xcd\xfe\x2f\x88\xbc\x40\x93\x35\x08\x02\xf4\x47\xc5\x2c\x4d\x93" +
-	"\x65\x09\x42\xb0\x6e\x10\xba\xb0\xca\x6c\xd2\x53\x88\xee\xc2\x48" +
-	"\xc0\x16\xf3\x6a\x28\xaa\xaf\x22\x6c\xa4\x08\xdc\x50\x06\x92\x68" +
-	"\x59\xee\xb4\x41\x37\x91\x22\xd7\x55\xd0\xa6\x47\x58\x78\xa2\xc0" +
-	"\xfa\xc1\xc1\x25\x44\x50\xb4\x0c\x97\x92\xa7\x47\x9c\xae\xcf\x86" +
-	"\xe9\x93\x00\xf9\x96\x08\xfe\xc6\x0a\x4b\xcf\x9a\xd7\x91\x51\xd3" +
-	"\x92\x50\xc2\x6c\x79\xee\x86\xf2\x44\xc2\x7e\x24\x49\x06\xd3\x60" +
-	"\x36\x4c\xfb\x6c\x84\xd1\x6c\xec\x35\x0b\xc0\x5b\xde\xc8\xdd\x3a" +
-	"\x01\x65\x49\xd6\x66\x9d\xe1\x6e\x07\xe9\xe3\xa7\x1d\x7f\x35\xf4" +
-	"\x7f\x1a\x66\xa1\x6d\x87\x27\xd0\xc5\xdc\x8e\x44\x90\x04\xa0\x8e" +
-	"\x02\xcb\xb3\x36\xf4\x37\x4d\x0d\x6d\xbd\x94\xc4\x7b\x9f\x36\xc2" +
-	"\x91\x35\x75\x61\x79\xda\x86\xc0\x9f\x98\x81\xb6\x7a\xc1\x52\x5a" +
-	"\x5f\x1f\x07\x53\x66\x14\xb9\xcb\x12\xf0\xff\x82\xac\x10\x1e\xdd" +
-	"\xf2\xff\x52\xd6\x34\xa8\x95\xff\x5a\x17\x24\x63\x00\xdc\x20\xc8" +
-	"\x79\xf0\xcf\x03\x98\x1b\xbf\x3b\x02\xac\x3b\x1e\xf7\xb7\x51\xf3" +
-	"\x20\x8e\x1f\xc2\xa2\x50\x61\xe6\xdf\xfa\xae\x53\xb9\xeb\x69\x56" +
-	"\xf7\x89\x96\xd3\x4f\x25\xe4\xc6\x3a\x54\x5f\xec\xbc\xdf\x5d\xe8" +
-	"\x35\x73\xc8\x4a\x47\x4b\xe2\xb7\xc5\xa7\x27\x44\x8c\x5e\x93\x82" +
-	"\xc9\x2f\x2b\x57\x21\x12\x69\x7e\x21\xc2\xcf\xcd\xeb\x2b\x62\x7d" +
-	"\x96\x1a\xbe\x6e\x9b\x3b\x5d\x55\x7a\x64\xe8\x17\x98\x03\xaf\xea" +
-	"\x96\xf1\x41\x69\x09\x31\x03\x5f\x78\xb7\x45\xa7\xe5\x92\x6b\x4d" +
-	"\x82\xa4\x70\x2b\x3e\x79\x12\xe4\x7a\xc7\x4f\xe9\xb6\x35\x5e\xac" +
-	"\x94\xb6\xe1\x0c\x57\x8a\x5a\x26\x59\x80\xba\xfc\x24\x30\xde\x4d" +
-	"\xf0\x9b\xa4\x4b\xea\xd2\xf2\x51\x04\xaa\x81\xbe\x7f\x9e\xce\x3d" +
-	"\x3f\x66\x55\x1b\xf6\xd5\xd7\xdb\x24\x97\xba\x45\x86\x00\x57\x82" +
-	"\xc9\xe8\x09\x96\xf1\x99\xe7\x37\xf7\x6b\x6d\x74\xd3\x4c\xc5\x38" +
-	"\x8e\x79\x06\x71\x01\xcb\x35\x69\x07\x36\x3f\x8f\xb1\xa2\xbd\xaf" +
-	"\xf2\xca\x2e\x9a\xb2\x68\xfa\x67\xb6\xf4\x7d\xd1\x0f\x3d\xca\x3e" +
-	"\x81\x3c\x0f\xb9\xa5\x04\x4d\xa9\xa6\xfb\xd7\x5c\x2d\xee\x75\x72" +
-	"\x58\x49\x64\xcd\x78\x5e\x9d\xb5\x2d\x32\xd7\x4f\x53\xb3\x98\x56" +
-	"\xe7\xd2\xf1\xcd\xde\x76\xb6\xd5\x77\x44\xd0\x31\xb3\xda\x13\xc1" +
-	"\xc4\x66\x8c\xec\xda\x26\x27\xab\x7d\x73\x8b\x4c\xd0\xb9\xb4\xfc" +
-	"\xba\x63\xd1\x78\x04\x65\xe7\x97\x5f\x44\xeb\xa6\xa4\xa4\x9a\xed" +
-	"\x0a\x96\x8c\x9c\xdc\x39\x3d\xfe\x87\x1e\xe4\x8e\x60\xdf\xdc\x22" +
-	"\x5e\x41\x52\x1b\x9d\xdb\x91\x17\xe3\xdc\xf1\xa4\x89\x36\xcf\x40" +
-	"\xf3\x88\x45\x30\xf0\x52\xef\x59\xb3\x2c\x9e\x5b\xd5\xf3\x4e\x8e" +
-	"\x47\x17\xb5\x79\x5e\x6a\x71\xbc\x5c\x5f\xfc\x02\x0a\xba\xfc\xe0" +
-	"\xb8\xf1\x22\xa5\x32\x23\x6a\x4e\x82\x4e\x8f\x72\x5f\xdf\xd2\x24" +
-	"\x28\xa1\x89\xa5\xac\xbf\x7f\xc5\xcd\xbd\x76\xc2\x0b\xb9\x8f\x97" +
-	"\xa5\xe4\x15\x3d\xd7\x92\x0c\xc5\x69\x54\xbb\x81\xb3\x8f\x73\xbd" +
-	"\xab\x0e\x29\xca\x94\x6a\x64\xbc\xe1\x21\x11\x19\x50\x5b\xdc\x52" +
-	"\xf0\x60\x11\x63\x39\xc9\x9d\xcd\xad\x2f\xdb\x3c\x9e\x48\x78\x7f" +
-	"\x24\xf5\x81\x07\x92\x83\x33\x52\x0a\x2d\x45\x12\xaa\xe6\x5e\xb9" +
-	"\x89\x30\x10\xe7\x30\xac\xd6\x8c\x07\x38\x11\x88\x86\x50\x6f\xe1" +
-	"\xd4\x7d\xa9\xf0\x89\xad\x02\xbd\xf9\x78\x60\x2f\x24\xfb\xf0\xba" +
-	"\x7e\x70\x3a\x21\x49\x47\x9a\xaf\x1e\xf4\x6e\x38\xdf\x9b\xc0\x5e" +
-	"\xfb\x8a\x12\x3b\xd9\x66\xb8\x9c\x63\x39\x85\xaf\x84\x20\x2b\x2a" +
-	"\x71\xff\xce\xab\x1c\x42\x0c\xfc\xac\x01\x82\xff\xe0\xfd\x3f\x2d" +
-	"\x8e\x80\xf7\x21\x8a\x28\x69\xe7\x33\xdc\xe4\x30\x77\xc7\x58\x22" +
-	"\x6b\x22\x7c\x40\x31\x1f\xeb\x75\x8f\x20\x76\x84\x0f\x5e\x9b\x4a" +
-	"\x7a\x7d\x9f\xa0\x90\xfd\x23\x6d\x67\x64\xe2\xc8\x94\x57\x7e\x5d" +
-	"\xdd\x6c\x16\x15\x55\x25\x66\xd8\x72\x6c\xbc\x0c\xe5\x76\x2b\x23" +
-	"\x93\xa2\x8f\xbd\x7a\xe8\xd3\xd8\x7a\x02\x8e\x05\x9e\x2d\xb7\xd1" +
-	"\x5b\xe4\x2f\x0c\x87\x6b\x32\xab\x1a\xa7\x09\x4d\x42\xd5\xc0\xd7" +
-	"\x25\xab\x8d\xa0\x6e\xbe\xf9\xfb\x34\x6d\x41\x95\x53\x57\x40\x12" +
-	"\x82\xaf\x3e\x7b\x8d\x51\x00\x19\xd7\x41\x81\xb0\xab\x32\xe4\xcf" +
-	"\xf0\x6b\x0b\x0d\xde\x98\x7c\x19\x2b\x74\x5e\xe2\xfe\x1d\x72\xda" +
-	"\x33\xf2\xe9\x15\xac\xfe\x45\xe7\x8c\x93\xb4\xcf\xa0\xb8\xbc\x92" +
-	"\xca\xb5\x63\xbd\x7e\x2c\x37\xca\x6d\x05\x26\x10\x04\xac\xaf\x2b" +
-	"\xc7\x29\x78\xee\x48\x6f\xc2\x43\xc8\xf6\xfe\x2e\x38\xa1\x5e\x05" +
-	"\xfa\x79\xdb\xc2\x2a\xd5\x7c\x2f\x45\xbf\x09\x45\xc2\xcf\xd4\x87" +
-	"\xfd\x40\xf4\xc5\xb9\x04\xd1\xf7\xe0\x3a\xea\x33\xe2\x41\x87\xed" +
-	"\x51\xf4\xa0\x1e\x46\x20\x5c\xa8\xb5\xfe\xf5\x41\xbc\x31\xdd\x80" +
-	"\x0c\x6e\x3f\xf6\x60\x98\x92\x2d\xe2\x60\x58\x97\xbf\x22\x14\xbd" +
-	"\xcf\x6d\xb7\xb4\xd8\x4e\x8d\x1e\xc2\x4a\x50\x0d\x95\xf4\x66\x01" +
-	"\x23\x54\x77\x02\xf6\xe2\x7f\xab\xb4\x9b\xec\xf5\x65\xd1\x44\xb1" +
-	"\xd2\x4f\x46\xf2\xc2\xdb\x66\x7c\x8d\x57\x96\xa7\xf0\x18\xdc\x0f" +
-	"\x7f\xf7\xdf\xba\x67\x5d\xbe\xee\xfa\x54\x3b\x3e\xe4\x2b\xa4\x23" +
-	"\x34\x63\xaf\xe6\x33\xb7\x38\x99\xab\xb4\xe7\x4c\x11\x49\xf1\x38" +
-	"\x77\x97\xd8\x6d\x7c\x0c\x9f\xe7\xcf\x6d\xf6\x69\xb6\x03\x35\x4a" +
-	"\xa6\x0f\x3e\x0a\x1d\x70\x7d\x4f\xb6\x17\x41\x3f\xc2\xef\x3b\x9e" +
-	"\x02\xef\xca\x60\xbd\xf2\xdc\xec\xfe\x2e\x55\xf8\xf6\x1e\x5c\xa3" +
-	"\x6a\xb7\xcc\xee\x8a\x07\xdd\x31\x97\xfb\x40\x5c\xda\xc2\x9b\x87" +
-	"\x31\x74\x34\x94\xdf\x5a\x31\x16\x61\xc4\xaf\x55\x71\xb7\x0a\x21" +
-	"\xca\xde\x78\x07\x1a\xcc\x6c\xb6\xb7\x7d\xb1\x46\xd6\x2a\x47\x35" +
-	"\x7e\xbd\xa2\x16\xd7\x95\xa7\xc8\xf4\x38\xb0\xe2\x91\x3f\x11\x9e" +
-	"\x15\xbd\x03\x41\xbb\xf4\xb2\x27\xf0\x27\xfd\xc9\x6e\xf5\xdb\x82" +
-	"\xf1\xc0\xba\x78\x61\x39\x98\x15\x06\xc5\xa0\x7b\x37\xf5\xd1\xa8" +
-	"\x9e\xa6\xd3\xda\xc9\x6f\x85\x36\x96\x1c\x32\x2a\x49\x34\x4c\xf4" +
-	"\x41\x17\xb4\xfb\xb4\x28\x44\x2e\x9e\xbc\xd4\x83\x9d\xca\xf7\xfe" +
-	"\x6a\xa0\xe6\xe6\xa8\x1e\xae\xd8\xd5\xb7\x96\x84\xd0\xab\xb4\xee" +
-	"\xfe\x07\xfb\xb3\xed\x90\x2d\xfd\xfb\x06\xfc\xdf\x00\x00\x00\xff" +
-	"\xff\x92\x24\xb8\x34\x1e\x07\x00\x00"
-
-// snakeoilCaCrt returns raw, uncompressed file data.
-func snakeoilCaCrt() []byte {
-	var empty [0]byte
-	sx := (*reflect.StringHeader)(unsafe.Pointer(&_snakeoilCaCrt))
-	b := empty[:]
-	bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-	bx.Data = sx.Data
-	bx.Len = len(_snakeoilCaCrt)
-	bx.Cap = bx.Len
-
-	gz, err := gzip.NewReader(bytes.NewBuffer(b))
-
-	if err != nil {
-		panic("Decompression failed: " + err.Error())
-	}
-
-	var buf bytes.Buffer
-	io.Copy(&buf, gz)
-	gz.Close()
-
-	return buf.Bytes()
-}

+ 7 - 2
src/ngrok/client/views/web/http.go

@@ -9,8 +9,8 @@ import (
 	"net/http"
 	"net/http/httputil"
 	"net/url"
+	"ngrok/assets"
 	"ngrok/client/ui"
-	"ngrok/client/views/web/static"
 	"ngrok/log"
 	"ngrok/proto"
 	"ngrok/util"
@@ -240,7 +240,12 @@ func (h *WebHttpView) register() {
 	})
 
 	http.HandleFunc("/http/in", func(w http.ResponseWriter, r *http.Request) {
-		tmpl := template.Must(template.New("page.html").Delims("{%", "%}").Parse(string(static.PageHtml())))
+		pageTmpl, err := assets.ReadAsset("assets/client/page.html")
+		if err != nil {
+			panic(err)
+		}
+
+		tmpl := template.Must(template.New("page.html").Delims("{%", "%}").Parse(string(pageTmpl)))
 
 		payloadData := SerializedPayload{
 			Txns:    h.HttpRequests.Slice(),

+ 0 - 65
src/ngrok/client/views/web/static/debug.go

@@ -1,65 +0,0 @@
-// +build !release
-
-package static
-
-import (
-	"io/ioutil"
-	"os"
-	"path"
-)
-
-var assetDir string
-
-func init() {
-	// find the directory with the assets.
-	// this doesn't work if you:
-	// 1. move the binary
-	// 2. put ngrok in your PATH
-	// but you shouldn't be doing either of these things while developng anyways
-	var binPath string
-	execPath := os.Args[0]
-	if path.IsAbs(execPath) {
-		binPath = execPath
-	} else {
-		wd, err := os.Getwd()
-		if err != nil {
-			panic(err)
-		}
-		binPath = path.Join(wd, execPath)
-	}
-	assetDir = path.Join(path.Dir(path.Dir(binPath)), "assets")
-
-	// call all the functions on startup to make sure the files exist
-	fns := []func() []byte{
-		PageHtml,
-		HighlightJs,
-		HighlightCss,
-		BootstrapCss,
-		JqueryJs,
-		VkBeautifyJs,
-		AngularJs,
-		NgrokJs,
-		Base64Js,
-	}
-	for _, f := range fns {
-		f()
-	}
-}
-
-func ReadFileOrPanic(p string) []byte {
-	bytes, err := ioutil.ReadFile(path.Join(assetDir, p))
-	if err != nil {
-		panic(err)
-	}
-	return bytes
-}
-
-func PageHtml() []byte     { return ReadFileOrPanic("page.html") }
-func HighlightJs() []byte  { return ReadFileOrPanic("highlight.min.js") }
-func HighlightCss() []byte { return ReadFileOrPanic("highlight.min.css") }
-func BootstrapCss() []byte { return ReadFileOrPanic("bootstrap.min.css") }
-func JqueryJs() []byte     { return ReadFileOrPanic("jquery-1.9.1.min.js") }
-func VkBeautifyJs() []byte { return ReadFileOrPanic("vkbeautify.js") }
-func AngularJs() []byte    { return ReadFileOrPanic("angular.js") }
-func NgrokJs() []byte      { return ReadFileOrPanic("ngrok.js") }
-func Base64Js() []byte     { return ReadFileOrPanic("base64.js") }

+ 0 - 12
src/ngrok/client/views/web/static/map.go

@@ -1,12 +0,0 @@
-package static
-
-var AssetMap = map[string]func() []byte{
-	"jquery-1.9.1.min.js": JqueryJs,
-	"bootstrap.min.css":   BootstrapCss,
-	"highlight.min.css":   HighlightCss,
-	"highlight.min.js":    HighlightJs,
-	"vkbeautify.js":       VkBeautifyJs,
-	"angular.js":          AngularJs,
-	"ngrok.js":            NgrokJs,
-	"base64.js":           Base64Js,
-}

+ 6 - 7
src/ngrok/client/views/web/view.go

@@ -5,12 +5,12 @@ import (
 	"fmt"
 	"github.com/garyburd/go-websocket/websocket"
 	"net/http"
+	"ngrok/assets"
 	"ngrok/client/ui"
-	"ngrok/client/views/web/static"
 	"ngrok/log"
 	"ngrok/proto"
 	"ngrok/util"
-	"strings"
+	"path"
 )
 
 type WebView struct {
@@ -52,14 +52,13 @@ func NewWebView(ctl *ui.Controller, state ui.State, port int) *WebView {
 	})
 
 	http.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
-		parts := strings.Split(r.URL.Path, "/")
-		name := parts[len(parts)-1]
-		fn, ok := static.AssetMap[name]
-		if !ok {
+		buf, err := assets.ReadAsset(path.Join("assets", "client", r.URL.Path[1:]))
+		if err != nil {
+			log.Warn("Error serving static file: %s", err.Error())
 			http.NotFound(w, r)
 			return
 		}
-		w.Write(fn())
+		w.Write(buf)
 	})
 
 	log.Info("Serving web interface on localhost:%d", port)

+ 2 - 3
src/ngrok/server/main.go

@@ -7,7 +7,6 @@ import (
 	"ngrok/conn"
 	log "ngrok/log"
 	"ngrok/msg"
-	"ngrok/server/tls"
 	"regexp"
 )
 
@@ -56,7 +55,7 @@ func parseArgs() *Options {
  */
 func controlListener(addr *net.TCPAddr, domain string) {
 	// listen for incoming connections
-	listener, err := conn.Listen(addr, "ctl", tls.Config)
+	listener, err := conn.Listen(addr, "ctl", tlsConfig)
 	if err != nil {
 		panic(err)
 	}
@@ -71,7 +70,7 @@ func controlListener(addr *net.TCPAddr, domain string) {
  * Listens for new proxy connections from tunnel clients
  */
 func proxyListener(addr *net.TCPAddr, domain string) {
-	listener, err := conn.Listen(addr, "pxy", tls.Config)
+	listener, err := conn.Listen(addr, "pxy", tlsConfig)
 	if err != nil {
 		panic(err)
 	}

+ 0 - 0
src/main/ngrokd/server.go → src/ngrok/server/main/ngrokd.go


+ 43 - 0
src/ngrok/server/tls.go

@@ -0,0 +1,43 @@
+package server
+
+import (
+	"crypto/tls"
+	"io/ioutil"
+	"ngrok/assets"
+	"os"
+)
+
+var (
+	tlsConfig *tls.Config
+)
+
+func init() {
+	readOrBytes := func(envVar string, default_path string) []byte {
+		f := os.Getenv(envVar)
+		if f == "" {
+			b, err := assets.ReadAsset(default_path)
+			if err != nil {
+				panic(err)
+			}
+			return b
+		} else {
+			if b, err := ioutil.ReadFile(f); err != nil {
+				panic(err)
+			} else {
+				return b
+			}
+		}
+	}
+
+	crt := readOrBytes("TLS_CRT_FILE", "assets/server/tls/snakeoil.crt")
+	key := readOrBytes("TLS_KEY_FILE", "assets/server/tls/snakeoil.key")
+	cert, err := tls.X509KeyPair(crt, key)
+
+	if err != nil {
+		panic(err)
+	}
+
+	tlsConfig = &tls.Config{
+		Certificates: []tls.Certificate{cert},
+	}
+}

+ 0 - 38
src/ngrok/server/tls/load.go

@@ -1,38 +0,0 @@
-package tls
-
-import (
-	"crypto/tls"
-	"io/ioutil"
-	"os"
-)
-
-var (
-	Config *tls.Config
-)
-
-func init() {
-	readOrBytes := func(envVar string, defaultFile func() []byte) []byte {
-		f := os.Getenv(envVar)
-		if f == "" {
-			return defaultFile()
-		} else {
-			if b, err := ioutil.ReadFile(f); err != nil {
-				panic(err)
-			} else {
-				return b
-			}
-		}
-	}
-
-	crt := readOrBytes("TLS_CRT_FILE", snakeoilCrt)
-	key := readOrBytes("TLS_KEY_FILE", snakeoilKey)
-	cert, err := tls.X509KeyPair(crt, key)
-
-	if err != nil {
-		panic(err)
-	}
-
-	Config = &tls.Config{
-		Certificates: []tls.Certificate{cert},
-	}
-}

+ 0 - 120
src/ngrok/server/tls/snakeoil.crt.go

@@ -1,120 +0,0 @@
-package tls
-
-import (
-	"bytes"
-	"compress/gzip"
-	"io"
-	"reflect"
-	"unsafe"
-)
-
-var _snakeoilCrt = "" +
-	"\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x64\x55\xc7\x0e\xab\xda" +
-	"\x96\x9c\xf3\x15\x3d\x47\x2d\x32\xb6\x87\xc0\x26\xb3\xc9\x06\xc3" +
-	"\x8c\x9c\xb3\x31\x98\xaf\x6f\x9f\x73\xa5\xd6\xd3\x7d\xcc\x56\x2d" +
-	"\xa9\xa8\x5d\xaa\xd2\xfa\xdf\x3f\x1f\x2f\xca\xaa\xf9\x3f\x82\xe8" +
-	"\xfa\xaa\xa4\x0a\x9c\x2f\xfe\x45\x11\xa8\xaa\x12\x00\x82\xc0\x7d" +
-	"\x1c\x81\x73\xc4\x03\x38\x91\xa6\x4f\xb1\x5a\x7f\x32\xf3\x37\x4b" +
-	"\xbc\xc3\x1d\x3e\x10\x0d\xc8\x75\x32\x47\x3c\x45\xbe\x86\x42\x10" +
-	"\xc0\x53\xbc\x38\x97\xaf\xcc\x00\xe1\xb9\xca\x17\x3a\xb3\x4e\xe5" +
-	"\x7e\x48\x29\x6d\x4f\x42\xf1\x14\x5b\xce\xf9\xb3\xe4\xb9\xc9\x17" +
-	"\x42\x66\xcc\x86\xc7\x6a\x0c\xe6\x27\xf5\xc5\x27\xe4\xd5\xbf\x44" +
-	"\xdc\xe9\x18\x7a\xc3\xec\x48\x4c\x69\x9f\xe4\xcb\xb4\x29\x89\x1f" +
-	"\x4a\x9d\x99\xd0\x87\x87\xd9\x72\x17\x04\xce\x17\x5e\xdc\x11\xfe" +
-	"\xc1\xda\xbf\xd8\xf9\xff\x58\xcb\x43\xe8\x6c\x87\xe0\x44\x00\x09" +
-	"\x1c\x47\x16\x0f\x2d\x78\x5e\xa2\x0f\x7f\xcf\xfc\xc3\x2e\xf0\x50" +
-	"\x77\x48\x69\x4b\xc2\xf8\x93\x0d\xcc\x1c\xf9\xa2\x07\x79\xee\x9f" +
-	"\x5d\x0d\xb5\x74\xc8\xbf\x29\xb9\xed\x11\xf9\x78\x23\xd0\x75\x0e" +
-	"\xb1\x8a\xc0\x8f\x08\x48\xdc\xb6\x18\xc3\x7f\x4a\xfe\x79\xd3\xa8" +
-	"\xff\xf6\x85\xff\xf9\x02\xaa\x4a\xb5\xb9\x9f\x77\x08\x57\x4d\xc2" +
-	"\x6f\xe0\x39\x73\xda\x5f\x02\x7b\x68\x49\x66\xab\x52\x24\x36\xba" +
-	"\x2a\xcb\x75\xdf\x78\xf5\xb9\x7d\x89\x3b\x61\x68\x38\x4b\xc7\x3e" +
-	"\xa0\x38\x17\xfa\xcd\xc3\x32\xad\xcd\xed\x94\x97\x8f\x4c\x10\x17" +
-	"\x02\x22\x36\xc1\xd8\xd8\x33\xa5\xa9\x46\x23\x1b\x0c\x29\xd9\x33" +
-	"\x5e\xe7\x5a\x51\x39\xe8\x7c\x5d\x58\x05\xda\x17\x5e\x3f\xa0\x10" +
-	"\x16\x27\xa4\x7f\x32\xe7\x08\xf7\x4b\x71\xe9\x1e\x3d\xa2\x84\xba" +
-	"\xad\x55\xa8\x05\xf4\xfb\x91\x10\xd8\xb1\x3b\x96\x8e\xa2\x03\xf6" +
-	"\x8a\xa8\x23\x4b\xe3\xca\x68\x49\x4a\x54\x32\xf9\x9b\xf6\xd8\x29" +
-	"\x6b\x5d\x52\x24\x8b\x6c\x7e\x56\x6d\xc2\x68\xb7\xf2\x0c\x04\x6b" +
-	"\xfd\x79\xc6\x73\x10\xea\xcf\x41\xe7\x67\x5f\xa1\xed\x1d\xb0\x69" +
-	"\xd7\xdf\x17\xdd\xe1\x6c\xa2\xd8\x7b\x36\xf6\x50\x79\xc5\xfa\x5e" +
-	"\x8a\xb4\x70\x39\xaa\x9c\xf2\x00\x15\xd6\x18\x4b\x44\xf4\x88\xb0" +
-	"\x1b\xd8\xb7\x62\x20\x4d\xa7\x7f\x8f\xbd\x74\x14\x4c\xe0\x11\x46" +
-	"\x39\xcd\xc1\xdb\xa2\x0a\xd2\x64\xca\x4f\x21\x3e\xf3\xb4\x22\x23" +
-	"\xb0\xdd\x8a\x8f\x19\x05\x3a\x4a\x34\x78\xd7\x4e\xbf\xdf\x52\x00" +
-	"\x79\xa7\x43\x5d\x10\x94\xe5\x60\x69\xb2\x97\x67\xa6\x64\xc4\xd9" +
-	"\xbe\xe5\x4d\x63\x6e\xc7\x76\x1f\x0b\xdb\xa0\x8b\x09\xfd\x48\x3b" +
-	"\x60\x9c\x36\x7b\x88\x5e\x79\xed\xa3\x57\x0c\x78\x2d\x30\x9c\x56" +
-	"\x49\xc8\xba\x85\x97\x1a\x6d\xeb\xed\xb9\x35\xbb\x2e\xd3\x95\x93" +
-	"\x03\xe2\x66\xa0\x60\xaa\x02\x61\x71\xb3\x3c\x7a\xed\xd5\x6a\x8b" +
-	"\x9a\x65\x36\xf7\x48\xa6\x0a\xd7\xb5\x31\xe7\xd1\xf5\x2f\xda\x0e" +
-	"\xbf\x37\x0b\x89\xdb\x9b\xfe\xc2\x4e\x7e\xfd\x78\x8c\x5c\x00\x73" +
-	"\x59\x41\xb0\xd9\x06\x1e\x92\xb4\xa4\x61\x98\xb7\x6f\x37\xde\x93" +
-	"\xf0\x32\x63\x80\x17\x2d\x6f\x40\xc7\x55\x49\xc8\x6e\x83\xa3\xa7" +
-	"\x97\x50\xc3\xe3\x97\x03\xed\x08\x2d\x65\x60\x1b\x01\x1f\x94\x23" +
-	"\xcf\xa7\xcb\x36\x72\x54\xb0\x31\x78\xb3\xa3\xcb\x76\x41\x13\x46" +
-	"\x58\x51\x4f\x82\xd4\x2c\x2e\x57\xf5\x91\x85\x0f\xb5\xfe\xd5\x3e" +
-	"\x93\x6f\xb5\x0b\x8b\xf8\x7c\x14\xcd\xd8\xdd\xc8\xd2\xa5\x5c\x9e" +
-	"\x9d\xca\x02\x6f\x8c\xc9\xd2\xcc\x5f\x3a\xf8\x36\x2b\xf4\x2c\x9f" +
-	"\xd6\x89\xbd\x22\xa0\x92\x2c\xf7\x29\xdd\x33\x63\x39\x51\x46\x69" +
-	"\x0a\x26\x67\x05\xdd\x45\xaa\xd1\x24\x98\x4d\x3b\x64\x5d\xfd\x92" +
-	"\xb7\xb2\x62\x0d\xee\x6a\x08\x39\xdc\x85\x2b\x26\x3a\x65\x69\x77" +
-	"\xa7\xa6\xa6\xa0\xdc\x79\x7d\x94\xca\x2d\x37\x9e\xa3\xc4\x55\xbf" +
-	"\x66\x70\xff\x54\x1f\xf9\x57\xf7\xc1\xdf\x58\x83\xa4\xe8\x49\xd4" +
-	"\x73\xef\x86\xc0\x9c\xa6\xc0\x67\x3b\x5d\x2c\x43\xd3\x53\x78\x58" +
-	"\xa7\xb7\x65\x59\x09\x56\x54\x9e\x18\xf4\x9c\x14\x19\x07\x09\x9e" +
-	"\xfc\xe2\x27\x24\x7f\x77\x41\xac\xaa\x5d\x7a\x33\xf6\x4e\xb9\xaf" +
-	"\x1b\x97\x3f\xef\xfc\xd5\x65\xe4\xd7\xcd\xdb\x89\x2b\x45\x08\x33" +
-	"\x8d\xc3\x4a\x38\x1f\x7b\xf2\x52\x99\x6c\x4f\xf4\x00\x69\xf2\x58" +
-	"\x9a\xcd\xe7\xd7\x45\x75\xe6\x29\x63\xc2\xf8\xce\x84\xcf\x71\xc5" +
-	"\x33\x8d\x61\x15\x6a\x04\xfa\x63\xb1\x41\x4c\xf2\xda\xc0\x61\x36" +
-	"\x74\x59\x6b\xae\xdd\xc3\x3d\x64\x74\xdd\x3d\xe3\x29\x34\xc8\xf7" +
-	"\xa8\x24\xa9\x36\x7b\x1b\xce\x76\x4c\x3f\x3e\x9b\x34\x60\x0e\xce" +
-	"\xd1\xda\x60\xcc\xf1\x2b\xe1\xdc\x37\x43\x5d\x66\x6a\x36\x8a\x4f" +
-	"\x48\x95\x6f\x63\x0f\x83\x50\xd4\xb9\x4b\xcb\x49\x72\x7c\xd6\x45" +
-	"\x66\x1e\x0b\xa2\xe2\x6e\xa1\xf2\xb0\x1e\x89\x41\xf5\xa8\x71\x4f" +
-	"\x2c\xfc\xa6\xb9\x10\xdd\x71\x4b\x37\xed\xd3\xaa\xce\xb0\x12\x6f" +
-	"\xcf\xb1\x6a\xc2\xbd\x7f\xcd\xa3\xaa\x70\xaf\xe8\xf4\x03\xe8\xdc" +
-	"\x03\x84\x50\xa3\xfd\xfd\x79\xa4\x91\x86\xa1\x3e\xf7\x7d\xe8\xe7" +
-	"\x95\xd1\x0e\x45\xe9\x28\xb3\xfc\xb2\x75\x97\x05\xae\xb5\x24\x02" +
-	"\x37\x47\xa5\x6b\x7c\xc7\x4e\xeb\x67\xa8\x7a\x53\x4b\x12\x45\xac" +
-	"\x11\x75\x8a\xc4\x34\x9f\x0a\xcc\x85\x45\xf7\x9f\x50\x98\x4c\x38" +
-	"\x27\x48\xb8\x33\xf4\xe3\xab\x7f\xe3\xd1\xda\xb5\x5d\x16\x3b\xfb" +
-	"\x52\xac\xd7\x2c\xb0\x11\x3c\x28\xf2\xf3\xeb\x9e\x2b\x66\x0c\xf3" +
-	"\x7a\x3c\x1d\x88\x0c\x41\x3a\x82\xa4\xa6\xcf\xaf\x0d\xd1\xaf\xa9" +
-	"\x56\xd8\xae\x2b\x81\x1f\x69\x2c\x4a\xfb\xef\x77\x28\xce\x84\x26" +
-	"\xbb\x89\x4d\x8a\x56\xb4\xe2\x5f\xb9\xa0\x5f\x92\xb4\xea\xaa\xad" +
-	"\x90\xa0\xe7\x66\x88\x8c\x66\xb9\xb8\x28\x2c\xcf\x47\x18\x7b\xd4" +
-	"\xc8\x4a\x7b\x68\xcb\xe1\x13\xf0\xdf\x82\x2c\xf3\xd3\x6a\xc3\x87" +
-	"\x76\x64\x18\xaa\x01\x97\xe2\x37\x8f\x65\x8c\xfe\xb2\xd7\x8d\x15" +
-	"\xee\x7e\x66\x8e\x23\x40\xc4\x3c\xd4\xe8\xae\x8f\xae\xb0\xdb\xbd" +
-	"\xfc\xd9\x04\x84\xf8\x4a\x37\x9e\xd8\x3c\x55\x1f\x9e\x7b\x4e\x96" +
-	"\xf4\x47\xdb\xad\xa5\xe7\xb7\xca\xbb\x63\x83\x7f\xb6\x1d\x41\x52" +
-	"\xfb\x2b\x31\x1f\x57\x62\xb2\x08\xf7\xc8\x60\xe8\xa8\x24\x4c\xa7" +
-	"\x54\xc7\x15\x71\xed\x3a\xdc\xf9\x9a\xfe\x3b\xf0\xf5\x7d\x10\xc5" +
-	"\x6e\xc2\x32\xb2\x7b\x6f\xe3\xbd\x5f\x73\x2d\xd3\x17\xa1\x70\x1e" +
-	"\xa2\x7e\xcc\xec\x8a\x1b\xc3\x7b\x46\xfe\x1e\x38\xd1\x04\xff\x7d" +
-	"\xf4\xfe\x2f\x00\x00\xff\xff\x82\xb7\xc1\xb2\x11\x07\x00\x00"
-
-// snakeoilCrt returns raw, uncompressed file data.
-func snakeoilCrt() []byte {
-	var empty [0]byte
-	sx := (*reflect.StringHeader)(unsafe.Pointer(&_snakeoilCrt))
-	b := empty[:]
-	bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-	bx.Data = sx.Data
-	bx.Len = len(_snakeoilCrt)
-	bx.Cap = bx.Len
-
-	gz, err := gzip.NewReader(bytes.NewBuffer(b))
-
-	if err != nil {
-		panic("Decompression failed: " + err.Error())
-	}
-
-	var buf bytes.Buffer
-	io.Copy(&buf, gz)
-	gz.Close()
-
-	return buf.Bytes()
-}

+ 0 - 190
src/ngrok/server/tls/snakeoil.key.go

@@ -1,190 +0,0 @@
-package tls
-
-import (
-	"bytes"
-	"compress/gzip"
-	"io"
-	"reflect"
-	"unsafe"
-)
-
-var _snakeoilKey = "" +
-	"\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x6c\x97\xb7\xb2\x84\x48" +
-	"\x94\x6d\x7d\xbe\xa2\x7d\xe2\x05\x5a\x19\xcf\x40\x6b\xad\xf1\x0a" +
-	"\x5d\x68\x4d\xc1\xd7\xcf\xed\x8e\x31\x27\xdd\xb4\x72\xe5\x8e\x73" +
-	"\xd6\xfe\x7f\xff\x1e\x4e\x94\x55\xeb\x1f\xcf\x67\xff\x71\x3c\x35" +
-	"\x62\x03\xf1\x1f\x5d\x4c\xff\xbb\x01\x4c\x55\xd5\x74\x56\xe5\x58" +
-	"\x56\xe7\xd9\x46\x64\xd1\x2f\x51\x18\x1b\x3b\x2c\x37\xdd\x44\x8d" +
-	"\xaf\xce\x4d\xfa\x91\x63\x4d\x57\xe4\xd7\x48\xde\x70\x9f\x82\xad" +
-	"\x1d\x4c\xa7\xe0\xc4\x9f\x6d\xc0\x38\x0c\x90\x3f\xd9\x2d\x4b\xbb" +
-	"\x79\x5d\x2d\x89\x7a\xd8\xae\x54\x70\x2a\xfa\xe6\x54\xd3\x6b\x4a" +
-	"\x43\x70\xf2\x25\x78\x20\x39\x81\x9c\x1c\x07\x64\x6d\xab\xf6\x15" +
-	"\xf8\xd6\x32\x4a\x7c\xbf\xcf\x7c\x0e\x9d\x07\x58\xb4\xbf\x06\x68" +
-	"\x58\xa6\x33\x3d\x0a\x38\x6e\x6e\x2f\xb7\x25\x10\x4f\xb0\xf8\x46" +
-	"\x91\x39\x53\x76\x35\xf7\x3b\x46\xf6\x74\xf2\xc2\x2d\xef\x5c\x3b" +
-	"\x13\x48\x4c\x47\x6f\x21\xd6\x39\x45\xc1\x7d\x04\x3a\xa8\x95\x39" +
-	"\xf5\x02\x2d\x7b\x9c\x3c\xd8\x4a\x17\x3f\x9d\xe5\xc1\xac\x1b\x10" +
-	"\x77\x96\xd3\x4f\x9e\x79\x61\x59\x28\x22\xc9\x64\x19\x0c\xfc\x73" +
-	"\x81\x71\x18\x35\xc3\x67\xe3\x39\xac\x54\x9d\xf2\x03\x28\xd0\x16" +
-	"\x75\xdf\x7a\xbd\x6d\xf2\x47\xe6\x29\xc2\xc7\x68\x15\x26\x1c\x35" +
-	"\x44\x46\x78\x80\xdf\x21\x86\xa9\x92\x4a\xb1\x01\x64\x70\xcf\x43" +
-	"\x4e\x21\x6b\xec\xf7\x20\x69\xa4\x0d\x37\x2a\x36\x7c\x1f\xb0\x3b" +
-	"\x0f\x76\x0a\x1b\x39\x3f\x12\x95\x14\x84\xc0\x1c\x2b\x01\x49\x77" +
-	"\xf9\x26\xb2\x0d\x7f\xee\x69\xba\xf8\xf7\x29\x71\xfa\x6a\xc9\x8e" +
-	"\xa4\x63\xdc\x19\x78\xeb\x85\x3d\x0d\xb2\xc9\x52\x23\x73\x1f\x10" +
-	"\x8d\x9e\x1d\xd9\xf8\xfc\xe5\x66\xfb\x7d\xae\xc3\x7f\x74\x7c\xce" +
-	"\xbf\x1c\x07\x3b\xc9\x7e\xe1\xf6\x97\x0b\xf5\x45\xfa\x21\x6d\x45" +
-	"\xf2\x3b\xed\xf6\x38\x6a\xfc\x9a\xbc\x24\x24\x11\x62\x04\xd4\x8f" +
-	"\x80\xba\x61\x72\x63\x27\x46\x67\x5f\x6a\x48\x94\x4f\xc6\xe8\x33" +
-	"\xdc\x44\xd7\xdd\x8a\x6f\xfa\xf2\xf2\xbc\x09\x27\x88\xd1\xc9\x77" +
-	"\x97\xd4\xc4\x63\xde\xde\xd2\xbe\x2b\xec\xb4\x23\x07\x85\x99\x6c" +
-	"\x04\x00\x25\x69\x5b\x95\xc3\x3c\x3b\x71\x29\x5e\xe5\xab\x6a\xf8" +
-	"\x69\xcd\x21\x68\x67\xd2\x07\x86\xab\x10\xfd\xee\x4c\x67\x32\xa2" +
-	"\xad\x65\x1d\x43\xca\x8d\x1a\xeb\x8b\xc8\xf3\x51\x43\xf9\x1f\x71" +
-	"\x53\x47\x00\x6c\x4d\xd2\xde\x16\x53\x6a\xbf\x13\x74\x1f\xbf\x73" +
-	"\x01\x17\xdf\xed\x66\x4b\x2f\xa7\x8c\x46\x90\x62\x76\x74\x7d\xff" +
-	"\xa9\x84\xd3\x6c\x31\x29\x84\x77\xb9\x6e\x4f\x7b\x12\xf7\xb9\x29" +
-	"\x54\x5f\x69\x00\x35\x60\xb3\xba\xc8\x7c\x81\x25\xe3\x3d\xb1\xe9" +
-	"\xdc\x19\xf9\x01\x0a\xf3\x2e\xd8\x46\x98\x7d\x70\xc3\x9a\x62\xb7" +
-	"\x5a\x6d\x82\x57\xaa\x36\x02\x71\x71\x2d\x22\xf0\x07\x1f\x7e\x11" +
-	"\xf2\xec\x2d\xb2\x00\xeb\xfe\x1b\x61\x2e\x27\xbd\x93\x36\xe0\xe6" +
-	"\x08\xb9\x09\x53\x67\xc5\xac\xb1\xd8\xd1\x21\x9e\xae\x8c\x36\x58" +
-	"\xdf\x2d\x55\x63\x2c\x96\xd2\xbb\xc5\x51\x73\x8f\x47\x8c\xad\x6c" +
-	"\x94\xb4\x7c\xdf\x05\x6c\xd9\xe3\x93\xdd\xfe\xc3\xac\xe5\x60\x77" +
-	"\xc3\x47\x66\x1a\x21\xb2\x59\x7c\xc0\x8d\xcf\xcc\xa9\xdd\x97\x23" +
-	"\x3b\x18\x2f\x52\x94\x2b\x40\x03\x86\xea\x98\x47\x31\xd2\x16\xcc" +
-	"\x0d\xdb\x35\xc9\x83\x81\x55\xed\x55\x49\x29\x82\xb2\x5e\xa4\x53" +
-	"\x5c\x71\x1f\xf9\x09\x38\x24\x1f\x61\x16\x46\xc3\x45\x75\xb0\xa1" +
-	"\xcb\x74\x0e\xa7\x10\xa3\x74\xac\x37\x51\x6b\x7e\x43\xba\xd6\x56" +
-	"\x4a\xc5\xb7\x72\xde\x8a\x00\xde\xf4\x07\xc1\x75\xd4\x19\xd2\x54" +
-	"\x4b\x75\x0a\x7b\x2f\x3d\x09\x95\xc3\x0d\x57\x7d\x0a\xc3\x39\xd4" +
-	"\x9c\xbe\x59\x1a\x10\xa1\x23\x5f\x7a\x07\x17\x9c\x5c\xa9\x5d\xa9" +
-	"\x4e\xda\x77\x90\x72\x3d\x62\x80\x7f\x2b\x6c\xd0\xb5\x40\x98\xf4" +
-	"\xdc\xe0\x98\xae\x17\x7a\x5a\xe5\x11\xb5\xc9\x3b\x03\xae\x4d\x35" +
-	"\x81\x6f\x5c\x7e\x61\xc5\xd3\x6a\x1c\x0e\x88\xef\x2c\x9f\xff\xfe" +
-	"\x14\x24\x85\x13\x3f\x3e\x25\x09\xdc\xa4\x6b\xae\x22\xa4\x59\xd5" +
-	"\x1e\xd4\xd2\xfa\x5b\xbd\x37\xe3\xee\x40\x43\xc0\x5f\x9f\xf4\xbe" +
-	"\x34\x4a\x6d\xc6\x98\x45\xfd\x1b\xc5\x63\x7e\x3f\x27\x6c\x28\x64" +
-	"\x70\xf4\xf2\xa8\x5c\xf5\x38\x91\x10\xa0\xd2\xea\x38\xa8\xde\xa3" +
-	"\xc8\x76\x18\x29\xbb\xc8\x7a\x74\x41\x7d\x04\xa6\xfc\x34\xb0\x91" +
-	"\x27\x63\xf7\xcc\x43\xfd\x9d\x68\x61\xbe\x11\x0c\x86\x64\xac\x0d" +
-	"\x92\x74\x12\xc4\xe0\x47\x92\x3d\xe2\x05\x00\xd7\x92\xbd\x20\xa6" +
-	"\xd7\xf9\xbb\xa4\xb5\x4f\x52\xdd\x63\x4f\xe2\x44\x90\xcb\x65\x99" +
-	"\xb3\x4c\x57\x0b\xff\x82\xed\xe1\xa2\xb6\x9d\xda\xa2\x6e\x25\xb4" +
-	"\xfe\x7b\x08\x12\xdd\x92\xa6\xa4\x09\xf3\x09\x80\x2a\x30\x70\x61" +
-	"\x6c\x21\x52\xa3\xa2\x23\x96\xf1\xc9\x42\x65\x7a\x99\x3a\xc2\x68" +
-	"\x18\xc6\xa5\xeb\x57\x94\xdc\x51\x32\xa4\x42\x87\x7b\xed\x56\x4e" +
-	"\x18\x5f\xb4\xcf\xba\x29\x06\x78\x2a\x4a\x49\x04\x80\x6e\xd7\x0e" +
-	"\xbb\xc1\x4b\x98\x57\x27\xba\x47\x25\x53\xb4\x8d\xd0\xb2\x42\x28" +
-	"\x22\x10\x9d\x3a\xad\xcf\xef\xca\x59\x9a\xb8\x35\xe3\x87\xc0\x67" +
-	"\x91\xb8\xea\x1a\xb2\xc8\x06\xbf\x84\x37\xa6\x20\x17\xd0\xc2\x1f" +
-	"\x16\xe2\x08\x1a\x5d\x50\x5e\x96\x16\x79\x56\x27\xbd\x96\xf4\x2b" +
-	"\xcc\xd3\x03\x9d\x2a\x21\xcb\xdc\xa7\x19\x53\x3e\x54\x9e\x7b\xb5" +
-	"\x7e\xee\x7f\xc9\x75\x45\x16\x52\x60\x93\xd7\xd2\x08\x88\x3c\xcf" +
-	"\x38\xeb\xac\x7f\xb1\x7a\xe1\xc1\x3b\x00\x8b\x79\xcd\x9b\xf3\xde" +
-	"\x02\x34\x5f\x22\xee\xb4\xca\xeb\x11\xf4\x54\xed\xf3\xc2\x17\x0e" +
-	"\x35\xb2\x76\x1b\x42\x16\x04\xe2\xe5\x79\x1b\x85\x61\x00\x7a\xa4" +
-	"\xb3\xa4\xd6\x03\x87\x95\xe3\x68\xd7\xad\x73\x24\xab\x0e\x67\x6e" +
-	"\x7f\xaf\x63\x4d\x85\xf3\xd5\x9e\x25\x67\xc2\xef\x75\x52\xb2\x8c" +
-	"\x98\x56\xa8\x68\x61\x55\x48\x07\x7d\xaa\x41\x91\x32\xd8\x0e\x84" +
-	"\x8d\xc7\x45\x3b\xbf\x18\x4d\xe8\x50\xbe\x44\x8e\x88\xb9\x9c\x28" +
-	"\xf7\x49\x5c\x68\x17\x4d\xba\x4c\x79\x7f\x3c\x70\xe9\xf3\xa3\x8c" +
-	"\x18\x86\x0b\x75\x31\x86\x2a\x1b\xf9\x64\x2e\xa0\x6e\x0f\x42\x13" +
-	"\xf8\xfe\xd2\xc0\x24\x36\x22\x8c\x13\xae\x1d\x10\x86\x34\xea\x13" +
-	"\x8c\xbb\x60\x9c\x7f\x72\x23\x55\xc1\x2d\xd1\x3f\xe4\x3e\x67\x6a" +
-	"\x74\x2f\xa7\xde\xbe\xcb\x15\x26\x50\xde\xc9\x1e\x3e\x13\x9a\x6b" +
-	"\xdf\x00\xa2\xc2\x89\x8e\x60\xcf\xd6\x4a\xbd\xc8\xaa\x11\x89\x4c" +
-	"\x0a\x27\x7f\x9f\x76\xd4\xfc\xd6\xf9\xf8\x2a\x7a\x0a\x67\xf9\x83" +
-	"\xb3\xbe\x3e\x43\xd5\x44\x42\xe9\x5a\xab\x35\xde\x3b\x36\xf8\x18" +
-	"\xa3\x1d\x03\x09\x35\x88\xf0\x6a\x35\x14\x31\xec\xde\xff\x12\xc6" +
-	"\x82\x62\x6d\xae\xef\xbe\x33\x1f\xdc\xbe\x37\x98\xfb\x34\x43\x65" +
-	"\xe7\xe1\x14\x98\xd2\xdb\xd3\x79\xb3\x54\xa3\x55\xbe\x5f\x9c\xaa" +
-	"\x64\x80\xe2\x09\x0a\x8d\x7f\xb4\xbc\x93\x49\x63\xe5\x36\x4a\x0f" +
-	"\x8b\x08\x3b\x02\xa5\x87\x90\x77\x1d\x18\x79\x3b\xcc\xf8\xca\x5f" +
-	"\x07\x36\xb1\x6c\xc3\x5b\x1a\x61\x6b\xe3\xaa\x8f\xd9\x34\x77\xf2" +
-	"\x39\x7a\xe0\x56\x34\xbb\x3c\x9c\x90\xcf\xd6\x6b\xca\x87\x4b\xb7" +
-	"\x55\x1c\x66\x26\x79\x9a\x43\x01\xc4\xa6\x5a\x81\xd6\x55\xe9\xf1" +
-	"\xcc\xc0\xea\x09\xbf\x94\xfc\x77\x9b\x73\x99\xd5\x76\xe2\x6d\x0a" +
-	"\xda\x6a\x1b\x20\x46\x2b\x3b\x4d\xd5\xef\xcb\xf8\xb0\x96\x6b\xda" +
-	"\xaf\x2c\xfc\x81\x33\x55\xe2\x72\x4d\xfd\x2f\x70\x1d\x81\xf2\xe8" +
-	"\x58\x17\x12\x98\x78\xe6\x29\xd1\x74\x7e\xd7\xda\xdf\x0a\xca\xb1" +
-	"\xa7\x7d\x2e\xfa\x0b\x2c\x89\xa2\x64\x19\xe3\xea\xe2\xdf\x83\x28" +
-	"\x32\xb4\x41\x51\xd6\x5f\xba\x99\xb0\x3b\xd6\xcf\x96\x50\x92\x05" +
-	"\x53\xe6\x47\xff\x96\xcd\x9b\x1c\x8e\x9a\x9f\x74\x5d\xe2\xe1\x9b" +
-	"\x0c\x10\xf7\x87\xa4\x00\xba\x98\x95\xe1\xb4\xd8\x47\xa2\x0c\xe6" +
-	"\xdc\x85\xd3\x19\x4e\xaa\xee\x24\x94\x9d\x70\xf9\x43\x3d\x52\xca" +
-	"\x66\xa5\x5d\x81\x9a\xff\x00\x73\x1c\x1f\xf0\x4c\x98\x58\x9d\xcd" +
-	"\xdc\xd9\x92\xe6\x33\x20\x94\x33\xdb\xfb\x13\x2b\x1a\x7f\x34\xe6" +
-	"\x11\xfd\x35\x3e\x58\xc1\x38\xae\x20\x5e\x7f\x91\x27\x95\xd9\xa8" +
-	"\x8a\x14\x5a\xa0\x54\x54\xad\xf3\x6d\xd9\xa7\xd6\x6b\xc4\xe8\x30" +
-	"\x12\xb0\x2b\x80\x48\x0d\xd4\x1e\x5e\x6b\x8c\x8c\xf0\xf7\xe0\x8a" +
-	"\x8b\x42\xbe\x9b\xbb\x52\x5c\x3e\xdd\x79\x8b\xab\x76\xb2\x99\xe5" +
-	"\xbc\xca\xf9\xdc\x1d\xab\x34\x74\xd9\xce\xac\x82\xd5\xcc\xf5\x4f" +
-	"\x0f\x59\x4e\xfd\x86\x98\x0e\x2c\xa5\xb8\xa4\x8b\x25\xf8\x9e\x9d" +
-	"\x3d\xa1\x51\xe6\xf4\xc0\x1c\xe7\x49\x68\x5e\x75\x17\x67\xdb\xb8" +
-	"\x4d\x35\xa0\x7d\x8f\x6e\xf6\x6b\xd2\xdc\x02\x9e\x0b\xa5\x9f\x29" +
-	"\x37\x4e\x8f\xab\xf1\x55\x38\x03\x15\x4c\x3c\xd0\x5e\xd3\xc8\x7e" +
-	"\x81\x8d\xbc\x2d\xdc\x6b\x1c\xf7\x57\x7c\xdf\x9f\x84\x16\x90\xb4" +
-	"\x4e\x93\x7c\xff\xa4\x0b\xcb\x30\x6e\xeb\xa3\x91\xa8\xf2\x66\xae" +
-	"\x32\x68\x80\xd9\xa4\x7f\xcd\x81\x07\xb0\x3b\x99\x9d\x5c\xd2\xf6" +
-	"\x9f\x94\x7d\x64\x8d\x7a\x1d\x14\x2d\x39\x41\x6e\x2c\x7c\x8e\xcc" +
-	"\x89\xbf\xf7\x05\x63\xf5\xd0\xa2\x4f\xba\xa4\xc7\x2e\x1c\x84\xf2" +
-	"\xcb\x64\x0a\x11\xf0\x64\x22\xbd\x5c\x00\x10\x2f\x2b\xb1\xf3\x9f" +
-	"\xa5\x49\x7c\x37\x24\x63\x01\x9b\x75\x04\x33\xe4\x97\x4b\xd3\x27" +
-	"\x81\x3f\x56\xb0\x40\x93\x8b\x3f\x86\x57\x4c\x94\x5a\x8f\x7b\x9b" +
-	"\x0a\xad\x0c\x5e\xf3\x54\xf7\xba\x64\x1e\x33\x80\xd0\x08\xd3\x28" +
-	"\x9f\x8f\xfc\x8b\xcd\x43\x0a\xa5\x1a\x8c\x6d\x33\x25\x53\x9d\xe1" +
-	"\x6e\x2a\x4e\x65\x5f\x57\xb4\x38\x31\xd6\x91\xb3\x10\x3e\x6c\x29" +
-	"\x25\x5a\xe1\xcb\x3c\x9e\x84\xbc\x8e\x08\x72\x5d\x20\x0c\x1b\x6a" +
-	"\x9c\xaf\xbf\x81\xcf\x9d\xa7\xb2\xd0\xd3\x22\x0a\x6e\x1b\x84\x76" +
-	"\x68\xc9\xb0\x6d\x81\x38\x9f\xa7\x19\x56\xea\x79\x7c\xb0\x59\x54" +
-	"\x29\xd6\xa7\x90\x71\xda\x47\xd6\x5b\xcc\x1c\x03\x39\x81\xf0\x1b" +
-	"\x06\xfb\x11\x58\x2b\x93\xfa\x4d\xaf\x82\xa9\xd4\xdc\x15\xcf\xca" +
-	"\xb2\x53\xcc\xa7\xc7\x21\x12\x5f\xae\xc2\xeb\x28\x7d\x71\x45\x50" +
-	"\x42\x57\x75\xe6\x86\x6a\xb0\xfb\xb2\x09\xde\x53\x12\xc3\x80\xdc" +
-	"\xd1\x15\x46\x67\x85\x76\xc5\x2a\x8c\x8f\xce\x2c\xc0\x0e\x13\x7f" +
-	"\x8c\x16\xf2\x71\x7c\x01\x3d\x71\xe8\x42\xe6\x90\xb5\x21\x79\x57" +
-	"\x03\x1d\xad\x71\x28\x9e\x3a\x7a\x84\x77\x6b\xc1\x86\xd5\x1c\xe0" +
-	"\x4d\x57\xf2\x64\x93\xe2\xb5\xee\x1a\x0a\x25\xa8\x23\x67\x5e\xa3" +
-	"\xd1\x4f\x84\xbe\x70\x74\x8b\x7c\xd3\x88\x1c\xab\x35\x1f\x54\xcf" +
-	"\x91\xf9\xb2\x0c\xd3\xa5\xa3\x73\x44\x0e\x91\xe6\xec\xfe\x64\x04" +
-	"\xa0\x0d\xa2\xe5\x05\x77\xe9\x6c\xb2\x33\x25\x84\x77\x60\x76\x47" +
-	"\x0e\xb0\x30\x91\xbb\x2c\xa3\x17\x59\x94\x17\xc3\x71\x75\x34\x75" +
-	"\x88\xa7\x00\xab\x96\x9f\x1a\xac\x72\x8e\x24\x82\x77\x27\xf4\x88" +
-	"\x18\x40\xa8\xee\x9b\x9b\xa8\x96\x4a\xbd\xc7\x78\x1a\xcf\xb3\x74" +
-	"\x01\x82\xa8\x7d\xff\xb2\x20\xd2\xfe\x46\x79\xd8\x2b\x32\x55\x2c" +
-	"\x03\xe1\x1a\xf9\x6b\x6b\x6c\x2c\x53\xf4\x9f\x29\x7f\xad\x35\x13" +
-	"\x1f\x1e\x06\xbc\x3d\xd5\x9d\x4f\x49\x56\x70\x35\xa5\x87\x73\xa5" +
-	"\xc3\xc4\xa7\x1b\x45\xa5\xb8\x6e\x91\x63\x48\xd8\x07\x66\xbf\xab" +
-	"\x5c\x39\x38\x08\x96\xa1\xf9\x4e\x06\x8a\x5c\x39\x7a\x8f\x7f\x66" +
-	"\xab\x18\x7f\x86\x62\xde\x1f\xf2\xa6\x6a\x35\x49\x2d\xd6\x3e\xf9" +
-	"\x1e\x96\xcd\x2a\x7d\x7d\x25\x0b\xa8\x2c\x7d\x8e\x30\x6c\xbf\xdf" +
-	"\x20\xca\x95\xec\xfc\xbc\x9a\x47\x6a\x8f\x47\x3d\x35\x56\x4e\x5d" +
-	"\xef\xd4\x5e\xa4\x54\xc0\x6a\xec\xfa\xdf\xbe\xc9\x9f\xf8\xf3\xe7" +
-	"\xd5\x24\x52\x5b\x59\x5c\x5b\xb8\xd4\x18\xe6\x18\x0a\x2f\x6f\x59" +
-	"\xc2\xcb\xec\x52\x02\x33\xda\x88\xb8\x1f\x71\x06\x85\x73\xa2\x84" +
-	"\x9b\xf6\xf7\xff\x0f\xfc\x57\x39\x44\x4b\xf8\xbf\xab\xc8\xff\x04" +
-	"\x00\x00\xff\xff\x14\x22\x96\x1d\xab\x0c\x00\x00"
-
-// snakeoilKey returns raw, uncompressed file data.
-func snakeoilKey() []byte {
-	var empty [0]byte
-	sx := (*reflect.StringHeader)(unsafe.Pointer(&_snakeoilKey))
-	b := empty[:]
-	bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-	bx.Data = sx.Data
-	bx.Len = len(_snakeoilKey)
-	bx.Cap = bx.Len
-
-	gz, err := gzip.NewReader(bytes.NewBuffer(b))
-
-	if err != nil {
-		panic("Decompression failed: " + err.Error())
-	}
-
-	var buf bytes.Buffer
-	io.Copy(&buf, gz)
-	gz.Close()
-
-	return buf.Bytes()
-}