├── .gitignore ├── LICENSE ├── README.md ├── _third_party ├── code.google.com │ └── p │ │ └── go-charset │ │ ├── charset │ │ ├── big5.go │ │ ├── charset.go │ │ ├── charset_test.go │ │ ├── codepage.go │ │ ├── cp932.go │ │ ├── example_test.go │ │ ├── file.go │ │ ├── local.go │ │ ├── utf16.go │ │ └── utf8.go │ │ └── data │ │ ├── data_big5.dat.go │ │ ├── data_charsets.json.go │ │ ├── data_cp932.dat.go │ │ ├── data_ibm437.cp.go │ │ ├── data_ibm850.cp.go │ │ ├── data_ibm866.cp.go │ │ ├── data_iso-8859-1.cp.go │ │ ├── data_iso-8859-10.cp.go │ │ ├── data_iso-8859-15.cp.go │ │ ├── data_iso-8859-2.cp.go │ │ ├── data_iso-8859-3.cp.go │ │ ├── data_iso-8859-4.cp.go │ │ ├── data_iso-8859-5.cp.go │ │ ├── data_iso-8859-6.cp.go │ │ ├── data_iso-8859-7.cp.go │ │ ├── data_iso-8859-8.cp.go │ │ ├── data_iso-8859-9.cp.go │ │ ├── data_jisx0201kana.dat.go │ │ ├── data_koi8-r.cp.go │ │ ├── data_windows-1250.cp.go │ │ ├── data_windows-1251.cp.go │ │ ├── data_windows-1252.cp.go │ │ ├── doc.go │ │ └── generate.go ├── github.com │ ├── MiniProfiler │ │ └── go │ │ │ ├── miniprofiler │ │ │ ├── doc.go │ │ │ ├── miniprofiler.go │ │ │ ├── static.go │ │ │ ├── templates.go │ │ │ └── types.go │ │ │ └── miniprofiler_gae │ │ │ ├── doc.go │ │ │ └── miniprofiler_gae.go │ ├── golang │ │ └── protobuf │ │ │ └── proto │ │ │ ├── Makefile │ │ │ ├── all_test.go │ │ │ ├── clone.go │ │ │ ├── clone_test.go │ │ │ ├── decode.go │ │ │ ├── encode.go │ │ │ ├── equal.go │ │ │ ├── equal_test.go │ │ │ ├── extensions.go │ │ │ ├── extensions_test.go │ │ │ ├── lib.go │ │ │ ├── message_set.go │ │ │ ├── message_set_test.go │ │ │ ├── pointer_reflect.go │ │ │ ├── pointer_unsafe.go │ │ │ ├── properties.go │ │ │ ├── proto3_test.go │ │ │ ├── size2_test.go │ │ │ ├── size_test.go │ │ │ ├── text.go │ │ │ ├── text_parser.go │ │ │ ├── text_parser_test.go │ │ │ └── text_test.go │ ├── gorilla │ │ ├── context │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── context.go │ │ │ ├── context_test.go │ │ │ └── doc.go │ │ └── mux │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── bench_test.go │ │ │ ├── doc.go │ │ │ ├── mux.go │ │ │ ├── mux_test.go │ │ │ ├── old_test.go │ │ │ ├── regexp.go │ │ │ └── route.go │ └── mjibson │ │ ├── appstats │ │ ├── README.md │ │ ├── appstats.go │ │ ├── bytesize.go │ │ ├── cost.go │ │ ├── doc.go │ │ ├── funcs.go │ │ ├── handler.go │ │ ├── html.go │ │ ├── static.go │ │ └── types.go │ │ └── goon │ │ ├── README.md │ │ ├── doc.go │ │ ├── entity.go │ │ ├── goon.go │ │ ├── goon_test.go │ │ └── query.go └── golang.org │ └── x │ ├── net │ └── html │ │ ├── atom │ │ ├── atom.go │ │ ├── atom_test.go │ │ ├── gen.go │ │ ├── table.go │ │ └── table_test.go │ │ ├── charset │ │ ├── charset.go │ │ ├── charset_test.go │ │ ├── gen.go │ │ └── table.go │ │ ├── const.go │ │ ├── doc.go │ │ ├── doctype.go │ │ ├── entity.go │ │ ├── entity_test.go │ │ ├── escape.go │ │ ├── escape_test.go │ │ ├── example_test.go │ │ ├── foreign.go │ │ ├── node.go │ │ ├── node_test.go │ │ ├── parse.go │ │ ├── parse_test.go │ │ ├── render.go │ │ ├── render_test.go │ │ ├── token.go │ │ └── token_test.go │ └── text │ ├── cldr │ ├── base.go │ ├── cldr.go │ ├── cldr_test.go │ ├── collate.go │ ├── collate_test.go │ ├── data_test.go │ ├── decode.go │ ├── examples_test.go │ ├── makexml.go │ ├── resolve.go │ ├── resolve_test.go │ ├── slice.go │ ├── slice_test.go │ └── xml.go │ ├── encoding │ ├── charmap │ │ ├── charmap.go │ │ ├── maketables.go │ │ └── tables.go │ ├── encoding.go │ ├── encoding_test.go │ ├── example_test.go │ ├── internal │ │ ├── identifier │ │ │ ├── gen.go │ │ │ ├── identifier.go │ │ │ └── mib.go │ │ └── internal.go │ ├── japanese │ │ ├── all.go │ │ ├── eucjp.go │ │ ├── iso2022jp.go │ │ ├── maketables.go │ │ ├── shiftjis.go │ │ └── tables.go │ ├── korean │ │ ├── euckr.go │ │ ├── maketables.go │ │ └── tables.go │ ├── simplifiedchinese │ │ ├── all.go │ │ ├── gbk.go │ │ ├── hzgb2312.go │ │ ├── maketables.go │ │ └── tables.go │ ├── traditionalchinese │ │ ├── big5.go │ │ ├── maketables.go │ │ └── tables.go │ └── unicode │ │ ├── override.go │ │ └── unicode.go │ ├── internal │ └── gen │ │ └── gen.go │ └── transform │ ├── examples_test.go │ ├── transform.go │ └── transform_test.go ├── admin.go ├── app ├── app.go ├── app.sample.yaml ├── cron.yaml ├── index.yaml ├── queue.yaml ├── static │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.min.css │ │ ├── font-awesome.css │ │ └── main.65b84ec7.css │ ├── favicon.png │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff │ ├── icon-grey.svg │ ├── icon-stroke.svg │ ├── icon.png │ ├── icon.svg │ ├── img │ │ ├── feed.png │ │ ├── glyphicons-halflings-white.png │ │ ├── glyphicons-halflings.png │ │ ├── preview.png │ │ └── stripe.png │ ├── index.html │ ├── js │ │ ├── angular.js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ ├── jquery-2.0.3.js │ │ ├── jquery-ui-1.10.3.sortable.js │ │ ├── jquery-ui-1.10.3.sortable.min.js │ │ ├── jquery.form.js │ │ ├── main.d499081b.js │ │ ├── moment.min.js │ │ ├── mousetrap.min.js │ │ ├── site.js │ │ ├── sortable.js │ │ ├── underscore-min.js │ │ └── underscore.js │ ├── large.png │ ├── manifest.json │ ├── media │ │ └── favicon.073a9b34.png │ └── service-worker.js └── templates │ ├── admin-all-feeds.html │ ├── admin-date-formats.html │ ├── admin-feed.html │ ├── admin-stats.html │ ├── admin-user.html │ └── base.html ├── atom └── atom.go ├── autodiscover.go ├── charge.go ├── dev.go ├── docs ├── CNAME └── index.html ├── funcs.go ├── main.go ├── mobile ├── .gitignore ├── LICENSE ├── README.md ├── index.html ├── manifest.json ├── package.json ├── src │ ├── App.js │ ├── favicon.png │ └── index.js └── sync.js ├── rdf └── rdf.go ├── rss ├── rss.go └── rss_test.go ├── sanitizer ├── sanitize.go ├── snip.go └── strip.go ├── settings.go.dist ├── tasks.go ├── types.go ├── user.go └── utils.go /.gitignore: -------------------------------------------------------------------------------- 1 | app.yaml 2 | d 3 | pw 4 | settings.go 5 | update 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2013 Matt Jibson 4 | 5 | Permission to use, copy, modify, and distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go read 2 | 3 | a google reader clone built with go on app engine and angularjs 4 | 5 | ## setting up a local dev environment 6 | 7 | 1. Install [Python 2.7](http://www.python.org/download/releases/2.7.5/) and make sure it is in your `PATH`. (Google App Engine doesn't yet work with Python 3.) 8 | 1. Install [Git](http://gitscm.com/) and [Mercurial](http://mercurial.selenic.com/wiki/Download) and make sure `git` and `hg` are in your `PATH`. 9 | 1. Install the [Go App Engine SDK](https://developers.google.com/appengine/downloads#Google_App_Engine_SDK_for_Go). 10 | 1. Set your `GOPATH` (to something like `/home/user`), and make sure it's a directory that exists. (Note: set this on your machine's environment, not in the go.bat file.) 11 | 1. Further commands use `goapp` which lives in the `go_appengine` directory from the SDK. Make sure it's in your `PATH`. 12 | 1. Download goread and dependencies by running: `goapp get -d github.com/mjibson/goread`. You may get messages about unrecognized imports. Ignore them. 13 | 1. `cd $GOPATH/src/github.com/mjibson/goread/app`. 14 | 1. Copy `app.sample.yaml` to `app.yaml`. 15 | 1. In the `goread` directory (`cd ..` from the command above), copy `settings.go.dist` to `settings.go`. 16 | 1. From the `app` directory, start the app with `goapp serve`. (On Windows, you may need to do this instead: `python C:\go_appengine\dev_appserver.py app.yaml`.) 17 | 1. View at [localhost:8080](http://localhost:8080), admin console at [localhost:8000](http://localhost:8000). 18 | 19 | ## developer notes 20 | 21 | 1. Press `alt+c` to show the miniprofiler window. 22 | 1. Press `c` to clear all feeds and stories, remove all your subscriptions, and reset your unread date. 23 | 24 | ## self host on production app engine servers 25 | 26 | 1. Set up a local dev environment as described above. 27 | 1. Create a [new app engine application](https://cloud.google.com/console?getstarted=https://appengine.google.com). 28 | 1. In `app.yaml`, change the first line to contain the name of the application you just created. 29 | 1. From the `app` directory, deploy with `goapp deploy`. 30 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/charset/big5.go: -------------------------------------------------------------------------------- 1 | package charset 2 | 3 | import ( 4 | "fmt" 5 | "unicode/utf8" 6 | ) 7 | 8 | func init() { 9 | registerClass("big5", fromBig5, nil) 10 | } 11 | 12 | // Big5 consists of 89 fonts of 157 chars each 13 | const ( 14 | big5Max = 13973 15 | big5Font = 157 16 | big5Data = "big5.dat" 17 | ) 18 | 19 | type translateFromBig5 struct { 20 | font int 21 | scratch []byte 22 | big5map []rune 23 | } 24 | 25 | func (p *translateFromBig5) Translate(data []byte, eof bool) (int, []byte, error) { 26 | p.scratch = p.scratch[:0] 27 | n := 0 28 | for len(data) > 0 { 29 | c := int(data[0]) 30 | data = data[1:] 31 | n++ 32 | if p.font == -1 { 33 | // idle state 34 | if c >= 0xa1 { 35 | p.font = c 36 | continue 37 | } 38 | if c == 26 { 39 | c = '\n' 40 | } 41 | continue 42 | } 43 | f := p.font 44 | p.font = -1 45 | r := utf8.RuneError 46 | switch { 47 | case c >= 64 && c <= 126: 48 | c -= 64 49 | case c >= 161 && c <= 254: 50 | c = c - 161 + 63 51 | default: 52 | // bad big5 char 53 | f = 255 54 | } 55 | if f <= 254 { 56 | f -= 161 57 | ix := f*big5Font + c 58 | if ix < len(p.big5map) { 59 | r = p.big5map[ix] 60 | } 61 | if r == -1 { 62 | r = utf8.RuneError 63 | } 64 | } 65 | p.scratch = appendRune(p.scratch, r) 66 | } 67 | return n, p.scratch, nil 68 | } 69 | 70 | type big5Key bool 71 | 72 | func fromBig5(arg string) (Translator, error) { 73 | big5map, err := cache(big5Key(false), func() (interface{}, error) { 74 | data, err := readFile(big5Data) 75 | if err != nil { 76 | return nil, fmt.Errorf("charset: cannot open big5 data file: %v", err) 77 | } 78 | big5map := []rune(string(data)) 79 | if len(big5map) != big5Max { 80 | return nil, fmt.Errorf("charset: corrupt big5 data") 81 | } 82 | return big5map, nil 83 | }) 84 | if err != nil { 85 | return nil, err 86 | } 87 | return &translateFromBig5{big5map: big5map.([]rune), font: -1}, nil 88 | } 89 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/charset/codepage.go: -------------------------------------------------------------------------------- 1 | package charset 2 | 3 | import ( 4 | "fmt" 5 | "unicode/utf8" 6 | ) 7 | 8 | func init() { 9 | registerClass("cp", fromCodePage, toCodePage) 10 | } 11 | 12 | type translateFromCodePage struct { 13 | byte2rune *[256]rune 14 | scratch []byte 15 | } 16 | 17 | type cpKeyFrom string 18 | type cpKeyTo string 19 | 20 | func (p *translateFromCodePage) Translate(data []byte, eof bool) (int, []byte, error) { 21 | p.scratch = ensureCap(p.scratch, len(data)*utf8.UTFMax)[:0] 22 | buf := p.scratch 23 | for _, x := range data { 24 | r := p.byte2rune[x] 25 | if r < utf8.RuneSelf { 26 | buf = append(buf, byte(r)) 27 | continue 28 | } 29 | size := utf8.EncodeRune(buf[len(buf):cap(buf)], r) 30 | buf = buf[0 : len(buf)+size] 31 | } 32 | return len(data), buf, nil 33 | } 34 | 35 | type toCodePageInfo struct { 36 | rune2byte map[rune]byte 37 | // same gives the number of runes at start of code page that map exactly to 38 | // unicode. 39 | same rune 40 | } 41 | 42 | type translateToCodePage struct { 43 | toCodePageInfo 44 | scratch []byte 45 | } 46 | 47 | func (p *translateToCodePage) Translate(data []byte, eof bool) (int, []byte, error) { 48 | p.scratch = ensureCap(p.scratch, len(data)) 49 | buf := p.scratch[:0] 50 | 51 | for i := 0; i < len(data); { 52 | r := rune(data[i]) 53 | size := 1 54 | if r >= utf8.RuneSelf { 55 | r, size = utf8.DecodeRune(data[i:]) 56 | if size == 1 && !eof && !utf8.FullRune(data[i:]) { 57 | return i, buf, nil 58 | } 59 | } 60 | 61 | var b byte 62 | if r < p.same { 63 | b = byte(r) 64 | } else { 65 | var ok bool 66 | b, ok = p.rune2byte[r] 67 | if !ok { 68 | b = '?' 69 | } 70 | } 71 | buf = append(buf, b) 72 | i += size 73 | } 74 | return len(data), buf, nil 75 | } 76 | 77 | func fromCodePage(arg string) (Translator, error) { 78 | runes, err := cache(cpKeyFrom(arg), func() (interface{}, error) { 79 | data, err := readFile(arg) 80 | if err != nil { 81 | return nil, err 82 | } 83 | runes := []rune(string(data)) 84 | if len(runes) != 256 { 85 | return nil, fmt.Errorf("charset: %q has wrong rune count (%d)", arg, len(runes)) 86 | } 87 | r := new([256]rune) 88 | copy(r[:], runes) 89 | return r, nil 90 | }) 91 | if err != nil { 92 | return nil, err 93 | } 94 | return &translateFromCodePage{byte2rune: runes.(*[256]rune)}, nil 95 | } 96 | 97 | func toCodePage(arg string) (Translator, error) { 98 | m, err := cache(cpKeyTo(arg), func() (interface{}, error) { 99 | data, err := readFile(arg) 100 | if err != nil { 101 | return nil, err 102 | } 103 | 104 | info := toCodePageInfo{ 105 | rune2byte: make(map[rune]byte), 106 | same: 256, 107 | } 108 | atStart := true 109 | i := rune(0) 110 | for _, r := range string(data) { 111 | if atStart { 112 | if r == i { 113 | i++ 114 | continue 115 | } 116 | info.same = i 117 | atStart = false 118 | } 119 | info.rune2byte[r] = byte(i) 120 | i++ 121 | } 122 | // TODO fix tables 123 | // fmt.Printf("%s, same = %d\n", arg, info.same) 124 | if i != 256 { 125 | return nil, fmt.Errorf("charset: %q has wrong rune count (%d)", arg, i) 126 | } 127 | return info, nil 128 | }) 129 | if err != nil { 130 | return nil, err 131 | } 132 | return &translateToCodePage{toCodePageInfo: m.(toCodePageInfo)}, nil 133 | } 134 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/charset/example_test.go: -------------------------------------------------------------------------------- 1 | package charset_test 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 7 | _ "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/data" 8 | "io/ioutil" 9 | "log" 10 | "strings" 11 | ) 12 | 13 | func ExampleNewReader() { 14 | r, err := charset.NewReader("latin1", strings.NewReader("\xa35 for Pepp\xe9")) 15 | if err != nil { 16 | log.Fatal(err) 17 | } 18 | result, err := ioutil.ReadAll(r) 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | fmt.Printf("%s\n", result) 23 | // Output: £5 for Peppé 24 | } 25 | 26 | func ExampleNewWriter() { 27 | buf := new(bytes.Buffer) 28 | w, err := charset.NewWriter("latin1", buf) 29 | if err != nil { 30 | log.Fatal(err) 31 | } 32 | fmt.Fprintf(w, "£5 for Peppé") 33 | w.Close() 34 | fmt.Printf("%q\n", buf.Bytes()) 35 | // Output: "\xa35 for Pepp\xe9" 36 | } 37 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/charset/file.go: -------------------------------------------------------------------------------- 1 | package charset 2 | 3 | import ( 4 | "io" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | var files = make(map[string]func() (io.ReadCloser, error)) 11 | 12 | // RegisterDataFile registers the existence of a given data 13 | // file with the given name that may be used by a character-set converter. 14 | // It is intended to be used by packages that wish to embed 15 | // data in the executable binary, and should not be 16 | // used normally. 17 | func RegisterDataFile(name string, open func() (io.ReadCloser, error)) { 18 | files[name] = open 19 | } 20 | 21 | // CharsetDir gives the location of the default data file directory. 22 | // This directory will be used for files with names that have not 23 | // been registered with RegisterDataFile. 24 | var CharsetDir = "/usr/local/lib/go-charset/datafiles" 25 | 26 | func readFile(name string) (data []byte, err error) { 27 | var r io.ReadCloser 28 | if open := files[name]; open != nil { 29 | r, err = open() 30 | if err != nil { 31 | return 32 | } 33 | } else { 34 | r, err = os.Open(filepath.Join(CharsetDir, name)) 35 | if err != nil { 36 | return 37 | } 38 | } 39 | return ioutil.ReadAll(r) 40 | } 41 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/charset/local.go: -------------------------------------------------------------------------------- 1 | package charset 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | "sync" 8 | ) 9 | 10 | var ( 11 | readLocalCharsetsOnce sync.Once 12 | localCharsets = make(map[string]*localCharset) 13 | ) 14 | 15 | type localCharset struct { 16 | Charset 17 | arg string 18 | *class 19 | } 20 | 21 | // A class of character sets. 22 | // Each class can be instantiated with an argument specified in the config file. 23 | // Many character sets can use a single class. 24 | type class struct { 25 | from, to func(arg string) (Translator, error) 26 | } 27 | 28 | // The set of classes, indexed by class name. 29 | var classes = make(map[string]*class) 30 | 31 | func registerClass(charset string, from, to func(arg string) (Translator, error)) { 32 | classes[charset] = &class{from, to} 33 | } 34 | 35 | type localFactory struct{} 36 | 37 | func (f localFactory) TranslatorFrom(name string) (Translator, error) { 38 | f.init() 39 | name = NormalizedName(name) 40 | cs := localCharsets[name] 41 | if cs == nil { 42 | return nil, fmt.Errorf("character set %q not found", name) 43 | } 44 | if cs.from == nil { 45 | return nil, fmt.Errorf("cannot translate from %q", name) 46 | } 47 | return cs.from(cs.arg) 48 | } 49 | 50 | func (f localFactory) TranslatorTo(name string) (Translator, error) { 51 | f.init() 52 | name = NormalizedName(name) 53 | cs := localCharsets[name] 54 | if cs == nil { 55 | return nil, fmt.Errorf("character set %q not found", name) 56 | } 57 | if cs.to == nil { 58 | return nil, fmt.Errorf("cannot translate to %q", name) 59 | } 60 | return cs.to(cs.arg) 61 | } 62 | 63 | func (f localFactory) Names() []string { 64 | f.init() 65 | var names []string 66 | for name, cs := range localCharsets { 67 | // add names only for non-aliases. 68 | if localCharsets[cs.Name] == cs { 69 | names = append(names, name) 70 | } 71 | } 72 | return names 73 | } 74 | 75 | func (f localFactory) Info(name string) *Charset { 76 | f.init() 77 | lcs := localCharsets[NormalizedName(name)] 78 | if lcs == nil { 79 | return nil 80 | } 81 | // copy the charset info so that callers can't mess with it. 82 | cs := lcs.Charset 83 | return &cs 84 | } 85 | 86 | func (f localFactory) init() { 87 | readLocalCharsetsOnce.Do(readLocalCharsets) 88 | } 89 | 90 | // charsetEntry is the data structure for one entry in the JSON config file. 91 | // If Alias is non-empty, it should be the canonical name of another 92 | // character set; otherwise Class should be the name 93 | // of an entry in classes, and Arg is the argument for 94 | // instantiating it. 95 | type charsetEntry struct { 96 | Aliases []string 97 | Desc string 98 | Class string 99 | Arg string 100 | } 101 | 102 | // readCharsets reads the JSON config file. 103 | // It's done once only, when first needed. 104 | func readLocalCharsets() { 105 | csdata, err := readFile("charsets.json") 106 | if err != nil { 107 | fmt.Fprintf(os.Stderr, "charset: cannot open \"charsets.json\": %v\n", err) 108 | return 109 | } 110 | 111 | var entries map[string]charsetEntry 112 | err = json.Unmarshal(csdata, &entries) 113 | if err != nil { 114 | fmt.Fprintf(os.Stderr, "charset: cannot decode config file: %v\n", err) 115 | } 116 | for name, e := range entries { 117 | class := classes[e.Class] 118 | if class == nil { 119 | continue 120 | } 121 | name = NormalizedName(name) 122 | for i, a := range e.Aliases { 123 | e.Aliases[i] = NormalizedName(a) 124 | } 125 | cs := &localCharset{ 126 | Charset: Charset{ 127 | Name: name, 128 | Aliases: e.Aliases, 129 | Desc: e.Desc, 130 | NoFrom: class.from == nil, 131 | NoTo: class.to == nil, 132 | }, 133 | arg: e.Arg, 134 | class: class, 135 | } 136 | localCharsets[cs.Name] = cs 137 | for _, a := range cs.Aliases { 138 | localCharsets[a] = cs 139 | } 140 | } 141 | } 142 | 143 | // A general cache store that local character set translators 144 | // can use for persistent storage of data. 145 | var ( 146 | cacheMutex sync.Mutex 147 | cacheStore = make(map[interface{}]interface{}) 148 | ) 149 | 150 | func cache(key interface{}, f func() (interface{}, error)) (interface{}, error) { 151 | cacheMutex.Lock() 152 | defer cacheMutex.Unlock() 153 | if x := cacheStore[key]; x != nil { 154 | return x, nil 155 | } 156 | x, err := f() 157 | if err != nil { 158 | return nil, err 159 | } 160 | cacheStore[key] = x 161 | return x, err 162 | } 163 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/charset/utf16.go: -------------------------------------------------------------------------------- 1 | package charset 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "unicode/utf8" 7 | ) 8 | 9 | func init() { 10 | registerClass("utf16", fromUTF16, toUTF16) 11 | } 12 | 13 | type translateFromUTF16 struct { 14 | first bool 15 | endian binary.ByteOrder 16 | scratch []byte 17 | } 18 | 19 | func (p *translateFromUTF16) Translate(data []byte, eof bool) (int, []byte, error) { 20 | data = data[0 : len(data)&^1] // round to even number of bytes. 21 | if len(data) < 2 { 22 | return 0, nil, nil 23 | } 24 | n := 0 25 | if p.first && p.endian == nil { 26 | switch binary.BigEndian.Uint16(data) { 27 | case 0xfeff: 28 | p.endian = binary.BigEndian 29 | data = data[2:] 30 | n += 2 31 | case 0xfffe: 32 | p.endian = binary.LittleEndian 33 | data = data[2:] 34 | n += 2 35 | default: 36 | p.endian = guessEndian(data) 37 | } 38 | p.first = false 39 | } 40 | 41 | p.scratch = p.scratch[:0] 42 | for ; len(data) > 0; data = data[2:] { 43 | p.scratch = appendRune(p.scratch, rune(p.endian.Uint16(data))) 44 | n += 2 45 | } 46 | return n, p.scratch, nil 47 | } 48 | 49 | func guessEndian(data []byte) binary.ByteOrder { 50 | // XXX TODO 51 | return binary.LittleEndian 52 | } 53 | 54 | type translateToUTF16 struct { 55 | first bool 56 | endian binary.ByteOrder 57 | scratch []byte 58 | } 59 | 60 | func (p *translateToUTF16) Translate(data []byte, eof bool) (int, []byte, error) { 61 | p.scratch = ensureCap(p.scratch[:0], (len(data)+1)*2) 62 | if p.first { 63 | p.scratch = p.scratch[0:2] 64 | p.endian.PutUint16(p.scratch, 0xfeff) 65 | p.first = false 66 | } 67 | n := 0 68 | for len(data) > 0 { 69 | if !utf8.FullRune(data) && !eof { 70 | break 71 | } 72 | r, size := utf8.DecodeRune(data) 73 | // TODO if r > 65535? 74 | 75 | slen := len(p.scratch) 76 | p.scratch = p.scratch[0 : slen+2] 77 | p.endian.PutUint16(p.scratch[slen:], uint16(r)) 78 | data = data[size:] 79 | n += size 80 | } 81 | return n, p.scratch, nil 82 | } 83 | 84 | func getEndian(arg string) (binary.ByteOrder, error) { 85 | switch arg { 86 | case "le": 87 | return binary.LittleEndian, nil 88 | case "be": 89 | return binary.BigEndian, nil 90 | case "": 91 | return nil, nil 92 | } 93 | return nil, errors.New("charset: unknown utf16 endianness") 94 | } 95 | 96 | func fromUTF16(arg string) (Translator, error) { 97 | endian, err := getEndian(arg) 98 | if err != nil { 99 | return nil, err 100 | } 101 | return &translateFromUTF16{first: true, endian: endian}, nil 102 | } 103 | 104 | func toUTF16(arg string) (Translator, error) { 105 | endian, err := getEndian(arg) 106 | if err != nil { 107 | return nil, err 108 | } 109 | return &translateToUTF16{first: false, endian: endian}, nil 110 | } 111 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/charset/utf8.go: -------------------------------------------------------------------------------- 1 | package charset 2 | 3 | import ( 4 | "unicode/utf8" 5 | ) 6 | 7 | func init() { 8 | registerClass("utf8", toUTF8, toUTF8) 9 | } 10 | 11 | type translateToUTF8 struct { 12 | scratch []byte 13 | } 14 | 15 | var errorBytes = []byte(string(utf8.RuneError)) 16 | 17 | const errorRuneLen = len(string(utf8.RuneError)) 18 | 19 | func (p *translateToUTF8) Translate(data []byte, eof bool) (int, []byte, error) { 20 | p.scratch = ensureCap(p.scratch, (len(data))*errorRuneLen) 21 | buf := p.scratch[:0] 22 | for i := 0; i < len(data); { 23 | // fast path for ASCII 24 | if b := data[i]; b < utf8.RuneSelf { 25 | buf = append(buf, b) 26 | i++ 27 | continue 28 | } 29 | _, size := utf8.DecodeRune(data[i:]) 30 | if size == 1 { 31 | if !eof && !utf8.FullRune(data) { 32 | // When DecodeRune has converted only a single 33 | // byte, we know there must be some kind of error 34 | // because we know the byte's not ASCII. 35 | // If we aren't at EOF, and it's an incomplete 36 | // rune encoding, then we return to process 37 | // the final bytes in a subsequent call. 38 | return i, buf, nil 39 | } 40 | buf = append(buf, errorBytes...) 41 | } else { 42 | buf = append(buf, data[i:i+size]...) 43 | } 44 | i += size 45 | } 46 | return len(data), buf, nil 47 | } 48 | 49 | func toUTF8(arg string) (Translator, error) { 50 | return new(translateToUTF8), nil 51 | } 52 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_ibm437.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("ibm437.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007fÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞∅∈∩≡±≥≤⌠⌡÷≈°•·√ⁿ²∎\u00a0") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_ibm850.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("ibm850.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007fÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø×ƒáíóúñѪº¿®¬½¼¡«»░▒▓│┤ÁÂÀ©╣║╗╝¢¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈıÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõÕµþÞÚÛÙýݯ´\u00ad±‗¾¶§÷¸°¨·¹³²∎\u00a0") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_ibm866.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("ibm866.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007fАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп������������������������������������������������рстуфхцчшщъыьэюяЁё��������������") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_iso-8859-1.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("iso-8859-1.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0¡¢£¤¥¦§¨©ª«¬\u00ad®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_iso-8859-10.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("iso-8859-10.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0ĄĒĢĪĨͧĻĐŠŦŽ\u00adŪŊ°ąēģīĩķ·ļĐšŧž—ūŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎÏÐŅŌÓÔÕÖŨØŲÚÛÜÝÞßāáâãäåæįčéęëėíîïðņōóôõöũøųúûüýþĸ") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_iso-8859-15.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("iso-8859-15.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0¡¢£€¥Š§š©ª«¬\u00ad®¯°±²³Žµ¶·ž¹º»ŒœŸ¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_iso-8859-2.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("iso-8859-2.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0Ą˘Ł¤ĽŚ§¨ŠŞŤŹ\u00adŽŻ°ą˛ł´ľśˇ¸šşťź˝žżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_iso-8859-3.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("iso-8859-3.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0Ħ˘£¤�Ĥ§¨İŞĞĴ\u00ad�ݰħ²³´µĥ·¸ışğĵ½�żÀÁÂ�ÄĊĈÇÈÉÊËÌÍÎÏ�ÑÒÓÔĠÖ×ĜÙÚÛÜŬŜßàáâ�äċĉçèéêëìíîï�ñòóôġö÷ĝùúûüŭŝ˙") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_iso-8859-4.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("iso-8859-4.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0ĄĸŖ¤Ĩϧ¨ŠĒĢŦ\u00adޝ°ą˛ŗ´ĩšēģŧŊžŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎĪĐŅŌĶÔÕÖרŲÚÛÜŨŪßāáâãäåæįčéęëėíîīđņōķôõö÷øųúûüũū˙") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_iso-8859-5.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("iso-8859-5.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0ЁЂЃЄЅІЇЈЉЊЋЌ\u00adЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ёђѓєѕіїјљњћќ§ўџ") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_iso-8859-6.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("iso-8859-6.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0���¤�������،\u00ad�������������؛���؟�ءآأؤإئابةتثجحخدذرزسشصضطظعغ�����ـفقكلمنهوىيًٌٍَُِّْ�������������") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_iso-8859-7.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("iso-8859-7.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0‘’£��¦§¨©�«¬\u00ad�―°±²³΄΅Ά·ΈΉΊ»Ό½ΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ�ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ�") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_iso-8859-8.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("iso-8859-8.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0�¢£¤¥¦§¨©×«¬\u00ad®‾°±²³´µ¶·¸¹÷»¼½¾��������������������������������‗אבגדהוזחטיךכלםמןנסעףפץצקרשת�����") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_iso-8859-9.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("iso-8859-9.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f\u00a0¡¢£¤¥¦§¨©ª«¬\u00ad®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖרÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_jisx0201kana.dat.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("jisx0201kana.dat", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_koi8-r.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("koi8-r.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥\u00a0⌡°²·÷═║╒ё╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡Ё╢╣╤╥╦╧╨╩╪╫╬©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_windows-1250.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("windows-1250.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f€�‚�„…†‡�‰Š‹ŚŤŽŹ�‘’“”•–—�™š›śťžź\u00a0ˇ˘Ł¤Ą¦§¨©Ş«¬\u00ad®Ż°±˛ł´µ¶·¸ąş»Ľ˝ľżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_windows-1251.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("windows-1251.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007fЂЃ‚ѓ„…†‡�‰Љ‹ЊЌЋЏђ‘’“”•–—�™љ›њќћџ\u00a0ЎўЈ¤Ґ¦§Ё©Є«¬\u00ad®Ї°±Ііґµ¶·ё№є»јЅѕїАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/data_windows-1252.cp.go: -------------------------------------------------------------------------------- 1 | // This file is automatically generated by generate-charset-data. 2 | // Do not hand-edit. 3 | 4 | package data 5 | 6 | import ( 7 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 8 | "io" 9 | "io/ioutil" 10 | "strings" 11 | ) 12 | 13 | func init() { 14 | charset.RegisterDataFile("windows-1252.cp", func() (io.ReadCloser, error) { 15 | r := strings.NewReader("\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f€�‚ƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ\u00a0¡¢£¤¥¦§¨©ª«¬\u00ad®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ") 16 | return ioutil.NopCloser(r), nil 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/doc.go: -------------------------------------------------------------------------------- 1 | // The data package embeds all the charset 2 | // data files as Go data. It registers the data with the charset 3 | // package as a side effect of its import. To use: 4 | // 5 | // import _ "code.google.com/p/go-charset" 6 | package data 7 | -------------------------------------------------------------------------------- /_third_party/code.google.com/p/go-charset/data/generate.go: -------------------------------------------------------------------------------- 1 | // +build ignore 2 | 3 | // go run generate.go && go fmt 4 | 5 | // The generate-charset-data command generates the Go source code 6 | // for code.google.com/p/go-charset/data from the data files 7 | // found in code.google.com/p/go-charset/datafiles. 8 | // It should be run in the go-charset root directory. 9 | // The resulting Go files will need gofmt'ing. 10 | package main 11 | 12 | import ( 13 | "fmt" 14 | "io/ioutil" 15 | "os" 16 | "path/filepath" 17 | "text/template" 18 | ) 19 | 20 | type info struct { 21 | Path string 22 | } 23 | 24 | var tfuncs = template.FuncMap{ 25 | "basename": func(s string) string { 26 | return filepath.Base(s) 27 | }, 28 | "read": func(path string) ([]byte, error) { 29 | return ioutil.ReadFile(path) 30 | }, 31 | } 32 | 33 | var tmpl = template.Must(template.New("").Funcs(tfuncs).Parse(` 34 | // This file is automatically generated by generate-charset-data. 35 | // Do not hand-edit. 36 | 37 | package data 38 | import ( 39 | "code.google.com/p/go-charset/charset" 40 | "io" 41 | "io/ioutil" 42 | "strings" 43 | ) 44 | 45 | func init() { 46 | charset.RegisterDataFile({{basename .Path | printf "%q"}}, func() (io.ReadCloser, error) { 47 | r := strings.NewReader({{read .Path | printf "%q"}}) 48 | return ioutil.NopCloser(r), nil 49 | }) 50 | } 51 | `)) 52 | 53 | var docTmpl = template.Must(template.New("").Funcs(tfuncs).Parse(` 54 | // This file is automatically generated by generate-charset-data. 55 | // Do not hand-edit. 56 | 57 | // The {{basename .Package}} package embeds all the charset 58 | // data files as Go data. It registers the data with the charset 59 | // package as a side effect of its import. To use: 60 | // 61 | // import _ "code.google.com/p/go-charset" 62 | package {{basename .Package}} 63 | `)) 64 | 65 | func main() { 66 | dataDir := filepath.Join("..", "datafiles") 67 | d, err := os.Open(dataDir) 68 | if err != nil { 69 | fatalf("%v", err) 70 | } 71 | names, err := d.Readdirnames(0) 72 | if err != nil { 73 | fatalf("cannot read datafiles dir: %v", err) 74 | } 75 | for _, name := range names { 76 | writeFile("data_"+name+".go", tmpl, info{ 77 | Path: filepath.Join(dataDir, name), 78 | }) 79 | } 80 | } 81 | 82 | func writeFile(name string, t *template.Template, data interface{}) { 83 | w, err := os.Create(name) 84 | if err != nil { 85 | fatalf("cannot create output file: %v", err) 86 | } 87 | defer w.Close() 88 | err = t.Execute(w, data) 89 | if err != nil { 90 | fatalf("template execute %q: %v", name, err) 91 | } 92 | } 93 | 94 | func fatalf(f string, a ...interface{}) { 95 | fmt.Fprintf(os.Stderr, "%s\n", fmt.Sprintf(f, a...)) 96 | os.Exit(2) 97 | } 98 | -------------------------------------------------------------------------------- /_third_party/github.com/MiniProfiler/go/miniprofiler/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Matt Jibson 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | Package miniprofiler is a simple but effective mini-profiler for websites. 19 | 20 | To use this package, change your HTTP handler functions to use this signature: 21 | 22 | func(miniprofiler.Timer, http.ResponseWriter, *http.Request) 23 | 24 | Register them in the usual way, wrapping them with NewHandler. 25 | 26 | By default, all requests are profiled. This should be changed to profile 27 | only developer requests. Set miniprofiler.Enable to a function that returns 28 | true if profiling is enabled. It might resemble this: 29 | 30 | miniprofiler.Enable = func(r *http.Request) bool { 31 | return isUserAuthenticated(r) 32 | } 33 | 34 | By default, profile results are stored in memory in a concurrent-safe 35 | data structure. To store in redis, memcache, or something else, set 36 | miniprofiler.Store and miniprofiler.Get to functions to back the profile 37 | data. The key is Profile.Id. 38 | 39 | Send output of t.Includes() to your HTML (it is empty if Enable returns 40 | false). 41 | 42 | Step 43 | 44 | The Step function can be used to profile more specific parts of your code. It 45 | should be called with the name of the step and a closure. Further Timers are 46 | used so concurrent work can be done and results applied to the correct location. 47 | 48 | t.Step("something", func(t miniprofiler.Timer) { 49 | // do some work 50 | // t.Step("another", func(t miniprofiler.Timer) { ... }) 51 | }) 52 | 53 | StepCustomTiming 54 | 55 | StepCustomTiming can be used to record any kind of call (redis, RPC, etc.) 56 | 57 | t.StepCustomTiming( 58 | "redis", // call type 59 | "get", // execute type 60 | "get key_name" // command string 61 | func() { 62 | // do work 63 | } 64 | ) 65 | 66 | Example 67 | 68 | This is a small example using this package. 69 | 70 | package main 71 | 72 | import ( 73 | "fmt" 74 | "net/http" 75 | 76 | "github.com/MiniProfiler/go/miniprofiler" 77 | ) 78 | 79 | func Index(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) { 80 | t.Step("something", func(t miniprofiler.Timer) { 81 | t.StepCustomTiming("RPC", "get", "get key_name", func() { 82 | // some RPC call 83 | }) 84 | }) 85 | fmt.Fprintf(w, "%v", p.Includes()) 86 | } 87 | 88 | func main() { 89 | http.Handle("/", miniprofiler.NewHandler(Index)) 90 | http.ListenAndServe(":8080", nil) 91 | } 92 | 93 | Configuration 94 | 95 | Refer to the variables section of the documentation: http://godoc.org/github.com/MiniProfiler/go/miniprofiler#pkg-variables. 96 | 97 | Other implementations and resources: http://miniprofiler.com. 98 | 99 | Frameworks 100 | 101 | Various frameworks have explicit support. 102 | 103 | Google App Engine: http://godoc.org/github.com/MiniProfiler/go/miniprofiler_gae 104 | 105 | Revel: http://godoc.org/github.com/MiniProfiler/go/miniprofiler_revel 106 | 107 | Martini: http://godoc.org/github.com/MiniProfiler/go/miniprofiler_martini 108 | 109 | Beego: http://godoc.org/github.com/MiniProfiler/go/miniprofiler_beego 110 | 111 | Traffic: http://godoc.org/github.com/MiniProfiler/go/miniprofiler_traffic 112 | 113 | gocraft/web: http://godoc.org/github.com/MiniProfiler/go/miniprofiler_gocraftweb 114 | 115 | RPCs 116 | 117 | Various RPCs have explicit support. 118 | 119 | Redis: http://godoc.org/github.com/MiniProfiler/go/redis 120 | 121 | SQL: http://godoc.org/github.com/MiniProfiler/go/sql 122 | */ 123 | package miniprofiler 124 | -------------------------------------------------------------------------------- /_third_party/github.com/MiniProfiler/go/miniprofiler/templates.go: -------------------------------------------------------------------------------- 1 | package miniprofiler 2 | 3 | import ( 4 | "html/template" 5 | "io/ioutil" 6 | "strings" 7 | ) 8 | 9 | var includePartialHtmlTmpl = parseInclude("include", "/include.partial.html") 10 | var shareHtmlTmpl = parseInclude("share", "/share.html") 11 | 12 | func parseInclude(name string, fname string) *template.Template { 13 | f, err := webFS.Open(fname) 14 | if err != nil { 15 | panic(err) 16 | } 17 | t, err := ioutil.ReadAll(f) 18 | if err != nil { 19 | panic(err) 20 | } 21 | f.Close() 22 | s := string(t) 23 | s = strings.Replace(s, "{", "{{.", -1) 24 | s = strings.Replace(s, "}", "}}", -1) 25 | return template.Must(template.New(name).Parse(s)) 26 | } 27 | -------------------------------------------------------------------------------- /_third_party/github.com/MiniProfiler/go/miniprofiler_gae/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Matt Jibson 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | Package miniprofiler_gae is a simple but effective mini-profiler for app engine. 19 | 20 | miniprofiler_gae hooks into the appstats package, and all app engine RPCs are automatically profiled. 21 | An appstats link is listed in each Profile. 22 | 23 | To use this package, change your HTTP handler functions to use this signature: 24 | 25 | func(mpg.Context, http.ResponseWriter, *http.Request) 26 | 27 | Register them in the usual way, wrapping them with NewHandler. 28 | 29 | Send output of c.Includes() to your HTML (it is empty if Enable returns 30 | false). 31 | 32 | By default, miniprofiler_gae is enabled on dev for all and on prod for admins. 33 | Override miniprofiler.Enable to change. 34 | 35 | Step 36 | 37 | Unlike base miniprofiler, the Step function returns a profiled context: 38 | 39 | c.Step("something", func(c mpg.Context) { 40 | // c is valid appengine.Context and miniprofiler.Timer: 41 | // datastore.Get(c, key, entity) 42 | // c.Step("another", func(c mpg.Context) { ... }) 43 | }) 44 | 45 | See the miniprofiler package docs about further usage: http://godoc.org/github.com/MiniProfiler/go/miniprofiler. 46 | */ 47 | package miniprofiler_gae 48 | -------------------------------------------------------------------------------- /_third_party/github.com/MiniProfiler/go/miniprofiler_gae/miniprofiler_gae.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Matt Jibson 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package miniprofiler_gae 18 | 19 | import ( 20 | "fmt" 21 | "net/http" 22 | 23 | "appengine" 24 | "appengine/memcache" 25 | "appengine/user" 26 | "appengine_internal" 27 | "github.com/mjibson/goread/_third_party/github.com/MiniProfiler/go/miniprofiler" 28 | "github.com/mjibson/goread/_third_party/github.com/mjibson/appstats" 29 | ) 30 | 31 | func init() { 32 | miniprofiler.Enable = EnableIfAdminOrDev 33 | miniprofiler.Get = GetMemcache 34 | miniprofiler.Store = StoreMemcache 35 | miniprofiler.MachineName = Instance 36 | } 37 | 38 | // EnableIfAdminOrDev returns true if this is the dev server or the current 39 | // user is an admin. This is the default for miniprofiler.Enable. 40 | func EnableIfAdminOrDev(r *http.Request) bool { 41 | if appengine.IsDevAppServer() { 42 | return true 43 | } 44 | c := appengine.NewContext(r) 45 | if u := user.Current(c); u != nil { 46 | return u.Admin 47 | } 48 | return false 49 | } 50 | 51 | // Instance returns the app engine instance id, or the hostname on dev. 52 | // This is the default for miniprofiler.MachineName. 53 | func Instance() string { 54 | if i := appengine.InstanceID(); i != "" && !appengine.IsDevAppServer() { 55 | return i[len(i)-8:] 56 | } 57 | return miniprofiler.Hostname() 58 | } 59 | 60 | // StoreMemcache stores the Profile in memcache. This is the default for 61 | // miniprofiler.Store. 62 | func StoreMemcache(r *http.Request, p *miniprofiler.Profile) { 63 | item := &memcache.Item{ 64 | Key: mp_key(string(p.Id)), 65 | Value: p.Json(), 66 | } 67 | c := appengine.NewContext(r) 68 | memcache.Set(c, item) 69 | } 70 | 71 | // GetMemcache gets the Profile from memcache. This is the default for 72 | // miniprofiler.Get. 73 | func GetMemcache(r *http.Request, id string) *miniprofiler.Profile { 74 | c := appengine.NewContext(r) 75 | item, err := memcache.Get(c, mp_key(id)) 76 | if err != nil { 77 | return nil 78 | } 79 | return miniprofiler.ProfileFromJson(item.Value) 80 | } 81 | 82 | type Context struct { 83 | appstats.Context 84 | miniprofiler.Timer 85 | } 86 | 87 | func (c Context) Call(service, method string, in, out appengine_internal.ProtoMessage, opts *appengine_internal.CallOptions) (err error) { 88 | if c.Timer != nil && service != "__go__" { 89 | c.StepCustomTiming(service, method, fmt.Sprintf("%v\n\n%v", method, in.String()), func() { 90 | err = c.Context.Call(service, method, in, out, opts) 91 | }) 92 | } else { 93 | err = c.Context.Call(service, method, in, out, opts) 94 | } 95 | return 96 | } 97 | 98 | func (c Context) Step(name string, f func(Context)) { 99 | if c.Timer != nil { 100 | c.Timer.Step(name, func(t miniprofiler.Timer) { 101 | f(Context{ 102 | Context: c.Context, 103 | Timer: t, 104 | }) 105 | }) 106 | } else { 107 | f(c) 108 | } 109 | } 110 | 111 | // NewHandler returns a profiled, appstats-aware appengine.Context. 112 | func NewHandler(f func(Context, http.ResponseWriter, *http.Request)) http.Handler { 113 | return appstats.NewHandler(func(c appengine.Context, w http.ResponseWriter, r *http.Request) { 114 | h := miniprofiler.NewHandler(func(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) { 115 | pc := Context{ 116 | Context: c.(appstats.Context), 117 | Timer: t, 118 | } 119 | t.SetName(miniprofiler.FuncName(f)) 120 | f(pc, w, r) 121 | t.AddCustomLink("appstats", pc.URL()) 122 | }) 123 | h.ServeHTTP(w, r) 124 | }) 125 | } 126 | 127 | func mp_key(id string) string { 128 | return fmt.Sprintf("mini-profiler-results:%s", id) 129 | } 130 | -------------------------------------------------------------------------------- /_third_party/github.com/golang/protobuf/proto/Makefile: -------------------------------------------------------------------------------- 1 | # Go support for Protocol Buffers - Google's data interchange format 2 | # 3 | # Copyright 2010 The Go Authors. All rights reserved. 4 | # https://github.com/golang/protobuf 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are 8 | # met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above 13 | # copyright notice, this list of conditions and the following disclaimer 14 | # in the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Google Inc. nor the names of its 17 | # contributors may be used to endorse or promote products derived from 18 | # this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | install: 33 | go install 34 | 35 | test: install generate-test-pbs 36 | go test 37 | 38 | 39 | generate-test-pbs: 40 | make install 41 | make -C testdata 42 | protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata:. proto3_proto/proto3.proto 43 | make 44 | -------------------------------------------------------------------------------- /_third_party/github.com/golang/protobuf/proto/message_set_test.go: -------------------------------------------------------------------------------- 1 | // Go support for Protocol Buffers - Google's data interchange format 2 | // 3 | // Copyright 2014 The Go Authors. All rights reserved. 4 | // https://github.com/golang/protobuf 5 | // 6 | // Redistribution and use in source and binary forms, with or without 7 | // modification, are permitted provided that the following conditions are 8 | // met: 9 | // 10 | // * Redistributions of source code must retain the above copyright 11 | // notice, this list of conditions and the following disclaimer. 12 | // * Redistributions in binary form must reproduce the above 13 | // copyright notice, this list of conditions and the following disclaimer 14 | // in the documentation and/or other materials provided with the 15 | // distribution. 16 | // * Neither the name of Google Inc. nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | package proto 33 | 34 | import ( 35 | "bytes" 36 | "testing" 37 | ) 38 | 39 | func TestUnmarshalMessageSetWithDuplicate(t *testing.T) { 40 | // Check that a repeated message set entry will be concatenated. 41 | in := &MessageSet{ 42 | Item: []*_MessageSet_Item{ 43 | {TypeId: Int32(12345), Message: []byte("hoo")}, 44 | {TypeId: Int32(12345), Message: []byte("hah")}, 45 | }, 46 | } 47 | b, err := Marshal(in) 48 | if err != nil { 49 | t.Fatalf("Marshal: %v", err) 50 | } 51 | t.Logf("Marshaled bytes: %q", b) 52 | 53 | m := make(map[int32]Extension) 54 | if err := UnmarshalMessageSet(b, m); err != nil { 55 | t.Fatalf("UnmarshalMessageSet: %v", err) 56 | } 57 | ext, ok := m[12345] 58 | if !ok { 59 | t.Fatalf("Didn't retrieve extension 12345; map is %v", m) 60 | } 61 | // Skip wire type/field number and length varints. 62 | got := skipVarint(skipVarint(ext.enc)) 63 | if want := []byte("hoohah"); !bytes.Equal(got, want) { 64 | t.Errorf("Combined extension is %q, want %q", got, want) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /_third_party/github.com/golang/protobuf/proto/proto3_test.go: -------------------------------------------------------------------------------- 1 | // Go support for Protocol Buffers - Google's data interchange format 2 | // 3 | // Copyright 2014 The Go Authors. All rights reserved. 4 | // https://github.com/golang/protobuf 5 | // 6 | // Redistribution and use in source and binary forms, with or without 7 | // modification, are permitted provided that the following conditions are 8 | // met: 9 | // 10 | // * Redistributions of source code must retain the above copyright 11 | // notice, this list of conditions and the following disclaimer. 12 | // * Redistributions in binary form must reproduce the above 13 | // copyright notice, this list of conditions and the following disclaimer 14 | // in the documentation and/or other materials provided with the 15 | // distribution. 16 | // * Neither the name of Google Inc. nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | package proto_test 33 | 34 | import ( 35 | "testing" 36 | 37 | "github.com/mjibson/goread/_third_party/github.com/golang/protobuf/proto" 38 | pb "github.com/mjibson/goread/_third_party/github.com/golang/protobuf/proto/proto3_proto" 39 | tpb "github.com/mjibson/goread/_third_party/github.com/golang/protobuf/proto/testdata" 40 | ) 41 | 42 | func TestProto3ZeroValues(t *testing.T) { 43 | tests := []struct { 44 | desc string 45 | m proto.Message 46 | }{ 47 | {"zero message", &pb.Message{}}, 48 | {"empty bytes field", &pb.Message{Data: []byte{}}}, 49 | } 50 | for _, test := range tests { 51 | b, err := proto.Marshal(test.m) 52 | if err != nil { 53 | t.Errorf("%s: proto.Marshal: %v", test.desc, err) 54 | continue 55 | } 56 | if len(b) > 0 { 57 | t.Errorf("%s: Encoding is non-empty: %q", test.desc, b) 58 | } 59 | } 60 | } 61 | 62 | func TestRoundTripProto3(t *testing.T) { 63 | m := &pb.Message{ 64 | Name: "David", // (2 | 1<<3): 0x0a 0x05 "David" 65 | Hilarity: pb.Message_PUNS, // (0 | 2<<3): 0x10 0x01 66 | HeightInCm: 178, // (0 | 3<<3): 0x18 0xb2 0x01 67 | Data: []byte("roboto"), // (2 | 4<<3): 0x20 0x06 "roboto" 68 | ResultCount: 47, // (0 | 7<<3): 0x38 0x2f 69 | TrueScotsman: true, // (0 | 8<<3): 0x40 0x01 70 | Score: 8.1, // (5 | 9<<3): 0x4d <8.1> 71 | 72 | Key: []uint64{1, 0xdeadbeef}, 73 | Nested: &pb.Nested{ 74 | Bunny: "Monty", 75 | }, 76 | } 77 | t.Logf(" m: %v", m) 78 | 79 | b, err := proto.Marshal(m) 80 | if err != nil { 81 | t.Fatalf("proto.Marshal: %v", err) 82 | } 83 | t.Logf(" b: %q", b) 84 | 85 | m2 := new(pb.Message) 86 | if err := proto.Unmarshal(b, m2); err != nil { 87 | t.Fatalf("proto.Unmarshal: %v", err) 88 | } 89 | t.Logf("m2: %v", m2) 90 | 91 | if !proto.Equal(m, m2) { 92 | t.Errorf("proto.Equal returned false:\n m: %v\nm2: %v", m, m2) 93 | } 94 | } 95 | 96 | func TestProto3SetDefaults(t *testing.T) { 97 | in := &pb.Message{ 98 | Terrain: map[string]*pb.Nested{ 99 | "meadow": new(pb.Nested), 100 | }, 101 | Proto2Field: new(tpb.SubDefaults), 102 | Proto2Value: map[string]*tpb.SubDefaults{ 103 | "badlands": new(tpb.SubDefaults), 104 | }, 105 | } 106 | 107 | got := proto.Clone(in).(*pb.Message) 108 | proto.SetDefaults(got) 109 | 110 | // There are no defaults in proto3. Everything should be the zero value, but 111 | // we need to remember to set defaults for nested proto2 messages. 112 | want := &pb.Message{ 113 | Terrain: map[string]*pb.Nested{ 114 | "meadow": new(pb.Nested), 115 | }, 116 | Proto2Field: &tpb.SubDefaults{N: proto.Int64(7)}, 117 | Proto2Value: map[string]*tpb.SubDefaults{ 118 | "badlands": &tpb.SubDefaults{N: proto.Int64(7)}, 119 | }, 120 | } 121 | 122 | if !proto.Equal(got, want) { 123 | t.Errorf("with in = %v\nproto.SetDefaults(in) =>\ngot %v\nwant %v", in, got, want) 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /_third_party/github.com/golang/protobuf/proto/size2_test.go: -------------------------------------------------------------------------------- 1 | // Go support for Protocol Buffers - Google's data interchange format 2 | // 3 | // Copyright 2012 The Go Authors. All rights reserved. 4 | // https://github.com/golang/protobuf 5 | // 6 | // Redistribution and use in source and binary forms, with or without 7 | // modification, are permitted provided that the following conditions are 8 | // met: 9 | // 10 | // * Redistributions of source code must retain the above copyright 11 | // notice, this list of conditions and the following disclaimer. 12 | // * Redistributions in binary form must reproduce the above 13 | // copyright notice, this list of conditions and the following disclaimer 14 | // in the documentation and/or other materials provided with the 15 | // distribution. 16 | // * Neither the name of Google Inc. nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | package proto 33 | 34 | import ( 35 | "testing" 36 | ) 37 | 38 | // This is a separate file and package from size_test.go because that one uses 39 | // generated messages and thus may not be in package proto without having a circular 40 | // dependency, whereas this file tests unexported details of size.go. 41 | 42 | func TestVarintSize(t *testing.T) { 43 | // Check the edge cases carefully. 44 | testCases := []struct { 45 | n uint64 46 | size int 47 | }{ 48 | {0, 1}, 49 | {1, 1}, 50 | {127, 1}, 51 | {128, 2}, 52 | {16383, 2}, 53 | {16384, 3}, 54 | {1<<63 - 1, 9}, 55 | {1 << 63, 10}, 56 | } 57 | for _, tc := range testCases { 58 | size := sizeVarint(tc.n) 59 | if size != tc.size { 60 | t.Errorf("sizeVarint(%d) = %d, want %d", tc.n, size, tc.size) 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /_third_party/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 | -------------------------------------------------------------------------------- /_third_party/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 | -------------------------------------------------------------------------------- /_third_party/github.com/gorilla/context/context.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Gorilla 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 context 6 | 7 | import ( 8 | "net/http" 9 | "sync" 10 | "time" 11 | ) 12 | 13 | var ( 14 | mutex sync.RWMutex 15 | data = make(map[*http.Request]map[interface{}]interface{}) 16 | datat = make(map[*http.Request]int64) 17 | ) 18 | 19 | // Set stores a value for a given key in a given request. 20 | func Set(r *http.Request, key, val interface{}) { 21 | mutex.Lock() 22 | if data[r] == nil { 23 | data[r] = make(map[interface{}]interface{}) 24 | datat[r] = time.Now().Unix() 25 | } 26 | data[r][key] = val 27 | mutex.Unlock() 28 | } 29 | 30 | // Get returns a value stored for a given key in a given request. 31 | func Get(r *http.Request, key interface{}) interface{} { 32 | mutex.RLock() 33 | if ctx := data[r]; ctx != nil { 34 | value := ctx[key] 35 | mutex.RUnlock() 36 | return value 37 | } 38 | mutex.RUnlock() 39 | return nil 40 | } 41 | 42 | // GetOk returns stored value and presence state like multi-value return of map access. 43 | func GetOk(r *http.Request, key interface{}) (interface{}, bool) { 44 | mutex.RLock() 45 | if _, ok := data[r]; ok { 46 | value, ok := data[r][key] 47 | mutex.RUnlock() 48 | return value, ok 49 | } 50 | mutex.RUnlock() 51 | return nil, false 52 | } 53 | 54 | // GetAll returns all stored values for the request as a map. Nil is returned for invalid requests. 55 | func GetAll(r *http.Request) map[interface{}]interface{} { 56 | mutex.RLock() 57 | if context, ok := data[r]; ok { 58 | result := make(map[interface{}]interface{}, len(context)) 59 | for k, v := range context { 60 | result[k] = v 61 | } 62 | mutex.RUnlock() 63 | return result 64 | } 65 | mutex.RUnlock() 66 | return nil 67 | } 68 | 69 | // GetAllOk returns all stored values for the request as a map and a boolean value that indicates if 70 | // the request was registered. 71 | func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) { 72 | mutex.RLock() 73 | context, ok := data[r] 74 | result := make(map[interface{}]interface{}, len(context)) 75 | for k, v := range context { 76 | result[k] = v 77 | } 78 | mutex.RUnlock() 79 | return result, ok 80 | } 81 | 82 | // Delete removes a value stored for a given key in a given request. 83 | func Delete(r *http.Request, key interface{}) { 84 | mutex.Lock() 85 | if data[r] != nil { 86 | delete(data[r], key) 87 | } 88 | mutex.Unlock() 89 | } 90 | 91 | // Clear removes all values stored for a given request. 92 | // 93 | // This is usually called by a handler wrapper to clean up request 94 | // variables at the end of a request lifetime. See ClearHandler(). 95 | func Clear(r *http.Request) { 96 | mutex.Lock() 97 | clear(r) 98 | mutex.Unlock() 99 | } 100 | 101 | // clear is Clear without the lock. 102 | func clear(r *http.Request) { 103 | delete(data, r) 104 | delete(datat, r) 105 | } 106 | 107 | // Purge removes request data stored for longer than maxAge, in seconds. 108 | // It returns the amount of requests removed. 109 | // 110 | // If maxAge <= 0, all request data is removed. 111 | // 112 | // This is only used for sanity check: in case context cleaning was not 113 | // properly set some request data can be kept forever, consuming an increasing 114 | // amount of memory. In case this is detected, Purge() must be called 115 | // periodically until the problem is fixed. 116 | func Purge(maxAge int) int { 117 | mutex.Lock() 118 | count := 0 119 | if maxAge <= 0 { 120 | count = len(data) 121 | data = make(map[*http.Request]map[interface{}]interface{}) 122 | datat = make(map[*http.Request]int64) 123 | } else { 124 | min := time.Now().Unix() - int64(maxAge) 125 | for r := range data { 126 | if datat[r] < min { 127 | clear(r) 128 | count++ 129 | } 130 | } 131 | } 132 | mutex.Unlock() 133 | return count 134 | } 135 | 136 | // ClearHandler wraps an http.Handler and clears request values at the end 137 | // of a request lifetime. 138 | func ClearHandler(h http.Handler) http.Handler { 139 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 140 | defer Clear(r) 141 | h.ServeHTTP(w, r) 142 | }) 143 | } 144 | -------------------------------------------------------------------------------- /_third_party/github.com/gorilla/context/context_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Gorilla 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 context 6 | 7 | import ( 8 | "net/http" 9 | "testing" 10 | ) 11 | 12 | type keyType int 13 | 14 | const ( 15 | key1 keyType = iota 16 | key2 17 | ) 18 | 19 | func TestContext(t *testing.T) { 20 | assertEqual := func(val interface{}, exp interface{}) { 21 | if val != exp { 22 | t.Errorf("Expected %v, got %v.", exp, val) 23 | } 24 | } 25 | 26 | r, _ := http.NewRequest("GET", "http://localhost:8080/", nil) 27 | emptyR, _ := http.NewRequest("GET", "http://localhost:8080/", nil) 28 | 29 | // Get() 30 | assertEqual(Get(r, key1), nil) 31 | 32 | // Set() 33 | Set(r, key1, "1") 34 | assertEqual(Get(r, key1), "1") 35 | assertEqual(len(data[r]), 1) 36 | 37 | Set(r, key2, "2") 38 | assertEqual(Get(r, key2), "2") 39 | assertEqual(len(data[r]), 2) 40 | 41 | //GetOk 42 | value, ok := GetOk(r, key1) 43 | assertEqual(value, "1") 44 | assertEqual(ok, true) 45 | 46 | value, ok = GetOk(r, "not exists") 47 | assertEqual(value, nil) 48 | assertEqual(ok, false) 49 | 50 | Set(r, "nil value", nil) 51 | value, ok = GetOk(r, "nil value") 52 | assertEqual(value, nil) 53 | assertEqual(ok, true) 54 | 55 | // GetAll() 56 | values := GetAll(r) 57 | assertEqual(len(values), 3) 58 | 59 | // GetAll() for empty request 60 | values = GetAll(emptyR) 61 | if values != nil { 62 | t.Error("GetAll didn't return nil value for invalid request") 63 | } 64 | 65 | // GetAllOk() 66 | values, ok = GetAllOk(r) 67 | assertEqual(len(values), 3) 68 | assertEqual(ok, true) 69 | 70 | // GetAllOk() for empty request 71 | values, ok = GetAllOk(emptyR) 72 | assertEqual(value, nil) 73 | assertEqual(ok, false) 74 | 75 | // Delete() 76 | Delete(r, key1) 77 | assertEqual(Get(r, key1), nil) 78 | assertEqual(len(data[r]), 2) 79 | 80 | Delete(r, key2) 81 | assertEqual(Get(r, key2), nil) 82 | assertEqual(len(data[r]), 1) 83 | 84 | // Clear() 85 | Clear(r) 86 | assertEqual(len(data), 0) 87 | } 88 | 89 | func parallelReader(r *http.Request, key string, iterations int, wait, done chan struct{}) { 90 | <-wait 91 | for i := 0; i < iterations; i++ { 92 | Get(r, key) 93 | } 94 | done <- struct{}{} 95 | 96 | } 97 | 98 | func parallelWriter(r *http.Request, key, value string, iterations int, wait, done chan struct{}) { 99 | <-wait 100 | for i := 0; i < iterations; i++ { 101 | Set(r, key, value) 102 | } 103 | done <- struct{}{} 104 | 105 | } 106 | 107 | func benchmarkMutex(b *testing.B, numReaders, numWriters, iterations int) { 108 | 109 | b.StopTimer() 110 | r, _ := http.NewRequest("GET", "http://localhost:8080/", nil) 111 | done := make(chan struct{}) 112 | b.StartTimer() 113 | 114 | for i := 0; i < b.N; i++ { 115 | wait := make(chan struct{}) 116 | 117 | for i := 0; i < numReaders; i++ { 118 | go parallelReader(r, "test", iterations, wait, done) 119 | } 120 | 121 | for i := 0; i < numWriters; i++ { 122 | go parallelWriter(r, "test", "123", iterations, wait, done) 123 | } 124 | 125 | close(wait) 126 | 127 | for i := 0; i < numReaders+numWriters; i++ { 128 | <-done 129 | } 130 | 131 | } 132 | 133 | } 134 | 135 | func BenchmarkMutexSameReadWrite1(b *testing.B) { 136 | benchmarkMutex(b, 1, 1, 32) 137 | } 138 | func BenchmarkMutexSameReadWrite2(b *testing.B) { 139 | benchmarkMutex(b, 2, 2, 32) 140 | } 141 | func BenchmarkMutexSameReadWrite4(b *testing.B) { 142 | benchmarkMutex(b, 4, 4, 32) 143 | } 144 | func BenchmarkMutex1(b *testing.B) { 145 | benchmarkMutex(b, 2, 8, 32) 146 | } 147 | func BenchmarkMutex2(b *testing.B) { 148 | benchmarkMutex(b, 16, 4, 64) 149 | } 150 | func BenchmarkMutex3(b *testing.B) { 151 | benchmarkMutex(b, 1, 2, 128) 152 | } 153 | func BenchmarkMutex4(b *testing.B) { 154 | benchmarkMutex(b, 128, 32, 256) 155 | } 156 | func BenchmarkMutex5(b *testing.B) { 157 | benchmarkMutex(b, 1024, 2048, 64) 158 | } 159 | func BenchmarkMutex6(b *testing.B) { 160 | benchmarkMutex(b, 2048, 1024, 512) 161 | } 162 | -------------------------------------------------------------------------------- /_third_party/github.com/gorilla/context/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Gorilla 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 | /* 6 | Package context stores values shared during a request lifetime. 7 | 8 | For example, a router can set variables extracted from the URL and later 9 | application handlers can access those values, or it can be used to store 10 | sessions values to be saved at the end of a request. There are several 11 | others common uses. 12 | 13 | The idea was posted by Brad Fitzpatrick to the go-nuts mailing list: 14 | 15 | http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53 16 | 17 | Here's the basic usage: first define the keys that you will need. The key 18 | type is interface{} so a key can be of any type that supports equality. 19 | Here we define a key using a custom int type to avoid name collisions: 20 | 21 | package foo 22 | 23 | import ( 24 | "github.com/gorilla/context" 25 | ) 26 | 27 | type key int 28 | 29 | const MyKey key = 0 30 | 31 | Then set a variable. Variables are bound to an http.Request object, so you 32 | need a request instance to set a value: 33 | 34 | context.Set(r, MyKey, "bar") 35 | 36 | The application can later access the variable using the same key you provided: 37 | 38 | func MyHandler(w http.ResponseWriter, r *http.Request) { 39 | // val is "bar". 40 | val := context.Get(r, foo.MyKey) 41 | 42 | // returns ("bar", true) 43 | val, ok := context.GetOk(r, foo.MyKey) 44 | // ... 45 | } 46 | 47 | And that's all about the basic usage. We discuss some other ideas below. 48 | 49 | Any type can be stored in the context. To enforce a given type, make the key 50 | private and wrap Get() and Set() to accept and return values of a specific 51 | type: 52 | 53 | type key int 54 | 55 | const mykey key = 0 56 | 57 | // GetMyKey returns a value for this package from the request values. 58 | func GetMyKey(r *http.Request) SomeType { 59 | if rv := context.Get(r, mykey); rv != nil { 60 | return rv.(SomeType) 61 | } 62 | return nil 63 | } 64 | 65 | // SetMyKey sets a value for this package in the request values. 66 | func SetMyKey(r *http.Request, val SomeType) { 67 | context.Set(r, mykey, val) 68 | } 69 | 70 | Variables must be cleared at the end of a request, to remove all values 71 | that were stored. This can be done in an http.Handler, after a request was 72 | served. Just call Clear() passing the request: 73 | 74 | context.Clear(r) 75 | 76 | ...or use ClearHandler(), which conveniently wraps an http.Handler to clear 77 | variables at the end of a request lifetime. 78 | 79 | The Routers from the packages gorilla/mux and gorilla/pat call Clear() 80 | so if you are using either of them you don't need to clear the context manually. 81 | */ 82 | package context 83 | -------------------------------------------------------------------------------- /_third_party/github.com/gorilla/mux/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 | -------------------------------------------------------------------------------- /_third_party/github.com/gorilla/mux/README.md: -------------------------------------------------------------------------------- 1 | mux 2 | === 3 | [![Build Status](https://travis-ci.org/gorilla/mux.png?branch=master)](https://travis-ci.org/gorilla/mux) 4 | 5 | gorilla/mux is a powerful URL router and dispatcher. 6 | 7 | Read the full documentation here: http://www.gorillatoolkit.org/pkg/mux 8 | -------------------------------------------------------------------------------- /_third_party/github.com/gorilla/mux/bench_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Gorilla 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 mux 6 | 7 | import ( 8 | "net/http" 9 | "testing" 10 | ) 11 | 12 | func BenchmarkMux(b *testing.B) { 13 | router := new(Router) 14 | handler := func(w http.ResponseWriter, r *http.Request) {} 15 | router.HandleFunc("/v1/{v1}", handler) 16 | 17 | request, _ := http.NewRequest("GET", "/v1/anything", nil) 18 | for i := 0; i < b.N; i++ { 19 | router.ServeHTTP(nil, request) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /_third_party/github.com/mjibson/appstats/README.md: -------------------------------------------------------------------------------- 1 | # appstats 2 | 3 | A port of the python appstats implementation to the Go runtime on Google App Engine. 4 | 5 | For installation and usage, see the docs: [http://godoc.org/github.com/mjibson/appstats](http://godoc.org/github.com/mjibson/appstats). 6 | -------------------------------------------------------------------------------- /_third_party/github.com/mjibson/appstats/bytesize.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go 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 appstats 6 | 7 | import ( 8 | "fmt" 9 | ) 10 | 11 | type byteSize float64 12 | 13 | const ( 14 | _ = iota 15 | _KB byteSize = 1 << (10 * iota) 16 | _MB 17 | _GB 18 | _TB 19 | _PB 20 | _EB 21 | _ZB 22 | _YB 23 | ) 24 | 25 | func (b byteSize) String() string { 26 | switch { 27 | case b >= _YB: 28 | return fmt.Sprintf("%.2fYB", b/_YB) 29 | case b >= _ZB: 30 | return fmt.Sprintf("%.2fZB", b/_ZB) 31 | case b >= _EB: 32 | return fmt.Sprintf("%.2fEB", b/_EB) 33 | case b >= _PB: 34 | return fmt.Sprintf("%.2fPB", b/_PB) 35 | case b >= _TB: 36 | return fmt.Sprintf("%.2fTB", b/_TB) 37 | case b >= _GB: 38 | return fmt.Sprintf("%.2fGB", b/_GB) 39 | case b >= _MB: 40 | return fmt.Sprintf("%.2fMB", b/_MB) 41 | case b >= _KB: 42 | return fmt.Sprintf("%.2fKB", b/_KB) 43 | } 44 | return fmt.Sprintf("%.2fB", b) 45 | } 46 | -------------------------------------------------------------------------------- /_third_party/github.com/mjibson/appstats/cost.go: -------------------------------------------------------------------------------- 1 | package appstats 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/mjibson/goread/_third_party/github.com/golang/protobuf/proto" 7 | ) 8 | 9 | const ( 10 | cost_Write = 10 11 | cost_Read = 7 12 | cost_Small = 1 13 | ) 14 | 15 | // todo: implement read and small ops costs 16 | 17 | func getCost(p proto.Message) int64 { 18 | v := reflect.ValueOf(p) 19 | v = reflect.Indirect(v) 20 | if v.Kind() != reflect.Struct { 21 | return 0 22 | } 23 | 24 | var cost int64 25 | cost += extractCost(v) 26 | 27 | return cost 28 | } 29 | 30 | func extractCost(v reflect.Value) int64 { 31 | v = v.FieldByName("Cost") 32 | if v.Kind() != reflect.Ptr { 33 | return 0 34 | } 35 | v = v.Elem() 36 | if v.Kind() != reflect.Struct { 37 | return 0 38 | } 39 | 40 | var cost int64 41 | 42 | extract := func(name string) int64 { 43 | w := v.FieldByName(name) 44 | if w.Kind() != reflect.Ptr { 45 | return 0 46 | } 47 | w = w.Elem() 48 | switch w.Kind() { 49 | case reflect.Int, reflect.Int32, reflect.Int64: 50 | return w.Int() 51 | } 52 | 53 | return 0 54 | } 55 | 56 | cost += extract("IndexWrites") 57 | cost += extract("EntityWrites") 58 | 59 | return cost * cost_Write 60 | } 61 | -------------------------------------------------------------------------------- /_third_party/github.com/mjibson/appstats/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Matt Jibson 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | Package appstats profiles the RPC performance of Google App Engine applications. 19 | 20 | Reference: https://developers.google.com/appengine/docs/python/tools/appstats 21 | 22 | To use this package, change your HTTP handler functions to use this signature: 23 | 24 | func(appengine.Context, http.ResponseWriter, *http.Request) 25 | 26 | Register them in the usual way, wrapping them with NewHandler. 27 | 28 | 29 | Example 30 | 31 | This is a small example using this package. 32 | 33 | import ( 34 | "net/http" 35 | 36 | "appengine" 37 | 38 | "github.com/mjibson/appstats" 39 | ) 40 | 41 | func init() { 42 | http.Handle("/", appstats.NewHandler(Main)) 43 | } 44 | 45 | func Main(c appengine.Context, w http.ResponseWriter, r *http.Request) { 46 | // do stuff with c: datastore.Get(c, key, entity) 47 | w.Write([]byte("success")) 48 | } 49 | 50 | 51 | Usage 52 | 53 | Use your app, and view the appstats interface at http://localhost:8080/_ah/stats/, or your production URL. 54 | 55 | 56 | Configuration 57 | 58 | Refer to the variables section of the documentation: http://godoc.org/github.com/mjibson/appstats#pkg-variables. 59 | 60 | 61 | Routing 62 | 63 | In general, your app.yaml will not need to change. In the case of conflicting 64 | routes, add the following to your app.yaml: 65 | 66 | handlers: 67 | - url: /_ah/stats/.* 68 | script: _go_app 69 | 70 | 71 | TODO 72 | 73 | Cost calculation is experimental. Currently it only includes write ops (read and small ops are TODO). 74 | */ 75 | package appstats 76 | -------------------------------------------------------------------------------- /_third_party/github.com/mjibson/appstats/funcs.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Matt Jibson 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package appstats 18 | 19 | import ( 20 | "html/template" 21 | "reflect" 22 | "strconv" 23 | "strings" 24 | ) 25 | 26 | // eq reports whether the first argument is equal to 27 | // any of the remaining arguments. 28 | func eq(args ...interface{}) bool { 29 | if len(args) == 0 { 30 | return false 31 | } 32 | x := args[0] 33 | switch x := x.(type) { 34 | case string, int, int64, byte, float32, float64: 35 | for _, y := range args[1:] { 36 | if x == y { 37 | return true 38 | } 39 | } 40 | return false 41 | } 42 | 43 | for _, y := range args[1:] { 44 | if reflect.DeepEqual(x, y) { 45 | return true 46 | } 47 | } 48 | return false 49 | } 50 | 51 | func add(a, b int) int { 52 | return a + b 53 | } 54 | 55 | func rjust(i, count int) string { 56 | s := strconv.Itoa(i) 57 | return strings.Repeat(" ", count-len(s)) + s 58 | } 59 | 60 | func lt(a, b int) bool { 61 | return a < b 62 | } 63 | 64 | var funcs = template.FuncMap{ 65 | "add": add, 66 | "eq": eq, 67 | "lt": lt, 68 | "rjust": rjust, 69 | } 70 | -------------------------------------------------------------------------------- /_third_party/github.com/mjibson/appstats/types.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Matt Jibson 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package appstats 18 | 19 | import ( 20 | "fmt" 21 | "net/http" 22 | "sort" 23 | "strconv" 24 | "strings" 25 | "sync" 26 | "time" 27 | ) 28 | 29 | const ( 30 | keyPrefix = "__appstats__:" 31 | keyPart = keyPrefix + "%06d:part" 32 | keyFull = keyPrefix + "%06d:full" 33 | distance = 100 34 | modulus = 1000 35 | ) 36 | 37 | type requestStats struct { 38 | User string 39 | Admin bool 40 | Method string 41 | Path, Query string 42 | Status int 43 | Cost int64 44 | Start time.Time 45 | Duration time.Duration 46 | RPCStats []rpcStat 47 | 48 | lock sync.Mutex 49 | wg sync.WaitGroup 50 | } 51 | 52 | type stats_part requestStats 53 | 54 | type stats_full struct { 55 | Header http.Header 56 | Stats *requestStats 57 | } 58 | 59 | func (r *requestStats) PartKey() string { 60 | t := roundTime(r.Start.Nanosecond()) 61 | return fmt.Sprintf(keyPart, t) 62 | } 63 | 64 | func (r *requestStats) FullKey() string { 65 | t := roundTime(r.Start.Nanosecond()) 66 | return fmt.Sprintf(keyFull, t) 67 | } 68 | 69 | func roundTime(i int) int { 70 | return (i / 1000 / distance) % modulus * distance 71 | } 72 | 73 | type rpcStat struct { 74 | Service, Method string 75 | Start time.Time 76 | Offset time.Duration 77 | Duration time.Duration 78 | StackData string 79 | In, Out string 80 | Cost int64 81 | } 82 | 83 | func (r rpcStat) Name() string { 84 | return r.Service + "." + r.Method 85 | } 86 | 87 | func (r rpcStat) Request() string { 88 | return r.In 89 | } 90 | 91 | func (r rpcStat) Response() string { 92 | return r.Out 93 | } 94 | 95 | func (r rpcStat) Stack() stack { 96 | s := stack{} 97 | 98 | if r.StackData == "" { 99 | return s 100 | } 101 | 102 | lines := strings.Split(r.StackData, "\n") 103 | for i := 0; i < len(lines); i++ { 104 | idx := strings.LastIndex(lines[i], " ") 105 | if idx == -1 { 106 | break 107 | } 108 | 109 | cidx := strings.LastIndex(lines[i], ":") 110 | lineno, _ := strconv.Atoi(lines[i][cidx+1 : idx]) 111 | f := &frame{ 112 | Location: lines[i][:cidx], 113 | Lineno: lineno, 114 | } 115 | 116 | if i+1 < len(lines) && strings.HasPrefix(lines[i+1], "\t") { 117 | f.Call = strings.TrimSpace(lines[i+1]) 118 | i++ 119 | } 120 | 121 | s = append(s, f) 122 | } 123 | 124 | return s[2:] 125 | } 126 | 127 | type stack []*frame 128 | 129 | type frame struct { 130 | Location string 131 | Call string 132 | Lineno int 133 | } 134 | 135 | type allrequestStats []*requestStats 136 | 137 | func (s allrequestStats) Len() int { return len(s) } 138 | func (s allrequestStats) Less(i, j int) bool { return s[i].Start.Sub(s[j].Start) < 0 } 139 | func (s allrequestStats) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 140 | 141 | type statsByName []*statByName 142 | 143 | func (s statsByName) Len() int { return len(s) } 144 | func (s statsByName) Less(i, j int) bool { return s[i].Count < s[j].Count } 145 | func (s statsByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 146 | 147 | type statByName struct { 148 | Name string 149 | Count int 150 | Cost int64 151 | SubStats []*statByName 152 | Requests int 153 | RecentReqs []int 154 | RequestStats *requestStats 155 | Duration time.Duration 156 | } 157 | 158 | type reverse struct{ sort.Interface } 159 | 160 | func (r reverse) Less(i, j int) bool { return r.Interface.Less(j, i) } 161 | 162 | type skey struct { 163 | a, b string 164 | } 165 | 166 | type cVal struct { 167 | count int 168 | cost int64 169 | } 170 | -------------------------------------------------------------------------------- /_third_party/github.com/mjibson/goon/README.md: -------------------------------------------------------------------------------- 1 | # goon 2 | 3 | An autocaching interface to the app engine datastore for Go. Designed to be similar to the python NDB package. 4 | 5 | Documentation: [http://godoc.org/github.com/mjibson/goon](http://godoc.org/github.com/mjibson/goon) 6 | -------------------------------------------------------------------------------- /_third_party/github.com/mjibson/goon/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package goon provides an autocaching interface to the app engine datastore 3 | similar to the python NDB package. 4 | 5 | Goon differs from the datastore package in various ways: it remembers the 6 | appengine Context, which need only be specified once at creation time; kinds 7 | need not be specified as they are computed, by default, from a type's name; 8 | keys are inferred from specially-tagged fields on types, removing the need to 9 | pass key objects around. 10 | 11 | In general, the difference is that Goon's API is identical to the datastore API, 12 | it's just shorter. 13 | 14 | Keys in Goon are stored in the structs themselves. Below is an example struct 15 | with a field to specify the id (see the Key Specifications section below for 16 | full documentation). 17 | type User struct { 18 | Id string `datastore:"-" goon:"id"` 19 | Name string 20 | } 21 | 22 | Thus, to get a User with id 2: 23 | userid := 2 24 | g := goon.NewGoon(r) 25 | u := &User{Id: userid} 26 | g.Get(u) 27 | 28 | Key Specifications 29 | 30 | For both the Key and KeyError functions, src must be a S or *S for some 31 | struct type S. The key is extracted based on various fields of S. If a field 32 | of type int64 or string has a struct tag named goon with value "id", it is 33 | used as the key's id. If a field of type *datastore.Key has a struct tag 34 | named goon with value "parent", it is used as the key's parent. If a field 35 | of type string has a struct tag named goon with value "kind", it is used 36 | as the key's kind. The "kind" field supports an optional second parameter 37 | which is the default kind name. If no kind field exists, the struct's name 38 | is used. These fields should all have their datastore field marked as "-". 39 | 40 | Example, with kind User: 41 | type User struct { 42 | Id string `datastore:"-" goon:"id"` 43 | Read time.Time 44 | } 45 | 46 | Example, with kind U if _kind is the empty string: 47 | type User struct { 48 | _kind string `goon:"kind,U"` 49 | Id string `datastore:"-" goon:"id"` 50 | Read time.Time 51 | } 52 | 53 | To override kind of a single entity to UserKind: 54 | u := User{_kind: "UserKind"} 55 | 56 | An example with both parent and kind: 57 | type UserData struct { 58 | Id string `datastore:"-" goon:"id"` 59 | _kind string `goon:"kind,UD"` 60 | Parent *datastore.Key `datastore:"-" goon:"parent"` 61 | Data []byte 62 | } 63 | 64 | Features 65 | 66 | Datastore interaction with: Get, GetMulti, Put, PutMulti, Delete, DeleteMulti, Queries. 67 | 68 | All key-based operations backed by memory and memcache. 69 | 70 | Per-request, in-memory cache: fetch the same key twice, the second request is served from local memory. 71 | 72 | Intelligent multi support: running GetMulti correctly fetches from memory, then memcache, then the datastore; each tier only sends keys off to the next one if they were missing. 73 | 74 | Memcache control variance: long memcache requests are cancelled. 75 | 76 | Transactions use a separate context, but locally cache any results on success. 77 | 78 | Automatic kind naming: struct names are inferred by reflection, removing the need to manually specify key kinds. 79 | 80 | Simpler API than appengine/datastore. 81 | 82 | API comparison between goon and datastore 83 | 84 | put with incomplete key 85 | 86 | datastore: 87 | 88 | type Group struct { 89 | Name string 90 | } 91 | c := appengine.NewContext(r) 92 | g := &Group{Name: "name"} 93 | k := datastore.NewIncompleteKey(c, "Group", nil) 94 | err := datastore.Put(c, k, g) 95 | 96 | goon: 97 | 98 | type Group struct { 99 | Id int64 `datastore:"-" goon:"id"` 100 | Name string 101 | } 102 | n := goon.NewGoon(r) 103 | g := &Group{Name: "name"} 104 | err := n.Put(g) 105 | 106 | get with known key 107 | 108 | datastore: 109 | 110 | type Group struct { 111 | Name string 112 | } 113 | c := appengine.NewContext(r) 114 | g := &Group{} 115 | k := datastore.NewKey(c, "Group", "", 1, nil) 116 | err := datastore.Get(c, k, g) 117 | 118 | goon: 119 | 120 | type Group struct { 121 | Id int64 `datastore:"-" goon:"id"` 122 | Name string 123 | } 124 | n := goon.NewGoon(r) 125 | g := &Group{Id: 1} 126 | err := n.Get(g) 127 | 128 | Memcache Control Variance 129 | 130 | Memcache is generally fast. When it is slow, goon will timeout the memcache 131 | requests and proceed to use the datastore directly. The memcache put and 132 | get timeout variables determine how long to wait for various kinds of 133 | requests. The default settings were determined experimentally and should 134 | provide reasonable defaults for most applications. 135 | 136 | See: http://talks.golang.org/2013/highperf.slide#23 137 | */ 138 | package goon 139 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/net/html/atom/atom.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go 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 atom provides integer codes (also known as atoms) for a fixed set of 6 | // frequently occurring HTML strings: tag names and attribute keys such as "p" 7 | // and "id". 8 | // 9 | // Sharing an atom's name between all elements with the same tag can result in 10 | // fewer string allocations when tokenizing and parsing HTML. Integer 11 | // comparisons are also generally faster than string comparisons. 12 | // 13 | // The value of an atom's particular code is not guaranteed to stay the same 14 | // between versions of this package. Neither is any ordering guaranteed: 15 | // whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to 16 | // be dense. The only guarantees are that e.g. looking up "div" will yield 17 | // atom.Div, calling atom.Div.String will return "div", and atom.Div != 0. 18 | package atom // import "github.com/mjibson/goread/_third_party/golang.org/x/net/html/atom" 19 | 20 | // Atom is an integer code for a string. The zero value maps to "". 21 | type Atom uint32 22 | 23 | // String returns the atom's name. 24 | func (a Atom) String() string { 25 | start := uint32(a >> 8) 26 | n := uint32(a & 0xff) 27 | if start+n > uint32(len(atomText)) { 28 | return "" 29 | } 30 | return atomText[start : start+n] 31 | } 32 | 33 | func (a Atom) string() string { 34 | return atomText[a>>8 : a>>8+a&0xff] 35 | } 36 | 37 | // fnv computes the FNV hash with an arbitrary starting value h. 38 | func fnv(h uint32, s []byte) uint32 { 39 | for i := range s { 40 | h ^= uint32(s[i]) 41 | h *= 16777619 42 | } 43 | return h 44 | } 45 | 46 | func match(s string, t []byte) bool { 47 | for i, c := range t { 48 | if s[i] != c { 49 | return false 50 | } 51 | } 52 | return true 53 | } 54 | 55 | // Lookup returns the atom whose name is s. It returns zero if there is no 56 | // such atom. The lookup is case sensitive. 57 | func Lookup(s []byte) Atom { 58 | if len(s) == 0 || len(s) > maxAtomLen { 59 | return 0 60 | } 61 | h := fnv(hash0, s) 62 | if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) { 63 | return a 64 | } 65 | if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) { 66 | return a 67 | } 68 | return 0 69 | } 70 | 71 | // String returns a string whose contents are equal to s. In that sense, it is 72 | // equivalent to string(s) but may be more efficient. 73 | func String(s []byte) string { 74 | if a := Lookup(s); a != 0 { 75 | return a.String() 76 | } 77 | return string(s) 78 | } 79 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/net/html/atom/atom_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go 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 atom 6 | 7 | import ( 8 | "sort" 9 | "testing" 10 | ) 11 | 12 | func TestKnown(t *testing.T) { 13 | for _, s := range testAtomList { 14 | if atom := Lookup([]byte(s)); atom.String() != s { 15 | t.Errorf("Lookup(%q) = %#x (%q)", s, uint32(atom), atom.String()) 16 | } 17 | } 18 | } 19 | 20 | func TestHits(t *testing.T) { 21 | for _, a := range table { 22 | if a == 0 { 23 | continue 24 | } 25 | got := Lookup([]byte(a.String())) 26 | if got != a { 27 | t.Errorf("Lookup(%q) = %#x, want %#x", a.String(), uint32(got), uint32(a)) 28 | } 29 | } 30 | } 31 | 32 | func TestMisses(t *testing.T) { 33 | testCases := []string{ 34 | "", 35 | "\x00", 36 | "\xff", 37 | "A", 38 | "DIV", 39 | "Div", 40 | "dIV", 41 | "aa", 42 | "a\x00", 43 | "ab", 44 | "abb", 45 | "abbr0", 46 | "abbr ", 47 | " abbr", 48 | " a", 49 | "acceptcharset", 50 | "acceptCharset", 51 | "accept_charset", 52 | "h0", 53 | "h1h2", 54 | "h7", 55 | "onClick", 56 | "λ", 57 | // The following string has the same hash (0xa1d7fab7) as "onmouseover". 58 | "\x00\x00\x00\x00\x00\x50\x18\xae\x38\xd0\xb7", 59 | } 60 | for _, tc := range testCases { 61 | got := Lookup([]byte(tc)) 62 | if got != 0 { 63 | t.Errorf("Lookup(%q): got %d, want 0", tc, got) 64 | } 65 | } 66 | } 67 | 68 | func TestForeignObject(t *testing.T) { 69 | const ( 70 | afo = Foreignobject 71 | afO = ForeignObject 72 | sfo = "foreignobject" 73 | sfO = "foreignObject" 74 | ) 75 | if got := Lookup([]byte(sfo)); got != afo { 76 | t.Errorf("Lookup(%q): got %#v, want %#v", sfo, got, afo) 77 | } 78 | if got := Lookup([]byte(sfO)); got != afO { 79 | t.Errorf("Lookup(%q): got %#v, want %#v", sfO, got, afO) 80 | } 81 | if got := afo.String(); got != sfo { 82 | t.Errorf("Atom(%#v).String(): got %q, want %q", afo, got, sfo) 83 | } 84 | if got := afO.String(); got != sfO { 85 | t.Errorf("Atom(%#v).String(): got %q, want %q", afO, got, sfO) 86 | } 87 | } 88 | 89 | func BenchmarkLookup(b *testing.B) { 90 | sortedTable := make([]string, 0, len(table)) 91 | for _, a := range table { 92 | if a != 0 { 93 | sortedTable = append(sortedTable, a.String()) 94 | } 95 | } 96 | sort.Strings(sortedTable) 97 | 98 | x := make([][]byte, 1000) 99 | for i := range x { 100 | x[i] = []byte(sortedTable[i%len(sortedTable)]) 101 | } 102 | 103 | b.ResetTimer() 104 | for i := 0; i < b.N; i++ { 105 | for _, s := range x { 106 | Lookup(s) 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/net/html/charset/gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go 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 | // +build ignore 6 | 7 | package main 8 | 9 | // Download https://encoding.spec.whatwg.org/encodings.json and use it to 10 | // generate table.go. 11 | 12 | import ( 13 | "encoding/json" 14 | "fmt" 15 | "log" 16 | "net/http" 17 | "strings" 18 | ) 19 | 20 | type enc struct { 21 | Name string 22 | Labels []string 23 | } 24 | 25 | type group struct { 26 | Encodings []enc 27 | Heading string 28 | } 29 | 30 | const specURL = "https://encoding.spec.whatwg.org/encodings.json" 31 | 32 | func main() { 33 | resp, err := http.Get(specURL) 34 | if err != nil { 35 | log.Fatalf("error fetching %s: %s", specURL, err) 36 | } 37 | if resp.StatusCode != 200 { 38 | log.Fatalf("error fetching %s: HTTP status %s", specURL, resp.Status) 39 | } 40 | defer resp.Body.Close() 41 | 42 | var groups []group 43 | d := json.NewDecoder(resp.Body) 44 | err = d.Decode(&groups) 45 | if err != nil { 46 | log.Fatalf("error reading encodings.json: %s", err) 47 | } 48 | 49 | fmt.Println("// generated by go run gen.go; DO NOT EDIT") 50 | fmt.Println() 51 | fmt.Println("package charset") 52 | fmt.Println() 53 | 54 | fmt.Println("import (") 55 | fmt.Println(`"golang.org/x/text/encoding"`) 56 | for _, pkg := range []string{"charmap", "japanese", "korean", "simplifiedchinese", "traditionalchinese", "unicode"} { 57 | fmt.Printf("\"golang.org/x/text/encoding/%s\"\n", pkg) 58 | } 59 | fmt.Println(")") 60 | fmt.Println() 61 | 62 | fmt.Println("var encodings = map[string]struct{e encoding.Encoding; name string} {") 63 | for _, g := range groups { 64 | for _, e := range g.Encodings { 65 | goName, ok := miscNames[e.Name] 66 | if !ok { 67 | for k, v := range prefixes { 68 | if strings.HasPrefix(e.Name, k) { 69 | goName = v + e.Name[len(k):] 70 | break 71 | } 72 | } 73 | if goName == "" { 74 | log.Fatalf("unrecognized encoding name: %s", e.Name) 75 | } 76 | } 77 | 78 | for _, label := range e.Labels { 79 | fmt.Printf("%q: {%s, %q},\n", label, goName, e.Name) 80 | } 81 | } 82 | } 83 | fmt.Println("}") 84 | } 85 | 86 | var prefixes = map[string]string{ 87 | "iso-8859-": "charmap.ISO8859_", 88 | "windows-": "charmap.Windows", 89 | } 90 | 91 | var miscNames = map[string]string{ 92 | "utf-8": "encoding.Nop", 93 | "ibm866": "charmap.CodePage866", 94 | "iso-8859-8-i": "charmap.ISO8859_8", 95 | "koi8-r": "charmap.KOI8R", 96 | "koi8-u": "charmap.KOI8U", 97 | "macintosh": "charmap.Macintosh", 98 | "x-mac-cyrillic": "charmap.MacintoshCyrillic", 99 | "gbk": "simplifiedchinese.GBK", 100 | "gb18030": "simplifiedchinese.GB18030", 101 | "hz-gb-2312": "simplifiedchinese.HZGB2312", 102 | "big5": "traditionalchinese.Big5", 103 | "euc-jp": "japanese.EUCJP", 104 | "iso-2022-jp": "japanese.ISO2022JP", 105 | "shift_jis": "japanese.ShiftJIS", 106 | "euc-kr": "korean.EUCKR", 107 | "replacement": "encoding.Replacement", 108 | "utf-16be": "unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM)", 109 | "utf-16le": "unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)", 110 | "x-user-defined": "charmap.XUserDefined", 111 | } 112 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/net/html/const.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go 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 html 6 | 7 | // Section 12.2.3.2 of the HTML5 specification says "The following elements 8 | // have varying levels of special parsing rules". 9 | // https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements 10 | var isSpecialElementMap = map[string]bool{ 11 | "address": true, 12 | "applet": true, 13 | "area": true, 14 | "article": true, 15 | "aside": true, 16 | "base": true, 17 | "basefont": true, 18 | "bgsound": true, 19 | "blockquote": true, 20 | "body": true, 21 | "br": true, 22 | "button": true, 23 | "caption": true, 24 | "center": true, 25 | "col": true, 26 | "colgroup": true, 27 | "dd": true, 28 | "details": true, 29 | "dir": true, 30 | "div": true, 31 | "dl": true, 32 | "dt": true, 33 | "embed": true, 34 | "fieldset": true, 35 | "figcaption": true, 36 | "figure": true, 37 | "footer": true, 38 | "form": true, 39 | "frame": true, 40 | "frameset": true, 41 | "h1": true, 42 | "h2": true, 43 | "h3": true, 44 | "h4": true, 45 | "h5": true, 46 | "h6": true, 47 | "head": true, 48 | "header": true, 49 | "hgroup": true, 50 | "hr": true, 51 | "html": true, 52 | "iframe": true, 53 | "img": true, 54 | "input": true, 55 | "isindex": true, 56 | "li": true, 57 | "link": true, 58 | "listing": true, 59 | "marquee": true, 60 | "menu": true, 61 | "meta": true, 62 | "nav": true, 63 | "noembed": true, 64 | "noframes": true, 65 | "noscript": true, 66 | "object": true, 67 | "ol": true, 68 | "p": true, 69 | "param": true, 70 | "plaintext": true, 71 | "pre": true, 72 | "script": true, 73 | "section": true, 74 | "select": true, 75 | "source": true, 76 | "style": true, 77 | "summary": true, 78 | "table": true, 79 | "tbody": true, 80 | "td": true, 81 | "template": true, 82 | "textarea": true, 83 | "tfoot": true, 84 | "th": true, 85 | "thead": true, 86 | "title": true, 87 | "tr": true, 88 | "track": true, 89 | "ul": true, 90 | "wbr": true, 91 | "xmp": true, 92 | } 93 | 94 | func isSpecialElement(element *Node) bool { 95 | switch element.Namespace { 96 | case "", "html": 97 | return isSpecialElementMap[element.Data] 98 | case "svg": 99 | return element.Data == "foreignObject" 100 | } 101 | return false 102 | } 103 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/net/html/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go 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 | /* 6 | Package html implements an HTML5-compliant tokenizer and parser. 7 | 8 | Tokenization is done by creating a Tokenizer for an io.Reader r. It is the 9 | caller's responsibility to ensure that r provides UTF-8 encoded HTML. 10 | 11 | z := html.NewTokenizer(r) 12 | 13 | Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(), 14 | which parses the next token and returns its type, or an error: 15 | 16 | for { 17 | tt := z.Next() 18 | if tt == html.ErrorToken { 19 | // ... 20 | return ... 21 | } 22 | // Process the current token. 23 | } 24 | 25 | There are two APIs for retrieving the current token. The high-level API is to 26 | call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs 27 | allow optionally calling Raw after Next but before Token, Text, TagName, or 28 | TagAttr. In EBNF notation, the valid call sequence per token is: 29 | 30 | Next {Raw} [ Token | Text | TagName {TagAttr} ] 31 | 32 | Token returns an independent data structure that completely describes a token. 33 | Entities (such as "<") are unescaped, tag names and attribute keys are 34 | lower-cased, and attributes are collected into a []Attribute. For example: 35 | 36 | for { 37 | if z.Next() == html.ErrorToken { 38 | // Returning io.EOF indicates success. 39 | return z.Err() 40 | } 41 | emitToken(z.Token()) 42 | } 43 | 44 | The low-level API performs fewer allocations and copies, but the contents of 45 | the []byte values returned by Text, TagName and TagAttr may change on the next 46 | call to Next. For example, to extract an HTML page's anchor text: 47 | 48 | depth := 0 49 | for { 50 | tt := z.Next() 51 | switch tt { 52 | case ErrorToken: 53 | return z.Err() 54 | case TextToken: 55 | if depth > 0 { 56 | // emitBytes should copy the []byte it receives, 57 | // if it doesn't process it immediately. 58 | emitBytes(z.Text()) 59 | } 60 | case StartTagToken, EndTagToken: 61 | tn, _ := z.TagName() 62 | if len(tn) == 1 && tn[0] == 'a' { 63 | if tt == StartTagToken { 64 | depth++ 65 | } else { 66 | depth-- 67 | } 68 | } 69 | } 70 | } 71 | 72 | Parsing is done by calling Parse with an io.Reader, which returns the root of 73 | the parse tree (the document element) as a *Node. It is the caller's 74 | responsibility to ensure that the Reader provides UTF-8 encoded HTML. For 75 | example, to process each anchor node in depth-first order: 76 | 77 | doc, err := html.Parse(r) 78 | if err != nil { 79 | // ... 80 | } 81 | var f func(*html.Node) 82 | f = func(n *html.Node) { 83 | if n.Type == html.ElementNode && n.Data == "a" { 84 | // Do something with n... 85 | } 86 | for c := n.FirstChild; c != nil; c = c.NextSibling { 87 | f(c) 88 | } 89 | } 90 | f(doc) 91 | 92 | The relevant specifications include: 93 | https://html.spec.whatwg.org/multipage/syntax.html and 94 | https://html.spec.whatwg.org/multipage/syntax.html#tokenization 95 | */ 96 | package html // import "github.com/mjibson/goread/_third_party/golang.org/x/net/html" 97 | 98 | // The tokenization algorithm implemented by this package is not a line-by-line 99 | // transliteration of the relatively verbose state-machine in the WHATWG 100 | // specification. A more direct approach is used instead, where the program 101 | // counter implies the state, such as whether it is tokenizing a tag or a text 102 | // node. Specification compliance is verified by checking expected and actual 103 | // outputs over a test suite rather than aiming for algorithmic fidelity. 104 | 105 | // TODO(nigeltao): Does a DOM API belong in this package or a separate one? 106 | // TODO(nigeltao): How does parsing interact with a JavaScript engine? 107 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/net/html/entity_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go 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 html 6 | 7 | import ( 8 | "testing" 9 | "unicode/utf8" 10 | ) 11 | 12 | func TestEntityLength(t *testing.T) { 13 | // We verify that the length of UTF-8 encoding of each value is <= 1 + len(key). 14 | // The +1 comes from the leading "&". This property implies that the length of 15 | // unescaped text is <= the length of escaped text. 16 | for k, v := range entity { 17 | if 1+len(k) < utf8.RuneLen(v) { 18 | t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v)) 19 | } 20 | if len(k) > longestEntityWithoutSemicolon && k[len(k)-1] != ';' { 21 | t.Errorf("entity name %s is %d characters, but longestEntityWithoutSemicolon=%d", k, len(k), longestEntityWithoutSemicolon) 22 | } 23 | } 24 | for k, v := range entity2 { 25 | if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) { 26 | t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v[0]) + string(v[1])) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/net/html/escape_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go 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 html 6 | 7 | import "testing" 8 | 9 | type unescapeTest struct { 10 | // A short description of the test case. 11 | desc string 12 | // The HTML text. 13 | html string 14 | // The unescaped text. 15 | unescaped string 16 | } 17 | 18 | var unescapeTests = []unescapeTest{ 19 | // Handle no entities. 20 | { 21 | "copy", 22 | "A\ttext\nstring", 23 | "A\ttext\nstring", 24 | }, 25 | // Handle simple named entities. 26 | { 27 | "simple", 28 | "& > <", 29 | "& > <", 30 | }, 31 | // Handle hitting the end of the string. 32 | { 33 | "stringEnd", 34 | "& &", 35 | "& &", 36 | }, 37 | // Handle entities with two codepoints. 38 | { 39 | "multiCodepoint", 40 | "text ⋛︀ blah", 41 | "text \u22db\ufe00 blah", 42 | }, 43 | // Handle decimal numeric entities. 44 | { 45 | "decimalEntity", 46 | "Delta = Δ ", 47 | "Delta = Δ ", 48 | }, 49 | // Handle hexadecimal numeric entities. 50 | { 51 | "hexadecimalEntity", 52 | "Lambda = λ = λ ", 53 | "Lambda = λ = λ ", 54 | }, 55 | // Handle numeric early termination. 56 | { 57 | "numericEnds", 58 | "&# &#x €43 © = ©f = ©", 59 | "&# &#x €43 © = ©f = ©", 60 | }, 61 | // Handle numeric ISO-8859-1 entity replacements. 62 | { 63 | "numericReplacements", 64 | "Footnote‡", 65 | "Footnote‡", 66 | }, 67 | } 68 | 69 | func TestUnescape(t *testing.T) { 70 | for _, tt := range unescapeTests { 71 | unescaped := UnescapeString(tt.html) 72 | if unescaped != tt.unescaped { 73 | t.Errorf("TestUnescape %s: want %q, got %q", tt.desc, tt.unescaped, unescaped) 74 | } 75 | } 76 | } 77 | 78 | func TestUnescapeEscape(t *testing.T) { 79 | ss := []string{ 80 | ``, 81 | `abc def`, 82 | `a & b`, 83 | `a&b`, 84 | `a & b`, 85 | `"`, 86 | `"`, 87 | `"<&>"`, 88 | `"<&>"`, 89 | `3&5==1 && 0<1, "0<1", a+acute=á`, 90 | `The special characters are: <, >, &, ' and "`, 91 | } 92 | for _, s := range ss { 93 | if got := UnescapeString(EscapeString(s)); got != s { 94 | t.Errorf("got %q want %q", got, s) 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/net/html/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go 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 | // This example demonstrates parsing HTML data and walking the resulting tree. 6 | package html_test 7 | 8 | import ( 9 | "fmt" 10 | "log" 11 | "strings" 12 | 13 | "github.com/mjibson/goread/_third_party/golang.org/x/net/html" 14 | ) 15 | 16 | func ExampleParse() { 17 | s := `

