├── public ├── style.css ├── favicon.ico ├── tracking.gif ├── images │ ├── .DS_Store │ ├── raptor.png │ ├── raptor@2x.png │ ├── asm-logotype.png │ ├── deal-with-it.png │ ├── jumbotron-bg.png │ ├── asm-logotype@2x.png │ ├── deal-with-it@2x.png │ ├── feature-digests.png │ ├── feature-receipts.png │ ├── feature-digests@2x.png │ ├── feature-receipts@2x.png │ ├── feature-notifications.png │ └── feature-notifications@2x.png └── js │ └── smooth-scroll.js ├── Godeps ├── _workspace │ ├── .gitignore │ └── src │ │ ├── github.com │ │ ├── boj │ │ │ └── redistore │ │ │ │ ├── .gitignore │ │ │ │ ├── doc.go │ │ │ │ ├── LICENSE │ │ │ │ └── README.md │ │ ├── go-martini │ │ │ └── martini │ │ │ │ ├── wercker.yml │ │ │ │ ├── Godeps │ │ │ │ ├── go_version.go │ │ │ │ ├── .gitignore │ │ │ │ ├── env_test.go │ │ │ │ ├── env.go │ │ │ │ ├── logger_test.go │ │ │ │ ├── logger.go │ │ │ │ ├── LICENSE │ │ │ │ ├── return_handler.go │ │ │ │ └── recovery_test.go │ │ ├── lib │ │ │ └── pq │ │ │ │ ├── .gitignore │ │ │ │ ├── oid │ │ │ │ ├── doc.go │ │ │ │ └── gen.go │ │ │ │ ├── certs │ │ │ │ ├── README │ │ │ │ ├── postgresql.key │ │ │ │ ├── root.crt │ │ │ │ └── server.key │ │ │ │ ├── user_posix.go │ │ │ │ ├── user_windows.go │ │ │ │ ├── LICENSE.md │ │ │ │ ├── conn_xact_test.go │ │ │ │ ├── CONTRIBUTING.md │ │ │ │ ├── url_test.go │ │ │ │ ├── buf.go │ │ │ │ └── url.go │ │ ├── codegangsta │ │ │ └── inject │ │ │ │ ├── .gitignore │ │ │ │ ├── update_readme.sh │ │ │ │ └── LICENSE │ │ ├── martini-contrib │ │ │ ├── cors │ │ │ │ ├── wercker.yml │ │ │ │ └── README.md │ │ │ ├── render │ │ │ │ ├── wercker.yml │ │ │ │ ├── fixtures │ │ │ │ │ ├── basic │ │ │ │ │ │ ├── hypertext.html │ │ │ │ │ │ ├── content.tmpl │ │ │ │ │ │ ├── delims.tmpl │ │ │ │ │ │ ├── hello.tmpl │ │ │ │ │ │ ├── admin │ │ │ │ │ │ │ └── index.tmpl │ │ │ │ │ │ ├── layout.tmpl │ │ │ │ │ │ ├── another_layout.tmpl │ │ │ │ │ │ └── current_layout.tmpl │ │ │ │ │ └── custom_funcs │ │ │ │ │ │ └── index.tmpl │ │ │ │ └── LICENSE │ │ │ ├── secure │ │ │ │ ├── wercker.yml │ │ │ │ └── LICENSE │ │ │ ├── sessionauth │ │ │ │ ├── wercker.yml │ │ │ │ ├── example │ │ │ │ │ ├── templates │ │ │ │ │ │ ├── index.tmpl │ │ │ │ │ │ ├── private.tmpl │ │ │ │ │ │ └── login.tmpl │ │ │ │ │ └── user.go │ │ │ │ └── LICENSE │ │ │ └── sessions │ │ │ │ ├── wercker.yml │ │ │ │ ├── README.md │ │ │ │ ├── LICENSE │ │ │ │ ├── cookie_store.go │ │ │ │ ├── redis_store.go │ │ │ │ └── benchmarks_test.go │ │ ├── technoweenie │ │ │ └── grohl │ │ │ │ ├── script │ │ │ │ ├── test │ │ │ │ └── fmt │ │ │ │ ├── context_test.go │ │ │ │ ├── LICENSE │ │ │ │ ├── statter_test.go │ │ │ │ ├── loggers.go │ │ │ │ ├── timer.go │ │ │ │ ├── context.go │ │ │ │ └── loggers_test.go │ │ ├── jrallison │ │ │ └── go-workers │ │ │ │ ├── job.go │ │ │ │ ├── workers_logger.go │ │ │ │ ├── .travis.yml │ │ │ │ ├── signals_windows.go │ │ │ │ ├── signals_posix.go │ │ │ │ ├── workers_test.go │ │ │ │ ├── middleware_logging.go │ │ │ │ ├── middleware_stats.go │ │ │ │ ├── msg_test.go │ │ │ │ ├── LICENSE.txt │ │ │ │ ├── middleware.go │ │ │ │ ├── all_specs_test.go │ │ │ │ ├── scheduled_test.go │ │ │ │ ├── worker.go │ │ │ │ ├── scheduled.go │ │ │ │ ├── msg.go │ │ │ │ ├── workers.go │ │ │ │ ├── stats.go │ │ │ │ ├── config.go │ │ │ │ ├── enqueue.go │ │ │ │ └── config_test.go │ │ ├── gorilla │ │ │ ├── websocket │ │ │ │ ├── .travis.yml │ │ │ │ ├── AUTHORS │ │ │ │ ├── .gitignore │ │ │ │ ├── examples │ │ │ │ │ ├── autobahn │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ └── fuzzingclient.json │ │ │ │ │ ├── filewatch │ │ │ │ │ │ └── README.md │ │ │ │ │ └── chat │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ ├── main.go │ │ │ │ │ │ └── hub.go │ │ │ │ ├── bench_test.go │ │ │ │ ├── util_test.go │ │ │ │ ├── server_test.go │ │ │ │ ├── util.go │ │ │ │ ├── LICENSE │ │ │ │ ├── json.go │ │ │ │ └── json_test.go │ │ │ ├── context │ │ │ │ ├── .travis.yml │ │ │ │ ├── README.md │ │ │ │ └── LICENSE │ │ │ ├── securecookie │ │ │ │ ├── .travis.yml │ │ │ │ ├── README.md │ │ │ │ └── LICENSE │ │ │ └── sessions │ │ │ │ ├── .travis.yml │ │ │ │ ├── README.md │ │ │ │ └── LICENSE │ │ ├── cupcake │ │ │ └── gokiq │ │ │ │ ├── .gitignore │ │ │ │ ├── .travis.yml │ │ │ │ ├── example_worker │ │ │ │ └── example_worker.go │ │ │ │ ├── example_client │ │ │ │ └── example_client.go │ │ │ │ └── LICENSE │ │ ├── coopernurse │ │ │ └── gorp │ │ │ │ ├── .gitignore │ │ │ │ ├── Makefile │ │ │ │ ├── .travis.yml │ │ │ │ ├── test_all.sh │ │ │ │ ├── errors.go │ │ │ │ └── LICENSE │ │ ├── bitly │ │ │ └── go-simplejson │ │ │ │ ├── .travis.yml │ │ │ │ ├── README.md │ │ │ │ └── LICENSE │ │ ├── kylelemons │ │ │ └── go-gypsy │ │ │ │ └── yaml │ │ │ │ └── Makefile │ │ ├── oxtoacart │ │ │ └── bpool │ │ │ │ ├── bpool.go │ │ │ │ ├── bufferpool.go │ │ │ │ ├── README.md │ │ │ │ └── bytepool.go │ │ ├── ziutek │ │ │ └── mymysql │ │ │ │ ├── mysql │ │ │ │ └── field.go │ │ │ │ ├── godrv │ │ │ │ └── appengine.go │ │ │ │ └── native │ │ │ │ ├── addons.go │ │ │ │ ├── common.go │ │ │ │ └── LICENSE │ │ ├── mattn │ │ │ └── go-sqlite3 │ │ │ │ ├── .travis.yml │ │ │ │ ├── sqlite3_other.go │ │ │ │ ├── sqlite3_windows.go │ │ │ │ ├── LICENSE │ │ │ │ ├── README.md │ │ │ │ └── backup.go │ │ ├── bradrydzewski │ │ │ └── go.stripe │ │ │ │ ├── .gitignore │ │ │ │ ├── LICENSE.txt │ │ │ │ ├── card_test.go │ │ │ │ └── token.go │ │ ├── sirsean │ │ │ └── go-mailgun │ │ │ │ └── mailgun │ │ │ │ ├── mime_message_test.go │ │ │ │ ├── mailgun.go │ │ │ │ └── mime_message.go │ │ └── garyburd │ │ │ └── redigo │ │ │ ├── redis │ │ │ ├── test_test.go │ │ │ └── redis.go │ │ │ └── internal │ │ │ ├── commandinfo.go │ │ │ └── redistest │ │ │ └── testdb.go │ │ └── bitbucket.org │ │ └── liamstask │ │ └── goose │ │ ├── cmd │ │ └── goose │ │ │ ├── cmd.go │ │ │ ├── cmd_dbversion.go │ │ │ ├── cmd_up.go │ │ │ ├── cmd_down.go │ │ │ ├── cmd_redo.go │ │ │ ├── cmd_create.go │ │ │ ├── main.go │ │ │ └── cmd_status.go │ │ └── lib │ │ └── goose │ │ ├── util.go │ │ ├── migrate_test.go │ │ └── dbconf_test.go └── Readme ├── Procfile ├── fig.yml ├── .gitignore ├── install_goose.go ├── db ├── dbconf.yml └── migrations │ ├── 20140226140220_AddStripeColsToAccounts.sql │ ├── 20150331105004_add_updated_at_to_articles.sql │ ├── 20140731133501_add_last_read_at_to_read_receipts.sql │ ├── 20140716150530_add_indexes.sql │ ├── 20140218125529_CreateAccounts.sql │ ├── 20150502160242_add_read_receipt_cols_to_expected_readers.sql │ ├── 20150503154705_add_read_counts_to_articles.sql │ ├── 20140219164920_CreateArticles.sql │ ├── 20140219165544_CreateReaders.sql │ ├── 20140225165143_AddConfirmationColsToAccounts.sql │ ├── 20140219165725_CreateReadReceipts.sql │ └── 20140221111211_CreateExpectedReaders.sql ├── .env.sample ├── assets └── stylesheets │ ├── partials │ ├── _all.scss │ ├── _reset.scss │ ├── _variables.scss │ └── _mixins.scss │ ├── modules │ ├── _grid.scss │ ├── _layout.scss │ ├── _all.scss │ ├── _buttons.scss │ ├── _base.scss │ ├── _call-to-action.scss │ ├── _animation.scss │ ├── _features.scss │ ├── _code.scss │ └── _jumbotron.scss │ └── style.scss ├── Makefile ├── .travis.yml ├── rrweb.go ├── templates ├── new_account_email.tmpl ├── layout.tmpl ├── setup.tmpl └── welcome.txt.tmpl ├── lib ├── req_logger.go ├── new_account_email_job_test.go ├── reader_handlers.go ├── timestamp.go ├── user_callback_job_test.go ├── read_receipt_handlers_test.go ├── read_receipt_test.go ├── reader.go ├── database.go ├── new_account_email_job.go └── hub.go ├── rrworker └── rrworker.go ├── config.rb ├── fake └── responsewriter.go └── LICENSE /public/style.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Godeps/_workspace/.gitignore: -------------------------------------------------------------------------------- 1 | /pkg 2 | /bin 3 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: readraptor 2 | worker: rrworker -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/boj/redistore/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | -------------------------------------------------------------------------------- /fig.yml: -------------------------------------------------------------------------------- 1 | redis: 2 | image: redis:2.8 3 | ports: 4 | - "6380:6379" 5 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/go-martini/martini/wercker.yml: -------------------------------------------------------------------------------- 1 | box: wercker/golang@1.1.1 -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/.gitignore: -------------------------------------------------------------------------------- 1 | .db 2 | *.test 3 | *~ 4 | *.swp 5 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/codegangsta/inject/.gitignore: -------------------------------------------------------------------------------- 1 | inject 2 | inject.test 3 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/cors/wercker.yml: -------------------------------------------------------------------------------- 1 | box: wercker/golang@1.1.1 -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/render/wercker.yml: -------------------------------------------------------------------------------- 1 | box: wercker/golang@1.1.1 -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/secure/wercker.yml: -------------------------------------------------------------------------------- 1 | box: wercker/golang@1.1.1 -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/sessionauth/wercker.yml: -------------------------------------------------------------------------------- 1 | box: wercker/golang@1.1.1 -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/sessions/wercker.yml: -------------------------------------------------------------------------------- 1 | box: wercker/golang@1.1.1 -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/tracking.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/tracking.gif -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/go-martini/martini/Godeps: -------------------------------------------------------------------------------- 1 | github.com/codegangsta/inject master 2 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/render/fixtures/basic/hypertext.html: -------------------------------------------------------------------------------- 1 | Hypertext! 2 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/technoweenie/grohl/script/test: -------------------------------------------------------------------------------- 1 | script/fmt 2 | go test -race -v . 3 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/render/fixtures/basic/content.tmpl: -------------------------------------------------------------------------------- 1 |

{{ . }}

2 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/render/fixtures/basic/delims.tmpl: -------------------------------------------------------------------------------- 1 |

Hello {[{.}]}

-------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/render/fixtures/basic/hello.tmpl: -------------------------------------------------------------------------------- 1 |

Hello {{.}}

2 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/technoweenie/grohl/script/fmt: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gofmt -w -l *.go 4 | -------------------------------------------------------------------------------- /public/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/.DS_Store -------------------------------------------------------------------------------- /public/images/raptor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/raptor.png -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/render/fixtures/basic/admin/index.tmpl: -------------------------------------------------------------------------------- 1 |

Admin {{.}}

2 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/render/fixtures/custom_funcs/index.tmpl: -------------------------------------------------------------------------------- 1 | {{ myCustomFunc }} 2 | -------------------------------------------------------------------------------- /public/images/raptor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/raptor@2x.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | readraptor 2 | 3 | gin-bin 4 | .sass-cache 5 | .env* 6 | .anvil 7 | db/latest.dump 8 | Procfile.dev 9 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/render/fixtures/basic/layout.tmpl: -------------------------------------------------------------------------------- 1 | head 2 | {{ yield }} 3 | foot 4 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/job.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | type jobFunc func(message *Msg) 4 | -------------------------------------------------------------------------------- /install_goose.go: -------------------------------------------------------------------------------- 1 | // +build heroku 2 | 3 | package main 4 | 5 | import _ "bitbucket.org/liamstask/goose/cmd/goose" 6 | -------------------------------------------------------------------------------- /public/images/asm-logotype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/asm-logotype.png -------------------------------------------------------------------------------- /public/images/deal-with-it.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/deal-with-it.png -------------------------------------------------------------------------------- /public/images/jumbotron-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/jumbotron-bg.png -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.1 5 | - 1.2 6 | - tip 7 | -------------------------------------------------------------------------------- /public/images/asm-logotype@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/asm-logotype@2x.png -------------------------------------------------------------------------------- /public/images/deal-with-it@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/deal-with-it@2x.png -------------------------------------------------------------------------------- /public/images/feature-digests.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/feature-digests.png -------------------------------------------------------------------------------- /public/images/feature-receipts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/feature-receipts.png -------------------------------------------------------------------------------- /public/images/feature-digests@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/feature-digests@2x.png -------------------------------------------------------------------------------- /public/images/feature-receipts@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/feature-receipts@2x.png -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/cupcake/gokiq/.gitignore: -------------------------------------------------------------------------------- 1 | *.test 2 | example_client/example_client 3 | example_worker/example_worker 4 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/context/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.0 5 | - 1.1 6 | - 1.2 7 | - tip 8 | -------------------------------------------------------------------------------- /public/images/feature-notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/feature-notifications.png -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/securecookie/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.0 5 | - 1.1 6 | - 1.2 7 | - tip 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/sessions/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.0 5 | - 1.1 6 | - 1.2 7 | - tip 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/render/fixtures/basic/another_layout.tmpl: -------------------------------------------------------------------------------- 1 | another head 2 | {{ yield }} 3 | another foot 4 | -------------------------------------------------------------------------------- /public/images/feature-notifications@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asm-products/readraptor/HEAD/public/images/feature-notifications@2x.png -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coopernurse/gorp/.gitignore: -------------------------------------------------------------------------------- 1 | _test 2 | _testmain.go 3 | _obj 4 | *~ 5 | *.6 6 | 6.out 7 | gorptest.bin 8 | tmp 9 | -------------------------------------------------------------------------------- /db/dbconf.yml: -------------------------------------------------------------------------------- 1 | development: 2 | driver: postgres 3 | open: $DATABASE_URL 4 | 5 | production: 6 | driver: postgres 7 | open: $DATABASE_URL -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/render/fixtures/basic/current_layout.tmpl: -------------------------------------------------------------------------------- 1 | {{ current }} head 2 | {{ yield }} 3 | {{ current }} foot 4 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/boj/redistore/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package redistore is a session store backend for gorilla/sessions 3 | */ 4 | package redistore 5 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/codegangsta/inject/update_readme.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | go get github.com/robertkrimen/godocdown/godocdown 3 | godocdown > README.md 4 | -------------------------------------------------------------------------------- /Godeps/Readme: -------------------------------------------------------------------------------- 1 | This directory tree is generated automatically by godep. 2 | 3 | Please do not edit. 4 | 5 | See https://github.com/tools/godep for more information. 6 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/cupcake/gokiq/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.1 4 | - tip 5 | services: 6 | - redis 7 | before_install: 8 | - go get launchpad.net/gocheck 9 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/workers_logger.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | type WorkersLogger interface { 4 | Println(...interface{}) 5 | Printf(string, ...interface{}) 6 | } 7 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coopernurse/gorp/Makefile: -------------------------------------------------------------------------------- 1 | include $(GOROOT)/src/Make.inc 2 | 3 | TARG = github.com/coopernurse/gorp 4 | GOFILES = gorp.go dialect.go 5 | 6 | include $(GOROOT)/src/Make.pkg -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/go-martini/martini/go_version.go: -------------------------------------------------------------------------------- 1 | // +build !go1.1 2 | 3 | package martini 4 | 5 | func MartiniDoesNotSupportGo1Point0() { 6 | "Martini requires Go 1.1 or greater." 7 | } 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/oid/doc.go: -------------------------------------------------------------------------------- 1 | // Package oid contains OID constants 2 | // as defined by the Postgres server. 3 | package oid 4 | 5 | // Oid is a Postgres Object ID. 6 | type Oid uint32 7 | -------------------------------------------------------------------------------- /db/migrations/20140226140220_AddStripeColsToAccounts.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | ALTER TABLE accounts 3 | ADD COLUMN customer_id text; 4 | 5 | -- +goose Down 6 | ALTER TABLE accounts 7 | DROP COLUMN customer_id; 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/securecookie/README.md: -------------------------------------------------------------------------------- 1 | securecookie 2 | ============ 3 | [![Build Status](https://travis-ci.org/gorilla/securecookie.png?branch=master)](https://travis-ci.org/gorilla/securecookie) 4 | -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | API_GEN_SECRET=sekret_change_me 2 | COOKIE_SECRET=change_me_too 3 | DATABASE_URL=postgres://localhost/rr_development?sslmode=disable 4 | REDIS_URL=redis://localhost:6379/ 5 | STRIPE_PUBLISHABLE= 6 | STRIPE_SECRET= 7 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/certs/README: -------------------------------------------------------------------------------- 1 | This directory contains certificates and private keys for testing some 2 | SSL-related functionality in Travis. Do NOT use these certificates for 3 | anything other than testing. 4 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/bitly/go-simplejson/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.0.3 4 | - 1.1.2 5 | - 1.2 6 | - tip 7 | install: 8 | - go get github.com/bmizerany/assert 9 | notifications: 10 | email: false 11 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.1 5 | - tip 6 | 7 | script: 8 | - go get github.com/customerio/gospec 9 | - go test -v 10 | 11 | services: 12 | - redis-server 13 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/kylelemons/go-gypsy/yaml/Makefile: -------------------------------------------------------------------------------- 1 | include $(GOROOT)/src/Make.inc 2 | 3 | TARG=github.com/kylelemons/go-gypsy/yaml 4 | GOFILES=\ 5 | types.go\ 6 | parser.go\ 7 | config.go\ 8 | 9 | include $(GOROOT)/src/Make.pkg 10 | -------------------------------------------------------------------------------- /assets/stylesheets/partials/_all.scss: -------------------------------------------------------------------------------- 1 | /*-----------------------------------*\ 2 | 3 | Partials: All 4 | 5 | Includes all partials 6 | 7 | \*-----------------------------------*/ 8 | 9 | @import "mixins"; 10 | @import "reset"; 11 | @import "typography"; -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: restore 2 | 3 | restore: 4 | heroku pgbackups:capture --expire --app readraptor 5 | curl `heroku pgbackups:url --app readraptor` -o db/latest.dump 6 | pg_restore --verbose --clean --no-acl --no-owner -h localhost -d rr_development db/latest.dump 7 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the official list of Gorilla WebSocket authors for copyright 2 | # purposes. 3 | # 4 | # Please keep the list sorted. 5 | 6 | Gary Burd 7 | Joachim Bauch 8 | 9 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/sessionauth/example/templates/index.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

This is the Martini-Sessionauth example

5 | Try to visit this private link
6 | 7 | 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/sessionauth/example/templates/private.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

This is a private link!

5 |

Hello {{ .Username }}

