├── .gitignore ├── Gopkg.lock ├── Gopkg.toml ├── LICENSE ├── README.md ├── archive └── main.go ├── cmd └── grain │ ├── .gitignore │ ├── lookup.json │ └── main.go ├── facebook ├── api.go └── facebook.go ├── gen ├── facebook │ ├── archive.pb.go │ ├── download │ │ ├── about_you.pb.go │ │ ├── ads.pb.go │ │ ├── apps.pb.go │ │ ├── comments.pb.go │ │ ├── events.pb.go │ │ ├── following_and_followers.pb.go │ │ ├── friends.pb.go │ │ └── groups.pb.go │ ├── node.pb.go │ ├── photo.pb.go │ └── user.pb.go └── twitter │ ├── archive.pb.go │ ├── dm.pb.go │ ├── entity.pb.go │ ├── list.pb.go │ ├── tweet.pb.go │ └── user.pb.go ├── proto ├── facebook │ ├── archive.proto │ ├── download │ │ ├── about_you.proto │ │ ├── ads.proto │ │ ├── apps.proto │ │ ├── comments.proto │ │ ├── events.proto │ │ ├── following_and_followers.proto │ │ ├── friends.proto │ │ └── groups.proto │ ├── node.proto │ ├── photo.proto │ └── user.proto ├── prototool.yaml └── twitter │ ├── archive.proto │ ├── dm.proto │ ├── entity.proto │ ├── list.proto │ ├── tweet.proto │ └── user.proto ├── twitter ├── api.go ├── csv.go ├── errors.go └── twitter.go └── vendor ├── github.com ├── ChimeraCoder │ └── tokenbucket │ │ ├── .gitignore │ │ ├── COPYING │ │ ├── LICENSE │ │ ├── README │ │ ├── README.md │ │ └── tokenbucket.go ├── garyburd │ └── go-oauth │ │ └── oauth │ │ ├── oauth.go │ │ ├── oauth16.go │ │ └── oauth17.go ├── golang │ └── protobuf │ │ ├── AUTHORS │ │ ├── CONTRIBUTORS │ │ ├── LICENSE │ │ ├── jsonpb │ │ └── jsonpb.go │ │ ├── proto │ │ ├── clone.go │ │ ├── decode.go │ │ ├── discard.go │ │ ├── encode.go │ │ ├── equal.go │ │ ├── extensions.go │ │ ├── lib.go │ │ ├── message_set.go │ │ ├── pointer_reflect.go │ │ ├── pointer_unsafe.go │ │ ├── properties.go │ │ ├── table_marshal.go │ │ ├── table_merge.go │ │ ├── table_unmarshal.go │ │ ├── text.go │ │ └── text_parser.go │ │ └── ptypes │ │ └── struct │ │ ├── struct.pb.go │ │ └── struct.proto ├── google │ └── btree │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── btree.go │ │ └── btree_mem.go ├── gregjones │ └── httpcache │ │ ├── .travis.yml │ │ ├── LICENSE.txt │ │ ├── README.md │ │ ├── diskcache │ │ └── diskcache.go │ │ └── httpcache.go ├── pelletier │ └── go-toml │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── benchmark.json │ │ ├── benchmark.sh │ │ ├── benchmark.toml │ │ ├── benchmark.yml │ │ ├── doc.go │ │ ├── example-crlf.toml │ │ ├── example.toml │ │ ├── fuzz.go │ │ ├── fuzz.sh │ │ ├── keysparsing.go │ │ ├── lexer.go │ │ ├── marshal.go │ │ ├── marshal_test.toml │ │ ├── parser.go │ │ ├── position.go │ │ ├── test.sh │ │ ├── token.go │ │ ├── toml.go │ │ ├── tomltree_create.go │ │ └── tomltree_write.go ├── petar │ └── GoLLRB │ │ ├── AUTHORS │ │ ├── LICENSE │ │ └── llrb │ │ ├── avgvar.go │ │ ├── iterator.go │ │ ├── llrb-stats.go │ │ ├── llrb.go │ │ └── util.go └── peterbourgon │ └── diskv │ ├── LICENSE │ ├── README.md │ ├── compression.go │ ├── diskv.go │ └── index.go └── golang.org └── x ├── net ├── AUTHORS ├── CONTRIBUTORS ├── LICENSE ├── PATENTS └── context │ ├── context.go │ ├── go17.go │ ├── go19.go │ ├── pre_go17.go │ └── pre_go19.go └── sync ├── AUTHORS ├── CONTRIBUTORS ├── LICENSE ├── PATENTS └── errgroup └── errgroup.go /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyleconroy/grain/5b2671dfb5f42dcccf7376cc63f7ef6d5b92cd4b/.gitignore -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | branch = "master" 6 | name = "github.com/ChimeraCoder/tokenbucket" 7 | packages = ["."] 8 | revision = "c5a927568de7aad8a58127d80bcd36ca4e71e454" 9 | 10 | [[projects]] 11 | branch = "master" 12 | name = "github.com/garyburd/go-oauth" 13 | packages = ["oauth"] 14 | revision = "bca2e7f09a178fd36b034107a00e2323bca6a82e" 15 | 16 | [[projects]] 17 | name = "github.com/golang/protobuf" 18 | packages = [ 19 | "jsonpb", 20 | "proto", 21 | "ptypes/struct" 22 | ] 23 | revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" 24 | version = "v1.1.0" 25 | 26 | [[projects]] 27 | branch = "master" 28 | name = "github.com/google/btree" 29 | packages = ["."] 30 | revision = "e89373fe6b4a7413d7acd6da1725b83ef713e6e4" 31 | 32 | [[projects]] 33 | branch = "master" 34 | name = "github.com/gregjones/httpcache" 35 | packages = [ 36 | ".", 37 | "diskcache" 38 | ] 39 | revision = "9cad4c3443a7200dd6400aef47183728de563a38" 40 | 41 | [[projects]] 42 | name = "github.com/pelletier/go-toml" 43 | packages = ["."] 44 | revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8" 45 | version = "v1.1.0" 46 | 47 | [[projects]] 48 | branch = "master" 49 | name = "github.com/petar/GoLLRB" 50 | packages = ["llrb"] 51 | revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" 52 | 53 | [[projects]] 54 | name = "github.com/peterbourgon/diskv" 55 | packages = ["."] 56 | revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" 57 | version = "v2.0.1" 58 | 59 | [[projects]] 60 | branch = "master" 61 | name = "golang.org/x/net" 62 | packages = ["context"] 63 | revision = "1e491301e022f8f977054da4c2d852decd59571f" 64 | 65 | [[projects]] 66 | branch = "master" 67 | name = "golang.org/x/sync" 68 | packages = ["errgroup"] 69 | revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca" 70 | 71 | [solve-meta] 72 | analyzer-name = "dep" 73 | analyzer-version = 1 74 | inputs-digest = "1d178e106be67bc1adfbec88d4b2d4fd7294d3344064be1687c9dbe17304e40c" 75 | solver-name = "gps-cdcl" 76 | solver-version = 1 77 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | 28 | [prune] 29 | go-tests = true 30 | unused-packages = true 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Kyle Conroy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Grain 2 | 3 | The Entire History of You 4 | 5 | ## Usage 6 | 7 | Grain looks for API access keys and secrets in `config.toml`. 8 | 9 | ## Twitter 10 | 11 | Grain will download a full archive of your Twitter account, unlike the official 12 | Twitter Archive. Your Grain archive includes the following records: 13 | 14 | - Direct messages 15 | - Favorites 16 | - Followers 17 | - Friends 18 | - Lists 19 | - Tweets 20 | 21 | The archive also includes all media associated with the above records. 22 | 23 | For privacy and performance reasons, you'll need to obtain your own API 24 | credentials. 25 | 26 | 1. Log onto [Twitter](https://twitter.com) with the account you'd like to archive 27 | 2. Request your archive from your [Settings page](https://twitter.com/settings/account) 28 | 3. Create a new [application](https://apps.twitter.com) 29 | 4. Go to the "Keys and Access Tokens" section for your application 30 | 5. Generate access tokens via "Create my access token" 31 | 6. Fill in `config.toml` with the access and secret tokens 32 | 33 | ``` 34 | [twitter] 35 | username = "" 36 | tweet-csv = "path/to/tweets.csv" 37 | consumer-key = "" 38 | consumer-secret = "" 39 | access-token = "" 40 | access-token-secret = "" 41 | ``` 42 | 43 | Running `grain` will download records to `archive/twitter` in the current 44 | working directory. 45 | 46 | ### Limitations 47 | 48 | The Twitter API has a set of limitations which makes archiving certain records 49 | difficult. 50 | 51 | - The API only returns the most recent 3,200 tweets from your timeline. You'll 52 | need to download your official Twitter Archive for Grain to successfully 53 | archive all of your tweets. 54 | - Only the last 30 days of direct message activity is available via the API. 55 | - Rate limits are very aggressive which means certain records take forever to 56 | archive. 57 | 58 | ## Facebook 59 | 60 | Coming soon… 61 | -------------------------------------------------------------------------------- /archive/main.go: -------------------------------------------------------------------------------- 1 | package archive 2 | 3 | import ( 4 | "context" 5 | "io/ioutil" 6 | "net/http" 7 | "net/url" 8 | "os" 9 | "path" 10 | "path/filepath" 11 | ) 12 | 13 | func ArchiveURL(ctx context.Context, service, folder, uri string) error { 14 | parsed, err := url.Parse(uri) 15 | if err != nil { 16 | return err 17 | } 18 | if parsed.Host == "" { 19 | panic("All URLs must have attached host names: " + uri) 20 | } 21 | 22 | fullpath := path.Join("archive", service, folder, parsed.Host, parsed.Path) 23 | 24 | if _, err := os.Stat(fullpath); err == nil { 25 | // path/to/whatever exists 26 | return nil 27 | } 28 | 29 | if err := os.MkdirAll(filepath.Dir(fullpath), 0755); err != nil { 30 | return err 31 | } 32 | 33 | resp, err := http.Get(parsed.String()) 34 | if err != nil { 35 | return err 36 | } 37 | 38 | // For now, ignore everything else that isn't 200 39 | if resp.StatusCode != http.StatusOK { 40 | return nil 41 | } 42 | 43 | defer resp.Body.Close() 44 | blob, err := ioutil.ReadAll(resp.Body) 45 | if err != nil { 46 | return err 47 | } 48 | 49 | return ioutil.WriteFile(fullpath, blob, 0644) 50 | } 51 | -------------------------------------------------------------------------------- /cmd/grain/.gitignore: -------------------------------------------------------------------------------- 1 | archive 2 | config.toml 3 | grain 4 | httpcache 5 | -------------------------------------------------------------------------------- /cmd/grain/lookup.json: -------------------------------------------------------------------------------- 1 | { 2 | "album": { 3 | "fields": [ 4 | "id", 5 | "backdated_time", 6 | "backdated_time_granularity", 7 | "can_backdate", 8 | "can_upload", 9 | "count", 10 | "cover_photo", 11 | "created_time", 12 | "description", 13 | "edit_link", 14 | "event", 15 | "from", 16 | "is_user_facing", 17 | "link", 18 | "location", 19 | "modified_major", 20 | "name", 21 | "photo_count", 22 | "place", 23 | "privacy", 24 | "type", 25 | "updated_time", 26 | "video_count" 27 | ], 28 | "connections": [ 29 | "reactions", 30 | "sharedposts", 31 | "comments", 32 | "likes", 33 | "photos" 34 | ] 35 | }, 36 | "photo": { 37 | "fields": [ 38 | "id", 39 | "album", 40 | "backdated_time", 41 | "backdated_time_granularity", 42 | "can_backdate", 43 | "can_delete", 44 | "can_tag", 45 | "created_time", 46 | "event", 47 | "from", 48 | "height", 49 | "icon", 50 | "images", 51 | "link", 52 | "name", 53 | "name_tags", 54 | "page_story_id", 55 | "picture", 56 | "place", 57 | "target", 58 | "updated_time", 59 | "webp_images", 60 | "width" 61 | ], 62 | "connections": [ 63 | "sponsor_tags", 64 | "tags", 65 | "comments", 66 | "likes", 67 | "reactions", 68 | "sharedposts" 69 | ] 70 | }, 71 | "user": { 72 | "fields": [ 73 | "about", 74 | "id", 75 | "address", 76 | "age_range", 77 | "birthday", 78 | "can_review_measurement_request", 79 | "context", 80 | "cover", 81 | "currency", 82 | "devices", 83 | "education", 84 | "email", 85 | "favorite_athletes", 86 | "favorite_teams", 87 | "first_name", 88 | "gender", 89 | "hometown", 90 | "inspirational_people", 91 | "install_type", 92 | "installed", 93 | "interested_in", 94 | "is_famedeeplinkinguser", 95 | "is_shared_login", 96 | "is_verified", 97 | "languages", 98 | "last_name", 99 | "link", 100 | "locale", 101 | "location", 102 | "meeting_for", 103 | "middle_name", 104 | "name", 105 | "name_format", 106 | "payment_pricepoints", 107 | "political", 108 | "public_key", 109 | "quotes", 110 | "relationship_status", 111 | "religion", 112 | "security_settings", 113 | "shared_login_upgrade_required_by", 114 | "short_name", 115 | "significant_other", 116 | "sports", 117 | "test_group", 118 | "third_party_id", 119 | "timezone", 120 | "updated_time", 121 | "verified", 122 | "video_upload_limits", 123 | "viewer_can_send_gift", 124 | "website", 125 | "work" 126 | ], 127 | "connections": [ 128 | "television", 129 | "video_broadcasts", 130 | "achievements", 131 | "adaccounts", 132 | "custom_labels", 133 | "friendlists", 134 | "photos", 135 | "posts", 136 | "rich_media_documents", 137 | "session_keys", 138 | "books", 139 | "feed", 140 | "tagged_places", 141 | "insights", 142 | "apprequestformerrecipients", 143 | "request_history", 144 | "adnetworkanalytics", 145 | "albums", 146 | "events", 147 | "groups", 148 | "domains", 149 | "promotable_events", 150 | "accounts", 151 | "favorite_requests", 152 | "ids_for_business", 153 | "videos", 154 | "asset3ds", 155 | "likes", 156 | "movies", 157 | "businesses", 158 | "friends", 159 | "business_users", 160 | "games", 161 | "tagged", 162 | "apprequests", 163 | "permissions", 164 | "family", 165 | "music" 166 | ] 167 | } 168 | } -------------------------------------------------------------------------------- /cmd/grain/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/kyleconroy/grain/facebook" 9 | "github.com/kyleconroy/grain/twitter" 10 | toml "github.com/pelletier/go-toml" 11 | ) 12 | 13 | func run() error { 14 | config, err := toml.LoadFile("config.toml") 15 | if err != nil { 16 | return err 17 | } 18 | 19 | if config.Has("twitter") { 20 | config, ok := config.Get("twitter").(*toml.Tree) 21 | if !ok { 22 | return fmt.Errorf("Config file should contain a [twitter] section") 23 | } 24 | a, err := twitter.NewArchiver(config) 25 | if err != nil { 26 | return err 27 | } 28 | if err := a.Sync(context.TODO()); err != nil { 29 | return err 30 | } 31 | } 32 | 33 | if config.Has("facebook") { 34 | config, ok := config.Get("facebook").(*toml.Tree) 35 | if !ok { 36 | return fmt.Errorf("Config file should contain a [facebook] section") 37 | } 38 | 39 | a := facebook.NewArchiver(config) 40 | if err := a.Sync(context.TODO()); err != nil { 41 | return err 42 | } 43 | } 44 | 45 | return nil 46 | } 47 | 48 | func main() { 49 | if err := run(); err != nil { 50 | fmt.Println(err) 51 | os.Exit(1) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /facebook/api.go: -------------------------------------------------------------------------------- 1 | package facebook 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "net/http/httputil" 9 | "net/url" 10 | "strings" 11 | 12 | "github.com/golang/protobuf/proto" 13 | "github.com/kyleconroy/grain/gen/facebook" 14 | ) 15 | 16 | type Client struct { 17 | HttpClient *http.Client 18 | baseURL string 19 | accessToken string 20 | } 21 | 22 | func NewClient(token string) *Client { 23 | return &Client{ 24 | accessToken: token, 25 | HttpClient: http.DefaultClient, 26 | baseURL: "https://graph.facebook.com/v3.0/", 27 | } 28 | } 29 | 30 | type Field struct { 31 | Name string `json:"name"` 32 | Description string `json:"description"` 33 | Type string `json:"type"` 34 | } 35 | 36 | type Metadata struct { 37 | Fields []Field `json:"fields"` 38 | Connections map[string]string `json:"connections"` 39 | Type string `json:"type"` 40 | } 41 | 42 | type Node struct { 43 | Metadata Metadata `json:"metadata"` 44 | ID string `json:"id"` 45 | 46 | Message proto.Message 47 | } 48 | 49 | type Option func(*url.Values) 50 | 51 | func Fields(args ...string) func(form *url.Values) { 52 | return func(form *url.Values) { 53 | form.Set("fields", strings.Join(args, ",")) 54 | } 55 | } 56 | 57 | func (c *Client) GetNode(id string, options ...Option) (*Node, error) { 58 | form := url.Values{} 59 | form.Set("access_token", c.accessToken) 60 | form.Set("metadata", "1") 61 | form.Set("method", "GET") 62 | for _, opt := range options { 63 | opt(&form) 64 | } 65 | 66 | req, _ := http.NewRequest("POST", c.baseURL+id, strings.NewReader(form.Encode())) 67 | resp, err := c.HttpClient.Do(req) 68 | if err != nil { 69 | return nil, err 70 | } 71 | if resp.StatusCode != http.StatusOK { 72 | blob, _ := httputil.DumpResponse(resp, true) 73 | fmt.Println(string(blob)) 74 | return nil, fmt.Errorf("Unexpected status code: %d", resp.StatusCode) 75 | } 76 | defer resp.Body.Close() 77 | var n Node 78 | blob, err := ioutil.ReadAll(resp.Body) 79 | if err := json.Unmarshal(blob, &n); err != nil { 80 | return nil, err 81 | } 82 | 83 | // fmt.Println(string(blob)) 84 | var m proto.Message 85 | switch n.Metadata.Type { 86 | case "album": 87 | m = &facebookpb.Album{} 88 | case "photo": 89 | m = &facebookpb.Photo{} 90 | case "user": 91 | m = &facebookpb.User{} 92 | default: 93 | m = &facebookpb.Node{} 94 | } 95 | 96 | if err := json.Unmarshal(blob, &m); err != nil { 97 | return nil, err 98 | } 99 | 100 | n.Message = m 101 | return &n, nil 102 | } 103 | 104 | type Paging struct { 105 | Previous string `json:"previous"` 106 | Next string `json:"next"` 107 | } 108 | 109 | type Datalist struct { 110 | Data []Node 111 | Paging Paging 112 | } 113 | 114 | func (c *Client) GetEdge(id, connection string, paging *Paging, options ...Option) (*Datalist, error) { 115 | form := url.Values{} 116 | form.Set("access_token", c.accessToken) 117 | form.Set("method", "GET") 118 | form.Set("limit", "2000") 119 | for _, opt := range options { 120 | opt(&form) 121 | } 122 | 123 | u := c.baseURL + id + "/" + connection 124 | if paging != nil && paging.Next != "" { 125 | u = paging.Next 126 | } 127 | 128 | req, _ := http.NewRequest("POST", u, strings.NewReader(form.Encode())) 129 | resp, err := c.HttpClient.Do(req) 130 | if err != nil { 131 | return nil, err 132 | } 133 | if resp.StatusCode != http.StatusOK { 134 | blob, _ := httputil.DumpResponse(resp, true) 135 | fmt.Println(string(blob)) 136 | return nil, fmt.Errorf("Unexpected status code: %d", resp.StatusCode) 137 | } 138 | defer resp.Body.Close() 139 | var dl Datalist 140 | dec := json.NewDecoder(resp.Body) 141 | if err := dec.Decode(&dl); err != nil { 142 | return nil, err 143 | } 144 | return &dl, nil 145 | } 146 | -------------------------------------------------------------------------------- /facebook/facebook.go: -------------------------------------------------------------------------------- 1 | package facebook 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "io/ioutil" 8 | "path/filepath" 9 | "sort" 10 | 11 | "github.com/gregjones/httpcache" 12 | "github.com/gregjones/httpcache/diskcache" 13 | "github.com/kyleconroy/grain/archive" 14 | "github.com/kyleconroy/grain/gen/facebook" 15 | toml "github.com/pelletier/go-toml" 16 | ) 17 | 18 | type fieldschema struct { 19 | Fields []string `json:"fields"` 20 | Conns []string `json:"connections"` 21 | } 22 | 23 | type Archiver struct { 24 | accessToken string 25 | 26 | count int 27 | seen map[string]struct{} 28 | api *Client 29 | archive *facebookpb.Archive 30 | metadata map[string]fieldschema 31 | } 32 | 33 | func NewArchiver(c *toml.Tree) *Archiver { 34 | fields := map[string]fieldschema{} 35 | if blob, err := ioutil.ReadFile("lookup.json"); err == nil { 36 | if err := json.Unmarshal(blob, &fields); err != nil { 37 | panic(err) 38 | } 39 | } 40 | 41 | transport := httpcache.NewTransport(diskcache.New("httpcache")) 42 | fapi := NewClient(c.Get("access-token").(string)) 43 | fapi.HttpClient = transport.Client() 44 | 45 | return &Archiver{ 46 | accessToken: c.Get("access-token").(string), 47 | archive: &facebookpb.Archive{}, 48 | metadata: fields, 49 | api: fapi, 50 | seen: map[string]struct{}{}, 51 | } 52 | } 53 | 54 | func (a *Archiver) buildMetadata(ctx context.Context, id string) (string, error) { 55 | // Get the metadata 56 | m, err := a.api.GetNode(id) 57 | if err != nil { 58 | return "", err 59 | } 60 | 61 | kind := m.Metadata.Type 62 | 63 | _, known := a.metadata[kind] 64 | if known { 65 | return kind, nil 66 | } 67 | 68 | fields := []string{} 69 | for _, field := range m.Metadata.Fields { 70 | fmt.Println("Checking field: ", field.Name) 71 | _, err := a.api.GetNode(id, Fields(field.Name)) 72 | if err == nil { 73 | fields = append(fields, field.Name) 74 | } 75 | } 76 | 77 | conns := []string{} 78 | for edge, _ := range m.Metadata.Connections { 79 | fmt.Println("Checking connection: ", edge) 80 | if _, err := a.api.GetEdge(id, edge, nil); err == nil { 81 | conns = append(conns, edge) 82 | } 83 | } 84 | 85 | schema := fieldschema{ 86 | Fields: fields, 87 | Conns: conns, 88 | } 89 | 90 | a.metadata[kind] = schema 91 | 92 | blob, _ := json.MarshalIndent(a.metadata, "", " ") 93 | ioutil.WriteFile("lookup.json", blob, 0644) 94 | return kind, nil 95 | } 96 | 97 | func (a *Archiver) save() error { 98 | { 99 | path := filepath.Join("archive", "facebook", "me.json") 100 | b, err := json.MarshalIndent(facebookpb.Archive{Me: a.archive.Me}, "", " ") 101 | if err != nil { 102 | return err 103 | } 104 | if err := ioutil.WriteFile(path, b, 0644); err != nil { 105 | return err 106 | } 107 | } 108 | { 109 | path := filepath.Join("archive", "facebook", "photos.json") 110 | b, err := json.MarshalIndent(facebookpb.Archive{Photos: a.archive.Photos}, "", " ") 111 | if err != nil { 112 | return err 113 | } 114 | if err := ioutil.WriteFile(path, b, 0644); err != nil { 115 | return err 116 | } 117 | } 118 | { 119 | path := filepath.Join("archive", "facebook", "albums.json") 120 | b, err := json.MarshalIndent(facebookpb.Archive{Albums: a.archive.Albums}, "", " ") 121 | if err != nil { 122 | return err 123 | } 124 | if err := ioutil.WriteFile(path, b, 0644); err != nil { 125 | return err 126 | } 127 | } 128 | { 129 | path := filepath.Join("archive", "facebook", "friends.json") 130 | b, err := json.MarshalIndent(facebookpb.Archive{Friends: a.archive.Friends}, "", " ") 131 | if err != nil { 132 | return err 133 | } 134 | if err := ioutil.WriteFile(path, b, 0644); err != nil { 135 | return err 136 | } 137 | } 138 | return nil 139 | } 140 | 141 | func (a *Archiver) archiveNode(ctx context.Context, id string) error { 142 | // Don't process a node twice 143 | if _, ok := a.seen[id]; ok { 144 | return nil 145 | } 146 | 147 | // Fetch the node 148 | kind, err := a.buildMetadata(ctx, id) 149 | if err != nil { 150 | return err 151 | } 152 | 153 | fmt.Printf("node:%s kind:%s\n", id, kind) 154 | 155 | node, err := a.api.GetNode(id, Fields(a.metadata[kind].Fields...)) 156 | if err != nil { 157 | return err 158 | } 159 | 160 | a.seen[id] = struct{}{} 161 | 162 | switch v := node.Message.(type) { 163 | case *facebookpb.Photo: 164 | a.archive.Photos = append(a.archive.Photos, v) 165 | sort.Slice(v.Images, func(i, j int) bool { 166 | return (v.Images[i].Width + v.Images[i].Height) > (v.Images[j].Width + v.Images[j].Height) 167 | }) 168 | if err := archive.ArchiveURL(ctx, "facebook", "media", v.Images[0].Source); err != nil { 169 | return err 170 | } 171 | case *facebookpb.Album: 172 | a.archive.Albums = append(a.archive.Albums, v) 173 | case *facebookpb.User: 174 | if id == "me" { 175 | a.archive.Me = v 176 | } else { 177 | a.archive.Friends = append(a.archive.Friends, v) 178 | } 179 | } 180 | 181 | a.count += 1 182 | if a.count > 100 { 183 | if err := a.save(); err != nil { 184 | return err 185 | } 186 | } 187 | 188 | // Archive connections 189 | for _, connection := range a.metadata[kind].Conns { 190 | if a.CanFollow(id, kind, connection) { 191 | if err := a.archiveConnection(ctx, id, connection); err != nil { 192 | return err 193 | } 194 | } 195 | } 196 | 197 | return nil 198 | } 199 | 200 | func (a *Archiver) CanFollow(id, kind, connection string) bool { 201 | if id == "me" { 202 | return connection == "photos" || connection == "albums" 203 | } 204 | switch kind { 205 | case "album": 206 | return connection == "photos" 207 | default: 208 | return false 209 | } 210 | } 211 | 212 | func (a *Archiver) archiveConnection(ctx context.Context, id, connection string) error { 213 | fmt.Println("Connection:", id, connection) 214 | 215 | paging := Paging{} 216 | 217 | for { 218 | data, err := a.api.GetEdge(id, connection, &paging) 219 | if err != nil { 220 | return err 221 | } 222 | 223 | for _, node := range data.Data { 224 | // TODO: Pass kind to archiveNode so we don't have to make two requests 225 | if err := a.archiveNode(ctx, node.ID); err != nil { 226 | return err 227 | } 228 | } 229 | 230 | paging = data.Paging 231 | if paging.Next == "" { 232 | return nil 233 | } 234 | } 235 | return nil 236 | } 237 | 238 | func (a *Archiver) Sync(ctx context.Context) error { 239 | err := a.archiveNode(ctx, "me") 240 | // best effort to save 241 | a.save() 242 | return err 243 | } 244 | -------------------------------------------------------------------------------- /gen/facebook/archive.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: facebook/archive.proto 3 | 4 | /* 5 | Package facebookpb is a generated protocol buffer package. 6 | 7 | It is generated from these files: 8 | facebook/archive.proto 9 | facebook/node.proto 10 | facebook/photo.proto 11 | facebook/user.proto 12 | 13 | It has these top-level messages: 14 | Archive 15 | Node 16 | Owner 17 | Location 18 | Place 19 | Album 20 | Image 21 | Photo 22 | User 23 | */ 24 | package facebookpb 25 | 26 | import proto "github.com/golang/protobuf/proto" 27 | import fmt "fmt" 28 | import math "math" 29 | 30 | // Reference imports to suppress errors if they are not otherwise used. 31 | var _ = proto.Marshal 32 | var _ = fmt.Errorf 33 | var _ = math.Inf 34 | 35 | // This is a compile-time assertion to ensure that this generated file 36 | // is compatible with the proto package it is being compiled against. 37 | // A compilation error at this line likely means your copy of the 38 | // proto package needs to be updated. 39 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 40 | 41 | type Archive struct { 42 | Me *User `protobuf:"bytes,1,opt,name=me" json:"me,omitempty"` 43 | Photos []*Photo `protobuf:"bytes,2,rep,name=photos" json:"photos,omitempty"` 44 | Albums []*Album `protobuf:"bytes,3,rep,name=albums" json:"albums,omitempty"` 45 | Friends []*User `protobuf:"bytes,4,rep,name=friends" json:"friends,omitempty"` 46 | } 47 | 48 | func (m *Archive) Reset() { *m = Archive{} } 49 | func (m *Archive) String() string { return proto.CompactTextString(m) } 50 | func (*Archive) ProtoMessage() {} 51 | func (*Archive) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 52 | 53 | func (m *Archive) GetMe() *User { 54 | if m != nil { 55 | return m.Me 56 | } 57 | return nil 58 | } 59 | 60 | func (m *Archive) GetPhotos() []*Photo { 61 | if m != nil { 62 | return m.Photos 63 | } 64 | return nil 65 | } 66 | 67 | func (m *Archive) GetAlbums() []*Album { 68 | if m != nil { 69 | return m.Albums 70 | } 71 | return nil 72 | } 73 | 74 | func (m *Archive) GetFriends() []*User { 75 | if m != nil { 76 | return m.Friends 77 | } 78 | return nil 79 | } 80 | 81 | func init() { 82 | proto.RegisterType((*Archive)(nil), "grain.facebook.Archive") 83 | } 84 | 85 | func init() { proto.RegisterFile("facebook/archive.proto", fileDescriptor0) } 86 | 87 | var fileDescriptor0 = []byte{ 88 | // 187 bytes of a gzipped FileDescriptorProto 89 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4b, 0x4b, 0x4c, 0x4e, 90 | 0x4d, 0xca, 0xcf, 0xcf, 0xd6, 0x4f, 0x2c, 0x4a, 0xce, 0xc8, 0x2c, 0x4b, 0xd5, 0x2b, 0x28, 0xca, 91 | 0x2f, 0xc9, 0x17, 0xe2, 0x4b, 0x2f, 0x4a, 0xcc, 0xcc, 0xd3, 0x83, 0xc9, 0x4a, 0x89, 0xc0, 0xd5, 92 | 0x15, 0x64, 0xe4, 0x97, 0xe4, 0x43, 0x54, 0x49, 0x09, 0xc3, 0x45, 0x4b, 0x8b, 0x53, 0x8b, 0x20, 93 | 0x82, 0x4a, 0x7b, 0x19, 0xb9, 0xd8, 0x1d, 0x21, 0x86, 0x09, 0xa9, 0x70, 0x31, 0xe5, 0xa6, 0x4a, 94 | 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x1b, 0x89, 0xe8, 0xa1, 0x9a, 0xa9, 0x17, 0x5a, 0x9c, 0x5a, 0x14, 95 | 0xc4, 0x94, 0x9b, 0x2a, 0xa4, 0xcb, 0xc5, 0x06, 0x36, 0xb5, 0x58, 0x82, 0x49, 0x81, 0x59, 0x83, 96 | 0xdb, 0x48, 0x14, 0x5d, 0x65, 0x00, 0x48, 0x36, 0x08, 0xaa, 0x08, 0xa4, 0x3c, 0x31, 0x27, 0xa9, 97 | 0x34, 0xb7, 0x58, 0x82, 0x19, 0xbb, 0x72, 0x47, 0x90, 0x6c, 0x10, 0x54, 0x91, 0x90, 0x1e, 0x17, 98 | 0x7b, 0x5a, 0x51, 0x66, 0x6a, 0x5e, 0x4a, 0xb1, 0x04, 0x0b, 0x58, 0x3d, 0x76, 0x87, 0xc0, 0x14, 99 | 0x39, 0xf1, 0x44, 0x71, 0xc1, 0x64, 0x0a, 0x92, 0x92, 0xd8, 0xc0, 0x9e, 0x32, 0x06, 0x04, 0x00, 100 | 0x00, 0xff, 0xff, 0x17, 0x9f, 0x8d, 0x78, 0x29, 0x01, 0x00, 0x00, 101 | } 102 | -------------------------------------------------------------------------------- /gen/facebook/download/about_you.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: facebook/download/about_you.proto 3 | 4 | /* 5 | Package grain_facebook_download is a generated protocol buffer package. 6 | 7 | It is generated from these files: 8 | facebook/download/about_you.proto 9 | facebook/download/ads.proto 10 | facebook/download/apps.proto 11 | facebook/download/comments.proto 12 | facebook/download/events.proto 13 | facebook/download/following_and_followers.proto 14 | facebook/download/friends.proto 15 | facebook/download/groups.proto 16 | 17 | It has these top-level messages: 18 | AddressBook 19 | Ads 20 | InstalledApps 21 | PostsFromApps 22 | YourApps 23 | Comment 24 | PhotoMetadata 25 | MediaMetadata 26 | Media 27 | AttachmentData 28 | Attachment 29 | Post 30 | YourPosts 31 | Coordinate 32 | Event 33 | EventInvitations 34 | EventResponses 35 | YourEvents 36 | FollowedPages 37 | Friend 38 | FriendsAdded 39 | RejectedRequests 40 | RemovedFriends 41 | SentRequests 42 | GroupsYouManage 43 | GroupMembershipActivity 44 | GroupPostsComments 45 | */ 46 | package grain_facebook_download 47 | 48 | import proto "github.com/golang/protobuf/proto" 49 | import fmt "fmt" 50 | import math "math" 51 | 52 | // Reference imports to suppress errors if they are not otherwise used. 53 | var _ = proto.Marshal 54 | var _ = fmt.Errorf 55 | var _ = math.Inf 56 | 57 | // This is a compile-time assertion to ensure that this generated file 58 | // is compatible with the proto package it is being compiled against. 59 | // A compilation error at this line likely means your copy of the 60 | // proto package needs to be updated. 61 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 62 | 63 | type AddressBook struct { 64 | AddressBook *AddressBook_AddressBookEntry `protobuf:"bytes,1,opt,name=address_book,json=addressBook" json:"address_book,omitempty"` 65 | } 66 | 67 | func (m *AddressBook) Reset() { *m = AddressBook{} } 68 | func (m *AddressBook) String() string { return proto.CompactTextString(m) } 69 | func (*AddressBook) ProtoMessage() {} 70 | func (*AddressBook) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 71 | 72 | func (m *AddressBook) GetAddressBook() *AddressBook_AddressBookEntry { 73 | if m != nil { 74 | return m.AddressBook 75 | } 76 | return nil 77 | } 78 | 79 | type AddressBook_Details struct { 80 | ContactPoint string `protobuf:"bytes,1,opt,name=contact_point,json=contactPoint" json:"contact_point,omitempty"` 81 | } 82 | 83 | func (m *AddressBook_Details) Reset() { *m = AddressBook_Details{} } 84 | func (m *AddressBook_Details) String() string { return proto.CompactTextString(m) } 85 | func (*AddressBook_Details) ProtoMessage() {} 86 | func (*AddressBook_Details) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} } 87 | 88 | func (m *AddressBook_Details) GetContactPoint() string { 89 | if m != nil { 90 | return m.ContactPoint 91 | } 92 | return "" 93 | } 94 | 95 | type AddressBook_Contact struct { 96 | Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` 97 | Details []*AddressBook_Details `protobuf:"bytes,2,rep,name=details" json:"details,omitempty"` 98 | } 99 | 100 | func (m *AddressBook_Contact) Reset() { *m = AddressBook_Contact{} } 101 | func (m *AddressBook_Contact) String() string { return proto.CompactTextString(m) } 102 | func (*AddressBook_Contact) ProtoMessage() {} 103 | func (*AddressBook_Contact) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 1} } 104 | 105 | func (m *AddressBook_Contact) GetName() string { 106 | if m != nil { 107 | return m.Name 108 | } 109 | return "" 110 | } 111 | 112 | func (m *AddressBook_Contact) GetDetails() []*AddressBook_Details { 113 | if m != nil { 114 | return m.Details 115 | } 116 | return nil 117 | } 118 | 119 | type AddressBook_AddressBookEntry struct { 120 | AddressBook []*AddressBook_Contact `protobuf:"bytes,1,rep,name=address_book,json=addressBook" json:"address_book,omitempty"` 121 | } 122 | 123 | func (m *AddressBook_AddressBookEntry) Reset() { *m = AddressBook_AddressBookEntry{} } 124 | func (m *AddressBook_AddressBookEntry) String() string { return proto.CompactTextString(m) } 125 | func (*AddressBook_AddressBookEntry) ProtoMessage() {} 126 | func (*AddressBook_AddressBookEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 2} } 127 | 128 | func (m *AddressBook_AddressBookEntry) GetAddressBook() []*AddressBook_Contact { 129 | if m != nil { 130 | return m.AddressBook 131 | } 132 | return nil 133 | } 134 | 135 | func init() { 136 | proto.RegisterType((*AddressBook)(nil), "grain.facebook.download.AddressBook") 137 | proto.RegisterType((*AddressBook_Details)(nil), "grain.facebook.download.AddressBook.Details") 138 | proto.RegisterType((*AddressBook_Contact)(nil), "grain.facebook.download.AddressBook.Contact") 139 | proto.RegisterType((*AddressBook_AddressBookEntry)(nil), "grain.facebook.download.AddressBook.AddressBookEntry") 140 | } 141 | 142 | func init() { proto.RegisterFile("facebook/download/about_you.proto", fileDescriptor0) } 143 | 144 | var fileDescriptor0 = []byte{ 145 | // 227 bytes of a gzipped FileDescriptorProto 146 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4c, 0x4b, 0x4c, 0x4e, 147 | 0x4d, 0xca, 0xcf, 0xcf, 0xd6, 0x4f, 0xc9, 0x2f, 0xcf, 0xcb, 0xc9, 0x4f, 0x4c, 0xd1, 0x4f, 0x4c, 148 | 0xca, 0x2f, 0x2d, 0x89, 0xaf, 0xcc, 0x2f, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x4f, 149 | 0x2f, 0x4a, 0xcc, 0xcc, 0xd3, 0x83, 0x29, 0xd4, 0x83, 0x29, 0x54, 0x7a, 0xcc, 0xc4, 0xc5, 0xed, 150 | 0x98, 0x92, 0x52, 0x94, 0x5a, 0x5c, 0xec, 0x94, 0x9f, 0x9f, 0x2d, 0x14, 0xc1, 0xc5, 0x93, 0x08, 151 | 0xe1, 0xc6, 0x83, 0x14, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x1b, 0x99, 0xea, 0xe1, 0xd0, 0xaf, 152 | 0x87, 0xa4, 0x17, 0x99, 0xed, 0x9a, 0x57, 0x52, 0x54, 0x19, 0xc4, 0x9d, 0x88, 0x10, 0x91, 0xd2, 153 | 0xe3, 0x62, 0x77, 0x49, 0x2d, 0x49, 0xcc, 0xcc, 0x29, 0x16, 0x52, 0xe6, 0xe2, 0x4d, 0xce, 0xcf, 154 | 0x2b, 0x49, 0x4c, 0x2e, 0x89, 0x2f, 0xc8, 0xcf, 0xcc, 0x2b, 0x01, 0xdb, 0xc2, 0x19, 0xc4, 0x03, 155 | 0x15, 0x0c, 0x00, 0x89, 0x49, 0xa5, 0x72, 0xb1, 0x3b, 0x43, 0xf8, 0x42, 0x42, 0x5c, 0x2c, 0x79, 156 | 0x89, 0xb9, 0xa9, 0x50, 0x65, 0x60, 0xb6, 0x90, 0x1b, 0x17, 0x7b, 0x0a, 0xc4, 0x38, 0x09, 0x26, 157 | 0x05, 0x66, 0x0d, 0x6e, 0x23, 0x1d, 0xa2, 0xdc, 0x08, 0x75, 0x42, 0x10, 0x4c, 0xb3, 0x54, 0x32, 158 | 0x97, 0x00, 0xba, 0xbb, 0x85, 0xfc, 0x31, 0x02, 0x81, 0x78, 0x0b, 0xa0, 0x6e, 0x46, 0xf1, 0x7b, 159 | 0x12, 0x1b, 0x38, 0x16, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x8e, 0x54, 0xa6, 0xff, 0xaa, 160 | 0x01, 0x00, 0x00, 161 | } 162 | -------------------------------------------------------------------------------- /gen/facebook/download/ads.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: facebook/download/ads.proto 3 | 4 | package grain_facebook_download 5 | 6 | import proto "github.com/golang/protobuf/proto" 7 | import fmt "fmt" 8 | import math "math" 9 | 10 | // Reference imports to suppress errors if they are not otherwise used. 11 | var _ = proto.Marshal 12 | var _ = fmt.Errorf 13 | var _ = math.Inf 14 | 15 | type Ads struct { 16 | Topics []string `protobuf:"bytes,1,rep,name=topics" json:"topics,omitempty"` 17 | CustomAudiences []string `protobuf:"bytes,2,rep,name=custom_audiences,json=customAudiences" json:"custom_audiences,omitempty"` 18 | LeadGenInfo []string `protobuf:"bytes,3,rep,name=lead_gen_info,json=leadGenInfo" json:"lead_gen_info,omitempty"` 19 | History []*Ads_History `protobuf:"bytes,4,rep,name=history" json:"history,omitempty"` 20 | } 21 | 22 | func (m *Ads) Reset() { *m = Ads{} } 23 | func (m *Ads) String() string { return proto.CompactTextString(m) } 24 | func (*Ads) ProtoMessage() {} 25 | func (*Ads) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } 26 | 27 | func (m *Ads) GetTopics() []string { 28 | if m != nil { 29 | return m.Topics 30 | } 31 | return nil 32 | } 33 | 34 | func (m *Ads) GetCustomAudiences() []string { 35 | if m != nil { 36 | return m.CustomAudiences 37 | } 38 | return nil 39 | } 40 | 41 | func (m *Ads) GetLeadGenInfo() []string { 42 | if m != nil { 43 | return m.LeadGenInfo 44 | } 45 | return nil 46 | } 47 | 48 | func (m *Ads) GetHistory() []*Ads_History { 49 | if m != nil { 50 | return m.History 51 | } 52 | return nil 53 | } 54 | 55 | type Ads_History struct { 56 | Title string `protobuf:"bytes,1,opt,name=title" json:"title,omitempty"` 57 | Action string `protobuf:"bytes,2,opt,name=action" json:"action,omitempty"` 58 | Timestamp int64 `protobuf:"varint,3,opt,name=timestamp" json:"timestamp,omitempty"` 59 | } 60 | 61 | func (m *Ads_History) Reset() { *m = Ads_History{} } 62 | func (m *Ads_History) String() string { return proto.CompactTextString(m) } 63 | func (*Ads_History) ProtoMessage() {} 64 | func (*Ads_History) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0, 0} } 65 | 66 | func (m *Ads_History) GetTitle() string { 67 | if m != nil { 68 | return m.Title 69 | } 70 | return "" 71 | } 72 | 73 | func (m *Ads_History) GetAction() string { 74 | if m != nil { 75 | return m.Action 76 | } 77 | return "" 78 | } 79 | 80 | func (m *Ads_History) GetTimestamp() int64 { 81 | if m != nil { 82 | return m.Timestamp 83 | } 84 | return 0 85 | } 86 | 87 | func init() { 88 | proto.RegisterType((*Ads)(nil), "grain.facebook.download.Ads") 89 | proto.RegisterType((*Ads_History)(nil), "grain.facebook.download.Ads.History") 90 | } 91 | 92 | func init() { proto.RegisterFile("facebook/download/ads.proto", fileDescriptor1) } 93 | 94 | var fileDescriptor1 = []byte{ 95 | // 239 bytes of a gzipped FileDescriptorProto 96 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x90, 0x4d, 0x4b, 0xc4, 0x30, 97 | 0x10, 0x40, 0x69, 0xa3, 0xbb, 0x74, 0x16, 0x51, 0x82, 0x68, 0x50, 0x0f, 0x65, 0xf1, 0x50, 0x2f, 98 | 0x59, 0xd0, 0xbb, 0xd0, 0x93, 0x7a, 0x2d, 0x78, 0x2e, 0xd9, 0x24, 0x5d, 0x83, 0x6d, 0xa6, 0x34, 99 | 0xb3, 0x88, 0x67, 0xff, 0xb8, 0xf4, 0x23, 0x78, 0xf2, 0xf8, 0x1e, 0x6f, 0x60, 0x66, 0xe0, 0xb6, 100 | 0x51, 0xda, 0xee, 0x11, 0x3f, 0x77, 0x06, 0xbf, 0x7c, 0x8b, 0xca, 0xec, 0x94, 0x09, 0xb2, 0x1f, 101 | 0x90, 0x90, 0x5f, 0x1f, 0x06, 0xe5, 0xbc, 0x8c, 0x89, 0x8c, 0xc9, 0xf6, 0x27, 0x05, 0x56, 0x9a, 102 | 0xc0, 0xaf, 0x60, 0x45, 0xd8, 0x3b, 0x1d, 0x44, 0x92, 0xb3, 0x22, 0xab, 0x16, 0xe2, 0x0f, 0x70, 103 | 0xa1, 0x8f, 0x81, 0xb0, 0xab, 0xd5, 0xd1, 0x38, 0xeb, 0xb5, 0x0d, 0x22, 0x9d, 0x8a, 0xf3, 0xd9, 104 | 0x97, 0x51, 0xf3, 0x2d, 0x9c, 0xb5, 0x56, 0x99, 0xfa, 0x60, 0x7d, 0xed, 0x7c, 0x83, 0x82, 0x4d, 105 | 0xdd, 0x66, 0x94, 0x2f, 0xd6, 0xbf, 0xf9, 0x06, 0xf9, 0x33, 0xac, 0x3f, 0x5c, 0x20, 0x1c, 0xbe, 106 | 0xc5, 0x49, 0xce, 0x8a, 0xcd, 0xe3, 0xbd, 0xfc, 0x67, 0x33, 0x59, 0x9a, 0x20, 0x5f, 0xe7, 0xb6, 107 | 0x8a, 0x43, 0x37, 0xef, 0xb0, 0x5e, 0x1c, 0xbf, 0x84, 0x53, 0x72, 0xd4, 0x5a, 0x91, 0xe4, 0x49, 108 | 0x91, 0x55, 0x33, 0x8c, 0x77, 0x28, 0x4d, 0x0e, 0xbd, 0x48, 0x27, 0xbd, 0x10, 0xbf, 0x83, 0x8c, 109 | 0x5c, 0x67, 0x03, 0xa9, 0xae, 0x17, 0x2c, 0x4f, 0x0a, 0x56, 0xfd, 0x89, 0xfd, 0x6a, 0xfa, 0xd2, 110 | 0xd3, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0xd5, 0x3f, 0xfb, 0x44, 0x01, 0x00, 0x00, 111 | } 112 | -------------------------------------------------------------------------------- /gen/facebook/download/following_and_followers.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: facebook/download/following_and_followers.proto 3 | 4 | package grain_facebook_download 5 | 6 | import proto "github.com/golang/protobuf/proto" 7 | import fmt "fmt" 8 | import math "math" 9 | 10 | // Reference imports to suppress errors if they are not otherwise used. 11 | var _ = proto.Marshal 12 | var _ = fmt.Errorf 13 | var _ = math.Inf 14 | 15 | // Stored as an array, not a top level message 16 | type FollowedPages struct { 17 | Pages []*FollowedPages_Page `protobuf:"bytes,1,rep,name=pages" json:"pages,omitempty"` 18 | } 19 | 20 | func (m *FollowedPages) Reset() { *m = FollowedPages{} } 21 | func (m *FollowedPages) String() string { return proto.CompactTextString(m) } 22 | func (*FollowedPages) ProtoMessage() {} 23 | func (*FollowedPages) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{0} } 24 | 25 | func (m *FollowedPages) GetPages() []*FollowedPages_Page { 26 | if m != nil { 27 | return m.Pages 28 | } 29 | return nil 30 | } 31 | 32 | type FollowedPages_Data struct { 33 | Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` 34 | } 35 | 36 | func (m *FollowedPages_Data) Reset() { *m = FollowedPages_Data{} } 37 | func (m *FollowedPages_Data) String() string { return proto.CompactTextString(m) } 38 | func (*FollowedPages_Data) ProtoMessage() {} 39 | func (*FollowedPages_Data) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{0, 0} } 40 | 41 | func (m *FollowedPages_Data) GetName() string { 42 | if m != nil { 43 | return m.Name 44 | } 45 | return "" 46 | } 47 | 48 | type FollowedPages_Page struct { 49 | Title string `protobuf:"bytes,1,opt,name=title" json:"title,omitempty"` 50 | Timestamp int64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` 51 | Data []*FollowedPages_Data `protobuf:"bytes,3,rep,name=data" json:"data,omitempty"` 52 | } 53 | 54 | func (m *FollowedPages_Page) Reset() { *m = FollowedPages_Page{} } 55 | func (m *FollowedPages_Page) String() string { return proto.CompactTextString(m) } 56 | func (*FollowedPages_Page) ProtoMessage() {} 57 | func (*FollowedPages_Page) Descriptor() ([]byte, []int) { return fileDescriptor5, []int{0, 1} } 58 | 59 | func (m *FollowedPages_Page) GetTitle() string { 60 | if m != nil { 61 | return m.Title 62 | } 63 | return "" 64 | } 65 | 66 | func (m *FollowedPages_Page) GetTimestamp() int64 { 67 | if m != nil { 68 | return m.Timestamp 69 | } 70 | return 0 71 | } 72 | 73 | func (m *FollowedPages_Page) GetData() []*FollowedPages_Data { 74 | if m != nil { 75 | return m.Data 76 | } 77 | return nil 78 | } 79 | 80 | func init() { 81 | proto.RegisterType((*FollowedPages)(nil), "grain.facebook.download.FollowedPages") 82 | proto.RegisterType((*FollowedPages_Data)(nil), "grain.facebook.download.FollowedPages.Data") 83 | proto.RegisterType((*FollowedPages_Page)(nil), "grain.facebook.download.FollowedPages.Page") 84 | } 85 | 86 | func init() { proto.RegisterFile("facebook/download/following_and_followers.proto", fileDescriptor5) } 87 | 88 | var fileDescriptor5 = []byte{ 89 | // 210 bytes of a gzipped FileDescriptorProto 90 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x4f, 0x4b, 0x4c, 0x4e, 91 | 0x4d, 0xca, 0xcf, 0xcf, 0xd6, 0x4f, 0xc9, 0x2f, 0xcf, 0xcb, 0xc9, 0x4f, 0x4c, 0xd1, 0x4f, 0xcb, 92 | 0xcf, 0xc9, 0xc9, 0x2f, 0xcf, 0xcc, 0x4b, 0x8f, 0x4f, 0xcc, 0x4b, 0x89, 0x87, 0xf0, 0x52, 0x8b, 93 | 0x8a, 0xf5, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0xc4, 0xd3, 0x8b, 0x12, 0x33, 0xf3, 0xf4, 0x60, 94 | 0xda, 0xf4, 0x60, 0xda, 0x94, 0x5e, 0x33, 0x72, 0xf1, 0xba, 0x41, 0x14, 0xa7, 0x04, 0x24, 0xa6, 95 | 0xa7, 0x16, 0x0b, 0x39, 0x72, 0xb1, 0x16, 0x80, 0x18, 0x12, 0x8c, 0x0a, 0xcc, 0x1a, 0xdc, 0x46, 96 | 0xda, 0x7a, 0x38, 0xb4, 0xea, 0xa1, 0x68, 0xd3, 0x03, 0x91, 0x41, 0x10, 0x9d, 0x52, 0x52, 0x5c, 97 | 0x2c, 0x2e, 0x89, 0x25, 0x89, 0x42, 0x42, 0x5c, 0x2c, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0x8c, 0x0a, 98 | 0x8c, 0x1a, 0x9c, 0x41, 0x60, 0xb6, 0x54, 0x35, 0x17, 0x0b, 0x48, 0xa9, 0x90, 0x08, 0x17, 0x6b, 99 | 0x49, 0x66, 0x49, 0x0e, 0x4c, 0x12, 0xc2, 0x11, 0x92, 0xe1, 0xe2, 0x2c, 0xc9, 0xcc, 0x4d, 0x2d, 100 | 0x2e, 0x49, 0xcc, 0x2d, 0x90, 0x60, 0x52, 0x60, 0xd4, 0x60, 0x0e, 0x42, 0x08, 0x08, 0xd9, 0x73, 101 | 0xb1, 0xa4, 0x24, 0x96, 0x24, 0x4a, 0x30, 0x93, 0xe4, 0x32, 0x90, 0x53, 0x82, 0xc0, 0x1a, 0x93, 102 | 0xd8, 0xc0, 0xa1, 0x61, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x22, 0x6e, 0xda, 0x17, 0x40, 0x01, 103 | 0x00, 0x00, 104 | } 105 | -------------------------------------------------------------------------------- /gen/facebook/download/friends.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: facebook/download/friends.proto 3 | 4 | package grain_facebook_download 5 | 6 | import proto "github.com/golang/protobuf/proto" 7 | import fmt "fmt" 8 | import math "math" 9 | 10 | // Reference imports to suppress errors if they are not otherwise used. 11 | var _ = proto.Marshal 12 | var _ = fmt.Errorf 13 | var _ = math.Inf 14 | 15 | type Friend struct { 16 | Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` 17 | Timestamp int64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"` 18 | } 19 | 20 | func (m *Friend) Reset() { *m = Friend{} } 21 | func (m *Friend) String() string { return proto.CompactTextString(m) } 22 | func (*Friend) ProtoMessage() {} 23 | func (*Friend) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{0} } 24 | 25 | func (m *Friend) GetName() string { 26 | if m != nil { 27 | return m.Name 28 | } 29 | return "" 30 | } 31 | 32 | func (m *Friend) GetTimestamp() int64 { 33 | if m != nil { 34 | return m.Timestamp 35 | } 36 | return 0 37 | } 38 | 39 | type FriendsAdded struct { 40 | Friends []*Friend `protobuf:"bytes,1,rep,name=friends" json:"friends,omitempty"` 41 | } 42 | 43 | func (m *FriendsAdded) Reset() { *m = FriendsAdded{} } 44 | func (m *FriendsAdded) String() string { return proto.CompactTextString(m) } 45 | func (*FriendsAdded) ProtoMessage() {} 46 | func (*FriendsAdded) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{1} } 47 | 48 | func (m *FriendsAdded) GetFriends() []*Friend { 49 | if m != nil { 50 | return m.Friends 51 | } 52 | return nil 53 | } 54 | 55 | type RejectedRequests struct { 56 | RejectedRequests []*Friend `protobuf:"bytes,1,rep,name=rejected_requests,json=rejectedRequests" json:"rejected_requests,omitempty"` 57 | } 58 | 59 | func (m *RejectedRequests) Reset() { *m = RejectedRequests{} } 60 | func (m *RejectedRequests) String() string { return proto.CompactTextString(m) } 61 | func (*RejectedRequests) ProtoMessage() {} 62 | func (*RejectedRequests) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{2} } 63 | 64 | func (m *RejectedRequests) GetRejectedRequests() []*Friend { 65 | if m != nil { 66 | return m.RejectedRequests 67 | } 68 | return nil 69 | } 70 | 71 | type RemovedFriends struct { 72 | DeletedFriends []*Friend `protobuf:"bytes,1,rep,name=deleted_friends,json=deletedFriends" json:"deleted_friends,omitempty"` 73 | } 74 | 75 | func (m *RemovedFriends) Reset() { *m = RemovedFriends{} } 76 | func (m *RemovedFriends) String() string { return proto.CompactTextString(m) } 77 | func (*RemovedFriends) ProtoMessage() {} 78 | func (*RemovedFriends) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{3} } 79 | 80 | func (m *RemovedFriends) GetDeletedFriends() []*Friend { 81 | if m != nil { 82 | return m.DeletedFriends 83 | } 84 | return nil 85 | } 86 | 87 | type SentRequests struct { 88 | SentRequests []*Friend `protobuf:"bytes,1,rep,name=sent_requests,json=sentRequests" json:"sent_requests,omitempty"` 89 | } 90 | 91 | func (m *SentRequests) Reset() { *m = SentRequests{} } 92 | func (m *SentRequests) String() string { return proto.CompactTextString(m) } 93 | func (*SentRequests) ProtoMessage() {} 94 | func (*SentRequests) Descriptor() ([]byte, []int) { return fileDescriptor6, []int{4} } 95 | 96 | func (m *SentRequests) GetSentRequests() []*Friend { 97 | if m != nil { 98 | return m.SentRequests 99 | } 100 | return nil 101 | } 102 | 103 | func init() { 104 | proto.RegisterType((*Friend)(nil), "grain.facebook.download.Friend") 105 | proto.RegisterType((*FriendsAdded)(nil), "grain.facebook.download.FriendsAdded") 106 | proto.RegisterType((*RejectedRequests)(nil), "grain.facebook.download.RejectedRequests") 107 | proto.RegisterType((*RemovedFriends)(nil), "grain.facebook.download.RemovedFriends") 108 | proto.RegisterType((*SentRequests)(nil), "grain.facebook.download.SentRequests") 109 | } 110 | 111 | func init() { proto.RegisterFile("facebook/download/friends.proto", fileDescriptor6) } 112 | 113 | var fileDescriptor6 = []byte{ 114 | // 244 bytes of a gzipped FileDescriptorProto 115 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x91, 0xb1, 0x4b, 0x03, 0x31, 116 | 0x18, 0xc5, 0x39, 0x2b, 0x95, 0x7e, 0x9e, 0xb5, 0x66, 0xf1, 0x06, 0xa1, 0x47, 0xa6, 0x9b, 0x52, 117 | 0xd0, 0x49, 0x37, 0x41, 0x44, 0xc1, 0x29, 0x3a, 0xb9, 0x68, 0xda, 0xef, 0x55, 0x4e, 0x7b, 0x49, 118 | 0x4d, 0xa2, 0xfe, 0xfb, 0xe2, 0x35, 0xa7, 0x22, 0x08, 0xed, 0x16, 0x1e, 0xef, 0xfd, 0xbe, 0x1f, 119 | 0x84, 0xc6, 0x73, 0x33, 0xc3, 0xd4, 0xb9, 0x97, 0x09, 0xbb, 0x0f, 0xbb, 0x70, 0x86, 0x27, 0x73, 120 | 0x5f, 0xc3, 0x72, 0x50, 0x4b, 0xef, 0xa2, 0x13, 0x87, 0x4f, 0xde, 0xd4, 0x56, 0x75, 0x35, 0xd5, 121 | 0xd5, 0xe4, 0x19, 0xf5, 0x2f, 0xdb, 0xa6, 0x10, 0xb4, 0x6d, 0x4d, 0x83, 0x22, 0x2b, 0xb3, 0x6a, 122 | 0xa0, 0xdb, 0xb7, 0x38, 0xa2, 0x41, 0xac, 0x1b, 0x84, 0x68, 0x9a, 0x65, 0xb1, 0x55, 0x66, 0x55, 123 | 0x4f, 0xff, 0x04, 0xf2, 0x9a, 0xf2, 0xd5, 0x36, 0x9c, 0x33, 0x83, 0xc5, 0x29, 0xed, 0xa4, 0xab, 124 | 0x45, 0x56, 0xf6, 0xaa, 0xdd, 0xe3, 0xb1, 0xfa, 0xe7, 0xac, 0x5a, 0xed, 0x74, 0xd7, 0x97, 0x8f, 125 | 0x34, 0xd2, 0x78, 0xc6, 0x2c, 0x82, 0x35, 0x5e, 0xdf, 0x10, 0x62, 0x10, 0x37, 0x74, 0xe0, 0x53, 126 | 0xf6, 0xe0, 0x53, 0xb8, 0x2e, 0x78, 0xe4, 0xff, 0xd0, 0xe4, 0x3d, 0x0d, 0x35, 0x1a, 0xf7, 0x0e, 127 | 0x4e, 0xce, 0xe2, 0x8a, 0xf6, 0x19, 0x0b, 0x7c, 0xe1, 0x37, 0xd4, 0x1e, 0xa6, 0x5d, 0x22, 0xc9, 128 | 0x3b, 0xca, 0x6f, 0x61, 0xe3, 0xb7, 0xf9, 0x05, 0xed, 0x05, 0xd8, 0xb8, 0xb1, 0x75, 0x1e, 0x7e, 129 | 0x51, 0xa6, 0xfd, 0xf6, 0xeb, 0x4e, 0x3e, 0x03, 0x00, 0x00, 0xff, 0xff, 0x67, 0x24, 0x75, 0xe3, 130 | 0xdd, 0x01, 0x00, 0x00, 131 | } 132 | -------------------------------------------------------------------------------- /gen/facebook/node.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: facebook/node.proto 3 | 4 | package facebookpb 5 | 6 | import proto "github.com/golang/protobuf/proto" 7 | import fmt "fmt" 8 | import math "math" 9 | 10 | // Reference imports to suppress errors if they are not otherwise used. 11 | var _ = proto.Marshal 12 | var _ = fmt.Errorf 13 | var _ = math.Inf 14 | 15 | type Node struct { 16 | Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` 17 | } 18 | 19 | func (m *Node) Reset() { *m = Node{} } 20 | func (m *Node) String() string { return proto.CompactTextString(m) } 21 | func (*Node) ProtoMessage() {} 22 | func (*Node) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } 23 | 24 | func (m *Node) GetId() string { 25 | if m != nil { 26 | return m.Id 27 | } 28 | return "" 29 | } 30 | 31 | func init() { 32 | proto.RegisterType((*Node)(nil), "grain.facebook.Node") 33 | } 34 | 35 | func init() { proto.RegisterFile("facebook/node.proto", fileDescriptor1) } 36 | 37 | var fileDescriptor1 = []byte{ 38 | // 92 bytes of a gzipped FileDescriptorProto 39 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4e, 0x4b, 0x4c, 0x4e, 40 | 0x4d, 0xca, 0xcf, 0xcf, 0xd6, 0xcf, 0xcb, 0x4f, 0x49, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 41 | 0xe2, 0x4b, 0x2f, 0x4a, 0xcc, 0xcc, 0xd3, 0x83, 0x49, 0x29, 0x89, 0x71, 0xb1, 0xf8, 0xe5, 0xa7, 42 | 0xa4, 0x0a, 0xf1, 0x71, 0x31, 0x65, 0xa6, 0x48, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x06, 0x31, 0x65, 43 | 0xa6, 0x38, 0xf1, 0x44, 0x71, 0xc1, 0xd4, 0x14, 0x24, 0x25, 0xb1, 0x81, 0x35, 0x1b, 0x03, 0x02, 44 | 0x00, 0x00, 0xff, 0xff, 0x12, 0x0e, 0xa2, 0xa1, 0x53, 0x00, 0x00, 0x00, 45 | } 46 | -------------------------------------------------------------------------------- /gen/facebook/user.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: facebook/user.proto 3 | 4 | package facebookpb 5 | 6 | import proto "github.com/golang/protobuf/proto" 7 | import fmt "fmt" 8 | import math "math" 9 | 10 | // Reference imports to suppress errors if they are not otherwise used. 11 | var _ = proto.Marshal 12 | var _ = fmt.Errorf 13 | var _ = math.Inf 14 | 15 | type User struct { 16 | Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` 17 | Birthday string `protobuf:"bytes,2,opt,name=birthday" json:"birthday,omitempty"` 18 | } 19 | 20 | func (m *User) Reset() { *m = User{} } 21 | func (m *User) String() string { return proto.CompactTextString(m) } 22 | func (*User) ProtoMessage() {} 23 | func (*User) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } 24 | 25 | func (m *User) GetId() string { 26 | if m != nil { 27 | return m.Id 28 | } 29 | return "" 30 | } 31 | 32 | func (m *User) GetBirthday() string { 33 | if m != nil { 34 | return m.Birthday 35 | } 36 | return "" 37 | } 38 | 39 | func init() { 40 | proto.RegisterType((*User)(nil), "grain.facebook.User") 41 | } 42 | 43 | func init() { proto.RegisterFile("facebook/user.proto", fileDescriptor3) } 44 | 45 | var fileDescriptor3 = []byte{ 46 | // 110 bytes of a gzipped FileDescriptorProto 47 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4e, 0x4b, 0x4c, 0x4e, 48 | 0x4d, 0xca, 0xcf, 0xcf, 0xd6, 0x2f, 0x2d, 0x4e, 0x2d, 0xd2, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 49 | 0xe2, 0x4b, 0x2f, 0x4a, 0xcc, 0xcc, 0xd3, 0x83, 0x49, 0x29, 0x19, 0x71, 0xb1, 0x84, 0x16, 0xa7, 50 | 0x16, 0x09, 0xf1, 0x71, 0x31, 0x65, 0xa6, 0x48, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x06, 0x31, 0x65, 51 | 0xa6, 0x08, 0x49, 0x71, 0x71, 0x24, 0x65, 0x16, 0x95, 0x64, 0xa4, 0x24, 0x56, 0x4a, 0x30, 0x81, 52 | 0x45, 0xe1, 0x7c, 0x27, 0x9e, 0x28, 0x2e, 0x98, 0xfe, 0x82, 0xa4, 0x24, 0x36, 0xb0, 0xc1, 0xc6, 53 | 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0x79, 0xa0, 0xaf, 0x69, 0x6f, 0x00, 0x00, 0x00, 54 | } 55 | -------------------------------------------------------------------------------- /gen/twitter/archive.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: twitter/archive.proto 3 | 4 | /* 5 | Package twitterpb is a generated protocol buffer package. 6 | 7 | It is generated from these files: 8 | twitter/archive.proto 9 | twitter/dm.proto 10 | twitter/entity.proto 11 | twitter/list.proto 12 | twitter/tweet.proto 13 | twitter/user.proto 14 | 15 | It has these top-level messages: 16 | Archive 17 | Target 18 | DirectMessageData 19 | DirectMessageCreate 20 | DirectMessageEvent 21 | Url 22 | Hashtag 23 | UserMention 24 | MediaSize 25 | MediaSizes 26 | Variant 27 | VideoInfo 28 | EntityMedia 29 | Entities 30 | List 31 | Place 32 | Coordinates 33 | ExtendedTweet 34 | Tweet 35 | User 36 | */ 37 | package twitterpb 38 | 39 | import proto "github.com/golang/protobuf/proto" 40 | import fmt "fmt" 41 | import math "math" 42 | 43 | // Reference imports to suppress errors if they are not otherwise used. 44 | var _ = proto.Marshal 45 | var _ = fmt.Errorf 46 | var _ = math.Inf 47 | 48 | // This is a compile-time assertion to ensure that this generated file 49 | // is compatible with the proto package it is being compiled against. 50 | // A compilation error at this line likely means your copy of the 51 | // proto package needs to be updated. 52 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 53 | 54 | type Archive struct { 55 | Lists []*List `protobuf:"bytes,1,rep,name=lists" json:"lists,omitempty"` 56 | Friends []*User `protobuf:"bytes,2,rep,name=friends" json:"friends,omitempty"` 57 | Followers []*User `protobuf:"bytes,3,rep,name=followers" json:"followers,omitempty"` 58 | Timeline []*Tweet `protobuf:"bytes,4,rep,name=timeline" json:"timeline,omitempty"` 59 | Favorites []*Tweet `protobuf:"bytes,5,rep,name=favorites" json:"favorites,omitempty"` 60 | DirectMessages []*DirectMessageEvent `protobuf:"bytes,6,rep,name=direct_messages,json=directMessages" json:"direct_messages,omitempty"` 61 | } 62 | 63 | func (m *Archive) Reset() { *m = Archive{} } 64 | func (m *Archive) String() string { return proto.CompactTextString(m) } 65 | func (*Archive) ProtoMessage() {} 66 | func (*Archive) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 67 | 68 | func (m *Archive) GetLists() []*List { 69 | if m != nil { 70 | return m.Lists 71 | } 72 | return nil 73 | } 74 | 75 | func (m *Archive) GetFriends() []*User { 76 | if m != nil { 77 | return m.Friends 78 | } 79 | return nil 80 | } 81 | 82 | func (m *Archive) GetFollowers() []*User { 83 | if m != nil { 84 | return m.Followers 85 | } 86 | return nil 87 | } 88 | 89 | func (m *Archive) GetTimeline() []*Tweet { 90 | if m != nil { 91 | return m.Timeline 92 | } 93 | return nil 94 | } 95 | 96 | func (m *Archive) GetFavorites() []*Tweet { 97 | if m != nil { 98 | return m.Favorites 99 | } 100 | return nil 101 | } 102 | 103 | func (m *Archive) GetDirectMessages() []*DirectMessageEvent { 104 | if m != nil { 105 | return m.DirectMessages 106 | } 107 | return nil 108 | } 109 | 110 | func init() { 111 | proto.RegisterType((*Archive)(nil), "grain.twitter.Archive") 112 | } 113 | 114 | func init() { proto.RegisterFile("twitter/archive.proto", fileDescriptor0) } 115 | 116 | var fileDescriptor0 = []byte{ 117 | // 258 bytes of a gzipped FileDescriptorProto 118 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0xd0, 0xcf, 0x4e, 0x83, 0x40, 119 | 0x10, 0xc7, 0xf1, 0xd8, 0xda, 0x56, 0xb6, 0xf1, 0x4f, 0xb6, 0x9a, 0x6c, 0x7a, 0x52, 0x4f, 0x7a, 120 | 0x10, 0xb5, 0x3e, 0x81, 0x46, 0x2f, 0x46, 0x2f, 0x44, 0x2f, 0x5e, 0x0c, 0x2d, 0x43, 0x9d, 0x04, 121 | 0xd8, 0x66, 0x66, 0x84, 0x57, 0xf4, 0xb1, 0x4c, 0x59, 0x56, 0x94, 0xa8, 0xd7, 0x1f, 0x9f, 0x2f, 122 | 0x13, 0x50, 0x07, 0x52, 0xa1, 0x08, 0xd0, 0x79, 0x4c, 0x8b, 0x37, 0x2c, 0x21, 0x5c, 0x91, 0x15, 123 | 0xab, 0xb7, 0x97, 0x14, 0x63, 0x11, 0x36, 0x0f, 0xa7, 0x7b, 0x5e, 0x25, 0xb9, 0x03, 0x53, 0xed, 124 | 0x97, 0x0c, 0x59, 0x9a, 0x6d, 0xe2, 0x37, 0xa9, 0x00, 0xa4, 0x0b, 0xdf, 0x19, 0xc8, 0x6d, 0xc7, 125 | 0x1f, 0x3d, 0x35, 0xba, 0x76, 0xf7, 0xf4, 0xa9, 0x1a, 0xac, 0x5f, 0xc1, 0x66, 0xe3, 0xb0, 0x7f, 126 | 0x32, 0x9e, 0x4d, 0xc2, 0x1f, 0x97, 0xc3, 0x07, 0x64, 0x89, 0x9c, 0xd0, 0x67, 0x6a, 0x94, 0x12, 127 | 0x42, 0x91, 0xb0, 0xe9, 0xfd, 0x8a, 0x9f, 0x19, 0x28, 0xf2, 0x46, 0x5f, 0xaa, 0x20, 0xb5, 0x59, 128 | 0x66, 0x2b, 0x20, 0x36, 0xfd, 0xbf, 0x83, 0x56, 0xe9, 0x0b, 0xb5, 0x25, 0x98, 0x43, 0x86, 0x05, 129 | 0x98, 0xcd, 0xba, 0xd8, 0xef, 0x14, 0x4f, 0xeb, 0x4f, 0x8b, 0xbe, 0x94, 0x9e, 0xa9, 0x20, 0x8d, 130 | 0x4b, 0x4b, 0x28, 0xc0, 0x66, 0xf0, 0x4f, 0xd2, 0x32, 0x7d, 0xaf, 0x76, 0x13, 0x24, 0x58, 0xc8, 131 | 0x6b, 0x0e, 0xcc, 0xf1, 0x12, 0xd8, 0x0c, 0xeb, 0xf2, 0xa8, 0x53, 0xde, 0xd6, 0xea, 0xd1, 0xa1, 132 | 0xbb, 0x12, 0x0a, 0x89, 0x76, 0x92, 0xef, 0x1b, 0xdf, 0x8c, 0x5f, 0x82, 0x46, 0xaf, 0xe6, 0xf3, 133 | 0x61, 0xfd, 0x7b, 0xaf, 0x3e, 0x03, 0x00, 0x00, 0xff, 0xff, 0x81, 0x31, 0xe5, 0x74, 0xd5, 0x01, 134 | 0x00, 0x00, 135 | } 136 | -------------------------------------------------------------------------------- /gen/twitter/dm.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: twitter/dm.proto 3 | 4 | package twitterpb 5 | 6 | import proto "github.com/golang/protobuf/proto" 7 | import fmt "fmt" 8 | import math "math" 9 | 10 | // Reference imports to suppress errors if they are not otherwise used. 11 | var _ = proto.Marshal 12 | var _ = fmt.Errorf 13 | var _ = math.Inf 14 | 15 | type Target struct { 16 | RecipientId string `protobuf:"bytes,1,opt,name=recipient_id,json=recipientId" json:"recipient_id,omitempty"` 17 | } 18 | 19 | func (m *Target) Reset() { *m = Target{} } 20 | func (m *Target) String() string { return proto.CompactTextString(m) } 21 | func (*Target) ProtoMessage() {} 22 | func (*Target) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{0} } 23 | 24 | func (m *Target) GetRecipientId() string { 25 | if m != nil { 26 | return m.RecipientId 27 | } 28 | return "" 29 | } 30 | 31 | type DirectMessageData struct { 32 | Text string `protobuf:"bytes,1,opt,name=text" json:"text,omitempty"` 33 | Entities *Entities `protobuf:"bytes,2,opt,name=entities" json:"entities,omitempty"` 34 | } 35 | 36 | func (m *DirectMessageData) Reset() { *m = DirectMessageData{} } 37 | func (m *DirectMessageData) String() string { return proto.CompactTextString(m) } 38 | func (*DirectMessageData) ProtoMessage() {} 39 | func (*DirectMessageData) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{1} } 40 | 41 | func (m *DirectMessageData) GetText() string { 42 | if m != nil { 43 | return m.Text 44 | } 45 | return "" 46 | } 47 | 48 | func (m *DirectMessageData) GetEntities() *Entities { 49 | if m != nil { 50 | return m.Entities 51 | } 52 | return nil 53 | } 54 | 55 | type DirectMessageCreate struct { 56 | Target *Target `protobuf:"bytes,1,opt,name=target" json:"target,omitempty"` 57 | SenderId string `protobuf:"bytes,2,opt,name=sender_id,json=senderId" json:"sender_id,omitempty"` 58 | SourceAppId string `protobuf:"bytes,3,opt,name=source_app_id,json=sourceAppId" json:"source_app_id,omitempty"` 59 | MessageData *DirectMessageData `protobuf:"bytes,4,opt,name=message_data,json=messageData" json:"message_data,omitempty"` 60 | } 61 | 62 | func (m *DirectMessageCreate) Reset() { *m = DirectMessageCreate{} } 63 | func (m *DirectMessageCreate) String() string { return proto.CompactTextString(m) } 64 | func (*DirectMessageCreate) ProtoMessage() {} 65 | func (*DirectMessageCreate) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{2} } 66 | 67 | func (m *DirectMessageCreate) GetTarget() *Target { 68 | if m != nil { 69 | return m.Target 70 | } 71 | return nil 72 | } 73 | 74 | func (m *DirectMessageCreate) GetSenderId() string { 75 | if m != nil { 76 | return m.SenderId 77 | } 78 | return "" 79 | } 80 | 81 | func (m *DirectMessageCreate) GetSourceAppId() string { 82 | if m != nil { 83 | return m.SourceAppId 84 | } 85 | return "" 86 | } 87 | 88 | func (m *DirectMessageCreate) GetMessageData() *DirectMessageData { 89 | if m != nil { 90 | return m.MessageData 91 | } 92 | return nil 93 | } 94 | 95 | type DirectMessageEvent struct { 96 | Type string `protobuf:"bytes,1,opt,name=type" json:"type,omitempty"` 97 | Id string `protobuf:"bytes,2,opt,name=id" json:"id,omitempty"` 98 | CreatedTimestamp string `protobuf:"bytes,3,opt,name=created_timestamp,json=createdTimestamp" json:"created_timestamp,omitempty"` 99 | MessageCreate *DirectMessageCreate `protobuf:"bytes,4,opt,name=message_create,json=messageCreate" json:"message_create,omitempty"` 100 | } 101 | 102 | func (m *DirectMessageEvent) Reset() { *m = DirectMessageEvent{} } 103 | func (m *DirectMessageEvent) String() string { return proto.CompactTextString(m) } 104 | func (*DirectMessageEvent) ProtoMessage() {} 105 | func (*DirectMessageEvent) Descriptor() ([]byte, []int) { return fileDescriptor1, []int{3} } 106 | 107 | func (m *DirectMessageEvent) GetType() string { 108 | if m != nil { 109 | return m.Type 110 | } 111 | return "" 112 | } 113 | 114 | func (m *DirectMessageEvent) GetId() string { 115 | if m != nil { 116 | return m.Id 117 | } 118 | return "" 119 | } 120 | 121 | func (m *DirectMessageEvent) GetCreatedTimestamp() string { 122 | if m != nil { 123 | return m.CreatedTimestamp 124 | } 125 | return "" 126 | } 127 | 128 | func (m *DirectMessageEvent) GetMessageCreate() *DirectMessageCreate { 129 | if m != nil { 130 | return m.MessageCreate 131 | } 132 | return nil 133 | } 134 | 135 | func init() { 136 | proto.RegisterType((*Target)(nil), "grain.twitter.Target") 137 | proto.RegisterType((*DirectMessageData)(nil), "grain.twitter.DirectMessageData") 138 | proto.RegisterType((*DirectMessageCreate)(nil), "grain.twitter.DirectMessageCreate") 139 | proto.RegisterType((*DirectMessageEvent)(nil), "grain.twitter.DirectMessageEvent") 140 | } 141 | 142 | func init() { proto.RegisterFile("twitter/dm.proto", fileDescriptor1) } 143 | 144 | var fileDescriptor1 = []byte{ 145 | // 335 bytes of a gzipped FileDescriptorProto 146 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0xcf, 0x6a, 0xc2, 0x40, 147 | 0x10, 0x87, 0x49, 0x2a, 0xa2, 0x13, 0x15, 0xdd, 0xb6, 0x54, 0xda, 0x8b, 0xcd, 0x49, 0x90, 0xa6, 148 | 0xa0, 0x4f, 0xd0, 0xaa, 0x87, 0x1c, 0x7a, 0x09, 0x9e, 0x4a, 0x21, 0xac, 0xd9, 0x41, 0xf6, 0x90, 149 | 0xb8, 0xec, 0x4e, 0xff, 0xf8, 0x56, 0x7d, 0x8e, 0x3e, 0x55, 0x71, 0x77, 0x4d, 0xab, 0x85, 0xde, 150 | 0xb2, 0xbf, 0xf9, 0x98, 0xf9, 0x66, 0x08, 0xf4, 0xe9, 0x5d, 0x12, 0xa1, 0xbe, 0x17, 0x65, 0xa2, 151 | 0xf4, 0x96, 0xb6, 0xac, 0xbb, 0xd1, 0x5c, 0x56, 0x89, 0xcf, 0xaf, 0x2f, 0x0e, 0x00, 0x56, 0x24, 152 | 0x69, 0xe7, 0xa0, 0x78, 0x02, 0xcd, 0x15, 0xd7, 0x1b, 0x24, 0x76, 0x0b, 0x1d, 0x8d, 0x85, 0x54, 153 | 0x12, 0x2b, 0xca, 0xa5, 0x18, 0x06, 0xa3, 0x60, 0xdc, 0xce, 0xa2, 0x3a, 0x4b, 0x45, 0xfc, 0x02, 154 | 0x83, 0x85, 0xd4, 0x58, 0xd0, 0x13, 0x1a, 0xc3, 0x37, 0xb8, 0xe0, 0xc4, 0x19, 0x83, 0x06, 0xe1, 155 | 0x07, 0x79, 0xde, 0x7e, 0xb3, 0x19, 0xb4, 0xec, 0x14, 0x89, 0x66, 0x18, 0x8e, 0x82, 0x71, 0x34, 156 | 0xbd, 0x4a, 0x8e, 0x6c, 0x92, 0xa5, 0x2f, 0x67, 0x35, 0x18, 0x7f, 0x05, 0x70, 0x7e, 0xd4, 0x7e, 157 | 0xae, 0x91, 0x13, 0xb2, 0x3b, 0x68, 0x92, 0x55, 0xb4, 0x23, 0xa2, 0xe9, 0xe5, 0x49, 0x2b, 0xe7, 158 | 0x9f, 0x79, 0x88, 0xdd, 0x40, 0xdb, 0x60, 0x25, 0x50, 0xef, 0x97, 0x08, 0xad, 0x54, 0xcb, 0x05, 159 | 0xa9, 0x60, 0x31, 0x74, 0xcd, 0xf6, 0x55, 0x17, 0x98, 0x73, 0xa5, 0xf6, 0xc0, 0x99, 0xdb, 0xd2, 160 | 0x85, 0x0f, 0x4a, 0xa5, 0x82, 0xcd, 0xa1, 0x53, 0x3a, 0x81, 0x5c, 0x70, 0xe2, 0xc3, 0x86, 0x9d, 161 | 0x3a, 0x3a, 0x99, 0xfa, 0xe7, 0x10, 0x59, 0x54, 0xfe, 0x3c, 0xe2, 0xcf, 0x00, 0xd8, 0x11, 0xb2, 162 | 0x7c, 0xc3, 0x8a, 0xec, 0xb1, 0x76, 0x0a, 0xeb, 0x63, 0xed, 0x14, 0xb2, 0x1e, 0x84, 0xb5, 0x69, 163 | 0x28, 0x05, 0x9b, 0xc0, 0xa0, 0xb0, 0x9b, 0x8b, 0x9c, 0x64, 0x89, 0x86, 0x78, 0xa9, 0xbc, 0x67, 164 | 0xdf, 0x17, 0x56, 0x87, 0x9c, 0xa5, 0xd0, 0x3b, 0xc8, 0xba, 0x9a, 0xd7, 0x8d, 0xff, 0xd3, 0x75, 165 | 0x87, 0xcd, 0xba, 0xe5, 0xef, 0xe7, 0x63, 0xf4, 0xdc, 0xf6, 0xb4, 0x5a, 0xaf, 0x9b, 0xf6, 0xf7, 166 | 0x98, 0x7d, 0x07, 0x00, 0x00, 0xff, 0xff, 0xab, 0xe9, 0x16, 0x97, 0x57, 0x02, 0x00, 0x00, 167 | } 168 | -------------------------------------------------------------------------------- /gen/twitter/list.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: twitter/list.proto 3 | 4 | package twitterpb 5 | 6 | import proto "github.com/golang/protobuf/proto" 7 | import fmt "fmt" 8 | import math "math" 9 | 10 | // Reference imports to suppress errors if they are not otherwise used. 11 | var _ = proto.Marshal 12 | var _ = fmt.Errorf 13 | var _ = math.Inf 14 | 15 | type List struct { 16 | Slug string `protobuf:"bytes,1,opt,name=slug" json:"slug,omitempty"` 17 | Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` 18 | Uri string `protobuf:"bytes,3,opt,name=uri" json:"uri,omitempty"` 19 | CreatedAt string `protobuf:"bytes,4,opt,name=created_at,json=createdAt" json:"created_at,omitempty"` 20 | Id int64 `protobuf:"varint,5,opt,name=id" json:"id,omitempty"` 21 | SubscriberCount int64 `protobuf:"varint,6,opt,name=subscriber_count,json=subscriberCount" json:"subscriber_count,omitempty"` 22 | MemberCount int64 `protobuf:"varint,7,opt,name=member_count,json=memberCount" json:"member_count,omitempty"` 23 | Mode string `protobuf:"bytes,8,opt,name=mode" json:"mode,omitempty"` 24 | FullName string `protobuf:"bytes,9,opt,name=full_name,json=fullName" json:"full_name,omitempty"` 25 | Description string `protobuf:"bytes,10,opt,name=description" json:"description,omitempty"` 26 | User *User `protobuf:"bytes,11,opt,name=user" json:"user,omitempty"` 27 | Following bool `protobuf:"varint,12,opt,name=following" json:"following,omitempty"` 28 | Members []*User `protobuf:"bytes,13,rep,name=members" json:"members,omitempty"` 29 | } 30 | 31 | func (m *List) Reset() { *m = List{} } 32 | func (m *List) String() string { return proto.CompactTextString(m) } 33 | func (*List) ProtoMessage() {} 34 | func (*List) Descriptor() ([]byte, []int) { return fileDescriptor3, []int{0} } 35 | 36 | func (m *List) GetSlug() string { 37 | if m != nil { 38 | return m.Slug 39 | } 40 | return "" 41 | } 42 | 43 | func (m *List) GetName() string { 44 | if m != nil { 45 | return m.Name 46 | } 47 | return "" 48 | } 49 | 50 | func (m *List) GetUri() string { 51 | if m != nil { 52 | return m.Uri 53 | } 54 | return "" 55 | } 56 | 57 | func (m *List) GetCreatedAt() string { 58 | if m != nil { 59 | return m.CreatedAt 60 | } 61 | return "" 62 | } 63 | 64 | func (m *List) GetId() int64 { 65 | if m != nil { 66 | return m.Id 67 | } 68 | return 0 69 | } 70 | 71 | func (m *List) GetSubscriberCount() int64 { 72 | if m != nil { 73 | return m.SubscriberCount 74 | } 75 | return 0 76 | } 77 | 78 | func (m *List) GetMemberCount() int64 { 79 | if m != nil { 80 | return m.MemberCount 81 | } 82 | return 0 83 | } 84 | 85 | func (m *List) GetMode() string { 86 | if m != nil { 87 | return m.Mode 88 | } 89 | return "" 90 | } 91 | 92 | func (m *List) GetFullName() string { 93 | if m != nil { 94 | return m.FullName 95 | } 96 | return "" 97 | } 98 | 99 | func (m *List) GetDescription() string { 100 | if m != nil { 101 | return m.Description 102 | } 103 | return "" 104 | } 105 | 106 | func (m *List) GetUser() *User { 107 | if m != nil { 108 | return m.User 109 | } 110 | return nil 111 | } 112 | 113 | func (m *List) GetFollowing() bool { 114 | if m != nil { 115 | return m.Following 116 | } 117 | return false 118 | } 119 | 120 | func (m *List) GetMembers() []*User { 121 | if m != nil { 122 | return m.Members 123 | } 124 | return nil 125 | } 126 | 127 | func init() { 128 | proto.RegisterType((*List)(nil), "grain.twitter.List") 129 | } 130 | 131 | func init() { proto.RegisterFile("twitter/list.proto", fileDescriptor3) } 132 | 133 | var fileDescriptor3 = []byte{ 134 | // 299 bytes of a gzipped FileDescriptorProto 135 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xbd, 0x4e, 0xc3, 0x30, 136 | 0x14, 0x85, 0x95, 0x26, 0xb4, 0xf5, 0x4d, 0x0b, 0xd5, 0x65, 0xb1, 0xf8, 0x91, 0x0c, 0x0b, 0x61, 137 | 0x20, 0x48, 0xf0, 0x04, 0xc0, 0x8a, 0x18, 0x22, 0xb1, 0xb0, 0x54, 0x49, 0xe3, 0x56, 0x96, 0x9c, 138 | 0xb8, 0xf2, 0x8f, 0xfa, 0x06, 0x3c, 0x37, 0xb2, 0x1d, 0x08, 0x0c, 0x6c, 0x47, 0xdf, 0xf9, 0x94, 139 | 0x1c, 0x5d, 0x03, 0xda, 0x83, 0xb0, 0x96, 0xeb, 0x7b, 0x29, 0x8c, 0x2d, 0xf7, 0x5a, 0x59, 0x85, 140 | 0xcb, 0x9d, 0xae, 0x45, 0x5f, 0x0e, 0xcd, 0xd9, 0x8f, 0xe2, 0x0c, 0xd7, 0x51, 0xb9, 0xfe, 0x4c, 141 | 0x21, 0x7b, 0x15, 0xc6, 0x22, 0x42, 0x66, 0xa4, 0xdb, 0xd1, 0x84, 0x25, 0x05, 0xa9, 0x42, 0xf6, 142 | 0xac, 0xaf, 0x3b, 0x4e, 0x27, 0x91, 0xf9, 0x8c, 0x2b, 0x48, 0x9d, 0x16, 0x34, 0x0d, 0xc8, 0x47, 143 | 0xbc, 0x04, 0xd8, 0x68, 0x5e, 0x5b, 0xde, 0xae, 0x6b, 0x4b, 0xb3, 0x50, 0x90, 0x81, 0x3c, 0x59, 144 | 0x3c, 0x86, 0x89, 0x68, 0xe9, 0x11, 0x4b, 0x8a, 0xb4, 0x9a, 0x88, 0x16, 0x6f, 0x61, 0x65, 0x5c, 145 | 0x63, 0x36, 0x5a, 0x34, 0x5c, 0xaf, 0x37, 0xca, 0xf5, 0x96, 0x4e, 0x43, 0x7b, 0x32, 0xf2, 0x17, 146 | 0x8f, 0xf1, 0x0a, 0x16, 0x1d, 0xef, 0x46, 0x6d, 0x16, 0xb4, 0x3c, 0xb2, 0xa8, 0x20, 0x64, 0x9d, 147 | 0x6a, 0x39, 0x9d, 0xc7, 0x89, 0x3e, 0xe3, 0x39, 0x90, 0xad, 0x93, 0x72, 0x1d, 0xb6, 0x93, 0x50, 148 | 0xcc, 0x3d, 0x78, 0xf3, 0xfb, 0x19, 0xe4, 0x2d, 0xf7, 0x7f, 0xd9, 0x5b, 0xa1, 0x7a, 0x0a, 0xa1, 149 | 0xfe, 0x8d, 0xf0, 0x06, 0x32, 0x7f, 0x20, 0x9a, 0xb3, 0xa4, 0xc8, 0x1f, 0x4e, 0xcb, 0x3f, 0x47, 150 | 0x2c, 0xdf, 0x0d, 0xd7, 0x55, 0x10, 0xf0, 0x02, 0xc8, 0x56, 0x49, 0xa9, 0x0e, 0xa2, 0xdf, 0xd1, 151 | 0x05, 0x4b, 0x8a, 0x79, 0x35, 0x02, 0xbc, 0x83, 0x59, 0x1c, 0x6a, 0xe8, 0x92, 0xa5, 0xff, 0x7d, 152 | 0xe9, 0xdb, 0x79, 0xce, 0x3f, 0xc8, 0x50, 0xec, 0x9b, 0x66, 0x1a, 0x1e, 0xe7, 0xf1, 0x2b, 0x00, 153 | 0x00, 0xff, 0xff, 0x98, 0x54, 0xe2, 0xff, 0xd5, 0x01, 0x00, 0x00, 154 | } 155 | -------------------------------------------------------------------------------- /proto/facebook/archive.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "facebook/photo.proto"; 4 | import "facebook/user.proto"; 5 | 6 | package grain.facebook; 7 | 8 | option go_package = "facebookpb"; 9 | 10 | message Archive { 11 | User me = 1; 12 | repeated Photo photos = 2; 13 | repeated Album albums = 3; 14 | repeated User friends = 4; 15 | } 16 | -------------------------------------------------------------------------------- /proto/facebook/download/about_you.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package grain.facebook.download; 4 | 5 | message AddressBook { 6 | message Details { 7 | string contact_point = 1; 8 | } 9 | message Contact { 10 | string name = 1; 11 | repeated Details details = 2; 12 | } 13 | message AddressBookEntry { 14 | repeated Contact address_book = 1; 15 | } 16 | AddressBookEntry address_book = 1; 17 | } 18 | -------------------------------------------------------------------------------- /proto/facebook/download/ads.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package grain.facebook.download; 4 | 5 | message Ads { 6 | message History { 7 | string title = 1; 8 | string action = 2; 9 | int64 timestamp = 3; // TODO: timestamp 10 | } 11 | repeated string topics = 1; 12 | repeated string custom_audiences = 2; 13 | repeated string lead_gen_info = 3; 14 | repeated History history = 4; 15 | } 16 | -------------------------------------------------------------------------------- /proto/facebook/download/apps.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package grain.facebook.download; 4 | 5 | message InstalledApps { 6 | message App { 7 | string name = 1; 8 | int64 time_added = 2; // TODO: timestamp 9 | } 10 | repeated App installed_apps = 1; 11 | } 12 | 13 | // Stored as an array, not a top level message 14 | message PostsFromApps { 15 | message ExternalContext { 16 | string name = 1; 17 | string url = 2; 18 | } 19 | message Data { 20 | ExternalContext external_context = 1; 21 | } 22 | message Attachment { 23 | repeated Data data = 1; 24 | } 25 | message Post { 26 | int64 timestamp = 1; // TODO: timestamp 27 | repeated Attachment attachments = 2; 28 | } 29 | repeated Post posts = 1; 30 | } 31 | 32 | message YourApps { 33 | message App { 34 | string name = 1; 35 | int64 time_added = 2; // TODO: timestamp 36 | } 37 | repeated App admined_apps = 1; 38 | } 39 | -------------------------------------------------------------------------------- /proto/facebook/download/comments.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package grain.facebook.download; 4 | 5 | message Comment { 6 | int64 timestamp = 1; // TODO: timestamp 7 | string comment = 2; 8 | string author = 3; 9 | string group = 4; 10 | } 11 | 12 | message PhotoMetadata { 13 | int64 iso_speed = 1; 14 | int64 orientation = 2; 15 | int64 original_width = 3; 16 | int64 original_height = 4; 17 | string upload_ip = 5; 18 | string camera_make = 6; 19 | string camera_model = 7; 20 | int64 taken_timestamp = 8; 21 | int64 modified_timestamp = 9; 22 | string exposure = 10; 23 | string focal_length = 11; 24 | string f_stop = 12; 25 | } 26 | 27 | message MediaMetadata { 28 | repeated PhotoMetadata photo_metadata = 1; 29 | } 30 | 31 | message Media { 32 | string uri = 1; 33 | string media_path = 2; 34 | int64 creation_timestamp = 3; 35 | MediaMetadata media_metadata = 4; 36 | repeated Comment comments = 5; 37 | } 38 | 39 | message AttachmentData { 40 | Media media = 1; 41 | } 42 | 43 | message Attachment { 44 | repeated AttachmentData data = 1; 45 | } 46 | 47 | message Post { 48 | message Data { 49 | string post = 1; 50 | Comment comment = 2; 51 | } 52 | int64 timestamp = 1; // TODO: timestamp 53 | string title = 2; 54 | repeated Data data = 3; 55 | repeated Attachment attachments = 4; 56 | } 57 | 58 | // Stored as an array, not a top level message 59 | message YourPosts { 60 | repeated Post posts = 1; 61 | } 62 | -------------------------------------------------------------------------------- /proto/facebook/download/events.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package grain.facebook.download; 4 | 5 | message Coordinate { 6 | float longitude = 1; 7 | float latitude = 2; 8 | } 9 | 10 | message Event { 11 | message Place { 12 | string name = 1; 13 | Coordinate coordinate = 2; 14 | string address = 3; 15 | } 16 | string name = 1; 17 | int64 start_timestamp = 2; // TODO: timestamp 18 | int64 end_timestamp = 3; // TODO: timestamp 19 | string description = 4; 20 | } 21 | 22 | message EventInvitations { 23 | repeated Event events_invited = 1; 24 | } 25 | 26 | message EventResponses { 27 | message Joined { 28 | repeated Event events_joined = 1; 29 | } 30 | Joined event_responses = 1; 31 | } 32 | 33 | message YourEvents { 34 | repeated Event your_events = 1; 35 | } 36 | -------------------------------------------------------------------------------- /proto/facebook/download/following_and_followers.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package grain.facebook.download; 4 | 5 | // Stored as an array, not a top level message 6 | message FollowedPages { 7 | message Data { 8 | string name = 1; 9 | } 10 | message Page { 11 | string title = 1; 12 | int64 timestamp = 2; // TODO: timestamp 13 | repeated Data data = 3; 14 | } 15 | repeated Page pages = 1; 16 | } 17 | -------------------------------------------------------------------------------- /proto/facebook/download/friends.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package grain.facebook.download; 4 | 5 | message Friend { 6 | string name = 1; 7 | int64 timestamp = 2; // TODO: timestamp 8 | } 9 | 10 | message FriendsAdded { 11 | repeated Friend friends = 1; 12 | } 13 | 14 | message RejectedRequests { 15 | repeated Friend rejected_requests = 1; 16 | } 17 | 18 | message RemovedFriends { 19 | repeated Friend deleted_friends = 1; 20 | } 21 | 22 | message SentRequests { 23 | repeated Friend sent_requests = 1; 24 | } 25 | -------------------------------------------------------------------------------- /proto/facebook/download/groups.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "facebook/download/comments.proto"; 4 | 5 | package grain.facebook.download; 6 | 7 | message GroupsYouManage { 8 | message Group { 9 | repeated string groups = 1; 10 | } 11 | Group groups_you_manage = 1; 12 | } 13 | 14 | // Stored as a top-level array 15 | message GroupMembershipActivity { 16 | message Data { 17 | string name = 1; 18 | } 19 | message Attachment { 20 | repeated Data data = 1; 21 | } 22 | message Group { 23 | int64 timestamp = 1; // TODO: timestamp 24 | string title = 2; 25 | repeated Attachment attachments = 3; 26 | } 27 | repeated Group membership_activity = 1; 28 | } 29 | 30 | // Stored as a top-level array 31 | message GroupPostsComments { 32 | repeated Post comments = 1; 33 | } 34 | -------------------------------------------------------------------------------- /proto/facebook/node.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package grain.facebook; 4 | 5 | option go_package = "facebookpb"; 6 | 7 | message Node { 8 | string id = 1; 9 | } 10 | -------------------------------------------------------------------------------- /proto/facebook/photo.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package grain.facebook; 4 | 5 | option go_package = "facebookpb"; 6 | 7 | message Owner { 8 | string name = 1; 9 | string id = 2; 10 | } 11 | 12 | message Location { 13 | string city = 1; 14 | string country = 2; 15 | float latitude = 3; 16 | float longitude = 4; 17 | } 18 | 19 | message Place { 20 | string id = 1; 21 | // The name of the Page 22 | string name = 2; 23 | // The location of this place. Applicable to all Places 24 | Location location = 3; 25 | } 26 | 27 | message Album { 28 | string id = 1; 29 | // A user-specified time for when this object was created 30 | string backdated_time = 2; 31 | // How accurate the backdated time is 32 | string backdated_time_granularity = 3; 33 | // Whether the viewer can backdate this album 34 | bool can_backdate = 4; 35 | // Whether the viewer can upload photos to this album 36 | bool can_upload = 5; 37 | // The approximate number of photos in the album. This is not necessarily an exact count 38 | uint32 count = 6; 39 | uint32 photo_count = 18; 40 | // Album cover photo id 41 | Photo cover_photo = 7; 42 | // The time the album was initially created 43 | string created_time = 8; 44 | // The description of the album 45 | string description = 9; 46 | // The URL for editing this album 47 | string edit_link = 10; 48 | // If this object has a place, the event associated with the place 49 | // string event = 11; 50 | // The profile that created the album 51 | Owner from = 12; 52 | // Determines whether or not the album should be shown to users 53 | bool is_user_facing = 13; 54 | // A link to this album on Facebook 55 | string link = 14; 56 | // The textual location of the album" 57 | string location = 15; 58 | // Time of the last major update (e.g. addition of photos) expressed as UNIX time 59 | string modified_major = 16; 60 | // The title of the album 61 | string name = 17; 62 | // The place associated with this album 63 | Place place = 19; 64 | // The privacy settings for the album 65 | string privacy = 20; 66 | // The type of the album: profile, mobile, wall, normal or album 67 | string type = 21; 68 | // The last time the album was updated 69 | string updated_time = 22; 70 | // The approximate number of videos in the album. This is not necessarily an exact count 71 | uint32 video_count = 23; 72 | } 73 | 74 | message Image { 75 | int32 height = 1; 76 | int32 width = 2; 77 | string source = 3; 78 | } 79 | 80 | message Photo { 81 | string id = 1; 82 | Album album = 2; 83 | // A user-specified time for when this object was created 84 | string backdated_time = 3; 85 | // How accurate the backdated time is 86 | string backdated_time_granularity = 4; 87 | bool can_backdate = 5; 88 | bool can_delete = 6; 89 | bool can_tag = 7; 90 | string created_time = 8; 91 | Owner from = 10; 92 | int32 height = 11; 93 | int32 width = 12; 94 | string icon = 13; 95 | repeated Image images = 14; 96 | string name = 15; 97 | // "link", 98 | // "name_tags", 99 | // "page_story_id", 100 | // "picture", 101 | // "place", 102 | // "target", 103 | // "updated_time", 104 | // "webp_images", 105 | 106 | } 107 | -------------------------------------------------------------------------------- /proto/facebook/user.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package grain.facebook; 4 | 5 | option go_package = "facebookpb"; 6 | 7 | message User { 8 | string id = 1; 9 | string birthday = 2; 10 | } 11 | -------------------------------------------------------------------------------- /proto/prototool.yaml: -------------------------------------------------------------------------------- 1 | # The Protobuf version to use from https://github.com/google/protobuf/releases. 2 | # By default use 3.5.1. 3 | # You probably want to set this to make your builds completely reproducible. 4 | protoc_version: 3.5.1 5 | gen: 6 | go_options: 7 | import_path: github.com/kyleconroy/grain/gen 8 | plugins: 9 | - name: go 10 | output: ../gen 11 | -------------------------------------------------------------------------------- /proto/twitter/archive.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "twitter/dm.proto"; 4 | import "twitter/list.proto"; 5 | import "twitter/tweet.proto"; 6 | import "twitter/user.proto"; 7 | 8 | package grain.twitter; 9 | 10 | option go_package = "twitterpb"; 11 | 12 | message Archive { 13 | repeated List lists = 1; 14 | repeated User friends = 2; 15 | repeated User followers = 3; 16 | repeated Tweet timeline = 4; 17 | repeated Tweet favorites = 5; 18 | repeated DirectMessageEvent direct_messages = 6; 19 | } 20 | -------------------------------------------------------------------------------- /proto/twitter/dm.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "twitter/entity.proto"; 4 | 5 | package grain.twitter; 6 | 7 | option go_package = "twitterpb"; 8 | 9 | message Target { 10 | string recipient_id = 1; 11 | } 12 | 13 | message DirectMessageData { 14 | string text = 1; 15 | Entities entities = 2; 16 | } 17 | 18 | message DirectMessageCreate { 19 | Target target = 1; 20 | string sender_id = 2; 21 | string source_app_id = 3; 22 | DirectMessageData message_data = 4; 23 | } 24 | 25 | message DirectMessageEvent { 26 | string type = 1; 27 | string id = 2; 28 | string created_timestamp = 3; 29 | DirectMessageCreate message_create = 4; 30 | } 31 | -------------------------------------------------------------------------------- /proto/twitter/entity.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package grain.twitter; 4 | 5 | option go_package = "twitterpb"; 6 | 7 | message Url { 8 | repeated int64 indices = 1; 9 | string url = 2; 10 | string display_url = 3; 11 | string expanded_url = 4; 12 | } 13 | 14 | message Hashtag { 15 | repeated int64 indices = 1; 16 | string text = 2; 17 | } 18 | 19 | message UserMention { 20 | reserved "id_str"; 21 | repeated int64 indices = 1; 22 | string name = 2; 23 | string screen_name = 3; 24 | int64 id = 4; 25 | } 26 | 27 | message MediaSize { 28 | int32 w = 1; 29 | int32 h = 2; 30 | string resize = 3; 31 | } 32 | 33 | message MediaSizes { 34 | MediaSize medium = 1; 35 | MediaSize thumb = 2; 36 | MediaSize small = 3; 37 | MediaSize large = 4; 38 | } 39 | 40 | message Variant { 41 | int32 bitrate = 1; 42 | string content_type = 2; 43 | string url = 3; 44 | } 45 | 46 | message VideoInfo { 47 | repeated int32 aspect_ratio = 1; 48 | int64 duration_millis = 2; 49 | repeated Variant variants = 3; 50 | } 51 | 52 | message EntityMedia { 53 | reserved "id_str", "source_status_id_str"; 54 | int64 id = 1; 55 | string media_url = 2; 56 | string media_url_https = 3; 57 | string url = 4; 58 | string display_url = 5; 59 | string expanded_url = 6; 60 | MediaSizes sizes = 7; 61 | int64 source_status_id = 8; 62 | string type = 9; 63 | repeated int64 indices = 10; 64 | VideoInfo video_info = 11; 65 | string ext_alt_text = 12; 66 | } 67 | 68 | message Entities { 69 | repeated Url urls = 1; 70 | repeated Hashtag hashtags = 2; 71 | Url url = 3; 72 | repeated UserMention user_mentions = 4; 73 | repeated EntityMedia media = 5; 74 | } 75 | -------------------------------------------------------------------------------- /proto/twitter/list.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "twitter/user.proto"; 4 | 5 | package grain.twitter; 6 | 7 | option go_package = "twitterpb"; 8 | 9 | message List { 10 | string slug = 1; 11 | string name = 2; 12 | string uri = 3; 13 | string created_at = 4; 14 | int64 id = 5; 15 | int64 subscriber_count = 6; 16 | int64 member_count = 7; 17 | string mode = 8; 18 | string full_name = 9; 19 | string description = 10; 20 | User user = 11; 21 | bool following = 12; 22 | repeated User members = 13; 23 | } 24 | -------------------------------------------------------------------------------- /proto/twitter/tweet.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "twitter/entity.proto"; 4 | import "twitter/user.proto"; 5 | 6 | package grain.twitter; 7 | 8 | option go_package = "twitterpb"; 9 | 10 | message Place {} 11 | 12 | message Coordinates {} 13 | 14 | message ExtendedTweet {} 15 | 16 | message Tweet { 17 | reserved "id_str", "in_reply_to_status_id_str", "in_reply_to_user_id_str", "quoted_status_id_str"; 18 | repeated int64 contributors = 1; 19 | Coordinates coordinates = 2; 20 | string created_at = 3; 21 | repeated int32 display_text_range = 4; 22 | Entities entities = 5; 23 | Entities extended_entities = 6; 24 | ExtendedTweet extended_tweet = 7; 25 | int32 favorite_count = 8; 26 | bool favorited = 9; 27 | string filter_level = 10; 28 | string full_text = 11; 29 | bool has_extended_profile = 12; 30 | int64 id = 13; 31 | string in_reply_to_screen_name = 14; 32 | int64 in_reply_to_status_id = 15; 33 | int64 in_reply_to_user_id = 16; 34 | string lang = 17; 35 | bool is_translation_enabled = 18; 36 | Place place = 19; 37 | int64 quoted_status_id = 20; 38 | Tweet quoted_status = 21; 39 | bool possibly_sensitive = 22; 40 | bool possibly_sensitive_appealable = 23; 41 | int32 retweet_count = 24; 42 | bool retweeted = 25; 43 | Tweet retweeted_status = 26; 44 | string source = 27; 45 | // map[string]interface{} scopes = 28; 46 | string text = 29; 47 | User user = 30; 48 | bool withheld_copyright = 31; 49 | repeated string withheld_in_countries = 32; 50 | string withheld_scope = 33; 51 | } 52 | -------------------------------------------------------------------------------- /proto/twitter/user.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "twitter/entity.proto"; 4 | 5 | package grain.twitter; 6 | 7 | option go_package = "twitterpb"; 8 | 9 | message User { 10 | reserved "id_str"; 11 | bool contributors_enabled = 1; 12 | string created_at = 2; 13 | bool default_profile = 3; 14 | bool default_profile_image = 4; 15 | string description = 5; 16 | string email = 6; 17 | Entities entities = 7; 18 | int64 favourites_count = 8; 19 | bool follow_request_sent = 9; 20 | int64 followers_count = 10; 21 | bool following = 11; 22 | int64 friends_count = 12; 23 | bool geo_enabled = 13; 24 | bool has_extended_profile = 14; 25 | int64 id = 15; 26 | bool is_translator = 17; 27 | bool is_translation_enabled = 18; 28 | string lang = 19; // BCP-47 code of user defined language 29 | int64 listed_count = 20; 30 | string location = 21; // User defined location 31 | string name = 22; 32 | bool notifications = 23; 33 | string profile_background_color = 24; 34 | string profile_background_image_url = 25; 35 | string profile_background_image_url_https = 26; 36 | bool profile_background_tile = 27; 37 | string profile_banner_url = 28; 38 | string profile_image_url = 29; 39 | string profile_image_url_https = 30; 40 | string profile_link_color = 31; 41 | string profile_sidebar_border_color = 32; 42 | string profile_sidebar_fill_color = 33; 43 | string profile_text_color = 34; 44 | bool profile_use_background_image = 35; 45 | bool protected = 37; 46 | string screen_name = 38; 47 | bool show_all_inline_media = 39; 48 | // Tweet status = 40; // Only included if the user is a friend 49 | int64 statuses_count = 41; 50 | string time_zone = 42; 51 | string url = 43; 52 | int64 utc_offset = 44; 53 | bool verified = 45; 54 | repeated string withheld_in_countries = 46; 55 | string withheld_scope = 47; 56 | } 57 | -------------------------------------------------------------------------------- /twitter/csv.go: -------------------------------------------------------------------------------- 1 | package twitter 2 | 3 | import ( 4 | "encoding/csv" 5 | "io" 6 | "strconv" 7 | "strings" 8 | "time" 9 | ) 10 | 11 | type CSVTweet struct { 12 | TweetID int64 13 | InReplyToStatusID int64 14 | InReplyToUserID int64 15 | Timestamp time.Time 16 | Source string 17 | Text string 18 | RetweetedStatusID int64 19 | RetweetedStatusUserID int64 20 | RetweetedStatusTimestamp time.Time 21 | ExpandedURLs []string 22 | } 23 | 24 | type Reader struct { 25 | r *csv.Reader 26 | skipped bool 27 | } 28 | 29 | func parseInt(i string) (int64, error) { 30 | if i == "" { 31 | return 0, nil 32 | } 33 | return strconv.ParseInt(i, 10, 64) 34 | } 35 | 36 | func NewCSVReader(in io.Reader) *Reader { 37 | return &Reader{r: csv.NewReader(in)} 38 | } 39 | 40 | func (c *Reader) Read() (r CSVTweet, err error) { 41 | record, err := c.r.Read() 42 | if !c.skipped { 43 | record, err = c.r.Read() 44 | c.skipped = true 45 | } 46 | 47 | if err != nil { 48 | return CSVTweet{}, err 49 | } 50 | 51 | r.TweetID, err = parseInt(record[0]) 52 | if err != nil { 53 | return 54 | } 55 | 56 | r.InReplyToStatusID, err = parseInt(record[1]) 57 | if err != nil { 58 | return 59 | } 60 | 61 | r.InReplyToUserID, err = parseInt(record[2]) 62 | if err != nil { 63 | return 64 | } 65 | 66 | if record[3] != "" { 67 | r.Timestamp, err = time.Parse("2006-01-02 15:04:05 -0700", record[3]) 68 | if err != nil { 69 | return 70 | } 71 | } 72 | 73 | r.RetweetedStatusID, err = parseInt(record[6]) 74 | if err != nil { 75 | return 76 | } 77 | 78 | r.RetweetedStatusUserID, err = parseInt(record[7]) 79 | if err != nil { 80 | return 81 | } 82 | 83 | if record[8] != "" { 84 | r.RetweetedStatusTimestamp, err = time.Parse("2006-01-02 15:04:05 -0700", record[8]) 85 | if err != nil { 86 | return 87 | } 88 | } 89 | 90 | r.Source = record[4] 91 | r.Text = record[5] 92 | r.ExpandedURLs = strings.Split(record[0], ",") 93 | 94 | return 95 | } 96 | -------------------------------------------------------------------------------- /twitter/errors.go: -------------------------------------------------------------------------------- 1 | package twitter 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "net/url" 9 | "strconv" 10 | "time" 11 | ) 12 | 13 | const ( 14 | //Error code defintions match the Twitter documentation 15 | //https://developer.twitter.com/en/docs/basics/response-codes 16 | TwitterErrorCouldNotAuthenticate = 32 17 | TwitterErrorDoesNotExist = 34 18 | TwitterErrorAccountSuspended = 64 19 | TwitterErrorApi1Deprecation = 68 //This should never be needed 20 | TwitterErrorRateLimitExceeded = 88 21 | TwitterErrorInvalidToken = 89 22 | TwitterErrorOverCapacity = 130 23 | TwitterErrorInternalError = 131 24 | TwitterErrorCouldNotAuthenticateYou = 135 25 | TwitterErrorStatusIsADuplicate = 187 26 | TwitterErrorBadAuthenticationData = 215 27 | TwitterErrorUserMustVerifyLogin = 231 28 | 29 | // Undocumented by Twitter, but may be returned instead of 34 30 | TwitterErrorDoesNotExist2 = 144 31 | ) 32 | 33 | type ApiError struct { 34 | StatusCode int 35 | Header http.Header 36 | Body string 37 | Decoded TwitterErrorResponse 38 | URL *url.URL 39 | } 40 | 41 | func newApiError(resp *http.Response) *ApiError { 42 | // TODO don't ignore this error 43 | // TODO don't use ReadAll 44 | p, _ := ioutil.ReadAll(resp.Body) 45 | 46 | var twitterErrorResp TwitterErrorResponse 47 | _ = json.Unmarshal(p, &twitterErrorResp) 48 | return &ApiError{ 49 | StatusCode: resp.StatusCode, 50 | Header: resp.Header, 51 | Body: string(p), 52 | Decoded: twitterErrorResp, 53 | URL: resp.Request.URL, 54 | } 55 | } 56 | 57 | // ApiError supports the error interface 58 | func (aerr ApiError) Error() string { 59 | return fmt.Sprintf("Get %s returned status %d, %s", aerr.URL, aerr.StatusCode, aerr.Body) 60 | } 61 | 62 | // Check to see if an error is a Rate Limiting error. If so, find the next available window in the header. 63 | // Use like so: 64 | // 65 | // if aerr, ok := err.(*ApiError); ok { 66 | // if isRateLimitError, nextWindow := aerr.RateLimitCheck(); isRateLimitError { 67 | // <-time.After(nextWindow.Sub(time.Now())) 68 | // } 69 | // } 70 | // 71 | func (aerr *ApiError) RateLimitCheck() (isRateLimitError bool, nextWindow time.Time) { 72 | // TODO check for error code 130, which also signifies a rate limit 73 | if aerr.StatusCode == 429 { 74 | if reset := aerr.Header.Get("X-Rate-Limit-Reset"); reset != "" { 75 | if resetUnix, err := strconv.ParseInt(reset, 10, 64); err == nil { 76 | resetTime := time.Unix(resetUnix, 0) 77 | // Reject any time greater than an hour away 78 | if resetTime.Sub(time.Now()) > time.Hour { 79 | return true, time.Now().Add(15 * time.Minute) 80 | } 81 | 82 | return true, resetTime 83 | } 84 | } 85 | } 86 | 87 | return false, time.Time{} 88 | } 89 | 90 | //TwitterErrorResponse has an array of Twitter error messages 91 | //It satisfies the "error" interface 92 | //For the most part, Twitter seems to return only a single error message 93 | //Currently, we assume that this always contains exactly one error message 94 | type TwitterErrorResponse struct { 95 | Errors []TwitterError `json:"errors"` 96 | } 97 | 98 | func (tr TwitterErrorResponse) First() error { 99 | return tr.Errors[0] 100 | } 101 | 102 | func (tr TwitterErrorResponse) Error() string { 103 | return tr.Errors[0].Message 104 | } 105 | 106 | //TwitterError represents a single Twitter error messages/code pair 107 | type TwitterError struct { 108 | Message string `json:"message"` 109 | Code int `json:"code"` 110 | } 111 | 112 | func (te TwitterError) Error() string { 113 | return te.Message 114 | } 115 | -------------------------------------------------------------------------------- /vendor/github.com/ChimeraCoder/tokenbucket/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | *.swn 4 | conf.sh 5 | -------------------------------------------------------------------------------- /vendor/github.com/ChimeraCoder/tokenbucket/COPYING: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /vendor/github.com/ChimeraCoder/tokenbucket/LICENSE: -------------------------------------------------------------------------------- 1 | COPYING -------------------------------------------------------------------------------- /vendor/github.com/ChimeraCoder/tokenbucket/README: -------------------------------------------------------------------------------- 1 | [![GoDoc](http://godoc.org/github.com/ChimeraCoder/tokenbucket?status.png)](http://godoc.org/github.com/ChimeraCoder/tokenbucket) 2 | 3 | tokenbucket 4 | ==================== 5 | 6 | This package provides an implementation of [Token bucket](https://en.wikipedia.org/wiki/Token_bucket) scheduling in Go. It is useful for implementing rate-limiting, traffic shaping, or other sorts of scheduling that depend on bandwidth constraints. 7 | 8 | 9 | Example 10 | ------------ 11 | 12 | 13 | To create a new bucket, specify a capacity (how many tokens can be stored "in the bank"), and a rate (how often a new token is added). 14 | 15 | ````go 16 | 17 | // Create a new bucket 18 | // Allow a new action every 5 seconds, with a maximum of 3 "in the bank" 19 | bucket := tokenbucket.NewBucket(3, 5 * time.Second) 20 | ```` 21 | 22 | This bucket should be shared between any functions that share the same constraints. (These functions may or may not run in separate goroutines). 23 | 24 | 25 | Anytime a regulated action is performed, spend a token. 26 | 27 | ````go 28 | // To perform a regulated action, we must spend a token 29 | // RegulatedAction will not be performed until the bucket contains enough tokens 30 | <-bucket.SpendToken(1) 31 | RegulatedAction() 32 | ```` 33 | 34 | `SpendToken` returns immediately. Reading from the channel that it returns will block until the action has "permission" to continue (ie, until there are enough tokens in the bucket). 35 | 36 | 37 | (The channel that `SpendToken` returns is of type `error`. For now, the value will always be `nil`, so it can be ignored.) 38 | 39 | 40 | 41 | ####License 42 | 43 | `tokenbucket` is free software provided under version 3 of the LGPL license. 44 | 45 | 46 | Software that uses `tokenbucket` may be released under *any* license, as long as the source code for `tokenbucket` (including any modifications) are made available under the LGPLv3 license. 47 | 48 | You do not need to release the rest of the software under the LGPL, or any free/open-source license, for that matter (though we would encourage you to do so!). 49 | -------------------------------------------------------------------------------- /vendor/github.com/ChimeraCoder/tokenbucket/README.md: -------------------------------------------------------------------------------- 1 | README -------------------------------------------------------------------------------- /vendor/github.com/ChimeraCoder/tokenbucket/tokenbucket.go: -------------------------------------------------------------------------------- 1 | package tokenbucket 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | type Bucket struct { 9 | capacity int64 10 | tokens chan struct{} 11 | rate time.Duration // Add a token to the bucket every 1/r units of time 12 | rateMutex sync.Mutex 13 | } 14 | 15 | func NewBucket(rate time.Duration, capacity int64) *Bucket { 16 | 17 | //A bucket is simply a channel with a buffer representing the maximum size 18 | tokens := make(chan struct{}, capacity) 19 | 20 | b := &Bucket{capacity, tokens, rate, sync.Mutex{}} 21 | 22 | //Set off a function that will continuously add tokens to the bucket 23 | go func(b *Bucket) { 24 | ticker := time.NewTicker(rate) 25 | for _ = range ticker.C { 26 | b.tokens <- struct{}{} 27 | } 28 | }(b) 29 | 30 | return b 31 | } 32 | 33 | func (b *Bucket) GetRate() time.Duration { 34 | b.rateMutex.Lock() 35 | tmp := b.rate 36 | b.rateMutex.Unlock() 37 | return tmp 38 | } 39 | 40 | func (b *Bucket) SetRate(rate time.Duration) { 41 | b.rateMutex.Lock() 42 | b.rate = rate 43 | b.rateMutex.Unlock() 44 | } 45 | 46 | //AddTokens manually adds n tokens to the bucket 47 | func (b *Bucket) AddToken(n int64) { 48 | } 49 | 50 | func (b *Bucket) withdrawTokens(n int64) error { 51 | for i := int64(0); i < n; i++ { 52 | <-b.tokens 53 | } 54 | return nil 55 | } 56 | 57 | func (b *Bucket) SpendToken(n int64) <-chan error { 58 | // Default to spending a single token 59 | if n < 0 { 60 | n = 1 61 | } 62 | 63 | c := make(chan error) 64 | go func(b *Bucket, n int64, c chan error) { 65 | c <- b.withdrawTokens(n) 66 | close(c) 67 | return 68 | }(b, n, c) 69 | 70 | return c 71 | } 72 | 73 | // Drain will empty all tokens in the bucket 74 | // If the tokens are being added too quickly (if the rate is too fast) 75 | // this will never drain 76 | func (b *Bucket) Drain() error{ 77 | // TODO replace this with a more solid approach (such as replacing the channel altogether) 78 | for { 79 | select { 80 | case _ = <-b.tokens: 81 | continue 82 | default: 83 | return nil 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /vendor/github.com/garyburd/go-oauth/oauth/oauth16.go: -------------------------------------------------------------------------------- 1 | // +build !go1.7 2 | 3 | package oauth 4 | 5 | import ( 6 | "net/http" 7 | 8 | "golang.org/x/net/context" 9 | ) 10 | 11 | func requestWithContext(ctx context.Context, req *http.Request) *http.Request { 12 | return req 13 | } 14 | -------------------------------------------------------------------------------- /vendor/github.com/garyburd/go-oauth/oauth/oauth17.go: -------------------------------------------------------------------------------- 1 | // +build go1.7 2 | 3 | package oauth 4 | 5 | import ( 6 | "context" 7 | "net/http" 8 | ) 9 | 10 | func requestWithContext(ctx context.Context, req *http.Request) *http.Request { 11 | return req.WithContext(ctx) 12 | } 13 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at http://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at http://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/LICENSE: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/proto/encode.go: -------------------------------------------------------------------------------- 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 | package proto 33 | 34 | /* 35 | * Routines for encoding data into the wire format for protocol buffers. 36 | */ 37 | 38 | import ( 39 | "errors" 40 | "fmt" 41 | "reflect" 42 | ) 43 | 44 | // RequiredNotSetError is the error returned if Marshal is called with 45 | // a protocol buffer struct whose required fields have not 46 | // all been initialized. It is also the error returned if Unmarshal is 47 | // called with an encoded protocol buffer that does not include all the 48 | // required fields. 49 | // 50 | // When printed, RequiredNotSetError reports the first unset required field in a 51 | // message. If the field cannot be precisely determined, it is reported as 52 | // "{Unknown}". 53 | type RequiredNotSetError struct { 54 | field string 55 | } 56 | 57 | func (e *RequiredNotSetError) Error() string { 58 | return fmt.Sprintf("proto: required field %q not set", e.field) 59 | } 60 | 61 | var ( 62 | // errRepeatedHasNil is the error returned if Marshal is called with 63 | // a struct with a repeated field containing a nil element. 64 | errRepeatedHasNil = errors.New("proto: repeated field has nil element") 65 | 66 | // errOneofHasNil is the error returned if Marshal is called with 67 | // a struct with a oneof field containing a nil element. 68 | errOneofHasNil = errors.New("proto: oneof field has nil value") 69 | 70 | // ErrNil is the error returned if Marshal is called with nil. 71 | ErrNil = errors.New("proto: Marshal called with nil") 72 | 73 | // ErrTooLarge is the error returned if Marshal is called with a 74 | // message that encodes to >2GB. 75 | ErrTooLarge = errors.New("proto: message encodes to over 2 GB") 76 | ) 77 | 78 | // The fundamental encoders that put bytes on the wire. 79 | // Those that take integer types all accept uint64 and are 80 | // therefore of type valueEncoder. 81 | 82 | const maxVarintBytes = 10 // maximum length of a varint 83 | 84 | // EncodeVarint returns the varint encoding of x. 85 | // This is the format for the 86 | // int32, int64, uint32, uint64, bool, and enum 87 | // protocol buffer types. 88 | // Not used by the package itself, but helpful to clients 89 | // wishing to use the same encoding. 90 | func EncodeVarint(x uint64) []byte { 91 | var buf [maxVarintBytes]byte 92 | var n int 93 | for n = 0; x > 127; n++ { 94 | buf[n] = 0x80 | uint8(x&0x7F) 95 | x >>= 7 96 | } 97 | buf[n] = uint8(x) 98 | n++ 99 | return buf[0:n] 100 | } 101 | 102 | // EncodeVarint writes a varint-encoded integer to the Buffer. 103 | // This is the format for the 104 | // int32, int64, uint32, uint64, bool, and enum 105 | // protocol buffer types. 106 | func (p *Buffer) EncodeVarint(x uint64) error { 107 | for x >= 1<<7 { 108 | p.buf = append(p.buf, uint8(x&0x7f|0x80)) 109 | x >>= 7 110 | } 111 | p.buf = append(p.buf, uint8(x)) 112 | return nil 113 | } 114 | 115 | // SizeVarint returns the varint encoding size of an integer. 116 | func SizeVarint(x uint64) int { 117 | switch { 118 | case x < 1<<7: 119 | return 1 120 | case x < 1<<14: 121 | return 2 122 | case x < 1<<21: 123 | return 3 124 | case x < 1<<28: 125 | return 4 126 | case x < 1<<35: 127 | return 5 128 | case x < 1<<42: 129 | return 6 130 | case x < 1<<49: 131 | return 7 132 | case x < 1<<56: 133 | return 8 134 | case x < 1<<63: 135 | return 9 136 | } 137 | return 10 138 | } 139 | 140 | // EncodeFixed64 writes a 64-bit integer to the Buffer. 141 | // This is the format for the 142 | // fixed64, sfixed64, and double protocol buffer types. 143 | func (p *Buffer) EncodeFixed64(x uint64) error { 144 | p.buf = append(p.buf, 145 | uint8(x), 146 | uint8(x>>8), 147 | uint8(x>>16), 148 | uint8(x>>24), 149 | uint8(x>>32), 150 | uint8(x>>40), 151 | uint8(x>>48), 152 | uint8(x>>56)) 153 | return nil 154 | } 155 | 156 | // EncodeFixed32 writes a 32-bit integer to the Buffer. 157 | // This is the format for the 158 | // fixed32, sfixed32, and float protocol buffer types. 159 | func (p *Buffer) EncodeFixed32(x uint64) error { 160 | p.buf = append(p.buf, 161 | uint8(x), 162 | uint8(x>>8), 163 | uint8(x>>16), 164 | uint8(x>>24)) 165 | return nil 166 | } 167 | 168 | // EncodeZigzag64 writes a zigzag-encoded 64-bit integer 169 | // to the Buffer. 170 | // This is the format used for the sint64 protocol buffer type. 171 | func (p *Buffer) EncodeZigzag64(x uint64) error { 172 | // use signed number to get arithmetic right shift. 173 | return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63)))) 174 | } 175 | 176 | // EncodeZigzag32 writes a zigzag-encoded 32-bit integer 177 | // to the Buffer. 178 | // This is the format used for the sint32 protocol buffer type. 179 | func (p *Buffer) EncodeZigzag32(x uint64) error { 180 | // use signed number to get arithmetic right shift. 181 | return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31)))) 182 | } 183 | 184 | // EncodeRawBytes writes a count-delimited byte buffer to the Buffer. 185 | // This is the format used for the bytes protocol buffer 186 | // type and for embedded messages. 187 | func (p *Buffer) EncodeRawBytes(b []byte) error { 188 | p.EncodeVarint(uint64(len(b))) 189 | p.buf = append(p.buf, b...) 190 | return nil 191 | } 192 | 193 | // EncodeStringBytes writes an encoded string to the Buffer. 194 | // This is the format used for the proto2 string type. 195 | func (p *Buffer) EncodeStringBytes(s string) error { 196 | p.EncodeVarint(uint64(len(s))) 197 | p.buf = append(p.buf, s...) 198 | return nil 199 | } 200 | 201 | // Marshaler is the interface representing objects that can marshal themselves. 202 | type Marshaler interface { 203 | Marshal() ([]byte, error) 204 | } 205 | 206 | // EncodeMessage writes the protocol buffer to the Buffer, 207 | // prefixed by a varint-encoded length. 208 | func (p *Buffer) EncodeMessage(pb Message) error { 209 | siz := Size(pb) 210 | p.EncodeVarint(uint64(siz)) 211 | return p.Marshal(pb) 212 | } 213 | 214 | // All protocol buffer fields are nillable, but be careful. 215 | func isNil(v reflect.Value) bool { 216 | switch v.Kind() { 217 | case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: 218 | return v.IsNil() 219 | } 220 | return false 221 | } 222 | -------------------------------------------------------------------------------- /vendor/github.com/golang/protobuf/ptypes/struct/struct.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option cc_enable_arenas = true; 37 | option go_package = "github.com/golang/protobuf/ptypes/struct;structpb"; 38 | option java_package = "com.google.protobuf"; 39 | option java_outer_classname = "StructProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | 43 | 44 | // `Struct` represents a structured data value, consisting of fields 45 | // which map to dynamically typed values. In some languages, `Struct` 46 | // might be supported by a native representation. For example, in 47 | // scripting languages like JS a struct is represented as an 48 | // object. The details of that representation are described together 49 | // with the proto support for the language. 50 | // 51 | // The JSON representation for `Struct` is JSON object. 52 | message Struct { 53 | // Unordered map of dynamically typed values. 54 | map fields = 1; 55 | } 56 | 57 | // `Value` represents a dynamically typed value which can be either 58 | // null, a number, a string, a boolean, a recursive struct value, or a 59 | // list of values. A producer of value is expected to set one of that 60 | // variants, absence of any variant indicates an error. 61 | // 62 | // The JSON representation for `Value` is JSON value. 63 | message Value { 64 | // The kind of value. 65 | oneof kind { 66 | // Represents a null value. 67 | NullValue null_value = 1; 68 | // Represents a double value. 69 | double number_value = 2; 70 | // Represents a string value. 71 | string string_value = 3; 72 | // Represents a boolean value. 73 | bool bool_value = 4; 74 | // Represents a structured value. 75 | Struct struct_value = 5; 76 | // Represents a repeated `Value`. 77 | ListValue list_value = 6; 78 | } 79 | } 80 | 81 | // `NullValue` is a singleton enumeration to represent the null value for the 82 | // `Value` type union. 83 | // 84 | // The JSON representation for `NullValue` is JSON `null`. 85 | enum NullValue { 86 | // Null value. 87 | NULL_VALUE = 0; 88 | } 89 | 90 | // `ListValue` is a wrapper around a repeated field of values. 91 | // 92 | // The JSON representation for `ListValue` is JSON array. 93 | message ListValue { 94 | // Repeated field of dynamically typed values. 95 | repeated Value values = 1; 96 | } 97 | -------------------------------------------------------------------------------- /vendor/github.com/google/btree/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | -------------------------------------------------------------------------------- /vendor/github.com/google/btree/README.md: -------------------------------------------------------------------------------- 1 | # BTree implementation for Go 2 | 3 | ![Travis CI Build Status](https://api.travis-ci.org/google/btree.svg?branch=master) 4 | 5 | This package provides an in-memory B-Tree implementation for Go, useful as 6 | an ordered, mutable data structure. 7 | 8 | The API is based off of the wonderful 9 | http://godoc.org/github.com/petar/GoLLRB/llrb, and is meant to allow btree to 10 | act as a drop-in replacement for gollrb trees. 11 | 12 | See http://godoc.org/github.com/google/btree for documentation. 13 | -------------------------------------------------------------------------------- /vendor/github.com/google/btree/btree_mem.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // +build ignore 16 | 17 | // This binary compares memory usage between btree and gollrb. 18 | package main 19 | 20 | import ( 21 | "flag" 22 | "fmt" 23 | "math/rand" 24 | "runtime" 25 | "time" 26 | 27 | "github.com/google/btree" 28 | "github.com/petar/GoLLRB/llrb" 29 | ) 30 | 31 | var ( 32 | size = flag.Int("size", 1000000, "size of the tree to build") 33 | degree = flag.Int("degree", 8, "degree of btree") 34 | gollrb = flag.Bool("llrb", false, "use llrb instead of btree") 35 | ) 36 | 37 | func main() { 38 | flag.Parse() 39 | vals := rand.Perm(*size) 40 | var t, v interface{} 41 | v = vals 42 | var stats runtime.MemStats 43 | for i := 0; i < 10; i++ { 44 | runtime.GC() 45 | } 46 | fmt.Println("-------- BEFORE ----------") 47 | runtime.ReadMemStats(&stats) 48 | fmt.Printf("%+v\n", stats) 49 | start := time.Now() 50 | if *gollrb { 51 | tr := llrb.New() 52 | for _, v := range vals { 53 | tr.ReplaceOrInsert(llrb.Int(v)) 54 | } 55 | t = tr // keep it around 56 | } else { 57 | tr := btree.New(*degree) 58 | for _, v := range vals { 59 | tr.ReplaceOrInsert(btree.Int(v)) 60 | } 61 | t = tr // keep it around 62 | } 63 | fmt.Printf("%v inserts in %v\n", *size, time.Since(start)) 64 | fmt.Println("-------- AFTER ----------") 65 | runtime.ReadMemStats(&stats) 66 | fmt.Printf("%+v\n", stats) 67 | for i := 0; i < 10; i++ { 68 | runtime.GC() 69 | } 70 | fmt.Println("-------- AFTER GC ----------") 71 | runtime.ReadMemStats(&stats) 72 | fmt.Printf("%+v\n", stats) 73 | if t == v { 74 | fmt.Println("to make sure vals and tree aren't GC'd") 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /vendor/github.com/gregjones/httpcache/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: go 3 | go: 4 | - 1.6.x 5 | - 1.7.x 6 | - 1.8.x 7 | - 1.9.x 8 | - master 9 | matrix: 10 | allow_failures: 11 | - go: master 12 | fast_finish: true 13 | install: 14 | - # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step). 15 | script: 16 | - go get -t -v ./... 17 | - diff -u <(echo -n) <(gofmt -d .) 18 | - go tool vet . 19 | - go test -v -race ./... 20 | -------------------------------------------------------------------------------- /vendor/github.com/gregjones/httpcache/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright © 2012 Greg Jones (greg.jones@gmail.com) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /vendor/github.com/gregjones/httpcache/README.md: -------------------------------------------------------------------------------- 1 | httpcache 2 | ========= 3 | 4 | [![Build Status](https://travis-ci.org/gregjones/httpcache.svg?branch=master)](https://travis-ci.org/gregjones/httpcache) [![GoDoc](https://godoc.org/github.com/gregjones/httpcache?status.svg)](https://godoc.org/github.com/gregjones/httpcache) 5 | 6 | Package httpcache provides a http.RoundTripper implementation that works as a mostly [RFC 7234](https://tools.ietf.org/html/rfc7234) compliant cache for http responses. 7 | 8 | It is only suitable for use as a 'private' cache (i.e. for a web-browser or an API-client and not for a shared proxy). 9 | 10 | Cache Backends 11 | -------------- 12 | 13 | - The built-in 'memory' cache stores responses in an in-memory map. 14 | - [`github.com/gregjones/httpcache/diskcache`](https://github.com/gregjones/httpcache/tree/master/diskcache) provides a filesystem-backed cache using the [diskv](https://github.com/peterbourgon/diskv) library. 15 | - [`github.com/gregjones/httpcache/memcache`](https://github.com/gregjones/httpcache/tree/master/memcache) provides memcache implementations, for both App Engine and 'normal' memcache servers. 16 | - [`sourcegraph.com/sourcegraph/s3cache`](https://sourcegraph.com/github.com/sourcegraph/s3cache) uses Amazon S3 for storage. 17 | - [`github.com/gregjones/httpcache/leveldbcache`](https://github.com/gregjones/httpcache/tree/master/leveldbcache) provides a filesystem-backed cache using [leveldb](https://github.com/syndtr/goleveldb/leveldb). 18 | - [`github.com/die-net/lrucache`](https://github.com/die-net/lrucache) provides an in-memory cache that will evict least-recently used entries. 19 | - [`github.com/die-net/lrucache/twotier`](https://github.com/die-net/lrucache/tree/master/twotier) allows caches to be combined, for example to use lrucache above with a persistent disk-cache. 20 | - [`github.com/birkelund/boltdbcache`](https://github.com/birkelund/boltdbcache) provides a BoltDB implementation (based on the [bbolt](https://github.com/coreos/bbolt) fork). 21 | 22 | License 23 | ------- 24 | 25 | - [MIT License](LICENSE.txt) 26 | -------------------------------------------------------------------------------- /vendor/github.com/gregjones/httpcache/diskcache/diskcache.go: -------------------------------------------------------------------------------- 1 | // Package diskcache provides an implementation of httpcache.Cache that uses the diskv package 2 | // to supplement an in-memory map with persistent storage 3 | // 4 | package diskcache 5 | 6 | import ( 7 | "bytes" 8 | "crypto/md5" 9 | "encoding/hex" 10 | "github.com/peterbourgon/diskv" 11 | "io" 12 | ) 13 | 14 | // Cache is an implementation of httpcache.Cache that supplements the in-memory map with persistent storage 15 | type Cache struct { 16 | d *diskv.Diskv 17 | } 18 | 19 | // Get returns the response corresponding to key if present 20 | func (c *Cache) Get(key string) (resp []byte, ok bool) { 21 | key = keyToFilename(key) 22 | resp, err := c.d.Read(key) 23 | if err != nil { 24 | return []byte{}, false 25 | } 26 | return resp, true 27 | } 28 | 29 | // Set saves a response to the cache as key 30 | func (c *Cache) Set(key string, resp []byte) { 31 | key = keyToFilename(key) 32 | c.d.WriteStream(key, bytes.NewReader(resp), true) 33 | } 34 | 35 | // Delete removes the response with key from the cache 36 | func (c *Cache) Delete(key string) { 37 | key = keyToFilename(key) 38 | c.d.Erase(key) 39 | } 40 | 41 | func keyToFilename(key string) string { 42 | h := md5.New() 43 | io.WriteString(h, key) 44 | return hex.EncodeToString(h.Sum(nil)) 45 | } 46 | 47 | // New returns a new Cache that will store files in basePath 48 | func New(basePath string) *Cache { 49 | return &Cache{ 50 | d: diskv.New(diskv.Options{ 51 | BasePath: basePath, 52 | CacheSizeMax: 100 * 1024 * 1024, // 100MB 53 | }), 54 | } 55 | } 56 | 57 | // NewWithDiskv returns a new Cache using the provided Diskv as underlying 58 | // storage. 59 | func NewWithDiskv(d *diskv.Diskv) *Cache { 60 | return &Cache{d} 61 | } 62 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/.gitignore: -------------------------------------------------------------------------------- 1 | test_program/test_program_bin 2 | fuzz/ 3 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: go 3 | go: 4 | - 1.8.5 5 | - 1.9.2 6 | - tip 7 | matrix: 8 | allow_failures: 9 | - go: tip 10 | fast_finish: true 11 | script: 12 | - if [ -n "$(go fmt ./...)" ]; then exit 1; fi 13 | - ./test.sh 14 | - ./benchmark.sh $TRAVIS_BRANCH https://github.com/$TRAVIS_REPO_SLUG.git 15 | before_install: 16 | - go get github.com/axw/gocov/gocov 17 | - go get github.com/mattn/goveralls 18 | - if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi 19 | branches: 20 | only: [master] 21 | after_success: 22 | - $HOME/gopath/bin/goveralls -service=travis-ci -coverprofile=coverage.out -repotoken $COVERALLS_TOKEN 23 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 - 2017 Thomas Pelletier, Eric Anderton 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/README.md: -------------------------------------------------------------------------------- 1 | # go-toml 2 | 3 | Go library for the [TOML](https://github.com/mojombo/toml) format. 4 | 5 | This library supports TOML version 6 | [v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md) 7 | 8 | [![GoDoc](https://godoc.org/github.com/pelletier/go-toml?status.svg)](http://godoc.org/github.com/pelletier/go-toml) 9 | [![license](https://img.shields.io/github/license/pelletier/go-toml.svg)](https://github.com/pelletier/go-toml/blob/master/LICENSE) 10 | [![Build Status](https://travis-ci.org/pelletier/go-toml.svg?branch=master)](https://travis-ci.org/pelletier/go-toml) 11 | [![Coverage Status](https://coveralls.io/repos/github/pelletier/go-toml/badge.svg?branch=master)](https://coveralls.io/github/pelletier/go-toml?branch=master) 12 | [![Go Report Card](https://goreportcard.com/badge/github.com/pelletier/go-toml)](https://goreportcard.com/report/github.com/pelletier/go-toml) 13 | 14 | ## Features 15 | 16 | Go-toml provides the following features for using data parsed from TOML documents: 17 | 18 | * Load TOML documents from files and string data 19 | * Easily navigate TOML structure using Tree 20 | * Mashaling and unmarshaling to and from data structures 21 | * Line & column position data for all parsed elements 22 | * [Query support similar to JSON-Path](query/) 23 | * Syntax errors contain line and column numbers 24 | 25 | ## Import 26 | 27 | ```go 28 | import "github.com/pelletier/go-toml" 29 | ``` 30 | 31 | ## Usage example 32 | 33 | Read a TOML document: 34 | 35 | ```go 36 | config, _ := toml.Load(` 37 | [postgres] 38 | user = "pelletier" 39 | password = "mypassword"`) 40 | // retrieve data directly 41 | user := config.Get("postgres.user").(string) 42 | 43 | // or using an intermediate object 44 | postgresConfig := config.Get("postgres").(*toml.Tree) 45 | password := postgresConfig.Get("password").(string) 46 | ``` 47 | 48 | Or use Unmarshal: 49 | 50 | ```go 51 | type Postgres struct { 52 | User string 53 | Password string 54 | } 55 | type Config struct { 56 | Postgres Postgres 57 | } 58 | 59 | doc := []byte(` 60 | [Postgres] 61 | User = "pelletier" 62 | Password = "mypassword"`) 63 | 64 | config := Config{} 65 | toml.Unmarshal(doc, &config) 66 | fmt.Println("user=", config.Postgres.User) 67 | ``` 68 | 69 | Or use a query: 70 | 71 | ```go 72 | // use a query to gather elements without walking the tree 73 | q, _ := query.Compile("$..[user,password]") 74 | results := q.Execute(config) 75 | for ii, item := range results.Values() { 76 | fmt.Println("Query result %d: %v", ii, item) 77 | } 78 | ``` 79 | 80 | ## Documentation 81 | 82 | The documentation and additional examples are available at 83 | [godoc.org](http://godoc.org/github.com/pelletier/go-toml). 84 | 85 | ## Tools 86 | 87 | Go-toml provides two handy command line tools: 88 | 89 | * `tomll`: Reads TOML files and lint them. 90 | 91 | ``` 92 | go install github.com/pelletier/go-toml/cmd/tomll 93 | tomll --help 94 | ``` 95 | * `tomljson`: Reads a TOML file and outputs its JSON representation. 96 | 97 | ``` 98 | go install github.com/pelletier/go-toml/cmd/tomljson 99 | tomljson --help 100 | ``` 101 | 102 | ## Contribute 103 | 104 | Feel free to report bugs and patches using GitHub's pull requests system on 105 | [pelletier/go-toml](https://github.com/pelletier/go-toml). Any feedback would be 106 | much appreciated! 107 | 108 | ### Run tests 109 | 110 | You have to make sure two kind of tests run: 111 | 112 | 1. The Go unit tests 113 | 2. The TOML examples base 114 | 115 | You can run both of them using `./test.sh`. 116 | 117 | ### Fuzzing 118 | 119 | The script `./fuzz.sh` is available to 120 | run [go-fuzz](https://github.com/dvyukov/go-fuzz) on go-toml. 121 | 122 | ## Versioning 123 | 124 | Go-toml follows [Semantic Versioning](http://semver.org/). The supported version 125 | of [TOML](https://github.com/toml-lang/toml) is indicated at the beginning of 126 | this document. The last two major versions of Go are supported 127 | (see [Go Release Policy](https://golang.org/doc/devel/release.html#policy)). 128 | 129 | ## License 130 | 131 | The MIT License (MIT). Read [LICENSE](LICENSE). 132 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/benchmark.json: -------------------------------------------------------------------------------- 1 | { 2 | "array": { 3 | "key1": [ 4 | 1, 5 | 2, 6 | 3 7 | ], 8 | "key2": [ 9 | "red", 10 | "yellow", 11 | "green" 12 | ], 13 | "key3": [ 14 | [ 15 | 1, 16 | 2 17 | ], 18 | [ 19 | 3, 20 | 4, 21 | 5 22 | ] 23 | ], 24 | "key4": [ 25 | [ 26 | 1, 27 | 2 28 | ], 29 | [ 30 | "a", 31 | "b", 32 | "c" 33 | ] 34 | ], 35 | "key5": [ 36 | 1, 37 | 2, 38 | 3 39 | ], 40 | "key6": [ 41 | 1, 42 | 2 43 | ] 44 | }, 45 | "boolean": { 46 | "False": false, 47 | "True": true 48 | }, 49 | "datetime": { 50 | "key1": "1979-05-27T07:32:00Z", 51 | "key2": "1979-05-27T00:32:00-07:00", 52 | "key3": "1979-05-27T00:32:00.999999-07:00" 53 | }, 54 | "float": { 55 | "both": { 56 | "key": 6.626e-34 57 | }, 58 | "exponent": { 59 | "key1": 5e+22, 60 | "key2": 1000000, 61 | "key3": -0.02 62 | }, 63 | "fractional": { 64 | "key1": 1, 65 | "key2": 3.1415, 66 | "key3": -0.01 67 | }, 68 | "underscores": { 69 | "key1": 9224617.445991227, 70 | "key2": 1e+100 71 | } 72 | }, 73 | "fruit": [{ 74 | "name": "apple", 75 | "physical": { 76 | "color": "red", 77 | "shape": "round" 78 | }, 79 | "variety": [{ 80 | "name": "red delicious" 81 | }, 82 | { 83 | "name": "granny smith" 84 | } 85 | ] 86 | }, 87 | { 88 | "name": "banana", 89 | "variety": [{ 90 | "name": "plantain" 91 | }] 92 | } 93 | ], 94 | "integer": { 95 | "key1": 99, 96 | "key2": 42, 97 | "key3": 0, 98 | "key4": -17, 99 | "underscores": { 100 | "key1": 1000, 101 | "key2": 5349221, 102 | "key3": 12345 103 | } 104 | }, 105 | "products": [{ 106 | "name": "Hammer", 107 | "sku": 738594937 108 | }, 109 | {}, 110 | { 111 | "color": "gray", 112 | "name": "Nail", 113 | "sku": 284758393 114 | } 115 | ], 116 | "string": { 117 | "basic": { 118 | "basic": "I'm a string. \"You can quote me\". Name\tJosé\nLocation\tSF." 119 | }, 120 | "literal": { 121 | "multiline": { 122 | "lines": "The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", 123 | "regex2": "I [dw]on't need \\d{2} apples" 124 | }, 125 | "quoted": "Tom \"Dubs\" Preston-Werner", 126 | "regex": "\u003c\\i\\c*\\s*\u003e", 127 | "winpath": "C:\\Users\\nodejs\\templates", 128 | "winpath2": "\\\\ServerX\\admin$\\system32\\" 129 | }, 130 | "multiline": { 131 | "continued": { 132 | "key1": "The quick brown fox jumps over the lazy dog.", 133 | "key2": "The quick brown fox jumps over the lazy dog.", 134 | "key3": "The quick brown fox jumps over the lazy dog." 135 | }, 136 | "key1": "One\nTwo", 137 | "key2": "One\nTwo", 138 | "key3": "One\nTwo" 139 | } 140 | }, 141 | "table": { 142 | "inline": { 143 | "name": { 144 | "first": "Tom", 145 | "last": "Preston-Werner" 146 | }, 147 | "point": { 148 | "x": 1, 149 | "y": 2 150 | } 151 | }, 152 | "key": "value", 153 | "subtable": { 154 | "key": "another value" 155 | } 156 | }, 157 | "x": { 158 | "y": { 159 | "z": { 160 | "w": {} 161 | } 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/benchmark.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | reference_ref=${1:-master} 6 | reference_git=${2:-.} 7 | 8 | if ! `hash benchstat 2>/dev/null`; then 9 | echo "Installing benchstat" 10 | go get golang.org/x/perf/cmd/benchstat 11 | go install golang.org/x/perf/cmd/benchstat 12 | fi 13 | 14 | tempdir=`mktemp -d /tmp/go-toml-benchmark-XXXXXX` 15 | ref_tempdir="${tempdir}/ref" 16 | ref_benchmark="${ref_tempdir}/benchmark-`echo -n ${reference_ref}|tr -s '/' '-'`.txt" 17 | local_benchmark="`pwd`/benchmark-local.txt" 18 | 19 | echo "=== ${reference_ref} (${ref_tempdir})" 20 | git clone ${reference_git} ${ref_tempdir} >/dev/null 2>/dev/null 21 | pushd ${ref_tempdir} >/dev/null 22 | git checkout ${reference_ref} >/dev/null 2>/dev/null 23 | go test -bench=. -benchmem | tee ${ref_benchmark} 24 | popd >/dev/null 25 | 26 | echo "" 27 | echo "=== local" 28 | go test -bench=. -benchmem | tee ${local_benchmark} 29 | 30 | echo "" 31 | echo "=== diff" 32 | benchstat -delta-test=none ${ref_benchmark} ${local_benchmark} -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/benchmark.toml: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ## Comment 3 | 4 | # Speak your mind with the hash symbol. They go from the symbol to the end of 5 | # the line. 6 | 7 | 8 | ################################################################################ 9 | ## Table 10 | 11 | # Tables (also known as hash tables or dictionaries) are collections of 12 | # key/value pairs. They appear in square brackets on a line by themselves. 13 | 14 | [table] 15 | 16 | key = "value" # Yeah, you can do this. 17 | 18 | # Nested tables are denoted by table names with dots in them. Name your tables 19 | # whatever crap you please, just don't use #, ., [ or ]. 20 | 21 | [table.subtable] 22 | 23 | key = "another value" 24 | 25 | # You don't need to specify all the super-tables if you don't want to. TOML 26 | # knows how to do it for you. 27 | 28 | # [x] you 29 | # [x.y] don't 30 | # [x.y.z] need these 31 | [x.y.z.w] # for this to work 32 | 33 | 34 | ################################################################################ 35 | ## Inline Table 36 | 37 | # Inline tables provide a more compact syntax for expressing tables. They are 38 | # especially useful for grouped data that can otherwise quickly become verbose. 39 | # Inline tables are enclosed in curly braces `{` and `}`. No newlines are 40 | # allowed between the curly braces unless they are valid within a value. 41 | 42 | [table.inline] 43 | 44 | name = { first = "Tom", last = "Preston-Werner" } 45 | point = { x = 1, y = 2 } 46 | 47 | 48 | ################################################################################ 49 | ## String 50 | 51 | # There are four ways to express strings: basic, multi-line basic, literal, and 52 | # multi-line literal. All strings must contain only valid UTF-8 characters. 53 | 54 | [string.basic] 55 | 56 | basic = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF." 57 | 58 | [string.multiline] 59 | 60 | # The following strings are byte-for-byte equivalent: 61 | key1 = "One\nTwo" 62 | key2 = """One\nTwo""" 63 | key3 = """ 64 | One 65 | Two""" 66 | 67 | [string.multiline.continued] 68 | 69 | # The following strings are byte-for-byte equivalent: 70 | key1 = "The quick brown fox jumps over the lazy dog." 71 | 72 | key2 = """ 73 | The quick brown \ 74 | 75 | 76 | fox jumps over \ 77 | the lazy dog.""" 78 | 79 | key3 = """\ 80 | The quick brown \ 81 | fox jumps over \ 82 | the lazy dog.\ 83 | """ 84 | 85 | [string.literal] 86 | 87 | # What you see is what you get. 88 | winpath = 'C:\Users\nodejs\templates' 89 | winpath2 = '\\ServerX\admin$\system32\' 90 | quoted = 'Tom "Dubs" Preston-Werner' 91 | regex = '<\i\c*\s*>' 92 | 93 | 94 | [string.literal.multiline] 95 | 96 | regex2 = '''I [dw]on't need \d{2} apples''' 97 | lines = ''' 98 | The first newline is 99 | trimmed in raw strings. 100 | All other whitespace 101 | is preserved. 102 | ''' 103 | 104 | 105 | ################################################################################ 106 | ## Integer 107 | 108 | # Integers are whole numbers. Positive numbers may be prefixed with a plus sign. 109 | # Negative numbers are prefixed with a minus sign. 110 | 111 | [integer] 112 | 113 | key1 = +99 114 | key2 = 42 115 | key3 = 0 116 | key4 = -17 117 | 118 | [integer.underscores] 119 | 120 | # For large numbers, you may use underscores to enhance readability. Each 121 | # underscore must be surrounded by at least one digit. 122 | key1 = 1_000 123 | key2 = 5_349_221 124 | key3 = 1_2_3_4_5 # valid but inadvisable 125 | 126 | 127 | ################################################################################ 128 | ## Float 129 | 130 | # A float consists of an integer part (which may be prefixed with a plus or 131 | # minus sign) followed by a fractional part and/or an exponent part. 132 | 133 | [float.fractional] 134 | 135 | key1 = +1.0 136 | key2 = 3.1415 137 | key3 = -0.01 138 | 139 | [float.exponent] 140 | 141 | key1 = 5e+22 142 | key2 = 1e6 143 | key3 = -2E-2 144 | 145 | [float.both] 146 | 147 | key = 6.626e-34 148 | 149 | [float.underscores] 150 | 151 | key1 = 9_224_617.445_991_228_313 152 | key2 = 1e1_00 153 | 154 | 155 | ################################################################################ 156 | ## Boolean 157 | 158 | # Booleans are just the tokens you're used to. Always lowercase. 159 | 160 | [boolean] 161 | 162 | True = true 163 | False = false 164 | 165 | 166 | ################################################################################ 167 | ## Datetime 168 | 169 | # Datetimes are RFC 3339 dates. 170 | 171 | [datetime] 172 | 173 | key1 = 1979-05-27T07:32:00Z 174 | key2 = 1979-05-27T00:32:00-07:00 175 | key3 = 1979-05-27T00:32:00.999999-07:00 176 | 177 | 178 | ################################################################################ 179 | ## Array 180 | 181 | # Arrays are square brackets with other primitives inside. Whitespace is 182 | # ignored. Elements are separated by commas. Data types may not be mixed. 183 | 184 | [array] 185 | 186 | key1 = [ 1, 2, 3 ] 187 | key2 = [ "red", "yellow", "green" ] 188 | key3 = [ [ 1, 2 ], [3, 4, 5] ] 189 | #key4 = [ [ 1, 2 ], ["a", "b", "c"] ] # this is ok 190 | 191 | # Arrays can also be multiline. So in addition to ignoring whitespace, arrays 192 | # also ignore newlines between the brackets. Terminating commas are ok before 193 | # the closing bracket. 194 | 195 | key5 = [ 196 | 1, 2, 3 197 | ] 198 | key6 = [ 199 | 1, 200 | 2, # this is ok 201 | ] 202 | 203 | 204 | ################################################################################ 205 | ## Array of Tables 206 | 207 | # These can be expressed by using a table name in double brackets. Each table 208 | # with the same double bracketed name will be an element in the array. The 209 | # tables are inserted in the order encountered. 210 | 211 | [[products]] 212 | 213 | name = "Hammer" 214 | sku = 738594937 215 | 216 | [[products]] 217 | 218 | [[products]] 219 | 220 | name = "Nail" 221 | sku = 284758393 222 | color = "gray" 223 | 224 | 225 | # You can create nested arrays of tables as well. 226 | 227 | [[fruit]] 228 | name = "apple" 229 | 230 | [fruit.physical] 231 | color = "red" 232 | shape = "round" 233 | 234 | [[fruit.variety]] 235 | name = "red delicious" 236 | 237 | [[fruit.variety]] 238 | name = "granny smith" 239 | 240 | [[fruit]] 241 | name = "banana" 242 | 243 | [[fruit.variety]] 244 | name = "plantain" 245 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/benchmark.yml: -------------------------------------------------------------------------------- 1 | --- 2 | array: 3 | key1: 4 | - 1 5 | - 2 6 | - 3 7 | key2: 8 | - red 9 | - yellow 10 | - green 11 | key3: 12 | - - 1 13 | - 2 14 | - - 3 15 | - 4 16 | - 5 17 | key4: 18 | - - 1 19 | - 2 20 | - - a 21 | - b 22 | - c 23 | key5: 24 | - 1 25 | - 2 26 | - 3 27 | key6: 28 | - 1 29 | - 2 30 | boolean: 31 | 'False': false 32 | 'True': true 33 | datetime: 34 | key1: '1979-05-27T07:32:00Z' 35 | key2: '1979-05-27T00:32:00-07:00' 36 | key3: '1979-05-27T00:32:00.999999-07:00' 37 | float: 38 | both: 39 | key: 6.626e-34 40 | exponent: 41 | key1: 5.0e+22 42 | key2: 1000000 43 | key3: -0.02 44 | fractional: 45 | key1: 1 46 | key2: 3.1415 47 | key3: -0.01 48 | underscores: 49 | key1: 9224617.445991227 50 | key2: 1.0e+100 51 | fruit: 52 | - name: apple 53 | physical: 54 | color: red 55 | shape: round 56 | variety: 57 | - name: red delicious 58 | - name: granny smith 59 | - name: banana 60 | variety: 61 | - name: plantain 62 | integer: 63 | key1: 99 64 | key2: 42 65 | key3: 0 66 | key4: -17 67 | underscores: 68 | key1: 1000 69 | key2: 5349221 70 | key3: 12345 71 | products: 72 | - name: Hammer 73 | sku: 738594937 74 | - {} 75 | - color: gray 76 | name: Nail 77 | sku: 284758393 78 | string: 79 | basic: 80 | basic: "I'm a string. \"You can quote me\". Name\tJosé\nLocation\tSF." 81 | literal: 82 | multiline: 83 | lines: | 84 | The first newline is 85 | trimmed in raw strings. 86 | All other whitespace 87 | is preserved. 88 | regex2: I [dw]on't need \d{2} apples 89 | quoted: Tom "Dubs" Preston-Werner 90 | regex: "<\\i\\c*\\s*>" 91 | winpath: C:\Users\nodejs\templates 92 | winpath2: "\\\\ServerX\\admin$\\system32\\" 93 | multiline: 94 | continued: 95 | key1: The quick brown fox jumps over the lazy dog. 96 | key2: The quick brown fox jumps over the lazy dog. 97 | key3: The quick brown fox jumps over the lazy dog. 98 | key1: |- 99 | One 100 | Two 101 | key2: |- 102 | One 103 | Two 104 | key3: |- 105 | One 106 | Two 107 | table: 108 | inline: 109 | name: 110 | first: Tom 111 | last: Preston-Werner 112 | point: 113 | x: 1 114 | y: 2 115 | key: value 116 | subtable: 117 | key: another value 118 | x: 119 | y: 120 | z: 121 | w: {} 122 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/doc.go: -------------------------------------------------------------------------------- 1 | // Package toml is a TOML parser and manipulation library. 2 | // 3 | // This version supports the specification as described in 4 | // https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md 5 | // 6 | // Marshaling 7 | // 8 | // Go-toml can marshal and unmarshal TOML documents from and to data 9 | // structures. 10 | // 11 | // TOML document as a tree 12 | // 13 | // Go-toml can operate on a TOML document as a tree. Use one of the Load* 14 | // functions to parse TOML data and obtain a Tree instance, then one of its 15 | // methods to manipulate the tree. 16 | // 17 | // JSONPath-like queries 18 | // 19 | // The package github.com/pelletier/go-toml/query implements a system 20 | // similar to JSONPath to quickly retrieve elements of a TOML document using a 21 | // single expression. See the package documentation for more information. 22 | // 23 | package toml 24 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/example-crlf.toml: -------------------------------------------------------------------------------- 1 | # This is a TOML document. Boom. 2 | 3 | title = "TOML Example" 4 | 5 | [owner] 6 | name = "Tom Preston-Werner" 7 | organization = "GitHub" 8 | bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." 9 | dob = 1979-05-27T07:32:00Z # First class dates? Why not? 10 | 11 | [database] 12 | server = "192.168.1.1" 13 | ports = [ 8001, 8001, 8002 ] 14 | connection_max = 5000 15 | enabled = true 16 | 17 | [servers] 18 | 19 | # You can indent as you please. Tabs or spaces. TOML don't care. 20 | [servers.alpha] 21 | ip = "10.0.0.1" 22 | dc = "eqdc10" 23 | 24 | [servers.beta] 25 | ip = "10.0.0.2" 26 | dc = "eqdc10" 27 | 28 | [clients] 29 | data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it 30 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/example.toml: -------------------------------------------------------------------------------- 1 | # This is a TOML document. Boom. 2 | 3 | title = "TOML Example" 4 | 5 | [owner] 6 | name = "Tom Preston-Werner" 7 | organization = "GitHub" 8 | bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." 9 | dob = 1979-05-27T07:32:00Z # First class dates? Why not? 10 | 11 | [database] 12 | server = "192.168.1.1" 13 | ports = [ 8001, 8001, 8002 ] 14 | connection_max = 5000 15 | enabled = true 16 | 17 | [servers] 18 | 19 | # You can indent as you please. Tabs or spaces. TOML don't care. 20 | [servers.alpha] 21 | ip = "10.0.0.1" 22 | dc = "eqdc10" 23 | 24 | [servers.beta] 25 | ip = "10.0.0.2" 26 | dc = "eqdc10" 27 | 28 | [clients] 29 | data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it 30 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/fuzz.go: -------------------------------------------------------------------------------- 1 | // +build gofuzz 2 | 3 | package toml 4 | 5 | func Fuzz(data []byte) int { 6 | tree, err := LoadBytes(data) 7 | if err != nil { 8 | if tree != nil { 9 | panic("tree must be nil if there is an error") 10 | } 11 | return 0 12 | } 13 | 14 | str, err := tree.ToTomlString() 15 | if err != nil { 16 | if str != "" { 17 | panic(`str must be "" if there is an error`) 18 | } 19 | panic(err) 20 | } 21 | 22 | tree, err = Load(str) 23 | if err != nil { 24 | if tree != nil { 25 | panic("tree must be nil if there is an error") 26 | } 27 | return 0 28 | } 29 | 30 | return 1 31 | } 32 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/fuzz.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | set -eu 3 | 4 | go get github.com/dvyukov/go-fuzz/go-fuzz 5 | go get github.com/dvyukov/go-fuzz/go-fuzz-build 6 | 7 | if [ ! -e toml-fuzz.zip ]; then 8 | go-fuzz-build github.com/pelletier/go-toml 9 | fi 10 | 11 | rm -fr fuzz 12 | mkdir -p fuzz/corpus 13 | cp *.toml fuzz/corpus 14 | 15 | go-fuzz -bin=toml-fuzz.zip -workdir=fuzz 16 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/keysparsing.go: -------------------------------------------------------------------------------- 1 | // Parsing keys handling both bare and quoted keys. 2 | 3 | package toml 4 | 5 | import ( 6 | "bytes" 7 | "errors" 8 | "fmt" 9 | "unicode" 10 | ) 11 | 12 | // Convert the bare key group string to an array. 13 | // The input supports double quotation to allow "." inside the key name, 14 | // but escape sequences are not supported. Lexers must unescape them beforehand. 15 | func parseKey(key string) ([]string, error) { 16 | groups := []string{} 17 | var buffer bytes.Buffer 18 | inQuotes := false 19 | wasInQuotes := false 20 | ignoreSpace := true 21 | expectDot := false 22 | 23 | for _, char := range key { 24 | if ignoreSpace { 25 | if char == ' ' { 26 | continue 27 | } 28 | ignoreSpace = false 29 | } 30 | switch char { 31 | case '"': 32 | if inQuotes { 33 | groups = append(groups, buffer.String()) 34 | buffer.Reset() 35 | wasInQuotes = true 36 | } 37 | inQuotes = !inQuotes 38 | expectDot = false 39 | case '.': 40 | if inQuotes { 41 | buffer.WriteRune(char) 42 | } else { 43 | if !wasInQuotes { 44 | if buffer.Len() == 0 { 45 | return nil, errors.New("empty table key") 46 | } 47 | groups = append(groups, buffer.String()) 48 | buffer.Reset() 49 | } 50 | ignoreSpace = true 51 | expectDot = false 52 | wasInQuotes = false 53 | } 54 | case ' ': 55 | if inQuotes { 56 | buffer.WriteRune(char) 57 | } else { 58 | expectDot = true 59 | } 60 | default: 61 | if !inQuotes && !isValidBareChar(char) { 62 | return nil, fmt.Errorf("invalid bare character: %c", char) 63 | } 64 | if !inQuotes && expectDot { 65 | return nil, errors.New("what?") 66 | } 67 | buffer.WriteRune(char) 68 | expectDot = false 69 | } 70 | } 71 | if inQuotes { 72 | return nil, errors.New("mismatched quotes") 73 | } 74 | if buffer.Len() > 0 { 75 | groups = append(groups, buffer.String()) 76 | } 77 | if len(groups) == 0 { 78 | return nil, errors.New("empty key") 79 | } 80 | return groups, nil 81 | } 82 | 83 | func isValidBareChar(r rune) bool { 84 | return isAlphanumeric(r) || r == '-' || unicode.IsNumber(r) 85 | } 86 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/marshal_test.toml: -------------------------------------------------------------------------------- 1 | title = "TOML Marshal Testing" 2 | 3 | [basic] 4 | bool = true 5 | date = 1979-05-27T07:32:00Z 6 | float = 123.4 7 | int = 5000 8 | string = "Bite me" 9 | uint = 5001 10 | 11 | [basic_lists] 12 | bools = [true,false,true] 13 | dates = [1979-05-27T07:32:00Z,1980-05-27T07:32:00Z] 14 | floats = [12.3,45.6,78.9] 15 | ints = [8001,8001,8002] 16 | strings = ["One","Two","Three"] 17 | uints = [5002,5003] 18 | 19 | [basic_map] 20 | one = "one" 21 | two = "two" 22 | 23 | [subdoc] 24 | 25 | [subdoc.first] 26 | name = "First" 27 | 28 | [subdoc.second] 29 | name = "Second" 30 | 31 | [[subdoclist]] 32 | name = "List.First" 33 | 34 | [[subdoclist]] 35 | name = "List.Second" 36 | 37 | [[subdocptrs]] 38 | name = "Second" 39 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/position.go: -------------------------------------------------------------------------------- 1 | // Position support for go-toml 2 | 3 | package toml 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | // Position of a document element within a TOML document. 10 | // 11 | // Line and Col are both 1-indexed positions for the element's line number and 12 | // column number, respectively. Values of zero or less will cause Invalid(), 13 | // to return true. 14 | type Position struct { 15 | Line int // line within the document 16 | Col int // column within the line 17 | } 18 | 19 | // String representation of the position. 20 | // Displays 1-indexed line and column numbers. 21 | func (p Position) String() string { 22 | return fmt.Sprintf("(%d, %d)", p.Line, p.Col) 23 | } 24 | 25 | // Invalid returns whether or not the position is valid (i.e. with negative or 26 | // null values) 27 | func (p Position) Invalid() bool { 28 | return p.Line <= 0 || p.Col <= 0 29 | } 30 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # fail out of the script if anything here fails 3 | set -e 4 | set -o pipefail 5 | 6 | # set the path to the present working directory 7 | export GOPATH=`pwd` 8 | 9 | function git_clone() { 10 | path=$1 11 | branch=$2 12 | version=$3 13 | if [ ! -d "src/$path" ]; then 14 | mkdir -p src/$path 15 | git clone https://$path.git src/$path 16 | fi 17 | pushd src/$path 18 | git checkout "$branch" 19 | git reset --hard "$version" 20 | popd 21 | } 22 | 23 | # Remove potential previous runs 24 | rm -rf src test_program_bin toml-test 25 | 26 | # Run go vet 27 | go vet ./... 28 | 29 | go get github.com/pelletier/go-buffruneio 30 | go get github.com/davecgh/go-spew/spew 31 | go get gopkg.in/yaml.v2 32 | go get github.com/BurntSushi/toml 33 | 34 | # get code for BurntSushi TOML validation 35 | # pinning all to 'HEAD' for version 0.3.x work (TODO: pin to commit hash when tests stabilize) 36 | git_clone github.com/BurntSushi/toml master HEAD 37 | git_clone github.com/BurntSushi/toml-test master HEAD #was: 0.2.0 HEAD 38 | 39 | # build the BurntSushi test application 40 | go build -o toml-test github.com/BurntSushi/toml-test 41 | 42 | # vendorize the current lib for testing 43 | # NOTE: this basically mocks an install without having to go back out to github for code 44 | mkdir -p src/github.com/pelletier/go-toml/cmd 45 | mkdir -p src/github.com/pelletier/go-toml/query 46 | cp *.go *.toml src/github.com/pelletier/go-toml 47 | cp -R cmd/* src/github.com/pelletier/go-toml/cmd 48 | cp -R query/* src/github.com/pelletier/go-toml/query 49 | go build -o test_program_bin src/github.com/pelletier/go-toml/cmd/test_program.go 50 | 51 | # Run basic unit tests 52 | go test github.com/pelletier/go-toml -covermode=count -coverprofile=coverage.out 53 | go test github.com/pelletier/go-toml/cmd/tomljson 54 | go test github.com/pelletier/go-toml/query 55 | 56 | # run the entire BurntSushi test suite 57 | if [[ $# -eq 0 ]] ; then 58 | echo "Running all BurntSushi tests" 59 | ./toml-test ./test_program_bin | tee test_out 60 | else 61 | # run a specific test 62 | test=$1 63 | test_path='src/github.com/BurntSushi/toml-test/tests' 64 | valid_test="$test_path/valid/$test" 65 | invalid_test="$test_path/invalid/$test" 66 | 67 | if [ -e "$valid_test.toml" ]; then 68 | echo "Valid Test TOML for $test:" 69 | echo "====" 70 | cat "$valid_test.toml" 71 | 72 | echo "Valid Test JSON for $test:" 73 | echo "====" 74 | cat "$valid_test.json" 75 | 76 | echo "Go-TOML Output for $test:" 77 | echo "====" 78 | cat "$valid_test.toml" | ./test_program_bin 79 | fi 80 | 81 | if [ -e "$invalid_test.toml" ]; then 82 | echo "Invalid Test TOML for $test:" 83 | echo "====" 84 | cat "$invalid_test.toml" 85 | 86 | echo "Go-TOML Output for $test:" 87 | echo "====" 88 | echo "go-toml Output:" 89 | cat "$invalid_test.toml" | ./test_program_bin 90 | fi 91 | fi 92 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/token.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "unicode" 7 | ) 8 | 9 | // Define tokens 10 | type tokenType int 11 | 12 | const ( 13 | eof = -(iota + 1) 14 | ) 15 | 16 | const ( 17 | tokenError tokenType = iota 18 | tokenEOF 19 | tokenComment 20 | tokenKey 21 | tokenString 22 | tokenInteger 23 | tokenTrue 24 | tokenFalse 25 | tokenFloat 26 | tokenInf 27 | tokenNan 28 | tokenEqual 29 | tokenLeftBracket 30 | tokenRightBracket 31 | tokenLeftCurlyBrace 32 | tokenRightCurlyBrace 33 | tokenLeftParen 34 | tokenRightParen 35 | tokenDoubleLeftBracket 36 | tokenDoubleRightBracket 37 | tokenDate 38 | tokenKeyGroup 39 | tokenKeyGroupArray 40 | tokenComma 41 | tokenColon 42 | tokenDollar 43 | tokenStar 44 | tokenQuestion 45 | tokenDot 46 | tokenDotDot 47 | tokenEOL 48 | ) 49 | 50 | var tokenTypeNames = []string{ 51 | "Error", 52 | "EOF", 53 | "Comment", 54 | "Key", 55 | "String", 56 | "Integer", 57 | "True", 58 | "False", 59 | "Float", 60 | "Inf", 61 | "NaN", 62 | "=", 63 | "[", 64 | "]", 65 | "{", 66 | "}", 67 | "(", 68 | ")", 69 | "]]", 70 | "[[", 71 | "Date", 72 | "KeyGroup", 73 | "KeyGroupArray", 74 | ",", 75 | ":", 76 | "$", 77 | "*", 78 | "?", 79 | ".", 80 | "..", 81 | "EOL", 82 | } 83 | 84 | type token struct { 85 | Position 86 | typ tokenType 87 | val string 88 | } 89 | 90 | func (tt tokenType) String() string { 91 | idx := int(tt) 92 | if idx < len(tokenTypeNames) { 93 | return tokenTypeNames[idx] 94 | } 95 | return "Unknown" 96 | } 97 | 98 | func (t token) Int() int { 99 | if result, err := strconv.Atoi(t.val); err != nil { 100 | panic(err) 101 | } else { 102 | return result 103 | } 104 | } 105 | 106 | func (t token) String() string { 107 | switch t.typ { 108 | case tokenEOF: 109 | return "EOF" 110 | case tokenError: 111 | return t.val 112 | } 113 | 114 | return fmt.Sprintf("%q", t.val) 115 | } 116 | 117 | func isSpace(r rune) bool { 118 | return r == ' ' || r == '\t' 119 | } 120 | 121 | func isAlphanumeric(r rune) bool { 122 | return unicode.IsLetter(r) || r == '_' 123 | } 124 | 125 | func isKeyChar(r rune) bool { 126 | // Keys start with the first character that isn't whitespace or [ and end 127 | // with the last non-whitespace character before the equals sign. Keys 128 | // cannot contain a # character." 129 | return !(r == '\r' || r == '\n' || r == eof || r == '=') 130 | } 131 | 132 | func isKeyStartChar(r rune) bool { 133 | return !(isSpace(r) || r == '\r' || r == '\n' || r == eof || r == '[') 134 | } 135 | 136 | func isDigit(r rune) bool { 137 | return unicode.IsNumber(r) 138 | } 139 | 140 | func isHexDigit(r rune) bool { 141 | return isDigit(r) || 142 | (r >= 'a' && r <= 'f') || 143 | (r >= 'A' && r <= 'F') 144 | } 145 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/tomltree_create.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | var kindToType = [reflect.String + 1]reflect.Type{ 10 | reflect.Bool: reflect.TypeOf(true), 11 | reflect.String: reflect.TypeOf(""), 12 | reflect.Float32: reflect.TypeOf(float64(1)), 13 | reflect.Float64: reflect.TypeOf(float64(1)), 14 | reflect.Int: reflect.TypeOf(int64(1)), 15 | reflect.Int8: reflect.TypeOf(int64(1)), 16 | reflect.Int16: reflect.TypeOf(int64(1)), 17 | reflect.Int32: reflect.TypeOf(int64(1)), 18 | reflect.Int64: reflect.TypeOf(int64(1)), 19 | reflect.Uint: reflect.TypeOf(uint64(1)), 20 | reflect.Uint8: reflect.TypeOf(uint64(1)), 21 | reflect.Uint16: reflect.TypeOf(uint64(1)), 22 | reflect.Uint32: reflect.TypeOf(uint64(1)), 23 | reflect.Uint64: reflect.TypeOf(uint64(1)), 24 | } 25 | 26 | // typeFor returns a reflect.Type for a reflect.Kind, or nil if none is found. 27 | // supported values: 28 | // string, bool, int64, uint64, float64, time.Time, int, int8, int16, int32, uint, uint8, uint16, uint32, float32 29 | func typeFor(k reflect.Kind) reflect.Type { 30 | if k > 0 && int(k) < len(kindToType) { 31 | return kindToType[k] 32 | } 33 | return nil 34 | } 35 | 36 | func simpleValueCoercion(object interface{}) (interface{}, error) { 37 | switch original := object.(type) { 38 | case string, bool, int64, uint64, float64, time.Time: 39 | return original, nil 40 | case int: 41 | return int64(original), nil 42 | case int8: 43 | return int64(original), nil 44 | case int16: 45 | return int64(original), nil 46 | case int32: 47 | return int64(original), nil 48 | case uint: 49 | return uint64(original), nil 50 | case uint8: 51 | return uint64(original), nil 52 | case uint16: 53 | return uint64(original), nil 54 | case uint32: 55 | return uint64(original), nil 56 | case float32: 57 | return float64(original), nil 58 | case fmt.Stringer: 59 | return original.String(), nil 60 | default: 61 | return nil, fmt.Errorf("cannot convert type %T to Tree", object) 62 | } 63 | } 64 | 65 | func sliceToTree(object interface{}) (interface{}, error) { 66 | // arrays are a bit tricky, since they can represent either a 67 | // collection of simple values, which is represented by one 68 | // *tomlValue, or an array of tables, which is represented by an 69 | // array of *Tree. 70 | 71 | // holding the assumption that this function is called from toTree only when value.Kind() is Array or Slice 72 | value := reflect.ValueOf(object) 73 | insideType := value.Type().Elem() 74 | length := value.Len() 75 | if length > 0 { 76 | insideType = reflect.ValueOf(value.Index(0).Interface()).Type() 77 | } 78 | if insideType.Kind() == reflect.Map { 79 | // this is considered as an array of tables 80 | tablesArray := make([]*Tree, 0, length) 81 | for i := 0; i < length; i++ { 82 | table := value.Index(i) 83 | tree, err := toTree(table.Interface()) 84 | if err != nil { 85 | return nil, err 86 | } 87 | tablesArray = append(tablesArray, tree.(*Tree)) 88 | } 89 | return tablesArray, nil 90 | } 91 | 92 | sliceType := typeFor(insideType.Kind()) 93 | if sliceType == nil { 94 | sliceType = insideType 95 | } 96 | 97 | arrayValue := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, length) 98 | 99 | for i := 0; i < length; i++ { 100 | val := value.Index(i).Interface() 101 | simpleValue, err := simpleValueCoercion(val) 102 | if err != nil { 103 | return nil, err 104 | } 105 | arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue)) 106 | } 107 | return &tomlValue{value: arrayValue.Interface(), position: Position{}}, nil 108 | } 109 | 110 | func toTree(object interface{}) (interface{}, error) { 111 | value := reflect.ValueOf(object) 112 | 113 | if value.Kind() == reflect.Map { 114 | values := map[string]interface{}{} 115 | keys := value.MapKeys() 116 | for _, key := range keys { 117 | if key.Kind() != reflect.String { 118 | if _, ok := key.Interface().(string); !ok { 119 | return nil, fmt.Errorf("map key needs to be a string, not %T (%v)", key.Interface(), key.Kind()) 120 | } 121 | } 122 | 123 | v := value.MapIndex(key) 124 | newValue, err := toTree(v.Interface()) 125 | if err != nil { 126 | return nil, err 127 | } 128 | values[key.String()] = newValue 129 | } 130 | return &Tree{values: values, position: Position{}}, nil 131 | } 132 | 133 | if value.Kind() == reflect.Array || value.Kind() == reflect.Slice { 134 | return sliceToTree(object) 135 | } 136 | 137 | simpleValue, err := simpleValueCoercion(object) 138 | if err != nil { 139 | return nil, err 140 | } 141 | return &tomlValue{value: simpleValue, position: Position{}}, nil 142 | } 143 | -------------------------------------------------------------------------------- /vendor/github.com/pelletier/go-toml/tomltree_write.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "math" 8 | "reflect" 9 | "sort" 10 | "strconv" 11 | "strings" 12 | "time" 13 | ) 14 | 15 | // encodes a string to a TOML-compliant string value 16 | func encodeTomlString(value string) string { 17 | var b bytes.Buffer 18 | 19 | for _, rr := range value { 20 | switch rr { 21 | case '\b': 22 | b.WriteString(`\b`) 23 | case '\t': 24 | b.WriteString(`\t`) 25 | case '\n': 26 | b.WriteString(`\n`) 27 | case '\f': 28 | b.WriteString(`\f`) 29 | case '\r': 30 | b.WriteString(`\r`) 31 | case '"': 32 | b.WriteString(`\"`) 33 | case '\\': 34 | b.WriteString(`\\`) 35 | default: 36 | intRr := uint16(rr) 37 | if intRr < 0x001F { 38 | b.WriteString(fmt.Sprintf("\\u%0.4X", intRr)) 39 | } else { 40 | b.WriteRune(rr) 41 | } 42 | } 43 | } 44 | return b.String() 45 | } 46 | 47 | func tomlValueStringRepresentation(v interface{}, indent string, arraysOneElementPerLine bool) (string, error) { 48 | switch value := v.(type) { 49 | case uint64: 50 | return strconv.FormatUint(value, 10), nil 51 | case int64: 52 | return strconv.FormatInt(value, 10), nil 53 | case float64: 54 | // Ensure a round float does contain a decimal point. Otherwise feeding 55 | // the output back to the parser would convert to an integer. 56 | if math.Trunc(value) == value { 57 | return strings.ToLower(strconv.FormatFloat(value, 'f', 1, 32)), nil 58 | } 59 | return strings.ToLower(strconv.FormatFloat(value, 'f', -1, 32)), nil 60 | case string: 61 | return "\"" + encodeTomlString(value) + "\"", nil 62 | case []byte: 63 | b, _ := v.([]byte) 64 | return tomlValueStringRepresentation(string(b), indent, arraysOneElementPerLine) 65 | case bool: 66 | if value { 67 | return "true", nil 68 | } 69 | return "false", nil 70 | case time.Time: 71 | return value.Format(time.RFC3339), nil 72 | case nil: 73 | return "", nil 74 | } 75 | 76 | rv := reflect.ValueOf(v) 77 | 78 | if rv.Kind() == reflect.Slice { 79 | var values []string 80 | for i := 0; i < rv.Len(); i++ { 81 | item := rv.Index(i).Interface() 82 | itemRepr, err := tomlValueStringRepresentation(item, indent, arraysOneElementPerLine) 83 | if err != nil { 84 | return "", err 85 | } 86 | values = append(values, itemRepr) 87 | } 88 | if arraysOneElementPerLine && len(values) > 1 { 89 | stringBuffer := bytes.Buffer{} 90 | valueIndent := indent + ` ` // TODO: move that to a shared encoder state 91 | 92 | stringBuffer.WriteString("[\n") 93 | 94 | for i, value := range values { 95 | stringBuffer.WriteString(valueIndent) 96 | stringBuffer.WriteString(value) 97 | if i != len(values)-1 { 98 | stringBuffer.WriteString(`,`) 99 | } 100 | stringBuffer.WriteString("\n") 101 | } 102 | 103 | stringBuffer.WriteString(indent + "]") 104 | 105 | return stringBuffer.String(), nil 106 | } 107 | return "[" + strings.Join(values, ",") + "]", nil 108 | } 109 | return "", fmt.Errorf("unsupported value type %T: %v", v, v) 110 | } 111 | 112 | func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool) (int64, error) { 113 | simpleValuesKeys := make([]string, 0) 114 | complexValuesKeys := make([]string, 0) 115 | 116 | for k := range t.values { 117 | v := t.values[k] 118 | switch v.(type) { 119 | case *Tree, []*Tree: 120 | complexValuesKeys = append(complexValuesKeys, k) 121 | default: 122 | simpleValuesKeys = append(simpleValuesKeys, k) 123 | } 124 | } 125 | 126 | sort.Strings(simpleValuesKeys) 127 | sort.Strings(complexValuesKeys) 128 | 129 | for _, k := range simpleValuesKeys { 130 | v, ok := t.values[k].(*tomlValue) 131 | if !ok { 132 | return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k]) 133 | } 134 | 135 | repr, err := tomlValueStringRepresentation(v.value, indent, arraysOneElementPerLine) 136 | if err != nil { 137 | return bytesCount, err 138 | } 139 | 140 | if v.comment != "" { 141 | comment := strings.Replace(v.comment, "\n", "\n"+indent+"#", -1) 142 | start := "# " 143 | if strings.HasPrefix(comment, "#") { 144 | start = "" 145 | } 146 | writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment, "\n") 147 | bytesCount += int64(writtenBytesCountComment) 148 | if errc != nil { 149 | return bytesCount, errc 150 | } 151 | } 152 | 153 | var commented string 154 | if v.commented { 155 | commented = "# " 156 | } 157 | writtenBytesCount, err := writeStrings(w, indent, commented, k, " = ", repr, "\n") 158 | bytesCount += int64(writtenBytesCount) 159 | if err != nil { 160 | return bytesCount, err 161 | } 162 | } 163 | 164 | for _, k := range complexValuesKeys { 165 | v := t.values[k] 166 | 167 | combinedKey := k 168 | if keyspace != "" { 169 | combinedKey = keyspace + "." + combinedKey 170 | } 171 | var commented string 172 | if t.commented { 173 | commented = "# " 174 | } 175 | 176 | switch node := v.(type) { 177 | // node has to be of those two types given how keys are sorted above 178 | case *Tree: 179 | tv, ok := t.values[k].(*Tree) 180 | if !ok { 181 | return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k]) 182 | } 183 | if tv.comment != "" { 184 | comment := strings.Replace(tv.comment, "\n", "\n"+indent+"#", -1) 185 | start := "# " 186 | if strings.HasPrefix(comment, "#") { 187 | start = "" 188 | } 189 | writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment) 190 | bytesCount += int64(writtenBytesCountComment) 191 | if errc != nil { 192 | return bytesCount, errc 193 | } 194 | } 195 | writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[", combinedKey, "]\n") 196 | bytesCount += int64(writtenBytesCount) 197 | if err != nil { 198 | return bytesCount, err 199 | } 200 | bytesCount, err = node.writeTo(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine) 201 | if err != nil { 202 | return bytesCount, err 203 | } 204 | case []*Tree: 205 | for _, subTree := range node { 206 | writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[[", combinedKey, "]]\n") 207 | bytesCount += int64(writtenBytesCount) 208 | if err != nil { 209 | return bytesCount, err 210 | } 211 | 212 | bytesCount, err = subTree.writeTo(w, indent+" ", combinedKey, bytesCount, arraysOneElementPerLine) 213 | if err != nil { 214 | return bytesCount, err 215 | } 216 | } 217 | } 218 | } 219 | 220 | return bytesCount, nil 221 | } 222 | 223 | func writeStrings(w io.Writer, s ...string) (int, error) { 224 | var n int 225 | for i := range s { 226 | b, err := io.WriteString(w, s[i]) 227 | n += b 228 | if err != nil { 229 | return n, err 230 | } 231 | } 232 | return n, nil 233 | } 234 | 235 | // WriteTo encode the Tree as Toml and writes it to the writer w. 236 | // Returns the number of bytes written in case of success, or an error if anything happened. 237 | func (t *Tree) WriteTo(w io.Writer) (int64, error) { 238 | return t.writeTo(w, "", "", 0, false) 239 | } 240 | 241 | // ToTomlString generates a human-readable representation of the current tree. 242 | // Output spans multiple lines, and is suitable for ingest by a TOML parser. 243 | // If the conversion cannot be performed, ToString returns a non-nil error. 244 | func (t *Tree) ToTomlString() (string, error) { 245 | var buf bytes.Buffer 246 | _, err := t.WriteTo(&buf) 247 | if err != nil { 248 | return "", err 249 | } 250 | return buf.String(), nil 251 | } 252 | 253 | // String generates a human-readable representation of the current tree. 254 | // Alias of ToString. Present to implement the fmt.Stringer interface. 255 | func (t *Tree) String() string { 256 | result, _ := t.ToTomlString() 257 | return result 258 | } 259 | 260 | // ToMap recursively generates a representation of the tree using Go built-in structures. 261 | // The following types are used: 262 | // 263 | // * bool 264 | // * float64 265 | // * int64 266 | // * string 267 | // * uint64 268 | // * time.Time 269 | // * map[string]interface{} (where interface{} is any of this list) 270 | // * []interface{} (where interface{} is any of this list) 271 | func (t *Tree) ToMap() map[string]interface{} { 272 | result := map[string]interface{}{} 273 | 274 | for k, v := range t.values { 275 | switch node := v.(type) { 276 | case []*Tree: 277 | var array []interface{} 278 | for _, item := range node { 279 | array = append(array, item.ToMap()) 280 | } 281 | result[k] = array 282 | case *Tree: 283 | result[k] = node.ToMap() 284 | case *tomlValue: 285 | result[k] = node.value 286 | } 287 | } 288 | return result 289 | } 290 | -------------------------------------------------------------------------------- /vendor/github.com/petar/GoLLRB/AUTHORS: -------------------------------------------------------------------------------- 1 | Petar Maymounkov 2 | Vadim Vygonets 3 | Ian Smith 4 | Martin Bruse 5 | -------------------------------------------------------------------------------- /vendor/github.com/petar/GoLLRB/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Petar Maymounkov 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | (*) Redistributions of source code must retain the above copyright notice, this list 8 | of conditions and the following disclaimer. 9 | 10 | (*) Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | (*) Neither the name of Petar Maymounkov nor the names of its contributors may be 15 | used to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/petar/GoLLRB/llrb/avgvar.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Petar Maymounkov. 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 llrb 6 | 7 | import "math" 8 | 9 | // avgVar maintains the average and variance of a stream of numbers 10 | // in a space-efficient manner. 11 | type avgVar struct { 12 | count int64 13 | sum, sumsq float64 14 | } 15 | 16 | func (av *avgVar) Init() { 17 | av.count = 0 18 | av.sum = 0.0 19 | av.sumsq = 0.0 20 | } 21 | 22 | func (av *avgVar) Add(sample float64) { 23 | av.count++ 24 | av.sum += sample 25 | av.sumsq += sample * sample 26 | } 27 | 28 | func (av *avgVar) GetCount() int64 { return av.count } 29 | 30 | func (av *avgVar) GetAvg() float64 { return av.sum / float64(av.count) } 31 | 32 | func (av *avgVar) GetTotal() float64 { return av.sum } 33 | 34 | func (av *avgVar) GetVar() float64 { 35 | a := av.GetAvg() 36 | return av.sumsq/float64(av.count) - a*a 37 | } 38 | 39 | func (av *avgVar) GetStdDev() float64 { return math.Sqrt(av.GetVar()) } 40 | -------------------------------------------------------------------------------- /vendor/github.com/petar/GoLLRB/llrb/iterator.go: -------------------------------------------------------------------------------- 1 | package llrb 2 | 3 | type ItemIterator func(i Item) bool 4 | 5 | //func (t *Tree) Ascend(iterator ItemIterator) { 6 | // t.AscendGreaterOrEqual(Inf(-1), iterator) 7 | //} 8 | 9 | func (t *LLRB) AscendRange(greaterOrEqual, lessThan Item, iterator ItemIterator) { 10 | t.ascendRange(t.root, greaterOrEqual, lessThan, iterator) 11 | } 12 | 13 | func (t *LLRB) ascendRange(h *Node, inf, sup Item, iterator ItemIterator) bool { 14 | if h == nil { 15 | return true 16 | } 17 | if !less(h.Item, sup) { 18 | return t.ascendRange(h.Left, inf, sup, iterator) 19 | } 20 | if less(h.Item, inf) { 21 | return t.ascendRange(h.Right, inf, sup, iterator) 22 | } 23 | 24 | if !t.ascendRange(h.Left, inf, sup, iterator) { 25 | return false 26 | } 27 | if !iterator(h.Item) { 28 | return false 29 | } 30 | return t.ascendRange(h.Right, inf, sup, iterator) 31 | } 32 | 33 | // AscendGreaterOrEqual will call iterator once for each element greater or equal to 34 | // pivot in ascending order. It will stop whenever the iterator returns false. 35 | func (t *LLRB) AscendGreaterOrEqual(pivot Item, iterator ItemIterator) { 36 | t.ascendGreaterOrEqual(t.root, pivot, iterator) 37 | } 38 | 39 | func (t *LLRB) ascendGreaterOrEqual(h *Node, pivot Item, iterator ItemIterator) bool { 40 | if h == nil { 41 | return true 42 | } 43 | if !less(h.Item, pivot) { 44 | if !t.ascendGreaterOrEqual(h.Left, pivot, iterator) { 45 | return false 46 | } 47 | if !iterator(h.Item) { 48 | return false 49 | } 50 | } 51 | return t.ascendGreaterOrEqual(h.Right, pivot, iterator) 52 | } 53 | 54 | func (t *LLRB) AscendLessThan(pivot Item, iterator ItemIterator) { 55 | t.ascendLessThan(t.root, pivot, iterator) 56 | } 57 | 58 | func (t *LLRB) ascendLessThan(h *Node, pivot Item, iterator ItemIterator) bool { 59 | if h == nil { 60 | return true 61 | } 62 | if !t.ascendLessThan(h.Left, pivot, iterator) { 63 | return false 64 | } 65 | if !iterator(h.Item) { 66 | return false 67 | } 68 | if less(h.Item, pivot) { 69 | return t.ascendLessThan(h.Left, pivot, iterator) 70 | } 71 | return true 72 | } 73 | 74 | // DescendLessOrEqual will call iterator once for each element less than the 75 | // pivot in descending order. It will stop whenever the iterator returns false. 76 | func (t *LLRB) DescendLessOrEqual(pivot Item, iterator ItemIterator) { 77 | t.descendLessOrEqual(t.root, pivot, iterator) 78 | } 79 | 80 | func (t *LLRB) descendLessOrEqual(h *Node, pivot Item, iterator ItemIterator) bool { 81 | if h == nil { 82 | return true 83 | } 84 | if less(h.Item, pivot) || !less(pivot, h.Item) { 85 | if !t.descendLessOrEqual(h.Right, pivot, iterator) { 86 | return false 87 | } 88 | if !iterator(h.Item) { 89 | return false 90 | } 91 | } 92 | return t.descendLessOrEqual(h.Left, pivot, iterator) 93 | } 94 | -------------------------------------------------------------------------------- /vendor/github.com/petar/GoLLRB/llrb/llrb-stats.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Petar Maymounkov. 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 llrb 6 | 7 | // GetHeight() returns an item in the tree with key @key, and it's height in the tree 8 | func (t *LLRB) GetHeight(key Item) (result Item, depth int) { 9 | return t.getHeight(t.root, key) 10 | } 11 | 12 | func (t *LLRB) getHeight(h *Node, item Item) (Item, int) { 13 | if h == nil { 14 | return nil, 0 15 | } 16 | if less(item, h.Item) { 17 | result, depth := t.getHeight(h.Left, item) 18 | return result, depth + 1 19 | } 20 | if less(h.Item, item) { 21 | result, depth := t.getHeight(h.Right, item) 22 | return result, depth + 1 23 | } 24 | return h.Item, 0 25 | } 26 | 27 | // HeightStats() returns the average and standard deviation of the height 28 | // of elements in the tree 29 | func (t *LLRB) HeightStats() (avg, stddev float64) { 30 | av := &avgVar{} 31 | heightStats(t.root, 0, av) 32 | return av.GetAvg(), av.GetStdDev() 33 | } 34 | 35 | func heightStats(h *Node, d int, av *avgVar) { 36 | if h == nil { 37 | return 38 | } 39 | av.Add(float64(d)) 40 | if h.Left != nil { 41 | heightStats(h.Left, d+1, av) 42 | } 43 | if h.Right != nil { 44 | heightStats(h.Right, d+1, av) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /vendor/github.com/petar/GoLLRB/llrb/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Petar Maymounkov. 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 llrb 6 | 7 | type Int int 8 | 9 | func (x Int) Less(than Item) bool { 10 | return x < than.(Int) 11 | } 12 | 13 | type String string 14 | 15 | func (x String) Less(than Item) bool { 16 | return x < than.(String) 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/peterbourgon/diskv/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2012 Peter Bourgon 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/github.com/peterbourgon/diskv/README.md: -------------------------------------------------------------------------------- 1 | # What is diskv? 2 | 3 | Diskv (disk-vee) is a simple, persistent key-value store written in the Go 4 | language. It starts with an incredibly simple API for storing arbitrary data on 5 | a filesystem by key, and builds several layers of performance-enhancing 6 | abstraction on top. The end result is a conceptually simple, but highly 7 | performant, disk-backed storage system. 8 | 9 | [![Build Status][1]][2] 10 | 11 | [1]: https://drone.io/github.com/peterbourgon/diskv/status.png 12 | [2]: https://drone.io/github.com/peterbourgon/diskv/latest 13 | 14 | 15 | # Installing 16 | 17 | Install [Go 1][3], either [from source][4] or [with a prepackaged binary][5]. 18 | Then, 19 | 20 | ```bash 21 | $ go get github.com/peterbourgon/diskv 22 | ``` 23 | 24 | [3]: http://golang.org 25 | [4]: http://golang.org/doc/install/source 26 | [5]: http://golang.org/doc/install 27 | 28 | 29 | # Usage 30 | 31 | ```go 32 | package main 33 | 34 | import ( 35 | "fmt" 36 | "github.com/peterbourgon/diskv" 37 | ) 38 | 39 | func main() { 40 | // Simplest transform function: put all the data files into the base dir. 41 | flatTransform := func(s string) []string { return []string{} } 42 | 43 | // Initialize a new diskv store, rooted at "my-data-dir", with a 1MB cache. 44 | d := diskv.New(diskv.Options{ 45 | BasePath: "my-data-dir", 46 | Transform: flatTransform, 47 | CacheSizeMax: 1024 * 1024, 48 | }) 49 | 50 | // Write three bytes to the key "alpha". 51 | key := "alpha" 52 | d.Write(key, []byte{'1', '2', '3'}) 53 | 54 | // Read the value back out of the store. 55 | value, _ := d.Read(key) 56 | fmt.Printf("%v\n", value) 57 | 58 | // Erase the key+value from the store (and the disk). 59 | d.Erase(key) 60 | } 61 | ``` 62 | 63 | More complex examples can be found in the "examples" subdirectory. 64 | 65 | 66 | # Theory 67 | 68 | ## Basic idea 69 | 70 | At its core, diskv is a map of a key (`string`) to arbitrary data (`[]byte`). 71 | The data is written to a single file on disk, with the same name as the key. 72 | The key determines where that file will be stored, via a user-provided 73 | `TransformFunc`, which takes a key and returns a slice (`[]string`) 74 | corresponding to a path list where the key file will be stored. The simplest 75 | TransformFunc, 76 | 77 | ```go 78 | func SimpleTransform (key string) []string { 79 | return []string{} 80 | } 81 | ``` 82 | 83 | will place all keys in the same, base directory. The design is inspired by 84 | [Redis diskstore][6]; a TransformFunc which emulates the default diskstore 85 | behavior is available in the content-addressable-storage example. 86 | 87 | [6]: http://groups.google.com/group/redis-db/browse_thread/thread/d444bc786689bde9?pli=1 88 | 89 | **Note** that your TransformFunc should ensure that one valid key doesn't 90 | transform to a subset of another valid key. That is, it shouldn't be possible 91 | to construct valid keys that resolve to directory names. As a concrete example, 92 | if your TransformFunc splits on every 3 characters, then 93 | 94 | ```go 95 | d.Write("abcabc", val) // OK: written to /abc/abc/abcabc 96 | d.Write("abc", val) // Error: attempted write to /abc/abc, but it's a directory 97 | ``` 98 | 99 | This will be addressed in an upcoming version of diskv. 100 | 101 | Probably the most important design principle behind diskv is that your data is 102 | always flatly available on the disk. diskv will never do anything that would 103 | prevent you from accessing, copying, backing up, or otherwise interacting with 104 | your data via common UNIX commandline tools. 105 | 106 | ## Adding a cache 107 | 108 | An in-memory caching layer is provided by combining the BasicStore 109 | functionality with a simple map structure, and keeping it up-to-date as 110 | appropriate. Since the map structure in Go is not threadsafe, it's combined 111 | with a RWMutex to provide safe concurrent access. 112 | 113 | ## Adding order 114 | 115 | diskv is a key-value store and therefore inherently unordered. An ordering 116 | system can be injected into the store by passing something which satisfies the 117 | diskv.Index interface. (A default implementation, using Google's 118 | [btree][7] package, is provided.) Basically, diskv keeps an ordered (by a 119 | user-provided Less function) index of the keys, which can be queried. 120 | 121 | [7]: https://github.com/google/btree 122 | 123 | ## Adding compression 124 | 125 | Something which implements the diskv.Compression interface may be passed 126 | during store creation, so that all Writes and Reads are filtered through 127 | a compression/decompression pipeline. Several default implementations, 128 | using stdlib compression algorithms, are provided. Note that data is cached 129 | compressed; the cost of decompression is borne with each Read. 130 | 131 | ## Streaming 132 | 133 | diskv also now provides ReadStream and WriteStream methods, to allow very large 134 | data to be handled efficiently. 135 | 136 | 137 | # Future plans 138 | 139 | * Needs plenty of robust testing: huge datasets, etc... 140 | * More thorough benchmarking 141 | * Your suggestions for use-cases I haven't thought of 142 | -------------------------------------------------------------------------------- /vendor/github.com/peterbourgon/diskv/compression.go: -------------------------------------------------------------------------------- 1 | package diskv 2 | 3 | import ( 4 | "compress/flate" 5 | "compress/gzip" 6 | "compress/zlib" 7 | "io" 8 | ) 9 | 10 | // Compression is an interface that Diskv uses to implement compression of 11 | // data. Writer takes a destination io.Writer and returns a WriteCloser that 12 | // compresses all data written through it. Reader takes a source io.Reader and 13 | // returns a ReadCloser that decompresses all data read through it. You may 14 | // define these methods on your own type, or use one of the NewCompression 15 | // helpers. 16 | type Compression interface { 17 | Writer(dst io.Writer) (io.WriteCloser, error) 18 | Reader(src io.Reader) (io.ReadCloser, error) 19 | } 20 | 21 | // NewGzipCompression returns a Gzip-based Compression. 22 | func NewGzipCompression() Compression { 23 | return NewGzipCompressionLevel(flate.DefaultCompression) 24 | } 25 | 26 | // NewGzipCompressionLevel returns a Gzip-based Compression with the given level. 27 | func NewGzipCompressionLevel(level int) Compression { 28 | return &genericCompression{ 29 | wf: func(w io.Writer) (io.WriteCloser, error) { return gzip.NewWriterLevel(w, level) }, 30 | rf: func(r io.Reader) (io.ReadCloser, error) { return gzip.NewReader(r) }, 31 | } 32 | } 33 | 34 | // NewZlibCompression returns a Zlib-based Compression. 35 | func NewZlibCompression() Compression { 36 | return NewZlibCompressionLevel(flate.DefaultCompression) 37 | } 38 | 39 | // NewZlibCompressionLevel returns a Zlib-based Compression with the given level. 40 | func NewZlibCompressionLevel(level int) Compression { 41 | return NewZlibCompressionLevelDict(level, nil) 42 | } 43 | 44 | // NewZlibCompressionLevelDict returns a Zlib-based Compression with the given 45 | // level, based on the given dictionary. 46 | func NewZlibCompressionLevelDict(level int, dict []byte) Compression { 47 | return &genericCompression{ 48 | func(w io.Writer) (io.WriteCloser, error) { return zlib.NewWriterLevelDict(w, level, dict) }, 49 | func(r io.Reader) (io.ReadCloser, error) { return zlib.NewReaderDict(r, dict) }, 50 | } 51 | } 52 | 53 | type genericCompression struct { 54 | wf func(w io.Writer) (io.WriteCloser, error) 55 | rf func(r io.Reader) (io.ReadCloser, error) 56 | } 57 | 58 | func (g *genericCompression) Writer(dst io.Writer) (io.WriteCloser, error) { 59 | return g.wf(dst) 60 | } 61 | 62 | func (g *genericCompression) Reader(src io.Reader) (io.ReadCloser, error) { 63 | return g.rf(src) 64 | } 65 | -------------------------------------------------------------------------------- /vendor/github.com/peterbourgon/diskv/index.go: -------------------------------------------------------------------------------- 1 | package diskv 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/google/btree" 7 | ) 8 | 9 | // Index is a generic interface for things that can 10 | // provide an ordered list of keys. 11 | type Index interface { 12 | Initialize(less LessFunction, keys <-chan string) 13 | Insert(key string) 14 | Delete(key string) 15 | Keys(from string, n int) []string 16 | } 17 | 18 | // LessFunction is used to initialize an Index of keys in a specific order. 19 | type LessFunction func(string, string) bool 20 | 21 | // btreeString is a custom data type that satisfies the BTree Less interface, 22 | // making the strings it wraps sortable by the BTree package. 23 | type btreeString struct { 24 | s string 25 | l LessFunction 26 | } 27 | 28 | // Less satisfies the BTree.Less interface using the btreeString's LessFunction. 29 | func (s btreeString) Less(i btree.Item) bool { 30 | return s.l(s.s, i.(btreeString).s) 31 | } 32 | 33 | // BTreeIndex is an implementation of the Index interface using google/btree. 34 | type BTreeIndex struct { 35 | sync.RWMutex 36 | LessFunction 37 | *btree.BTree 38 | } 39 | 40 | // Initialize populates the BTree tree with data from the keys channel, 41 | // according to the passed less function. It's destructive to the BTreeIndex. 42 | func (i *BTreeIndex) Initialize(less LessFunction, keys <-chan string) { 43 | i.Lock() 44 | defer i.Unlock() 45 | i.LessFunction = less 46 | i.BTree = rebuild(less, keys) 47 | } 48 | 49 | // Insert inserts the given key (only) into the BTree tree. 50 | func (i *BTreeIndex) Insert(key string) { 51 | i.Lock() 52 | defer i.Unlock() 53 | if i.BTree == nil || i.LessFunction == nil { 54 | panic("uninitialized index") 55 | } 56 | i.BTree.ReplaceOrInsert(btreeString{s: key, l: i.LessFunction}) 57 | } 58 | 59 | // Delete removes the given key (only) from the BTree tree. 60 | func (i *BTreeIndex) Delete(key string) { 61 | i.Lock() 62 | defer i.Unlock() 63 | if i.BTree == nil || i.LessFunction == nil { 64 | panic("uninitialized index") 65 | } 66 | i.BTree.Delete(btreeString{s: key, l: i.LessFunction}) 67 | } 68 | 69 | // Keys yields a maximum of n keys in order. If the passed 'from' key is empty, 70 | // Keys will return the first n keys. If the passed 'from' key is non-empty, the 71 | // first key in the returned slice will be the key that immediately follows the 72 | // passed key, in key order. 73 | func (i *BTreeIndex) Keys(from string, n int) []string { 74 | i.RLock() 75 | defer i.RUnlock() 76 | 77 | if i.BTree == nil || i.LessFunction == nil { 78 | panic("uninitialized index") 79 | } 80 | 81 | if i.BTree.Len() <= 0 { 82 | return []string{} 83 | } 84 | 85 | btreeFrom := btreeString{s: from, l: i.LessFunction} 86 | skipFirst := true 87 | if len(from) <= 0 || !i.BTree.Has(btreeFrom) { 88 | // no such key, so fabricate an always-smallest item 89 | btreeFrom = btreeString{s: "", l: func(string, string) bool { return true }} 90 | skipFirst = false 91 | } 92 | 93 | keys := []string{} 94 | iterator := func(i btree.Item) bool { 95 | keys = append(keys, i.(btreeString).s) 96 | return len(keys) < n 97 | } 98 | i.BTree.AscendGreaterOrEqual(btreeFrom, iterator) 99 | 100 | if skipFirst && len(keys) > 0 { 101 | keys = keys[1:] 102 | } 103 | 104 | return keys 105 | } 106 | 107 | // rebuildIndex does the work of regenerating the index 108 | // with the given keys. 109 | func rebuild(less LessFunction, keys <-chan string) *btree.BTree { 110 | tree := btree.New(2) 111 | for key := range keys { 112 | tree.ReplaceOrInsert(btreeString{s: key, l: less}) 113 | } 114 | return tree 115 | } 116 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at http://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at http://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 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 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/context/context.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 context defines the Context type, which carries deadlines, 6 | // cancelation signals, and other request-scoped values across API boundaries 7 | // and between processes. 8 | // As of Go 1.7 this package is available in the standard library under the 9 | // name context. https://golang.org/pkg/context. 10 | // 11 | // Incoming requests to a server should create a Context, and outgoing calls to 12 | // servers should accept a Context. The chain of function calls between must 13 | // propagate the Context, optionally replacing it with a modified copy created 14 | // using WithDeadline, WithTimeout, WithCancel, or WithValue. 15 | // 16 | // Programs that use Contexts should follow these rules to keep interfaces 17 | // consistent across packages and enable static analysis tools to check context 18 | // propagation: 19 | // 20 | // Do not store Contexts inside a struct type; instead, pass a Context 21 | // explicitly to each function that needs it. The Context should be the first 22 | // parameter, typically named ctx: 23 | // 24 | // func DoSomething(ctx context.Context, arg Arg) error { 25 | // // ... use ctx ... 26 | // } 27 | // 28 | // Do not pass a nil Context, even if a function permits it. Pass context.TODO 29 | // if you are unsure about which Context to use. 30 | // 31 | // Use context Values only for request-scoped data that transits processes and 32 | // APIs, not for passing optional parameters to functions. 33 | // 34 | // The same Context may be passed to functions running in different goroutines; 35 | // Contexts are safe for simultaneous use by multiple goroutines. 36 | // 37 | // See http://blog.golang.org/context for example code for a server that uses 38 | // Contexts. 39 | package context // import "golang.org/x/net/context" 40 | 41 | // Background returns a non-nil, empty Context. It is never canceled, has no 42 | // values, and has no deadline. It is typically used by the main function, 43 | // initialization, and tests, and as the top-level Context for incoming 44 | // requests. 45 | func Background() Context { 46 | return background 47 | } 48 | 49 | // TODO returns a non-nil, empty Context. Code should use context.TODO when 50 | // it's unclear which Context to use or it is not yet available (because the 51 | // surrounding function has not yet been extended to accept a Context 52 | // parameter). TODO is recognized by static analysis tools that determine 53 | // whether Contexts are propagated correctly in a program. 54 | func TODO() Context { 55 | return todo 56 | } 57 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/context/go17.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 go1.7 6 | 7 | package context 8 | 9 | import ( 10 | "context" // standard library's context, as of Go 1.7 11 | "time" 12 | ) 13 | 14 | var ( 15 | todo = context.TODO() 16 | background = context.Background() 17 | ) 18 | 19 | // Canceled is the error returned by Context.Err when the context is canceled. 20 | var Canceled = context.Canceled 21 | 22 | // DeadlineExceeded is the error returned by Context.Err when the context's 23 | // deadline passes. 24 | var DeadlineExceeded = context.DeadlineExceeded 25 | 26 | // WithCancel returns a copy of parent with a new Done channel. The returned 27 | // context's Done channel is closed when the returned cancel function is called 28 | // or when the parent context's Done channel is closed, whichever happens first. 29 | // 30 | // Canceling this context releases resources associated with it, so code should 31 | // call cancel as soon as the operations running in this Context complete. 32 | func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { 33 | ctx, f := context.WithCancel(parent) 34 | return ctx, CancelFunc(f) 35 | } 36 | 37 | // WithDeadline returns a copy of the parent context with the deadline adjusted 38 | // to be no later than d. If the parent's deadline is already earlier than d, 39 | // WithDeadline(parent, d) is semantically equivalent to parent. The returned 40 | // context's Done channel is closed when the deadline expires, when the returned 41 | // cancel function is called, or when the parent context's Done channel is 42 | // closed, whichever happens first. 43 | // 44 | // Canceling this context releases resources associated with it, so code should 45 | // call cancel as soon as the operations running in this Context complete. 46 | func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { 47 | ctx, f := context.WithDeadline(parent, deadline) 48 | return ctx, CancelFunc(f) 49 | } 50 | 51 | // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). 52 | // 53 | // Canceling this context releases resources associated with it, so code should 54 | // call cancel as soon as the operations running in this Context complete: 55 | // 56 | // func slowOperationWithTimeout(ctx context.Context) (Result, error) { 57 | // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) 58 | // defer cancel() // releases resources if slowOperation completes before timeout elapses 59 | // return slowOperation(ctx) 60 | // } 61 | func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { 62 | return WithDeadline(parent, time.Now().Add(timeout)) 63 | } 64 | 65 | // WithValue returns a copy of parent in which the value associated with key is 66 | // val. 67 | // 68 | // Use context Values only for request-scoped data that transits processes and 69 | // APIs, not for passing optional parameters to functions. 70 | func WithValue(parent Context, key interface{}, val interface{}) Context { 71 | return context.WithValue(parent, key, val) 72 | } 73 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/context/go19.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 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 go1.9 6 | 7 | package context 8 | 9 | import "context" // standard library's context, as of Go 1.7 10 | 11 | // A Context carries a deadline, a cancelation signal, and other values across 12 | // API boundaries. 13 | // 14 | // Context's methods may be called by multiple goroutines simultaneously. 15 | type Context = context.Context 16 | 17 | // A CancelFunc tells an operation to abandon its work. 18 | // A CancelFunc does not wait for the work to stop. 19 | // After the first call, subsequent calls to a CancelFunc do nothing. 20 | type CancelFunc = context.CancelFunc 21 | -------------------------------------------------------------------------------- /vendor/golang.org/x/net/context/pre_go19.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 | // +build !go1.9 6 | 7 | package context 8 | 9 | import "time" 10 | 11 | // A Context carries a deadline, a cancelation signal, and other values across 12 | // API boundaries. 13 | // 14 | // Context's methods may be called by multiple goroutines simultaneously. 15 | type Context interface { 16 | // Deadline returns the time when work done on behalf of this context 17 | // should be canceled. Deadline returns ok==false when no deadline is 18 | // set. Successive calls to Deadline return the same results. 19 | Deadline() (deadline time.Time, ok bool) 20 | 21 | // Done returns a channel that's closed when work done on behalf of this 22 | // context should be canceled. Done may return nil if this context can 23 | // never be canceled. Successive calls to Done return the same value. 24 | // 25 | // WithCancel arranges for Done to be closed when cancel is called; 26 | // WithDeadline arranges for Done to be closed when the deadline 27 | // expires; WithTimeout arranges for Done to be closed when the timeout 28 | // elapses. 29 | // 30 | // Done is provided for use in select statements: 31 | // 32 | // // Stream generates values with DoSomething and sends them to out 33 | // // until DoSomething returns an error or ctx.Done is closed. 34 | // func Stream(ctx context.Context, out chan<- Value) error { 35 | // for { 36 | // v, err := DoSomething(ctx) 37 | // if err != nil { 38 | // return err 39 | // } 40 | // select { 41 | // case <-ctx.Done(): 42 | // return ctx.Err() 43 | // case out <- v: 44 | // } 45 | // } 46 | // } 47 | // 48 | // See http://blog.golang.org/pipelines for more examples of how to use 49 | // a Done channel for cancelation. 50 | Done() <-chan struct{} 51 | 52 | // Err returns a non-nil error value after Done is closed. Err returns 53 | // Canceled if the context was canceled or DeadlineExceeded if the 54 | // context's deadline passed. No other values for Err are defined. 55 | // After Done is closed, successive calls to Err return the same value. 56 | Err() error 57 | 58 | // Value returns the value associated with this context for key, or nil 59 | // if no value is associated with key. Successive calls to Value with 60 | // the same key returns the same result. 61 | // 62 | // Use context values only for request-scoped data that transits 63 | // processes and API boundaries, not for passing optional parameters to 64 | // functions. 65 | // 66 | // A key identifies a specific value in a Context. Functions that wish 67 | // to store values in Context typically allocate a key in a global 68 | // variable then use that key as the argument to context.WithValue and 69 | // Context.Value. A key can be any type that supports equality; 70 | // packages should define keys as an unexported type to avoid 71 | // collisions. 72 | // 73 | // Packages that define a Context key should provide type-safe accessors 74 | // for the values stores using that key: 75 | // 76 | // // Package user defines a User type that's stored in Contexts. 77 | // package user 78 | // 79 | // import "golang.org/x/net/context" 80 | // 81 | // // User is the type of value stored in the Contexts. 82 | // type User struct {...} 83 | // 84 | // // key is an unexported type for keys defined in this package. 85 | // // This prevents collisions with keys defined in other packages. 86 | // type key int 87 | // 88 | // // userKey is the key for user.User values in Contexts. It is 89 | // // unexported; clients use user.NewContext and user.FromContext 90 | // // instead of using this key directly. 91 | // var userKey key = 0 92 | // 93 | // // NewContext returns a new Context that carries value u. 94 | // func NewContext(ctx context.Context, u *User) context.Context { 95 | // return context.WithValue(ctx, userKey, u) 96 | // } 97 | // 98 | // // FromContext returns the User value stored in ctx, if any. 99 | // func FromContext(ctx context.Context) (*User, bool) { 100 | // u, ok := ctx.Value(userKey).(*User) 101 | // return u, ok 102 | // } 103 | Value(key interface{}) interface{} 104 | } 105 | 106 | // A CancelFunc tells an operation to abandon its work. 107 | // A CancelFunc does not wait for the work to stop. 108 | // After the first call, subsequent calls to a CancelFunc do nothing. 109 | type CancelFunc func() 110 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sync/AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at http://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sync/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at http://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sync/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 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 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sync/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sync/errgroup/errgroup.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 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 errgroup provides synchronization, error propagation, and Context 6 | // cancelation for groups of goroutines working on subtasks of a common task. 7 | package errgroup 8 | 9 | import ( 10 | "sync" 11 | 12 | "golang.org/x/net/context" 13 | ) 14 | 15 | // A Group is a collection of goroutines working on subtasks that are part of 16 | // the same overall task. 17 | // 18 | // A zero Group is valid and does not cancel on error. 19 | type Group struct { 20 | cancel func() 21 | 22 | wg sync.WaitGroup 23 | 24 | errOnce sync.Once 25 | err error 26 | } 27 | 28 | // WithContext returns a new Group and an associated Context derived from ctx. 29 | // 30 | // The derived Context is canceled the first time a function passed to Go 31 | // returns a non-nil error or the first time Wait returns, whichever occurs 32 | // first. 33 | func WithContext(ctx context.Context) (*Group, context.Context) { 34 | ctx, cancel := context.WithCancel(ctx) 35 | return &Group{cancel: cancel}, ctx 36 | } 37 | 38 | // Wait blocks until all function calls from the Go method have returned, then 39 | // returns the first non-nil error (if any) from them. 40 | func (g *Group) Wait() error { 41 | g.wg.Wait() 42 | if g.cancel != nil { 43 | g.cancel() 44 | } 45 | return g.err 46 | } 47 | 48 | // Go calls the given function in a new goroutine. 49 | // 50 | // The first call to return a non-nil error cancels the group; its error will be 51 | // returned by Wait. 52 | func (g *Group) Go(f func() error) { 53 | g.wg.Add(1) 54 | 55 | go func() { 56 | defer g.wg.Done() 57 | 58 | if err := f(); err != nil { 59 | g.errOnce.Do(func() { 60 | g.err = err 61 | if g.cancel != nil { 62 | g.cancel() 63 | } 64 | }) 65 | } 66 | }() 67 | } 68 | --------------------------------------------------------------------------------