Links:

` 18 | doc, err := html.Parse(strings.NewReader(s)) 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | var f func(*html.Node) 23 | f = func(n *html.Node) { 24 | if n.Type == html.ElementNode && n.Data == "a" { 25 | for _, a := range n.Attr { 26 | if a.Key == "href" { 27 | fmt.Println(a.Val) 28 | break 29 | } 30 | } 31 | } 32 | for c := n.FirstChild; c != nil; c = c.NextSibling { 33 | f(c) 34 | } 35 | } 36 | f(doc) 37 | // Output: 38 | // foo 39 | // /bar/baz 40 | } 41 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/net/html/node_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go 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 html 6 | 7 | import ( 8 | "fmt" 9 | ) 10 | 11 | // checkTreeConsistency checks that a node and its descendants are all 12 | // consistent in their parent/child/sibling relationships. 13 | func checkTreeConsistency(n *Node) error { 14 | return checkTreeConsistency1(n, 0) 15 | } 16 | 17 | func checkTreeConsistency1(n *Node, depth int) error { 18 | if depth == 1e4 { 19 | return fmt.Errorf("html: tree looks like it contains a cycle") 20 | } 21 | if err := checkNodeConsistency(n); err != nil { 22 | return err 23 | } 24 | for c := n.FirstChild; c != nil; c = c.NextSibling { 25 | if err := checkTreeConsistency1(c, depth+1); err != nil { 26 | return err 27 | } 28 | } 29 | return nil 30 | } 31 | 32 | // checkNodeConsistency checks that a node's parent/child/sibling relationships 33 | // are consistent. 34 | func checkNodeConsistency(n *Node) error { 35 | if n == nil { 36 | return nil 37 | } 38 | 39 | nParent := 0 40 | for p := n.Parent; p != nil; p = p.Parent { 41 | nParent++ 42 | if nParent == 1e4 { 43 | return fmt.Errorf("html: parent list looks like an infinite loop") 44 | } 45 | } 46 | 47 | nForward := 0 48 | for c := n.FirstChild; c != nil; c = c.NextSibling { 49 | nForward++ 50 | if nForward == 1e6 { 51 | return fmt.Errorf("html: forward list of children looks like an infinite loop") 52 | } 53 | if c.Parent != n { 54 | return fmt.Errorf("html: inconsistent child/parent relationship") 55 | } 56 | } 57 | 58 | nBackward := 0 59 | for c := n.LastChild; c != nil; c = c.PrevSibling { 60 | nBackward++ 61 | if nBackward == 1e6 { 62 | return fmt.Errorf("html: backward list of children looks like an infinite loop") 63 | } 64 | if c.Parent != n { 65 | return fmt.Errorf("html: inconsistent child/parent relationship") 66 | } 67 | } 68 | 69 | if n.Parent != nil { 70 | if n.Parent == n { 71 | return fmt.Errorf("html: inconsistent parent relationship") 72 | } 73 | if n.Parent == n.FirstChild { 74 | return fmt.Errorf("html: inconsistent parent/first relationship") 75 | } 76 | if n.Parent == n.LastChild { 77 | return fmt.Errorf("html: inconsistent parent/last relationship") 78 | } 79 | if n.Parent == n.PrevSibling { 80 | return fmt.Errorf("html: inconsistent parent/prev relationship") 81 | } 82 | if n.Parent == n.NextSibling { 83 | return fmt.Errorf("html: inconsistent parent/next relationship") 84 | } 85 | 86 | parentHasNAsAChild := false 87 | for c := n.Parent.FirstChild; c != nil; c = c.NextSibling { 88 | if c == n { 89 | parentHasNAsAChild = true 90 | break 91 | } 92 | } 93 | if !parentHasNAsAChild { 94 | return fmt.Errorf("html: inconsistent parent/child relationship") 95 | } 96 | } 97 | 98 | if n.PrevSibling != nil && n.PrevSibling.NextSibling != n { 99 | return fmt.Errorf("html: inconsistent prev/next relationship") 100 | } 101 | if n.NextSibling != nil && n.NextSibling.PrevSibling != n { 102 | return fmt.Errorf("html: inconsistent next/prev relationship") 103 | } 104 | 105 | if (n.FirstChild == nil) != (n.LastChild == nil) { 106 | return fmt.Errorf("html: inconsistent first/last relationship") 107 | } 108 | if n.FirstChild != nil && n.FirstChild == n.LastChild { 109 | // We have a sole child. 110 | if n.FirstChild.PrevSibling != nil || n.FirstChild.NextSibling != nil { 111 | return fmt.Errorf("html: inconsistent sole child's sibling relationship") 112 | } 113 | } 114 | 115 | seen := map[*Node]bool{} 116 | 117 | var last *Node 118 | for c := n.FirstChild; c != nil; c = c.NextSibling { 119 | if seen[c] { 120 | return fmt.Errorf("html: inconsistent repeated child") 121 | } 122 | seen[c] = true 123 | last = c 124 | } 125 | if last != n.LastChild { 126 | return fmt.Errorf("html: inconsistent last relationship") 127 | } 128 | 129 | var first *Node 130 | for c := n.LastChild; c != nil; c = c.PrevSibling { 131 | if !seen[c] { 132 | return fmt.Errorf("html: inconsistent missing child") 133 | } 134 | delete(seen, c) 135 | first = c 136 | } 137 | if first != n.FirstChild { 138 | return fmt.Errorf("html: inconsistent first relationship") 139 | } 140 | 141 | if len(seen) != 0 { 142 | return fmt.Errorf("html: inconsistent forwards/backwards child list") 143 | } 144 | 145 | return nil 146 | } 147 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/net/html/render_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go 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 html 6 | 7 | import ( 8 | "bytes" 9 | "testing" 10 | ) 11 | 12 | func TestRenderer(t *testing.T) { 13 | nodes := [...]*Node{ 14 | 0: { 15 | Type: ElementNode, 16 | Data: "html", 17 | }, 18 | 1: { 19 | Type: ElementNode, 20 | Data: "head", 21 | }, 22 | 2: { 23 | Type: ElementNode, 24 | Data: "body", 25 | }, 26 | 3: { 27 | Type: TextNode, 28 | Data: "0<1", 29 | }, 30 | 4: { 31 | Type: ElementNode, 32 | Data: "p", 33 | Attr: []Attribute{ 34 | { 35 | Key: "id", 36 | Val: "A", 37 | }, 38 | { 39 | Key: "foo", 40 | Val: `abc"def`, 41 | }, 42 | }, 43 | }, 44 | 5: { 45 | Type: TextNode, 46 | Data: "2", 47 | }, 48 | 6: { 49 | Type: ElementNode, 50 | Data: "b", 51 | Attr: []Attribute{ 52 | { 53 | Key: "empty", 54 | Val: "", 55 | }, 56 | }, 57 | }, 58 | 7: { 59 | Type: TextNode, 60 | Data: "3", 61 | }, 62 | 8: { 63 | Type: ElementNode, 64 | Data: "i", 65 | Attr: []Attribute{ 66 | { 67 | Key: "backslash", 68 | Val: `\`, 69 | }, 70 | }, 71 | }, 72 | 9: { 73 | Type: TextNode, 74 | Data: "&4", 75 | }, 76 | 10: { 77 | Type: TextNode, 78 | Data: "5", 79 | }, 80 | 11: { 81 | Type: ElementNode, 82 | Data: "blockquote", 83 | }, 84 | 12: { 85 | Type: ElementNode, 86 | Data: "br", 87 | }, 88 | 13: { 89 | Type: TextNode, 90 | Data: "6", 91 | }, 92 | } 93 | 94 | // Build a tree out of those nodes, based on a textual representation. 95 | // Only the ".\t"s are significant. The trailing HTML-like text is 96 | // just commentary. The "0:" prefixes are for easy cross-reference with 97 | // the nodes array. 98 | treeAsText := [...]string{ 99 | 0: ``, 100 | 1: `. `, 101 | 2: `. `, 102 | 3: `. . "0<1"`, 103 | 4: `. .