6 | Logout
7 | 8 | 9 | -------------------------------------------------------------------------------- /db/migrations/20150331105004_add_updated_at_to_articles.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | ALTER TABLE articles 3 | ADD COLUMN updated_at timestamp; 4 | 5 | update articles set updated_at=created_at; 6 | 7 | -- +goose Down 8 | ALTER TABLE articles 9 | DROP COLUMN updated_at; 10 | -------------------------------------------------------------------------------- /db/migrations/20140731133501_add_last_read_at_to_read_receipts.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | ALTER TABLE read_receipts 3 | ADD COLUMN last_read_at timestamp; 4 | 5 | update read_receipts set last_read_at=created_at; 6 | 7 | -- +goose Down 8 | ALTER TABLE read_receipts 9 | DROP COLUMN last_read_at; 10 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/oxtoacart/bpool/bpool.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package bpool implements leaky pools of byte arrays and Buffers as bounded 3 | channels. It is based on the leaky buffer example from the Effective Go 4 | documentation: http://golang.org/doc/effective_go.html#leaky_buffer 5 | */ 6 | package bpool 7 | -------------------------------------------------------------------------------- /db/migrations/20140716150530_add_indexes.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | CREATE INDEX expected_readers_reader_id ON expected_readers (reader_id); 3 | CREATE INDEX read_receipts_reader_id ON read_receipts (reader_id); 4 | 5 | -- +goose Down 6 | DROP INDEX expected_readers_reader_id; 7 | DROP INDEX read_receipts_reader_id; 8 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/mysql/field.go: -------------------------------------------------------------------------------- 1 | package mysql 2 | 3 | type Field struct { 4 | Catalog string 5 | Db string 6 | Table string 7 | OrgTable string 8 | Name string 9 | OrgName string 10 | DispLen uint32 11 | // Charset uint16 12 | Flags uint16 13 | Type byte 14 | Scale byte 15 | } 16 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/mattn/go-sqlite3/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - tip 4 | before_install: 5 | - go get github.com/axw/gocov/gocov 6 | - go get github.com/mattn/goveralls 7 | - go get code.google.com/p/go.tools/cmd/cover 8 | script: 9 | - $HOME/gopath/bin/goveralls -repotoken 3qJVUE0iQwqnCbmNcDsjYu1nh4J4KIFXx 10 | -------------------------------------------------------------------------------- /assets/stylesheets/modules/_grid.scss: -------------------------------------------------------------------------------- 1 | // --------------------------------------------------------------------------- 2 | // Basic Grid 3 | 4 | $break : 47.5em 12; 5 | $total-columns : 12; 6 | $column-width : 54px; 7 | $gutter-width : 30px; 8 | $grid-padding : $gutter-width * 1.5; 9 | 10 | $show-grid-backgrounds : false; 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.3 5 | - release 6 | - tip 7 | 8 | addons: 9 | postgresql: "9.3" 10 | 11 | services: 12 | - redis-server 13 | 14 | before_install: 15 | - go get github.com/kr/godep 16 | 17 | before_script: 18 | - psql -c 'create database rr_test;' -U postgres 19 | 20 | script: 21 | - godep go test ./... -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/context/README.md: -------------------------------------------------------------------------------- 1 | context 2 | ======= 3 | [![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context) 4 | 5 | gorilla/context is a general purpose registry for global request variables. 6 | 7 | Read the full documentation here: http://www.gorillatoolkit.org/pkg/context 8 | -------------------------------------------------------------------------------- /db/migrations/20140218125529_CreateAccounts.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | CREATE TABLE accounts ( 3 | id SERIAL PRIMARY KEY, 4 | created_at timestamp NOT NULL, 5 | email text NOT NULL UNIQUE, 6 | public_key text NOT NULL UNIQUE, 7 | private_key text NOT NULL UNIQUE 8 | ); 9 | 10 | -- +goose Down 11 | DROP TABLE accounts; 12 | -------------------------------------------------------------------------------- /rrweb.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | 7 | rr "github.com/asm-products/readraptor/lib" 8 | "github.com/coopernurse/gorp" 9 | ) 10 | 11 | var dbmap *gorp.DbMap 12 | 13 | func main() { 14 | dir, err := filepath.Abs(filepath.Dir(os.Args[0])) 15 | if err != nil { 16 | panic(err) 17 | } 18 | 19 | rr.RunWeb(dir) 20 | } 21 | -------------------------------------------------------------------------------- /templates/new_account_email.tmpl: -------------------------------------------------------------------------------- 1 | Thanks for signing up to Read Raptor! 2 | 3 | You're almost ready to start tracking read receipts and sending smart notifications to your users. 4 | 5 | Follow this link to complete the signup process: https://readraptor.com/confirm/{{.ConfirmationToken}} 6 | 7 | If you need any help, just reply to this email. 8 | 9 | The Read Raptor Team -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/godrv/appengine.go: -------------------------------------------------------------------------------- 1 | // +build appengine 2 | 3 | package godrv 4 | 5 | import ( 6 | "net" 7 | "time" 8 | 9 | "appengine/cloudsql" 10 | ) 11 | 12 | func init() { 13 | SetDialer(func(proto, laddr, raddr, user, dbname string, timeout time.Duration) (net.Conn, error) { 14 | return cloudsql.Dial(raddr) 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/native/addons.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | func NbinToNstr(nbin *[]byte) *string { 4 | if nbin == nil { 5 | return nil 6 | } 7 | str := string(*nbin) 8 | return &str 9 | } 10 | 11 | func NstrToNbin(nstr *string) *[]byte { 12 | if nstr == nil { 13 | return nil 14 | } 15 | bin := []byte(*nstr) 16 | return &bin 17 | } 18 | -------------------------------------------------------------------------------- /db/migrations/20150502160242_add_read_receipt_cols_to_expected_readers.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | ALTER TABLE read_receipts 3 | ADD COLUMN first_read_at timestamp; 4 | ALTER TABLE read_receipts 5 | ADD COLUMN read_count integer default(0); 6 | 7 | -- +goose Down 8 | ALTER TABLE read_receipts 9 | DROP COLUMN first_read_at; 10 | ALTER TABLE read_receipts 11 | DROP COLUMN read_count; 12 | -------------------------------------------------------------------------------- /db/migrations/20150503154705_add_read_counts_to_articles.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | ALTER TABLE articles 3 | ADD COLUMN total_read_count integer default(0); 4 | ALTER TABLE articles 5 | ADD COLUMN unique_read_count integer default(0); 6 | 7 | -- +goose Down 8 | ALTER TABLE read_receipts 9 | DROP COLUMN total_read_count; 10 | ALTER TABLE read_receipts 11 | DROP COLUMN unique_read_count; 12 | -------------------------------------------------------------------------------- /assets/stylesheets/modules/_layout.scss: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------*/ 2 | /* Layout */ 3 | 4 | .container { 5 | @include susy-grid-background; 6 | @include container($total-columns, $break); 7 | } 8 | 9 | section { 10 | padding-top: $base * 4; 11 | padding-bottom: $base * 4; 12 | 13 | border-bottom: 1px solid $lightest-gray; 14 | } 15 | -------------------------------------------------------------------------------- /db/migrations/20140219164920_CreateArticles.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | CREATE TABLE articles ( 3 | id SERIAL PRIMARY KEY, 4 | account_id int NOT NULL, 5 | created_at timestamp NOT NULL, 6 | key text NOT NULL UNIQUE, 7 | 8 | CONSTRAINT fk_articles_account FOREIGN KEY (account_id) REFERENCES accounts (id) 9 | ); 10 | 11 | -- +goose Down 12 | DROP TABLE articles; 13 | -------------------------------------------------------------------------------- /db/migrations/20140219165544_CreateReaders.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | CREATE TABLE readers ( 3 | id SERIAL PRIMARY KEY, 4 | account_id int NOT NULL, 5 | created_at timestamp NOT NULL, 6 | distinct_id text NOT NULL UNIQUE, 7 | 8 | CONSTRAINT fk_readers_account FOREIGN KEY (account_id) REFERENCES accounts (id) 9 | ); 10 | 11 | -- +goose Down 12 | DROP TABLE readers; 13 | -------------------------------------------------------------------------------- /db/migrations/20140225165143_AddConfirmationColsToAccounts.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | ALTER TABLE accounts 3 | ADD COLUMN confirmation_token text, 4 | ADD COLUMN confirmation_sent_at timestamp, 5 | ADD COLUMN confirmed_at timestamp; 6 | 7 | -- +goose Down 8 | ALTER TABLE accounts 9 | DROP COLUMN confirmation_token, 10 | DROP COLUMN confirmation_sent_at, 11 | DROP COLUMN confirmed_at; 12 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/user_posix.go: -------------------------------------------------------------------------------- 1 | // Package pq is a pure Go Postgres driver for the database/sql package. 2 | 3 | // +build darwin freebsd linux nacl netbsd openbsd solaris 4 | 5 | package pq 6 | 7 | import "os/user" 8 | 9 | func userCurrent() (string, error) { 10 | u, err := user.Current() 11 | if err != nil { 12 | return "", err 13 | } 14 | return u.Username, nil 15 | } 16 | -------------------------------------------------------------------------------- /assets/stylesheets/modules/_all.scss: -------------------------------------------------------------------------------- 1 | /*-----------------------------------*\ 2 | 3 | Module: All 4 | 5 | Includes all Modules 6 | 7 | \*-----------------------------------*/ 8 | 9 | @import "grid"; 10 | @import "layout"; 11 | @import "animation"; 12 | @import "buttons"; 13 | @import "jumbotron"; 14 | @import "call-to-action"; 15 | @import "features"; 16 | @import "code"; 17 | @import "billing"; 18 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/sessionauth/example/templates/login.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

You must login!

5 |
6 |
7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /assets/stylesheets/modules/_buttons.scss: -------------------------------------------------------------------------------- 1 | .btn { 2 | display: inline-block; 3 | 4 | padding: .5em 1em; 5 | 6 | font-weight: 600; 7 | text-decoration: none; 8 | 9 | border: 2px solid $white; 10 | border-radius: $radius + 1px; 11 | 12 | &:hover { 13 | color: shade($addendum, 15%); 14 | 15 | background-color: $white; 16 | } 17 | } 18 | 19 | .btn ~ .btn { 20 | margin-left: $base; 21 | } 22 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/bradrydzewski/go.stripe/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *~ 24 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/signals_windows.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "os" 5 | "os/signal" 6 | "syscall" 7 | ) 8 | 9 | func handleSignals() { 10 | signals := make(chan os.Signal, 1) 11 | signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) 12 | 13 | for sig := range signals { 14 | switch sig { 15 | case syscall.SIGINT, syscall.SIGTERM: 16 | Quit() 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /assets/stylesheets/partials/_reset.scss: -------------------------------------------------------------------------------- 1 | /*-----------------------------------*\ 2 | 3 | Partial: Reset 4 | 5 | \*-----------------------------------*/ 6 | 7 | // Sloppy reset. Applied to everything. 8 | *, :before, :after { 9 | margin: 0; 10 | padding: 0; 11 | // Layout for dummies 12 | box-sizing: border-box; 13 | position: relative; 14 | } 15 | 16 | // Blanket ban on oversized images. 17 | img { 18 | max-width: 100%; 19 | } -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/bitly/go-simplejson/README.md: -------------------------------------------------------------------------------- 1 | ### go-simplejson 2 | 3 | a Go package to interact with arbitrary JSON 4 | 5 | [![Build Status](https://secure.travis-ci.org/bitly/go-simplejson.png)](http://travis-ci.org/bitly/go-simplejson) 6 | 7 | ### Importing 8 | 9 | import github.com/bitly/go-simplejson 10 | 11 | ### Documentation 12 | 13 | Visit the docs on [gopkgdoc](http://godoc.org/github.com/bitly/go-simplejson) 14 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_other.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | // +build !windows 6 | 7 | package sqlite3 8 | 9 | /* 10 | #cgo CFLAGS: -I. 11 | #cgo linux LDFLAGS: -ldl 12 | #cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE 13 | */ 14 | import "C" 15 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/go-martini/martini/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | 25 | /.godeps 26 | /.envrc 27 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md: -------------------------------------------------------------------------------- 1 | # Test Server 2 | 3 | This package contains a server for the [Autobahn WebSockets Test Suite](http://autobahn.ws/testsuite). 4 | 5 | To test the server, run 6 | 7 | go run server.go 8 | 9 | and start the client test driver 10 | 11 | wstest -m fuzzingclient -s fuzzingclient.json 12 | 13 | When the client completes, it writes a report to reports/clients/index.html. 14 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md: -------------------------------------------------------------------------------- 1 | # File Watch example. 2 | 3 | This example sends a file to the browser client for display whenever the file is modified. 4 | 5 | $ go get github.com/gorilla/websocket 6 | $ cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/filewatch` 7 | $ go run main.go 8 | # Open http://localhost:8080/ . 9 | # Modify the file to see it update in the browser. 10 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/signals_posix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package workers 4 | 5 | import ( 6 | "os" 7 | "os/signal" 8 | "syscall" 9 | ) 10 | 11 | func handleSignals() { 12 | signals := make(chan os.Signal, 1) 13 | signal.Notify(signals, syscall.SIGUSR1, syscall.SIGINT, syscall.SIGTERM) 14 | 15 | for sig := range signals { 16 | switch sig { 17 | case syscall.SIGINT, syscall.SIGUSR1, syscall.SIGTERM: 18 | Quit() 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/native/common.go: -------------------------------------------------------------------------------- 1 | package native 2 | 3 | import ( 4 | "io" 5 | "runtime" 6 | ) 7 | 8 | var tab8s = " " 9 | 10 | func catchError(err *error) { 11 | if pv := recover(); pv != nil { 12 | switch e := pv.(type) { 13 | case runtime.Error: 14 | panic(pv) 15 | case error: 16 | if e == io.EOF { 17 | *err = io.ErrUnexpectedEOF 18 | } else { 19 | *err = e 20 | } 21 | default: 22 | panic(pv) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/mattn/go-sqlite3/sqlite3_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package sqlite3 7 | 8 | /* 9 | #cgo CFLAGS: -I. -fno-stack-check -fno-stack-protector -mno-stack-arg-probe 10 | #cgo windows,386 CFLAGS: -D_localtime32=localtime 11 | #cgo LDFLAGS: -lmingwex -lmingw32 12 | #cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE 13 | */ 14 | import "C" 15 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Gorilla WebSocket Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package websocket 6 | 7 | import ( 8 | "testing" 9 | ) 10 | 11 | func BenchmarkMaskBytes(b *testing.B) { 12 | var key [4]byte 13 | data := make([]byte, 1024) 14 | pos := 0 15 | for i := 0; i < b.N; i++ { 16 | pos = maskBytes(key, pos, data) 17 | } 18 | b.SetBytes(int64(len(data))) 19 | } 20 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/cupcake/gokiq/example_worker/example_worker.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/cupcake/gokiq" 7 | ) 8 | 9 | type ExampleWorker struct { 10 | Data []int 11 | } 12 | 13 | func (w *ExampleWorker) Perform() error { 14 | doSomething(w.Data[0]) 15 | time.Sleep(100 * time.Millisecond) 16 | return nil 17 | } 18 | 19 | func doSomething(i int) { 20 | } 21 | 22 | func main() { 23 | gokiq.Workers.Register(&ExampleWorker{}) 24 | gokiq.Workers.WorkerCount = 200 25 | gokiq.Workers.Run() 26 | } 27 | -------------------------------------------------------------------------------- /db/migrations/20140219165725_CreateReadReceipts.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | CREATE TABLE read_receipts ( 3 | id SERIAL PRIMARY KEY, 4 | article_id int NOT NULL, 5 | reader_id int NOT NULL, 6 | created_at timestamp NOT NULL, 7 | 8 | CONSTRAINT fk_read_receipts_articles FOREIGN KEY (article_id) REFERENCES articles (id), 9 | CONSTRAINT fk_read_receipts_readers FOREIGN KEY (reader_id) REFERENCES readers (id), 10 | CONSTRAINT uq_article_reader UNIQUE(article_id, reader_id) 11 | ); 12 | 13 | -- +goose Down 14 | DROP TABLE read_receipts; 15 | -------------------------------------------------------------------------------- /public/js/smooth-scroll.js: -------------------------------------------------------------------------------- 1 | jQuery.easing.def = "easeInOutQuart"; 2 | 3 | $(function() { 4 | $('a[href*=#]:not([href=#])').click(function() { 5 | if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) { 6 | var target = $(this.hash); 7 | target = target.length ? target : $('[name=' + this.hash.slice(1) +']'); 8 | if (target.length) { 9 | $('html,body').animate({ 10 | scrollTop: target.offset().top 11 | }, 800); 12 | return false; 13 | } 14 | } 15 | }); 16 | }); -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/go-martini/martini/env_test.go: -------------------------------------------------------------------------------- 1 | package martini 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func Test_SetENV(t *testing.T) { 8 | tests := []struct { 9 | in string 10 | out string 11 | }{ 12 | {"", "development"}, 13 | {"not_development", "not_development"}, 14 | } 15 | 16 | for _, test := range tests { 17 | setENV(test.in) 18 | if Env != test.out { 19 | expect(t, Env, test.out) 20 | } 21 | } 22 | } 23 | 24 | func Test_Root(t *testing.T) { 25 | if len(Root) == 0 { 26 | t.Errorf("Expected root path will be set") 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/workers_test.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "github.com/customerio/gospec" 5 | ) 6 | 7 | var called chan bool 8 | 9 | func myJob(message *Msg) { 10 | called <- true 11 | } 12 | 13 | func WorkersSpec(c gospec.Context) { 14 | c.Specify("Workers", func() { 15 | c.Specify("allows running in tests", func() { 16 | called = make(chan bool) 17 | 18 | Process("myqueue", myJob, 10) 19 | 20 | Start() 21 | 22 | Enqueue("myqueue", "Add", []int{1, 2}) 23 | <-called 24 | 25 | Quit() 26 | }) 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /db/migrations/20140221111211_CreateExpectedReaders.sql: -------------------------------------------------------------------------------- 1 | -- +goose Up 2 | CREATE TABLE expected_readers ( 3 | id SERIAL PRIMARY KEY, 4 | article_id int NOT NULL, 5 | reader_id int NOT NULL, 6 | created_at timestamp NOT NULL, 7 | 8 | CONSTRAINT fk_expected_readers_articles FOREIGN KEY (article_id) REFERENCES articles (id), 9 | CONSTRAINT fk_expected_readers_readers FOREIGN KEY (reader_id) REFERENCES readers (id), 10 | CONSTRAINT uq_expected_readers_article_reader UNIQUE(article_id, reader_id) 11 | ); 12 | 13 | -- +goose Down 14 | DROP TABLE expected_readers; 15 | -------------------------------------------------------------------------------- /lib/req_logger.go: -------------------------------------------------------------------------------- 1 | package readraptor 2 | 3 | import ( 4 | "github.com/go-martini/martini" 5 | "github.com/technoweenie/grohl" 6 | "log" 7 | "net/http" 8 | "time" 9 | ) 10 | 11 | func ReqLogger() martini.Handler { 12 | return func(res http.ResponseWriter, req *http.Request, c martini.Context, log *log.Logger) { 13 | start := time.Now().UTC() 14 | rw := res.(martini.ResponseWriter) 15 | c.Next() 16 | 17 | grohl.Log(grohl.Data{ 18 | "method": req.Method, 19 | "path": req.URL.Path, 20 | "status": rw.Status(), 21 | "duration": time.Since(start).Seconds(), 22 | }) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | ) 6 | 7 | // shamelessly snagged from the go tool 8 | // each command gets its own set of args, 9 | // defines its own entry point, and provides its own help 10 | type Command struct { 11 | Run func(cmd *Command, args ...string) 12 | Flag flag.FlagSet 13 | 14 | Name string 15 | Usage string 16 | 17 | Summary string 18 | Help string 19 | } 20 | 21 | func (c *Command) Exec(args []string) { 22 | c.Flag.Usage = func() { 23 | // helpFunc(c, c.Name) 24 | } 25 | c.Flag.Parse(args) 26 | c.Run(c, c.Flag.Args()...) 27 | } 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/go-martini/martini/env.go: -------------------------------------------------------------------------------- 1 | package martini 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | // Envs 8 | const ( 9 | Dev string = "development" 10 | Prod string = "production" 11 | Test string = "test" 12 | ) 13 | 14 | // Env is the environment that Martini is executing in. The MARTINI_ENV is read on initialization to set this variable. 15 | var Env = Dev 16 | var Root string 17 | 18 | func setENV(e string) { 19 | if len(e) > 0 { 20 | Env = e 21 | } 22 | } 23 | 24 | func init() { 25 | setENV(os.Getenv("MARTINI_ENV")) 26 | var err error 27 | Root, err = os.Getwd() 28 | if err != nil { 29 | panic(err) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coopernurse/gorp/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.1 4 | - tip 5 | 6 | services: 7 | - mysql 8 | - postgres 9 | - sqlite3 10 | 11 | before_script: 12 | - mysql -e "CREATE DATABASE gorptest;" 13 | - mysql -u root -e "GRANT ALL ON gorptest.* TO gorptest@localhost IDENTIFIED BY 'gorptest'" 14 | - psql -c "CREATE DATABASE gorptest;" -U postgres 15 | - psql -c "CREATE USER "gorptest" WITH SUPERUSER PASSWORD 'gorptest';" -U postgres 16 | - go get github.com/lib/pq 17 | - go get github.com/mattn/go-sqlite3 18 | - go get github.com/ziutek/mymysql/godrv 19 | - go get github.com/go-sql-driver/mysql 20 | 21 | script: ./test_all.sh 22 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "options": {"failByDrop": false}, 4 | "outdir": "./reports/clients", 5 | "servers": [ 6 | {"agent": "ReadAllWriteMessage", "url": "ws://localhost:9000/m", "options": {"version": 18}}, 7 | {"agent": "ReadAllWrite", "url": "ws://localhost:9000/r", "options": {"version": 18}}, 8 | {"agent": "CopyFull", "url": "ws://localhost:9000/f", "options": {"version": 18}}, 9 | {"agent": "CopyWriterOnly", "url": "ws://localhost:9000/c", "options": {"version": 18}} 10 | ], 11 | "cases": ["*"], 12 | "exclude-cases": [], 13 | "exclude-agent-cases": {} 14 | } 15 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coopernurse/gorp/test_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # on macs, you may need to: 4 | # export GOBUILDFLAG=-ldflags -linkmode=external 5 | 6 | set -e 7 | 8 | export GORP_TEST_DSN=gorptest/gorptest/gorptest 9 | export GORP_TEST_DIALECT=mysql 10 | go test $GOBUILDFLAG . 11 | 12 | export GORP_TEST_DSN=gorptest:gorptest@/gorptest 13 | export GORP_TEST_DIALECT=gomysql 14 | go test $GOBUILDFLAG . 15 | 16 | export GORP_TEST_DSN="user=gorptest password=gorptest dbname=gorptest sslmode=disable" 17 | export GORP_TEST_DIALECT=postgres 18 | go test $GOBUILDFLAG . 19 | 20 | export GORP_TEST_DSN=/tmp/gorptest.bin 21 | export GORP_TEST_DIALECT=sqlite 22 | go test $GOBUILDFLAG . 23 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd_dbversion.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "fmt" 6 | "log" 7 | ) 8 | 9 | var dbVersionCmd = &Command{ 10 | Name: "dbversion", 11 | Usage: "", 12 | Summary: "Print the current version of the database", 13 | Help: `dbversion extended help here...`, 14 | Run: dbVersionRun, 15 | } 16 | 17 | func dbVersionRun(cmd *Command, args ...string) { 18 | conf, err := dbConfFromFlags() 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | 23 | current, err := goose.GetDBVersion(conf) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | 28 | fmt.Printf("goose: dbversion %v\n", current) 29 | } 30 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/cupcake/gokiq/example_client/example_client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/cupcake/gokiq" 8 | ) 9 | 10 | type ExampleWorker struct { 11 | Data []int 12 | } 13 | 14 | func (w *ExampleWorker) Perform() error { return nil } 15 | 16 | func main() { 17 | gokiq.Client.Register(&ExampleWorker{}, "default", 5) 18 | 19 | fmt.Println("Queuing a broken job...") 20 | gokiq.Client.QueueJob(&ExampleWorker{}) // has no arguments, worker will panic due to out of bounds slice access 21 | 22 | fmt.Println("Queuing a job every 5ms...") 23 | for _ = range time.Tick(5 * time.Millisecond) { 24 | gokiq.Client.QueueJob(&ExampleWorker{[]int{1}}) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/new_account_email_job_test.go: -------------------------------------------------------------------------------- 1 | package readraptor_test 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | rr "github.com/asm-products/readraptor/lib" 8 | _ "github.com/lib/pq" 9 | ) 10 | 11 | func Test_NewAccountEmailJob(t *testing.T) { 12 | dbmap := initTestDb(t) 13 | defer dbmap.Db.Close() 14 | 15 | os.Setenv("RR_ROOT", "..") 16 | 17 | account := rr.NewAccount("joe@crabshack.com") 18 | token := "confirm1234" 19 | account.ConfirmationToken = &token 20 | err := dbmap.Insert(account) 21 | ok(t, err) 22 | 23 | job := rr.NewAccountEmailJob{ 24 | AccountId: account.Id, 25 | } 26 | 27 | message, err := job.CreateMessage(account) 28 | ok(t, err) 29 | 30 | expectInclude(t, message.Body, "/confirm/confirm1234") 31 | } 32 | -------------------------------------------------------------------------------- /lib/reader_handlers.go: -------------------------------------------------------------------------------- 1 | package readraptor 2 | 3 | import ( 4 | "encoding/json" 5 | "net/http" 6 | 7 | "github.com/go-martini/martini" 8 | ) 9 | 10 | func GetReader(account *Account, params martini.Params) (string, int) { 11 | var readerId int64 12 | readerId, err := dbmap.SelectInt(` 13 | select id 14 | from readers 15 | where account_id = $1 16 | and distinct_id = $2;`, account.Id, params["distinct_id"]) 17 | if err != nil { 18 | panic(err) 19 | } 20 | 21 | articles, err := UnreadArticles(dbmap, readerId) 22 | if err != nil { 23 | panic(err) 24 | } 25 | 26 | json, err := json.Marshal(articles) 27 | if err != nil { 28 | panic(err) 29 | } 30 | 31 | return string(json), http.StatusOK 32 | } 33 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coopernurse/gorp/errors.go: -------------------------------------------------------------------------------- 1 | package gorp 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // A non-fatal error, when a select query returns columns that do not exist 8 | // as fields in the struct it is being mapped to 9 | type NoFieldInTypeError struct { 10 | TypeName string 11 | MissingColNames []string 12 | } 13 | 14 | func (err *NoFieldInTypeError) Error() string { 15 | return fmt.Sprintf("gorp: No fields %+v in type %s", err.MissingColNames, err.TypeName) 16 | } 17 | 18 | // returns true if the error is non-fatal (ie, we shouldn't immediately return) 19 | func NonFatalError(err error) bool { 20 | switch err.(type) { 21 | case *NoFieldInTypeError: 22 | return true 23 | default: 24 | return false 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd_up.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "log" 6 | ) 7 | 8 | var upCmd = &Command{ 9 | Name: "up", 10 | Usage: "", 11 | Summary: "Migrate the DB to the most recent version available", 12 | Help: `up extended help here...`, 13 | Run: upRun, 14 | } 15 | 16 | func upRun(cmd *Command, args ...string) { 17 | 18 | conf, err := dbConfFromFlags() 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | 23 | target, err := goose.GetMostRecentDBVersion(conf.MigrationsDir) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | 28 | if err := goose.RunMigrations(conf, conf.MigrationsDir, target); err != nil { 29 | log.Fatal(err) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md: -------------------------------------------------------------------------------- 1 | # Chat Example 2 | 3 | This application shows how to use use the 4 | [websocket](https://github.com/gorilla/websocket) package and 5 | [jQuery](http://jquery.com) to implement a simple web chat application. 6 | 7 | ## Running the example 8 | 9 | The example requires a working Go development environment. The [Getting 10 | Started](http://golang.org/doc/install) page describes how to install the 11 | development environment. 12 | 13 | Once you have Go up and running, you can download, build and run the example 14 | using the following commands. 15 | 16 | $ go get github.com/gorilla/websocket 17 | $ cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/chat` 18 | $ go run *.go 19 | 20 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/go-martini/martini/logger_test.go: -------------------------------------------------------------------------------- 1 | package martini 2 | 3 | import ( 4 | "bytes" 5 | "log" 6 | "net/http" 7 | "net/http/httptest" 8 | "testing" 9 | ) 10 | 11 | func Test_Logger(t *testing.T) { 12 | buff := bytes.NewBufferString("") 13 | recorder := httptest.NewRecorder() 14 | 15 | m := New() 16 | // replace log for testing 17 | m.Map(log.New(buff, "[martini] ", 0)) 18 | m.Use(Logger()) 19 | m.Use(func(res http.ResponseWriter) { 20 | res.WriteHeader(http.StatusNotFound) 21 | }) 22 | 23 | req, err := http.NewRequest("GET", "http://localhost:3000/foobar", nil) 24 | if err != nil { 25 | t.Error(err) 26 | } 27 | 28 | m.ServeHTTP(recorder, req) 29 | expect(t, recorder.Code, http.StatusNotFound) 30 | refute(t, len(buff.String()), 0) 31 | } 32 | -------------------------------------------------------------------------------- /lib/timestamp.go: -------------------------------------------------------------------------------- 1 | package readraptor 2 | 3 | import ( 4 | "database/sql/driver" 5 | "strconv" 6 | "time" 7 | ) 8 | 9 | type Timestamp struct { 10 | Time time.Time 11 | Valid bool // Valid is true if Time is not NULL 12 | } 13 | 14 | // Scan implements the Scanner interface. 15 | func (nt *Timestamp) Scan(value interface{}) error { 16 | nt.Time, nt.Valid = value.(time.Time) 17 | return nil 18 | } 19 | 20 | // Value implements the driver Valuer interface. 21 | func (nt Timestamp) Value() (driver.Value, error) { 22 | if !nt.Valid { 23 | return nil, nil 24 | } 25 | return nt.Time, nil 26 | } 27 | 28 | func (t Timestamp) MarshalJSON() ([]byte, error) { 29 | if !t.Valid { 30 | return []byte(`""`), nil 31 | } 32 | return []byte(strconv.FormatInt(t.Time.Local().Unix(), 10)), nil 33 | } 34 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/lib/goose/util.go: -------------------------------------------------------------------------------- 1 | package goose 2 | 3 | import ( 4 | "io" 5 | "os" 6 | "text/template" 7 | ) 8 | 9 | // common routines 10 | 11 | func writeTemplateToFile(path string, t *template.Template, data interface{}) (string, error) { 12 | f, e := os.Create(path) 13 | if e != nil { 14 | return "", e 15 | } 16 | defer f.Close() 17 | 18 | e = t.Execute(f, data) 19 | if e != nil { 20 | return "", e 21 | } 22 | 23 | return f.Name(), nil 24 | } 25 | 26 | func copyFile(dst, src string) (int64, error) { 27 | sf, err := os.Open(src) 28 | if err != nil { 29 | return 0, err 30 | } 31 | defer sf.Close() 32 | 33 | df, err := os.Create(dst) 34 | if err != nil { 35 | return 0, err 36 | } 37 | defer df.Close() 38 | 39 | return io.Copy(df, sf) 40 | } 41 | -------------------------------------------------------------------------------- /rrworker/rrworker.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | "time" 7 | 8 | rr "github.com/asm-products/readraptor/lib" 9 | "github.com/cupcake/gokiq" 10 | "github.com/garyburd/redigo/redis" 11 | ) 12 | 13 | func main() { 14 | dir, err := filepath.Abs(filepath.Dir(os.Args[0])) 15 | if err != nil { 16 | panic(err) 17 | } 18 | os.Setenv("RR_ROOT", dir) 19 | 20 | // database 21 | rr.InitDb(os.Getenv("DATABASE_URL")) 22 | 23 | gokiq.Workers.RedisPool = redis.NewPool(rr.RedisConnect(os.Getenv("REDIS_URL")), 1) 24 | 25 | gokiq.Workers.PollInterval = 1 * time.Second 26 | gokiq.Workers.RedisNamespace = "rr" 27 | gokiq.Workers.WorkerCount = 5 28 | 29 | gokiq.Workers.Register(&rr.UserCallbackJob{}) 30 | gokiq.Workers.Register(&rr.NewAccountEmailJob{}) 31 | 32 | gokiq.Workers.Run() 33 | } 34 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/go-martini/martini/logger.go: -------------------------------------------------------------------------------- 1 | package martini 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "time" 7 | ) 8 | 9 | // Logger returns a middleware handler that logs the request as it goes in and the response as it goes out. 10 | func Logger() Handler { 11 | return func(res http.ResponseWriter, req *http.Request, c Context, log *log.Logger) { 12 | start := time.Now() 13 | 14 | addr := req.Header.Get("X-Real-IP") 15 | if addr == "" { 16 | addr = req.Header.Get("X-Forwarded-For") 17 | if addr == "" { 18 | addr = req.RemoteAddr 19 | } 20 | } 21 | 22 | log.Printf("Started %s %s for %s", req.Method, req.URL.Path, addr) 23 | 24 | rw := res.(ResponseWriter) 25 | c.Next() 26 | 27 | log.Printf("Completed %v %s in %v\n", rw.Status(), http.StatusText(rw.Status()), time.Since(start)) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/technoweenie/grohl/context_test.go: -------------------------------------------------------------------------------- 1 | package grohl 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestContextMerge(t *testing.T) { 8 | orig := NewContext(nil) 9 | 10 | orig.Add("a", 1) 11 | orig.Add("b", 1) 12 | 13 | merged := orig.Merge(Data{"b": 2, "c": 3}) 14 | 15 | AssertData(t, merged, "a=1", "b=2", "c=3") 16 | AssertLog(t, orig, "a=1", "b=1") 17 | } 18 | 19 | func TestContextStatterPrefix(t *testing.T) { 20 | ctx1 := NewContext(nil) 21 | ctx2 := NewContext(nil) 22 | ctx3 := ctx1.New(nil) 23 | AssertString(t, "", ctx1.StatterBucket) 24 | AssertString(t, "", ctx2.StatterBucket) 25 | AssertString(t, "", ctx3.StatterBucket) 26 | 27 | ctx1.SetStatter(nil, 1.0, "abc") 28 | AssertString(t, "abc", ctx1.StatterBucket) 29 | AssertString(t, "", ctx2.StatterBucket) 30 | AssertString(t, "", ctx3.StatterBucket) 31 | } 32 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd_down.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "log" 6 | ) 7 | 8 | var downCmd = &Command{ 9 | Name: "down", 10 | Usage: "", 11 | Summary: "Roll back the version by 1", 12 | Help: `down extended help here...`, 13 | Run: downRun, 14 | } 15 | 16 | func downRun(cmd *Command, args ...string) { 17 | 18 | conf, err := dbConfFromFlags() 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | 23 | current, err := goose.GetDBVersion(conf) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | 28 | previous, err := goose.GetPreviousDBVersion(conf.MigrationsDir, current) 29 | if err != nil { 30 | log.Fatal(err) 31 | } 32 | 33 | if err = goose.RunMigrations(conf, conf.MigrationsDir, previous); err != nil { 34 | log.Fatal(err) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /assets/stylesheets/modules/_base.scss: -------------------------------------------------------------------------------- 1 | /*-----------------------------------*\ 2 | 3 | Module: Base 4 | 5 | Anything that can't be abstracted 6 | or assigned to another section. 7 | Low-level stuff. Typically only body 8 | and html styles. 9 | 10 | \*-----------------------------------*/ 11 | 12 | @import "susy"; 13 | 14 | ::-moz-selection { 15 | background-color: transparentize($lighter-gray, .5); 16 | } 17 | 18 | ::selection { 19 | background-color: transparentize($lighter-gray, .5); 20 | } 21 | 22 | html { 23 | font: #{$base-font-size}/#{$baseline} $font-Sans; 24 | -webkit-font-smoothing: antialiased; 25 | -webkit-text-size-adjust: none; 26 | text-rendering: optimizeLegibility; 27 | font-feature-settings: "kern" 1; 28 | font-kerning: normal; 29 | 30 | color: $gray; 31 | background-color: #fff; 32 | } 33 | 34 | body { 35 | overflow-x: hidden; 36 | } 37 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/middleware_logging.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | "time" 7 | ) 8 | 9 | type MiddlewareLogging struct{} 10 | 11 | func (l *MiddlewareLogging) Call(queue string, message *Msg, next func() bool) (acknowledge bool) { 12 | prefix := fmt.Sprint(queue, " JID-", message.Jid()) 13 | 14 | start := time.Now() 15 | Logger.Println(prefix, "start") 16 | Logger.Println(prefix, "args: ", message.Args().ToJson()) 17 | 18 | defer func() { 19 | if e := recover(); e != nil { 20 | Logger.Println(prefix, "fail:", time.Since(start)) 21 | 22 | buf := make([]byte, 4096) 23 | buf = buf[:runtime.Stack(buf, false)] 24 | Logger.Printf("%s error: %v\n%s", prefix, e, buf) 25 | 26 | panic(e) 27 | } 28 | }() 29 | 30 | acknowledge = next() 31 | 32 | Logger.Println(prefix, "done:", time.Since(start)) 33 | 34 | return 35 | } 36 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/sirsean/go-mailgun/mailgun/mime_message_test.go: -------------------------------------------------------------------------------- 1 | package mailgun 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | // TestMessageValidity just provides some basic checks for whether a Message is valid. 8 | // A Message needs to have a ToAddress, and then either a MimeMessage, or the set of 9 | // FromAddress, Subject, and Body. 10 | func TestMimeMessageValidity(t *testing.T) { 11 | m := MimeMessage{ 12 | ToAddress: "bar@baz.org", 13 | Content: []byte("This is my body. There are many like it but this one is mine.")} 14 | 15 | if m.IsValid() != true { 16 | t.Error("Message should have been valid!") 17 | } 18 | 19 | m.ToAddress = "" 20 | if m.IsValid() != false { 21 | t.Error("Message(2) should have been invalid!") 22 | } 23 | 24 | m = MimeMessage{ToAddress: "bar@baz.org"} 25 | if m.IsValid() != false { 26 | t.Error("Message(3) should have been invalid!") 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/middleware_stats.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type MiddlewareStats struct{} 8 | 9 | func (l *MiddlewareStats) Call(queue string, message *Msg, next func() bool) (acknowledge bool) { 10 | defer func() { 11 | if e := recover(); e != nil { 12 | incrementStats("failed") 13 | panic(e) 14 | } 15 | }() 16 | 17 | acknowledge = next() 18 | 19 | incrementStats("processed") 20 | 21 | return 22 | } 23 | 24 | func incrementStats(metric string) { 25 | conn := Config.Pool.Get() 26 | defer conn.Close() 27 | 28 | today := time.Now().UTC().Format("2006-01-02") 29 | 30 | conn.Send("multi") 31 | conn.Send("incr", Config.Namespace+"stat:"+metric) 32 | conn.Send("incr", Config.Namespace+"stat:"+metric+":"+today) 33 | 34 | if _, err := conn.Do("exec"); err != nil { 35 | Logger.Println("couldn't save stats:", err) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /assets/stylesheets/modules/_call-to-action.scss: -------------------------------------------------------------------------------- 1 | .cta-module { 2 | $cta-from : lighten($triassic, 20%); 3 | $cta-to : lighten($triassic, 15%); 4 | 5 | @include background(linear-gradient(45deg, $cta-from, $cta-to)); 6 | 7 | // FIXME: Negative margin is a shitty way to compensate for the border above. 8 | margin-top: -1px; 9 | padding-top: $base * 2.5; 10 | padding-bottom: $base * 2.5; 11 | 12 | border: 0; 13 | 14 | p { 15 | margin-bottom: 0; 16 | 17 | font-size: 21px; 18 | 19 | color: $cretaceous; 20 | 21 | &:before { 22 | @include background(image-url("/assets/images/asm-logotype.png")); 23 | 24 | margin: 0 auto; 25 | margin-right: $base; 26 | top: 10px; 27 | 28 | float: left; 29 | width: 52px; 30 | height: 46px; 31 | 32 | background-position: 0 0; 33 | background-repeat: no-repeat; 34 | 35 | content: ""; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/user_callback_job_test.go: -------------------------------------------------------------------------------- 1 | package readraptor_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | rr "github.com/asm-products/readraptor/lib" 8 | "github.com/cupcake/gokiq" 9 | "github.com/garyburd/redigo/redis" 10 | ) 11 | 12 | func Test_ScheduleCallbacks(t *testing.T) { 13 | pool := redis.NewPool(rr.RedisConnect("redis://localhost:6379/6"), 1) 14 | gokiq.Client.RedisPool = pool 15 | gokiq.Client.RedisNamespace = "test" 16 | 17 | conn := pool.Get() 18 | defer conn.Close() 19 | 20 | conn.Do("del", "test:schedule") 21 | 22 | rids := []int64{1, 2} 23 | err := rr.ScheduleCallbacks(gokiq.Client, rids, time.Now().UTC(), "http://example.com/webhook") 24 | if err != nil { 25 | t.Fatal(err) 26 | } 27 | err = rr.ScheduleCallbacks(gokiq.Client, rids, time.Now().UTC(), "http://example.com/webhook") 28 | if err != nil { 29 | t.Fatal(err) 30 | } 31 | 32 | jobs, _ := conn.Do("ZCARD", "test:schedule") 33 | 34 | expect(t, int64(2), jobs) 35 | } 36 | -------------------------------------------------------------------------------- /lib/read_receipt_handlers_test.go: -------------------------------------------------------------------------------- 1 | package readraptor_test 2 | 3 | import ( 4 | "io/ioutil" 5 | "net/http" 6 | "net/url" 7 | "testing" 8 | 9 | "github.com/asm-products/readraptor/fake" 10 | 11 | rr "github.com/asm-products/readraptor/lib" 12 | "github.com/go-martini/martini" 13 | _ "github.com/lib/pq" 14 | ) 15 | 16 | func Test_Tracking(t *testing.T) { 17 | dbmap := initTestDb(t) 18 | defer dbmap.Db.Close() 19 | 20 | account := MustCreateAccount(dbmap, "weasley@example.com") 21 | 22 | params := martini.Params{ 23 | "public_key": account.PublicKey, 24 | "article_id": "article_1", 25 | "user_id": "user_1", 26 | "signature": rr.Signature(account.PrivateKey, account.PublicKey, "article_1", "user_1"), 27 | } 28 | 29 | req := &http.Request{} 30 | req.URL, _ = url.Parse("/t") 31 | rw := fake.New(t) 32 | rr.GetTrackReadReceipts("..")(params, rw, req) 33 | 34 | gif, _ := ioutil.ReadFile("../public/tracking.gif") 35 | rw.Assert(200, gif) 36 | } 37 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd_redo.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "log" 6 | ) 7 | 8 | var redoCmd = &Command{ 9 | Name: "redo", 10 | Usage: "", 11 | Summary: "Re-run the latest migration", 12 | Help: `redo extended help here...`, 13 | Run: redoRun, 14 | } 15 | 16 | func redoRun(cmd *Command, args ...string) { 17 | conf, err := dbConfFromFlags() 18 | if err != nil { 19 | log.Fatal(err) 20 | } 21 | 22 | current, err := goose.GetDBVersion(conf) 23 | if err != nil { 24 | log.Fatal(err) 25 | } 26 | 27 | previous, err := goose.GetPreviousDBVersion(conf.MigrationsDir, current) 28 | if err != nil { 29 | log.Fatal(err) 30 | } 31 | 32 | if err := goose.RunMigrations(conf, conf.MigrationsDir, previous); err != nil { 33 | log.Fatal(err) 34 | } 35 | 36 | if err := goose.RunMigrations(conf, conf.MigrationsDir, current); err != nil { 37 | log.Fatal(err) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/certs/postgresql.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICWwIBAAKBgQDjjAaacFRR0TQ0gznNolkPBe2N2A400JL0CU3ujHhVSST4POA0 3 | WAKy55RYwejlu9Gv9lTBQLGQcHkNNVScjxbpwvCS5mRJOMF2+EdmxFtKtqlDzsi+ 4 | bE0rlJc8VbzR0G63U66JXEtrhkC+wa4eZM6crocKaeXIIRK+rh32Rd8WpwIDAQAB 5 | AoGAM5dM6/kp9P700i8qjOgRPym96Zoh5nGfz/rIE5z/r36NBkdvIg8OVZfR96nH 6 | b0b9TOMR5lsPp0sI9yivTWvX6qyvLJRWy2vvx17hXK9NxXUNTAm0PYZUTvCtcPeX 7 | RnJpzQKNZQPkFzF0uXBc4CtPK2Vz0+FGvAelrhYAxnw1dIkCQQD+9qaW5QhXjsjb 8 | Nl85CmXgxPmGROcgLQCO+omfrjf9UXrituU9Dz6auym5lDGEdMFnkzfr+wpasEy9 9 | mf5ZZOhDAkEA5HjXfVGaCtpydOt6hDon/uZsyssCK2lQ7NSuE3vP+sUsYMzIpEoy 10 | t3VWXqKbo+g9KNDTP4WEliqp1aiSIylzzQJANPeqzihQnlgEdD4MdD4rwhFJwVIp 11 | Le8Lcais1KaN7StzOwxB/XhgSibd2TbnPpw+3bSg5n5lvUdo+e62/31OHwJAU1jS 12 | I+F09KikQIr28u3UUWT2IzTT4cpVv1AHAQyV3sG3YsjSGT0IK20eyP9BEBZU2WL0 13 | 7aNjrvR5aHxKc5FXsQJABsFtyGpgI5X4xufkJZVZ+Mklz2n7iXa+XPatMAHFxAtb 14 | EEMt60rngwMjXAzBSC6OYuYogRRAY3UCacNC5VhLYQ== 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /config.rb: -------------------------------------------------------------------------------- 1 | # Require any additional compass plugins here. 2 | require 'susy' 3 | 4 | # Set this to the root of your project when deployed: 5 | http_path = "/" 6 | css_dir = "public/css" 7 | sass_dir = "assets/stylesheets" 8 | images_dir = "assets/images" 9 | javascripts_dir = "assets/javascripts" 10 | 11 | # You can select your preferred output style here (can be overridden via the command line): 12 | # output_style = :expanded or :nested or :compact or :compressed 13 | 14 | # To enable relative paths to assets via compass helper functions. Uncomment: 15 | # relative_assets = true 16 | 17 | # To disable debugging comments that display the original location of your selectors. Uncomment: 18 | # line_comments = false 19 | 20 | 21 | # If you prefer the indented syntax, you might want to regenerate this 22 | # project again passing --syntax sass, or you can uncomment this: 23 | # preferred_syntax = :sass 24 | # and then run: 25 | # sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass 26 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/user_windows.go: -------------------------------------------------------------------------------- 1 | // Package pq is a pure Go Postgres driver for the database/sql package. 2 | package pq 3 | 4 | import ( 5 | "path/filepath" 6 | "syscall" 7 | ) 8 | 9 | // Perform Windows user name lookup identically to libpq. 10 | // 11 | // The PostgreSQL code makes use of the legacy Win32 function 12 | // GetUserName, and that function has not been imported into stock Go. 13 | // GetUserNameEx is available though, the difference being that a 14 | // wider range of names are available. To get the output to be the 15 | // same as GetUserName, only the base (or last) component of the 16 | // result is returned. 17 | func userCurrent() (string, error) { 18 | pw_name := make([]uint16, 128) 19 | pwname_size := uint32(len(pw_name)) - 1 20 | err := syscall.GetUserNameEx(syscall.NameSamCompatible, &pw_name[0], &pwname_size) 21 | if err != nil { 22 | return "", err 23 | } 24 | s := syscall.UTF16ToString(pw_name) 25 | u := filepath.Base(s) 26 | return u, nil 27 | } 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/oxtoacart/bpool/bufferpool.go: -------------------------------------------------------------------------------- 1 | package bpool 2 | 3 | import ( 4 | "bytes" 5 | ) 6 | 7 | /* 8 | BufferPool implements a pool of bytes.Buffers in the form of a bounded 9 | channel. 10 | */ 11 | type BufferPool struct { 12 | c chan *bytes.Buffer 13 | } 14 | 15 | /* 16 | NewBufferPool creates a new BufferPool bounded to the given size. 17 | */ 18 | func NewBufferPool(size int) (bp *BufferPool) { 19 | return &BufferPool{ 20 | c: make(chan *bytes.Buffer, size), 21 | } 22 | } 23 | 24 | /* 25 | Get gets a Buffer from the BufferPool, or creates a new one if none are available 26 | in the pool. 27 | */ 28 | func (bp *BufferPool) Get() (b *bytes.Buffer) { 29 | select { 30 | case b = <-bp.c: 31 | // reuse existing buffer 32 | default: 33 | // create new buffer 34 | b = bytes.NewBuffer([]byte{}) 35 | } 36 | return 37 | } 38 | 39 | /* 40 | Put returns the given Buffer to the BufferPool. 41 | */ 42 | func (bp *BufferPool) Put(b *bytes.Buffer) { 43 | b.Reset() 44 | bp.c <- b 45 | } 46 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Gorilla WebSocket Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package websocket 6 | 7 | import ( 8 | "net/http" 9 | "testing" 10 | ) 11 | 12 | var tokenListContainsValueTests = []struct { 13 | value string 14 | ok bool 15 | }{ 16 | {"WebSocket", true}, 17 | {"WEBSOCKET", true}, 18 | {"websocket", true}, 19 | {"websockets", false}, 20 | {"x websocket", false}, 21 | {"websocket x", false}, 22 | {"other,websocket,more", true}, 23 | {"other, websocket, more", true}, 24 | } 25 | 26 | func TestTokenListContainsValue(t *testing.T) { 27 | for _, tt := range tokenListContainsValueTests { 28 | h := http.Header{"Upgrade": {tt.value}} 29 | ok := tokenListContainsValue(h, "Upgrade", "websocket") 30 | if ok != tt.ok { 31 | t.Errorf("tokenListContainsValue(h, n, %q) = %v, want %v", tt.value, ok, tt.ok) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/read_receipt_test.go: -------------------------------------------------------------------------------- 1 | package readraptor_test 2 | 3 | import ( 4 | "testing" 5 | 6 | rr "github.com/asm-products/readraptor/lib" 7 | ) 8 | 9 | func Test_TrackReadReceipt_FirstTime(t *testing.T) { 10 | dbmap := initTestDb(t) 11 | defer dbmap.Db.Close() 12 | a := MustCreateAccount(dbmap, "weasley@example.com") 13 | rid := MustCreateReader(dbmap, a.Id, "user_1") 14 | 15 | err := rr.TrackReadReceipt(dbmap, a, "article_1", "user_1") 16 | ok(t, err) 17 | 18 | aid, err := rr.FindArticleIdByKey(dbmap, a.Id, "article_1") 19 | assert(t, aid != 0, "Article not created") 20 | ok(t, err) 21 | 22 | var rec rr.ReadReceipt 23 | err = dbmap.SelectOne(&rec, ` 24 | select first_read_at, last_read_at, read_count 25 | from read_receipts where article_id = $1 and reader_id = $2`, aid, rid) 26 | if err != nil { 27 | t.Fatal(err) 28 | } 29 | 30 | assert(t, rec.FirstReadAt != nil, "FirstReadAt should be set") 31 | assert(t, rec.LastReadAt != nil, "LastReadAt should be set") 32 | equals(t, int64(1), rec.ReadCount) 33 | } 34 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/oxtoacart/bpool/README.md: -------------------------------------------------------------------------------- 1 | # bpool [![GoDoc](https://godoc.org/github.com/oxtoacart/bpool?status.png)](https://godoc.org/github.com/oxtoacart/bpool) 2 | 3 | Package bpool implements leaky pools of byte arrays and Buffers as bounded channels. It is based on the leaky buffer example from the Effective Go documentation: http://golang.org/doc/effective_go.html#leaky_buffer 4 | 5 | ## Install 6 | 7 | `go get github.com/oxtoacart/bpool` 8 | 9 | ## Documentation 10 | 11 | See [godoc.org](http://godoc.org/github.com/oxtoacart/bpool) or use `godoc github.com/oxtoacart/bpool` 12 | 13 | ## Example 14 | 15 | ```go 16 | 17 | var bufpool *bpol.BufferPool 18 | 19 | func main() { 20 | 21 | bufpool = bpool.NewBufferPool(48) 22 | 23 | } 24 | 25 | func someFunction() error { 26 | 27 | // Get a buffer from the pool 28 | buf := bufpool.Get() 29 | ... 30 | ... 31 | ... 32 | // Return the buffer to the pool 33 | bufpool.Put(buf) 34 | 35 | return nil 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/sessions/README.md: -------------------------------------------------------------------------------- 1 | sessions 2 | ======== 3 | 4 | Store Implementations 5 | --------------------- 6 | Other implementations of the sessions.Store interface: 7 | 8 | * [github.com/yosssi/boltstore](https://github.com/yosssi/boltstore) - Bolt 9 | * [github.com/srinathgs/couchbasestore](https://github.com/srinathgs/couchbasestore) - Couchbase 10 | * [github.com/bradleypeabody/gorilla-sessions-memcache](https://github.com/bradleypeabody/gorilla-sessions-memcache) - Memcache 11 | * [github.com/hnakamur/gaesessions](https://github.com/hnakamur/gaesessions) - Memcache on GAE 12 | * [github.com/kidstuff/mongostore](https://github.com/kidstuff/mongostore) - MongoDB 13 | * [github.com/srinathgs/mysqlstore](https://github.com/srinathgs/mysqlstore) - MySQL 14 | * [github.com/antonlindstrom/pgstore](https://github.com/antonlindstrom/pgstore) - PostgreSQL 15 | * [github.com/boj/redistore](https://github.com/boj/redistore) - Redis 16 | * [github.com/boj/riakstore](https://github.com/boj/riakstore) - Riak 17 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package websocket 6 | 7 | import ( 8 | "net/http" 9 | "reflect" 10 | "testing" 11 | ) 12 | 13 | var subprotocolTests = []struct { 14 | h string 15 | protocols []string 16 | }{ 17 | {"", nil}, 18 | {"foo", []string{"foo"}}, 19 | {"foo,bar", []string{"foo", "bar"}}, 20 | {"foo, bar", []string{"foo", "bar"}}, 21 | {" foo, bar", []string{"foo", "bar"}}, 22 | {" foo, bar ", []string{"foo", "bar"}}, 23 | } 24 | 25 | func TestSubprotocols(t *testing.T) { 26 | for _, st := range subprotocolTests { 27 | r := http.Request{Header: http.Header{"Sec-Websocket-Protocol": {st.h}}} 28 | protocols := Subprotocols(&r) 29 | if !reflect.DeepEqual(st.protocols, protocols) { 30 | t.Errorf("SubProtocols(%q) returned %#v, want %#v", st.h, protocols, st.protocols) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /fake/responsewriter.go: -------------------------------------------------------------------------------- 1 | package fake 2 | 3 | import ( 4 | "net/http" 5 | "testing" 6 | ) 7 | 8 | type ResponseWriter struct { 9 | http.ResponseWriter 10 | 11 | t *testing.T 12 | headers http.Header 13 | body []byte 14 | status int 15 | } 16 | 17 | func New(t *testing.T) *ResponseWriter { 18 | return &ResponseWriter{ 19 | t: t, 20 | headers: make(http.Header), 21 | } 22 | } 23 | 24 | func (r *ResponseWriter) Header() http.Header { 25 | return r.headers 26 | } 27 | 28 | func (r *ResponseWriter) Write(body []byte) (int, error) { 29 | r.body = body 30 | return len(body), nil 31 | } 32 | 33 | func (r *ResponseWriter) WriteHeader(status int) { 34 | r.status = status 35 | } 36 | 37 | func (r *ResponseWriter) Assert(status int, body []byte) { 38 | if r.status != status { 39 | r.t.Errorf("expected status %+v to equal %+v", r.status, status) 40 | } 41 | if string(r.body) != string(body) { 42 | r.t.Errorf("expected body %+v to equal %+v", string(r.body), body) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /templates/layout.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Read Raptor 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | {{ yield }} 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "flag" 9 | "log" 10 | "net/http" 11 | "text/template" 12 | ) 13 | 14 | var addr = flag.String("addr", ":8080", "http service address") 15 | var homeTempl = template.Must(template.ParseFiles("home.html")) 16 | 17 | func serveHome(w http.ResponseWriter, r *http.Request) { 18 | if r.URL.Path != "/" { 19 | http.Error(w, "Not found", 404) 20 | return 21 | } 22 | if r.Method != "GET" { 23 | http.Error(w, "Method not allowed", 405) 24 | return 25 | } 26 | w.Header().Set("Content-Type", "text/html; charset=utf-8") 27 | homeTempl.Execute(w, r.Host) 28 | } 29 | 30 | func main() { 31 | flag.Parse() 32 | go h.run() 33 | http.HandleFunc("/", serveHome) 34 | http.HandleFunc("/ws", serveWs) 35 | err := http.ListenAndServe(*addr, nil) 36 | if err != nil { 37 | log.Fatal("ListenAndServe: ", err) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/bitly/go-simplejson/LICENSE: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in 9 | all copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 17 | THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/sessions/README.md: -------------------------------------------------------------------------------- 1 | # sessions [![wercker status](https://app.wercker.com/status/af92c7633124fffea8984e48ee0c418b "wercker status")](https://app.wercker.com/project/bykey/af92c7633124fffea8984e48ee0c418b) 2 | Martini middleware/handler for easy session management. 3 | 4 | [API Reference](http://godoc.org/github.com/martini-contrib/sessions) 5 | 6 | ## Usage 7 | 8 | ~~~ go 9 | package main 10 | 11 | import ( 12 | "github.com/go-martini/martini" 13 | "github.com/martini-contrib/sessions" 14 | ) 15 | 16 | func main() { 17 | m := martini.Classic() 18 | 19 | store := sessions.NewCookieStore([]byte("secret123")) 20 | m.Use(sessions.Sessions("my_session", store)) 21 | 22 | m.Get("/set", func(session sessions.Session) string { 23 | session.Set("hello", "world") 24 | return "OK" 25 | }) 26 | 27 | m.Get("/get", func(session sessions.Session) string { 28 | v := session.Get("hello") 29 | if v == nil { 30 | return "" 31 | } 32 | return v.(string) 33 | }) 34 | 35 | m.Run() 36 | } 37 | 38 | ~~~ 39 | 40 | ## Authors 41 | * [Jeremy Saenz](http://github.com/codegangsta) 42 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2013, 'pq' Contributors 2 | Portions Copyright (C) 2011 Blake Mizerany 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/boj/redistore/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Brian Jones 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /assets/stylesheets/partials/_variables.scss: -------------------------------------------------------------------------------- 1 | /*-----------------------------------*\ 2 | 3 | Partial: Variables 4 | 5 | Includes global variables for 6 | colors and unit sizes 7 | 8 | \*-----------------------------------*/ 9 | 10 | // Group: Unit Sizes 11 | $base: 18px; 12 | $base-font-size: $base; 13 | $baseline: 1.6; 14 | 15 | 16 | // Group: Fonts 17 | $font-Serif: "Tiempos Text", Georgia, serif; 18 | $font-Sans: "runda", Geneva, Verdana, san-serif; 19 | $font-Display: $font-Sans; 20 | $font-Code: "source-code-pro", Monaco, monospace; 21 | 22 | 23 | // Group: Colors 24 | $white: #fff; // Duh. 25 | 26 | $lightest-gray: #eff1f5; 27 | $lighter-gray: #BDC4CA; 28 | $light-gray: #7B8994; 29 | $gray: #47525D; 30 | $dark-gray: #3D464D; 31 | 32 | $subtle-gray: #d8dce0; 33 | 34 | $green: #a3be8c; 35 | $blue: #96b5b4; 36 | 37 | $gradient-from: $green; 38 | $gradient-to: shade($green, 20%); 39 | 40 | $addendum: desaturate(mix($green, $gradient-to), 10%); 41 | 42 | $free: $green; 43 | $triassic: #ddbd7d; 44 | $jurassic: #dc937c; 45 | $cretaceous: #ab7967; 46 | 47 | 48 | // Group: Aesthetics 49 | $radius: 3px; 50 | 51 | // Group: Breakpoints 52 | $breakpoint: 12; 53 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/msg_test.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "github.com/customerio/gospec" 5 | . "github.com/customerio/gospec" 6 | ) 7 | 8 | func MsgSpec(c gospec.Context) { 9 | c.Specify("NewMsg", func() { 10 | c.Specify("unmarshals json", func() { 11 | msg, _ := NewMsg("{\"hello\":\"world\",\"foo\":3}") 12 | hello, _ := msg.Get("hello").String() 13 | foo, _ := msg.Get("foo").Int() 14 | 15 | c.Expect(hello, Equals, "world") 16 | c.Expect(foo, Equals, 3) 17 | }) 18 | 19 | c.Specify("returns an error if invalid json", func() { 20 | msg, err := NewMsg("{\"hello:\"world\",\"foo\":3}") 21 | 22 | c.Expect(msg, IsNil) 23 | c.Expect(err, Not(IsNil)) 24 | }) 25 | }) 26 | 27 | c.Specify("Args", func() { 28 | c.Specify("returns args key", func() { 29 | msg, _ := NewMsg("{\"hello\":\"world\",\"args\":[\"foo\",\"bar\"]}") 30 | c.Expect(msg.Args().ToJson(), Equals, "[\"foo\",\"bar\"]") 31 | }) 32 | 33 | c.Specify("returns empty array if args key doesn't exist", func() { 34 | msg, _ := NewMsg("{\"hello\":\"world\"}") 35 | c.Expect(msg.Args().ToJson(), Equals, "[]") 36 | }) 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/technoweenie/grohl/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 rick olson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/bradrydzewski/go.stripe/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Brad Rydzewski 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/garyburd/redigo/redis/test_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Gary Burd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package redis 16 | 17 | import ( 18 | "bufio" 19 | "net" 20 | "time" 21 | ) 22 | 23 | func SetNowFunc(f func() time.Time) { 24 | nowFunc = f 25 | } 26 | 27 | type nopCloser struct{ net.Conn } 28 | 29 | func (nopCloser) Close() error { return nil } 30 | 31 | // NewConnBufio is a hook for tests. 32 | func NewConnBufio(rw bufio.ReadWriter) Conn { 33 | return &conn{br: rw.Reader, bw: rw.Writer, conn: nopCloser{}} 34 | } 35 | 36 | var ( 37 | ErrNegativeInt = errNegativeInt 38 | ) 39 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd_create.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "fmt" 6 | "log" 7 | "os" 8 | "path/filepath" 9 | "time" 10 | ) 11 | 12 | var createCmd = &Command{ 13 | Name: "create", 14 | Usage: "", 15 | Summary: "Create the scaffolding for a new migration", 16 | Help: `create extended help here...`, 17 | Run: createRun, 18 | } 19 | 20 | func createRun(cmd *Command, args ...string) { 21 | 22 | if len(args) < 1 { 23 | log.Fatal("goose create: migration name required") 24 | } 25 | 26 | migrationType := "go" // default to Go migrations 27 | if len(args) >= 2 { 28 | migrationType = args[1] 29 | } 30 | 31 | conf, err := dbConfFromFlags() 32 | if err != nil { 33 | log.Fatal(err) 34 | } 35 | 36 | if err = os.MkdirAll(conf.MigrationsDir, 0777); err != nil { 37 | log.Fatal(err) 38 | } 39 | 40 | n, err := goose.CreateMigration(args[0], migrationType, conf.MigrationsDir, time.Now()) 41 | if err != nil { 42 | log.Fatal(err) 43 | } 44 | 45 | a, e := filepath.Abs(n) 46 | if e != nil { 47 | log.Fatal(e) 48 | } 49 | 50 | fmt.Println("goose: created", a) 51 | } 52 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/codegangsta/inject/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Jeremy Saenz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/go-martini/martini/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Jeremy Saenz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/render/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Jeremy Saenz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/secure/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Jeremy Saenz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 John Allison 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/sessionauth/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Jeremy Saenz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/sessions/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Jeremy Saenz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/mattn/go-sqlite3/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Yasuhiro Matsumoto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/coopernurse/gorp/LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2012 James Cooper 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/middleware.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | type Action interface { 4 | Call(queue string, message *Msg, next func() bool) bool 5 | } 6 | 7 | type Middlewares struct { 8 | actions []Action 9 | } 10 | 11 | func (m *Middlewares) Append(action Action) { 12 | m.actions = append(m.actions, action) 13 | } 14 | 15 | func (m *Middlewares) Prepend(action Action) { 16 | actions := make([]Action, len(m.actions)+1) 17 | actions[0] = action 18 | copy(actions[1:], m.actions) 19 | m.actions = actions 20 | } 21 | 22 | func (m *Middlewares) call(queue string, message *Msg, final func()) bool { 23 | return continuation(m.actions, queue, message, final)() 24 | } 25 | 26 | func continuation(actions []Action, queue string, message *Msg, final func()) func() bool { 27 | return func() (acknowledge bool) { 28 | if len(actions) > 0 { 29 | acknowledge = actions[0].Call( 30 | queue, 31 | message, 32 | continuation(actions[1:], queue, message, final), 33 | ) 34 | 35 | if !acknowledge { 36 | return 37 | } 38 | } else { 39 | final() 40 | } 41 | 42 | return true 43 | } 44 | } 45 | 46 | func NewMiddleware(actions ...Action) *Middlewares { 47 | return &Middlewares{actions} 48 | } 49 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/oxtoacart/bpool/bytepool.go: -------------------------------------------------------------------------------- 1 | package bpool 2 | 3 | /* 4 | BytePool implements a leaky pool of []byte in the form of a bounded 5 | channel. 6 | */ 7 | type BytePool struct { 8 | c chan []byte 9 | w int 10 | } 11 | 12 | /* 13 | NewBytePool creates a new BytePool bounded to the given maxSize, with new byte 14 | arrays sized based on width. 15 | */ 16 | func NewBytePool(maxSize int, width int) (bp *BytePool) { 17 | return &BytePool{ 18 | c: make(chan []byte, maxSize), 19 | w: width, 20 | } 21 | } 22 | 23 | /* 24 | Get gets a []byte from the BytePool, or creates a new one if none are available 25 | in the pool. 26 | */ 27 | func (bp *BytePool) Get() (b []byte) { 28 | select { 29 | case b = <-bp.c: 30 | // reuse existing buffer 31 | default: 32 | // create new buffer 33 | b = make([]byte, bp.w) 34 | } 35 | return 36 | } 37 | 38 | /* 39 | Put returns the given Buffer to the BytePool. 40 | */ 41 | func (bp *BytePool) Put(b []byte) { 42 | select { 43 | case bp.c <- b: 44 | // buffer went back into pool 45 | default: 46 | // buffer didn't go back into pool, just discard 47 | } 48 | } 49 | 50 | /* 51 | Width returns the width of the byte arrays in this pool. 52 | */ 53 | func (bp *BytePool) Width() (n int) { 54 | return bp.w 55 | } 56 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/technoweenie/grohl/statter_test.go: -------------------------------------------------------------------------------- 1 | package grohl 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | ) 7 | 8 | func TestLogsCounter(t *testing.T) { 9 | s, buf := setupLogger(t) 10 | s.Counter(1.0, "a", 1, 2) 11 | buf.AssertLine("metric=a", "count=1") 12 | buf.AssertLine("metric=a", "count=2") 13 | buf.AssertEOF() 14 | } 15 | 16 | func TestLogsTiming(t *testing.T) { 17 | s, buf := setupLogger(t) 18 | dur1, _ := time.ParseDuration("15ms") 19 | dur2, _ := time.ParseDuration("3s") 20 | 21 | s.Timing(1.0, "a", dur1, dur2) 22 | buf.AssertLine("metric=a", "timing=15") 23 | buf.AssertLine("metric=a", "timing=3000") 24 | buf.AssertEOF() 25 | } 26 | 27 | func TestLogsGauge(t *testing.T) { 28 | s, buf := setupLogger(t) 29 | s.Gauge(1.0, "a", "1", "2") 30 | buf.AssertLine("metric=a", "gauge=1") 31 | buf.AssertLine("metric=a", "gauge=2") 32 | buf.AssertEOF() 33 | } 34 | 35 | var suffixTests = []string{"abc", "abc."} 36 | 37 | func TestSetsBucketSuffix(t *testing.T) { 38 | s, _ := setupLogger(t) 39 | for _, prefix := range suffixTests { 40 | s.StatterBucket = prefix 41 | s.StatterBucketSuffix("def") 42 | if s.StatterBucket != "abc.def" { 43 | t.Errorf("bucket is wrong after prefix %s: %s", prefix, s.StatterBucket) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package websocket 6 | 7 | import ( 8 | "crypto/rand" 9 | "crypto/sha1" 10 | "encoding/base64" 11 | "io" 12 | "net/http" 13 | "strings" 14 | ) 15 | 16 | // tokenListContainsValue returns true if the 1#token header with the given 17 | // name contains token. 18 | func tokenListContainsValue(header http.Header, name string, value string) bool { 19 | for _, v := range header[name] { 20 | for _, s := range strings.Split(v, ",") { 21 | if strings.EqualFold(value, strings.TrimSpace(s)) { 22 | return true 23 | } 24 | } 25 | } 26 | return false 27 | } 28 | 29 | var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") 30 | 31 | func computeAcceptKey(challengeKey string) string { 32 | h := sha1.New() 33 | h.Write([]byte(challengeKey)) 34 | h.Write(keyGUID) 35 | return base64.StdEncoding.EncodeToString(h.Sum(nil)) 36 | } 37 | 38 | func generateChallengeKey() (string, error) { 39 | p := make([]byte, 16) 40 | if _, err := io.ReadFull(rand.Reader, p); err != nil { 41 | return "", err 42 | } 43 | return base64.StdEncoding.EncodeToString(p), nil 44 | } 45 | -------------------------------------------------------------------------------- /assets/stylesheets/modules/_animation.scss: -------------------------------------------------------------------------------- 1 | // Fade in drop 2 | 3 | @-webkit-keyframes fadein { 4 | 0% { 5 | -webkit-transform: translateY(-20px); 6 | opacity: 0; 7 | } 8 | 100% { 9 | -webkit-transform: translateY(0); 10 | opacity: 1; 11 | } 12 | } 13 | 14 | @-moz-keyframes fadein { 15 | 0% { 16 | -moz-transform: translateY(-20px); 17 | opacity: 0; 18 | } 19 | 100% { 20 | -moz-transform: translateY(0); 21 | opacity: 1; 22 | } 23 | } 24 | 25 | @keyframes fadein { 26 | 0% { transform: translateY(-20px); 27 | opacity: 0; 28 | } 29 | 100% { 30 | transform: translateY(0); 31 | opacity: 1; 32 | } 33 | } 34 | 35 | 36 | // Raptor Time! 37 | 38 | @-webkit-keyframes deal-with-it { 39 | 0% { 40 | -webkit-transform: translateY(-80px); 41 | opacity: 0; 42 | } 43 | 100% { 44 | -webkit-transform: translateY(0); 45 | opacity: 1; 46 | } 47 | } 48 | 49 | @-moz-keyframes deal-with-it { 50 | 0% { 51 | -moz-transform: translateY(-80px); 52 | opacity: 0; 53 | } 54 | 100% { 55 | -moz-transform: translateY(0); 56 | opacity: 1; 57 | } 58 | } 59 | 60 | @keyframes deal-with-it { 61 | 0% { transform: translateY(-80px); 62 | opacity: 0; 63 | } 64 | 100% { 65 | transform: translateY(0); 66 | opacity: 1; 67 | } 68 | } -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/conn_xact_test.go: -------------------------------------------------------------------------------- 1 | // +build go1.1 2 | 3 | package pq 4 | 5 | import ( 6 | "testing" 7 | ) 8 | 9 | func TestXactMultiStmt(t *testing.T) { 10 | // minified test case based on bug reports from 11 | // pico303@gmail.com and rangelspam@gmail.com 12 | t.Skip("Skipping failing test") 13 | db := openTestConn(t) 14 | defer db.Close() 15 | 16 | tx, err := db.Begin() 17 | if err != nil { 18 | t.Fatal(err) 19 | } 20 | defer tx.Commit() 21 | 22 | rows, err := tx.Query("select 1") 23 | if err != nil { 24 | t.Fatal(err) 25 | } 26 | 27 | if rows.Next() { 28 | var val int32 29 | if err = rows.Scan(&val); err != nil { 30 | t.Fatal(err) 31 | } 32 | } else { 33 | t.Fatal("Expected at least one row in first query in xact") 34 | } 35 | 36 | rows2, err := tx.Query("select 2") 37 | if err != nil { 38 | t.Fatal(err) 39 | } 40 | 41 | if rows2.Next() { 42 | var val2 int32 43 | if err := rows2.Scan(&val2); err != nil { 44 | t.Fatal(err) 45 | } 46 | } else { 47 | t.Fatal("Expected at least one row in second query in xact") 48 | } 49 | 50 | if err = rows.Err(); err != nil { 51 | t.Fatal(err) 52 | } 53 | 54 | if err = rows2.Err(); err != nil { 55 | t.Fatal(err) 56 | } 57 | 58 | if err = tx.Commit(); err != nil { 59 | t.Fatal(err) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/reader.go: -------------------------------------------------------------------------------- 1 | package readraptor 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/coopernurse/gorp" 7 | ) 8 | 9 | type Reader struct { 10 | Id int64 `db:"id"` 11 | Created time.Time `db:"created_at"` 12 | AccountId int64 `db:"account_id"` 13 | DistinctId string `db:"distinct_id"` 14 | } 15 | 16 | func InsertReader(dbmap *gorp.DbMap, accountId int64, distinctId string) (int64, error) { 17 | id, err := dbmap.SelectNullInt(` 18 | with s as ( 19 | select id from readers where account_id = $1 and distinct_id = $2 20 | ), i as ( 21 | insert into readers ("account_id", "distinct_id", "created_at") 22 | select $1, $2, $3 23 | where not exists (select 1 from s) 24 | returning id 25 | ) 26 | select id from i union all select id from s; 27 | `, accountId, 28 | distinctId, 29 | time.Now().UTC(), 30 | ) 31 | if err != nil { 32 | return -1, err 33 | } 34 | 35 | iid, err := id.Value() 36 | 37 | return iid.(int64), err 38 | } 39 | 40 | func FindReaderByAccountIdDistinctId(aid int64, distinctId string) (*Reader, error) { 41 | var reader Reader 42 | err := dbmap.SelectOne(&reader, 43 | "select * from readers where account_id = $1 and distinct_id = $2", aid, distinctId) 44 | return &reader, err 45 | } 46 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing to pq 2 | 3 | `pq` has a backlog of pull requests, but contributions are still very 4 | much welcome. You can help with patch review, submitting bug reports, 5 | or adding new functionality. There is no formal style guide, but 6 | please conform to the style of existing code and general Go formatting 7 | conventions when submitting patches. 8 | 9 | ### Patch review 10 | 11 | Help review existing open pull requests by commenting on the code or 12 | proposed functionality. 13 | 14 | ### Bug reports 15 | 16 | We appreciate any bug reports, but especially ones with self-contained 17 | (doesn't depend on code outside of pq), minimal (can't be simplified 18 | further) test cases. It's especially helpful if you can submit a pull 19 | request with just the failing test case (you'll probably want to 20 | pattern it after the tests in 21 | [conn_test.go](https://github.com/lib/pq/blob/master/conn_test.go). 22 | 23 | ### New functionality 24 | 25 | There are a number of pending patches for new functionality, so 26 | additional feature patches will take a while to merge. Still, patches 27 | are generally reviewed based on usefulness and complexity in addition 28 | to time-in-queue, so if you have a knockout idea, take a shot. Feel 29 | free to open an issue discussion your proposed patch beforehand. 30 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/all_specs_test.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "github.com/customerio/gospec" 5 | "testing" 6 | ) 7 | 8 | // You will need to list every spec in a TestXxx method like this, 9 | // so that gotest can be used to run the specs. Later GoSpec might 10 | // get its own command line tool similar to gotest, but for now this 11 | // is the way to go. This shouldn't require too much typing, because 12 | // there will be typically only one top-level spec per class/feature. 13 | 14 | func TestAllSpecs(t *testing.T) { 15 | r := gospec.NewRunner() 16 | 17 | r.Parallel = false 18 | 19 | r.BeforeEach = func() { 20 | Configure(map[string]string{ 21 | "server": "localhost:6379", 22 | "process": "1", 23 | "database": "15", 24 | "pool": "1", 25 | }) 26 | 27 | conn := Config.Pool.Get() 28 | conn.Do("flushdb") 29 | conn.Close() 30 | } 31 | 32 | // List all specs here 33 | r.AddSpec(WorkersSpec) 34 | r.AddSpec(ConfigSpec) 35 | r.AddSpec(MsgSpec) 36 | r.AddSpec(FetchSpec) 37 | r.AddSpec(WorkerSpec) 38 | r.AddSpec(ManagerSpec) 39 | r.AddSpec(ScheduledSpec) 40 | r.AddSpec(EnqueueSpec) 41 | r.AddSpec(MiddlewareSpec) 42 | r.AddSpec(MiddlewareRetrySpec) 43 | r.AddSpec(MiddlewareStatsSpec) 44 | 45 | // Run GoSpec and report any errors to gotest's `testing.T` instance 46 | gospec.MainGoTest(r, t) 47 | } 48 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package main 6 | 7 | // hub maintains the set of active connections and broadcasts messages to the 8 | // connections. 9 | type hub struct { 10 | // Registered connections. 11 | connections map[*connection]bool 12 | 13 | // Inbound messages from the connections. 14 | broadcast chan []byte 15 | 16 | // Register requests from the connections. 17 | register chan *connection 18 | 19 | // Unregister requests from connections. 20 | unregister chan *connection 21 | } 22 | 23 | var h = hub{ 24 | broadcast: make(chan []byte), 25 | register: make(chan *connection), 26 | unregister: make(chan *connection), 27 | connections: make(map[*connection]bool), 28 | } 29 | 30 | func (h *hub) run() { 31 | for { 32 | select { 33 | case c := <-h.register: 34 | h.connections[c] = true 35 | case c := <-h.unregister: 36 | if _, ok := h.connections[c]; ok { 37 | delete(h.connections, c) 38 | close(c.send) 39 | } 40 | case m := <-h.broadcast: 41 | for c := range h.connections { 42 | select { 43 | case c.send <- m: 44 | default: 45 | close(c.send) 46 | delete(h.connections, c) 47 | } 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/scheduled_test.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "github.com/customerio/gospec" 5 | . "github.com/customerio/gospec" 6 | "github.com/garyburd/redigo/redis" 7 | "time" 8 | ) 9 | 10 | func ScheduledSpec(c gospec.Context) { 11 | scheduled := newScheduled(RETRY_KEY) 12 | 13 | was := Config.Namespace 14 | Config.Namespace = "prod:" 15 | 16 | c.Specify("empties retry queues up to the current time", func() { 17 | conn := Config.Pool.Get() 18 | defer conn.Close() 19 | 20 | now := time.Now().Unix() 21 | 22 | message1, _ := NewMsg("{\"queue\":\"default\",\"foo\":\"bar1\"}") 23 | message2, _ := NewMsg("{\"queue\":\"myqueue\",\"foo\":\"bar2\"}") 24 | message3, _ := NewMsg("{\"queue\":\"default\",\"foo\":\"bar3\"}") 25 | 26 | conn.Do("zadd", "prod:"+RETRY_KEY, now-60, message1.ToJson()) 27 | conn.Do("zadd", "prod:"+RETRY_KEY, now-10, message2.ToJson()) 28 | conn.Do("zadd", "prod:"+RETRY_KEY, now+60, message3.ToJson()) 29 | 30 | scheduled.poll(false) 31 | 32 | defaultCount, _ := redis.Int(conn.Do("llen", "prod:queue:default")) 33 | myqueueCount, _ := redis.Int(conn.Do("llen", "prod:queue:myqueue")) 34 | pending, _ := redis.Int(conn.Do("zcard", "prod:"+RETRY_KEY)) 35 | 36 | c.Expect(defaultCount, Equals, 1) 37 | c.Expect(myqueueCount, Equals, 1) 38 | c.Expect(pending, Equals, 1) 39 | }) 40 | 41 | Config.Namespace = was 42 | } 43 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 17 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 20 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/worker.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type worker struct { 8 | manager *manager 9 | stop chan bool 10 | exit chan bool 11 | currentMsg *Msg 12 | startedAt int64 13 | } 14 | 15 | func (w *worker) start() { 16 | go w.work(w.manager.fetch.Messages()) 17 | } 18 | 19 | func (w *worker) quit() { 20 | w.stop <- true 21 | <-w.exit 22 | } 23 | 24 | func (w *worker) work(messages chan *Msg) { 25 | for { 26 | select { 27 | case message := <-messages: 28 | w.startedAt = time.Now().UTC().Unix() 29 | w.currentMsg = message 30 | 31 | if w.process(message) { 32 | w.manager.confirm <- message 33 | } 34 | 35 | w.startedAt = 0 36 | w.currentMsg = nil 37 | case w.manager.fetch.Ready() <- true: 38 | // Signaled to fetcher that we're 39 | // ready to accept a message 40 | case <-w.stop: 41 | w.exit <- true 42 | break 43 | } 44 | } 45 | } 46 | 47 | func (w *worker) process(message *Msg) (acknowledge bool) { 48 | acknowledge = true 49 | 50 | defer func() { 51 | recover() 52 | }() 53 | 54 | return Middleware.call(w.manager.queueName(), message, func() { 55 | w.manager.job(message) 56 | }) 57 | } 58 | 59 | func (w *worker) processing() bool { 60 | return w.startedAt > 0 61 | } 62 | 63 | func newWorker(m *manager) *worker { 64 | return &worker{m, make(chan bool), make(chan bool), nil, 0} 65 | } 66 | -------------------------------------------------------------------------------- /templates/setup.tmpl: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 10 |
11 | 12 |
13 | 14 |

You're good to go

15 | 16 |
17 |

Register an Article

18 | 19 |
20 | 21 |
curl -X POST https://readraptor.com/articles \
22 |      -u {{.Account.PrivateKey}}: \
23 |      -d '{
24 |        "key": "article_1",
25 |        "recipients": ["user_1", "user_2"]
26 |      }'
27 |
28 |
29 | 30 |
31 |

Mark the Article as read

32 |
curl -I https://readraptor.com/t/{{.Account.PublicKey}}/article_1/user_1/{{.Signature}}.gif
33 |
34 | 35 |
36 |

Check who hasn't read it

37 |
curl -u {{.Account.PrivateKey}}: \
38 |     https://readraptor.com/articles/article_1
39 |
40 | 41 |
42 |

Help us build this! Check out Read Raptor on Github

43 |
44 | 45 |
46 |
-------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/scheduled.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "strings" 5 | "time" 6 | 7 | "github.com/garyburd/redigo/redis" 8 | ) 9 | 10 | const ( 11 | POLL_INTERVAL = 15 12 | ) 13 | 14 | type scheduled struct { 15 | keys []string 16 | closed bool 17 | exit chan bool 18 | } 19 | 20 | func (s *scheduled) start() { 21 | go s.poll(true) 22 | } 23 | 24 | func (s *scheduled) quit() { 25 | s.closed = true 26 | } 27 | 28 | func (s *scheduled) poll(continuing bool) { 29 | if s.closed { 30 | return 31 | } 32 | 33 | conn := Config.Pool.Get() 34 | 35 | now := time.Now().Unix() 36 | 37 | for _, key := range s.keys { 38 | key = Config.Namespace + key 39 | for { 40 | messages, _ := redis.Strings(conn.Do("zrangebyscore", key, "-inf", now, "limit", 0, 1)) 41 | 42 | if len(messages) == 0 { 43 | break 44 | } 45 | 46 | message, _ := NewMsg(messages[0]) 47 | 48 | if removed, _ := redis.Bool(conn.Do("zrem", key, messages[0])); removed { 49 | queue, _ := message.Get("queue").String() 50 | queue = strings.TrimPrefix(queue, Config.Namespace) 51 | conn.Do("lpush", Config.Namespace+"queue:"+queue, message.ToJson()) 52 | } 53 | } 54 | } 55 | 56 | conn.Close() 57 | if continuing { 58 | time.Sleep(POLL_INTERVAL * time.Second) 59 | s.poll(true) 60 | } 61 | } 62 | 63 | func newScheduled(keys ...string) *scheduled { 64 | return &scheduled{keys, false, make(chan bool)} 65 | } 66 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/go-martini/martini/return_handler.go: -------------------------------------------------------------------------------- 1 | package martini 2 | 3 | import ( 4 | "github.com/codegangsta/inject" 5 | "net/http" 6 | "reflect" 7 | ) 8 | 9 | // ReturnHandler is a service that Martini provides that is called 10 | // when a route handler returns something. The ReturnHandler is 11 | // responsible for writing to the ResponseWriter based on the values 12 | // that are passed into this function. 13 | type ReturnHandler func(Context, []reflect.Value) 14 | 15 | func defaultReturnHandler() ReturnHandler { 16 | return func(ctx Context, vals []reflect.Value) { 17 | rv := ctx.Get(inject.InterfaceOf((*http.ResponseWriter)(nil))) 18 | res := rv.Interface().(http.ResponseWriter) 19 | var responseVal reflect.Value 20 | if len(vals) > 1 && vals[0].Kind() == reflect.Int { 21 | res.WriteHeader(int(vals[0].Int())) 22 | responseVal = vals[1] 23 | } else if len(vals) > 0 { 24 | responseVal = vals[0] 25 | } 26 | if canDeref(responseVal) { 27 | responseVal = responseVal.Elem() 28 | } 29 | if isByteSlice(responseVal) { 30 | res.Write(responseVal.Bytes()) 31 | } else { 32 | res.Write([]byte(responseVal.String())) 33 | } 34 | } 35 | } 36 | 37 | func isByteSlice(val reflect.Value) bool { 38 | return val.Kind() == reflect.Slice && val.Type().Elem().Kind() == reflect.Uint8 39 | } 40 | 41 | func canDeref(val reflect.Value) bool { 42 | return val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr 43 | } 44 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/url_test.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestSimpleParseURL(t *testing.T) { 8 | expected := "host=hostname.remote" 9 | str, err := ParseURL("postgres://hostname.remote") 10 | if err != nil { 11 | t.Fatal(err) 12 | } 13 | 14 | if str != expected { 15 | t.Fatalf("unexpected result from ParseURL:\n+ %v\n- %v", str, expected) 16 | } 17 | } 18 | 19 | func TestFullParseURL(t *testing.T) { 20 | expected := `dbname=database host=hostname.remote password=top\ secret port=1234 user=username` 21 | str, err := ParseURL("postgres://username:top%20secret@hostname.remote:1234/database") 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | 26 | if str != expected { 27 | t.Fatalf("unexpected result from ParseURL:\n+ %s\n- %s", str, expected) 28 | } 29 | } 30 | 31 | func TestInvalidProtocolParseURL(t *testing.T) { 32 | _, err := ParseURL("http://hostname.remote") 33 | switch err { 34 | case nil: 35 | t.Fatal("Expected an error from parsing invalid protocol") 36 | default: 37 | msg := "invalid connection protocol: http" 38 | if err.Error() != msg { 39 | t.Fatalf("Unexpected error message:\n+ %s\n- %s", 40 | err.Error(), msg) 41 | } 42 | } 43 | } 44 | 45 | func TestMinimalURL(t *testing.T) { 46 | cs, err := ParseURL("postgres://") 47 | if err != nil { 48 | t.Fatal(err) 49 | } 50 | 51 | if cs != "" { 52 | t.Fatalf("expected blank connection string, got: %q", cs) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/bradrydzewski/go.stripe/card_test.go: -------------------------------------------------------------------------------- 1 | package stripe 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | type card struct { 8 | Number string 9 | Type string 10 | Valid bool 11 | } 12 | 13 | var cards = []*card{ 14 | &card{"4242424242424242", Visa, true}, // should pass 15 | &card{"4213729238347292", Visa, false}, // should fail 16 | &card{"79927398713", UnknownCard, true}, // should pass 17 | &card{"79927398710", UnknownCard, false}, // should fail 18 | &card{"601134239348202", Discover, false}, // should fail 19 | &card{"344347386473833", AmericanExpress, false}, // should fail 20 | &card{"374347386473833", AmericanExpress, false}, // should fail 21 | &card{"361134239348202", DinersClub, false}, // should fail 22 | &card{"300134239348202", DinersClub, false}, // should fail 23 | &card{"521134239348202", MasterCard, false}, // should fail 24 | &card{"380134239348202", JCB, false}, // should fail 25 | &card{"180034239348202", JCB, false}, // should fail 26 | } 27 | 28 | func TestLuhn(t *testing.T) { 29 | for _, card := range cards { 30 | valid, _ := IsLuhnValid(card.Number) 31 | cardType := GetCardType(card.Number) 32 | 33 | if valid != card.Valid { 34 | t.Errorf("card validation [%v]; want [%v]", valid, card.Valid) 35 | } 36 | if cardType != card.Type { 37 | t.Errorf("card type [%s]; want [%s]", cardType, card.Type) 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/boj/redistore/README.md: -------------------------------------------------------------------------------- 1 | # redistore 2 | 3 | A session store backend for [gorilla/sessions](http://www.gorillatoolkit.org/pkg/sessions) - [src](https://github.com/gorilla/sessions). 4 | 5 | ## Requirements 6 | 7 | Depends on the [Redigo](https://github.com/garyburd/redigo) Redis library. 8 | 9 | ## Installation 10 | 11 | go get gopkg.in/boj/redistore.v1 12 | 13 | ## Documentation 14 | 15 | Available on [godoc.org](http://www.godoc.org/gopkg.in/boj/redistore.v1). 16 | 17 | See http://www.gorillatoolkit.org/pkg/sessions for full documentation on underlying interface. 18 | 19 | ### Example 20 | 21 | // Fetch new store. 22 | store, err := NewRediStore(10, "tcp", ":6379", "", []byte("secret-key")) 23 | if err != nil { 24 | panic(err) 25 | } 26 | defer store.Close() 27 | 28 | // Get a session. 29 | session, err = store.Get(req, "session-key") 30 | if err != nil { 31 | log.Error(err.Error()) 32 | } 33 | 34 | // Add a value. 35 | session.Values["foo"] = "bar" 36 | 37 | // Save. 38 | if err = sessions.Save(req, rsp); err != nil { 39 | t.Fatalf("Error saving session: %v", err) 40 | } 41 | 42 | // Delete session. 43 | session.Options.MaxAge = -1 44 | if err = sessions.Save(req, rsp); err != nil { 45 | t.Fatalf("Error saving session: %v", err) 46 | } 47 | 48 | // Change session storage configuration for MaxAge = 10 days. 49 | store.SetMaxAge(10*24*3600) 50 | 51 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/msg.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "github.com/bitly/go-simplejson" 5 | "reflect" 6 | ) 7 | 8 | type data struct { 9 | *simplejson.Json 10 | } 11 | 12 | type Msg struct { 13 | *data 14 | original string 15 | } 16 | 17 | type Args struct { 18 | *data 19 | } 20 | 21 | func (m *Msg) Jid() string { 22 | return m.Get("jid").MustString() 23 | } 24 | 25 | func (m *Msg) Args() *Args { 26 | if args, ok := m.CheckGet("args"); ok { 27 | return &Args{&data{args}} 28 | } else { 29 | d, _ := newData("[]") 30 | return &Args{d} 31 | } 32 | } 33 | 34 | func (m *Msg) OriginalJson() string { 35 | return m.original 36 | } 37 | 38 | func (d *data) ToJson() string { 39 | json, err := d.Encode() 40 | 41 | if err != nil { 42 | Logger.Println("ERR: Couldn't generate json from", d, ":", err) 43 | } 44 | 45 | return string(json) 46 | } 47 | 48 | func (d *data) Equals(other interface{}) bool { 49 | otherJson := reflect.ValueOf(other).MethodByName("ToJson").Call([]reflect.Value{}) 50 | return d.ToJson() == otherJson[0].String() 51 | } 52 | 53 | func NewMsg(content string) (*Msg, error) { 54 | if d, err := newData(content); err != nil { 55 | return nil, err 56 | } else { 57 | return &Msg{d, content}, nil 58 | } 59 | } 60 | 61 | func newData(content string) (*data, error) { 62 | if json, err := simplejson.NewJson([]byte(content)); err != nil { 63 | return nil, err 64 | } else { 65 | return &data{json}, nil 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2013, Assembly Made, Inc 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted and provided that the following conditions are met: 5 | 6 | * Any redistribution or use is for noncommercial purposes only and is not redistributed or used in connection with any application that is substantially similar to the Selected App Idea. 7 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OF BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/go-martini/martini/recovery_test.go: -------------------------------------------------------------------------------- 1 | package martini 2 | 3 | import ( 4 | "bytes" 5 | "log" 6 | "net/http" 7 | "net/http/httptest" 8 | "testing" 9 | ) 10 | 11 | func Test_Recovery(t *testing.T) { 12 | buff := bytes.NewBufferString("") 13 | recorder := httptest.NewRecorder() 14 | 15 | setENV(Dev) 16 | m := New() 17 | // replace log for testing 18 | m.Map(log.New(buff, "[martini] ", 0)) 19 | m.Use(func(res http.ResponseWriter, req *http.Request) { 20 | res.Header().Set("Content-Type", "unpredictable") 21 | }) 22 | m.Use(Recovery()) 23 | m.Use(func(res http.ResponseWriter, req *http.Request) { 24 | panic("here is a panic!") 25 | }) 26 | m.ServeHTTP(recorder, (*http.Request)(nil)) 27 | expect(t, recorder.Code, http.StatusInternalServerError) 28 | expect(t, recorder.HeaderMap.Get("Content-Type"), "text/html") 29 | refute(t, recorder.Body.Len(), 0) 30 | refute(t, len(buff.String()), 0) 31 | } 32 | 33 | func Test_Recovery_ResponseWriter(t *testing.T) { 34 | recorder := httptest.NewRecorder() 35 | recorder2 := httptest.NewRecorder() 36 | 37 | setENV(Dev) 38 | m := New() 39 | m.Use(Recovery()) 40 | m.Use(func(c Context) { 41 | c.MapTo(recorder2, (*http.ResponseWriter)(nil)) 42 | panic("here is a panic!") 43 | }) 44 | m.ServeHTTP(recorder, (*http.Request)(nil)) 45 | 46 | expect(t, recorder2.Code, http.StatusInternalServerError) 47 | expect(t, recorder2.HeaderMap.Get("Content-Type"), "text/html") 48 | refute(t, recorder2.Body.Len(), 0) 49 | } 50 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/garyburd/redigo/internal/commandinfo.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Gary Burd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package internal // import "github.com/garyburd/redigo/internal" 16 | 17 | import ( 18 | "strings" 19 | ) 20 | 21 | const ( 22 | WatchState = 1 << iota 23 | MultiState 24 | SubscribeState 25 | MonitorState 26 | ) 27 | 28 | type CommandInfo struct { 29 | Set, Clear int 30 | } 31 | 32 | var commandInfos = map[string]CommandInfo{ 33 | "WATCH": {Set: WatchState}, 34 | "UNWATCH": {Clear: WatchState}, 35 | "MULTI": {Set: MultiState}, 36 | "EXEC": {Clear: WatchState | MultiState}, 37 | "DISCARD": {Clear: WatchState | MultiState}, 38 | "PSUBSCRIBE": {Set: SubscribeState}, 39 | "SUBSCRIBE": {Set: SubscribeState}, 40 | "MONITOR": {Set: MonitorState}, 41 | } 42 | 43 | func LookupCommandInfo(commandName string) CommandInfo { 44 | return commandInfos[strings.ToUpper(commandName)] 45 | } 46 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/json.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package websocket 6 | 7 | import ( 8 | "encoding/json" 9 | ) 10 | 11 | // WriteJSON is deprecated, use c.WriteJSON instead. 12 | func WriteJSON(c *Conn, v interface{}) error { 13 | return c.WriteJSON(v) 14 | } 15 | 16 | // WriteJSON writes the JSON encoding of v to the connection. 17 | // 18 | // See the documentation for encoding/json Marshal for details about the 19 | // conversion of Go values to JSON. 20 | func (c *Conn) WriteJSON(v interface{}) error { 21 | w, err := c.NextWriter(TextMessage) 22 | if err != nil { 23 | return err 24 | } 25 | err1 := json.NewEncoder(w).Encode(v) 26 | err2 := w.Close() 27 | if err1 != nil { 28 | return err1 29 | } 30 | return err2 31 | } 32 | 33 | // ReadJSON is deprecated, use c.ReadJSON instead. 34 | func ReadJSON(c *Conn, v interface{}) error { 35 | return c.ReadJSON(v) 36 | } 37 | 38 | // ReadJSON reads the next JSON-encoded message from the connection and stores 39 | // it in the value pointed to by v. 40 | // 41 | // See the documentation for the encoding/json Unmarshal function for details 42 | // about the conversion of JSON to a Go value. 43 | func (c *Conn) ReadJSON(v interface{}) error { 44 | _, r, err := c.NextReader() 45 | if err != nil { 46 | return err 47 | } 48 | return json.NewDecoder(r).Decode(v) 49 | } 50 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package websocket 6 | 7 | import ( 8 | "bytes" 9 | "reflect" 10 | "testing" 11 | ) 12 | 13 | func TestJSON(t *testing.T) { 14 | var buf bytes.Buffer 15 | c := fakeNetConn{&buf, &buf} 16 | wc := newConn(c, true, 1024, 1024) 17 | rc := newConn(c, false, 1024, 1024) 18 | 19 | var actual, expect struct { 20 | A int 21 | B string 22 | } 23 | expect.A = 1 24 | expect.B = "hello" 25 | 26 | if err := wc.WriteJSON(&expect); err != nil { 27 | t.Fatal("write", err) 28 | } 29 | 30 | if err := rc.ReadJSON(&actual); err != nil { 31 | t.Fatal("read", err) 32 | } 33 | 34 | if !reflect.DeepEqual(&actual, &expect) { 35 | t.Fatal("equal", actual, expect) 36 | } 37 | } 38 | 39 | func TestDeprecatedJSON(t *testing.T) { 40 | var buf bytes.Buffer 41 | c := fakeNetConn{&buf, &buf} 42 | wc := newConn(c, true, 1024, 1024) 43 | rc := newConn(c, false, 1024, 1024) 44 | 45 | var actual, expect struct { 46 | A int 47 | B string 48 | } 49 | expect.A = 1 50 | expect.B = "hello" 51 | 52 | if err := WriteJSON(wc, &expect); err != nil { 53 | t.Fatal("write", err) 54 | } 55 | 56 | if err := ReadJSON(rc, &actual); err != nil { 57 | t.Fatal("read", err) 58 | } 59 | 60 | if !reflect.DeepEqual(&actual, &expect) { 61 | t.Fatal("equal", actual, expect) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/ziutek/mymysql/native/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Michal Derkacz 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. The name of the author may not be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /assets/stylesheets/modules/_features.scss: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------*/ 2 | /* Features */ 3 | 4 | .feature-set { 5 | padding-top: $base * 3; 6 | padding-bottom: $base * 3; 7 | 8 | .feature { 9 | @include at-breakpoint($break) { 10 | @include span-columns(4,12); 11 | @include fade-slide-animation; 12 | margin-bottom: 0; 13 | 14 | &:nth-child(3n) { 15 | @include omega; 16 | } 17 | } 18 | 19 | // 80px = icon size 20 | padding-top: 80px + $base; 21 | margin-bottom: $base * 2; 22 | 23 | background-repeat: no-repeat; 24 | background-position: top center; 25 | 26 | text-align: center; 27 | font-size: 16px; 28 | 29 | &:nth-child(3n) { 30 | @include omega; 31 | } 32 | 33 | h4 { 34 | color: $dark-gray; 35 | } 36 | 37 | p { 38 | margin-bottom: 0; 39 | } 40 | 41 | &:nth-child(1) { 42 | @include animation-stagger(200ms); 43 | } 44 | 45 | &:nth-child(2) { 46 | @include animation-stagger(400ms); 47 | } 48 | 49 | &:nth-child(3) { 50 | @include animation-stagger(600ms); 51 | } 52 | } 53 | 54 | .feature-notifications { 55 | @include background-image(image-url("feature-notifications.png")); 56 | } 57 | 58 | .feature-digests { 59 | @include background-image(image-url("feature-digests.png")); 60 | } 61 | 62 | .feature-receipts { 63 | @include background-image(image-url("feature-receipts.png")); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /templates/welcome.txt.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | ____ ________ 4 | Thanks for checking ,^.__.>--"~~'_.--~_)~^. 5 | out Read Raptor! _L^~ ~ (~ _.-~ \. |\ 6 | ,-~ __ __,^"/\_A_/ /' \ 7 | Check your _/ ,-" "~~" __) \ ~_,^ /\ 8 | email for // / ,-~\ x~" \._"-~ ~ _Y 9 | instructions on Y' Y. (__.// / " , "\_r ' ] 10 | how to get started. J-.__l_>---r{ ~ \__/ \_ _/ 11 | (_ ( (~ ( ~"--- _.-~ `\ / \ ! 12 | (_"~--^----^--------" _.-c Y /Y' 13 | l~---v----.,______.--" / !_/ | 14 | \.__!.____./~-. _/ / \ ! 15 | `x._\_____\__,>---"~___Y\__/Y' 16 | ~(_~~(_)"~___)/ /\| 17 | (_~~ ~~___) \_t 18 | (_~~ ~~___)\_/ | 19 | (_~~ ~~___)\_/ | 20 | { ~~ ~~ }/ \ l 21 | ____ __ ____ __ 22 | / __ \___ ____ _____/ / / __ \____ _____ / /_____ _____ 23 | / /_/ / _ \/ __ `/ __ / / /_/ / __ `/ __ \/ __/ __ \/ ___/ 24 | / _, _/ __/ /_/ / /_/ / / _, _/ /_/ / /_/ / /_/ /_/ / / 25 | /_/ |_|\___/\__,_/\__,_/ /_/ |_|\__,_/ .___/\__/\____/_/ 26 | /_/ 27 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/buf.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "github.com/lib/pq/oid" 7 | ) 8 | 9 | type readBuf []byte 10 | 11 | func (b *readBuf) int32() (n int) { 12 | n = int(int32(binary.BigEndian.Uint32(*b))) 13 | *b = (*b)[4:] 14 | return 15 | } 16 | 17 | func (b *readBuf) oid() (n oid.Oid) { 18 | n = oid.Oid(binary.BigEndian.Uint32(*b)) 19 | *b = (*b)[4:] 20 | return 21 | } 22 | 23 | func (b *readBuf) int16() (n int) { 24 | n = int(binary.BigEndian.Uint16(*b)) 25 | *b = (*b)[2:] 26 | return 27 | } 28 | 29 | func (b *readBuf) string() string { 30 | i := bytes.IndexByte(*b, 0) 31 | if i < 0 { 32 | errorf("invalid message format; expected string terminator") 33 | } 34 | s := (*b)[:i] 35 | *b = (*b)[i+1:] 36 | return string(s) 37 | } 38 | 39 | func (b *readBuf) next(n int) (v []byte) { 40 | v = (*b)[:n] 41 | *b = (*b)[n:] 42 | return 43 | } 44 | 45 | func (b *readBuf) byte() byte { 46 | return b.next(1)[0] 47 | } 48 | 49 | type writeBuf []byte 50 | 51 | func (b *writeBuf) int32(n int) { 52 | x := make([]byte, 4) 53 | binary.BigEndian.PutUint32(x, uint32(n)) 54 | *b = append(*b, x...) 55 | } 56 | 57 | func (b *writeBuf) int16(n int) { 58 | x := make([]byte, 2) 59 | binary.BigEndian.PutUint16(x, uint16(n)) 60 | *b = append(*b, x...) 61 | } 62 | 63 | func (b *writeBuf) string(s string) { 64 | *b = append(*b, (s + "\000")...) 65 | } 66 | 67 | func (b *writeBuf) byte(c byte) { 68 | *b = append(*b, c) 69 | } 70 | 71 | func (b *writeBuf) bytes(v []byte) { 72 | *b = append(*b, v...) 73 | } 74 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/certs/root.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEAzCCAuugAwIBAgIJANmheROCdW1NMA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNV 3 | BAYTAlVTMQ8wDQYDVQQIEwZOZXZhZGExEjAQBgNVBAcTCUxhcyBWZWdhczEaMBgG 4 | A1UEChMRZ2l0aHViLmNvbS9saWIvcHExDjAMBgNVBAMTBXBxIENBMB4XDTE0MTAx 5 | MTE1MDQyOVoXDTI0MTAwODE1MDQyOVowXjELMAkGA1UEBhMCVVMxDzANBgNVBAgT 6 | Bk5ldmFkYTESMBAGA1UEBxMJTGFzIFZlZ2FzMRowGAYDVQQKExFnaXRodWIuY29t 7 | L2xpYi9wcTEOMAwGA1UEAxMFcHEgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw 8 | ggEKAoIBAQCV4PxP7ShzWBzUCThcKk3qZtOLtHmszQVtbqhvgTpm1kTRtKBdVMu0 9 | pLAHQ3JgJCnAYgH0iZxVGoMP16T3irdgsdC48+nNTFM2T0cCdkfDURGIhSFN47cb 10 | Pgy306BcDUD2q7ucW33+dlFSRuGVewocoh4BWM/vMtMvvWzdi4Ag/L/jhb+5wZxZ 11 | sWymsadOVSDePEMKOvlCa3EdVwVFV40TVyDb+iWBUivDAYsS2a3KajuJrO6MbZiE 12 | Sp2RCIkZS2zFmzWxVRi9ZhzIZhh7EVF9JAaNC3T52jhGUdlRq3YpBTMnd89iOh74 13 | 6jWXG7wSuPj3haFzyNhmJ0ZUh+2Ynoh1AgMBAAGjgcMwgcAwHQYDVR0OBBYEFFKT 14 | 7R52Cp9lT94ZZsHVIkA1y6ByMIGQBgNVHSMEgYgwgYWAFFKT7R52Cp9lT94ZZsHV 15 | IkA1y6ByoWKkYDBeMQswCQYDVQQGEwJVUzEPMA0GA1UECBMGTmV2YWRhMRIwEAYD 16 | VQQHEwlMYXMgVmVnYXMxGjAYBgNVBAoTEWdpdGh1Yi5jb20vbGliL3BxMQ4wDAYD 17 | VQQDEwVwcSBDQYIJANmheROCdW1NMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF 18 | BQADggEBAAEhCLWkqJNMI8b4gkbmj5fqQ/4+oO83bZ3w2Oqf6eZ8I8BC4f2NOyE6 19 | tRUlq5+aU7eqC1cOAvGjO+YHN/bF/DFpwLlzvUSXt+JP/pYcUjL7v+pIvwqec9hD 20 | ndvM4iIbkD/H/OYQ3L+N3W+G1x7AcFIX+bGCb3PzYVQAjxreV6//wgKBosMGFbZo 21 | HPxT9RPMun61SViF04H5TNs0derVn1+5eiiYENeAhJzQNyZoOOUuX1X/Inx9bEPh 22 | C5vFBtSMgIytPgieRJVWAiMLYsfpIAStrHztRAbBs2DU01LmMgRvHdxgFEKinC/d 23 | UHZZQDP+6pT+zADrGhQGXe4eThaO6f0= 24 | -----END CERTIFICATE----- 25 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/technoweenie/grohl/loggers.go: -------------------------------------------------------------------------------- 1 | package grohl 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | ) 8 | 9 | // IoLogger assembles the key/value pairs into a line and writes it to any 10 | // io.Writer. This expects the writers to be threadsafe. 11 | type IoLogger struct { 12 | stream io.Writer 13 | AddTime bool 14 | } 15 | 16 | func NewIoLogger(stream io.Writer) *IoLogger { 17 | if stream == nil { 18 | stream = os.Stdout 19 | } 20 | 21 | return &IoLogger{stream, true} 22 | } 23 | 24 | // Log writes the assembled log line. 25 | func (l *IoLogger) Log(data Data) error { 26 | line := fmt.Sprintf("%s\n", BuildLog(data, l.AddTime)) 27 | _, err := l.stream.Write([]byte(line)) 28 | return err 29 | } 30 | 31 | // ChannelLogger sends the key/value data to a channel. This is useful when 32 | // loggers are in separate goroutines. 33 | type ChannelLogger struct { 34 | channel chan Data 35 | } 36 | 37 | func NewChannelLogger(channel chan Data) (*ChannelLogger, chan Data) { 38 | if channel == nil { 39 | channel = make(chan Data) 40 | } 41 | return &ChannelLogger{channel}, channel 42 | } 43 | 44 | // Log writes the assembled log line. 45 | func (l *ChannelLogger) Log(data Data) error { 46 | l.channel <- data 47 | return nil 48 | } 49 | 50 | // Watch starts a for loop that sends any output from logch to logger.Log(). 51 | // This is intended to be used in a goroutine. 52 | func Watch(logger Logger, logch chan Data) { 53 | for { 54 | data := <-logch 55 | if data != nil { 56 | logger.Log(data) 57 | } else { 58 | return 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/cors/README.md: -------------------------------------------------------------------------------- 1 | # cors [![wercker status](https://app.wercker.com/status/4d44f8169ae6c51d0f2d6ffe523bd72e "wercker status")](https://app.wercker.com/project/bykey/4d44f8169ae6c51d0f2d6ffe523bd72e) 2 | 3 | Martini middleware/handler to enable CORS support. 4 | 5 | ## Usage 6 | 7 | ~~~ go 8 | import ( 9 | "github.com/go-martini/martini" 10 | "github.com/martini-contrib/cors" 11 | ) 12 | 13 | func main() { 14 | m := martini.Classic() 15 | // CORS for https://foo.* origins, allowing: 16 | // - PUT and PATCH methods 17 | // - Origin header 18 | // - Credentials share 19 | m.Use(cors.Allow(&cors.Options{ 20 | AllowOrigins: []string{"https://*.foo.com"}, 21 | AllowMethods: []string{"PUT", "PATCH"}, 22 | AllowHeaders: []string{"Origin"}, 23 | ExposeHeaders: []string{"Content-Length"}, 24 | AllowCredentials: true, 25 | })) 26 | m.Run() 27 | } 28 | ~~~ 29 | 30 | You may alternatively prefer to allow CORS only for certain routes. Instead of using the CORS middleware app-wide, register it for the prefered routes. The following snippet demonstrates how to enable CORS for `/api/books` endpoint's PUT handler. 31 | 32 | ~~~ go 33 | m := martini.Classic() 34 | allowCORSHandler := cors.Allow(&cors.Options{ 35 | AllowOrigins: []string{"https://*.foo.com"}, 36 | AllowMethods: []string{"PUT", "PATCH"}, 37 | AllowHeaders: []string{"Origin"}, 38 | }) 39 | 40 | m.Put("/api/books", allowCORSHandler, func() string { 41 | // ... 42 | }) 43 | ~~~ 44 | 45 | ## Authors 46 | 47 | * [Burcu Dogan](http://github.com/rakyll) 48 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/context/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Rodrigo Moraes. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/securecookie/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Rodrigo Moraes. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/gorilla/sessions/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Rodrigo Moraes. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/oid/gen.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | // Generate the table of OID values 4 | // Run with 'go run gen.go'. 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | "log" 10 | "os" 11 | "os/exec" 12 | 13 | "database/sql" 14 | _ "github.com/lib/pq" 15 | ) 16 | 17 | func main() { 18 | datname := os.Getenv("PGDATABASE") 19 | sslmode := os.Getenv("PGSSLMODE") 20 | 21 | if datname == "" { 22 | os.Setenv("PGDATABASE", "pqgotest") 23 | } 24 | 25 | if sslmode == "" { 26 | os.Setenv("PGSSLMODE", "disable") 27 | } 28 | 29 | db, err := sql.Open("postgres", "") 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | cmd := exec.Command("gofmt") 34 | cmd.Stderr = os.Stderr 35 | w, err := cmd.StdinPipe() 36 | if err != nil { 37 | log.Fatal(err) 38 | } 39 | f, err := os.Create("types.go") 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | cmd.Stdout = f 44 | err = cmd.Start() 45 | if err != nil { 46 | log.Fatal(err) 47 | } 48 | fmt.Fprintln(w, "// generated by 'go run gen.go'; do not edit") 49 | fmt.Fprintln(w, "\npackage oid") 50 | fmt.Fprintln(w, "const (") 51 | rows, err := db.Query(` 52 | SELECT typname, oid 53 | FROM pg_type WHERE oid < 10000 54 | ORDER BY oid; 55 | `) 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | var name string 60 | var oid int 61 | for rows.Next() { 62 | err = rows.Scan(&name, &oid) 63 | if err != nil { 64 | log.Fatal(err) 65 | } 66 | fmt.Fprintf(w, "T_%s Oid = %d\n", name, oid) 67 | } 68 | if err = rows.Err(); err != nil { 69 | log.Fatal(err) 70 | } 71 | fmt.Fprintln(w, ")") 72 | w.Close() 73 | cmd.Wait() 74 | } 75 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/sessions/cookie_store.go: -------------------------------------------------------------------------------- 1 | package sessions 2 | 3 | import ( 4 | "github.com/gorilla/sessions" 5 | ) 6 | 7 | // CookieStore is an interface that represents a Cookie based storage 8 | // for Sessions. 9 | type CookieStore interface { 10 | // Store is an embedded interface so that CookieStore can be used 11 | // as a session store. 12 | Store 13 | // Options sets the default options for each session stored in this 14 | // CookieStore. 15 | Options(Options) 16 | } 17 | 18 | // NewCookieStore returns a new CookieStore. 19 | // 20 | // Keys are defined in pairs to allow key rotation, but the common case is to set a single 21 | // authentication key and optionally an encryption key. 22 | // 23 | // The first key in a pair is used for authentication and the second for encryption. The 24 | // encryption key can be set to nil or omitted in the last pair, but the authentication key 25 | // is required in all pairs. 26 | // 27 | // It is recommended to use an authentication key with 32 or 64 bytes. The encryption key, 28 | // if set, must be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256 modes. 29 | func NewCookieStore(keyPairs ...[]byte) CookieStore { 30 | return &cookieStore{sessions.NewCookieStore(keyPairs...)} 31 | } 32 | 33 | type cookieStore struct { 34 | *sessions.CookieStore 35 | } 36 | 37 | func (c *cookieStore) Options(options Options) { 38 | c.CookieStore.Options = &sessions.Options{ 39 | Path: options.Path, 40 | Domain: options.Domain, 41 | MaxAge: options.MaxAge, 42 | Secure: options.Secure, 43 | HttpOnly: options.HttpOnly, 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/mattn/go-sqlite3/README.md: -------------------------------------------------------------------------------- 1 | go-sqlite3 2 | ========== 3 | 4 | [![Build Status](https://travis-ci.org/mattn/go-sqlite3.png?branch=master)](https://travis-ci.org/mattn/go-sqlite3) 5 | [![Coverage Status](https://coveralls.io/repos/mattn/go-sqlite3/badge.png?branch=master)](https://coveralls.io/r/mattn/go-sqlite3?branch=master) 6 | 7 | Description 8 | ----------- 9 | 10 | sqlite3 driver conforming to the built-in database/sql interface 11 | 12 | Installation 13 | ------------ 14 | 15 | This package can be installed with the go get command: 16 | 17 | go get github.com/mattn/go-sqlite3 18 | 19 | Documentation 20 | ------------- 21 | 22 | API documentation can be found here: http://godoc.org/github.com/mattn/go-sqlite3 23 | 24 | Examples can be found under the `./_example` directory 25 | 26 | FAQ 27 | --- 28 | 29 | * Can't build go-sqlite3 on windows 64bit. 30 | 31 | > Probably, you are using go 1.0, go1.0 has a problem when it comes to compiling/linking on windows 64bit. 32 | > See: https://github.com/mattn/go-sqlite3/issues/27 33 | 34 | * Getting insert error while query is opened. 35 | 36 | > You can pass some arguments into the connection string, for example, a URI. 37 | > See: https://github.com/mattn/go-sqlite3/issues/39 38 | 39 | License 40 | ------- 41 | 42 | MIT: http://mattn.mit-license.org/2012 43 | 44 | sqlite.c, sqlite3.h, sqlite3ext.h 45 | 46 | In this repository, those files are amalgamation code that copied from SQLite3. The license of those codes are depend on the license of SQLite3. 47 | 48 | Author 49 | ------ 50 | 51 | Yasuhiro Matsumoto (a.k.a mattn) 52 | -------------------------------------------------------------------------------- /lib/database.go: -------------------------------------------------------------------------------- 1 | package readraptor 2 | 3 | import ( 4 | "database/sql" 5 | "net/url" 6 | "path" 7 | "strconv" 8 | 9 | "github.com/coopernurse/gorp" 10 | "github.com/garyburd/redigo/redis" 11 | _ "github.com/lib/pq" 12 | ) 13 | 14 | var dbmap *gorp.DbMap 15 | 16 | func InitDb(connection string) *gorp.DbMap { 17 | db, err := sql.Open("postgres", connection) 18 | if err != nil { 19 | panic(err) 20 | } 21 | 22 | dbmap = &gorp.DbMap{Db: db, Dialect: gorp.PostgresDialect{}} 23 | dbmap.AddTableWithName(Account{}, "accounts").SetKeys(true, "Id") 24 | dbmap.AddTableWithName(Article{}, "articles").SetKeys(true, "Id") 25 | dbmap.AddTableWithName(Reader{}, "readers").SetKeys(true, "Id") 26 | dbmap.AddTableWithName(ReadReceipt{}, "read_receipts").SetKeys(true, "Id") 27 | 28 | // dbmap.TraceOn("[gorp]", log.New(os.Stdout, "sql:", log.Lmicroseconds)) 29 | 30 | return dbmap 31 | } 32 | 33 | func RedisConnect(connection string) func() (redis.Conn, error) { 34 | return func() (redis.Conn, error) { 35 | url, err := url.Parse(connection) 36 | if err != nil { 37 | return nil, err 38 | } 39 | 40 | c, err := redis.Dial("tcp", url.Host) 41 | if err != nil { 42 | return nil, err 43 | } 44 | 45 | if url.User != nil { 46 | password, set := url.User.Password() 47 | 48 | if set { 49 | if _, err := c.Do("AUTH", password); err != nil { 50 | c.Close() 51 | return nil, err 52 | } 53 | } 54 | } 55 | 56 | db, _ := strconv.Atoi(path.Base(url.Path)) 57 | if _, err := c.Do("SELECT", db); err != nil { 58 | c.Close() 59 | return nil, err 60 | } 61 | 62 | return c, err 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/cupcake/gokiq/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Apollic Software, LLC. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Apollic Software, LLC nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/workers.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "os" 8 | ) 9 | 10 | const ( 11 | RETRY_KEY = "goretry" 12 | SCHEDULED_JOBS_KEY = "schedule" 13 | ) 14 | 15 | var Logger WorkersLogger = log.New(os.Stdout, "workers: ", log.Ldate|log.Lmicroseconds) 16 | 17 | var managers = make(map[string]*manager) 18 | var schedule = newScheduled(RETRY_KEY, SCHEDULED_JOBS_KEY) 19 | var control = make(map[string]chan string) 20 | 21 | var Middleware = NewMiddleware( 22 | &MiddlewareLogging{}, 23 | &MiddlewareRetry{}, 24 | &MiddlewareStats{}, 25 | ) 26 | 27 | func Process(queue string, job jobFunc, concurrency int) { 28 | managers[queue] = newManager(queue, job, concurrency) 29 | } 30 | 31 | func Run() { 32 | Start() 33 | go handleSignals() 34 | waitForExit() 35 | } 36 | 37 | func Start() { 38 | schedule.start() 39 | startManagers() 40 | } 41 | 42 | func Quit() { 43 | quitManagers() 44 | schedule.quit() 45 | waitForExit() 46 | } 47 | 48 | func StatsServer(port int) { 49 | http.HandleFunc("/stats", Stats) 50 | 51 | Logger.Println("Stats are available at", fmt.Sprint("http://localhost:", port, "/stats")) 52 | 53 | if err := http.ListenAndServe(fmt.Sprint(":", port), nil); err != nil { 54 | Logger.Println(err) 55 | } 56 | } 57 | 58 | func startManagers() { 59 | for _, manager := range managers { 60 | manager.start() 61 | } 62 | } 63 | 64 | func quitManagers() { 65 | for _, m := range managers { 66 | go (func(m *manager) { m.quit() })(m) 67 | } 68 | } 69 | 70 | func waitForExit() { 71 | for _, manager := range managers { 72 | manager.Wait() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/sessionauth/example/user.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/martini-contrib/sessionauth" 5 | ) 6 | 7 | // MyUserModel can be any struct that represents a user in my system 8 | type MyUserModel struct { 9 | Id int64 `form:"id" db:"id"` 10 | Username string `form:"name" db:"username"` 11 | Password string `form:"password" db:"password"` 12 | authenticated bool `form:"-" db:"-"` 13 | } 14 | 15 | // GetAnonymousUser should generate an anonymous user model 16 | // for all sessions. This should be an unauthenticated 0 value struct. 17 | func GenerateAnonymousUser() sessionauth.User { 18 | return &MyUserModel{} 19 | } 20 | 21 | // Login will preform any actions that are required to make a user model 22 | // officially authenticated. 23 | func (u *MyUserModel) Login() { 24 | // Update last login time 25 | // Add to logged-in user's list 26 | // etc ... 27 | u.authenticated = true 28 | } 29 | 30 | // Logout will preform any actions that are required to completely 31 | // logout a user. 32 | func (u *MyUserModel) Logout() { 33 | // Remove from logged-in user's list 34 | // etc ... 35 | u.authenticated = false 36 | } 37 | 38 | func (u *MyUserModel) IsAuthenticated() bool { 39 | return u.authenticated 40 | } 41 | 42 | func (u *MyUserModel) UniqueId() interface{} { 43 | return u.Id 44 | } 45 | 46 | // GetById will populate a user object from a database model with 47 | // a matching id. 48 | func (u *MyUserModel) GetById(id interface{}) error { 49 | err := dbmap.SelectOne(u, "SELECT * FROM users WHERE id = $1", id) 50 | if err != nil { 51 | return err 52 | } 53 | 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/stats.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | "strconv" 8 | ) 9 | 10 | type stats struct { 11 | Processed int `json:"processed"` 12 | Failed int `json:"failed"` 13 | Jobs interface{} `json:"jobs"` 14 | } 15 | 16 | func Stats(w http.ResponseWriter, req *http.Request) { 17 | w.Header().Set("Content-Type", "application/json; charset=utf-8") 18 | 19 | jobs := make(map[string][]*map[string]interface{}) 20 | 21 | for _, m := range managers { 22 | queue := m.queueName() 23 | jobs[queue] = make([]*map[string]interface{}, 0) 24 | 25 | for _, worker := range m.workers { 26 | message := worker.currentMsg 27 | startedAt := worker.startedAt 28 | 29 | if message != nil && startedAt > 0 { 30 | jobs[queue] = append(jobs[queue], &map[string]interface{}{ 31 | "message": message, 32 | "started_at": startedAt, 33 | }) 34 | } 35 | } 36 | } 37 | 38 | stats := stats{ 39 | 0, 40 | 0, 41 | jobs, 42 | } 43 | 44 | conn := Config.Pool.Get() 45 | defer conn.Close() 46 | 47 | conn.Send("multi") 48 | conn.Send("get", Config.Namespace+"stat:processed") 49 | conn.Send("get", Config.Namespace+"stat:failed") 50 | r, err := conn.Do("exec") 51 | 52 | if err != nil { 53 | Logger.Println("couldn't retrieve stats:", err) 54 | } 55 | 56 | results := r.([]interface{}) 57 | 58 | if len(results) == 2 { 59 | stats.Processed, _ = strconv.Atoi(string(results[0].([]byte))) 60 | stats.Failed, _ = strconv.Atoi(string(results[1].([]byte))) 61 | } 62 | 63 | body, _ := json.MarshalIndent(stats, "", " ") 64 | fmt.Fprintln(w, string(body)) 65 | } 66 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/technoweenie/grohl/timer.go: -------------------------------------------------------------------------------- 1 | package grohl 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // A Timer tracks the duration spent since its creation. 8 | type Timer struct { 9 | Started time.Time 10 | TimeUnit string 11 | context *Context 12 | *_statter 13 | } 14 | 15 | // Creates a Timer from the current Context, with the given key/value data. 16 | func (c *Context) Timer(data Data) *Timer { 17 | context := c.New(data) 18 | context.Log(Data{"at": "start"}) 19 | return &Timer{ 20 | Started: time.Now(), 21 | TimeUnit: context.TimeUnit, 22 | context: context, 23 | _statter: c._statter.dup(), 24 | } 25 | } 26 | 27 | // Finish writes a final log message with the elapsed time shown. 28 | func (t *Timer) Finish() { 29 | t.Log(Data{"at": "finish"}) 30 | } 31 | 32 | // Log writes a log message with extra data or the elapsed time shown. Pass nil 33 | // or use Finish() if there is no extra data. 34 | func (t *Timer) Log(data Data) error { 35 | if data == nil { 36 | data = make(Data) 37 | } 38 | 39 | dur := t.Elapsed() 40 | 41 | if _, ok := data["elapsed"]; !ok { 42 | data["elapsed"] = t.durationUnit(dur) 43 | } 44 | 45 | t._statter.Timing(dur) 46 | return t.context.Log(data) 47 | } 48 | 49 | // Add adds the key and value to the Timer's Context. 50 | func (t *Timer) Add(key string, value interface{}) { 51 | t.context.Add(key, value) 52 | } 53 | 54 | // Elapsed returns the duration since the Timer was created. 55 | func (t *Timer) Elapsed() time.Duration { 56 | return time.Since(t.Started) 57 | } 58 | 59 | func (t *Timer) durationUnit(dur time.Duration) float64 { 60 | sec := dur.Seconds() 61 | if t.TimeUnit == "ms" { 62 | return sec * 1000 63 | } 64 | return sec 65 | } 66 | -------------------------------------------------------------------------------- /assets/stylesheets/modules/_code.scss: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------*/ 2 | /* Code */ 3 | 4 | .code-set { 5 | 6 | .code-feature { 7 | margin-bottom: $base * 4; 8 | 9 | &:last-of-type { 10 | margin-bottom: 0; 11 | } 12 | 13 | h5 { 14 | color: $blue; 15 | } 16 | 17 | .code-block { 18 | padding: ($base / 1.5) $base; 19 | 20 | font-family: $font-Code; 21 | font-size: 14px; 22 | 23 | border-radius: $radius; 24 | border: 1px solid $subtle-gray; 25 | background-color: lighten($subtle-gray, 10%); 26 | 27 | overflow-x: auto; 28 | word-wrap: normal; 29 | 30 | margin-bottom: $base; 31 | 32 | @include at-breakpoint($break) { 33 | font-size: 16px; 34 | } 35 | } 36 | } 37 | } 38 | 39 | table.code-params { 40 | overflow-x: scroll; 41 | margin-bottom: $base * 2; 42 | width: 100%; 43 | overflow: auto; 44 | border-collapse: collapse; 45 | border-spacing: 0; 46 | font-size: 14px; 47 | line-height: 1.8; 48 | 49 | @include at-breakpoint($break) { 50 | font-size: 16px; 51 | } 52 | 53 | th { 54 | padding: 9px 13px; 55 | font-weight: bold; 56 | text-align: left; 57 | color: $lighter-gray; 58 | font-size: 13px; 59 | text-transform: uppercase; 60 | letter-spacing: 0.4pt; 61 | border: 1px solid $lightest-gray; 62 | } 63 | 64 | tbody { 65 | vertical-align: middle; 66 | border-color: $lightest-gray; 67 | } 68 | 69 | tr { 70 | border-top: 1px solid $lightest-gray; 71 | vertical-align: inherit; 72 | } 73 | 74 | td { 75 | border: 1px solid $lightest-gray; 76 | padding: 6px 13px; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /assets/stylesheets/partials/_mixins.scss: -------------------------------------------------------------------------------- 1 | /*-----------------------------------*\ 2 | 3 | Partial: Mixins 4 | 5 | \*-----------------------------------*/ 6 | 7 | // SVG backgrounds with PNG fallback 8 | // All browsers that support multiple backgrounds also support SVGs. Woohoo! 9 | @mixin bg-image($image, $size: 16px, $repeat: no-repeat, $position: center) { 10 | background-image: image-url("#{$image}.png"); 11 | background-image: inline-image("#{$image}.min.svg"), none; 12 | 13 | background-size: $size; 14 | 15 | background-repeat: $repeat; 16 | 17 | background-position: $position; 18 | } 19 | 20 | // Image replacement technique 21 | @mixin image-replace { 22 | // Extra text indent to account for narrow parent widths 23 | text-indent: 200%; 24 | overflow: hidden; 25 | white-space: nowrap; 26 | } 27 | 28 | @mixin fade-slide-animation { 29 | opacity: 0; 30 | -webkit-transform: translateY(-20px); 31 | -moz-transform: translateY(-20px); 32 | transform: translateY(-20px); 33 | -webkit-animation: fadein 0.6s 0.5s 1 forwards ease-in-out; 34 | -moz-animation: fadein 0.6s 0.5s 1 forwards ease-in-out; 35 | animation: fadein 0.6s 0.5s 1 forwards ease-in-out; 36 | } 37 | 38 | @mixin deal-with-it-animation { 39 | opacity: 0; 40 | -webkit-transform: translateY(-80px); 41 | -moz-transform: translateY(-80px); 42 | transform: translateY(-80px); 43 | -webkit-animation: deal-with-it 0.8s 0.2s 1 forwards ease-in-out; 44 | -moz-animation: deal-with-it 0.8s 0.2s 1 forwards ease-in-out; 45 | animation: deal-with-it 0.8s 0.2s 1 forwards ease-in-out; 46 | } 47 | 48 | @mixin animation-stagger($time) { 49 | -webkit-animation-delay: $time; 50 | -moz-animation-delay: $time; 51 | animation-delay: $time; 52 | } 53 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/mattn/go-sqlite3/backup.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2014 Yasuhiro Matsumoto . 2 | // 3 | // Use of this source code is governed by an MIT-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package sqlite3 7 | 8 | /* 9 | #include 10 | #include 11 | */ 12 | import "C" 13 | import ( 14 | "unsafe" 15 | ) 16 | 17 | type Backup struct { 18 | b *C.sqlite3_backup 19 | } 20 | 21 | func (c *SQLiteConn) Backup(dest string, conn *SQLiteConn, src string) (*Backup, error) { 22 | destptr := C.CString(dest) 23 | defer C.free(unsafe.Pointer(destptr)) 24 | srcptr := C.CString(src) 25 | defer C.free(unsafe.Pointer(srcptr)) 26 | 27 | if b := C.sqlite3_backup_init(c.db, destptr, conn.db, srcptr); b != nil { 28 | return &Backup{b: b}, nil 29 | } 30 | return nil, c.lastError() 31 | } 32 | 33 | // Backs up for one step. Calls the underlying `sqlite3_backup_step` function. 34 | // This function returns a boolean indicating if the backup is done and 35 | // an error signalling any other error. Done is returned if the underlying C 36 | // function returns SQLITE_DONE (Code 101) 37 | func (b *Backup) Step(p int) (bool, error) { 38 | ret := C.sqlite3_backup_step(b.b, C.int(p)) 39 | if ret == C.SQLITE_DONE { 40 | return true, nil 41 | } else if ret != 0 { 42 | return false, Error{Code: ErrNo(ret)} 43 | } 44 | return false, nil 45 | } 46 | 47 | func (b *Backup) Remaining() int { 48 | return int(C.sqlite3_backup_remaining(b.b)) 49 | } 50 | 51 | func (b *Backup) PageCount() int { 52 | return int(C.sqlite3_backup_pagecount(b.b)) 53 | } 54 | 55 | func (b *Backup) Finish() error { 56 | ret := C.sqlite3_backup_finish(b.b) 57 | if ret != 0 { 58 | return Error{Code: ErrNo(ret)} 59 | } 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/garyburd/redigo/redis/redis.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Gary Burd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | package redis 16 | 17 | // Error represents an error returned in a command reply. 18 | type Error string 19 | 20 | func (err Error) Error() string { return string(err) } 21 | 22 | // Conn represents a connection to a Redis server. 23 | type Conn interface { 24 | // Close closes the connection. 25 | Close() error 26 | 27 | // Err returns a non-nil value if the connection is broken. The returned 28 | // value is either the first non-nil value returned from the underlying 29 | // network connection or a protocol parsing error. Applications should 30 | // close broken connections. 31 | Err() error 32 | 33 | // Do sends a command to the server and returns the received reply. 34 | Do(commandName string, args ...interface{}) (reply interface{}, err error) 35 | 36 | // Send writes the command to the client's output buffer. 37 | Send(commandName string, args ...interface{}) error 38 | 39 | // Flush flushes the output buffer to the Redis server. 40 | Flush() error 41 | 42 | // Receive receives a single reply from the Redis server 43 | Receive() (reply interface{}, err error) 44 | } 45 | -------------------------------------------------------------------------------- /lib/new_account_email_job.go: -------------------------------------------------------------------------------- 1 | package readraptor 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "text/template" 8 | "time" 9 | 10 | "github.com/sirsean/go-mailgun/mailgun" 11 | ) 12 | 13 | type NewAccountEmailJob struct { 14 | AccountId int64 15 | } 16 | 17 | func (j *NewAccountEmailJob) Perform() error { 18 | account, err := FindAccount(j.AccountId) 19 | if err != nil { 20 | return err 21 | } 22 | 23 | token := genKey("confirm" + account.Email) 24 | account.ConfirmationToken = &token 25 | 26 | message, err := j.CreateMessage(account) 27 | if err != nil { 28 | return err 29 | } 30 | 31 | _, err = dbmap.Exec( 32 | "update accounts set confirmation_token = $1, confirmation_sent_at = $2 where id = $3", 33 | token, 34 | time.Now().UTC(), 35 | j.AccountId, 36 | ) 37 | if err != nil { 38 | return err 39 | } 40 | 41 | if os.Getenv("MAILGUN_API_KEY") != "" { 42 | mg := mailgun.NewClient(os.Getenv("MAILGUN_API_KEY"), os.Getenv("MAILGUN_DOMAIN")) 43 | _, err := mg.Send(message) 44 | if err != nil { 45 | return err 46 | } 47 | } else { 48 | fmt.Println(message) 49 | } 50 | 51 | return nil 52 | } 53 | 54 | func (j *NewAccountEmailJob) CreateMessage(account *Account) (*mailgun.Message, error) { 55 | template, err := template.ParseFiles(os.Getenv("RR_ROOT") + "/templates/new_account_email.tmpl") 56 | if err != nil { 57 | return nil, err 58 | } 59 | 60 | var buf bytes.Buffer 61 | err = template.Execute(&buf, account) 62 | if err != nil { 63 | return nil, err 64 | } 65 | 66 | message := &mailgun.Message{ 67 | FromName: "Read Raptor", 68 | FromAddress: "admin@readraptor.com", 69 | ToAddress: account.Email, 70 | Subject: "Get started with Read Raptor", 71 | Body: buf.String(), 72 | } 73 | 74 | return message, nil 75 | } 76 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/certs/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEA14pMhfsXpTyP4HIRKc4/sB8/fcbuf6f8Ais1RwimPZDfXFYU 3 | lADHbdHS4mGVd7jjpmYx+R8hfWLhJ9qUN2FK6mNToGG4nLul4ue3ptgPBQTHKeLq 4 | SSt/3hUAphhwUMcM3pr5Wpaw4ZQGxm1KITu0D6VtkoY0sk7XDqcZwHcLe4fIkt5C 5 | /4bSt5qk1BUjyq2laSG4zn5my4Vdue2LLQmNlOQEHnLs79B2kBVapPeRS+nOTp1d 6 | mnAXnNjpc4PqPWGZps2skUBaiHflTiqOPRPz+ThvgWuKlcoOB6tv2rSM2f+qeAOq 7 | x8LPb2SS09iD1a/xIxinLnsXC+d98fqoQaMEVwIDAQABAoIBAF3ZoihUhJ82F4+r 8 | Gz4QyDpv4L1reT2sb1aiabhcU8ZK5nbWJG+tRyjSS/i2dNaEcttpdCj9HR/zhgZM 9 | bm0OuAgG58rVwgS80CZUruq++Qs+YVojq8/gWPTiQD4SNhV2Fmx3HkwLgUk3oxuT 10 | SsvdqzGE3okGVrutCIcgy126eA147VPMoej1Bb3fO6npqK0pFPhZfAc0YoqJuM+k 11 | obRm5pAnGUipyLCFXjA9HYPKwYZw2RtfdA3CiImHeanSdqS+ctrC9y8BV40Th7gZ 12 | haXdKUNdjmIxV695QQ1mkGqpKLZFqhzKioGQ2/Ly2d1iaKN9fZltTusu8unepWJ2 13 | tlT9qMECgYEA9uHaF1t2CqE+AJvWTihHhPIIuLxoOQXYea1qvxfcH/UMtaLKzCNm 14 | lQ5pqCGsPvp+10f36yttO1ZehIvlVNXuJsjt0zJmPtIolNuJY76yeussfQ9jHheB 15 | 5uPEzCFlHzxYbBUyqgWaF6W74okRGzEGJXjYSP0yHPPdU4ep2q3bGiUCgYEA34Af 16 | wBSuQSK7uLxArWHvQhyuvi43ZGXls6oRGl+Ysj54s8BP6XGkq9hEJ6G4yxgyV+BR 17 | DUOs5X8/TLT8POuIMYvKTQthQyCk0eLv2FLdESDuuKx0kBVY3s8lK3/z5HhrdOiN 18 | VMNZU+xDKgKc3hN9ypkk8vcZe6EtH7Y14e0rVcsCgYBTgxi8F/M5K0wG9rAqphNz 19 | VFBA9XKn/2M33cKjO5X5tXIEKzpAjaUQvNxexG04rJGljzG8+mar0M6ONahw5yD1 20 | O7i/XWgazgpuOEkkVYiYbd8RutfDgR4vFVMn3hAP3eDnRtBplRWH9Ec3HTiNIys6 21 | F8PKBOQjyRZQQC7jyzW3hQKBgACe5HeuFwXLSOYsb6mLmhR+6+VPT4wR1F95W27N 22 | USk9jyxAnngxfpmTkiziABdgS9N+pfr5cyN4BP77ia/Jn6kzkC5Cl9SN5KdIkA3z 23 | vPVtN/x/ThuQU5zaymmig1ThGLtMYggYOslG4LDfLPxY5YKIhle+Y+259twdr2yf 24 | Mf2dAoGAaGv3tWMgnIdGRk6EQL/yb9PKHo7ShN+tKNlGaK7WwzBdKs+Fe8jkgcr7 25 | pz4Ne887CmxejdISzOCcdT+Zm9Bx6I/uZwWOtDvWpIgIxVX9a9URj/+D1MxTE/y4 26 | d6H+c89yDY62I2+drMpdjCd3EtCaTlxpTbRS+s1eAHMH7aEkcCE= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/sessions/redis_store.go: -------------------------------------------------------------------------------- 1 | package sessions 2 | 3 | import ( 4 | "github.com/boj/redistore" 5 | "github.com/gorilla/sessions" 6 | ) 7 | 8 | // RedisStore is an interface that represents a Cookie based storage 9 | // for Sessions. 10 | type RediStore interface { 11 | // Store is an embedded interface so that RedisStore can be used 12 | // as a session store. 13 | Store 14 | // Options sets the default options for each session stored in this 15 | // CookieStore. 16 | Options(Options) 17 | } 18 | 19 | // NewCookieStore returns a new CookieStore. 20 | // 21 | // Keys are defined in pairs to allow key rotation, but the common case is to set a single 22 | // authentication key and optionally an encryption key. 23 | // 24 | // The first key in a pair is used for authentication and the second for encryption. The 25 | // encryption key can be set to nil or omitted in the last pair, but the authentication key 26 | // is required in all pairs. 27 | // 28 | // It is recommended to use an authentication key with 32 or 64 bytes. The encryption key, 29 | // if set, must be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256 modes. 30 | func NewRediStore(size int, network, address, password string, keyPairs ...[]byte) (RediStore, error) { 31 | store, err := redistore.NewRediStore(size, network, address, password, keyPairs...) 32 | if err != nil { 33 | return nil, err 34 | } 35 | return &rediStore{store}, nil 36 | } 37 | 38 | type rediStore struct { 39 | *redistore.RediStore 40 | } 41 | 42 | func (c *rediStore) Options(options Options) { 43 | c.RediStore.Options = &sessions.Options{ 44 | Path: options.Path, 45 | Domain: options.Domain, 46 | MaxAge: options.MaxAge, 47 | Secure: options.Secure, 48 | HttpOnly: options.HttpOnly, 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "flag" 6 | "fmt" 7 | "os" 8 | "strings" 9 | "text/template" 10 | ) 11 | 12 | // global options. available to any subcommands. 13 | var flagPath = flag.String("path", "db", "folder containing db info") 14 | var flagEnv = flag.String("env", "development", "which DB environment to use") 15 | var flagPgSchema = flag.String("pgschema", "", "which postgres-schema to migrate (default = none)") 16 | 17 | // helper to create a DBConf from the given flags 18 | func dbConfFromFlags() (dbconf *goose.DBConf, err error) { 19 | return goose.NewDBConf(*flagPath, *flagEnv, *flagPgSchema) 20 | } 21 | 22 | var commands = []*Command{ 23 | upCmd, 24 | downCmd, 25 | redoCmd, 26 | statusCmd, 27 | createCmd, 28 | dbVersionCmd, 29 | } 30 | 31 | func main() { 32 | 33 | flag.Usage = usage 34 | flag.Parse() 35 | 36 | args := flag.Args() 37 | if len(args) == 0 || args[0] == "-h" { 38 | flag.Usage() 39 | return 40 | } 41 | 42 | var cmd *Command 43 | name := args[0] 44 | for _, c := range commands { 45 | if strings.HasPrefix(c.Name, name) { 46 | cmd = c 47 | break 48 | } 49 | } 50 | 51 | if cmd == nil { 52 | fmt.Printf("error: unknown command %q\n", name) 53 | flag.Usage() 54 | os.Exit(1) 55 | } 56 | 57 | cmd.Exec(args[1:]) 58 | } 59 | 60 | func usage() { 61 | fmt.Print(usagePrefix) 62 | flag.PrintDefaults() 63 | usageTmpl.Execute(os.Stdout, commands) 64 | } 65 | 66 | var usagePrefix = ` 67 | goose is a database migration management system for Go projects. 68 | 69 | Usage: 70 | goose [options] [subcommand options] 71 | 72 | Options: 73 | ` 74 | var usageTmpl = template.Must(template.New("usage").Parse( 75 | ` 76 | Commands:{{range .}} 77 | {{.Name | printf "%-10s"}} {{.Summary}}{{end}} 78 | `)) 79 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/lib/goose/migrate_test.go: -------------------------------------------------------------------------------- 1 | package goose 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestMigrationMapSortUp(t *testing.T) { 8 | 9 | ms := migrationSorter{} 10 | 11 | // insert in any order 12 | ms = append(ms, newMigration(20120000, "test")) 13 | ms = append(ms, newMigration(20128000, "test")) 14 | ms = append(ms, newMigration(20129000, "test")) 15 | ms = append(ms, newMigration(20127000, "test")) 16 | 17 | ms.Sort(true) // sort Upwards 18 | 19 | sorted := []int64{20120000, 20127000, 20128000, 20129000} 20 | 21 | validateMigrationSort(t, ms, sorted) 22 | } 23 | 24 | func TestMigrationMapSortDown(t *testing.T) { 25 | 26 | ms := migrationSorter{} 27 | 28 | // insert in any order 29 | ms = append(ms, newMigration(20120000, "test")) 30 | ms = append(ms, newMigration(20128000, "test")) 31 | ms = append(ms, newMigration(20129000, "test")) 32 | ms = append(ms, newMigration(20127000, "test")) 33 | 34 | ms.Sort(false) // sort Downwards 35 | 36 | sorted := []int64{20129000, 20128000, 20127000, 20120000} 37 | 38 | validateMigrationSort(t, ms, sorted) 39 | } 40 | 41 | func validateMigrationSort(t *testing.T, ms migrationSorter, sorted []int64) { 42 | 43 | for i, m := range ms { 44 | if sorted[i] != m.Version { 45 | t.Error("incorrect sorted version") 46 | } 47 | 48 | var next, prev int64 49 | 50 | if i == 0 { 51 | prev = -1 52 | next = ms[i+1].Version 53 | } else if i == len(ms)-1 { 54 | prev = ms[i-1].Version 55 | next = -1 56 | } else { 57 | prev = ms[i-1].Version 58 | next = ms[i+1].Version 59 | } 60 | 61 | if m.Next != next { 62 | t.Errorf("mismatched Next. v: %v, got %v, wanted %v\n", m, m.Next, next) 63 | } 64 | 65 | if m.Previous != prev { 66 | t.Errorf("mismatched Previous v: %v, got %v, wanted %v\n", m, m.Previous, prev) 67 | } 68 | } 69 | 70 | t.Log(ms) 71 | } 72 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/config.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "github.com/garyburd/redigo/redis" 5 | "strconv" 6 | "time" 7 | ) 8 | 9 | type config struct { 10 | processId string 11 | Namespace string 12 | Pool *redis.Pool 13 | Fetch func(queue string) Fetcher 14 | } 15 | 16 | var Config *config 17 | 18 | func Configure(options map[string]string) { 19 | var poolSize int 20 | var namespace string 21 | 22 | if options["server"] == "" { 23 | panic("Configure requires a 'server' option, which identifies a Redis instance") 24 | } 25 | if options["process"] == "" { 26 | panic("Configure requires a 'process' option, which uniquely identifies this instance") 27 | } 28 | if options["pool"] == "" { 29 | options["pool"] = "1" 30 | } 31 | if options["namespace"] != "" { 32 | namespace = options["namespace"] + ":" 33 | } 34 | 35 | poolSize, _ = strconv.Atoi(options["pool"]) 36 | 37 | Config = &config{ 38 | options["process"], 39 | namespace, 40 | &redis.Pool{ 41 | MaxIdle: poolSize, 42 | IdleTimeout: 240 * time.Second, 43 | Dial: func() (redis.Conn, error) { 44 | c, err := redis.Dial("tcp", options["server"]) 45 | if err != nil { 46 | return nil, err 47 | } 48 | if options["password"] != "" { 49 | if _, err := c.Do("AUTH", options["password"]); err != nil { 50 | c.Close() 51 | return nil, err 52 | } 53 | } 54 | if options["database"] != "" { 55 | if _, err := c.Do("SELECT", options["database"]); err != nil { 56 | c.Close() 57 | return nil, err 58 | } 59 | } 60 | return c, err 61 | }, 62 | TestOnBorrow: func(c redis.Conn, t time.Time) error { 63 | _, err := c.Do("PING") 64 | return err 65 | }, 66 | }, 67 | func(queue string) Fetcher { 68 | return NewFetch(queue, make(chan *Msg), make(chan bool)) 69 | }, 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/enqueue.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "time" 9 | ) 10 | 11 | type EnqueueData struct { 12 | Queue string `json:"queue,omitempty"` 13 | Class string `json:"class"` 14 | Args interface{} `json:"args"` 15 | Jid string `json:"jid"` 16 | EnqueuedAt float64 `json:"enqueued_at"` 17 | EnqueueOptions 18 | } 19 | 20 | type EnqueueOptions struct { 21 | RetryCount int `json:"retry_count,omitempty"` 22 | Retry bool `json:"retry,omitempty"` 23 | At float64 `json:"at,omitempty"` 24 | } 25 | 26 | func generateJid() string { 27 | // Return 12 random bytes as 24 character hex 28 | b := make([]byte, 12) 29 | _, err := io.ReadFull(rand.Reader, b) 30 | if err != nil { 31 | return "" 32 | } 33 | return fmt.Sprintf("%x", b) 34 | } 35 | 36 | func Enqueue(queue, class string, args interface{}) (string, error) { 37 | return EnqueueWithOptions(queue, class, args, EnqueueOptions{}) 38 | } 39 | 40 | func EnqueueWithOptions(queue, class string, args interface{}, opts EnqueueOptions) (string, error) { 41 | conn := Config.Pool.Get() 42 | defer conn.Close() 43 | 44 | data := EnqueueData{ 45 | Queue: queue, 46 | Class: class, 47 | Args: args, 48 | Jid: generateJid(), 49 | EnqueuedAt: float64(time.Now().UnixNano()) / 1000000000, 50 | EnqueueOptions: opts, 51 | } 52 | bytes, err := json.Marshal(data) 53 | if err != nil { 54 | return "", err 55 | } 56 | 57 | _, err = conn.Do("sadd", Config.Namespace+"queues", queue) 58 | if err != nil { 59 | return "", err 60 | } 61 | queue = Config.Namespace + "queue:" + queue 62 | _, err = conn.Do("rpush", queue, bytes) 63 | if err != nil { 64 | return "", err 65 | } 66 | 67 | return data.Jid, nil 68 | return "", err 69 | } 70 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/jrallison/go-workers/config_test.go: -------------------------------------------------------------------------------- 1 | package workers 2 | 3 | import ( 4 | "github.com/customerio/gospec" 5 | . "github.com/customerio/gospec" 6 | ) 7 | 8 | func ConfigSpec(c gospec.Context) { 9 | var recoverOnPanic = func(f func()) (err interface{}) { 10 | defer func() { 11 | if cause := recover(); cause != nil { 12 | err = cause 13 | } 14 | }() 15 | 16 | f() 17 | 18 | return 19 | } 20 | 21 | c.Specify("sets redis pool size which defaults to 1", func() { 22 | c.Expect(Config.Pool.MaxIdle, Equals, 1) 23 | 24 | Configure(map[string]string{ 25 | "server": "localhost:6379", 26 | "process": "1", 27 | "pool": "20", 28 | }) 29 | 30 | c.Expect(Config.Pool.MaxIdle, Equals, 20) 31 | }) 32 | 33 | c.Specify("can specify custom process", func() { 34 | c.Expect(Config.processId, Equals, "1") 35 | 36 | Configure(map[string]string{ 37 | "server": "localhost:6379", 38 | "process": "2", 39 | }) 40 | 41 | c.Expect(Config.processId, Equals, "2") 42 | }) 43 | 44 | c.Specify("requires a server parameter", func() { 45 | err := recoverOnPanic(func() { 46 | Configure(map[string]string{"process": "2"}) 47 | }) 48 | 49 | c.Expect(err, Equals, "Configure requires a 'server' option, which identifies a Redis instance") 50 | }) 51 | 52 | c.Specify("requires a process parameter", func() { 53 | err := recoverOnPanic(func() { 54 | Configure(map[string]string{"server": "localhost:6379"}) 55 | }) 56 | 57 | c.Expect(err, Equals, "Configure requires a 'process' option, which uniquely identifies this instance") 58 | }) 59 | 60 | c.Specify("adds ':' to the end of the namespace", func() { 61 | c.Expect(Config.Namespace, Equals, "") 62 | 63 | Configure(map[string]string{ 64 | "server": "localhost:6379", 65 | "process": "1", 66 | "namespace": "prod", 67 | }) 68 | 69 | c.Expect(Config.Namespace, Equals, "prod:") 70 | }) 71 | } 72 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/garyburd/redigo/internal/redistest/testdb.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Gary Burd 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 | // not use this file except in compliance with the License. You may obtain 5 | // a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 | // License for the specific language governing permissions and limitations 13 | // under the License. 14 | 15 | // Package redistest contains utilities for writing Redigo tests. 16 | package redistest 17 | 18 | import ( 19 | "errors" 20 | "time" 21 | 22 | "github.com/garyburd/redigo/redis" 23 | ) 24 | 25 | type testConn struct { 26 | redis.Conn 27 | } 28 | 29 | func (t testConn) Close() error { 30 | _, err := t.Conn.Do("SELECT", "9") 31 | if err != nil { 32 | return nil 33 | } 34 | _, err = t.Conn.Do("FLUSHDB") 35 | if err != nil { 36 | return err 37 | } 38 | return t.Conn.Close() 39 | } 40 | 41 | // Dial dials the local Redis server and selects database 9. To prevent 42 | // stomping on real data, DialTestDB fails if database 9 contains data. The 43 | // returned connection flushes database 9 on close. 44 | func Dial() (redis.Conn, error) { 45 | c, err := redis.DialTimeout("tcp", ":6379", 0, 1*time.Second, 1*time.Second) 46 | if err != nil { 47 | return nil, err 48 | } 49 | 50 | _, err = c.Do("SELECT", "9") 51 | if err != nil { 52 | return nil, err 53 | } 54 | 55 | n, err := redis.Int(c.Do("DBSIZE")) 56 | if err != nil { 57 | return nil, err 58 | } 59 | 60 | if n != 0 { 61 | return nil, errors.New("database #9 is not empty, test can not continue") 62 | } 63 | 64 | return testConn{c}, nil 65 | } 66 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/bradrydzewski/go.stripe/token.go: -------------------------------------------------------------------------------- 1 | package stripe 2 | 3 | import ( 4 | "net/url" 5 | ) 6 | 7 | // Token represents a unique identifier for a credit card that can be safely 8 | // stored without having to hold sensitive card information on your own servers. 9 | // 10 | // see https://stripe.com/docs/api#token_object 11 | type Token struct { 12 | Id string `json:"id"` 13 | Amount int64 `json:"amount"` 14 | Currency string `json:"currency"` 15 | Card *Card `json:"card"` 16 | Created int64 `json:"created"` 17 | Used bool `json:"used"` 18 | Livemode bool `json:"livemode"` 19 | } 20 | 21 | // TokenClient encapsulates operations for creating and querying tokens using 22 | // the Stripe REST API. 23 | type TokenClient struct{} 24 | 25 | // TokenParams encapsulates options for creating a new Card Token. 26 | type TokenParams struct { 27 | //Currency string REMOVED! no longer part of the API 28 | Card *CardParams 29 | } 30 | 31 | // Creates a single use token that wraps the details of a credit card. 32 | // This token can be used in place of a credit card hash with any API method. 33 | // These tokens can only be used once: by creating a new charge object, or 34 | // attaching them to a customer. 35 | // 36 | // see https://stripe.com/docs/api#create_token 37 | func (self *TokenClient) Create(params *TokenParams) (*Token, error) { 38 | token := Token{} 39 | values := url.Values{} // REMOVED "currency": {params.Currency}} 40 | appendCardParamsToValues(params.Card, &values) 41 | 42 | err := query("POST", "/v1/tokens", values, &token) 43 | return &token, err 44 | } 45 | 46 | // Retrieves the card token with the given Id. 47 | // 48 | // see https://stripe.com/docs/api#retrieve_token 49 | func (self *TokenClient) Retrieve(id string) (*Token, error) { 50 | token := Token{} 51 | path := "/v1/tokens/" + url.QueryEscape(id) 52 | err := query("GET", path, nil, &token) 53 | return &token, err 54 | } 55 | -------------------------------------------------------------------------------- /assets/stylesheets/style.scss: -------------------------------------------------------------------------------- 1 | // --------------------------------------------------------------------------- 2 | // Imports 3 | 4 | @import "partials/variables"; 5 | @import "modules/base"; 6 | 7 | @import "partials/all"; 8 | @import "modules/all"; 9 | 10 | 11 | /*===================================*\ 12 | Sass Authoring Rules 13 | -------------------- 14 | 15 | Some basic guidelines (that may be broken) for authoring manageable, readable Sass styles: 16 | 17 | .block { 18 | // 1. Layout Properties 19 | // display, width, padding, margin, vertical-align, box-sizing, etc. 20 | // Note: Bracketed expression values - such as calc() or linear-gradient() - must have spaces [e.g. calc( 100% + 2rem )] for Grunt tasks to run properly 21 | 22 | // 2. Typography Properties 23 | // font[-size, -weight, etc], line-height, text-align, letter-spacing, white-space, etc. 24 | 25 | // 3. Appearance Properties 26 | // color, box-shadow, background, border, text-shadow, opacity, etc. 27 | 28 | // 4. UI Properties 29 | // appearance, cursor, pointer-events, etc. 30 | 31 | // Child elements are not always (and shouldn't be) nested in the parent block 32 | .block__child { 33 | 34 | // Modifiers are almost always nested in their parent element 35 | &.block__child--modifier { 36 | 37 | } 38 | 39 | &:after { 40 | // 'content' counts as a layout property 41 | } 42 | 43 | } 44 | } 45 | 46 | Full Example: 47 | 48 | .block { 49 | width: 100%; 50 | 51 | font-size: 1rem; 52 | font-weight: 400; 53 | 54 | color: $blue; 55 | 56 | .block__child { 57 | display: inline-block; 58 | 59 | &.block__child--modifier { 60 | color: $gray; 61 | } 62 | 63 | &:after { 64 | content: ''; 65 | padding: 1.5rem; 66 | 67 | cursor: pointer; 68 | } 69 | } 70 | } 71 | 72 | \*===================================*/ 73 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/lib/pq/url.go: -------------------------------------------------------------------------------- 1 | package pq 2 | 3 | import ( 4 | "fmt" 5 | nurl "net/url" 6 | "sort" 7 | "strings" 8 | ) 9 | 10 | // ParseURL no longer needs to be used by clients of this library since supplying a URL as a 11 | // connection string to sql.Open() is now supported: 12 | // 13 | // sql.Open("postgres", "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full") 14 | // 15 | // It remains exported here for backwards-compatibility. 16 | // 17 | // ParseURL converts a url to a connection string for driver.Open. 18 | // Example: 19 | // 20 | // "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full" 21 | // 22 | // converts to: 23 | // 24 | // "user=bob password=secret host=1.2.3.4 port=5432 dbname=mydb sslmode=verify-full" 25 | // 26 | // A minimal example: 27 | // 28 | // "postgres://" 29 | // 30 | // This will be blank, causing driver.Open to use all of the defaults 31 | func ParseURL(url string) (string, error) { 32 | u, err := nurl.Parse(url) 33 | if err != nil { 34 | return "", err 35 | } 36 | 37 | if u.Scheme != "postgres" { 38 | return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme) 39 | } 40 | 41 | var kvs []string 42 | escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`) 43 | accrue := func(k, v string) { 44 | if v != "" { 45 | kvs = append(kvs, k+"="+escaper.Replace(v)) 46 | } 47 | } 48 | 49 | if u.User != nil { 50 | v := u.User.Username() 51 | accrue("user", v) 52 | 53 | v, _ = u.User.Password() 54 | accrue("password", v) 55 | } 56 | 57 | i := strings.Index(u.Host, ":") 58 | if i < 0 { 59 | accrue("host", u.Host) 60 | } else { 61 | accrue("host", u.Host[:i]) 62 | accrue("port", u.Host[i+1:]) 63 | } 64 | 65 | if u.Path != "" { 66 | accrue("dbname", u.Path[1:]) 67 | } 68 | 69 | q := u.Query() 70 | for k := range q { 71 | accrue(k, q.Get(k)) 72 | } 73 | 74 | sort.Strings(kvs) // Makes testing easier (not a performance concern) 75 | return strings.Join(kvs, " "), nil 76 | } 77 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/sirsean/go-mailgun/mailgun/mailgun.go: -------------------------------------------------------------------------------- 1 | package mailgun 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | // Client is the base configuration for the Mailgun connection. 11 | type Client struct { 12 | ApiKey string 13 | Domain string 14 | Hostname string // this is mostly for testing purposes 15 | } 16 | 17 | // MailgunMessage is used for those things that are "sendable" 18 | // to a Mailgun endpoint 19 | type MailgunMessage interface { 20 | IsValid() bool 21 | GetRequest(Client) *http.Request 22 | Endpoint() string 23 | } 24 | 25 | // NewClient creates a new Client using the API key and Domain passed in 26 | func NewClient(apikey, domain string) *Client { 27 | return &Client{ApiKey: apikey, Domain: domain, Hostname: "https://api.mailgun.net"} 28 | } 29 | 30 | // Endpoint returns the URL to the Mailgun API for the MailgunMessage type that 31 | // is being used. 32 | func (mailgun Client) Endpoint(m MailgunMessage) string { 33 | return fmt.Sprintf("%s/v2/%s/%s", mailgun.Hostname, mailgun.Domain, m.Endpoint()) 34 | } 35 | 36 | // Send processes a MailgunMessage and emits it to Mailgun for processing. If 37 | // there is no error, it will return the text that the Mailgun endpoint returns. 38 | func (mailgun Client) Send(message MailgunMessage) (result string, err error) { 39 | client := &http.Client{} 40 | 41 | if !message.IsValid() { 42 | log.Print("Mailgun.Send did not receive a valid Message object!") 43 | return 44 | } 45 | 46 | request := message.GetRequest(mailgun) 47 | request.SetBasicAuth("api", mailgun.ApiKey) 48 | request.Close = true 49 | 50 | response, err := client.Do(request) 51 | if err != nil { 52 | log.Fatal("Failed to send request: ", err) 53 | return 54 | } 55 | defer response.Body.Close() 56 | 57 | body_bytes, err := ioutil.ReadAll(response.Body) 58 | if err != nil { 59 | log.Fatal("Failed to read response: ", err) 60 | return 61 | } 62 | 63 | return string(body_bytes), nil 64 | } 65 | -------------------------------------------------------------------------------- /assets/stylesheets/modules/_jumbotron.scss: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------------------------------------*/ 2 | /* Jumbotron */ 3 | 4 | .jumbotron { 5 | @include background(image-url("/assets/images/jumbotron-bg.png"), linear-gradient(-45deg, $gradient-from, $gradient-to)); 6 | 7 | color: $white; 8 | 9 | position: relative; 10 | overflow: hidden; 11 | 12 | .raptored { 13 | @include background(image-url("/assets/images/raptor.png")); 14 | background-position: 0 0; 15 | background-repeat: no-repeat; 16 | 17 | width: 421px; 18 | height: 356px; 19 | position: absolute; 20 | right: -280px; 21 | top: 27px; 22 | z-index: 10; 23 | 24 | @include at-breakpoint($break) { 25 | right: -50px; 26 | top: 67px; 27 | } 28 | 29 | .deal-with-it { 30 | @include deal-with-it-animation; 31 | 32 | @include background(image-url("/assets/images/deal-with-it.png")); 33 | background-position: 0 0; 34 | background-repeat: no-repeat; 35 | 36 | width: 128px; 37 | height: 20px; 38 | position: absolute; 39 | left: 20px; 40 | top: 10px; 41 | z-index: 11; 42 | } 43 | } 44 | 45 | hgroup { 46 | @include at-breakpoint($break) { 47 | @include span-columns(7,12); 48 | } 49 | 50 | @include span-columns(10,12); 51 | padding: ($base * 4) 0; 52 | } 53 | 54 | h1, 55 | h2 { 56 | text-align: left; 57 | color: inherit; 58 | } 59 | 60 | .badge { 61 | padding: .3em .5em; 62 | 63 | font-size: 30%; 64 | text-transform: uppercase; 65 | vertical-align: middle; 66 | letter-spacing: 1pt; 67 | 68 | background-color: rgba($dark-gray, 0.5); 69 | border-radius: $radius; 70 | } 71 | 72 | .addendum { 73 | padding: 30px 0; 74 | 75 | font-size: 21px; 76 | 77 | background-color: rgba(darken($addendum, 25%), 0.6); 78 | 79 | p { 80 | margin-bottom: 0; 81 | 82 | & + p { 83 | margin-top: $base; 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/martini-contrib/sessions/benchmarks_test.go: -------------------------------------------------------------------------------- 1 | package sessions 2 | 3 | import ( 4 | "github.com/go-martini/martini" 5 | "net/http" 6 | "net/http/httptest" 7 | "testing" 8 | ) 9 | 10 | func BenchmarkNoSessionsMiddleware(b *testing.B) { 11 | m := testMartini() 12 | m.Get("/foo", func() string { 13 | return "Foo" 14 | }) 15 | 16 | recorder := httptest.NewRecorder() 17 | r, _ := http.NewRequest("GET", "/foo", nil) 18 | 19 | b.ResetTimer() 20 | for n := 0; n < b.N; n++ { 21 | m.ServeHTTP(recorder, r) 22 | } 23 | } 24 | 25 | func BenchmarkSessionsNoWrites(b *testing.B) { 26 | m := testMartini() 27 | store := NewCookieStore([]byte("secret123")) 28 | m.Use(Sessions("my_session", store)) 29 | m.Get("/foo", func() string { 30 | return "Foo" 31 | }) 32 | 33 | recorder := httptest.NewRecorder() 34 | r, _ := http.NewRequest("GET", "/foo", nil) 35 | 36 | b.ResetTimer() 37 | for n := 0; n < b.N; n++ { 38 | m.ServeHTTP(recorder, r) 39 | } 40 | } 41 | 42 | func BenchmarkSessionsWithWrite(b *testing.B) { 43 | m := testMartini() 44 | store := NewCookieStore([]byte("secret123")) 45 | m.Use(Sessions("my_session", store)) 46 | m.Get("/foo", func(s Session) string { 47 | s.Set("foo", "bar") 48 | return "Foo" 49 | }) 50 | 51 | recorder := httptest.NewRecorder() 52 | r, _ := http.NewRequest("GET", "/foo", nil) 53 | 54 | b.ResetTimer() 55 | for n := 0; n < b.N; n++ { 56 | m.ServeHTTP(recorder, r) 57 | } 58 | } 59 | 60 | func BenchmarkSessionsWithRead(b *testing.B) { 61 | m := testMartini() 62 | store := NewCookieStore([]byte("secret123")) 63 | m.Use(Sessions("my_session", store)) 64 | m.Get("/foo", func(s Session) string { 65 | s.Get("foo") 66 | return "Foo" 67 | }) 68 | 69 | recorder := httptest.NewRecorder() 70 | r, _ := http.NewRequest("GET", "/foo", nil) 71 | 72 | b.ResetTimer() 73 | for n := 0; n < b.N; n++ { 74 | m.ServeHTTP(recorder, r) 75 | } 76 | } 77 | 78 | func testMartini() *martini.ClassicMartini { 79 | m := martini.Classic() 80 | m.Handlers() 81 | return m 82 | } 83 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/lib/goose/dbconf_test.go: -------------------------------------------------------------------------------- 1 | package goose 2 | 3 | import ( 4 | "os" 5 | "reflect" 6 | "testing" 7 | ) 8 | 9 | func TestBasics(t *testing.T) { 10 | 11 | dbconf, err := NewDBConf("../../db-sample", "test", "") 12 | if err != nil { 13 | t.Fatal(err) 14 | } 15 | 16 | got := []string{dbconf.MigrationsDir, dbconf.Env, dbconf.Driver.Name, dbconf.Driver.OpenStr} 17 | want := []string{"../../db-sample/migrations", "test", "postgres", "user=liam dbname=tester sslmode=disable"} 18 | 19 | for i, s := range got { 20 | if s != want[i] { 21 | t.Errorf("Unexpected DBConf value. got %v, want %v", s, want[i]) 22 | } 23 | } 24 | } 25 | 26 | func TestImportOverride(t *testing.T) { 27 | 28 | dbconf, err := NewDBConf("../../db-sample", "customimport", "") 29 | if err != nil { 30 | t.Fatal(err) 31 | } 32 | 33 | got := dbconf.Driver.Import 34 | want := "github.com/custom/driver" 35 | if got != want { 36 | t.Errorf("bad custom import. got %v want %v", got, want) 37 | } 38 | } 39 | 40 | func TestDriverSetFromEnvironmentVariable(t *testing.T) { 41 | 42 | databaseUrlEnvVariableKey := "DB_DRIVER" 43 | databaseUrlEnvVariableVal := "sqlite3" 44 | databaseOpenStringKey := "DATABASE_URL" 45 | databaseOpenStringVal := "db.db" 46 | 47 | os.Setenv(databaseUrlEnvVariableKey, databaseUrlEnvVariableVal) 48 | os.Setenv(databaseOpenStringKey, databaseOpenStringVal) 49 | 50 | dbconf, err := NewDBConf("../../db-sample", "environment_variable_config", "") 51 | if err != nil { 52 | t.Fatal(err) 53 | } 54 | 55 | got := reflect.TypeOf(dbconf.Driver.Dialect) 56 | want := reflect.TypeOf(&Sqlite3Dialect{}) 57 | 58 | if got != want { 59 | t.Errorf("Not able to read the driver type from environment variable."+ 60 | "got %v want %v", got, want) 61 | } 62 | 63 | gotOpenString := dbconf.Driver.OpenStr 64 | wantOpenString := databaseOpenStringVal 65 | 66 | if gotOpenString != wantOpenString { 67 | t.Errorf("Not able to read the open string from the environment."+ 68 | "got %v want %v", gotOpenString, wantOpenString) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /lib/hub.go: -------------------------------------------------------------------------------- 1 | package readraptor 2 | 3 | import "fmt" 4 | 5 | // Hub maintains the set of active websocket connections 6 | type Hub struct { 7 | // Registered connections. 8 | connections map[*wsconn]bool 9 | 10 | subscriptions map[int64]*wsconn 11 | 12 | // Inbound messages from the connections. 13 | broadcast chan *Broadcast 14 | 15 | // Register requests from the connections. 16 | register chan *wsconn 17 | 18 | // Unregister requests from connections. 19 | unregister chan *wsconn 20 | 21 | // Register distinct id listening channel 22 | subscribe chan *Channel 23 | 24 | // Unregister distinct id listening channel 25 | unsubscribe chan *Channel 26 | } 27 | 28 | type Broadcast struct { 29 | ConnIds []int64 30 | Message []byte 31 | } 32 | 33 | type Channel struct { 34 | Conn *wsconn 35 | Id int64 36 | } 37 | 38 | var hub = Hub{ 39 | broadcast: make(chan *Broadcast), 40 | register: make(chan *wsconn), 41 | subscribe: make(chan *Channel), 42 | unsubscribe: make(chan *Channel), 43 | unregister: make(chan *wsconn), 44 | 45 | connections: make(map[*wsconn]bool), 46 | subscriptions: make(map[int64]*wsconn), 47 | } 48 | 49 | func (h *Hub) run() { 50 | for { 51 | select { 52 | case c := <-h.register: 53 | h.connections[c] = true 54 | case c := <-h.unregister: 55 | if _, ok := h.connections[c]; ok { 56 | delete(h.connections, c) 57 | close(c.send) 58 | 59 | for k, v := range h.subscriptions { 60 | if v == c { 61 | fmt.Println("removing", k) 62 | delete(h.subscriptions, k) 63 | } 64 | } 65 | } 66 | case c := <-h.subscribe: 67 | h.subscriptions[c.Id] = c.Conn 68 | case c := <-h.unsubscribe: 69 | if _, ok := h.subscriptions[c.Id]; ok { 70 | fmt.Println("unsubscribe", c.Id) 71 | delete(h.subscriptions, c.Id) 72 | } 73 | case b := <-h.broadcast: 74 | for _, id := range b.ConnIds { 75 | if c, ok := h.subscriptions[id]; ok { 76 | select { 77 | case c.send <- b.Message: 78 | default: 79 | close(c.send) 80 | delete(h.connections, c) 81 | } 82 | } 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/sirsean/go-mailgun/mailgun/mime_message.go: -------------------------------------------------------------------------------- 1 | package mailgun 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "log" 8 | "mime/multipart" 9 | "net/http" 10 | ) 11 | 12 | // MimeMessage is the structure for communicating a MIME message to Mailgun. 13 | type MimeMessage struct { 14 | ToAddress string 15 | Content []byte 16 | } 17 | 18 | // IsValid verifies that the Message has all of the required 19 | // fields filled in 20 | func (message MimeMessage) IsValid() (validity bool) { 21 | if message.ToAddress == "" || string(message.Content) == "" { 22 | return false 23 | } 24 | 25 | return true 26 | } 27 | 28 | // MimeReader returns a reader from which the MIME email may be read. Mailgun 29 | // requires a different header and multipart message when talking to the MIME 30 | // endpoint. 31 | func (message MimeMessage) MimeReader() (b io.Reader, boundary string) { 32 | buffer := new(bytes.Buffer) 33 | mimeWriter := multipart.NewWriter(buffer) 34 | boundary = mimeWriter.Boundary() 35 | 36 | go func() { 37 | defer mimeWriter.Close() 38 | mimeWriter.WriteField("to", message.ToAddress) 39 | 40 | messageField, err := mimeWriter.CreateFormFile("message", "message.mime") 41 | if err != nil { 42 | log.Fatal("Could not create MIME part for the 'message' field!") 43 | } 44 | messageField.Write(message.Content) 45 | }() 46 | 47 | return buffer, boundary 48 | } 49 | 50 | // GetRequest returns a skeleton http.Request refernce with the Content-Type 51 | // header filled in, along with the formatting required for this type of Message 52 | func (message MimeMessage) GetRequest(mailgun Client) (request *http.Request) { 53 | mimeReader, boundary := message.MimeReader() 54 | request, _ = http.NewRequest("POST", mailgun.Endpoint(message), mimeReader) 55 | request.Header.Set("content-type", fmt.Sprintf("multipart/form-data; boundary=%s", boundary)) 56 | return 57 | } 58 | 59 | // Endpoint returns the final part of the path required for creating 60 | // the Mailgun URL for this type of Message 61 | func (message MimeMessage) Endpoint() string { 62 | return "messages.mime" 63 | } 64 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/technoweenie/grohl/context.go: -------------------------------------------------------------------------------- 1 | package grohl 2 | 3 | // A Context holds default key/value data that merges with the data every Log() 4 | // call receives. 5 | type Context struct { 6 | data Data 7 | Logger Logger 8 | TimeUnit string 9 | ErrorReporter ErrorReporter 10 | *_statter 11 | } 12 | 13 | // Log merges the given data with the Context's data, and passes it to the 14 | // Logger. 15 | func (c *Context) Log(data Data) error { 16 | return c.Logger.Log(c.Merge(data)) 17 | } 18 | 19 | func (c *Context) log(data Data) error { 20 | return c.Logger.Log(data) 21 | } 22 | 23 | // New creates a duplicate Context object, merging the given data with the 24 | // Context's data. 25 | func (c *Context) New(data Data) *Context { 26 | return newContext(c.Merge(data), c.Logger, c.TimeUnit, c.ErrorReporter, c._statter.dup()) 27 | } 28 | 29 | // Add adds the key and value to the Context's data. 30 | func (c *Context) Add(key string, value interface{}) { 31 | c.data[key] = value 32 | } 33 | 34 | // Merge combines the given key/value data with the Context's data. If no data 35 | // is given, a clean duplicate of the Context's data is returned. 36 | func (c *Context) Merge(data Data) Data { 37 | if data == nil { 38 | return dupeMaps(c.data) 39 | } else { 40 | return dupeMaps(c.data, data) 41 | } 42 | } 43 | 44 | // Data returns the Context's current Data. 45 | func (c *Context) Data() Data { 46 | return c.data 47 | } 48 | 49 | // Delete removes the key from the Context's data. 50 | func (c *Context) Delete(key string) { 51 | delete(c.data, key) 52 | } 53 | 54 | func dupeMaps(maps ...Data) Data { 55 | merged := make(Data) 56 | for _, orig := range maps { 57 | for key, value := range orig { 58 | merged[key] = value 59 | } 60 | } 61 | return merged 62 | } 63 | 64 | func newContext(data Data, logger Logger, timeunit string, reporter ErrorReporter, statter *_statter) *Context { 65 | return &Context{ 66 | data: data, 67 | Logger: logger, 68 | TimeUnit: timeunit, 69 | ErrorReporter: reporter, 70 | _statter: statter, 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/bitbucket.org/liamstask/goose/cmd/goose/cmd_status.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bitbucket.org/liamstask/goose/lib/goose" 5 | "database/sql" 6 | "fmt" 7 | "log" 8 | "path/filepath" 9 | "time" 10 | ) 11 | 12 | var statusCmd = &Command{ 13 | Name: "status", 14 | Usage: "", 15 | Summary: "dump the migration status for the current DB", 16 | Help: `status extended help here...`, 17 | Run: statusRun, 18 | } 19 | 20 | type StatusData struct { 21 | Source string 22 | Status string 23 | } 24 | 25 | func statusRun(cmd *Command, args ...string) { 26 | 27 | conf, err := dbConfFromFlags() 28 | if err != nil { 29 | log.Fatal(err) 30 | } 31 | 32 | // collect all migrations 33 | min := int64(0) 34 | max := int64((1 << 63) - 1) 35 | migrations, e := goose.CollectMigrations(conf.MigrationsDir, min, max) 36 | if e != nil { 37 | log.Fatal(e) 38 | } 39 | 40 | db, e := goose.OpenDBFromDBConf(conf) 41 | if e != nil { 42 | log.Fatal("couldn't open DB:", e) 43 | } 44 | defer db.Close() 45 | 46 | // must ensure that the version table exists if we're running on a pristine DB 47 | if _, e := goose.EnsureDBVersion(conf, db); e != nil { 48 | log.Fatal(e) 49 | } 50 | 51 | fmt.Printf("goose: status for environment '%v'\n", conf.Env) 52 | fmt.Println(" Applied At Migration") 53 | fmt.Println(" =======================================") 54 | for _, m := range migrations { 55 | printMigrationStatus(db, m.Version, filepath.Base(m.Source)) 56 | } 57 | } 58 | 59 | func printMigrationStatus(db *sql.DB, version int64, script string) { 60 | var row goose.MigrationRecord 61 | q := fmt.Sprintf("SELECT tstamp, is_applied FROM goose_db_version WHERE version_id=%d ORDER BY tstamp DESC LIMIT 1", version) 62 | e := db.QueryRow(q).Scan(&row.TStamp, &row.IsApplied) 63 | 64 | if e != nil && e != sql.ErrNoRows { 65 | log.Fatal(e) 66 | } 67 | 68 | var appliedAt string 69 | 70 | if row.IsApplied { 71 | appliedAt = row.TStamp.Format(time.ANSIC) 72 | } else { 73 | appliedAt = "Pending" 74 | } 75 | 76 | fmt.Printf(" %-24s -- %v\n", appliedAt, script) 77 | } 78 | -------------------------------------------------------------------------------- /Godeps/_workspace/src/github.com/technoweenie/grohl/loggers_test.go: -------------------------------------------------------------------------------- 1 | package grohl 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | func TestIoLog(t *testing.T) { 9 | buf := bytes.NewBufferString("") 10 | logger := NewIoLogger(buf) 11 | logger.AddTime = false 12 | logger.Log(Data{"a": 1}) 13 | expected := "a=1\n" 14 | 15 | if actual := buf.String(); actual != expected { 16 | t.Errorf("e: %s\na: %s", expected, actual) 17 | } 18 | } 19 | 20 | func TestChannelLog(t *testing.T) { 21 | channel := make(chan Data, 1) 22 | logger, channel := NewChannelLogger(channel) 23 | data := Data{"a": 1} 24 | logger.Log(data) 25 | 26 | recv := <-channel 27 | 28 | if recvKeys := len(recv); recvKeys != len(data) { 29 | t.Errorf("Wrong number of keys: %d (%s)", recvKeys, recv) 30 | } 31 | 32 | if data["a"] != recv["a"] { 33 | t.Errorf("Received: %s", recv) 34 | } 35 | } 36 | 37 | type loggerBuffer struct { 38 | channel chan Data 39 | t *testing.T 40 | lines []builtLogLine 41 | index int 42 | } 43 | 44 | func (b *loggerBuffer) Lines() []builtLogLine { 45 | if b.lines == nil { 46 | close(b.channel) 47 | b.lines = make([]builtLogLine, len(b.channel)) 48 | i := 0 49 | 50 | for data := range b.channel { 51 | b.lines[i] = buildLogLine(data) 52 | i = i + 1 53 | } 54 | } 55 | 56 | return b.lines 57 | } 58 | 59 | func (b *loggerBuffer) AssertLine(parts ...string) { 60 | lines := b.Lines() 61 | if b.index < 0 || b.index >= len(lines) { 62 | b.t.Errorf("No line %d", b.index) 63 | return 64 | } 65 | 66 | AssertBuiltLine(b.t, lines[b.index], parts...) 67 | b.index += 1 68 | } 69 | 70 | func (b *loggerBuffer) AssertEOF() { 71 | lines := b.Lines() 72 | if b.index < 0 { 73 | b.t.Errorf("Invalid index %d", b.index) 74 | return 75 | } 76 | 77 | if b.index < len(lines) { 78 | b.t.Errorf("Not EOF, on line %d", b.index) 79 | return 80 | } 81 | } 82 | 83 | func setupLogger(t *testing.T) (*Context, *loggerBuffer) { 84 | ch := make(chan Data, 100) 85 | logger, _ := NewChannelLogger(ch) 86 | context := NewContext(nil) 87 | context.Logger = logger 88 | return context, &loggerBuffer{channel: ch, t: t} 89 | } 90 | --------------------------------------------------------------------------------