`, 104 | 5: `. . . "2"`, 105 | 6: `. . . `, 106 | 7: `. . . . "3"`, 107 | 8: `. . . `, 108 | 9: `. . . . "&4"`, 109 | 10: `. . "5"`, 110 | 11: `. .

`, 111 | 12: `. .
`, 112 | 13: `. . "6"`, 113 | } 114 | if len(nodes) != len(treeAsText) { 115 | t.Fatal("len(nodes) != len(treeAsText)") 116 | } 117 | var stack [8]*Node 118 | for i, line := range treeAsText { 119 | level := 0 120 | for line[0] == '.' { 121 | // Strip a leading ".\t". 122 | line = line[2:] 123 | level++ 124 | } 125 | n := nodes[i] 126 | if level == 0 { 127 | if stack[0] != nil { 128 | t.Fatal("multiple root nodes") 129 | } 130 | stack[0] = n 131 | } else { 132 | stack[level-1].AppendChild(n) 133 | stack[level] = n 134 | for i := level + 1; i < len(stack); i++ { 135 | stack[i] = nil 136 | } 137 | } 138 | // At each stage of tree construction, we check all nodes for consistency. 139 | for j, m := range nodes { 140 | if err := checkNodeConsistency(m); err != nil { 141 | t.Fatalf("i=%d, j=%d: %v", i, j, err) 142 | } 143 | } 144 | } 145 | 146 | want := `0<1

` + 147 | `23&4

` + 148 | `5

6` 149 | b := new(bytes.Buffer) 150 | if err := Render(b, nodes[0]); err != nil { 151 | t.Fatal(err) 152 | } 153 | if got := b.String(); got != want { 154 | t.Errorf("got vs want:\n%s\n%s\n", got, want) 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/cldr/base.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go 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 cldr provides a parser for LDML and related XML formats. 6 | // This package is inteded to be used by the table generation tools 7 | // for the various internationalization-related packages. 8 | // As the XML types are generated from the CLDR DTD, and as the CLDR standard 9 | // is periodically amended, this package may change considerably over time. 10 | // This mostly means that data may appear and disappear between versions. 11 | // That is, old code should keep compiling for newer versions, but data 12 | // may have moved or changed. 13 | // CLDR version 22 is the first version supported by this package. 14 | // Older versions may not work. 15 | package cldr 16 | 17 | import ( 18 | "encoding/xml" 19 | "regexp" 20 | "strconv" 21 | ) 22 | 23 | // Elem is implemented by every XML element. 24 | type Elem interface { 25 | setEnclosing(Elem) 26 | setName(string) 27 | enclosing() Elem 28 | 29 | GetCommon() *Common 30 | } 31 | 32 | type hidden struct { 33 | CharData string `xml:",chardata"` 34 | Alias *struct { 35 | Common 36 | Source string `xml:"source,attr"` 37 | Path string `xml:"path,attr"` 38 | } `xml:"alias"` 39 | Def *struct { 40 | Common 41 | Choice string `xml:"choice,attr,omitempty"` 42 | Type string `xml:"type,attr,omitempty"` 43 | } `xml:"default"` 44 | } 45 | 46 | // Common holds several of the most common attributes and sub elements 47 | // of an XML element. 48 | type Common struct { 49 | XMLName xml.Name 50 | name string 51 | enclElem Elem 52 | Type string `xml:"type,attr,omitempty"` 53 | Reference string `xml:"reference,attr,omitempty"` 54 | Alt string `xml:"alt,attr,omitempty"` 55 | ValidSubLocales string `xml:"validSubLocales,attr,omitempty"` 56 | Draft string `xml:"draft,attr,omitempty"` 57 | hidden 58 | } 59 | 60 | // Default returns the default type to select from the enclosed list 61 | // or "" if no default value is specified. 62 | func (e *Common) Default() string { 63 | if e.Def == nil { 64 | return "" 65 | } 66 | if e.Def.Choice != "" { 67 | return e.Def.Choice 68 | } else if e.Def.Type != "" { 69 | // Type is still used by the default element in collation. 70 | return e.Def.Type 71 | } 72 | return "" 73 | } 74 | 75 | // GetCommon returns e. It is provided such that Common implements Elem. 76 | func (e *Common) GetCommon() *Common { 77 | return e 78 | } 79 | 80 | // Data returns the character data accumulated for this element. 81 | func (e *Common) Data() string { 82 | e.CharData = charRe.ReplaceAllStringFunc(e.CharData, replaceUnicode) 83 | return e.CharData 84 | } 85 | 86 | func (e *Common) setName(s string) { 87 | e.name = s 88 | } 89 | 90 | func (e *Common) enclosing() Elem { 91 | return e.enclElem 92 | } 93 | 94 | func (e *Common) setEnclosing(en Elem) { 95 | e.enclElem = en 96 | } 97 | 98 | // Escape characters that can be escaped without further escaping the string. 99 | var charRe = regexp.MustCompile(`&#x[0-9a-fA-F]*;|\\u[0-9a-fA-F]{4}|\\U[0-9a-fA-F]{8}|\\x[0-9a-fA-F]{2}|\\[0-7]{3}|\\[abtnvfr]`) 100 | 101 | // replaceUnicode converts hexadecimal Unicode codepoint notations to a one-rune string. 102 | // It assumes the input string is correctly formatted. 103 | func replaceUnicode(s string) string { 104 | if s[1] == '#' { 105 | r, _ := strconv.ParseInt(s[3:len(s)-1], 16, 32) 106 | return string(r) 107 | } 108 | r, _, _, _ := strconv.UnquoteChar(s, 0) 109 | return string(r) 110 | } 111 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/cldr/cldr.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go 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 | //go:generate go run makexml.go -output xml.go 6 | 7 | // Package cldr provides a parser for LDML and related XML formats. 8 | // This package is inteded to be used by the table generation tools 9 | // for the various internationalization-related packages. 10 | // As the XML types are generated from the CLDR DTD, and as the CLDR standard 11 | // is periodically amended, this package may change considerably over time. 12 | // This mostly means that data may appear and disappear between versions. 13 | // That is, old code should keep compiling for newer versions, but data 14 | // may have moved or changed. 15 | // CLDR version 22 is the first version supported by this package. 16 | // Older versions may not work. 17 | package cldr // import "github.com/mjibson/goread/_third_party/golang.org/x/text/cldr" 18 | 19 | import ( 20 | "fmt" 21 | "sort" 22 | ) 23 | 24 | // CLDR provides access to parsed data of the Unicode Common Locale Data Repository. 25 | type CLDR struct { 26 | parent map[string][]string 27 | locale map[string]*LDML 28 | resolved map[string]*LDML 29 | bcp47 *LDMLBCP47 30 | supp *SupplementalData 31 | } 32 | 33 | func makeCLDR() *CLDR { 34 | return &CLDR{ 35 | parent: make(map[string][]string), 36 | locale: make(map[string]*LDML), 37 | resolved: make(map[string]*LDML), 38 | bcp47: &LDMLBCP47{}, 39 | supp: &SupplementalData{}, 40 | } 41 | } 42 | 43 | // BCP47 returns the parsed BCP47 LDML data. If no such data was parsed, nil is returned. 44 | func (cldr *CLDR) BCP47() *LDMLBCP47 { 45 | return nil 46 | } 47 | 48 | // Draft indicates the draft level of an element. 49 | type Draft int 50 | 51 | const ( 52 | Approved Draft = iota 53 | Contributed 54 | Provisional 55 | Unconfirmed 56 | ) 57 | 58 | var drafts = []string{"unconfirmed", "provisional", "contributed", "approved", ""} 59 | 60 | // ParseDraft returns the Draft value corresponding to the given string. The 61 | // empty string corresponds to Approved. 62 | func ParseDraft(level string) (Draft, error) { 63 | if level == "" { 64 | return Approved, nil 65 | } 66 | for i, s := range drafts { 67 | if level == s { 68 | return Unconfirmed - Draft(i), nil 69 | } 70 | } 71 | return Approved, fmt.Errorf("cldr: unknown draft level %q", level) 72 | } 73 | 74 | func (d Draft) String() string { 75 | return drafts[len(drafts)-1-int(d)] 76 | } 77 | 78 | // SetDraftLevel sets which draft levels to include in the evaluated LDML. 79 | // Any draft element for which the draft level is higher than lev will be excluded. 80 | // If multiple draft levels are available for a single element, the one with the 81 | // lowest draft level will be selected, unless preferDraft is true, in which case 82 | // the highest draft will be chosen. 83 | // It is assumed that the underlying LDML is canonicalized. 84 | func (cldr *CLDR) SetDraftLevel(lev Draft, preferDraft bool) { 85 | // TODO: implement 86 | cldr.resolved = make(map[string]*LDML) 87 | } 88 | 89 | // RawLDML returns the LDML XML for id in unresolved form. 90 | // id must be one of the strings returned by Locales. 91 | func (cldr *CLDR) RawLDML(loc string) *LDML { 92 | return cldr.locale[loc] 93 | } 94 | 95 | // LDML returns the fully resolved LDML XML for loc, which must be one of 96 | // the strings returned by Locales. 97 | func (cldr *CLDR) LDML(loc string) (*LDML, error) { 98 | return cldr.resolve(loc) 99 | } 100 | 101 | // Supplemental returns the parsed supplemental data. If no such data was parsed, 102 | // nil is returned. 103 | func (cldr *CLDR) Supplemental() *SupplementalData { 104 | return cldr.supp 105 | } 106 | 107 | // Locales returns the locales for which there exist files. 108 | // Valid sublocales for which there is no file are not included. 109 | func (cldr *CLDR) Locales() []string { 110 | loc := []string{} 111 | for l, _ := range cldr.locale { 112 | loc = append(loc, l) 113 | } 114 | sort.Strings(loc) 115 | return loc 116 | } 117 | 118 | // Get fills in the fields of x based on the XPath path. 119 | func Get(e Elem, path string) (res Elem, err error) { 120 | return walkXPath(e, path) 121 | } 122 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/cldr/cldr_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go 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 cldr 6 | 7 | import "testing" 8 | 9 | func TestParseDraft(t *testing.T) { 10 | tests := []struct { 11 | in string 12 | draft Draft 13 | err bool 14 | }{ 15 | {"unconfirmed", Unconfirmed, false}, 16 | {"provisional", Provisional, false}, 17 | {"contributed", Contributed, false}, 18 | {"approved", Approved, false}, 19 | {"", Approved, false}, 20 | {"foo", Approved, true}, 21 | } 22 | for _, tt := range tests { 23 | if d, err := ParseDraft(tt.in); d != tt.draft || (err != nil) != tt.err { 24 | t.Errorf("%q: was %v, %v; want %v, %v", tt.in, d, err != nil, tt.draft, tt.err) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/cldr/decode.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go 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 cldr 6 | 7 | import ( 8 | "archive/zip" 9 | "bytes" 10 | "encoding/xml" 11 | "fmt" 12 | "io" 13 | "io/ioutil" 14 | "log" 15 | "os" 16 | "path/filepath" 17 | "regexp" 18 | "strings" 19 | ) 20 | 21 | // A Decoder loads an archive of CLDR data. 22 | type Decoder struct { 23 | dirFilter []string 24 | sectionFilter []string 25 | loader Loader 26 | cldr *CLDR 27 | curLocale string 28 | } 29 | 30 | // SetSectionFilter takes a list top-level LDML element names to which 31 | // evaluation of LDML should be limited. It automatically calls SetDirFilter. 32 | func (d *Decoder) SetSectionFilter(filter ...string) { 33 | d.sectionFilter = filter 34 | // TODO: automatically set dir filter 35 | } 36 | 37 | // SetDirFilter limits the loading of LDML XML files of the specied directories. 38 | // Note that sections may be split across directories differently for different CLDR versions. 39 | // For more robust code, use SetSectionFilter. 40 | func (d *Decoder) SetDirFilter(dir ...string) { 41 | d.dirFilter = dir 42 | } 43 | 44 | // A Loader provides access to the files of a CLDR archive. 45 | type Loader interface { 46 | Len() int 47 | Path(i int) string 48 | Reader(i int) (io.ReadCloser, error) 49 | } 50 | 51 | var fileRe = regexp.MustCompile(".*/(.*)/(.*)\\.xml") 52 | 53 | // Decode loads and decodes the files represented by l. 54 | func (d *Decoder) Decode(l Loader) (cldr *CLDR, err error) { 55 | d.cldr = makeCLDR() 56 | for i := 0; i < l.Len(); i++ { 57 | fname := l.Path(i) 58 | if m := fileRe.FindStringSubmatch(fname); m != nil { 59 | if len(d.dirFilter) > 0 && !in(d.dirFilter, m[1]) { 60 | continue 61 | } 62 | var r io.Reader 63 | if r, err = l.Reader(i); err == nil { 64 | err = d.decode(m[1], m[2], r) 65 | } 66 | if err != nil { 67 | return nil, err 68 | } 69 | } 70 | } 71 | d.cldr.finalize(d.sectionFilter) 72 | return d.cldr, nil 73 | } 74 | 75 | func (d *Decoder) decode(dir, id string, r io.Reader) error { 76 | var v interface{} 77 | var l *LDML 78 | cldr := d.cldr 79 | switch { 80 | case dir == "supplemental": 81 | v = cldr.supp 82 | case dir == "transforms": 83 | return nil 84 | case dir == "bcp47": 85 | v = cldr.bcp47 86 | default: 87 | ok := false 88 | if v, ok = cldr.locale[id]; !ok { 89 | l = &LDML{} 90 | v, cldr.locale[id] = l, l 91 | } 92 | } 93 | x := xml.NewDecoder(r) 94 | if err := x.Decode(v); err != nil { 95 | log.Printf("%s/%s: %v", dir, id, err) 96 | return err 97 | } 98 | if l != nil { 99 | if l.Identity == nil { 100 | return fmt.Errorf("%s/%s: missing identity element", dir, id) 101 | } 102 | // TODO: use Locale.Parse 103 | path := strings.Split(id, "_") 104 | if lang := l.Identity.Language.Type; lang != path[0] { 105 | return fmt.Errorf("%s/%s: language was %s; want %s", dir, id, lang, path[0]) 106 | } 107 | } 108 | return nil 109 | } 110 | 111 | type pathLoader []string 112 | 113 | func makePathLoader(path string) (pl pathLoader, err error) { 114 | err = filepath.Walk(path, func(path string, _ os.FileInfo, err error) error { 115 | pl = append(pl, path) 116 | return err 117 | }) 118 | return pl, err 119 | } 120 | 121 | func (pl pathLoader) Len() int { 122 | return len(pl) 123 | } 124 | 125 | func (pl pathLoader) Path(i int) string { 126 | return pl[i] 127 | } 128 | 129 | func (pl pathLoader) Reader(i int) (io.ReadCloser, error) { 130 | return os.Open(pl[i]) 131 | } 132 | 133 | // DecodePath loads CLDR data from the given path. 134 | func (d *Decoder) DecodePath(path string) (cldr *CLDR, err error) { 135 | loader, err := makePathLoader(path) 136 | if err != nil { 137 | return nil, err 138 | } 139 | return d.Decode(loader) 140 | } 141 | 142 | type zipLoader struct { 143 | r *zip.Reader 144 | } 145 | 146 | func (zl zipLoader) Len() int { 147 | return len(zl.r.File) 148 | } 149 | 150 | func (zl zipLoader) Path(i int) string { 151 | return zl.r.File[i].Name 152 | } 153 | 154 | func (zl zipLoader) Reader(i int) (io.ReadCloser, error) { 155 | return zl.r.File[i].Open() 156 | } 157 | 158 | // DecodeZip loads CLDR data from the zip archive for which r is the source. 159 | func (d *Decoder) DecodeZip(r io.Reader) (cldr *CLDR, err error) { 160 | buffer, err := ioutil.ReadAll(r) 161 | if err != nil { 162 | return nil, err 163 | } 164 | archive, err := zip.NewReader(bytes.NewReader(buffer), int64(len(buffer))) 165 | if err != nil { 166 | return nil, err 167 | } 168 | return d.Decode(zipLoader{archive}) 169 | } 170 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/cldr/examples_test.go: -------------------------------------------------------------------------------- 1 | package cldr_test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/mjibson/goread/_third_party/golang.org/x/text/cldr" 6 | ) 7 | 8 | func ExampleSlice() { 9 | var dr *cldr.CLDR // assume this is initalized 10 | 11 | x, _ := dr.LDML("en") 12 | cs := x.Collations.Collation 13 | // remove all but the default 14 | cldr.MakeSlice(&cs).Filter(func(e cldr.Elem) bool { 15 | return e.GetCommon().Type != x.Collations.Default() 16 | }) 17 | for i, c := range cs { 18 | fmt.Println(i, c.Type) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/cldr/slice.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go 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 cldr 6 | 7 | import ( 8 | "fmt" 9 | "reflect" 10 | "sort" 11 | ) 12 | 13 | // Slice provides utilities for modifying slices of elements. 14 | // It can be wrapped around any slice of which the element type implements 15 | // interface Elem. 16 | type Slice struct { 17 | ptr reflect.Value 18 | typ reflect.Type 19 | } 20 | 21 | // Value returns the reflect.Value of the underlying slice. 22 | func (s *Slice) Value() reflect.Value { 23 | return s.ptr.Elem() 24 | } 25 | 26 | // MakeSlice wraps a pointer to a slice of Elems. 27 | // It replaces the array pointed to by the slice so that subsequent modifications 28 | // do not alter the data in a CLDR type. 29 | // It panics if an incorrect type is passed. 30 | func MakeSlice(slicePtr interface{}) Slice { 31 | ptr := reflect.ValueOf(slicePtr) 32 | if ptr.Kind() != reflect.Ptr { 33 | panic(fmt.Sprintf("MakeSlice: argument must be pointer to slice, found %v", ptr.Type())) 34 | } 35 | sl := ptr.Elem() 36 | if sl.Kind() != reflect.Slice { 37 | panic(fmt.Sprintf("MakeSlice: argument must point to a slice, found %v", sl.Type())) 38 | } 39 | intf := reflect.TypeOf((*Elem)(nil)).Elem() 40 | if !sl.Type().Elem().Implements(intf) { 41 | panic(fmt.Sprintf("MakeSlice: element type of slice (%v) does not implement Elem", sl.Type().Elem())) 42 | } 43 | nsl := reflect.MakeSlice(sl.Type(), sl.Len(), sl.Len()) 44 | reflect.Copy(nsl, sl) 45 | sl.Set(nsl) 46 | return Slice{ 47 | ptr: ptr, 48 | typ: sl.Type().Elem().Elem(), 49 | } 50 | } 51 | 52 | func (s Slice) indexForAttr(a string) []int { 53 | for i := iter(reflect.Zero(s.typ)); !i.done(); i.next() { 54 | if n, _ := xmlName(i.field()); n == a { 55 | return i.index 56 | } 57 | } 58 | panic(fmt.Sprintf("MakeSlice: no attribute %q for type %v", a, s.typ)) 59 | } 60 | 61 | // Filter filters s to only include elements for which fn returns true. 62 | func (s Slice) Filter(fn func(e Elem) bool) { 63 | k := 0 64 | sl := s.Value() 65 | for i := 0; i < sl.Len(); i++ { 66 | vi := sl.Index(i) 67 | if fn(vi.Interface().(Elem)) { 68 | sl.Index(k).Set(vi) 69 | k++ 70 | } 71 | } 72 | sl.Set(sl.Slice(0, k)) 73 | } 74 | 75 | // Group finds elements in s for which fn returns the same value and groups 76 | // them in a new Slice. 77 | func (s Slice) Group(fn func(e Elem) string) []Slice { 78 | m := make(map[string][]reflect.Value) 79 | sl := s.Value() 80 | for i := 0; i < sl.Len(); i++ { 81 | vi := sl.Index(i) 82 | key := fn(vi.Interface().(Elem)) 83 | m[key] = append(m[key], vi) 84 | } 85 | keys := []string{} 86 | for k, _ := range m { 87 | keys = append(keys, k) 88 | } 89 | sort.Strings(keys) 90 | res := []Slice{} 91 | for _, k := range keys { 92 | nsl := reflect.New(sl.Type()) 93 | nsl.Elem().Set(reflect.Append(nsl.Elem(), m[k]...)) 94 | res = append(res, MakeSlice(nsl.Interface())) 95 | } 96 | return res 97 | } 98 | 99 | // SelectAnyOf filters s to contain only elements for which attr matches 100 | // any of the values. 101 | func (s Slice) SelectAnyOf(attr string, values ...string) { 102 | index := s.indexForAttr(attr) 103 | s.Filter(func(e Elem) bool { 104 | vf := reflect.ValueOf(e).Elem().FieldByIndex(index) 105 | return in(values, vf.String()) 106 | }) 107 | } 108 | 109 | // SelectOnePerGroup filters s to include at most one element e per group of 110 | // elements matching Key(attr), where e has an attribute a that matches any 111 | // the values in v. 112 | // If more than one element in a group matches a value in v preference 113 | // is given to the element that matches the first value in v. 114 | func (s Slice) SelectOnePerGroup(a string, v []string) { 115 | index := s.indexForAttr(a) 116 | grouped := s.Group(func(e Elem) string { return Key(e, a) }) 117 | sl := s.Value() 118 | sl.Set(sl.Slice(0, 0)) 119 | for _, g := range grouped { 120 | e := reflect.Value{} 121 | found := len(v) 122 | gsl := g.Value() 123 | for i := 0; i < gsl.Len(); i++ { 124 | vi := gsl.Index(i).Elem().FieldByIndex(index) 125 | j := 0 126 | for ; j < len(v) && v[j] != vi.String(); j++ { 127 | } 128 | if j < found { 129 | found = j 130 | e = gsl.Index(i) 131 | } 132 | } 133 | if found < len(v) { 134 | sl.Set(reflect.Append(sl, e)) 135 | } 136 | } 137 | } 138 | 139 | // SelectDraft drops all elements from the list with a draft level smaller than d 140 | // and selects the highest draft level of the remaining. 141 | // This method assumes that the input CLDR is canonicalized. 142 | func (s Slice) SelectDraft(d Draft) { 143 | s.SelectOnePerGroup("draft", drafts[len(drafts)-2-int(d):]) 144 | } 145 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/encoding/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go 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 encoding_test 6 | 7 | import ( 8 | "fmt" 9 | "io" 10 | "os" 11 | "strings" 12 | 13 | "github.com/mjibson/goread/_third_party/golang.org/x/text/encoding" 14 | "github.com/mjibson/goread/_third_party/golang.org/x/text/encoding/charmap" 15 | "github.com/mjibson/goread/_third_party/golang.org/x/text/transform" 16 | ) 17 | 18 | func ExampleDecodeWindows1252() { 19 | sr := strings.NewReader("Gar\xe7on !") 20 | tr := transform.NewReader(sr, charmap.Windows1252.NewDecoder()) 21 | io.Copy(os.Stdout, tr) 22 | // Output: Garçon ! 23 | } 24 | 25 | func ExampleUTF8Validator() { 26 | for i := 0; i < 2; i++ { 27 | transformer := charmap.Windows1252.NewEncoder() 28 | if i == 1 { 29 | transformer = transform.Chain(encoding.UTF8Validator, transformer) 30 | } 31 | dst := make([]byte, 256) 32 | src := []byte("abc\xffxyz") // src is invalid UTF-8. 33 | nDst, nSrc, err := transformer.Transform(dst, src, true) 34 | fmt.Printf("i=%d: produced %q, consumed %q, error %v\n", 35 | i, dst[:nDst], src[:nSrc], err) 36 | } 37 | // Output: 38 | // i=0: produced "abc\x1axyz", consumed "abc\xffxyz", error 39 | // i=1: produced "abc", consumed "abc", error encoding: invalid UTF-8 40 | } 41 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/encoding/internal/identifier/gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go 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 | // +build ignore 6 | 7 | package main 8 | 9 | import ( 10 | "bytes" 11 | "encoding/xml" 12 | "fmt" 13 | "io" 14 | "log" 15 | "strings" 16 | 17 | "github.com/mjibson/goread/_third_party/golang.org/x/text/internal/gen" 18 | ) 19 | 20 | type registry struct { 21 | XMLName xml.Name `xml:"registry"` 22 | Updated string `xml:"updated"` 23 | Registry []struct { 24 | ID string `xml:"id,attr"` 25 | Record []struct { 26 | Name string `xml:"name"` 27 | Xref []struct { 28 | Type string `xml:"type,attr"` 29 | Data string `xml:"data,attr"` 30 | } `xml:"xref"` 31 | Desc struct { 32 | Data string `xml:",innerxml"` 33 | // Any []struct { 34 | // Data string `xml:",chardata"` 35 | // } `xml:",any"` 36 | // Data string `xml:",chardata"` 37 | } `xml:"description,"` 38 | MIB string `xml:"value"` 39 | Alias []string `xml:"alias"` 40 | MIME string `xml:"preferred_alias"` 41 | } `xml:"record"` 42 | } `xml:"registry"` 43 | } 44 | 45 | func main() { 46 | r := gen.OpenIANAFile("assignments/character-sets/character-sets.xml") 47 | reg := ®istry{} 48 | if err := xml.NewDecoder(r).Decode(®); err != nil && err != io.EOF { 49 | log.Fatalf("Error decoding charset registry: %v", err) 50 | } 51 | if len(reg.Registry) == 0 || reg.Registry[0].ID != "character-sets-1" { 52 | log.Fatalf("Unexpected ID %s", reg.Registry[0].ID) 53 | } 54 | 55 | w := &bytes.Buffer{} 56 | fmt.Fprintf(w, "const (\n") 57 | for _, rec := range reg.Registry[0].Record { 58 | constName := "" 59 | for _, a := range rec.Alias { 60 | if strings.HasPrefix(a, "cs") && strings.IndexByte(a, '-') == -1 { 61 | // Some of the constant definitions have comments in them. Strip those. 62 | constName = strings.Title(strings.SplitN(a[2:], "\n", 2)[0]) 63 | } 64 | } 65 | if constName == "" { 66 | switch rec.MIB { 67 | case "2085": 68 | constName = "HZGB2312" // Not listed as alias for some reason. 69 | default: 70 | log.Fatalf("No cs alias defined for %s.", rec.MIB) 71 | } 72 | } 73 | if rec.MIME != "" { 74 | rec.MIME = fmt.Sprintf(" (MIME: %s)", rec.MIME) 75 | } 76 | fmt.Fprintf(w, "// %s is the MIB identifier with IANA name %s%s.\n//\n", constName, rec.Name, rec.MIME) 77 | if len(rec.Desc.Data) > 0 { 78 | fmt.Fprint(w, "// ") 79 | d := xml.NewDecoder(strings.NewReader(rec.Desc.Data)) 80 | inElem := true 81 | attr := "" 82 | for { 83 | t, err := d.Token() 84 | if err != nil { 85 | if err != io.EOF { 86 | log.Fatal(err) 87 | } 88 | break 89 | } 90 | switch x := t.(type) { 91 | case xml.CharData: 92 | attr = "" // Don't need attribute info. 93 | a := bytes.Split([]byte(x), []byte("\n")) 94 | for i, b := range a { 95 | if b = bytes.TrimSpace(b); len(b) != 0 { 96 | if !inElem && i > 0 { 97 | fmt.Fprint(w, "\n// ") 98 | } 99 | inElem = false 100 | fmt.Fprintf(w, "%s ", string(b)) 101 | } 102 | } 103 | case xml.StartElement: 104 | if x.Name.Local == "xref" { 105 | inElem = true 106 | use := false 107 | for _, a := range x.Attr { 108 | if a.Name.Local == "type" { 109 | use = use || a.Value != "person" 110 | } 111 | if a.Name.Local == "data" && use { 112 | attr = a.Value + " " 113 | } 114 | } 115 | } 116 | case xml.EndElement: 117 | inElem = false 118 | fmt.Fprint(w, attr) 119 | } 120 | } 121 | fmt.Fprint(w, "\n") 122 | } 123 | for _, x := range rec.Xref { 124 | switch x.Type { 125 | case "rfc": 126 | fmt.Fprintf(w, "// Reference: %s\n", strings.ToUpper(x.Data)) 127 | case "uri": 128 | fmt.Fprintf(w, "// Reference: %s\n", x.Data) 129 | } 130 | } 131 | fmt.Fprintf(w, "%s MIB = %s\n", constName, rec.MIB) 132 | fmt.Fprintln(w) 133 | } 134 | fmt.Fprintln(w, ")") 135 | 136 | gen.WriteGoFile("mib.go", "identifier", w.Bytes()) 137 | } 138 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/encoding/internal/identifier/identifier.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go 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 | //go:generate go run gen.go 6 | 7 | // Package identifier defines the contract between implementations of Encoding 8 | // and Index by defining identifiers that uniquely identify standardized coded 9 | // character sets (CCS) and character encoding schemes (CES), which we will 10 | // together refer to as encodings, for which Encoding implementations provide 11 | // converters to and from UTF-8. This package is typically only of concern to 12 | // implementers of Indexes and Encodings. 13 | // 14 | // One part of the identifier is the MIB code, which is defined by IANA and 15 | // uniquely identifies a CCS or CES. Each code is associated with data that 16 | // references authorities, official documentation as well as aliases and MIME 17 | // names. 18 | // 19 | // Not all CESs are covered by the IANA registry. The "other" string that is 20 | // returned by ID can be used to identify other character sets or versions of 21 | // existing ones. 22 | // 23 | // It is recommended that each package that provides a set of Encodings provide 24 | // the All and Common variables to reference all supported encodings and 25 | // commonly used subset. This allows Index implementations to include all 26 | // available encodings without explicitly referencing or knowing about them. 27 | package identifier 28 | 29 | // Note: this package is internal, but could be made public if there is a need 30 | // for writing third-party Indexes and Encodings. 31 | 32 | // References: 33 | // - http://source.icu-project.org/repos/icu/icu/trunk/source/data/mappings/convrtrs.txt 34 | // - http://www.iana.org/assignments/character-sets/character-sets.xhtml 35 | // - http://www.iana.org/assignments/ianacharset-mib/ianacharset-mib 36 | // - http://www.ietf.org/rfc/rfc2978.txt 37 | // - http://www.unicode.org/reports/tr22/ 38 | // - http://www.w3.org/TR/encoding/ 39 | // - http://www.w3.org/TR/encoding/indexes/encodings.json 40 | // - https://encoding.spec.whatwg.org/ 41 | // - https://tools.ietf.org/html/rfc6657#section-5 42 | 43 | // Interface can be implemented by Encodings to define the CCS or CES for which 44 | // it implements conversions. 45 | type Interface interface { 46 | // ID returns an encoding identifier. Exactly one of the mib and other 47 | // values should be non-zero. 48 | // 49 | // In the usual case it is only necessary to indicate the MIB code. The 50 | // other string can be used to specify encodings for which there is no MIB, 51 | // such as "x-mac-dingbat". 52 | // 53 | // The other string may only contain the characters a-z, A-Z, 0-9, - and _. 54 | ID() (mib MIB, other string) 55 | 56 | // NOTE: the restrictions on the encoding are to allow extending the syntax 57 | // with additional information such as versions, vendors and other variants. 58 | } 59 | 60 | // A MIB identifies an encoding. It is derived from the IANA MIB codes and adds 61 | // some identifiers for some encodings that are not covered by the IANA 62 | // standard. 63 | // 64 | // See http://www.iana.org/assignments/ianacharset-mib. 65 | type MIB uint16 66 | 67 | // These additional MIB types are not defined in IANA. They are added because 68 | // they are common and defined within the text repo. 69 | const ( 70 | // Unofficial marks the start of encodings not registered by IANA. 71 | Unofficial MIB = 10000 + iota 72 | 73 | // TODO: add Replacement? 74 | 75 | // XUserDefined is the code for x-user-defined. 76 | XUserDefined 77 | 78 | // MacintoshCyrillic is the code for x-mac-cyrillic. 79 | MacintoshCyrillic 80 | ) 81 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/encoding/internal/internal.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go 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 internal contains code that is shared among encoding implementations. 6 | package internal 7 | 8 | import ( 9 | "github.com/mjibson/goread/_third_party/golang.org/x/text/encoding" 10 | "github.com/mjibson/goread/_third_party/golang.org/x/text/encoding/internal/identifier" 11 | "github.com/mjibson/goread/_third_party/golang.org/x/text/transform" 12 | ) 13 | 14 | // Encoding is an implementation of the Encoding interface that adds the String 15 | // and ID methods to an existing encoding. 16 | type Encoding struct { 17 | encoding.Encoding 18 | Name string 19 | MIB identifier.MIB 20 | } 21 | 22 | // _ verifies that Encoding implements identifier.Interface. 23 | var _ identifier.Interface = (*Encoding)(nil) 24 | 25 | func (e *Encoding) String() string { 26 | return e.Name 27 | } 28 | 29 | func (e *Encoding) ID() (mib identifier.MIB, other string) { 30 | return e.MIB, "" 31 | } 32 | 33 | // SimpleEncoding is an Encoding that combines two Transformers. 34 | type SimpleEncoding struct { 35 | Decoder transform.Transformer 36 | Encoder transform.Transformer 37 | } 38 | 39 | func (e *SimpleEncoding) NewDecoder() transform.Transformer { 40 | return e.Decoder 41 | } 42 | 43 | func (e *SimpleEncoding) NewEncoder() transform.Transformer { 44 | return e.Encoder 45 | } 46 | 47 | // FuncEncoding is an Encoding that combines two functions returning a new 48 | // Transformer. 49 | type FuncEncoding struct { 50 | Decoder func() transform.Transformer 51 | Encoder func() transform.Transformer 52 | } 53 | 54 | func (e FuncEncoding) NewDecoder() transform.Transformer { 55 | return e.Decoder() 56 | } 57 | 58 | func (e FuncEncoding) NewEncoder() transform.Transformer { 59 | return e.Encoder() 60 | } 61 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/encoding/japanese/all.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go 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 japanese 6 | 7 | import ( 8 | "github.com/mjibson/goread/_third_party/golang.org/x/text/encoding" 9 | ) 10 | 11 | // All is a list of all defined encodings in this package. 12 | var All = []encoding.Encoding{EUCJP, ISO2022JP, ShiftJIS} 13 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/encoding/korean/maketables.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go 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 | // +build ignore 6 | 7 | package main 8 | 9 | // This program generates tables.go: 10 | // go run maketables.go | gofmt > tables.go 11 | 12 | import ( 13 | "bufio" 14 | "fmt" 15 | "log" 16 | "net/http" 17 | "sort" 18 | "strings" 19 | ) 20 | 21 | func main() { 22 | fmt.Printf("// generated by go run maketables.go; DO NOT EDIT\n\n") 23 | fmt.Printf("// Package korean provides Korean encodings such as EUC-KR.\n") 24 | fmt.Printf(`package korean // import "golang.org/x/text/encoding/korean"` + "\n\n") 25 | 26 | res, err := http.Get("http://encoding.spec.whatwg.org/index-euc-kr.txt") 27 | if err != nil { 28 | log.Fatalf("Get: %v", err) 29 | } 30 | defer res.Body.Close() 31 | 32 | mapping := [65536]uint16{} 33 | reverse := [65536]uint16{} 34 | 35 | scanner := bufio.NewScanner(res.Body) 36 | for scanner.Scan() { 37 | s := strings.TrimSpace(scanner.Text()) 38 | if s == "" || s[0] == '#' { 39 | continue 40 | } 41 | x, y := uint16(0), uint16(0) 42 | if _, err := fmt.Sscanf(s, "%d 0x%x", &x, &y); err != nil { 43 | log.Fatalf("could not parse %q", s) 44 | } 45 | if x < 0 || 178*(0xc7-0x81)+(0xfe-0xc7)*94+(0xff-0xa1) <= x { 46 | log.Fatalf("EUC-KR code %d is out of range", x) 47 | } 48 | mapping[x] = y 49 | if reverse[y] == 0 { 50 | c0, c1 := uint16(0), uint16(0) 51 | if x < 178*(0xc7-0x81) { 52 | c0 = uint16(x/178) + 0x81 53 | c1 = uint16(x % 178) 54 | switch { 55 | case c1 < 1*26: 56 | c1 += 0x41 57 | case c1 < 2*26: 58 | c1 += 0x47 59 | default: 60 | c1 += 0x4d 61 | } 62 | } else { 63 | x -= 178 * (0xc7 - 0x81) 64 | c0 = uint16(x/94) + 0xc7 65 | c1 = uint16(x%94) + 0xa1 66 | } 67 | reverse[y] = c0<<8 | c1 68 | } 69 | } 70 | if err := scanner.Err(); err != nil { 71 | log.Fatalf("scanner error: %v", err) 72 | } 73 | 74 | fmt.Printf("// decode is the decoding table from EUC-KR code to Unicode.\n") 75 | fmt.Printf("// It is defined at http://encoding.spec.whatwg.org/index-euc-kr.txt\n") 76 | fmt.Printf("var decode = [...]uint16{\n") 77 | for i, v := range mapping { 78 | if v != 0 { 79 | fmt.Printf("\t%d: 0x%04X,\n", i, v) 80 | } 81 | } 82 | fmt.Printf("}\n\n") 83 | 84 | // Any run of at least separation continuous zero entries in the reverse map will 85 | // be a separate encode table. 86 | const separation = 1024 87 | 88 | intervals := []interval(nil) 89 | low, high := -1, -1 90 | for i, v := range reverse { 91 | if v == 0 { 92 | continue 93 | } 94 | if low < 0 { 95 | low = i 96 | } else if i-high >= separation { 97 | if high >= 0 { 98 | intervals = append(intervals, interval{low, high}) 99 | } 100 | low = i 101 | } 102 | high = i + 1 103 | } 104 | if high >= 0 { 105 | intervals = append(intervals, interval{low, high}) 106 | } 107 | sort.Sort(byDecreasingLength(intervals)) 108 | 109 | fmt.Printf("const numEncodeTables = %d\n\n", len(intervals)) 110 | fmt.Printf("// encodeX are the encoding tables from Unicode to EUC-KR code,\n") 111 | fmt.Printf("// sorted by decreasing length.\n") 112 | for i, v := range intervals { 113 | fmt.Printf("// encode%d: %5d entries for runes in [%5d, %5d).\n", i, v.len(), v.low, v.high) 114 | } 115 | fmt.Printf("\n") 116 | 117 | for i, v := range intervals { 118 | fmt.Printf("const encode%dLow, encode%dHigh = %d, %d\n\n", i, i, v.low, v.high) 119 | fmt.Printf("var encode%d = [...]uint16{\n", i) 120 | for j := v.low; j < v.high; j++ { 121 | x := reverse[j] 122 | if x == 0 { 123 | continue 124 | } 125 | fmt.Printf("\t%d-%d: 0x%04X,\n", j, v.low, x) 126 | } 127 | fmt.Printf("}\n\n") 128 | } 129 | } 130 | 131 | // interval is a half-open interval [low, high). 132 | type interval struct { 133 | low, high int 134 | } 135 | 136 | func (i interval) len() int { return i.high - i.low } 137 | 138 | // byDecreasingLength sorts intervals by decreasing length. 139 | type byDecreasingLength []interval 140 | 141 | func (b byDecreasingLength) Len() int { return len(b) } 142 | func (b byDecreasingLength) Less(i, j int) bool { return b[i].len() > b[j].len() } 143 | func (b byDecreasingLength) Swap(i, j int) { b[i], b[j] = b[j], b[i] } 144 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/encoding/simplifiedchinese/all.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go 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 simplifiedchinese 6 | 7 | import ( 8 | "github.com/mjibson/goread/_third_party/golang.org/x/text/encoding" 9 | ) 10 | 11 | // All is a list of all defined encodings in this package. 12 | var All = []encoding.Encoding{GB18030, GBK, HZGB2312} 13 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/encoding/traditionalchinese/maketables.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go 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 | // +build ignore 6 | 7 | package main 8 | 9 | // This program generates tables.go: 10 | // go run maketables.go | gofmt > tables.go 11 | 12 | import ( 13 | "bufio" 14 | "fmt" 15 | "log" 16 | "net/http" 17 | "sort" 18 | "strings" 19 | ) 20 | 21 | func main() { 22 | fmt.Printf("// generated by go run maketables.go; DO NOT EDIT\n\n") 23 | fmt.Printf("// Package traditionalchinese provides Traditional Chinese encodings such as Big5.\n") 24 | fmt.Printf(`package traditionalchinese // import "golang.org/x/text/encoding/traditionalchinese"` + "\n\n") 25 | 26 | res, err := http.Get("http://encoding.spec.whatwg.org/index-big5.txt") 27 | if err != nil { 28 | log.Fatalf("Get: %v", err) 29 | } 30 | defer res.Body.Close() 31 | 32 | mapping := [65536]uint32{} 33 | reverse := [65536 * 4]uint16{} 34 | 35 | scanner := bufio.NewScanner(res.Body) 36 | for scanner.Scan() { 37 | s := strings.TrimSpace(scanner.Text()) 38 | if s == "" || s[0] == '#' { 39 | continue 40 | } 41 | x, y := uint16(0), uint32(0) 42 | if _, err := fmt.Sscanf(s, "%d 0x%x", &x, &y); err != nil { 43 | log.Fatalf("could not parse %q", s) 44 | } 45 | if x < 0 || 126*157 <= x { 46 | log.Fatalf("Big5 code %d is out of range", x) 47 | } 48 | mapping[x] = y 49 | 50 | // The WHATWG spec http://encoding.spec.whatwg.org/#indexes says that 51 | // "The index pointer for code point in index is the first pointer 52 | // corresponding to code point in index", which would normally mean 53 | // that the code below should be guarded by "if reverse[y] == 0", but 54 | // last instead of first seems to match the behavior of 55 | // "iconv -f UTF-8 -t BIG5". For example, U+8005 者 occurs twice in 56 | // http://encoding.spec.whatwg.org/index-big5.txt, as index 2148 57 | // (encoded as "\x8e\xcd") and index 6543 (encoded as "\xaa\xcc") 58 | // and "echo 者 | iconv -f UTF-8 -t BIG5 | xxd" gives "\xaa\xcc". 59 | c0, c1 := x/157, x%157 60 | if c1 < 0x3f { 61 | c1 += 0x40 62 | } else { 63 | c1 += 0x62 64 | } 65 | reverse[y] = (0x81+c0)<<8 | c1 66 | } 67 | if err := scanner.Err(); err != nil { 68 | log.Fatalf("scanner error: %v", err) 69 | } 70 | 71 | fmt.Printf("// decode is the decoding table from Big5 code to Unicode.\n") 72 | fmt.Printf("// It is defined at http://encoding.spec.whatwg.org/index-big5.txt\n") 73 | fmt.Printf("var decode = [...]uint32{\n") 74 | for i, v := range mapping { 75 | if v != 0 { 76 | fmt.Printf("\t%d: 0x%08X,\n", i, v) 77 | } 78 | } 79 | fmt.Printf("}\n\n") 80 | 81 | // Any run of at least separation continuous zero entries in the reverse map will 82 | // be a separate encode table. 83 | const separation = 1024 84 | 85 | intervals := []interval(nil) 86 | low, high := -1, -1 87 | for i, v := range reverse { 88 | if v == 0 { 89 | continue 90 | } 91 | if low < 0 { 92 | low = i 93 | } else if i-high >= separation { 94 | if high >= 0 { 95 | intervals = append(intervals, interval{low, high}) 96 | } 97 | low = i 98 | } 99 | high = i + 1 100 | } 101 | if high >= 0 { 102 | intervals = append(intervals, interval{low, high}) 103 | } 104 | sort.Sort(byDecreasingLength(intervals)) 105 | 106 | fmt.Printf("const numEncodeTables = %d\n\n", len(intervals)) 107 | fmt.Printf("// encodeX are the encoding tables from Unicode to Big5 code,\n") 108 | fmt.Printf("// sorted by decreasing length.\n") 109 | for i, v := range intervals { 110 | fmt.Printf("// encode%d: %5d entries for runes in [%6d, %6d).\n", i, v.len(), v.low, v.high) 111 | } 112 | fmt.Printf("\n") 113 | 114 | for i, v := range intervals { 115 | fmt.Printf("const encode%dLow, encode%dHigh = %d, %d\n\n", i, i, v.low, v.high) 116 | fmt.Printf("var encode%d = [...]uint16{\n", i) 117 | for j := v.low; j < v.high; j++ { 118 | x := reverse[j] 119 | if x == 0 { 120 | continue 121 | } 122 | fmt.Printf("\t%d-%d: 0x%04X,\n", j, v.low, x) 123 | } 124 | fmt.Printf("}\n\n") 125 | } 126 | } 127 | 128 | // interval is a half-open interval [low, high). 129 | type interval struct { 130 | low, high int 131 | } 132 | 133 | func (i interval) len() int { return i.high - i.low } 134 | 135 | // byDecreasingLength sorts intervals by decreasing length. 136 | type byDecreasingLength []interval 137 | 138 | func (b byDecreasingLength) Len() int { return len(b) } 139 | func (b byDecreasingLength) Less(i, j int) bool { return b[i].len() > b[j].len() } 140 | func (b byDecreasingLength) Swap(i, j int) { b[i], b[j] = b[j], b[i] } 141 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/encoding/unicode/override.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go 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 unicode 6 | 7 | import ( 8 | "github.com/mjibson/goread/_third_party/golang.org/x/text/transform" 9 | ) 10 | 11 | // BOMOverride returns a new decoder transformer that is identical to fallback, 12 | // except that the presence of a Byte Order Mark at the start of the input 13 | // causes it to switch to the corresponding Unicode decoding. It will only 14 | // consider BOMs for UTF-8, UTF-16BE, and UTF-16LE. 15 | // 16 | // This differs from using ExpectBOM by allowing a BOM to switch to UTF-8, not 17 | // just UTF-16 variants, and allowing falling back to any encoding scheme. 18 | // 19 | // This technique is recommended by the W3C for use in HTML 5: "For 20 | // compatibility with deployed content, the byte order mark (also known as BOM) 21 | // is considered more authoritative than anything else." 22 | // http://www.w3.org/TR/encoding/#specification-hooks 23 | // 24 | // Using BOMOverride is mostly intended for use cases where the first characters 25 | // of a fallback encoding are known to not be a BOM, for example, for valid HTML 26 | // and most encodings. 27 | func BOMOverride(fallback transform.Transformer) transform.Transformer { 28 | // TODO: possibly allow a variadic argument of unicode encodings to allow 29 | // specifying details of which fallbacks are supported as well as 30 | // specifying the details of the implementations. This would also allow for 31 | // support for UTF-32, which should not be supported by default. 32 | return &bomOverride{fallback: fallback} 33 | } 34 | 35 | type bomOverride struct { 36 | fallback transform.Transformer 37 | current transform.Transformer 38 | } 39 | 40 | func (d *bomOverride) Reset() { 41 | d.current = nil 42 | d.fallback.Reset() 43 | } 44 | 45 | var ( 46 | // TODO: we could use decode functions here, instead of allocating a new 47 | // decoder on every NewDecoder as IgnoreBOM decoders can be stateless. 48 | utf16le = UTF16(LittleEndian, IgnoreBOM) 49 | utf16be = UTF16(BigEndian, IgnoreBOM) 50 | ) 51 | 52 | const utf8BOM = "\ufeff" 53 | 54 | func (d *bomOverride) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { 55 | if d.current != nil { 56 | return d.current.Transform(dst, src, atEOF) 57 | } 58 | if len(src) < 3 && !atEOF { 59 | return 0, 0, transform.ErrShortSrc 60 | } 61 | d.current = d.fallback 62 | bomSize := 0 63 | if len(src) >= 2 { 64 | if src[0] == 0xFF && src[1] == 0xFE { 65 | d.current = utf16le.NewDecoder() 66 | bomSize = 2 67 | } else if src[0] == 0xFE && src[1] == 0xFF { 68 | d.current = utf16be.NewDecoder() 69 | bomSize = 2 70 | } else if len(src) >= 3 && 71 | src[0] == utf8BOM[0] && 72 | src[1] == utf8BOM[1] && 73 | src[2] == utf8BOM[2] { 74 | d.current = transform.Nop 75 | bomSize = 3 76 | } 77 | } 78 | if bomSize < len(src) { 79 | nDst, nSrc, err = d.current.Transform(dst, src[bomSize:], atEOF) 80 | } 81 | return nDst, nSrc + bomSize, err 82 | } 83 | -------------------------------------------------------------------------------- /_third_party/golang.org/x/text/transform/examples_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go 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 transform_test 6 | 7 | import ( 8 | "fmt" 9 | "unicode" 10 | 11 | "github.com/mjibson/goread/_third_party/golang.org/x/text/transform" 12 | "github.com/mjibson/goread/_third_party/golang.org/x/text/unicode/norm" 13 | ) 14 | 15 | func ExampleRemoveFunc() { 16 | input := []byte(`tschüß; до свидания`) 17 | 18 | b := make([]byte, len(input)) 19 | 20 | t := transform.RemoveFunc(unicode.IsSpace) 21 | n, _, _ := t.Transform(b, input, true) 22 | fmt.Println(string(b[:n])) 23 | 24 | t = transform.RemoveFunc(func(r rune) bool { 25 | return !unicode.Is(unicode.Latin, r) 26 | }) 27 | n, _, _ = t.Transform(b, input, true) 28 | fmt.Println(string(b[:n])) 29 | 30 | n, _, _ = t.Transform(b, norm.NFD.Bytes(input), true) 31 | fmt.Println(string(b[:n])) 32 | 33 | // Output: 34 | // tschüß;досвидания 35 | // tschüß 36 | // tschuß 37 | } 38 | -------------------------------------------------------------------------------- /app/app.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/mjibson/goread/_third_party/github.com/gorilla/mux" 7 | 8 | app "github.com/mjibson/goread" 9 | ) 10 | 11 | func init() { 12 | router := mux.NewRouter() 13 | app.RegisterHandlers(router) 14 | http.Handle("/", router) 15 | } 16 | -------------------------------------------------------------------------------- /app/app.sample.yaml: -------------------------------------------------------------------------------- 1 | application: go-read 2 | version: 1 3 | runtime: go 4 | api_version: go1 5 | 6 | automatic_scaling: 7 | min_idle_instances: 1 8 | max_idle_instances: 1 9 | min_pending_latency: 500ms 10 | max_pending_latency: 5s 11 | max_concurrent_requests: 100 12 | 13 | handlers: 14 | - url: /favicon.ico 15 | static_files: static/favicon.png 16 | upload: static/favicon.png 17 | 18 | - url: /service-worker.js 19 | static_files: static/service-worker.js 20 | upload: static/service-worker.js 21 | 22 | - url: /manifest.json 23 | static_files: static/manifest.json 24 | upload: static/manifest.json 25 | 26 | - url: /index.html 27 | static_files: static/index.html 28 | upload: static/index.html 29 | application_readable: true 30 | 31 | - url: /static 32 | static_dir: static 33 | 34 | - url: /login/google 35 | login: required 36 | script: _go_app 37 | secure: always 38 | 39 | - url: /user/.* 40 | login: required 41 | script: _go_app 42 | secure: always 43 | 44 | - url: /task/.* 45 | login: admin 46 | script: _go_app 47 | secure: always 48 | 49 | - url: /admin/.* 50 | login: admin 51 | script: _go_app 52 | secure: always 53 | 54 | - url: /push 55 | script: _go_app 56 | 57 | - url: /.* 58 | script: _go_app 59 | secure: always 60 | -------------------------------------------------------------------------------- /app/cron.yaml: -------------------------------------------------------------------------------- 1 | cron: 2 | - description: hourly feed update 3 | url: /tasks/update-feeds 4 | schedule: every 2 minutes -------------------------------------------------------------------------------- /app/index.yaml: -------------------------------------------------------------------------------- 1 | indexes: 2 | 3 | # AUTOGENERATED 4 | 5 | # This index.yaml is automatically updated whenever the dev_appserver 6 | # detects that a new type of query is run. If you want to manage the 7 | # index.yaml file manually, remove the above marker line (the line 8 | # saying "# AUTOGENERATED"). If you want to manage some indexes 9 | # manually, move them above the marker line. The index.yaml file is 10 | # automatically uploaded to the admin console when you next deploy 11 | # your application using appcfg.py. 12 | 13 | - kind: S 14 | ancestor: yes 15 | properties: 16 | - name: c 17 | direction: desc 18 | 19 | - kind: US 20 | ancestor: yes 21 | properties: 22 | - name: c 23 | direction: desc 24 | -------------------------------------------------------------------------------- /app/queue.yaml: -------------------------------------------------------------------------------- 1 | queue: 2 | - name: update-feed 3 | rate: 10/s 4 | bucket_size: 20 5 | retry_parameters: 6 | task_retry_limit: 1 7 | - name: import-reader 8 | rate: 20/s 9 | retry_parameters: 10 | task_retry_limit: 2 11 | - name: update-manual 12 | rate: 50/s 13 | bucket_size: 20 14 | retry_parameters: 15 | task_retry_limit: 0 16 | - name: default 17 | rate: 20/s 18 | bucket_size: 20 -------------------------------------------------------------------------------- /app/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddyblue/goread/fa4d2aa4c078c7035cd04fe6bc981e0a3d1eac56/app/static/favicon.png -------------------------------------------------------------------------------- /app/static/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddyblue/goread/fa4d2aa4c078c7035cd04fe6bc981e0a3d1eac56/app/static/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /app/static/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddyblue/goread/fa4d2aa4c078c7035cd04fe6bc981e0a3d1eac56/app/static/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /app/static/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddyblue/goread/fa4d2aa4c078c7035cd04fe6bc981e0a3d1eac56/app/static/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /app/static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddyblue/goread/fa4d2aa4c078c7035cd04fe6bc981e0a3d1eac56/app/static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /app/static/icon-grey.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 13 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/static/icon-stroke.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 30 | 50 | 61 | 66 | 71 | 72 | -------------------------------------------------------------------------------- /app/static/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddyblue/goread/fa4d2aa4c078c7035cd04fe6bc981e0a3d1eac56/app/static/icon.png -------------------------------------------------------------------------------- /app/static/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 13 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /app/static/img/feed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddyblue/goread/fa4d2aa4c078c7035cd04fe6bc981e0a3d1eac56/app/static/img/feed.png -------------------------------------------------------------------------------- /app/static/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddyblue/goread/fa4d2aa4c078c7035cd04fe6bc981e0a3d1eac56/app/static/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /app/static/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddyblue/goread/fa4d2aa4c078c7035cd04fe6bc981e0a3d1eac56/app/static/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /app/static/img/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddyblue/goread/fa4d2aa4c078c7035cd04fe6bc981e0a3d1eac56/app/static/img/preview.png -------------------------------------------------------------------------------- /app/static/img/stripe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddyblue/goread/fa4d2aa4c078c7035cd04fe6bc981e0a3d1eac56/app/static/img/stripe.png -------------------------------------------------------------------------------- /app/static/index.html: -------------------------------------------------------------------------------- 1 | go read
-------------------------------------------------------------------------------- /app/static/js/mousetrap.min.js: -------------------------------------------------------------------------------- 1 | /* mousetrap v1.4.5 craig.is/killing/mice */ 2 | (function(J,r,f){function s(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c)}function A(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return h[a.which]?h[a.which]:B[a.which]?B[a.which]:String.fromCharCode(a.which).toLowerCase()}function t(a){a=a||{};var b=!1,c;for(c in n)a[c]?b=!0:n[c]=0;b||(u=!1)}function C(a,b,c,d,e,v){var g,k,f=[],h=c.type;if(!l[a])return[];"keyup"==h&&w(a)&&(b=[a]);for(g=0;gg||h.hasOwnProperty(g)&&(p[h[g]]=g)}e=p[c]?"keydown":"keypress"}"keypress"==e&&f.length&&(e="keydown");return{key:d,modifiers:f,action:e}}function F(a,b,c,d,e){q[a+":"+c]=b;a=a.replace(/\s+/g," ");var f=a.split(" ");1":".","?":"/","|":"\\"},G={option:"alt",command:"meta","return":"enter",escape:"esc",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},p,l={},q={},n={},D,z=!1,I=!1,u=!1;for(f=1;20>f;++f)h[111+f]="f"+f;for(f=0;9>=f;++f)h[f+96]=f;s(r,"keypress",y);s(r,"keydown",y);s(r,"keyup",y);var m={bind:function(a,b,c){a=a instanceof Array?a:[a];for(var d=0;d 2 | 3 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/templates/admin-date-formats.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 | {{range .}} 5 |
  • {{.Format}} - {{.URL}}
  • 6 | {{end}} 7 |
8 | 9 | 10 | -------------------------------------------------------------------------------- /app/templates/admin-feed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | update 5 | pubsub subscribe 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
url{{.Feed.Url}}
img{{.Feed.Image}}
img
title{{.Feed.Title}}
link{{.Feed.Link}}
errors{{.Feed.Errors}}
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
now{{.Now}}
updated{{.Feed.Updated}}{{since .Feed.Updated}}
date{{.Feed.Date}}{{since .Feed.Date}}
checked{{.Feed.Checked}}{{since .Feed.Checked}}
next{{.Feed.NextUpdate}}{{since .Feed.NextUpdate}}
subscribed{{.Feed.Subscribed}}{{since .Feed.Subscribed}}
last view{{.Feed.LastViewed}}{{since .Feed.LastViewed}}
average{{.Feed.Average}}
is subbed{{.Feed.IsSubscribed}}
pubsub
27 | 28 | logs: 29 |
    30 | {{range .Logs}} 31 |
  • 32 | {{nanotime .Id | since}} 33 | {{nanotime .Id}} 34 | {{.Text}} 35 |
  • 36 | {{end}} 37 |
38 | 39 | stories: 40 |
    41 | {{range .Stories}} 42 |
  • 43 | {{.Id}} 44 | {{.Created}} 45 | {{.Title}} 46 |
  • 47 | {{end}} 48 |
49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/templates/admin-stats.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 |
  • num users: {{.Users}}
  • 5 |
6 | 7 | 8 | -------------------------------------------------------------------------------- /app/templates/admin-user.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 18 | 19 |
id{{.User.Id}}
email{{.User.Email}}
read{{.User.Read}}
created{{.User.Created}}
account{{.User.Account}}
until{{.User.Until}}
set until 13 |
14 | 15 | 16 |
17 |
20 | OPML {{len .Data.Opml}}: 21 |
22 |
23 | 26 |
27 |
28 | 29 | {{range .Log}} 30 | 31 | 32 | 33 | 34 | 35 | {{end}} 36 |
{{nanotime .Id | since}}{{nanotime .Id}}{{.Text}}
37 | 38 | -------------------------------------------------------------------------------- /atom/atom.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go 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 | // Adapted from encoding/xml/read_test.go. 6 | 7 | // Package atom defines XML data structures for an Atom feed. 8 | package atom 9 | 10 | import ( 11 | "encoding/xml" 12 | "time" 13 | ) 14 | 15 | type Feed struct { 16 | XMLName xml.Name `xml:"feed"` 17 | Title string `xml:"title"` 18 | ID string `xml:"id"` 19 | Link []Link `xml:"link"` 20 | Updated TimeStr `xml:"updated"` 21 | Author *Person `xml:"author"` 22 | Entry []*Entry `xml:"entry"` 23 | XMLBase string `xml:"base,attr"` 24 | } 25 | 26 | type Entry struct { 27 | Title *Text `xml:"title"` 28 | ID string `xml:"id"` 29 | Link []Link `xml:"link"` 30 | Published TimeStr `xml:"published"` 31 | Updated TimeStr `xml:"updated"` 32 | Author *Person `xml:"author"` 33 | Summary *Text `xml:"summary"` 34 | Content *Text `xml:"content"` 35 | XMLBase string `xml:"base,attr"` 36 | } 37 | 38 | type Link struct { 39 | Rel string `xml:"rel,attr"` 40 | Href string `xml:"href,attr"` 41 | Type string `xml:"type,attr"` 42 | } 43 | 44 | type Person struct { 45 | Name string `xml:"name"` 46 | URI string `xml:"uri"` 47 | Email string `xml:"email"` 48 | InnerXML string `xml:",innerxml"` 49 | } 50 | 51 | type Text struct { 52 | Type string `xml:"type,attr"` 53 | Body string `xml:",chardata"` 54 | InnerXML string `xml:",innerxml"` 55 | } 56 | 57 | type TimeStr string 58 | 59 | func Time(t time.Time) TimeStr { 60 | return TimeStr(t.Format("2006-01-02T15:04:05-07:00")) 61 | } 62 | -------------------------------------------------------------------------------- /autodiscover.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Matt Jibson 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package goapp 18 | 19 | import ( 20 | "bytes" 21 | "errors" 22 | "io" 23 | 24 | "github.com/mjibson/goread/_third_party/golang.org/x/net/html" 25 | "github.com/mjibson/goread/_third_party/golang.org/x/net/html/atom" 26 | ) 27 | 28 | var ( 29 | ErrNoRssLink = errors.New("No rss link found") 30 | ErrNoIcon = errors.New("No icon found") 31 | ) 32 | 33 | func Autodiscover(b []byte) (string, error) { 34 | r := bytes.NewReader(b) 35 | z := html.NewTokenizer(r) 36 | for { 37 | if z.Next() == html.ErrorToken { 38 | if err := z.Err(); err == io.EOF { 39 | break 40 | } else { 41 | return "", ErrNoRssLink 42 | } 43 | } 44 | t := z.Token() 45 | switch t.DataAtom { 46 | case atom.Link: 47 | if t.Type == html.StartTagToken || t.Type == html.SelfClosingTagToken { 48 | attrs := make(map[string]string) 49 | for _, a := range t.Attr { 50 | attrs[a.Key] = a.Val 51 | } 52 | if attrs["rel"] == "alternate" && attrs["href"] != "" && 53 | (attrs["type"] == "application/rss+xml" || attrs["type"] == "application/atom+xml") { 54 | return attrs["href"], nil 55 | } 56 | } 57 | } 58 | } 59 | return "", ErrNoRssLink 60 | } 61 | 62 | // Returns the href attribute of a tag or error if not found. 63 | func FindIcon(b []byte) (string, error) { 64 | r := bytes.NewReader(b) 65 | z := html.NewTokenizer(r) 66 | for { 67 | if z.Next() == html.ErrorToken { 68 | if err := z.Err(); err == io.EOF { 69 | break 70 | } else { 71 | return "", ErrNoIcon 72 | } 73 | } 74 | t := z.Token() 75 | switch t.DataAtom { 76 | case atom.Link: 77 | if t.Type == html.StartTagToken || t.Type == html.SelfClosingTagToken { 78 | attrs := make(map[string]string) 79 | for _, a := range t.Attr { 80 | attrs[a.Key] = a.Val 81 | } 82 | if attrs["rel"] == "shortcut icon" && attrs["href"] != "" { 83 | return attrs["href"], nil 84 | } 85 | } 86 | } 87 | } 88 | return "", ErrNoIcon 89 | } 90 | -------------------------------------------------------------------------------- /dev.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Matt Jibson 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package goapp 18 | 19 | import ( 20 | "fmt" 21 | "net/http" 22 | "time" 23 | 24 | mpg "github.com/mjibson/goread/_third_party/github.com/MiniProfiler/go/miniprofiler_gae" 25 | "github.com/mjibson/goread/_third_party/github.com/mjibson/goon" 26 | 27 | "appengine/datastore" 28 | "appengine/user" 29 | ) 30 | 31 | func ClearRead(c mpg.Context, w http.ResponseWriter, r *http.Request) { 32 | if !isDevServer { 33 | return 34 | } 35 | 36 | cu := user.Current(c) 37 | gn := goon.FromContext(c) 38 | u := &User{Id: cu.ID} 39 | ud := &UserData{Id: "data", Parent: gn.Key(u)} 40 | if err := gn.Get(u); err != nil { 41 | c.Errorf("err: %v", err.Error()) 42 | return 43 | } 44 | gn.Get(ud) 45 | u.Read = time.Time{} 46 | ud.Read = nil 47 | gn.PutMulti([]interface{}{u, ud}) 48 | http.Redirect(w, r, "/", http.StatusFound) 49 | } 50 | 51 | func ClearFeeds(c mpg.Context, w http.ResponseWriter, r *http.Request) { 52 | if !isDevServer { 53 | return 54 | } 55 | 56 | cu := user.Current(c) 57 | gn := goon.FromContext(c) 58 | done := make(chan bool) 59 | go func() { 60 | u := &User{Id: cu.ID} 61 | defer func() { done <- true }() 62 | ud := &UserData{Id: "data", Parent: gn.Key(u)} 63 | if err := gn.Get(u); err != nil { 64 | c.Errorf("user del err: %v", err.Error()) 65 | return 66 | } 67 | gn.Get(ud) 68 | u.Read = time.Time{} 69 | ud.Read = nil 70 | ud.Opml = nil 71 | gn.PutMulti([]interface{}{u, ud}) 72 | c.Infof("%v cleared", u.Email) 73 | }() 74 | del := func(kind string) { 75 | defer func() { done <- true }() 76 | q := datastore.NewQuery(kind).KeysOnly() 77 | keys, err := gn.GetAll(q, nil) 78 | if err != nil { 79 | c.Errorf("err: %v", err.Error()) 80 | return 81 | } 82 | if err := gn.DeleteMulti(keys); err != nil { 83 | c.Errorf("err: %v", err.Error()) 84 | return 85 | } 86 | c.Infof("%v deleted", kind) 87 | } 88 | types := []interface{}{ 89 | &Feed{}, 90 | &Story{}, 91 | &StoryContent{}, 92 | &Log{}, 93 | &UserOpml{}, 94 | } 95 | for _, i := range types { 96 | k := gn.Kind(i) 97 | go del(k) 98 | } 99 | 100 | for i := 0; i < len(types); i++ { 101 | <-done 102 | } 103 | 104 | http.Redirect(w, r, fmt.Sprintf("%s?url=http://localhost:8080%s", routeUrl("add-subscription"), routeUrl("test-atom")), http.StatusFound) 105 | } 106 | 107 | func TestAtom(c mpg.Context, w http.ResponseWriter, r *http.Request) { 108 | w.Write([]byte(testAtom)) 109 | } 110 | 111 | const testAtom = ` 112 | 113 | 114 | goread atom test 115 | 11 A look at <em>em</em> 116 | 22 A look at <em>em</em> 117 | 118 | 4 119 | Issue 8311 created: "HtmlElementBuilder doesn't allow <col> elements in <colgroup>" 120 | 121 | 122 | ` 123 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | goread.io -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | Page Redirection 10 | 11 | 12 | 13 | If you are not redirected automatically, follow this link. 14 | 15 | 16 | -------------------------------------------------------------------------------- /funcs.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Matt Jibson 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package goapp 18 | 19 | import ( 20 | "html/template" 21 | "reflect" 22 | "time" 23 | ) 24 | 25 | // eq reports whether the first argument is equal to 26 | // any of the remaining arguments. 27 | func eq(args ...interface{}) bool { 28 | if len(args) == 0 { 29 | return false 30 | } 31 | x := args[0] 32 | switch x := x.(type) { 33 | case string, int, int64, byte, float32, float64: 34 | for _, y := range args[1:] { 35 | if x == y { 36 | return true 37 | } 38 | } 39 | return false 40 | } 41 | 42 | for _, y := range args[1:] { 43 | if reflect.DeepEqual(x, y) { 44 | return true 45 | } 46 | } 47 | return false 48 | } 49 | 50 | func routeUrl(name string, pairs ...string) string { 51 | u, err := router.Get(name).URL(pairs...) 52 | if err != nil { 53 | return err.Error() 54 | } 55 | return u.String() 56 | } 57 | 58 | func htmlattr(s string) template.HTMLAttr { 59 | return template.HTMLAttr(s) 60 | } 61 | 62 | func since(t time.Time) time.Duration { 63 | return time.Since(t) 64 | } 65 | 66 | func nanotime(i int64) time.Time { 67 | return time.Unix(0, i) 68 | } 69 | 70 | var funcs = template.FuncMap{ 71 | "eq": eq, 72 | "htmlattr": htmlattr, 73 | "nanotime": nanotime, 74 | "url": routeUrl, 75 | "since": since, 76 | } 77 | -------------------------------------------------------------------------------- /mobile/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | coverage 3 | *.gzip 4 | node_modules 5 | npm-debug.log 6 | -------------------------------------------------------------------------------- /mobile/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | go read 9 | 15 | 16 | 17 |
18 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /mobile/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "go read", 3 | "icons": [ 4 | { 5 | "src": "/static/icon-stroke.svg", 6 | "sizes": "192x192", 7 | "type": "image/svg" 8 | } 9 | ], 10 | "start_url": "/", 11 | "display": "standalone" 12 | } 13 | -------------------------------------------------------------------------------- /mobile/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "goread-react", 3 | "version": "0.1.0", 4 | "private": true, 5 | "devDependencies": { 6 | "react-scripts": "0.4.2", 7 | "sw-precache": "^4.0.0" 8 | }, 9 | "dependencies": { 10 | "idb-keyval": "^2.1.2", 11 | "material-design-lite": "^1.2.1", 12 | "material-ui": "^0.15.4", 13 | "react": "^15.3.1", 14 | "react-dom": "^15.3.1", 15 | "react-tap-event-plugin": "^1.0.0" 16 | }, 17 | "scripts": { 18 | "start": "react-scripts start", 19 | "build": "react-scripts build && rm build/static/css/*.map build/static/js/*.map && cp manifest.json build/ && sw-precache --root='build/' --static-file-globs='build/**/!(*map*)' && git clean -f ../app/static && rm -f ../app/static/js/main.* ../app/static/css/main.* && cp -R build/static/* ../app/static/ && cp build/*.* ../app/static/", 20 | "test": "react-scripts test --env=jsdom", 21 | "eject": "react-scripts eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": "./node_modules/react-scripts/config/eslint.js" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /mobile/src/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maddyblue/goread/fa4d2aa4c078c7035cd04fe6bc981e0a3d1eac56/mobile/src/favicon.png -------------------------------------------------------------------------------- /mobile/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import 'material-design-lite/dist/material.css'; 5 | 6 | import injectTapEventPlugin from 'react-tap-event-plugin'; 7 | injectTapEventPlugin(); 8 | 9 | ReactDOM.render( 10 | , 11 | document.getElementById('root') 12 | ); 13 | -------------------------------------------------------------------------------- /rdf/rdf.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Matt Jibson 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package rdf 18 | 19 | import ( 20 | "encoding/xml" 21 | ) 22 | 23 | type RDF struct { 24 | XMLName xml.Name `xml:"RDF"` 25 | Channel *Channel `xml:"channel"` 26 | Item []*Item `xml:"item"` 27 | } 28 | 29 | type Channel struct { 30 | Title string `xml:"title"` 31 | Description string `xml:"description"` 32 | Link string `xml:"link"` 33 | Date string `xml:"date"` 34 | } 35 | 36 | type Item struct { 37 | About string `xml:"about,attr"` 38 | Format string `xml:"format"` 39 | Date string `xml:"date"` 40 | Source string `xml:"source"` 41 | Creator string `xml:"creator"` 42 | Title string `xml:"title"` 43 | Link string `xml:"link"` 44 | Description string `xml:"description"` 45 | Content string `xml:"encoded"` 46 | } 47 | -------------------------------------------------------------------------------- /rss/rss.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 Evan Farrer. 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 rss 6 | 7 | type Rss struct { 8 | XMLName string `xml:"rss"` 9 | Title string `xml:"channel>title"` 10 | Link []Link `xml:"channel>link"` 11 | Description string `xml:"channel>description"` 12 | PubDate string `xml:"channel>pubDate,omitempty"` 13 | LastBuildDate string `xml:"channel>lastBuildDate,omitempty"` 14 | Items []*Item `xml:"channel>item"` 15 | } 16 | 17 | func (r *Rss) Hub() string { 18 | for _, l := range r.Link { 19 | if l.Rel == "hub" { 20 | return l.Href 21 | } 22 | } 23 | return "" 24 | } 25 | 26 | func (r *Rss) BaseLink() string { 27 | for _, l := range r.Link { 28 | if l.Rel == "" && l.Type == "" && l.Href == "" && l.Chardata != "" { 29 | return l.Chardata 30 | } 31 | } 32 | return "" 33 | } 34 | 35 | type Link struct { 36 | Rel string `xml:"rel,attr"` 37 | Href string `xml:"href,attr"` 38 | Type string `xml:"type,attr"` 39 | Chardata string `xml:",chardata"` 40 | } 41 | 42 | type Item struct { 43 | Title string `xml:"title,omitempty"` 44 | Link string `xml:"link,omitempty"` 45 | Description string `xml:"description,omitempty"` 46 | Author string `xml:"author,omitempty"` 47 | Enclosure *Enclosure `xml:"enclosure"` 48 | Guid *Guid `xml:"guid"` 49 | PubDate string `xml:"pubDate,omitempty"` 50 | Source *Source `xml:"source"` 51 | Content string `xml:"encoded,omitempty"` 52 | Date string `xml:"date,omitempty"` 53 | Published string `xml:"published,omitempty"` 54 | Media *MediaContent `xml:"content"` 55 | } 56 | 57 | type MediaContent struct { 58 | XMLBase string `xml:"http://search.yahoo.com/mrss/ content"` 59 | URL string `xml:"url,attr"` 60 | Type string `xml:"type,attr"` 61 | } 62 | 63 | type Source struct { 64 | Source string `xml:",chardata"` 65 | Url string `xml:"url,attr"` 66 | } 67 | 68 | type Guid struct { 69 | Guid string `xml:",chardata"` 70 | IsPermaLink bool `xml:"isPermaLink,attr,omitempty"` 71 | } 72 | 73 | type Enclosure struct { 74 | Url string `xml:"url,attr"` 75 | Length string `xml:"length,attr,omitempty"` 76 | Type string `xml:"type,attr"` 77 | } 78 | -------------------------------------------------------------------------------- /rss/rss_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Matt Jibson 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package rss 18 | 19 | import ( 20 | "encoding/xml" 21 | "strings" 22 | "testing" 23 | 24 | "github.com/mjibson/goread/_third_party/code.google.com/p/go-charset/charset" 25 | ) 26 | 27 | func TestCDATALink(t *testing.T) { 28 | r := Rss{} 29 | d := xml.NewDecoder(strings.NewReader(ATALSOFT_FEED)) 30 | d.CharsetReader = charset.NewReader 31 | d.DefaultSpace = "DefaultSpace" 32 | if err := d.Decode(&r); err != nil { 33 | t.Fatal(err) 34 | } 35 | if r.BaseLink() != "http://www.atalasoft.com/blogs/blogsrss.aspx?rss=loufranco" { 36 | t.Error("bad link", r.BaseLink()) 37 | } 38 | } 39 | 40 | const ATALSOFT_FEED = ` 41 | 42 | 43 | <![CDATA[Lou Franco]]> 44 | 45 | 46 | 47 | 48 | 49 | ` 50 | 51 | func TestParseHub(t *testing.T) { 52 | r := Rss{} 53 | d := xml.NewDecoder(strings.NewReader(WP_FEED)) 54 | d.CharsetReader = charset.NewReader 55 | d.DefaultSpace = "DefaultSpace" 56 | if err := d.Decode(&r); err != nil { 57 | t.Fatal(err) 58 | } 59 | if r.Hub() != "http://en.blog.wordpress.com/?pushpress=hub" { 60 | t.Error("bad hub") 61 | } 62 | if r.BaseLink() != "http://en.blog.wordpress.com" { 63 | t.Error("bad link") 64 | } 65 | } 66 | 67 | const WP_FEED = ` 68 | 69 | 78 | 79 | 80 | WordPress.com News 81 | 82 | http://en.blog.wordpress.com 83 | The latest news on WordPress.com and the WordPress community. 84 | Sat, 07 Dec 2013 04:07:23 +0000 85 | en 86 | hourly 87 | 1 88 | http://wordpress.com/ 89 | 90 | 91 | http://s2.wp.com/i/buttonw-com.png 92 | 93 | http://en.blog.wordpress.com 94 | 95 | 98 | 99 | ` 100 | -------------------------------------------------------------------------------- /sanitizer/snip.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Matt Jibson 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package sanitizer 18 | 19 | import ( 20 | "bytes" 21 | "regexp" 22 | "strings" 23 | "unicode/utf8" 24 | 25 | "github.com/mjibson/goread/_third_party/golang.org/x/net/html" 26 | ) 27 | 28 | var snipRe = regexp.MustCompile("[\\s]+") 29 | 30 | func SnipText(s string, length int) string { 31 | s = snipRe.ReplaceAllString(strings.TrimSpace(s), " ") 32 | s = html.UnescapeString(s) 33 | if len(s) <= length { 34 | return s 35 | } 36 | s = s[:length] 37 | i := strings.LastIndexAny(s, " .-!?") 38 | if i != -1 { 39 | return s[:i] 40 | } 41 | return CleanNonUTF8(s) 42 | } 43 | 44 | func CleanNonUTF8(s string) string { 45 | b := &bytes.Buffer{} 46 | for i := 0; i < len(s); i++ { 47 | c, size := utf8.DecodeRuneInString(s[i:]) 48 | if c != utf8.RuneError || size != 1 { 49 | b.WriteRune(c) 50 | } 51 | } 52 | return b.String() 53 | } 54 | -------------------------------------------------------------------------------- /sanitizer/strip.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Matt Jibson 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package sanitizer 18 | 19 | func StripTags(s string) (r string) { 20 | _, r = Sanitize(s, nil) 21 | return 22 | } 23 | -------------------------------------------------------------------------------- /settings.go.dist: -------------------------------------------------------------------------------- 1 | package goapp 2 | 3 | import ( 4 | "appengine" 5 | "time" 6 | ) 7 | 8 | var ( 9 | ENABLE_PUBSUBHUBBUB bool = !appengine.IsDevAppServer() 10 | STRIPE_PLANS = []Plan{} 11 | ) 12 | 13 | const ( 14 | GOOGLE_ANALYTICS_ID = "" 15 | GOOGLE_ANALYTICS_HOST = "" 16 | PUBSUBHUBBUB_HOST = "" // e.g., "www.goread.io" 17 | STRIPE_KEY = "" 18 | STRIPE_SECRET = "" 19 | STRIPE_PLAN = "" 20 | ) 21 | 22 | const ( 23 | UpdateMin = time.Minute * 20 24 | UpdateMax = time.Hour * 12 25 | UpdateDefault = time.Hour * 3 26 | UpdateFraction = 0.5 27 | UpdateJitter = time.Minute * 3 28 | UpdateLongFactor = 20 29 | NewIntervalWeight = 0.2 30 | ) 31 | --------------------------------------------------------------------------------