diff --git a/Makefile b/Makefile index d3e5ad8..7c37890 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ cli: @make cli-lookup + go build -mod vendor -o bin/supersede-gallery cmd/supersede-gallery/main.go cli-lookup: go build -mod vendor -o bin/lookup cmd/lookup/main.go diff --git a/cmd/supersede-gallery/main.go b/cmd/supersede-gallery/main.go new file mode 100644 index 0000000..bc6f3b3 --- /dev/null +++ b/cmd/supersede-gallery/main.go @@ -0,0 +1,125 @@ +// supersede-gallery is a command line tool to clone and supersede an existing gallery record assigning +// updated parent and hierarchy information at the same time. For example: +// $> ./bin/supersede-gallery -architecture-reader-uri repo:///usr/local/build/collection/sfomuseum-data-architecture/ -gallery-id 1763595133 -parent-id 1763588365 +package main + +import ( + "context" + "flag" + sfom_reader "github.com/sfomuseum/go-sfomuseum-reader" + sfom_writer "github.com/sfomuseum/go-sfomuseum-writer" + "github.com/tidwall/gjson" + "github.com/whosonfirst/go-reader" + "github.com/whosonfirst/go-whosonfirst-export/v2" + "github.com/whosonfirst/go-whosonfirst-id" + "github.com/whosonfirst/go-writer" + "log" + +) + +func main() { + + architecture_reader_uri := flag.String("architecture-reader-uri", "repo:///usr/local/data/sfomuseum-data-architecture", "") + architecture_writer_uri := flag.String("architecture-writer-uri", "", "If empty, the value of the -architecture-reader-uri flag will be used.") + + gallery_id := flag.Int64("gallery-id", 0, "The SFO Museum gallery ID to supersede") + parent_id := flag.Int64("parent-id", 0, "The SFO Museum parent ID of the new gallery") + + name := flag.String("name", "", "An optional name for the new gallery. If empty the name of the previous gallery will be used.") + map_id := flag.String("map_id", "", "An optional map ID for the new gallery. If empty the name of the previous gallery will be used.") + + flag.Parse() + + ctx := context.Background() + + if *architecture_writer_uri == "" { + *architecture_writer_uri = *architecture_reader_uri + } + + arch_r, err := reader.NewReader(ctx, *architecture_reader_uri) + + if err != nil { + log.Fatalf("Failed to create architecture reader, %v", err) + } + + arch_wr, err := writer.NewWriter(ctx, *architecture_writer_uri) + + if err != nil { + log.Fatalf("Failed to create architecture writer, %v", err) + } + + id_provider, err := id.NewProvider(ctx) + + if err != nil { + log.Fatalf("Failed to create ID provider, %v", err) + } + + gallery_f, err := sfom_reader.LoadBytesFromID(ctx, arch_r, *gallery_id) + + if err != nil { + log.Fatalf("Failed to load gallery record, %v", err) + } + + parent_f, err := sfom_reader.LoadBytesFromID(ctx, arch_r, *parent_id) + + if err != nil { + log.Fatalf("Failed to load parent record, %v", err) + } + + new_id, err := id_provider.NewID() + + if err != nil { + log.Fatalf("Failed to create new ID, %v", err) + } + + new_updates := map[string]interface{}{ + "properties.wof:id": new_id, + "properties.wof:parent_id": *parent_id, + "properties.wof:hierarchy": gjson.GetBytes(parent_f, "properties.wof:hierarchy").Value(), + "properties.mz:is_current": gjson.GetBytes(parent_f, "properties.mz:is_current").Value(), + "properties.edtf:inception": gjson.GetBytes(parent_f, "properties.edtf:inception").Value(), + "properties.edtf:cessation": gjson.GetBytes(parent_f, "properties.edtf:cessation").Value(), + "properties.wof:supersedes": []int64{ *gallery_id }, + } + + if *name != "" { + new_updates["properties.wof:name"] = *name + } + + if *map_id != "" { + new_updates["properties.sfomuseum:map_id"] = *map_id + } + + // Create and record the new gallery + + _, new_gallery, err := export.AssignPropertiesIfChanged(ctx, gallery_f, new_updates) + + if err != nil { + log.Fatalf("Failed to export new gallery, %v", err) + } + + _, err = sfom_writer.WriteFeatureBytes(ctx, arch_wr, new_gallery) + + if err != nil { + log.Fatalf("Failed to write new gallery, %v", err) + } + + old_updates := map[string]interface{}{ + "properties.wof:superseded_by": []int64{ new_id }, + } + + // Now update the previous gallery + + _, gallery_f, err = export.AssignPropertiesIfChanged(ctx, gallery_f, old_updates) + + if err != nil { + log.Fatalf("Failed to export new gallery, %v", err) + } + + _, err = sfom_writer.WriteFeatureBytes(ctx, arch_wr, gallery_f) + + if err != nil { + log.Fatalf("Failed to write previous gallery, %v", err) + } + +} diff --git a/go.mod b/go.mod index 489b072..2eae6d3 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,16 @@ require ( github.com/aaronland/go-sqlite v0.1.1 github.com/paulmach/orb v0.5.0 github.com/sfomuseum/go-sfomuseum-reader v0.0.2 + github.com/sfomuseum/go-sfomuseum-writer v0.2.7 github.com/tidwall/gjson v1.14.1 github.com/whosonfirst/go-reader v0.10.0 + github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.2 github.com/whosonfirst/go-whosonfirst-feature v0.0.20 + github.com/whosonfirst/go-whosonfirst-id v0.0.4 github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.2 github.com/whosonfirst/go-whosonfirst-sqlite-features v0.9.4 github.com/whosonfirst/go-whosonfirst-sqlite-features-index v1.4.6 github.com/whosonfirst/go-whosonfirst-sqlite-index/v2 v2.0.1 github.com/whosonfirst/go-whosonfirst-uri v1.2.0 + github.com/whosonfirst/go-writer v0.8.0 ) diff --git a/go.sum b/go.sum index 025c035..2764d92 100644 --- a/go.sum +++ b/go.sum @@ -7,18 +7,56 @@ github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jB github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/aaronland/go-artisanal-integers v0.1.0/go.mod h1:00F0qOpuZZkzWiSSEQYk6Ul1Oc5kwgcYgsfYRmuR+wY= +github.com/aaronland/go-artisanal-integers v0.1.1 h1:bLQmWqcqgPT1NOJFwJtZZ9O/QTnttO54ODiWIVuOW1Y= +github.com/aaronland/go-artisanal-integers v0.1.1/go.mod h1:ZTeFI+Ck+q+Dp11Htld5aU6V+YwEzxzprsBO0t9GPp8= +github.com/aaronland/go-artisanal-integers-proxy v0.2.0/go.mod h1:7Pkt553bRIgRMzkyPzPzvPDweCxMG6wx96qMBLlCk/Y= +github.com/aaronland/go-artisanal-integers-proxy v0.2.5 h1:jkQ0p8TLCTPFH8rqFqYWMu3Qzr5ZzZWT9KhehzT091k= +github.com/aaronland/go-artisanal-integers-proxy v0.2.5/go.mod h1:mldeud4G0Yn4a+VKZ+CHrg5mw3u5OIOok25q5OKsOrM= +github.com/aaronland/go-brooklynintegers-api v1.0.2/go.mod h1:JlR7i6vciy3W0aMnid7cN/Ls9Pz/vaq1lNj9sCENQf0= +github.com/aaronland/go-brooklynintegers-api v1.1.0/go.mod h1:agceH8JW8PcdHGCyKEDmOntccB3m7xUKrUejHpxAs6U= +github.com/aaronland/go-brooklynintegers-api v1.2.1/go.mod h1:vFyhY89Uc0LDZEaEam5EQ+2La2VlkTvSfExuZgZhmX4= +github.com/aaronland/go-brooklynintegers-api v1.2.4 h1:KcRWO9kWTL6iNmZVTdPZVo7ngN0O9FFTKoQrFSjPMsU= +github.com/aaronland/go-brooklynintegers-api v1.2.4/go.mod h1:hNUn5nueKQM23ptExy20p5qDpRPhWg8RbjwW2BuXWmw= github.com/aaronland/go-json-query v0.1.1/go.mod h1:lZHt3LmcrZ0bovlqvr1jQaQKJKpb2pMLN2er6RGHAIQ= github.com/aaronland/go-json-query v0.1.2 h1:+yJBCJk9kcRAzbErhh+zOqK3DHSs/GmuSqXcCn5yH/c= github.com/aaronland/go-json-query v0.1.2/go.mod h1:kkCl5KrO+fVSL2M8b/i3qO5PsnCpmajGXkbJHpEQPY8= +github.com/aaronland/go-londonintegers-api v0.1.0/go.mod h1:E0VIcwks+So4FL1FYAQzrO5/OVOUsFPsqW85UrZArSE= +github.com/aaronland/go-londonintegers-api v0.1.1/go.mod h1:N7Y0jrx+ouRAMrFcdH4nvJH6vrszj8/3yOOe0F8EV1E= +github.com/aaronland/go-missionintegers-api v0.1.0/go.mod h1:LZEM5+MkPX5RehLxTEv+3Y3cqMSYEk86qBa+aVecnKw= +github.com/aaronland/go-missionintegers-api v0.1.1 h1:zn6ohxxdUp3UXD8kv7ZXceS6CbGemtyDjvMT1VLezKI= +github.com/aaronland/go-missionintegers-api v0.1.1/go.mod h1:CvByrizvklOxK6QD+Z4RNqACxHqqVjiB/GdWQfrB4Mc= +github.com/aaronland/go-pool v0.0.0-20191128211702-88306299c758/go.mod h1:hL9EPOZJ6WVHaz7D0Jw1Dn1vaCOOSZNrYBTKMgDKYRk= +github.com/aaronland/go-pool v1.0.0 h1:RupGLoRO5EHzPZ08zZgiLeDXPhErUAtPonzVLM2D6yM= +github.com/aaronland/go-pool v1.0.0/go.mod h1:5EzZAfp1v2N+EyyGQ3868fxNxBL5+b4OUmVgnJZpMFo= +github.com/aaronland/go-roster v0.0.1/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= github.com/aaronland/go-roster v0.0.2 h1:2Fu7v4VQLRLRL/Zgr6R9S5JxsW75Ab/K88QtMVX532s= github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= github.com/aaronland/go-sqlite v0.1.0/go.mod h1:/Q4BWbsdgHtQY+99oxaeCj4TwGc8qyAN8CUyF2JK0xg= github.com/aaronland/go-sqlite v0.1.1 h1:bqObBiGw3K01Nq9Zt2NtFTESHSoNVd5ZaLc+FYVivhI= github.com/aaronland/go-sqlite v0.1.1/go.mod h1:EoqGJ9v4WGF9Gwln7g6b0ANsIED2sBit7p4VMtnD/yU= +github.com/aaronland/go-string v0.1.1/go.mod h1:2aMIWdTqk63jZsaLLy+p9dsB1MDRqx4sHYoLtkwyYUo= +github.com/aaronland/go-string v0.1.2 h1:RSr/mQNbLgF37H0RV+nF7j2kILRRFkCmr8Jwq4lw92k= +github.com/aaronland/go-string v0.1.2/go.mod h1:2aMIWdTqk63jZsaLLy+p9dsB1MDRqx4sHYoLtkwyYUo= +github.com/aaronland/go-uid v0.0.2/go.mod h1:Kb/J05tYHWxp+Dkpod+oRkBKnxyw+szODwIQKIjvhj0= +github.com/aaronland/go-uid v0.0.3 h1:MIcdw+Jp8tVx+m9wrExxl2y8l5KbzsTTOUCDNOnNRnk= +github.com/aaronland/go-uid v0.0.3/go.mod h1:VccCcqEWQgE9fr42fwnWIPBRMQlN1Yx+GLUQBPR3xNA= +github.com/aaronland/go-uid-artisanal v0.0.0-20191128230022-67bc446aa49d/go.mod h1:/fkI7C9H/GTB/TlLmNsKjHoNyXnYlkb/iG4Qp3tSCmE= +github.com/aaronland/go-uid-artisanal v0.0.1 h1:WRDDfSO7vqWnkMYFCYEjU2TCs6csDuBHoo7o/jDOcWE= +github.com/aaronland/go-uid-artisanal v0.0.1/go.mod h1:WbAHDcfpYJ673t5kXgZn0zH7XiBjoLdvOMgngVQpCcg= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/akrylysov/algnhsa v0.0.0-20190319020909-05b3d192e9a7/go.mod h1:HhzjNA0EjUWcwHTUMwqrpeAdIF3gRmpH0HpWx1hYJSc= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/aws/aws-lambda-go v1.9.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A= +github.com/aws/aws-lambda-go v1.10.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -28,6 +66,8 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/g8rswimmer/error-chain v1.0.0 h1:WnwnunlvqtGPHVHmBfbmUyAgrtag8Y6nNpwLWmtSYOQ= +github.com/g8rswimmer/error-chain v1.0.0/go.mod h1:XPJ/brUsL7yzc5VRlIxtf9GvoUqnOKVI9fg2MB5DWx8= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= @@ -73,6 +113,8 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mmcloughlin/geohash v0.10.0 h1:9w1HchfDfdeLc+jFEf/04D27KP7E2QmpDu52wPbJWRE= github.com/mmcloughlin/geohash v0.10.0/go.mod h1:oNZxQo5yWJh0eMQEP/8hwQuVx9Z9tjwFUqcTB1SmG0c= +github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= +github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -91,15 +133,20 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sfomuseum/go-edtf v0.2.2/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= github.com/sfomuseum/go-edtf v0.2.3/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= github.com/sfomuseum/go-edtf v0.3.1 h1:22DEXVvGhnpF7PD4dvpgKH0/oD8u9I+a4cXCwy1x2f4= github.com/sfomuseum/go-edtf v0.3.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= github.com/sfomuseum/go-flags v0.7.0/go.mod h1:ML3DTNbF9xnjExSdS/9FtVLjIUhRU5gm/ehzISv+t2w= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.6 h1:EF3N7AyGTDxo/yoXFhLnY/I0qH/g5DjVS1QMzasxOf8= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.6/go.mod h1:WWJDFbaouciMMx7+70FkC/iyxum9ElV8TvcBPNDOgLE= github.com/sfomuseum/go-sfomuseum-geojson v0.1.3 h1:+OyduTQhBgVajdXFqXbX1hxuYY4IK56nYvaI/xtuPcY= github.com/sfomuseum/go-sfomuseum-geojson v0.1.3/go.mod h1:s9/XT2coL6uShnA1reWOfBSOMJsDIERERxdVZQkQQjI= github.com/sfomuseum/go-sfomuseum-reader v0.0.2 h1:S1h8jUUGegWYCcF5tbX2E2rSji4y6W4HWG3bNGyG9XM= github.com/sfomuseum/go-sfomuseum-reader v0.0.2/go.mod h1:ixmpeo1E4fHGiXPBxC+DQ1fpY+5suZHpZveyA0OrBUE= +github.com/sfomuseum/go-sfomuseum-writer v0.2.7 h1:ng+8lN13O7ckCJI5hZR4tDSvgYV3nNAAgTLiT76nkds= +github.com/sfomuseum/go-sfomuseum-writer v0.2.7/go.mod h1:hqk8Tgx/NTDskkSHRohbAX/cJ7gmrRDGd4DIof4Q7pA= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/skelterjohn/geom v0.0.0-20180103142417-96f3e8a219c5 h1:qQF/q/+xaKD4CAVz3zfuvpij8U4ihSGIhHfOROI4NFc= @@ -110,28 +157,39 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/gjson v1.2.1/go.mod h1:c/nTNbUr0E0OrXEhq1pwa8iEgc2DOt4ZZqAt1HtCkPA= +github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo= github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc= +github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= github.com/twpayne/go-geom v1.4.1 h1:LeivFqaGBRfyg0XJJ9pkudcptwhSSrYN9KZUW6HcgdA= github.com/twpayne/go-geom v1.4.1/go.mod h1:k/zktXdL+qnA6OgKsdEGUTA17jbQ2ZPTUa3CCySuGpE= github.com/twpayne/go-kml v1.5.2/go.mod h1:kz8jAiIz6FIdU2Zjce9qGlVtgFYES9vt7BTPBHf5jl4= github.com/twpayne/go-polyline v1.0.0/go.mod h1:ICh24bcLYBX8CknfvNPKqoTbe+eg+MX1NPyJmSBo7pU= github.com/twpayne/go-waypoint v0.0.0-20200706203930-b263a7f6e4e8/go.mod h1:qj5pHncxKhu9gxtZEYWypA/z097sxhFlbTyOyt9gcnU= +github.com/whosonfirst/algnhsa v0.1.0/go.mod h1:swLBXxaVTv3s6dJLhekdQCuCTshUew+xHjptRC21RG0= github.com/whosonfirst/go-ioutil v1.0.0/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= github.com/whosonfirst/go-ioutil v1.0.1 h1:xITnQgEGdG+Qlph7jPY5htL7UpPSm2wEw1WiUlKTWPc= github.com/whosonfirst/go-ioutil v1.0.1/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= @@ -144,17 +202,25 @@ github.com/whosonfirst/go-rfc-5646 v0.1.0/go.mod h1:JZj//FV9YeV3fkyOY/82V53EMLQX github.com/whosonfirst/go-whosonfirst-cli v0.1.0/go.mod h1:Edy+amD+fMq1QS1yxB3u8maA8I93q/LG7JRNh+fsdfc= github.com/whosonfirst/go-whosonfirst-crawl v0.2.1 h1:nNG7r7/4MaII/NM8Df2oqgfgVNBDoIKlseleoX1vw1Q= github.com/whosonfirst/go-whosonfirst-crawl v0.2.1/go.mod h1:MTD1TCgAkXlAtysPU98ylrz9Y5+ZCfRrsrBnRyiH/t8= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.1/go.mod h1:ZT5g5W34H4ymvxkSQXNJ+DPSl61J+u/5/uS9QxRLiPw= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.2 h1:7VK59x+khENOtu9V0qfpObAHbfFq6j67k/GFTzbjC+0= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.2/go.mod h1:ruEZ8HfXvc+krTXc4SdykS/c/benSEXSQekfZ+rnFjI= github.com/whosonfirst/go-whosonfirst-feature v0.0.20 h1:6sMgbNvM9/PEFHB5LyDajdlCaYNT/1Uf4bxCIlUFFAE= github.com/whosonfirst/go-whosonfirst-feature v0.0.20/go.mod h1:nCozCejA/5uCPLZjsSXOv6CLnm63U+QQJtkCafXIdBY= github.com/whosonfirst/go-whosonfirst-flags v0.2.0/go.mod h1:ECd0AJJZIlybmjTGB9z+CPz9pSiMTwxur7fPKmDnoqI= github.com/whosonfirst/go-whosonfirst-flags v0.4.2/go.mod h1:kewFjxBiE00SqjjIanm5DPI81SYvx93wVb3ogwV/PMk= github.com/whosonfirst/go-whosonfirst-flags v0.4.3 h1:ef6IkgvYADL4kc750sl6i5hkReNq0Z6upLcqpK2CHLY= github.com/whosonfirst/go-whosonfirst-flags v0.4.3/go.mod h1:pL17Ryo60FH8RYaQRgfu5XnxhrNRK3x+rn03TYD6Gc8= +github.com/whosonfirst/go-whosonfirst-format v0.3.7 h1:SkiUt2s0LqvH5JP7586+Rz7SgKwtRoFt7aGfWFFemoI= +github.com/whosonfirst/go-whosonfirst-format v0.3.7/go.mod h1:lMBIXCnD9ZA+wCNtu6XFYoq5DTfnEALO8k6OkEn11MM= github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.16.3/go.mod h1:R3GximAGJWLCITU2eh3I5Vtyze/usjOl5LTGQCDI89Y= github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.16.4 h1:5FVbXC6PvohoxFAd2fXanmERwFjz9ExJIoj4mC+AAwM= github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.16.4/go.mod h1:nlnmDlcm3OjkKBihOIGdzWW8fSpR+ubD3JUSXLLG5y4= github.com/whosonfirst/go-whosonfirst-hash v0.1.0 h1:FpnclPIb+8M1uhSXfl3z8nYcG/3O59vgfkdV+m0hQpA= github.com/whosonfirst/go-whosonfirst-hash v0.1.0/go.mod h1:1ZdCFZTnQt5bwnsj2daB9yHilKOKToVh+Tyj/Z8TbUk= +github.com/whosonfirst/go-whosonfirst-id v0.0.3/go.mod h1:JuDIBvv0gzygE83XjX8Ym7JnX6OTO1X1efikSwTh8Ic= +github.com/whosonfirst/go-whosonfirst-id v0.0.4 h1:Vhvo4qUjQCrM9r1E37DY3lHhbJJE5UazxcmTFAdqQVU= +github.com/whosonfirst/go-whosonfirst-id v0.0.4/go.mod h1:APHWvXV+DOqANgD1Lq615oJpLtdRjKdVV5cV7OgzER0= github.com/whosonfirst/go-whosonfirst-iterate-git/v2 v2.1.0/go.mod h1:okSGTdAZsnR1zvNow9VwtSn1hmbgEZhNc7EymHaEFRU= github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.1/go.mod h1:oGk1jhZiP1Hfe4QVQAMAVCkTTjxlr5/hrzk/xfxWVss= github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.2 h1:IJ4o6/I0+yfedzv/dy3SPENbxibwxil8ve1URPPGKv8= @@ -166,6 +232,7 @@ github.com/whosonfirst/go-whosonfirst-names v0.1.0/go.mod h1:0z86/nedM9T/5C8cAdb github.com/whosonfirst/go-whosonfirst-placetypes v0.2.4/go.mod h1:yl0zZ5tfK80C0kl34pJcPB3mZC5XXR7ybQJ5OJyEcDU= github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0 h1:68kuizK8FXjfEIOKlqWemhs7gyMBIgpLJDbCZF8+8Ok= github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0/go.mod h1:ez0VFkGFbgT2/z2oi3PIuW6FewsZ2+5glyfDD79XEHk= +github.com/whosonfirst/go-whosonfirst-pool v0.1.0/go.mod h1:6LeQYv7hVK16LVevMuOuaLRfgI3JDtaoVxaMMVqRS38= github.com/whosonfirst/go-whosonfirst-sources v0.1.0 h1:JuKLa6KWke22jBfJ1pM9WQHoz1/3pbDv2C+aR+THPPQ= github.com/whosonfirst/go-whosonfirst-sources v0.1.0/go.mod h1:EUMHyGzUmqPPxlMmOp+28BFeoBdxxE0HCKRd67lkqGM= github.com/whosonfirst/go-whosonfirst-spr/v2 v2.0.0 h1:UQ1n/uODS50mckZpXYe5GKm8XwoUUC1jRcNN8oiW2uc= @@ -182,6 +249,8 @@ github.com/whosonfirst/go-whosonfirst-uri v1.0.1/go.mod h1:8eaDVcc4v+HHHEDaRbApd github.com/whosonfirst/go-whosonfirst-uri v1.1.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= github.com/whosonfirst/go-whosonfirst-uri v1.2.0 h1:lhmRsIhcpTr5HAo+kXKRGsSt76HTh3Ko/oTR2jpCm/o= github.com/whosonfirst/go-whosonfirst-uri v1.2.0/go.mod h1:CuVygTCUpMG945MMvqHyqxvc/L5YkDaMrrVpRFr7ZxY= +github.com/whosonfirst/go-writer v0.8.0 h1:Tgibn65KrLqfC5YSIxZfXNsNFdk8bvP3/LpqbERU0FY= +github.com/whosonfirst/go-writer v0.8.0/go.mod h1:Qj0rZgdoFagSJ1xwhm60KyTgMU4DK5C6q5n8zKpgnj8= github.com/whosonfirst/walk v0.0.1 h1:t0QrqGwOdPMSeovFZSXfiS0GIGHrRXK3Wb9z5Uhs2bg= github.com/whosonfirst/walk v0.0.1/go.mod h1:1KtP/VeooSlFOI61p+THc/C16Ra8Z5MjpjI0tsd3c1M= github.com/whosonfirst/warning v0.1.1 h1:h29zL3VNL9VUHztkAAndzblhrDHyik9z47OuUR2Vovw= @@ -189,6 +258,12 @@ github.com/whosonfirst/warning v0.1.1/go.mod h1:/unEMzhB9YaMeEwTJpzLN3kM5LiSxdJh github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/ratelimit v0.1.0/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= +go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= +go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -196,6 +271,7 @@ golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -226,8 +302,10 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= diff --git a/vendor/github.com/aaronland/go-artisanal-integers-proxy/LICENSE b/vendor/github.com/aaronland/go-artisanal-integers-proxy/LICENSE new file mode 100644 index 0000000..bcd5b50 --- /dev/null +++ b/vendor/github.com/aaronland/go-artisanal-integers-proxy/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2018, Aaron Straup Cope +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/aaronland/go-artisanal-integers-proxy/service/proxy.go b/vendor/github.com/aaronland/go-artisanal-integers-proxy/service/proxy.go new file mode 100644 index 0000000..8b885dc --- /dev/null +++ b/vendor/github.com/aaronland/go-artisanal-integers-proxy/service/proxy.go @@ -0,0 +1,263 @@ +package service + +import ( + "context" + "errors" + "github.com/aaronland/go-artisanal-integers" + "github.com/aaronland/go-pool" + "github.com/whosonfirst/go-whosonfirst-log" + "math/rand" + "sync" + "time" +) + +var r *rand.Rand + +func init() { + + r = rand.New(rand.NewSource(time.Now().UnixNano())) +} + +type ProxyServiceOptions struct { + Pool pool.Pool + Minimum int + Logger *log.WOFLogger + Workers int +} + +func DefaultProxyServiceOptions() (*ProxyServiceOptions, error) { + + ctx := context.Background() + pl, err := pool.NewPool(ctx, "memory://") + + if err != nil { + return nil, err + } + + logger := log.NewWOFLogger() + + opts := ProxyServiceOptions{ + Pool: pl, + Logger: logger, + Minimum: 10, + Workers: 0, + } + + return &opts, nil +} + +type ProxyService struct { + artisanalinteger.Service + artisanalinteger.Client + options *ProxyServiceOptions + clients []artisanalinteger.Client + refill chan bool +} + +func NewProxyService(opts *ProxyServiceOptions, clients ...artisanalinteger.Client) (artisanalinteger.Service, error) { + + if len(clients) == 0 { + return nil, errors.New("Insuffient clients") + } + + // See notes in RefillPool() for details + + size := opts.Minimum + refill := make(chan bool, size) + + for i := 0; i < size; i++ { + refill <- true + } + + // Possibly also keep global stats on number of fetches + // and cache hits/misses/etc + + p := &ProxyService{ + options: opts, + clients: clients, + refill: refill, + } + + go p.refillPool() + go p.status() + go p.monitor() + + return p, nil +} + +func (p *ProxyService) status() { + + for { + select { + case <-time.After(5 * time.Second): + p.options.Logger.Status("pool length: %d", p.options.Pool.Length()) + } + } +} + +func (p *ProxyService) monitor() { + + for { + select { + case <-time.After(10 * time.Second): + if p.options.Pool.Length() < int64(p.options.Minimum) { + go p.refillPool() + } + } + + } +} + +func (p *ProxyService) refillPool() { + + // Remember there is a fixed size work queue of allowable times to try + // and refill the pool simultaneously. First, we block until a slot opens + // up. + + <-p.refill + + t1 := time.Now() + + // Figure out how many integers we need to get *at this moment* which when + // the service is under heavy load is a misleading number at best. It might + // be worth adjusting this by a factor of (n) depending on the current load. + // But that also means tracking what we think the current load means so we + // aren't going to do that now... + + todo := int64(p.options.Minimum) - p.options.Pool.Length() + + workers := p.options.Workers + + if workers == 0 { + workers = int(p.options.Minimum / 2) + } + + if workers == 0 { + workers = 1 + } + + // Now we're going to set up two simultaneous queues. One (the work group) is + // just there to keep track of all the requests for new integers we need to + // make. The second (the throttle) is there to make sure we don't exhaust all + // the filehandles or network connections. + + th := make(chan bool, workers) + + for i := 0; i < workers; i++ { + th <- true + } + + wg := new(sync.WaitGroup) + + p.options.Logger.Debug("refill poll w/ %d integers and %d workers", todo, workers) + + success := 0 + failed := 0 + + for j := 0; int64(j) < todo; j++ { + + // Wait for the throttle to open a slot. Also record whether + // the operation was successful. + + rsp := <-th + + if rsp == true { + success += 1 + } else { + failed += 1 + } + + // First check that we still actually need to keep fetching integers + + if p.options.Pool.Length() >= int64(p.options.Minimum) { + p.options.Logger.Debug("pool is full (%d) stopping after %d iterations", p.options.Pool.Length(), j) + break + } + + // Standard work group stuff + + wg.Add(1) + + // Sudo make me a sandwitch. Note the part where we ping the throttle with + // the return value at the end both to signal an available slot and to record + // whether the integer harvesting was successful. + + go func(pr *ProxyService) { + defer wg.Done() + th <- pr.addToPool() + }(p) + } + + // More standard work group stuff + + wg.Wait() + + // Again note the way we are freeing a spot in the refill queue + + p.refill <- true + + t2 := time.Since(t1) + p.options.Logger.Info("time to refill the pool with %d integers (success: %d failed: %d): %v (pool length is now %d)", todo, success, failed, t2, p.options.Pool.Length()) + +} + +func (p *ProxyService) addToPool() bool { + + i, err := p.getInteger() + + if err != nil { + return false + } + + pi := pool.NewIntItem(i) + + p.options.Pool.Push(pi) + return true +} + +func (p *ProxyService) getInteger() (int64, error) { + + idx := r.Intn(len(p.clients)) + + cl := p.clients[idx] // round-robin me or something... + + i, err := cl.NextInt() + + if err != nil { + p.options.Logger.Error("failed to create new integer, because %v", err) + return 0, err + } + + p.options.Logger.Debug("got new integer %d", i) + return i, nil +} + +func (p *ProxyService) NextInt() (int64, error) { + + if p.options.Pool.Length() == 0 { + + go p.refillPool() + + p.options.Logger.Warning("pool length is 0 so fetching integer from source") + return p.getInteger() + } + + v, ok := p.options.Pool.Pop() + + if !ok { + p.options.Logger.Error("failed to pop integer!") + + go p.refillPool() + return p.getInteger() + } + + i := v.Int() + + p.options.Logger.Debug("return cached integer %d", i) + + return i, nil +} + +func (p *ProxyService) LastInt() (int64, error) { + return -1, errors.New("Please write me") +} diff --git a/vendor/github.com/aaronland/go-artisanal-integers/.gitignore b/vendor/github.com/aaronland/go-artisanal-integers/.gitignore new file mode 100644 index 0000000..126dc03 --- /dev/null +++ b/vendor/github.com/aaronland/go-artisanal-integers/.gitignore @@ -0,0 +1,5 @@ +*~ +pkg +src +!vendor/src +bin diff --git a/vendor/github.com/aaronland/go-artisanal-integers/LICENSE b/vendor/github.com/aaronland/go-artisanal-integers/LICENSE new file mode 100644 index 0000000..605a7ad --- /dev/null +++ b/vendor/github.com/aaronland/go-artisanal-integers/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2016, Aaron Straup Cope +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/aaronland/go-artisanal-integers/Makefile b/vendor/github.com/aaronland/go-artisanal-integers/Makefile new file mode 100644 index 0000000..28f5261 --- /dev/null +++ b/vendor/github.com/aaronland/go-artisanal-integers/Makefile @@ -0,0 +1,16 @@ +fmt: + go fmt *.go + go fmt application/*.go + go fmt client/*.go + go fmt cmd/*.go + go fmt engine/*.go + go fmt http/*.go + go fmt server/*.go + go fmt service/*.go + go fmt utils/*.go + +tools: + if test ! -d bin; then mkdir bin; fi + go build -o bin/int cmd/int/main.go + go build -o bin/intd-client cmd/intd-client/main.go + go build -o bin/intd-server cmd/intd-server/main.go \ No newline at end of file diff --git a/vendor/github.com/aaronland/go-artisanal-integers/README.md b/vendor/github.com/aaronland/go-artisanal-integers/README.md new file mode 100644 index 0000000..ff182ee --- /dev/null +++ b/vendor/github.com/aaronland/go-artisanal-integers/README.md @@ -0,0 +1,81 @@ +# go-artisanal-integers + +No, really. + + +## Install + +You will need to have both `Go` and the `make` programs installed on your computer. Assuming you do just type: + +``` +make tools +``` + +All of this package's dependencies are bundled with the code in the `vendor` directory. + +## Usage + +## Interfaces + +### Client + +``` +type Client interface { + NextInt() (int64, error) +} +``` + +### Engine + +An "engine" is the interface between your code and an underlying data model (typically a database) for minting artisanal integers. The interface looks like this: + +``` +type Engine interface { + NextInt() (int64, error) + LastInt() (int64, error) + SetLastInt(int64) error + SetKey(string) error + SetOffset(int64) error + SetIncrement(int64) error + Close() error +} +``` + +### Service + +``` +type Service interface { + NextInt() (int64, error) + LastInt() (int64, error) +} +``` + +### Server + +``` +type Server interface { + ListenAndServe(Service) error +} +``` + +## Tools + +Everything is in flux. This will be updated soon. + +## Engines + +* https://github.com/aaronland/go-artisanal-integers-mysql +* https://github.com/aaronland/go-artisanal-integers-redis +* https://github.com/aaronland/go-artisanal-integers-rqlite +* https://github.com/aaronland/go-artisanal-integers-summitdb + +## See also + +* http://www.brooklynintegers.com/ +* http://www.londonintegers.com/ +* http://www.neverendingbooks.org/artisanal-integers +* https://nelsonslog.wordpress.com/2012/07/29/artisinal-integers/ +* https://nelsonslog.wordpress.com/2012/08/25/artisinal-integers-part-2/ +* http://www.aaronland.info/weblog/2012/12/01/coffee-and-wifi/#timepixels +* https://mapzen.com/blog/mapzen-acquires-mission-integers/ +* http://code.flickr.net/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-cheap/ diff --git a/vendor/github.com/aaronland/go-artisanal-integers/go.mod b/vendor/github.com/aaronland/go-artisanal-integers/go.mod new file mode 100644 index 0000000..63fb2cb --- /dev/null +++ b/vendor/github.com/aaronland/go-artisanal-integers/go.mod @@ -0,0 +1,5 @@ +module github.com/aaronland/go-artisanal-integers + +go 1.12 + +require github.com/aaronland/go-roster v0.0.1 diff --git a/vendor/github.com/aaronland/go-artisanal-integers/go.sum b/vendor/github.com/aaronland/go-artisanal-integers/go.sum new file mode 100644 index 0000000..35f4751 --- /dev/null +++ b/vendor/github.com/aaronland/go-artisanal-integers/go.sum @@ -0,0 +1,2 @@ +github.com/aaronland/go-roster v0.0.1 h1:r1l4n1HfWvEtOXZvhfXX0Won9Xf6QJsigdUdzOtuy/M= +github.com/aaronland/go-roster v0.0.1/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= diff --git a/vendor/github.com/aaronland/go-artisanal-integers/integer.go b/vendor/github.com/aaronland/go-artisanal-integers/integer.go new file mode 100644 index 0000000..9804a25 --- /dev/null +++ b/vendor/github.com/aaronland/go-artisanal-integers/integer.go @@ -0,0 +1,84 @@ +package artisanalinteger + +import ( + "context" + "github.com/aaronland/go-roster" + "net/url" +) + +var clients roster.Roster + +func ensureClients() error { + + if clients == nil { + + r, err := roster.NewDefaultRoster() + + if err != nil { + return err + } + + clients = r + } + + return nil +} + +func RegisterClient(ctx context.Context, name string, cl Client) error { + + err := ensureClients() + + if err != nil { + return err + } + + return clients.Register(ctx, name, cl) +} + +func NewClient(ctx context.Context, uri string) (Client, error) { + + u, err := url.Parse(uri) + + if err != nil { + return nil, err + } + + scheme := u.Scheme + + i, err := clients.Driver(ctx, scheme) + + if err != nil { + return nil, err + } + + cl := i.(Client) + return cl, nil +} + +type Engine interface { + NextInt() (int64, error) + LastInt() (int64, error) + SetLastInt(int64) error + SetKey(string) error + SetOffset(int64) error + SetIncrement(int64) error + Close() error +} + +type Service interface { + NextInt() (int64, error) + LastInt() (int64, error) +} + +type Server interface { + ListenAndServe(Service) error + Address() string +} + +type Client interface { + NextInt() (int64, error) +} + +type Integer struct { + Integer int64 `json:"integer"` +} diff --git a/vendor/github.com/aaronland/go-brooklynintegers-api/.gitignore b/vendor/github.com/aaronland/go-brooklynintegers-api/.gitignore new file mode 100644 index 0000000..4389d1a --- /dev/null +++ b/vendor/github.com/aaronland/go-brooklynintegers-api/.gitignore @@ -0,0 +1,4 @@ +*~ +pkg +src +!vendor/src diff --git a/vendor/github.com/aaronland/go-brooklynintegers-api/LICENSE b/vendor/github.com/aaronland/go-brooklynintegers-api/LICENSE new file mode 100644 index 0000000..f31cac8 --- /dev/null +++ b/vendor/github.com/aaronland/go-brooklynintegers-api/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2015, Smithsonian Institution +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + Neither the name of the Smithsonian Institution nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/aaronland/go-brooklynintegers-api/Makefile b/vendor/github.com/aaronland/go-brooklynintegers-api/Makefile new file mode 100644 index 0000000..98dc907 --- /dev/null +++ b/vendor/github.com/aaronland/go-brooklynintegers-api/Makefile @@ -0,0 +1,3 @@ +tools: + go build -o bin/int cmd/int/main.go + diff --git a/vendor/github.com/aaronland/go-brooklynintegers-api/README.md b/vendor/github.com/aaronland/go-brooklynintegers-api/README.md new file mode 100644 index 0000000..5edf27a --- /dev/null +++ b/vendor/github.com/aaronland/go-brooklynintegers-api/README.md @@ -0,0 +1,79 @@ +# go-brooklynintegers-api + +Go package for the Brooklyn Integers API. + +## Install + +You will need to have both `Go` and the `make` programs installed on your computer. Assuming you do just type: + +``` +make tools +``` + +All of this package's dependencies are bundled with the code in the `vendor` directory. + +## Usage + +## Simple + +``` +package main + +import ( + "fmt" + "github.com/aaronland/go-brooklynintegers-api" +) + +func main() { + + client := api.NewAPIClient() + i, _ := client.CreateInteger() + + fmt.Println(i) +} +``` + +## Less simple + +``` +import ( + "fmt" + "github.com/aaronland/go-brooklynintegers-api" +) + +func main() { + + client := api.NewAPIClient() + + params := url.Values{} + method := "brooklyn.integers.create" + + rsp, _ := client.ExecuteMethod(method, ¶ms) + i, _ := rsp.Int() + + fmt.Println(i) +} +``` + +## Tools + +### int + +Mint one or more Brooklyn Integers. + +``` +$> ./bin/int -h +Usage of ./bin/int: + -count int + The number of Brooklyn Integers to mint (default 1) +``` + +### proxy-server + +This tool has been moved to the [go-brooklynintegers-proxy](https://github.com/aaronland/go-brooklynintegers-proxy#proxy-server) package. + +## See also + +* http://brooklynintegers.com/ +* http://brooklynintegers.com/api +* https://github.com/aaronland/go-brooklynintegers-proxy diff --git a/vendor/github.com/aaronland/go-brooklynintegers-api/api.go b/vendor/github.com/aaronland/go-brooklynintegers-api/api.go new file mode 100644 index 0000000..12ffd1b --- /dev/null +++ b/vendor/github.com/aaronland/go-brooklynintegers-api/api.go @@ -0,0 +1,203 @@ +package api + +import ( + "context" + "errors" + "fmt" + "github.com/aaronland/go-artisanal-integers" + "github.com/tidwall/gjson" + "go.uber.org/ratelimit" + "io/ioutil" + "log" + "net/http" + "net/url" + "github.com/cenkalti/backoff/v4" +) + +func init() { + ctx := context.Background() + cl := NewAPIClient() + artisanalinteger.RegisterClient(ctx, "brooklynintegers", cl) +} + +// this is basically just so we can preserve backwards compatibility +// even though the artisanalinteger.Client interface is the new new +// (20181210/thisisaaronland) + +type BrooklynIntegersClient interface { + CreateInteger() (int64, error) + ExecuteMethod(string, *url.Values) (*APIResponse, error) +} + +type APIClient struct { + artisanalinteger.Client + BrooklynIntegersClient // see above + isa string + http_client *http.Client + Scheme string + Host string + Endpoint string + rate_limiter ratelimit.Limiter +} + +type APIError struct { + Code int64 + Message string +} + +func (e *APIError) Error() string { + return fmt.Sprintf("[%d] %s", e.Code, e.Message) +} + +type APIResponse struct { + raw []byte +} + +func (rsp *APIResponse) Int() (int64, error) { + + ints := gjson.GetBytes(rsp.raw, "integers.0.integer") + + if !ints.Exists() { + return -1, errors.New("Failed to generate any integers") + } + + i := ints.Int() + return i, nil +} + +func (rsp *APIResponse) Stat() string { + + r := gjson.GetBytes(rsp.raw, "stat") + + if !r.Exists() { + return "" + } + + return r.String() +} + +func (rsp *APIResponse) Ok() (bool, error) { + + stat := rsp.Stat() + + if stat == "ok" { + return true, nil + } + + return false, rsp.Error() +} + +func (rsp *APIResponse) Error() error { + + c := gjson.GetBytes(rsp.raw, "error.code") + m := gjson.GetBytes(rsp.raw, "error.message") + + if !c.Exists() { + return errors.New("Failed to parse error code") + } + + if !m.Exists() { + return errors.New("Failed to parse error message") + } + + err := APIError{ + Code: c.Int(), + Message: m.String(), + } + + return &err +} + +func NewAPIClient() artisanalinteger.Client { + + http_client := &http.Client{} + rl := ratelimit.New(10) // please make this configurable + + return &APIClient{ + Scheme: "https", + Host: "api.brooklynintegers.com", + Endpoint: "rest/", + http_client: http_client, + rate_limiter: rl, + } +} + +func (client *APIClient) CreateInteger() (int64, error) { + return client.NextInt() +} + +func (client *APIClient) NextInt() (int64, error) { + + params := url.Values{} + method := "brooklyn.integers.create" + + var next_id int64 + + cb := func() error { + + rsp, err := client.ExecuteMethod(method, ¶ms) + + if err != nil { + return err + } + + i, err := rsp.Int() + + if err != nil { + log.Println(err) + return err + } + + next_id = i + return nil + } + + bo := backoff.NewExponentialBackOff() + + err := backoff.Retry(cb, bo) + + if err != nil { + return -1, err + } + + return next_id, nil +} + +func (client *APIClient) ExecuteMethod(method string, params *url.Values) (*APIResponse, error) { + + client.rate_limiter.Take() + + url := client.Scheme + "://" + client.Host + "/" + client.Endpoint + + params.Set("method", method) + + req, err := http.NewRequest("POST", url, nil) + + if err != nil { + return nil, err + } + + req.URL.RawQuery = (*params).Encode() + + req.Header.Add("Accept-Encoding", "gzip") + + rsp, err := client.http_client.Do(req) + + if err != nil { + return nil, err + } + + defer rsp.Body.Close() + + body, err := ioutil.ReadAll(rsp.Body) + + if err != nil { + return nil, err + } + + r := APIResponse{ + raw: body, + } + + return &r, nil +} diff --git a/vendor/github.com/aaronland/go-brooklynintegers-api/go.mod b/vendor/github.com/aaronland/go-brooklynintegers-api/go.mod new file mode 100644 index 0000000..3ab1e51 --- /dev/null +++ b/vendor/github.com/aaronland/go-brooklynintegers-api/go.mod @@ -0,0 +1,10 @@ +module github.com/aaronland/go-brooklynintegers-api + +go 1.12 + +require ( + github.com/aaronland/go-artisanal-integers v0.1.1 + github.com/cenkalti/backoff/v4 v4.1.2 + github.com/tidwall/gjson v1.13.0 + go.uber.org/ratelimit v0.2.0 +) diff --git a/vendor/github.com/aaronland/go-brooklynintegers-api/go.sum b/vendor/github.com/aaronland/go-brooklynintegers-api/go.sum new file mode 100644 index 0000000..d362584 --- /dev/null +++ b/vendor/github.com/aaronland/go-brooklynintegers-api/go.sum @@ -0,0 +1,35 @@ +github.com/aaronland/go-artisanal-integers v0.1.1 h1:bLQmWqcqgPT1NOJFwJtZZ9O/QTnttO54ODiWIVuOW1Y= +github.com/aaronland/go-artisanal-integers v0.1.1/go.mod h1:ZTeFI+Ck+q+Dp11Htld5aU6V+YwEzxzprsBO0t9GPp8= +github.com/aaronland/go-roster v0.0.1 h1:r1l4n1HfWvEtOXZvhfXX0Won9Xf6QJsigdUdzOtuy/M= +github.com/aaronland/go-roster v0.0.1/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/gjson v1.8.1 h1:8j5EE9Hrh3l9Od1OIEDAb7IpezNA20UdRngNAj5N0WU= +github.com/tidwall/gjson v1.8.1/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/gjson v1.10.2 h1:APbLGOM0rrEkd8WBw9C24nllro4ajFuJu0Sc9hRz8Bo= +github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M= +github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= +github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8= +github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= +go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/aaronland/go-pool/.gitignore b/vendor/github.com/aaronland/go-pool/.gitignore new file mode 100644 index 0000000..ce65b89 --- /dev/null +++ b/vendor/github.com/aaronland/go-pool/.gitignore @@ -0,0 +1,4 @@ +*~ +src +pkg +bin diff --git a/vendor/github.com/aaronland/go-pool/README.md b/vendor/github.com/aaronland/go-pool/README.md new file mode 100644 index 0000000..a0bda62 --- /dev/null +++ b/vendor/github.com/aaronland/go-pool/README.md @@ -0,0 +1,3 @@ +# go-pool + +A generic LIFO pool derived from Simon Waldherr's [example code](https://github.com/SimonWaldherr/golang-examples/blob/2be89f3185aded00740a45a64e3c98855193b948/advanced/lifo.go). This implementation is safe to use with goroutines. diff --git a/vendor/github.com/aaronland/go-pool/go.mod b/vendor/github.com/aaronland/go-pool/go.mod new file mode 100644 index 0000000..9986fb3 --- /dev/null +++ b/vendor/github.com/aaronland/go-pool/go.mod @@ -0,0 +1,5 @@ +module github.com/aaronland/go-pool + +go 1.12 + +require github.com/aaronland/go-roster v0.0.2 diff --git a/vendor/github.com/aaronland/go-pool/go.sum b/vendor/github.com/aaronland/go-pool/go.sum new file mode 100644 index 0000000..c39f1ac --- /dev/null +++ b/vendor/github.com/aaronland/go-pool/go.sum @@ -0,0 +1,4 @@ +github.com/aaronland/go-roster v0.0.1 h1:r1l4n1HfWvEtOXZvhfXX0Won9Xf6QJsigdUdzOtuy/M= +github.com/aaronland/go-roster v0.0.1/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-roster v0.0.2 h1:2Fu7v4VQLRLRL/Zgr6R9S5JxsW75Ab/K88QtMVX532s= +github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= diff --git a/vendor/github.com/aaronland/go-pool/memory.go b/vendor/github.com/aaronland/go-pool/memory.go new file mode 100644 index 0000000..28df553 --- /dev/null +++ b/vendor/github.com/aaronland/go-pool/memory.go @@ -0,0 +1,72 @@ +package pool + +// https://github.com/SimonWaldherr/golang-examples/blob/2be89f3185aded00740a45a64e3c98855193b948/advanced/lifo.go + +import ( + "context" + "sync" + "sync/atomic" +) + +func init() { + ctx := context.Background() + pl := NewMemoryPool() + Register(ctx, "memory", pl) +} + +type MemoryPool struct { + Pool + nodes []Item + count int64 + mutex *sync.Mutex +} + +func NewMemoryPool() Pool { + + mu := new(sync.Mutex) + nodes := make([]Item, 0) + + pl := &MemoryPool{ + mutex: mu, + nodes: nodes, + count: 0, + } + + return pl +} + +func (pl *MemoryPool) Open(ctx context.Context, uri string) error { + return nil +} + +func (pl *MemoryPool) Length() int64 { + + pl.mutex.Lock() + defer pl.mutex.Unlock() + + return atomic.LoadInt64(&pl.count) +} + +func (pl *MemoryPool) Push(i Item) { + + pl.mutex.Lock() + defer pl.mutex.Unlock() + + pl.nodes = append(pl.nodes[:pl.count], i) + atomic.AddInt64(&pl.count, 1) +} + +func (pl *MemoryPool) Pop() (Item, bool) { + + pl.mutex.Lock() + defer pl.mutex.Unlock() + + if pl.count == 0 { + return nil, false + } + + atomic.AddInt64(&pl.count, -1) + i := pl.nodes[pl.count] + + return i, true +} diff --git a/vendor/github.com/aaronland/go-pool/pool.go b/vendor/github.com/aaronland/go-pool/pool.go new file mode 100644 index 0000000..39a2903 --- /dev/null +++ b/vendor/github.com/aaronland/go-pool/pool.go @@ -0,0 +1,110 @@ +package pool + +import ( + "context" + "github.com/aaronland/go-roster" + "net/url" + "strconv" +) + +var providers roster.Roster + +func ensureRoster() error { + + if providers == nil { + + r, err := roster.NewDefaultRoster() + + if err != nil { + return err + } + + providers = r + } + + return nil +} + +func Register(ctx context.Context, name string, pr Pool) error { + + err := ensureRoster() + + if err != nil { + return err + } + + return providers.Register(ctx, name, pr) +} + +type Pool interface { + Open(context.Context, string) error + Length() int64 + Push(Item) + Pop() (Item, bool) +} + +type Item interface { + String() string + Int() int64 +} + +type Int struct { + Item + int int64 +} + +type String struct { + Item + string string +} + +func NewIntItem(i int64) Item { + return &Int{int: i} +} + +func NewStringItem(s string) Item { + return &String{string: s} +} + +func (i Int) String() string { + return strconv.FormatInt(i.int, 10) +} + +func (i Int) Int() int64 { + return i.int +} + +func (s String) String() string { + return s.string +} + +func (s String) Int() int64 { + return int64(0) +} + +func NewPool(ctx context.Context, uri string) (Pool, error) { + + u, err := url.Parse(uri) + + if err != nil { + return nil, err + } + + scheme := u.Scheme + + i, err := providers.Driver(ctx, scheme) + + if err != nil { + return nil, err + } + + pr := i.(Pool) + + err = pr.Open(ctx, uri) + + if err != nil { + return nil, err + } + + return pr, nil +} diff --git a/vendor/github.com/aaronland/go-string/LICENSE b/vendor/github.com/aaronland/go-string/LICENSE new file mode 100644 index 0000000..2ab38b7 --- /dev/null +++ b/vendor/github.com/aaronland/go-string/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2018, Aaron Straup Cope +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/aaronland/go-string/random/random.go b/vendor/github.com/aaronland/go-string/random/random.go new file mode 100644 index 0000000..63193d1 --- /dev/null +++ b/vendor/github.com/aaronland/go-string/random/random.go @@ -0,0 +1,153 @@ +package random + +import ( + "encoding/base32" + "fmt" + "math/rand" + "strings" + "time" + "unicode" +) + +const min_length int = 32 + +var runes []rune + +var r *rand.Rand + +func init() { + + r = rand.New(rand.NewSource(time.Now().UnixNano())) + + runes = make([]rune, 0) + + codepoints := [][]int{ + []int{1, 255}, // ascii + []int{127744, 128317}, // emoji + } + + for _, r := range codepoints { + + first := r[0] + last := r[1] + + for i := first; i < last; i++ { + + r := rune(i) + + if unicode.IsControl(r) { + continue + } + + if unicode.IsSpace(r) { + continue + } + + if unicode.IsMark(r) { + continue + } + + runes = append(runes, r) + } + } + +} + +type Options struct { + Length int + Chars int + ASCII bool + AlphaNumeric bool + Base32 bool +} + +func DefaultOptions() *Options { + + opts := Options{ + Length: min_length, + Chars: 0, + ASCII: false, + AlphaNumeric: false, + Base32: false, + } + + return &opts +} + +func String(opts *Options) (string, error) { + + count := len(runes) + + result := make([]string, 0) + + var last string + + // chars := 0 + b := 0 + + alpha_numeric := [][]int{ + []int{48, 57}, // (0-9) + []int{65, 90}, // (A-Z) + []int{97, 122}, // (a-z) + } + + for b < opts.Length { + + j := r.Intn(count) + r := runes[j] + + if opts.ASCII && r > 127 { + continue + } + + if opts.AlphaNumeric { + + is_alpha_numeric := false + + for _, bookends := range alpha_numeric { + + r_int := int(r) + + if r_int >= bookends[0] && r_int <= bookends[1] { + is_alpha_numeric = true + break + } + } + + if !is_alpha_numeric { + continue + } + + } + + c := fmt.Sprintf("%c", r) + + if c == last { + continue + } + + last = c + + b += len(c) + + if b <= opts.Length { + result = append(result, c) + } else { + + if len(result) > 2 { + result = result[0 : len(result)-2] + } else { + result = make([]string, 0) + } + b = len(strings.Join(result, "")) + } + } + + s := strings.Join(result, "") + + if opts.Base32 { + s = base32.StdEncoding.EncodeToString([]byte(s)) + } + + return s, nil +} diff --git a/vendor/github.com/aaronland/go-uid-artisanal/.gitignore b/vendor/github.com/aaronland/go-uid-artisanal/.gitignore new file mode 100644 index 0000000..e4e5f6c --- /dev/null +++ b/vendor/github.com/aaronland/go-uid-artisanal/.gitignore @@ -0,0 +1 @@ +*~ \ No newline at end of file diff --git a/vendor/github.com/aaronland/go-uid-artisanal/README.md b/vendor/github.com/aaronland/go-uid-artisanal/README.md new file mode 100644 index 0000000..5e33ad9 --- /dev/null +++ b/vendor/github.com/aaronland/go-uid-artisanal/README.md @@ -0,0 +1,48 @@ +# go-uid-artisanal + +Work in progress. + +## Example + +``` +package main + +import ( + "context" + _ "github.com/aaronland/go-brooklynintegers-api" + "github.com/aaronland/go-uid" + "log" +) + +func main() { + + ctx := context.Background() + + opts := &ArtisanalProviderURIOptions{ + Pool: "memory://", + Minimum: 5, + Clients: []string{ + "brooklynintegers://", + }, + } + + uri, _ := NewArtisanalProviderURI(opts) + str_uri := uri.String() + + // str_uri ends up looking like this: + // artisanal:?client=brooklynintegers%3A%2F%2F&minimum=5&pool=memory%3A%2F%2F + + pr, _ := uid.NewProvider(ctx, str_uri) + id, _ := pr.UID() + + log.Println(id.String()) +} + +``` + +## See also + +* https://github.com/aaronland/go-uid +* https://github.com/aaronland/go-pool +* https://github.com/aaronland/go-artisanal-integers +* https://github.com/aaronland/go-artisanal-integers-proxy/service \ No newline at end of file diff --git a/vendor/github.com/aaronland/go-uid-artisanal/artisanal.go b/vendor/github.com/aaronland/go-uid-artisanal/artisanal.go new file mode 100644 index 0000000..fe84a55 --- /dev/null +++ b/vendor/github.com/aaronland/go-uid-artisanal/artisanal.go @@ -0,0 +1,157 @@ +package artisanal + +import ( + "context" + "errors" + "github.com/aaronland/go-artisanal-integers" + "github.com/aaronland/go-artisanal-integers-proxy/service" + "github.com/aaronland/go-pool" + "github.com/aaronland/go-uid" + _ "log" + "net/url" + "strconv" +) + +func init() { + ctx := context.Background() + pr := NewArtisanalProvider() + uid.RegisterProvider(ctx, "artisanal", pr) +} + +type ArtisanalProviderURIOptions struct { + Minimum int + Pool string + Clients []string +} + +func NewArtisanalProviderURI(opts *ArtisanalProviderURIOptions) (*url.URL, error) { + + _, err := url.Parse(opts.Pool) + + if err != nil { + return nil, err + } + + for _, cl := range opts.Clients { + + _, err := url.Parse(cl) + + if err != nil { + return nil, err + } + } + + q := url.Values{} + q.Set("minimum", strconv.Itoa(opts.Minimum)) + q.Set("pool", opts.Pool) + + q["client"] = opts.Clients + + u := new(url.URL) + u.Scheme = "artisanal" + u.RawQuery = q.Encode() + + return u, nil +} + +type ArtisanalProvider struct { + uid.Provider + proxy artisanalinteger.Service +} + +type ArtisanalUID struct { + uid.UID + // integer artisanalinteger.Integer + integer int64 +} + +func NewArtisanalProvider() uid.Provider { + pr := &ArtisanalProvider{} + return pr +} + +func (pr *ArtisanalProvider) Open(ctx context.Context, uri string) error { + + u, err := url.Parse(uri) + + if err != nil { + return err + } + + q := u.Query() + + clients := make([]artisanalinteger.Client, 0) + + for _, cl_uri := range q["client"] { + + cl, err := artisanalinteger.NewClient(ctx, cl_uri) + + if err != nil { + return err + } + + clients = append(clients, cl) + } + + if len(clients) == 0 { + return errors.New("No artisanal integer clients defined") + } + + pool_uri := q.Get("pool") + + pl, err := pool.NewPool(ctx, pool_uri) + + if err != nil { + return err + } + + str_min := q.Get("minimum") + min, err := strconv.Atoi(str_min) + + if err != nil { + return err + } + + svc_opts, err := service.DefaultProxyServiceOptions() + + if err != nil { + return err + } + + svc_opts.Pool = pl + svc_opts.Minimum = min + + svc, err := service.NewProxyService(svc_opts, clients...) + + if err != nil { + return err + } + + pr.proxy = svc + return nil +} + +func (pr *ArtisanalProvider) UID(...interface{}) (uid.UID, error) { + + i, err := pr.proxy.NextInt() + + if err != nil { + return nil, err + } + + return NewArtisanalUID(i) +} + +func NewArtisanalUID(int int64) (uid.UID, error) { + + u := ArtisanalUID{ + integer: int, + } + + return &u, nil +} + +func (u *ArtisanalUID) String() string { + + return strconv.FormatInt(u.integer, 10) +} diff --git a/vendor/github.com/aaronland/go-uid-artisanal/go.mod b/vendor/github.com/aaronland/go-uid-artisanal/go.mod new file mode 100644 index 0000000..b11f412 --- /dev/null +++ b/vendor/github.com/aaronland/go-uid-artisanal/go.mod @@ -0,0 +1,12 @@ +module github.com/aaronland/go-uid-artisanal + +go 1.12 + +require ( + github.com/aaronland/go-artisanal-integers v0.1.1 + github.com/aaronland/go-artisanal-integers-proxy v0.2.5 + github.com/aaronland/go-brooklynintegers-api v1.2.4 + github.com/aaronland/go-missionintegers-api v0.1.1 + github.com/aaronland/go-pool v1.0.0 + github.com/aaronland/go-uid v0.0.3 +) diff --git a/vendor/github.com/aaronland/go-uid-artisanal/go.sum b/vendor/github.com/aaronland/go-uid-artisanal/go.sum new file mode 100644 index 0000000..1a6f007 --- /dev/null +++ b/vendor/github.com/aaronland/go-uid-artisanal/go.sum @@ -0,0 +1,98 @@ +github.com/aaronland/go-artisanal-integers v0.1.0 h1:WN00aqbjfElOD8dUngFMOdd9wEWW0vyitnOMSRaNqsk= +github.com/aaronland/go-artisanal-integers v0.1.0/go.mod h1:00F0qOpuZZkzWiSSEQYk6Ul1Oc5kwgcYgsfYRmuR+wY= +github.com/aaronland/go-artisanal-integers v0.1.1 h1:bLQmWqcqgPT1NOJFwJtZZ9O/QTnttO54ODiWIVuOW1Y= +github.com/aaronland/go-artisanal-integers v0.1.1/go.mod h1:ZTeFI+Ck+q+Dp11Htld5aU6V+YwEzxzprsBO0t9GPp8= +github.com/aaronland/go-artisanal-integers-proxy v0.1.0 h1:OYJk6iEd3IBpdPOjPaCmF0sN7j6wjKsH65g38lpj4RA= +github.com/aaronland/go-artisanal-integers-proxy v0.1.0/go.mod h1:Dylvjaghl8WY0gA6tOj1YE/X2FXjyDTu9LtAiYXl+oI= +github.com/aaronland/go-artisanal-integers-proxy v0.2.0 h1:3gQznMIWKNXbm3iMVKVC9l7nuZUj3ySUSN889fKlxhQ= +github.com/aaronland/go-artisanal-integers-proxy v0.2.0/go.mod h1:7Pkt553bRIgRMzkyPzPzvPDweCxMG6wx96qMBLlCk/Y= +github.com/aaronland/go-artisanal-integers-proxy v0.2.5 h1:jkQ0p8TLCTPFH8rqFqYWMu3Qzr5ZzZWT9KhehzT091k= +github.com/aaronland/go-artisanal-integers-proxy v0.2.5/go.mod h1:mldeud4G0Yn4a+VKZ+CHrg5mw3u5OIOok25q5OKsOrM= +github.com/aaronland/go-brooklynintegers-api v1.0.1/go.mod h1:aZ4tIFeMdAQRSLZYfGdAiDeBWUHDQkFdqZ9091mk8H8= +github.com/aaronland/go-brooklynintegers-api v1.0.2 h1:qE+CUQTMDUfsTsYU1DWgOW9qLq/RT1a7cMyeATgGpYc= +github.com/aaronland/go-brooklynintegers-api v1.0.2/go.mod h1:JlR7i6vciy3W0aMnid7cN/Ls9Pz/vaq1lNj9sCENQf0= +github.com/aaronland/go-brooklynintegers-api v1.1.0 h1:eyoSZjn3Qiy79H+1rG/HtkEShNBZkPUWs4YKpFWkuD8= +github.com/aaronland/go-brooklynintegers-api v1.1.0/go.mod h1:agceH8JW8PcdHGCyKEDmOntccB3m7xUKrUejHpxAs6U= +github.com/aaronland/go-brooklynintegers-api v1.2.1/go.mod h1:vFyhY89Uc0LDZEaEam5EQ+2La2VlkTvSfExuZgZhmX4= +github.com/aaronland/go-brooklynintegers-api v1.2.4 h1:KcRWO9kWTL6iNmZVTdPZVo7ngN0O9FFTKoQrFSjPMsU= +github.com/aaronland/go-brooklynintegers-api v1.2.4/go.mod h1:hNUn5nueKQM23ptExy20p5qDpRPhWg8RbjwW2BuXWmw= +github.com/aaronland/go-londonintegers-api v0.1.0/go.mod h1:E0VIcwks+So4FL1FYAQzrO5/OVOUsFPsqW85UrZArSE= +github.com/aaronland/go-londonintegers-api v0.1.1/go.mod h1:N7Y0jrx+ouRAMrFcdH4nvJH6vrszj8/3yOOe0F8EV1E= +github.com/aaronland/go-missionintegers-api v0.1.0 h1:huuTG5CaJBye+Eng+kSxbKwm2SBmeM1YMkO6C+eTVbo= +github.com/aaronland/go-missionintegers-api v0.1.0/go.mod h1:LZEM5+MkPX5RehLxTEv+3Y3cqMSYEk86qBa+aVecnKw= +github.com/aaronland/go-missionintegers-api v0.1.1 h1:zn6ohxxdUp3UXD8kv7ZXceS6CbGemtyDjvMT1VLezKI= +github.com/aaronland/go-missionintegers-api v0.1.1/go.mod h1:CvByrizvklOxK6QD+Z4RNqACxHqqVjiB/GdWQfrB4Mc= +github.com/aaronland/go-pool v0.0.0-20191128211702-88306299c758 h1:m/JUyvxsCbgOyhecvs9WXFvZy9dj8BKu4T96J53d/ao= +github.com/aaronland/go-pool v0.0.0-20191128211702-88306299c758/go.mod h1:hL9EPOZJ6WVHaz7D0Jw1Dn1vaCOOSZNrYBTKMgDKYRk= +github.com/aaronland/go-pool v1.0.0 h1:RupGLoRO5EHzPZ08zZgiLeDXPhErUAtPonzVLM2D6yM= +github.com/aaronland/go-pool v1.0.0/go.mod h1:5EzZAfp1v2N+EyyGQ3868fxNxBL5+b4OUmVgnJZpMFo= +github.com/aaronland/go-roster v0.0.1 h1:r1l4n1HfWvEtOXZvhfXX0Won9Xf6QJsigdUdzOtuy/M= +github.com/aaronland/go-roster v0.0.1/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-roster v0.0.2 h1:2Fu7v4VQLRLRL/Zgr6R9S5JxsW75Ab/K88QtMVX532s= +github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-string v0.1.1 h1:btdr18owWCBN14ojKx3p+PBCKfm9qIggYEguPLUb2wE= +github.com/aaronland/go-string v0.1.1/go.mod h1:2aMIWdTqk63jZsaLLy+p9dsB1MDRqx4sHYoLtkwyYUo= +github.com/aaronland/go-string v0.1.2 h1:RSr/mQNbLgF37H0RV+nF7j2kILRRFkCmr8Jwq4lw92k= +github.com/aaronland/go-string v0.1.2/go.mod h1:2aMIWdTqk63jZsaLLy+p9dsB1MDRqx4sHYoLtkwyYUo= +github.com/aaronland/go-uid v0.0.2 h1:5H3wtTBi58lkW5bqbaFR8Hp1MXfcraoJRlxKoUDeVfg= +github.com/aaronland/go-uid v0.0.2/go.mod h1:Kb/J05tYHWxp+Dkpod+oRkBKnxyw+szODwIQKIjvhj0= +github.com/aaronland/go-uid v0.0.3 h1:MIcdw+Jp8tVx+m9wrExxl2y8l5KbzsTTOUCDNOnNRnk= +github.com/aaronland/go-uid v0.0.3/go.mod h1:VccCcqEWQgE9fr42fwnWIPBRMQlN1Yx+GLUQBPR3xNA= +github.com/akrylysov/algnhsa v0.0.0-20190319020909-05b3d192e9a7/go.mod h1:HhzjNA0EjUWcwHTUMwqrpeAdIF3gRmpH0HpWx1hYJSc= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/aws/aws-lambda-go v1.9.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A= +github.com/aws/aws-lambda-go v1.10.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A= +github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/gjson v1.2.1/go.mod h1:c/nTNbUr0E0OrXEhq1pwa8iEgc2DOt4ZZqAt1HtCkPA= +github.com/tidwall/gjson v1.3.5 h1:2oW9FBNu8qt9jy5URgrzsVx/T/KSn3qn/smJQ0crlDQ= +github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M= +github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/whosonfirst/algnhsa v0.1.0/go.mod h1:swLBXxaVTv3s6dJLhekdQCuCTshUew+xHjptRC21RG0= +github.com/whosonfirst/go-whosonfirst-log v0.1.0 h1:mWYI5hn16uyeLxBmPsLSvYV4rQKK/cxGVhM+bC2ZoGc= +github.com/whosonfirst/go-whosonfirst-log v0.1.0/go.mod h1:pmgBbxZSnjGVy2nsUJBBMcFagxwIKLlmRsW7ClkXmac= +github.com/whosonfirst/go-whosonfirst-pool v0.1.0 h1:pwbGycsy/UqK6DJ29tTwnl6wnYYfcaJmsGD+If8un6E= +github.com/whosonfirst/go-whosonfirst-pool v0.1.0/go.mod h1:6LeQYv7hVK16LVevMuOuaLRfgI3JDtaoVxaMMVqRS38= +github.com/whosonfirst/go-whosonfirst-pool-boltdb v0.1.0 h1:qnyzcxqZ07fi/PvKjsLHYV5FMQSRaI569wKIbqZShEs= +github.com/whosonfirst/go-whosonfirst-pool-boltdb v0.1.0/go.mod h1:1pZMCsA7Ml2bPeiywULYJfs2yYS7Ol//pn177FstYmI= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/ratelimit v0.1.0/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= +go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= +go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190516110030-61b9204099cb h1:k07iPOt0d6nEnwXF+kHB+iEg+WSuKe/SOQuFM2QoD+E= +golang.org/x/sys v0.0.0-20190516110030-61b9204099cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/aaronland/go-uid/.gitignore b/vendor/github.com/aaronland/go-uid/.gitignore new file mode 100644 index 0000000..0b4e391 --- /dev/null +++ b/vendor/github.com/aaronland/go-uid/.gitignore @@ -0,0 +1,8 @@ +*~ +pkg +src +!vendor/src +bin +!bin/.gitignore +*.db +.DS_Store diff --git a/vendor/github.com/aaronland/go-uid/Makefile b/vendor/github.com/aaronland/go-uid/Makefile new file mode 100644 index 0000000..95de61c --- /dev/null +++ b/vendor/github.com/aaronland/go-uid/Makefile @@ -0,0 +1,7 @@ +fmt: + go fmt cmd/*.go + go fmt *.go + + +tools: + go build -o bin/uid cmd/uid/main.go \ No newline at end of file diff --git a/vendor/github.com/aaronland/go-uid/README.md b/vendor/github.com/aaronland/go-uid/README.md new file mode 100644 index 0000000..20c4a0b --- /dev/null +++ b/vendor/github.com/aaronland/go-uid/README.md @@ -0,0 +1 @@ +# go-uid diff --git a/vendor/github.com/aaronland/go-uid/go.mod b/vendor/github.com/aaronland/go-uid/go.mod new file mode 100644 index 0000000..2b912a3 --- /dev/null +++ b/vendor/github.com/aaronland/go-uid/go.mod @@ -0,0 +1,8 @@ +module github.com/aaronland/go-uid + +go 1.12 + +require ( + github.com/aaronland/go-roster v0.0.2 + github.com/aaronland/go-string v0.1.2 +) diff --git a/vendor/github.com/aaronland/go-uid/go.sum b/vendor/github.com/aaronland/go-uid/go.sum new file mode 100644 index 0000000..cc1aafb --- /dev/null +++ b/vendor/github.com/aaronland/go-uid/go.sum @@ -0,0 +1,4 @@ +github.com/aaronland/go-roster v0.0.2 h1:2Fu7v4VQLRLRL/Zgr6R9S5JxsW75Ab/K88QtMVX532s= +github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-string v0.1.2 h1:RSr/mQNbLgF37H0RV+nF7j2kILRRFkCmr8Jwq4lw92k= +github.com/aaronland/go-string v0.1.2/go.mod h1:2aMIWdTqk63jZsaLLy+p9dsB1MDRqx4sHYoLtkwyYUo= diff --git a/vendor/github.com/aaronland/go-uid/null.go b/vendor/github.com/aaronland/go-uid/null.go new file mode 100644 index 0000000..bf98a5a --- /dev/null +++ b/vendor/github.com/aaronland/go-uid/null.go @@ -0,0 +1,41 @@ +package uid + +import ( + "context" +) + +func init() { + ctx := context.Background() + pr := NewNullProvider() + RegisterProvider(ctx, "null", pr) +} + +type NullProvider struct { + Provider +} + +type NullUID struct { + UID +} + +func NewNullProvider() Provider { + pr := &NullProvider{} + return pr +} + +func (pr *NullProvider) Open(ctx context.Context, uri string) error { + return nil +} + +func (n *NullProvider) UID(...interface{}) (UID, error) { + return NewNullUID() +} + +func NewNullUID() (UID, error) { + n := &NullUID{} + return n, nil +} + +func (n *NullUID) String() string { + return "" +} diff --git a/vendor/github.com/aaronland/go-uid/random.go b/vendor/github.com/aaronland/go-uid/random.go new file mode 100644 index 0000000..97ebba5 --- /dev/null +++ b/vendor/github.com/aaronland/go-uid/random.go @@ -0,0 +1,44 @@ +package uid + +import ( + "context" + "github.com/aaronland/go-string/random" +) + +func init() { + ctx := context.Background() + pr := NewRandomProvider() + RegisterProvider(ctx, "random", pr) +} + +type RandomProvider struct { + Provider +} + +// type RandomUID is a type StringUID + +func NewRandomProvider() Provider { + pr := &RandomProvider{} + return pr +} + +func (pr *RandomProvider) Open(ctx context.Context, uri string) error { + return nil +} + +func (pr *RandomProvider) UID(...interface{}) (UID, error) { + + opts := random.DefaultOptions() + opts.Length = 16 + opts.Chars = 16 + opts.ASCII = true + opts.AlphaNumeric = true + + s, err := random.String(opts) + + if err != nil { + return nil, err + } + + return NewStringUID(s) +} diff --git a/vendor/github.com/aaronland/go-uid/string.go b/vendor/github.com/aaronland/go-uid/string.go new file mode 100644 index 0000000..24e7914 --- /dev/null +++ b/vendor/github.com/aaronland/go-uid/string.go @@ -0,0 +1,66 @@ +package uid + +import ( + "context" + "errors" + "net/url" +) + +func init() { + ctx := context.Background() + pr := NewStringProvider() + RegisterProvider(ctx, "string", pr) +} + +type StringProvider struct { + Provider + string string +} + +type StringUID struct { + UID + string string +} + +func NewStringProvider() Provider { + pr := &StringProvider{} + return pr +} + +func (pr *StringProvider) Open(ctx context.Context, uri string) error { + + u, err := url.Parse(uri) + + if err != nil { + return err + } + + q := u.Query() + s := q.Get("string") + + if s == "" { + return errors.New("Empty string") + } + + pr.string = s + return nil +} + +func (pr *StringProvider) UID(...interface{}) (UID, error) { + return NewStringUID(pr.string) +} + +func NewStringUID(s string) (UID, error) { + + u := StringUID{ + string: s, + } + + return &u, nil +} + +// where is UID() ? + +func (u *StringUID) String() string { + return u.string +} diff --git a/vendor/github.com/aaronland/go-uid/uid.go b/vendor/github.com/aaronland/go-uid/uid.go new file mode 100644 index 0000000..00baf19 --- /dev/null +++ b/vendor/github.com/aaronland/go-uid/uid.go @@ -0,0 +1,72 @@ +package uid + +import ( + "context" + "github.com/aaronland/go-roster" + "net/url" +) + +var providers roster.Roster + +func ensureRoster() error { + + if providers == nil { + + r, err := roster.NewDefaultRoster() + + if err != nil { + return err + } + + providers = r + } + + return nil +} + +func RegisterProvider(ctx context.Context, name string, pr Provider) error { + + err := ensureRoster() + + if err != nil { + return err + } + + return providers.Register(ctx, name, pr) +} + +func NewProvider(ctx context.Context, uri string) (Provider, error) { + + u, err := url.Parse(uri) + + if err != nil { + return nil, err + } + + scheme := u.Scheme + + i, err := providers.Driver(ctx, scheme) + + if err != nil { + return nil, err + } + + pr := i.(Provider) + + err = pr.Open(ctx, uri) + + if err != nil { + return nil, err + } + + return pr, nil +} + +type Provider interface { + Open(context.Context, string) error + UID(...interface{}) (UID, error) // NOT SURE ABOUT THIS... +} + +type UID interface { + String() string +} diff --git a/vendor/github.com/aaronland/go-uid/ymd.go b/vendor/github.com/aaronland/go-uid/ymd.go new file mode 100644 index 0000000..32c8b49 --- /dev/null +++ b/vendor/github.com/aaronland/go-uid/ymd.go @@ -0,0 +1,65 @@ +package uid + +import ( + "context" + "time" +) + +func init() { + ctx := context.Background() + pr := NewYMDProvider() + RegisterProvider(ctx, "ymd", pr) +} + +type YMDProvider struct { + Provider +} + +type YMDUID struct { + UID + date time.Time +} + +func NewYMDProvider() Provider { + + pr := &YMDProvider{} + return pr +} + +func (pr *YMDProvider) Open(ctx context.Context, uri string) error { + return nil +} + +func (pr *YMDProvider) UID(args ...interface{}) (UID, error) { + + date := time.Now() + + if len(args) == 1 { + + str_date := args[0].(string) + + t, err := time.Parse("20060102", str_date) + + if err != nil { + return nil, err + } + + date = t + } + + return NewYMDUID(date) +} + +func NewYMDUID(date time.Time) (UID, error) { + + u := &YMDUID{ + date: date, + } + + return u, nil +} + +func (u *YMDUID) String() string { + + return u.date.Format("20060102") +} diff --git a/vendor/github.com/andres-erbsen/clock/.travis.yml b/vendor/github.com/andres-erbsen/clock/.travis.yml new file mode 100644 index 0000000..ca785e5 --- /dev/null +++ b/vendor/github.com/andres-erbsen/clock/.travis.yml @@ -0,0 +1,7 @@ +language: go +go: + - 1.3 + - 1.4 + - release + - tip +sudo: false diff --git a/vendor/github.com/andres-erbsen/clock/LICENSE b/vendor/github.com/andres-erbsen/clock/LICENSE new file mode 100644 index 0000000..ddf4e00 --- /dev/null +++ b/vendor/github.com/andres-erbsen/clock/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Ben Johnson, Copyright (c) 2015 Yahoo Inc. + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/vendor/github.com/andres-erbsen/clock/README.md b/vendor/github.com/andres-erbsen/clock/README.md new file mode 100644 index 0000000..f744e76 --- /dev/null +++ b/vendor/github.com/andres-erbsen/clock/README.md @@ -0,0 +1,104 @@ +clock [![Build Status](https://travis-ci.org/andres-erbsen/clock.svg)](https://travis-ci.org/andres-erbsen/clock) [![Coverage Status](https://coveralls.io/repos/andres-erbsen/clock/badge.png?branch=master)](https://coveralls.io/r/andres-erbsen/clock?branch=master) [![GoDoc](https://godoc.org/github.com/andres-erbsen/clock?status.png)](https://godoc.org/github.com/andres-erbsen/clock) ![Project status](http://img.shields.io/status/experimental.png?color=red) +===== + +Clock is a small library for mocking time in Go. It provides an interface +around the standard library's [`time`][time] package so that the application +can use the realtime clock while tests can use the mock clock. + +[time]: http://golang.org/pkg/time/ + + +## Usage + +### Realtime Clock + +Your application can maintain a `Clock` variable that will allow realtime and +mock clocks to be interchangable. For example, if you had an `Application` type: + +```go +import "github.com/andres-erbsen/clock" + +type Application struct { + Clock clock.Clock +} +``` + +You could initialize it to use the realtime clock like this: + +```go +var app Application +app.Clock = clock.New() +... +``` + +Then all timers and time-related functionality should be performed from the +`Clock` variable. + + +### Mocking time + +In your tests, you will want to use a `Mock` clock: + +```go +import ( + "testing" + + "github.com/andres-erbsen/clock" +) + +func TestApplication_DoSomething(t *testing.T) { + mock := clock.NewMock() + app := Application{Clock: mock} + ... +} +``` + +Now that you've initialized your application to use the mock clock, you can +adjust the time programmatically. The mock clock always starts from the Unix +epoch (midnight, Jan 1, 1970 UTC). + + +### Controlling time + +The mock clock provides the same functions that the standard library's `time` +package provides. For example, to find the current time, you use the `Now()` +function: + +```go +mock := clock.NewMock() + +// Find the current time. +mock.Now().UTC() // 1970-01-01 00:00:00 +0000 UTC + +// Move the clock forward. +mock.Add(2 * time.Hour) + +// Check the time again. It's 2 hours later! +mock.Now().UTC() // 1970-01-01 02:00:00 +0000 UTC +``` + +Timers and Tickers are also controlled by this same mock clock. They will only +execute when the clock is moved forward: + +``` +mock := clock.NewMock() +count := 0 + +// Kick off a timer to increment every 1 mock second. +go func() { + ticker := clock.Ticker(1 * time.Second) + for { + <-ticker.C + count++ + } +}() +runtime.Gosched() + +// Move the clock forward 10 second. +mock.Add(10 * time.Second) + +// This prints 10. +fmt.Println(count) +``` + + diff --git a/vendor/github.com/andres-erbsen/clock/clock.go b/vendor/github.com/andres-erbsen/clock/clock.go new file mode 100644 index 0000000..b58b703 --- /dev/null +++ b/vendor/github.com/andres-erbsen/clock/clock.go @@ -0,0 +1,317 @@ +package clock + +import ( + "sort" + "sync" + "time" +) + +// Clock represents an interface to the functions in the standard library time +// package. Two implementations are available in the clock package. The first +// is a real-time clock which simply wraps the time package's functions. The +// second is a mock clock which will only make forward progress when +// programmatically adjusted. +type Clock interface { + After(d time.Duration) <-chan time.Time + AfterFunc(d time.Duration, f func()) *Timer + Now() time.Time + Sleep(d time.Duration) + Tick(d time.Duration) <-chan time.Time + Ticker(d time.Duration) *Ticker + Timer(d time.Duration) *Timer +} + +// New returns an instance of a real-time clock. +func New() Clock { + return &clock{} +} + +// clock implements a real-time clock by simply wrapping the time package functions. +type clock struct{} + +func (c *clock) After(d time.Duration) <-chan time.Time { return time.After(d) } + +func (c *clock) AfterFunc(d time.Duration, f func()) *Timer { + return &Timer{timer: time.AfterFunc(d, f)} +} + +func (c *clock) Now() time.Time { return time.Now() } + +func (c *clock) Sleep(d time.Duration) { time.Sleep(d) } + +func (c *clock) Tick(d time.Duration) <-chan time.Time { return time.Tick(d) } + +func (c *clock) Ticker(d time.Duration) *Ticker { + t := time.NewTicker(d) + return &Ticker{C: t.C, ticker: t} +} + +func (c *clock) Timer(d time.Duration) *Timer { + t := time.NewTimer(d) + return &Timer{C: t.C, timer: t} +} + +// Mock represents a mock clock that only moves forward programmically. +// It can be preferable to a real-time clock when testing time-based functionality. +type Mock struct { + mu sync.Mutex + now time.Time // current time + timers clockTimers // tickers & timers +} + +// NewMock returns an instance of a mock clock. +// The current time of the mock clock on initialization is the Unix epoch. +func NewMock() *Mock { + return &Mock{now: time.Unix(0, 0)} +} + +// Add moves the current time of the mock clock forward by the duration. +// This should only be called from a single goroutine at a time. +func (m *Mock) Add(d time.Duration) { + // Calculate the final current time. + t := m.now.Add(d) + + // Continue to execute timers until there are no more before the new time. + for { + if !m.runNextTimer(t) { + break + } + } + + // Ensure that we end with the new time. + m.mu.Lock() + m.now = t + m.mu.Unlock() + + // Give a small buffer to make sure the other goroutines get handled. + gosched() +} + +// Sets the current time of the mock clock to a specific one. +// This should only be called from a single goroutine at a time. +func (m *Mock) Set(t time.Time) { + // Continue to execute timers until there are no more before the new time. + for { + if !m.runNextTimer(t) { + break + } + } + + // Ensure that we end with the new time. + m.mu.Lock() + m.now = t + m.mu.Unlock() + + // Give a small buffer to make sure the other goroutines get handled. + gosched() +} + +// runNextTimer executes the next timer in chronological order and moves the +// current time to the timer's next tick time. The next time is not executed if +// it's next time if after the max time. Returns true if a timer is executed. +func (m *Mock) runNextTimer(max time.Time) bool { + m.mu.Lock() + + // Sort timers by time. + sort.Sort(m.timers) + + // If we have no more timers then exit. + if len(m.timers) == 0 { + m.mu.Unlock() + return false + } + + // Retrieve next timer. Exit if next tick is after new time. + t := m.timers[0] + if t.Next().After(max) { + m.mu.Unlock() + return false + } + + // Move "now" forward and unlock clock. + m.now = t.Next() + m.mu.Unlock() + + // Execute timer. + t.Tick(m.now) + return true +} + +// After waits for the duration to elapse and then sends the current time on the returned channel. +func (m *Mock) After(d time.Duration) <-chan time.Time { + return m.Timer(d).C +} + +// AfterFunc waits for the duration to elapse and then executes a function. +// A Timer is returned that can be stopped. +func (m *Mock) AfterFunc(d time.Duration, f func()) *Timer { + t := m.Timer(d) + t.C = nil + t.fn = f + return t +} + +// Now returns the current wall time on the mock clock. +func (m *Mock) Now() time.Time { + m.mu.Lock() + defer m.mu.Unlock() + return m.now +} + +// Sleep pauses the goroutine for the given duration on the mock clock. +// The clock must be moved forward in a separate goroutine. +func (m *Mock) Sleep(d time.Duration) { + <-m.After(d) +} + +// Tick is a convenience function for Ticker(). +// It will return a ticker channel that cannot be stopped. +func (m *Mock) Tick(d time.Duration) <-chan time.Time { + return m.Ticker(d).C +} + +// Ticker creates a new instance of Ticker. +func (m *Mock) Ticker(d time.Duration) *Ticker { + m.mu.Lock() + defer m.mu.Unlock() + ch := make(chan time.Time, 1) + t := &Ticker{ + C: ch, + c: ch, + mock: m, + d: d, + next: m.now.Add(d), + } + m.timers = append(m.timers, (*internalTicker)(t)) + return t +} + +// Timer creates a new instance of Timer. +func (m *Mock) Timer(d time.Duration) *Timer { + ch := make(chan time.Time, 1) + t := &Timer{ + C: ch, + c: ch, + mock: m, + next: m.Now().Add(d), + } + m.addTimer((*internalTimer)(t)) + return t +} + +func (m *Mock) addTimer(t *internalTimer) { + m.mu.Lock() + defer m.mu.Unlock() + m.timers = append(m.timers, t) +} + +func (m *Mock) removeClockTimer(t clockTimer) bool { + m.mu.Lock() + defer m.mu.Unlock() + ret := false + for i, timer := range m.timers { + if timer == t { + ret = true + copy(m.timers[i:], m.timers[i+1:]) + m.timers[len(m.timers)-1] = nil + m.timers = m.timers[:len(m.timers)-1] + break + } + } + sort.Sort(m.timers) + return ret +} + +// clockTimer represents an object with an associated start time. +type clockTimer interface { + Next() time.Time + Tick(time.Time) +} + +// clockTimers represents a list of sortable timers. +type clockTimers []clockTimer + +func (a clockTimers) Len() int { return len(a) } +func (a clockTimers) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a clockTimers) Less(i, j int) bool { return a[i].Next().Before(a[j].Next()) } + +// Timer represents a single event. +// The current time will be sent on C, unless the timer was created by AfterFunc. +type Timer struct { + C <-chan time.Time + c chan time.Time + timer *time.Timer // realtime impl, if set + next time.Time // next tick time + mock *Mock // mock clock, if set + fn func() // AfterFunc function, if set +} + +// Stop turns off the timer. +func (t *Timer) Stop() bool { + if t.timer != nil { + return t.timer.Stop() + } + return t.mock.removeClockTimer((*internalTimer)(t)) +} + +// Reset changes the timer to expire after duration d. It returns true if the +// timer had been active, false if the timer had expired or been stopped. +func (t *Timer) Reset(d time.Duration) bool { + if t.timer != nil { + return t.timer.Reset(d) + } + ret := t.mock.removeClockTimer((*internalTimer)(t)) + t.next = t.mock.Now().Add(d) + t.mock.addTimer((*internalTimer)(t)) + return ret +} + +type internalTimer Timer + +func (t *internalTimer) Next() time.Time { return t.next } +func (t *internalTimer) Tick(now time.Time) { + if t.fn != nil { + t.fn() + } else { + select { + case t.c <- now: + default: + } + } + t.mock.removeClockTimer((*internalTimer)(t)) + gosched() +} + +// Ticker holds a channel that receives "ticks" at regular intervals. +type Ticker struct { + C <-chan time.Time + c chan time.Time + ticker *time.Ticker // realtime impl, if set + next time.Time // next tick time + mock *Mock // mock clock, if set + d time.Duration // time between ticks +} + +// Stop turns off the ticker. +func (t *Ticker) Stop() { + if t.ticker != nil { + t.ticker.Stop() + } else { + t.mock.removeClockTimer((*internalTicker)(t)) + } +} + +type internalTicker Ticker + +func (t *internalTicker) Next() time.Time { return t.next } +func (t *internalTicker) Tick(now time.Time) { + select { + case t.c <- now: + default: + } + t.next = now.Add(t.d) + gosched() +} + +// Sleep momentarily so that other goroutines can process. +func gosched() { time.Sleep(1 * time.Millisecond) } diff --git a/vendor/github.com/cenkalti/backoff/v4/.gitignore b/vendor/github.com/cenkalti/backoff/v4/.gitignore new file mode 100644 index 0000000..50d95c5 --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/v4/.gitignore @@ -0,0 +1,25 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe + +# IDEs +.idea/ diff --git a/vendor/github.com/cenkalti/backoff/v4/.travis.yml b/vendor/github.com/cenkalti/backoff/v4/.travis.yml new file mode 100644 index 0000000..c79105c --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/v4/.travis.yml @@ -0,0 +1,10 @@ +language: go +go: + - 1.13 + - 1.x + - tip +before_install: + - go get github.com/mattn/goveralls + - go get golang.org/x/tools/cmd/cover +script: + - $HOME/gopath/bin/goveralls -service=travis-ci diff --git a/vendor/github.com/cenkalti/backoff/v4/LICENSE b/vendor/github.com/cenkalti/backoff/v4/LICENSE new file mode 100644 index 0000000..89b8179 --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/v4/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Cenk Altı + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/vendor/github.com/cenkalti/backoff/v4/README.md b/vendor/github.com/cenkalti/backoff/v4/README.md new file mode 100644 index 0000000..16abdfc --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/v4/README.md @@ -0,0 +1,32 @@ +# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Build Status][travis image]][travis] [![Coverage Status][coveralls image]][coveralls] + +This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client]. + +[Exponential backoff][exponential backoff wiki] +is an algorithm that uses feedback to multiplicatively decrease the rate of some process, +in order to gradually find an acceptable rate. +The retries exponentially increase and stop increasing when a certain threshold is met. + +## Usage + +Import path is `github.com/cenkalti/backoff/v4`. Please note the version part at the end. + +Use https://pkg.go.dev/github.com/cenkalti/backoff/v4 to view the documentation. + +## Contributing + +* I would like to keep this library as small as possible. +* Please don't send a PR without opening an issue and discussing it first. +* If proposed change is not a common use case, I will probably not accept it. + +[godoc]: https://pkg.go.dev/github.com/cenkalti/backoff/v4 +[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png +[travis]: https://travis-ci.org/cenkalti/backoff +[travis image]: https://travis-ci.org/cenkalti/backoff.png?branch=master +[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master +[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master + +[google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java +[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff + +[advanced example]: https://pkg.go.dev/github.com/cenkalti/backoff/v4?tab=doc#pkg-examples diff --git a/vendor/github.com/cenkalti/backoff/v4/backoff.go b/vendor/github.com/cenkalti/backoff/v4/backoff.go new file mode 100644 index 0000000..3676ee4 --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/v4/backoff.go @@ -0,0 +1,66 @@ +// Package backoff implements backoff algorithms for retrying operations. +// +// Use Retry function for retrying operations that may fail. +// If Retry does not meet your needs, +// copy/paste the function into your project and modify as you wish. +// +// There is also Ticker type similar to time.Ticker. +// You can use it if you need to work with channels. +// +// See Examples section below for usage examples. +package backoff + +import "time" + +// BackOff is a backoff policy for retrying an operation. +type BackOff interface { + // NextBackOff returns the duration to wait before retrying the operation, + // or backoff. Stop to indicate that no more retries should be made. + // + // Example usage: + // + // duration := backoff.NextBackOff(); + // if (duration == backoff.Stop) { + // // Do not retry operation. + // } else { + // // Sleep for duration and retry operation. + // } + // + NextBackOff() time.Duration + + // Reset to initial state. + Reset() +} + +// Stop indicates that no more retries should be made for use in NextBackOff(). +const Stop time.Duration = -1 + +// ZeroBackOff is a fixed backoff policy whose backoff time is always zero, +// meaning that the operation is retried immediately without waiting, indefinitely. +type ZeroBackOff struct{} + +func (b *ZeroBackOff) Reset() {} + +func (b *ZeroBackOff) NextBackOff() time.Duration { return 0 } + +// StopBackOff is a fixed backoff policy that always returns backoff.Stop for +// NextBackOff(), meaning that the operation should never be retried. +type StopBackOff struct{} + +func (b *StopBackOff) Reset() {} + +func (b *StopBackOff) NextBackOff() time.Duration { return Stop } + +// ConstantBackOff is a backoff policy that always returns the same backoff delay. +// This is in contrast to an exponential backoff policy, +// which returns a delay that grows longer as you call NextBackOff() over and over again. +type ConstantBackOff struct { + Interval time.Duration +} + +func (b *ConstantBackOff) Reset() {} +func (b *ConstantBackOff) NextBackOff() time.Duration { return b.Interval } + +func NewConstantBackOff(d time.Duration) *ConstantBackOff { + return &ConstantBackOff{Interval: d} +} diff --git a/vendor/github.com/cenkalti/backoff/v4/context.go b/vendor/github.com/cenkalti/backoff/v4/context.go new file mode 100644 index 0000000..4848233 --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/v4/context.go @@ -0,0 +1,62 @@ +package backoff + +import ( + "context" + "time" +) + +// BackOffContext is a backoff policy that stops retrying after the context +// is canceled. +type BackOffContext interface { // nolint: golint + BackOff + Context() context.Context +} + +type backOffContext struct { + BackOff + ctx context.Context +} + +// WithContext returns a BackOffContext with context ctx +// +// ctx must not be nil +func WithContext(b BackOff, ctx context.Context) BackOffContext { // nolint: golint + if ctx == nil { + panic("nil context") + } + + if b, ok := b.(*backOffContext); ok { + return &backOffContext{ + BackOff: b.BackOff, + ctx: ctx, + } + } + + return &backOffContext{ + BackOff: b, + ctx: ctx, + } +} + +func getContext(b BackOff) context.Context { + if cb, ok := b.(BackOffContext); ok { + return cb.Context() + } + if tb, ok := b.(*backOffTries); ok { + return getContext(tb.delegate) + } + return context.Background() +} + +func (b *backOffContext) Context() context.Context { + return b.ctx +} + +func (b *backOffContext) NextBackOff() time.Duration { + select { + case <-b.ctx.Done(): + return Stop + default: + return b.BackOff.NextBackOff() + } +} diff --git a/vendor/github.com/cenkalti/backoff/v4/exponential.go b/vendor/github.com/cenkalti/backoff/v4/exponential.go new file mode 100644 index 0000000..3d34532 --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/v4/exponential.go @@ -0,0 +1,158 @@ +package backoff + +import ( + "math/rand" + "time" +) + +/* +ExponentialBackOff is a backoff implementation that increases the backoff +period for each retry attempt using a randomization function that grows exponentially. + +NextBackOff() is calculated using the following formula: + + randomized interval = + RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor]) + +In other words NextBackOff() will range between the randomization factor +percentage below and above the retry interval. + +For example, given the following parameters: + + RetryInterval = 2 + RandomizationFactor = 0.5 + Multiplier = 2 + +the actual backoff period used in the next retry attempt will range between 1 and 3 seconds, +multiplied by the exponential, that is, between 2 and 6 seconds. + +Note: MaxInterval caps the RetryInterval and not the randomized interval. + +If the time elapsed since an ExponentialBackOff instance is created goes past the +MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop. + +The elapsed time can be reset by calling Reset(). + +Example: Given the following default arguments, for 10 tries the sequence will be, +and assuming we go over the MaxElapsedTime on the 10th try: + + Request # RetryInterval (seconds) Randomized Interval (seconds) + + 1 0.5 [0.25, 0.75] + 2 0.75 [0.375, 1.125] + 3 1.125 [0.562, 1.687] + 4 1.687 [0.8435, 2.53] + 5 2.53 [1.265, 3.795] + 6 3.795 [1.897, 5.692] + 7 5.692 [2.846, 8.538] + 8 8.538 [4.269, 12.807] + 9 12.807 [6.403, 19.210] + 10 19.210 backoff.Stop + +Note: Implementation is not thread-safe. +*/ +type ExponentialBackOff struct { + InitialInterval time.Duration + RandomizationFactor float64 + Multiplier float64 + MaxInterval time.Duration + // After MaxElapsedTime the ExponentialBackOff returns Stop. + // It never stops if MaxElapsedTime == 0. + MaxElapsedTime time.Duration + Stop time.Duration + Clock Clock + + currentInterval time.Duration + startTime time.Time +} + +// Clock is an interface that returns current time for BackOff. +type Clock interface { + Now() time.Time +} + +// Default values for ExponentialBackOff. +const ( + DefaultInitialInterval = 500 * time.Millisecond + DefaultRandomizationFactor = 0.5 + DefaultMultiplier = 1.5 + DefaultMaxInterval = 60 * time.Second + DefaultMaxElapsedTime = 15 * time.Minute +) + +// NewExponentialBackOff creates an instance of ExponentialBackOff using default values. +func NewExponentialBackOff() *ExponentialBackOff { + b := &ExponentialBackOff{ + InitialInterval: DefaultInitialInterval, + RandomizationFactor: DefaultRandomizationFactor, + Multiplier: DefaultMultiplier, + MaxInterval: DefaultMaxInterval, + MaxElapsedTime: DefaultMaxElapsedTime, + Stop: Stop, + Clock: SystemClock, + } + b.Reset() + return b +} + +type systemClock struct{} + +func (t systemClock) Now() time.Time { + return time.Now() +} + +// SystemClock implements Clock interface that uses time.Now(). +var SystemClock = systemClock{} + +// Reset the interval back to the initial retry interval and restarts the timer. +// Reset must be called before using b. +func (b *ExponentialBackOff) Reset() { + b.currentInterval = b.InitialInterval + b.startTime = b.Clock.Now() +} + +// NextBackOff calculates the next backoff interval using the formula: +// Randomized interval = RetryInterval * (1 ± RandomizationFactor) +func (b *ExponentialBackOff) NextBackOff() time.Duration { + // Make sure we have not gone over the maximum elapsed time. + elapsed := b.GetElapsedTime() + next := getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval) + b.incrementCurrentInterval() + if b.MaxElapsedTime != 0 && elapsed+next > b.MaxElapsedTime { + return b.Stop + } + return next +} + +// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance +// is created and is reset when Reset() is called. +// +// The elapsed time is computed using time.Now().UnixNano(). It is +// safe to call even while the backoff policy is used by a running +// ticker. +func (b *ExponentialBackOff) GetElapsedTime() time.Duration { + return b.Clock.Now().Sub(b.startTime) +} + +// Increments the current interval by multiplying it with the multiplier. +func (b *ExponentialBackOff) incrementCurrentInterval() { + // Check for overflow, if overflow is detected set the current interval to the max interval. + if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier { + b.currentInterval = b.MaxInterval + } else { + b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier) + } +} + +// Returns a random value from the following interval: +// [currentInterval - randomizationFactor * currentInterval, currentInterval + randomizationFactor * currentInterval]. +func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration { + var delta = randomizationFactor * float64(currentInterval) + var minInterval = float64(currentInterval) - delta + var maxInterval = float64(currentInterval) + delta + + // Get a random value from the range [minInterval, maxInterval]. + // The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then + // we want a 33% chance for selecting either 1, 2 or 3. + return time.Duration(minInterval + (random * (maxInterval - minInterval + 1))) +} diff --git a/vendor/github.com/cenkalti/backoff/v4/go.mod b/vendor/github.com/cenkalti/backoff/v4/go.mod new file mode 100644 index 0000000..f811bea --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/v4/go.mod @@ -0,0 +1,3 @@ +module github.com/cenkalti/backoff/v4 + +go 1.13 diff --git a/vendor/github.com/cenkalti/backoff/v4/retry.go b/vendor/github.com/cenkalti/backoff/v4/retry.go new file mode 100644 index 0000000..1ce2507 --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/v4/retry.go @@ -0,0 +1,112 @@ +package backoff + +import ( + "errors" + "time" +) + +// An Operation is executing by Retry() or RetryNotify(). +// The operation will be retried using a backoff policy if it returns an error. +type Operation func() error + +// Notify is a notify-on-error function. It receives an operation error and +// backoff delay if the operation failed (with an error). +// +// NOTE that if the backoff policy stated to stop retrying, +// the notify function isn't called. +type Notify func(error, time.Duration) + +// Retry the operation o until it does not return error or BackOff stops. +// o is guaranteed to be run at least once. +// +// If o returns a *PermanentError, the operation is not retried, and the +// wrapped error is returned. +// +// Retry sleeps the goroutine for the duration returned by BackOff after a +// failed operation returns. +func Retry(o Operation, b BackOff) error { + return RetryNotify(o, b, nil) +} + +// RetryNotify calls notify function with the error and wait duration +// for each failed attempt before sleep. +func RetryNotify(operation Operation, b BackOff, notify Notify) error { + return RetryNotifyWithTimer(operation, b, notify, nil) +} + +// RetryNotifyWithTimer calls notify function with the error and wait duration using the given Timer +// for each failed attempt before sleep. +// A default timer that uses system timer is used when nil is passed. +func RetryNotifyWithTimer(operation Operation, b BackOff, notify Notify, t Timer) error { + var err error + var next time.Duration + if t == nil { + t = &defaultTimer{} + } + + defer func() { + t.Stop() + }() + + ctx := getContext(b) + + b.Reset() + for { + if err = operation(); err == nil { + return nil + } + + var permanent *PermanentError + if errors.As(err, &permanent) { + return permanent.Err + } + + if next = b.NextBackOff(); next == Stop { + if cerr := ctx.Err(); cerr != nil { + return cerr + } + + return err + } + + if notify != nil { + notify(err, next) + } + + t.Start(next) + + select { + case <-ctx.Done(): + return ctx.Err() + case <-t.C(): + } + } +} + +// PermanentError signals that the operation should not be retried. +type PermanentError struct { + Err error +} + +func (e *PermanentError) Error() string { + return e.Err.Error() +} + +func (e *PermanentError) Unwrap() error { + return e.Err +} + +func (e *PermanentError) Is(target error) bool { + _, ok := target.(*PermanentError) + return ok +} + +// Permanent wraps the given err in a *PermanentError. +func Permanent(err error) error { + if err == nil { + return nil + } + return &PermanentError{ + Err: err, + } +} diff --git a/vendor/github.com/cenkalti/backoff/v4/ticker.go b/vendor/github.com/cenkalti/backoff/v4/ticker.go new file mode 100644 index 0000000..df9d68b --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/v4/ticker.go @@ -0,0 +1,97 @@ +package backoff + +import ( + "context" + "sync" + "time" +) + +// Ticker holds a channel that delivers `ticks' of a clock at times reported by a BackOff. +// +// Ticks will continue to arrive when the previous operation is still running, +// so operations that take a while to fail could run in quick succession. +type Ticker struct { + C <-chan time.Time + c chan time.Time + b BackOff + ctx context.Context + timer Timer + stop chan struct{} + stopOnce sync.Once +} + +// NewTicker returns a new Ticker containing a channel that will send +// the time at times specified by the BackOff argument. Ticker is +// guaranteed to tick at least once. The channel is closed when Stop +// method is called or BackOff stops. It is not safe to manipulate the +// provided backoff policy (notably calling NextBackOff or Reset) +// while the ticker is running. +func NewTicker(b BackOff) *Ticker { + return NewTickerWithTimer(b, &defaultTimer{}) +} + +// NewTickerWithTimer returns a new Ticker with a custom timer. +// A default timer that uses system timer is used when nil is passed. +func NewTickerWithTimer(b BackOff, timer Timer) *Ticker { + if timer == nil { + timer = &defaultTimer{} + } + c := make(chan time.Time) + t := &Ticker{ + C: c, + c: c, + b: b, + ctx: getContext(b), + timer: timer, + stop: make(chan struct{}), + } + t.b.Reset() + go t.run() + return t +} + +// Stop turns off a ticker. After Stop, no more ticks will be sent. +func (t *Ticker) Stop() { + t.stopOnce.Do(func() { close(t.stop) }) +} + +func (t *Ticker) run() { + c := t.c + defer close(c) + + // Ticker is guaranteed to tick at least once. + afterC := t.send(time.Now()) + + for { + if afterC == nil { + return + } + + select { + case tick := <-afterC: + afterC = t.send(tick) + case <-t.stop: + t.c = nil // Prevent future ticks from being sent to the channel. + return + case <-t.ctx.Done(): + return + } + } +} + +func (t *Ticker) send(tick time.Time) <-chan time.Time { + select { + case t.c <- tick: + case <-t.stop: + return nil + } + + next := t.b.NextBackOff() + if next == Stop { + t.Stop() + return nil + } + + t.timer.Start(next) + return t.timer.C() +} diff --git a/vendor/github.com/cenkalti/backoff/v4/timer.go b/vendor/github.com/cenkalti/backoff/v4/timer.go new file mode 100644 index 0000000..8120d02 --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/v4/timer.go @@ -0,0 +1,35 @@ +package backoff + +import "time" + +type Timer interface { + Start(duration time.Duration) + Stop() + C() <-chan time.Time +} + +// defaultTimer implements Timer interface using time.Timer +type defaultTimer struct { + timer *time.Timer +} + +// C returns the timers channel which receives the current time when the timer fires. +func (t *defaultTimer) C() <-chan time.Time { + return t.timer.C +} + +// Start starts the timer to fire after the given duration +func (t *defaultTimer) Start(duration time.Duration) { + if t.timer == nil { + t.timer = time.NewTimer(duration) + } else { + t.timer.Reset(duration) + } +} + +// Stop is called when the timer is not used anymore and resources may be freed. +func (t *defaultTimer) Stop() { + if t.timer != nil { + t.timer.Stop() + } +} diff --git a/vendor/github.com/cenkalti/backoff/v4/tries.go b/vendor/github.com/cenkalti/backoff/v4/tries.go new file mode 100644 index 0000000..28d58ca --- /dev/null +++ b/vendor/github.com/cenkalti/backoff/v4/tries.go @@ -0,0 +1,38 @@ +package backoff + +import "time" + +/* +WithMaxRetries creates a wrapper around another BackOff, which will +return Stop if NextBackOff() has been called too many times since +the last time Reset() was called + +Note: Implementation is not thread-safe. +*/ +func WithMaxRetries(b BackOff, max uint64) BackOff { + return &backOffTries{delegate: b, maxTries: max} +} + +type backOffTries struct { + delegate BackOff + maxTries uint64 + numTries uint64 +} + +func (b *backOffTries) NextBackOff() time.Duration { + if b.maxTries == 0 { + return Stop + } + if b.maxTries > 0 { + if b.maxTries <= b.numTries { + return Stop + } + b.numTries++ + } + return b.delegate.NextBackOff() +} + +func (b *backOffTries) Reset() { + b.numTries = 0 + b.delegate.Reset() +} diff --git a/vendor/github.com/g8rswimmer/error-chain/LICENSE b/vendor/github.com/g8rswimmer/error-chain/LICENSE new file mode 100644 index 0000000..88e91f2 --- /dev/null +++ b/vendor/github.com/g8rswimmer/error-chain/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 g8rswimmer + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/vendor/github.com/g8rswimmer/error-chain/README.md b/vendor/github.com/g8rswimmer/error-chain/README.md new file mode 100644 index 0000000..1cb9f7e --- /dev/null +++ b/vendor/github.com/g8rswimmer/error-chain/README.md @@ -0,0 +1,58 @@ +# error-chain + +With `golang 1.13` the introduction of error wrapping was introduced. + +There may be a need to gather an array of errors. With this package you can do just that and leverage the new `1.13` functionality. + +```go +package main + +import ( + "errors" + "fmt" + + chain "github.com/g8rswimmer/error-chain" +) + +type myError struct { + code int +} + +func (e *myError) Error() string { + return fmt.Sprintf("%d", e.code) +} + +func (e *myError) Is(target error) bool { + te, ok := target.(*myError) + if ok == false { + return false + } + return e.code == te.code +} + +func someFunction() error { + ec := chain.New() + ec.Add(errors.New("some error")) + ec.Add(fmt.Errorf("wrap it up %w", &myError{code: 12})) + return ec +} + +func otherFunction() { + err := someFunction() + if errors.Is(err, &myError{code: 12}) { + fmt.Println("got an error") + } +} + +func main() { + fmt.Println("runing the error chain example") + otherFunction() +} +``` + +Output: +``` +â–¶ go run *.go +runing the error chain example +got an error +``` \ No newline at end of file diff --git a/vendor/github.com/g8rswimmer/error-chain/chain.go b/vendor/github.com/g8rswimmer/error-chain/chain.go new file mode 100644 index 0000000..d55c01a --- /dev/null +++ b/vendor/github.com/g8rswimmer/error-chain/chain.go @@ -0,0 +1,73 @@ +package echain + +import ( + "errors" + "strings" +) + +type link struct { + err error + next *link +} + +// ErrorChain will chain multiple errors +type ErrorChain struct { + head *link + tail *link +} + +// New create a new error chain +func New() *ErrorChain { + return &ErrorChain{} +} +func (e *ErrorChain) Error() string { + errs := []string{} + h := e.head + for h != nil { + errs = append(errs, h.err.Error()) + h = h.next + } + return strings.Join(errs, ": ") +} + +// Unwrap will give the next error +func (e *ErrorChain) Unwrap() error { + if e.head.next == nil { + return nil + } + ec := &ErrorChain{ + head: e.head.next, + tail: e.tail, + } + return ec +} + +// Is will comapre the target +func (e *ErrorChain) Is(target error) bool { + return errors.Is(e.head.err, target) +} + +// Add will place another error in the chain +func (e *ErrorChain) Add(err error) { + l := &link{ + err: err, + } + if e.head == nil { + e.head = l + e.tail = l + return + } + e.tail.next = l + e.tail = l +} + +// Errors will return the errors in the chain +func (e *ErrorChain) Errors() []error { + errs := []error{} + l := e.head + for l != nil { + errs = append(errs, l.err) + l = l.next + } + return errs +} diff --git a/vendor/github.com/natefinch/atomic/.gitignore b/vendor/github.com/natefinch/atomic/.gitignore new file mode 100644 index 0000000..daf913b --- /dev/null +++ b/vendor/github.com/natefinch/atomic/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/natefinch/atomic/LICENSE b/vendor/github.com/natefinch/atomic/LICENSE new file mode 100644 index 0000000..cc38d64 --- /dev/null +++ b/vendor/github.com/natefinch/atomic/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Nate Finch + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. + diff --git a/vendor/github.com/natefinch/atomic/README.md b/vendor/github.com/natefinch/atomic/README.md new file mode 100644 index 0000000..37cd673 --- /dev/null +++ b/vendor/github.com/natefinch/atomic/README.md @@ -0,0 +1,35 @@ +# atomic + import "github.com/natefinch/atomic" +atomic is a go package for atomic file writing + +By default, writing to a file in go (and generally any language) can fail +partway through... you then have a partially written file, which probably was +truncated when the write began, and bam, now you've lost data. + +This go package avoids this problem, by writing first to a temp file, and then +overwriting the target file in an atomic way. This is easy on linux, os.Rename +just is atomic. However, on Windows, os.Rename is not atomic, and so bad things +can happen. By wrapping the windows API moveFileEx, we can ensure that the move +is atomic, and we can be safe in knowing that either the move succeeds entirely, +or neither file will be modified. + + +## func ReplaceFile +``` go +func ReplaceFile(source, destination string) error +``` +ReplaceFile atomically replaces the destination file or directory with the +source. It is guaranteed to either replace the target file entirely, or not +change either file. + + +## func WriteFile +``` go +func WriteFile(filename string, r io.Reader) (err error) +``` +WriteFile atomically writes the contents of r to the specified filepath. If +an error occurs, the target file is guaranteed to be either fully written, or +not written at all. WriteFile overwrites any file that exists at the +location (but only if the write fully succeeds, otherwise the existing file +is unmodified). + diff --git a/vendor/github.com/natefinch/atomic/atomic.go b/vendor/github.com/natefinch/atomic/atomic.go new file mode 100644 index 0000000..f7e2706 --- /dev/null +++ b/vendor/github.com/natefinch/atomic/atomic.go @@ -0,0 +1,73 @@ +// package atomic provides functions to atomically change files. +package atomic + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" +) + +// WriteFile atomically writes the contents of r to the specified filepath. If +// an error occurs, the target file is guaranteed to be either fully written, or +// not written at all. WriteFile overwrites any file that exists at the +// location (but only if the write fully succeeds, otherwise the existing file +// is unmodified). +func WriteFile(filename string, r io.Reader) (err error) { + // write to a temp file first, then we'll atomically replace the target file + // with the temp file. + dir, file := filepath.Split(filename) + if dir == "" { + dir = "." + } + + f, err := ioutil.TempFile(dir, file) + if err != nil { + return fmt.Errorf("cannot create temp file: %v", err) + } + defer func() { + if err != nil { + // Don't leave the temp file lying around on error. + _ = os.Remove(f.Name()) // yes, ignore the error, not much we can do about it. + } + }() + // ensure we always close f. Note that this does not conflict with the + // close below, as close is idempotent. + defer f.Close() + name := f.Name() + if _, err := io.Copy(f, r); err != nil { + return fmt.Errorf("cannot write data to tempfile %q: %v", name, err) + } + // fsync is important, otherwise os.Rename could rename a zero-length file + if err := f.Sync(); err != nil { + return fmt.Errorf("can't flush tempfile %q: %v", name, err) + } + if err := f.Close(); err != nil { + return fmt.Errorf("can't close tempfile %q: %v", name, err) + } + + // get the file mode from the original file and use that for the replacement + // file, too. + destInfo, err := os.Stat(filename) + if os.IsNotExist(err) { + // no original file + } else if err != nil { + return err + } else { + sourceInfo, err := os.Stat(name) + if err != nil { + return err + } + + if sourceInfo.Mode() != destInfo.Mode() { + if err := os.Chmod(name, destInfo.Mode()); err != nil { + return fmt.Errorf("can't set filemode on tempfile %q: %v", name, err) + } + } + } + if err := ReplaceFile(name, filename); err != nil { + return fmt.Errorf("cannot replace %q with tempfile %q: %v", filename, name, err) + } + return nil +} diff --git a/vendor/github.com/natefinch/atomic/file_unix.go b/vendor/github.com/natefinch/atomic/file_unix.go new file mode 100644 index 0000000..408f18e --- /dev/null +++ b/vendor/github.com/natefinch/atomic/file_unix.go @@ -0,0 +1,14 @@ +// +build !windows + +package atomic + +import ( + "os" +) + +// ReplaceFile atomically replaces the destination file or directory with the +// source. It is guaranteed to either replace the target file entirely, or not +// change either file. +func ReplaceFile(source, destination string) error { + return os.Rename(source, destination) +} diff --git a/vendor/github.com/natefinch/atomic/file_windows.go b/vendor/github.com/natefinch/atomic/file_windows.go new file mode 100644 index 0000000..e507143 --- /dev/null +++ b/vendor/github.com/natefinch/atomic/file_windows.go @@ -0,0 +1,33 @@ +package atomic + +import ( + "os" + "syscall" +) + +const ( + movefile_replace_existing = 0x1 + movefile_write_through = 0x8 +) + +//sys moveFileEx(lpExistingFileName *uint16, lpNewFileName *uint16, dwFlags uint32) (err error) = MoveFileExW + +// ReplaceFile atomically replaces the destination file or directory with the +// source. It is guaranteed to either replace the target file entirely, or not +// change either file. +func ReplaceFile(source, destination string) error { + src, err := syscall.UTF16PtrFromString(source) + if err != nil { + return &os.LinkError{"replace", source, destination, err} + } + dest, err := syscall.UTF16PtrFromString(destination) + if err != nil { + return &os.LinkError{"replace", source, destination, err} + } + + // see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365240(v=vs.85).aspx + if err := moveFileEx(src, dest, movefile_replace_existing|movefile_write_through); err != nil { + return &os.LinkError{"replace", source, destination, err} + } + return nil +} diff --git a/vendor/github.com/natefinch/atomic/go.mod b/vendor/github.com/natefinch/atomic/go.mod new file mode 100644 index 0000000..4b8d336 --- /dev/null +++ b/vendor/github.com/natefinch/atomic/go.mod @@ -0,0 +1,3 @@ +module github.com/natefinch/atomic + +go 1.12 diff --git a/vendor/github.com/natefinch/atomic/zfile_windows.go b/vendor/github.com/natefinch/atomic/zfile_windows.go new file mode 100644 index 0000000..d55db61 --- /dev/null +++ b/vendor/github.com/natefinch/atomic/zfile_windows.go @@ -0,0 +1,27 @@ +// mksyscall_windows -l32 file_windows.go +// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT + +package atomic + +import ( + "syscall" + "unsafe" +) + +var ( + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + + procMoveFileExW = modkernel32.NewProc("MoveFileExW") +) + +func moveFileEx(lpExistingFileName *uint16, lpNewFileName *uint16, dwFlags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(lpExistingFileName)), uintptr(unsafe.Pointer(lpNewFileName)), uintptr(dwFlags)) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/.gitignore b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/.gitignore new file mode 100644 index 0000000..f385b1c --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/.gitignore @@ -0,0 +1,6 @@ +*~ +pkg +src +*.bak +!vendor/src +bin/wof-* diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/LICENSE b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/LICENSE new file mode 100644 index 0000000..06532e4 --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2019, SFO Museum +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of SFO Museum nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/Makefile b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/Makefile new file mode 100644 index 0000000..7468ac1 --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/Makefile @@ -0,0 +1,7 @@ +fmt: + go fmt cmd/sfom-export-feature/main.go + go fmt export.go + go fmt properties/*.go + +tools: + go build -o bin/sfom-export-feature cmd/sfom-export-feature/main.go diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/README.md b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/README.md new file mode 100644 index 0000000..93d2a25 --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/README.md @@ -0,0 +1,12 @@ +# go-sfomuseum-export + +Go package for exporting SFO Museum specific Who's On First documents. + +## Important + +Work in progress. This works, until it doesn't. + +## See also + +* https://github.com/whosonfirst/go-whosonfirst-export +* https://github.com/sfomuseum-data \ No newline at end of file diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/export.go b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/export.go new file mode 100644 index 0000000..2306c60 --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/export.go @@ -0,0 +1,43 @@ +package export + +import ( + "github.com/sfomuseum/go-sfomuseum-export/v2/properties" + wof_export "github.com/whosonfirst/go-whosonfirst-export/v2" +) + +func Prepare(feature []byte, opts *wof_export.Options) ([]byte, error) { + + var err error + + feature, err = wof_export.Prepare(feature, opts) + + if err != nil { + return nil, err + } + + feature, err = properties.EnsurePlacetype(feature) + + if err != nil { + return nil, err + } + + feature, err = properties.EnsureIsSFO(feature) + + if err != nil { + return nil, err + } + + feature, err = properties.EnsureSFOLevel(feature) + + if err != nil { + return nil, err + } + + feature, err = properties.EnsureWOFDepicts(feature) + + if err != nil { + return nil, err + } + + return feature, nil +} diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/go.mod b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/go.mod new file mode 100644 index 0000000..f4fad53 --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/go.mod @@ -0,0 +1,9 @@ +module github.com/sfomuseum/go-sfomuseum-export/v2 + +go 1.16 + +require ( + github.com/tidwall/gjson v1.13.0 + github.com/tidwall/sjson v1.2.4 + github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.1 +) diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/go.sum b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/go.sum new file mode 100644 index 0000000..0856a6a --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/go.sum @@ -0,0 +1,346 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/aaronland/go-artisanal-integers v0.1.0 h1:WN00aqbjfElOD8dUngFMOdd9wEWW0vyitnOMSRaNqsk= +github.com/aaronland/go-artisanal-integers v0.1.0/go.mod h1:00F0qOpuZZkzWiSSEQYk6Ul1Oc5kwgcYgsfYRmuR+wY= +github.com/aaronland/go-artisanal-integers v0.1.1 h1:bLQmWqcqgPT1NOJFwJtZZ9O/QTnttO54ODiWIVuOW1Y= +github.com/aaronland/go-artisanal-integers v0.1.1/go.mod h1:ZTeFI+Ck+q+Dp11Htld5aU6V+YwEzxzprsBO0t9GPp8= +github.com/aaronland/go-artisanal-integers-proxy v0.2.0 h1:3gQznMIWKNXbm3iMVKVC9l7nuZUj3ySUSN889fKlxhQ= +github.com/aaronland/go-artisanal-integers-proxy v0.2.0/go.mod h1:7Pkt553bRIgRMzkyPzPzvPDweCxMG6wx96qMBLlCk/Y= +github.com/aaronland/go-brooklynintegers-api v1.0.1 h1:HrEo98HD5YOfC/slzkROCxMuZTeCpT3srf1G+eO9sX8= +github.com/aaronland/go-brooklynintegers-api v1.0.1/go.mod h1:aZ4tIFeMdAQRSLZYfGdAiDeBWUHDQkFdqZ9091mk8H8= +github.com/aaronland/go-brooklynintegers-api v1.0.2/go.mod h1:JlR7i6vciy3W0aMnid7cN/Ls9Pz/vaq1lNj9sCENQf0= +github.com/aaronland/go-brooklynintegers-api v1.1.0 h1:eyoSZjn3Qiy79H+1rG/HtkEShNBZkPUWs4YKpFWkuD8= +github.com/aaronland/go-brooklynintegers-api v1.1.0/go.mod h1:agceH8JW8PcdHGCyKEDmOntccB3m7xUKrUejHpxAs6U= +github.com/aaronland/go-brooklynintegers-api v1.2.4 h1:KcRWO9kWTL6iNmZVTdPZVo7ngN0O9FFTKoQrFSjPMsU= +github.com/aaronland/go-brooklynintegers-api v1.2.4/go.mod h1:hNUn5nueKQM23ptExy20p5qDpRPhWg8RbjwW2BuXWmw= +github.com/aaronland/go-londonintegers-api v0.1.0/go.mod h1:E0VIcwks+So4FL1FYAQzrO5/OVOUsFPsqW85UrZArSE= +github.com/aaronland/go-missionintegers-api v0.1.0/go.mod h1:LZEM5+MkPX5RehLxTEv+3Y3cqMSYEk86qBa+aVecnKw= +github.com/aaronland/go-missionintegers-api v0.1.1/go.mod h1:CvByrizvklOxK6QD+Z4RNqACxHqqVjiB/GdWQfrB4Mc= +github.com/aaronland/go-pool v0.0.0-20191128211702-88306299c758 h1:m/JUyvxsCbgOyhecvs9WXFvZy9dj8BKu4T96J53d/ao= +github.com/aaronland/go-pool v0.0.0-20191128211702-88306299c758/go.mod h1:hL9EPOZJ6WVHaz7D0Jw1Dn1vaCOOSZNrYBTKMgDKYRk= +github.com/aaronland/go-roster v0.0.1 h1:r1l4n1HfWvEtOXZvhfXX0Won9Xf6QJsigdUdzOtuy/M= +github.com/aaronland/go-roster v0.0.1/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-roster v0.0.2 h1:2Fu7v4VQLRLRL/Zgr6R9S5JxsW75Ab/K88QtMVX532s= +github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-string v0.1.1 h1:btdr18owWCBN14ojKx3p+PBCKfm9qIggYEguPLUb2wE= +github.com/aaronland/go-string v0.1.1/go.mod h1:2aMIWdTqk63jZsaLLy+p9dsB1MDRqx4sHYoLtkwyYUo= +github.com/aaronland/go-uid v0.0.2 h1:5H3wtTBi58lkW5bqbaFR8Hp1MXfcraoJRlxKoUDeVfg= +github.com/aaronland/go-uid v0.0.2/go.mod h1:Kb/J05tYHWxp+Dkpod+oRkBKnxyw+szODwIQKIjvhj0= +github.com/aaronland/go-uid-artisanal v0.0.0-20191128230022-67bc446aa49d h1:2Sa8kTm10DVvAPESKu0XhQHNOBKpGxpkqLb7TvFMa4I= +github.com/aaronland/go-uid-artisanal v0.0.0-20191128230022-67bc446aa49d/go.mod h1:/fkI7C9H/GTB/TlLmNsKjHoNyXnYlkb/iG4Qp3tSCmE= +github.com/akrylysov/algnhsa v0.0.0-20190319020909-05b3d192e9a7/go.mod h1:HhzjNA0EjUWcwHTUMwqrpeAdIF3gRmpH0HpWx1hYJSc= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/aws/aws-lambda-go v1.9.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A= +github.com/aws/aws-lambda-go v1.10.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/g8rswimmer/error-chain v1.0.0 h1:WnwnunlvqtGPHVHmBfbmUyAgrtag8Y6nNpwLWmtSYOQ= +github.com/g8rswimmer/error-chain v1.0.0/go.mod h1:XPJ/brUsL7yzc5VRlIxtf9GvoUqnOKVI9fg2MB5DWx8= +github.com/go-ini/ini v1.42.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874 h1:em+tTnzgU7N22woTBMcSJAOW7tRHAkK597W+MD/CpK8= +github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mmcloughlin/geohash v0.10.0 h1:9w1HchfDfdeLc+jFEf/04D27KP7E2QmpDu52wPbJWRE= +github.com/mmcloughlin/geohash v0.10.0/go.mod h1:oNZxQo5yWJh0eMQEP/8hwQuVx9Z9tjwFUqcTB1SmG0c= +github.com/natefinch/atomic v0.0.0-20200526193002-18c0533a5b09 h1:DXR0VtCesBD2ss3toN9OEeXszpQmW9dc3SvUbUfiBC0= +github.com/natefinch/atomic v0.0.0-20200526193002-18c0533a5b09/go.mod h1:1rLVY/DWf3U6vSZgH16S7pymfrhK2lcUlXjgGglw/lY= +github.com/paulmach/go.geojson v1.4.0 h1:5x5moCkCtDo5x8af62P9IOAYGQcYHtxz2QJ3x1DoCgY= +github.com/paulmach/go.geojson v1.4.0/go.mod h1:YaKx1hKpWF+T2oj2lFJPsW/t1Q5e1jQI61eoQSTwpIs= +github.com/paulmach/orb v0.1.3 h1:Wa1nzU269Zv7V9paVEY1COWW8FCqv4PC/KJRbJSimpM= +github.com/paulmach/orb v0.1.3/go.mod h1:VFlX/8C+IQ1p6FTRRKzKoOPJnvEtA5G0Veuqwbu//Vk= +github.com/paulmach/orb v0.1.5 h1:GUcATabvxciqEzGd+c01/9ek3B6pUp9OdcIHFSDDSSg= +github.com/paulmach/orb v0.1.5/go.mod h1:pPwxxs3zoAyosNSbNKn1jiXV2+oovRDObDKfTvRegDI= +github.com/paulmach/orb v0.1.7 h1:Lwv10ANhqpTH3Kw5qow4YpSW5RLAx67nNGgbJpv/GC0= +github.com/paulmach/orb v0.1.7/go.mod h1:qakeIafyxF4NlRIgpXp3awhLCNuqhl3lyNpkWws2BNQ= +github.com/paulmach/orb v0.2.1 h1:Pp9UuWpUlGVRXzRC5eFlOgdlOXd/a3ALWC3UFLM3gOc= +github.com/paulmach/orb v0.2.1/go.mod h1:91bG5A8qKNOiZtlKc0BqKMB3O5kWfRQorTwo8BZ2B/0= +github.com/paulmach/orb v0.2.2 h1:PblToKAbU0xHVypex/GdZfibA1CeCfN5s0UjxyWExdo= +github.com/paulmach/orb v0.2.2/go.mod h1:FkcWtplUAIVqAuhAOV2d3rpbnQyliDOjOcLW9dUrfdU= +github.com/paulmach/orb v0.4.0 h1:ilp1MQjRapLJ1+qcays1nZpe0mvkCY+b8JU/qBKRZ1A= +github.com/paulmach/orb v0.4.0/go.mod h1:FkcWtplUAIVqAuhAOV2d3rpbnQyliDOjOcLW9dUrfdU= +github.com/paulmach/protoscan v0.2.0/go.mod h1:2c55sl1Hu6/tgRfc8Y8zADsxuSCYC2IrPh0JCqP/yrw= +github.com/paulmach/protoscan v0.2.1-0.20210522164731-4e53c6875432/go.mod h1:2sV+uZ/oQh66m4XJVZm5iqUZ62BN88Ex1E+TTS0nLzI= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sfomuseum/go-edtf v0.2.1 h1:wIbFlBK5jbqQOR3D79iTB+dZTBcs7DPFigPPimgkepg= +github.com/sfomuseum/go-edtf v0.2.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v0.2.2 h1:8n1UekTCU6fkgAf3bWqG5RyQxOd9hRhy4lg91aQ3kMk= +github.com/sfomuseum/go-edtf v0.2.2/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v0.2.3 h1:wpcpwl1RD9W/sXFDi4zpoIpQcIwIk8em9CGwa7YWv4g= +github.com/sfomuseum/go-edtf v0.2.3/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v0.2.4 h1:74T8YgcypVOCBvcGq6tWD7A7YpMrxwwbXTxmtf6Dg5M= +github.com/sfomuseum/go-edtf v0.2.4/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v0.3.1 h1:22DEXVvGhnpF7PD4dvpgKH0/oD8u9I+a4cXCwy1x2f4= +github.com/sfomuseum/go-edtf v0.3.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-flags v0.7.0/go.mod h1:ML3DTNbF9xnjExSdS/9FtVLjIUhRU5gm/ehzISv+t2w= +github.com/sfomuseum/go-flags v0.8.2 h1:elSU3KWMo442d1YjXu5Y/bokxvkGV+OrgAHshHZaeIo= +github.com/sfomuseum/go-flags v0.8.2/go.mod h1:ML3DTNbF9xnjExSdS/9FtVLjIUhRU5gm/ehzISv+t2w= +github.com/skelterjohn/geom v0.0.0-20180103142417-96f3e8a219c5 h1:qQF/q/+xaKD4CAVz3zfuvpij8U4ihSGIhHfOROI4NFc= +github.com/skelterjohn/geom v0.0.0-20180103142417-96f3e8a219c5/go.mod h1:w8cQIijHlvvZM7afYlixPThHAdD+AkRFw3Mb9yQ2Y+I= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/gjson v1.2.1 h1:j0efZLrZUvNerEf6xqoi0NjWMK5YlLrR7Guo/dxY174= +github.com/tidwall/gjson v1.2.1/go.mod h1:c/nTNbUr0E0OrXEhq1pwa8iEgc2DOt4ZZqAt1HtCkPA= +github.com/tidwall/gjson v1.3.2/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.3.5 h1:2oW9FBNu8qt9jy5URgrzsVx/T/KSn3qn/smJQ0crlDQ= +github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.6.7 h1:Mb1M9HZCRWEcXQ8ieJo7auYyyiSux6w9XN3AdTpxJrE= +github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= +github.com/tidwall/gjson v1.6.8 h1:CTmXMClGYPAmln7652e69B7OLXfTi5ABcPPwjIWUv7w= +github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= +github.com/tidwall/gjson v1.7.4/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/gjson v1.7.5 h1:zmAN/xmX7OtpAkv4Ovfso60r/BiCi5IErCDYGNJu+uc= +github.com/tidwall/gjson v1.7.5/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/gjson v1.8.0 h1:Qt+orfosKn0rbNTZqHYDqBrmm3UDA4KRkv70fDzG+PQ= +github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/gjson v1.8.1 h1:8j5EE9Hrh3l9Od1OIEDAb7IpezNA20UdRngNAj5N0WU= +github.com/tidwall/gjson v1.8.1/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/gjson v1.9.0 h1:+Od7AE26jAaMgVC31cQV/Ope5iKXulNMflrlB7k+F9E= +github.com/tidwall/gjson v1.9.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/gjson v1.9.1 h1:wrrRk7TyL7MmKanNRck/Mcr3VU1sdMvJHvJXzqBIUNo= +github.com/tidwall/gjson v1.9.1/go.mod h1:jydLKE7s8J0+1/5jC4eXcuFlzKizGrCKvLmBVX/5oXc= +github.com/tidwall/gjson v1.9.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo= +github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M= +github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= +github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65 h1:rQ229MBgvW68s1/g6f1/63TgYwYxfF4E+bi/KC19P8g= +github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU= +github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8= +github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.0.4 h1:UcdIRXff12Lpnu3OLtZvnc03g4vH2suXDXhBwBqmzYg= +github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y= +github.com/tidwall/sjson v1.1.4 h1:bTSsPLdAYF5QNLSwYsKfBKKTnlGbIuhqL3CpRsjzGhg= +github.com/tidwall/sjson v1.1.4/go.mod h1:wXpKXu8CtDjKAZ+3DrKY5ROCorDFahq8l0tey/Lx1fg= +github.com/tidwall/sjson v1.1.5 h1:wsUceI/XDyZk3J1FUvuuYlK62zJv2HO2Pzb8A5EWdUE= +github.com/tidwall/sjson v1.1.5/go.mod h1:VuJzsZnTowhSxWdOgsAnb886i4AjEyTkk7tNtsL7EYE= +github.com/tidwall/sjson v1.1.6 h1:8fDdlahON04OZBlTQCIatW8FstSFJz8oxidj5h0rmSQ= +github.com/tidwall/sjson v1.1.6/go.mod h1:KN3FZ7odvXIHPbJdhNorK/M9lWweVUbXsXXhrJ/kGOA= +github.com/tidwall/sjson v1.1.7 h1:sgVPwu/yygHJ2m1pJDLgGM/h+1F5odx5Q9ljG3imRm8= +github.com/tidwall/sjson v1.1.7/go.mod h1:w/yG+ezBeTdUxiKs5NcPicO9diP38nk96QBAbIIGeFs= +github.com/tidwall/sjson v1.2.2 h1:H1Llj/C9G+BoUN2DsybLHjWvr9dx4Uazavf0sXQ+rOs= +github.com/tidwall/sjson v1.2.2/go.mod h1:jmW2RZpbKuExPFUHeFSBMiovT9ZyOziEHDRkbsdp0B0= +github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc= +github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= +github.com/tomtaylor/go-whosonfirst-format v0.2.0 h1:UD/kP2dFApJFkgo/gGC08/7t018bP7PHQreDVoTYLTs= +github.com/tomtaylor/go-whosonfirst-format v0.2.0/go.mod h1:fjMnbCrPWx3EHMHWoyqH12A/nxAvWbdIPHjXBMteDm4= +github.com/whosonfirst/algnhsa v0.1.0/go.mod h1:swLBXxaVTv3s6dJLhekdQCuCTshUew+xHjptRC21RG0= +github.com/whosonfirst/go-ioutil v0.0.1 h1:cCrEYen6NDvHfjzV2q4u/VB21u2kTOwDnUGRlMI8Z9o= +github.com/whosonfirst/go-ioutil v0.0.1/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= +github.com/whosonfirst/go-reader v0.5.0 h1:nx+ai0F6JXouw+7Dln34dmYglw+3sQ6sG4JZGOJ/sqA= +github.com/whosonfirst/go-reader v0.5.0/go.mod h1:4ou/wZUss2CDZp27QK5ySDc8p98GVWvUiqqmwEprjgk= +github.com/whosonfirst/go-whosonfirst-cli v0.1.0/go.mod h1:Edy+amD+fMq1QS1yxB3u8maA8I93q/LG7JRNh+fsdfc= +github.com/whosonfirst/go-whosonfirst-export v0.1.0 h1:TyweYI1wFG3oOl66F7/az73QUf/GUAbqHVrAoYVEURA= +github.com/whosonfirst/go-whosonfirst-export v0.1.0/go.mod h1:X5JQYFJrgzjY5rANRBmY0BAmPbIy63jQDOvljqvBJiA= +github.com/whosonfirst/go-whosonfirst-export v0.1.1 h1:N2eXZH4rH3zDWBSIwYsFy1ROKe3twd82kTYc8JnnLj8= +github.com/whosonfirst/go-whosonfirst-export v0.1.1/go.mod h1:WUei94AxfPppqom4s7Y3VVTV2o6NsGjdpCaR+zyD89s= +github.com/whosonfirst/go-whosonfirst-export v0.1.2 h1:7NncfM1VdX0d8b30/uLLt3zN8HraYY4Xvbi2yAuUBRo= +github.com/whosonfirst/go-whosonfirst-export v0.1.2/go.mod h1:P7sAJi9D10i6XydqkHwmFoRFCSogBlRxzUkaVy5vqew= +github.com/whosonfirst/go-whosonfirst-export v0.3.0 h1:+Ub2G9QXY6ZXhfAnfLnf1dbC1YFqowq3Z+cKR8LCSTM= +github.com/whosonfirst/go-whosonfirst-export v0.3.0/go.mod h1:UO/uZcV+kGoDZPYKSb05Yj28e1sk4r8aQvCyIjBQOxc= +github.com/whosonfirst/go-whosonfirst-export v0.3.4 h1:/09Ny6HIOpPAzqCIPIOVplwekSbCTSA/wi7wJU4lwmI= +github.com/whosonfirst/go-whosonfirst-export v0.3.4/go.mod h1:y3FiLZ95MVzfE4OyPm2aWzZ7Uld74FrsQbjhFKEwgL8= +github.com/whosonfirst/go-whosonfirst-export v0.3.5 h1:OjWTF1Wt6OGvKAGl7VtuljdGhQG8Daay7VMx2k9NCis= +github.com/whosonfirst/go-whosonfirst-export v0.3.5/go.mod h1:XmkUCwpzlHNUWURdOeWcDrDQlWmdNe09lIvVIzrpYCI= +github.com/whosonfirst/go-whosonfirst-export v0.3.6 h1:KsbYGXTm9pgdO2tv9sAdfJFNSOpLr/IrTOSDS7+FF/4= +github.com/whosonfirst/go-whosonfirst-export v0.3.6/go.mod h1:XmkUCwpzlHNUWURdOeWcDrDQlWmdNe09lIvVIzrpYCI= +github.com/whosonfirst/go-whosonfirst-export v0.3.7 h1:+0nDg+eb0YUvjltK5Yu0/JPjWCQshGHspfev0lAMUP4= +github.com/whosonfirst/go-whosonfirst-export v0.3.7/go.mod h1:XmkUCwpzlHNUWURdOeWcDrDQlWmdNe09lIvVIzrpYCI= +github.com/whosonfirst/go-whosonfirst-export v0.4.0 h1:d+2V+wGjRH2ldCLCFb/JTl2jYGEBxSaWZlwDDeWfI8U= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.0.0 h1:xxrZUyNOAuMeNrUvXgQtTSde/Z2nS0AKHqqfhYRmhjs= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.0.0/go.mod h1:hLZ4MkFDW5hy1hskAkWp41ix49f0/euccCMFO1d29m0= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.0 h1:lgjoKIDSFu110++cQaqsQnHahU4cU6y0liGiSfihUAI= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.0/go.mod h1:ec4uJ6eXFuGhD80THlh9kb5iZTCw6x8uNRdS/7Fl4BE= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.1 h1:NVzXfQ5e/szXXXHoD16ctqPOYyO65B3pEDV2NG55fyI= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.1/go.mod h1:ec4uJ6eXFuGhD80THlh9kb5iZTCw6x8uNRdS/7Fl4BE= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.2 h1:asiWcMY/xPmcrUYNjfDaBI5aahxds95G9yjRb1glEmM= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.2/go.mod h1:NAYuj2MLeI4YKfbp6UFigcdr+PKSPSbXZKZSvET+ulQ= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.4 h1:xQ3k23Xp5fmKcXTJJbYItLJniJ9Q0GeW2vm+OdzwvgA= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.4/go.mod h1:FR44unsidZRY4fn0tM0XlG1ONiMxx7JkwKYztDEFzR0= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.5 h1:vK+KcvyMKae/OYsbwAU5LCSHEoa8np11gAam0YCGLK8= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.5/go.mod h1:O/2L+z5U6TGBRiKThePlJ5/3n/TZJ9Tcu3ZybW9WB7I= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.0 h1:54mWDJ5byeTi43Xv4bTwUBRl7Jh78ubTxe4DgsUwW3M= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.0/go.mod h1:a5KG4HeagwCyyyDx9K41QjYrnNmqv0gWQUmm1ZdgaSU= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.1 h1:Xel8DH2SRCeSBgUlxgVJMt0wxS7yeIeYIBT8avQ927Q= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.1/go.mod h1:ZT5g5W34H4ymvxkSQXNJ+DPSl61J+u/5/uS9QxRLiPw= +github.com/whosonfirst/go-whosonfirst-flags v0.2.0/go.mod h1:ECd0AJJZIlybmjTGB9z+CPz9pSiMTwxur7fPKmDnoqI= +github.com/whosonfirst/go-whosonfirst-flags v0.4.2 h1:HWjy/0MfAQMdCj4M9hi3LAITgK/D+cuDWGHP37mFeZo= +github.com/whosonfirst/go-whosonfirst-flags v0.4.2/go.mod h1:kewFjxBiE00SqjjIanm5DPI81SYvx93wVb3ogwV/PMk= +github.com/whosonfirst/go-whosonfirst-format v0.3.0 h1:PEhduZdcTBYynvIQPARBTkEQ8csJnipLgILq/F98o/0= +github.com/whosonfirst/go-whosonfirst-format v0.3.0/go.mod h1:OVt+Nc3jg+XIcrOuWHPvA3Vz4eEJ6uBzwlFlIdw4+Ak= +github.com/whosonfirst/go-whosonfirst-format v0.3.3 h1:QCZK6fygIYKT3oyOXpnlrsAOpIuOTEHhnIx8dr4kEEQ= +github.com/whosonfirst/go-whosonfirst-format v0.3.3/go.mod h1:eTEqWH2Mw6xf0AopaMM5WRlkotUioyioK2JlYbVlsl8= +github.com/whosonfirst/go-whosonfirst-format v0.3.6 h1:gakZfbkObpXrkLZGqGaf+F7oBOUKCvpwnJUZGHvO184= +github.com/whosonfirst/go-whosonfirst-format v0.3.6/go.mod h1:eTEqWH2Mw6xf0AopaMM5WRlkotUioyioK2JlYbVlsl8= +github.com/whosonfirst/go-whosonfirst-format v0.3.7 h1:SkiUt2s0LqvH5JP7586+Rz7SgKwtRoFt7aGfWFFemoI= +github.com/whosonfirst/go-whosonfirst-format v0.3.7/go.mod h1:lMBIXCnD9ZA+wCNtu6XFYoq5DTfnEALO8k6OkEn11MM= +github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.16.3 h1:EaLfTJqWj7q3bVCNil+F9QtVylxiyWNlo09ZEUDtf+E= +github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.16.3/go.mod h1:R3GximAGJWLCITU2eh3I5Vtyze/usjOl5LTGQCDI89Y= +github.com/whosonfirst/go-whosonfirst-hash v0.1.0 h1:FpnclPIb+8M1uhSXfl3z8nYcG/3O59vgfkdV+m0hQpA= +github.com/whosonfirst/go-whosonfirst-hash v0.1.0/go.mod h1:1ZdCFZTnQt5bwnsj2daB9yHilKOKToVh+Tyj/Z8TbUk= +github.com/whosonfirst/go-whosonfirst-id v0.0.2 h1:MYtBPYtOND/KSLYeaoURWyh2OkyVqwpOXSuNj9vNf9Q= +github.com/whosonfirst/go-whosonfirst-id v0.0.2/go.mod h1:/Oq+Gbvlf33mixjc1aMqAAaOh1JB+wWlNRptbSqP0vI= +github.com/whosonfirst/go-whosonfirst-id v0.0.3 h1:sIsUkVPDbR9lgWcgQ9e4C7K4wlpSOGzALHp3iNid8ds= +github.com/whosonfirst/go-whosonfirst-id v0.0.3/go.mod h1:JuDIBvv0gzygE83XjX8Ym7JnX6OTO1X1efikSwTh8Ic= +github.com/whosonfirst/go-whosonfirst-log v0.1.0 h1:mWYI5hn16uyeLxBmPsLSvYV4rQKK/cxGVhM+bC2ZoGc= +github.com/whosonfirst/go-whosonfirst-log v0.1.0/go.mod h1:pmgBbxZSnjGVy2nsUJBBMcFagxwIKLlmRsW7ClkXmac= +github.com/whosonfirst/go-whosonfirst-placetypes v0.2.4/go.mod h1:yl0zZ5tfK80C0kl34pJcPB3mZC5XXR7ybQJ5OJyEcDU= +github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0 h1:68kuizK8FXjfEIOKlqWemhs7gyMBIgpLJDbCZF8+8Ok= +github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0/go.mod h1:ez0VFkGFbgT2/z2oi3PIuW6FewsZ2+5glyfDD79XEHk= +github.com/whosonfirst/go-whosonfirst-pool v0.1.0/go.mod h1:6LeQYv7hVK16LVevMuOuaLRfgI3JDtaoVxaMMVqRS38= +github.com/whosonfirst/go-whosonfirst-reader v0.0.3 h1:YrRYUrgBpoTE4AZGa52qCrwR1BD7wx107ngOaSRYXmg= +github.com/whosonfirst/go-whosonfirst-reader v0.0.3/go.mod h1:vBd1WkWo8/CFpbfmpNqvCRDjMv5ziHW141MELHaK338= +github.com/whosonfirst/go-whosonfirst-sources v0.1.0 h1:JuKLa6KWke22jBfJ1pM9WQHoz1/3pbDv2C+aR+THPPQ= +github.com/whosonfirst/go-whosonfirst-sources v0.1.0/go.mod h1:EUMHyGzUmqPPxlMmOp+28BFeoBdxxE0HCKRd67lkqGM= +github.com/whosonfirst/go-whosonfirst-spr/v2 v2.0.0 h1:UQ1n/uODS50mckZpXYe5GKm8XwoUUC1jRcNN8oiW2uc= +github.com/whosonfirst/go-whosonfirst-spr/v2 v2.0.0/go.mod h1:tveSSFDn8XoiCeAMarSCn769lA6e3Y0/Qi8S19Jz7Gw= +github.com/whosonfirst/go-whosonfirst-uri v0.2.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= +github.com/whosonfirst/go-whosonfirst-uri v1.0.1 h1:hVEDRuW9WhqvTksDi092OO9UecX7PAMDrD47KPEqAg0= +github.com/whosonfirst/go-whosonfirst-uri v1.0.1/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= +github.com/whosonfirst/go-whosonfirst-writer v0.2.2 h1:rkKe9UCO1W5yLiT8WlufKIRSEsCbuW9ywBVqAjnYvzY= +github.com/whosonfirst/go-whosonfirst-writer v0.2.2/go.mod h1:qasxGdvum1noY+HYpOHB2udK0KpgSvYuv5AeqMFEOag= +github.com/whosonfirst/go-writer v0.4.1/go.mod h1:kFzhremCFtnkJdmviwJEPLFYKQ5+vq6ocJPxt1bHPFY= +github.com/whosonfirst/go-writer v0.5.0 h1:+pcSBpTR6KST+HaGrIiQXCC4u2G+S5Ry8BHVgQ56jhc= +github.com/whosonfirst/go-writer v0.5.0/go.mod h1:TDK4n9E2JPxiGlmSAdi8BQUSlpawEPMF5grpFDjfqRA= +github.com/whosonfirst/warning v0.1.1 h1:h29zL3VNL9VUHztkAAndzblhrDHyik9z47OuUR2Vovw= +github.com/whosonfirst/warning v0.1.1/go.mod h1:/unEMzhB9YaMeEwTJpzLN3kM5LiSxdJhKEsf/OQhn6s= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= +go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/properties/depicts.go b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/properties/depicts.go new file mode 100644 index 0000000..ce37b1b --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/properties/depicts.go @@ -0,0 +1,49 @@ +package properties + +import ( + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +func EnsureWOFDepicts(feature []byte) ([]byte, error) { + + depicts_map := make(map[int64]bool) + + paths := []string{ + "properties.wof:depicts", + "properties.millsfield:airline_id", + "properties.millsfield:airport_id", + "properties.millsfield:aircraft_id", + "properties.millsfield:company_id", + } + + for _, p := range paths { + + rsp := gjson.GetBytes(feature, p) + + if !rsp.Exists() { + continue + } + + for _, id_rsp := range rsp.Array() { + depicts_map[id_rsp.Int()] = true + } + } + + depicts := make([]int64, 0) + + for id, _ := range depicts_map { + + if id <= 0 { + continue + } + + depicts = append(depicts, id) + } + + if len(depicts) == 0 { + return feature, nil + } + + return sjson.SetBytes(feature, "properties.wof:depicts", depicts) +} diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/properties/sfo.go b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/properties/sfo.go new file mode 100644 index 0000000..a787432 --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/properties/sfo.go @@ -0,0 +1,19 @@ +package properties + +import ( + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +func EnsureSFOLevel(feature []byte) ([]byte, error) { + + path := "properties.sfo:level" + + rsp := gjson.GetBytes(feature, path) + + if !rsp.Exists() { + return feature, nil + } + + return sjson.SetBytes(feature, path, rsp.Int()) +} diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/properties/sfomuseum.go b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/properties/sfomuseum.go new file mode 100644 index 0000000..d711cc9 --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/properties/sfomuseum.go @@ -0,0 +1,29 @@ +package properties + +import ( + "errors" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +func EnsurePlacetype(feature []byte) ([]byte, error) { + + rsp := gjson.GetBytes(feature, "properties.sfomuseum:placetype") + + if !rsp.Exists() { + return feature, errors.New("missing sfomuseum:placetype") + } + + return sjson.SetBytes(feature, "wof:placetype_alt", rsp.String()) +} + +func EnsureIsSFO(feature []byte) ([]byte, error) { + + rsp := gjson.GetBytes(feature, "properties.sfomuseum:is_sfo") + + if rsp.Exists() { + return feature, nil + } + + return sjson.SetBytes(feature, "sfomuseum:is_sfo", -1) +} diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/sfomuseum.go b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/sfomuseum.go new file mode 100644 index 0000000..5c13c4a --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-export/v2/sfomuseum.go @@ -0,0 +1,68 @@ +package export + +import ( + "context" + "encoding/json" + wof_export "github.com/whosonfirst/go-whosonfirst-export/v2" +) + +type SFOMuseumExporter struct { + wof_export.Exporter + options *wof_export.Options +} + +func init() { + + ctx := context.Background() + + err := wof_export.RegisterExporter(ctx, "sfomuseum", NewSFOMuseumExporter) + + if err != nil { + panic(err) + } +} + +func NewSFOMuseumExporter(ctx context.Context, uri string) (wof_export.Exporter, error) { + + opts, err := wof_export.NewDefaultOptions(ctx) + + if err != nil { + return nil, err + } + + ex := &SFOMuseumExporter{ + options: opts, + } + + return ex, nil +} + +func (ex *SFOMuseumExporter) ExportFeature(ctx context.Context, feature interface{}) ([]byte, error) { + + body, err := json.Marshal(feature) + + if err != nil { + return nil, err + } + + return ex.Export(ctx, body) +} + +func (ex *SFOMuseumExporter) Export(ctx context.Context, feature []byte) ([]byte, error) { + + var err error + + feature, err = Prepare(feature, ex.options) + + if err != nil { + return nil, err + } + + feature, err = wof_export.Format(feature, ex.options) + + if err != nil { + return nil, err + } + + return feature, nil +} diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-writer/.gitignore b/vendor/github.com/sfomuseum/go-sfomuseum-writer/.gitignore new file mode 100644 index 0000000..c8016db --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-writer/.gitignore @@ -0,0 +1,8 @@ +*~ +pkg +src +!vendor/src +bin +!bin/.gitignore +*.dot +*.png diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-writer/LICENSE b/vendor/github.com/sfomuseum/go-sfomuseum-writer/LICENSE new file mode 100644 index 0000000..a0c6f6a --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-writer/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2019, City and County of San Francisco, acting by and through its +Airport Commission ("City"). All rights reserved. + +The City and County of San Francisco, acting by and through its Airport +Commission, created and operates the SFO Museum. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +3. Neither the name of the City nor the names of its contributors may be used + to endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-writer/README.md b/vendor/github.com/sfomuseum/go-sfomuseum-writer/README.md new file mode 100644 index 0000000..c74f745 --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-writer/README.md @@ -0,0 +1,65 @@ +# go-sfomuseum-writer + +Common methods for writing SFO Museum (Who's On First) documents. + +## Examples + +_Note that error handling has been removed for the sake of brevity._ + +### WriteFeature + +``` +import ( + "context" + "flag" + "github.com/whosonfirst/go-writer" + "github.com/whosonfirst/go-whosonfirst-geojson-v2/feature" + sfom_writer "github.com/sfomuseum/go-sfomuseum-writer" +) + +func main() { + + flag.Parse() + + ctx := context.Background() + wr, _ := writer.NewWriter(ctx, "stdout://") + + for _, feature_path := range flag.Args() { + + fh, _ := os.Open(feature_path) + f, _ := feature.LoadWOFFeatureFromReader(fh) + + sfom_writer.WriteFeature(ctx, wr, f) + } +``` + +### WriteFeatureBytes + +``` +import ( + "context" + "flag" + "github.com/whosonfirst/go-writer" + sfom_writer "github.com/sfomuseum/go-sfomuseum-writer" + "io/ioutil" +) + +func main() { + + flag.Parse() + + ctx := context.Background() + wr, _ := writer.NewWriter(ctx, "stdout://") + + for _, feature_path := range flag.Args() { + + fh, _ := os.Open(feature_path) + body, _ := ioutil.ReadAll(fh) + + sfom_writer.WriteFeatureBytes(ctx, wr, body) + } +``` + +## See also + +* https://github.com/whosonfirst/go-writer \ No newline at end of file diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-writer/go.mod b/vendor/github.com/sfomuseum/go-sfomuseum-writer/go.mod new file mode 100644 index 0000000..a2497c7 --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-writer/go.mod @@ -0,0 +1,12 @@ +module github.com/sfomuseum/go-sfomuseum-writer + +go 1.16 + +require ( + github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.6 + github.com/tidwall/gjson v1.13.0 + github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.1 + github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.16.3 + github.com/whosonfirst/go-whosonfirst-uri v1.1.0 + github.com/whosonfirst/go-writer v0.8.0 +) diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-writer/go.sum b/vendor/github.com/sfomuseum/go-sfomuseum-writer/go.sum new file mode 100644 index 0000000..e96d2a0 --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-writer/go.sum @@ -0,0 +1,378 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/aaronland/go-artisanal-integers v0.1.0 h1:WN00aqbjfElOD8dUngFMOdd9wEWW0vyitnOMSRaNqsk= +github.com/aaronland/go-artisanal-integers v0.1.0/go.mod h1:00F0qOpuZZkzWiSSEQYk6Ul1Oc5kwgcYgsfYRmuR+wY= +github.com/aaronland/go-artisanal-integers v0.1.1 h1:bLQmWqcqgPT1NOJFwJtZZ9O/QTnttO54ODiWIVuOW1Y= +github.com/aaronland/go-artisanal-integers v0.1.1/go.mod h1:ZTeFI+Ck+q+Dp11Htld5aU6V+YwEzxzprsBO0t9GPp8= +github.com/aaronland/go-artisanal-integers-proxy v0.2.0 h1:3gQznMIWKNXbm3iMVKVC9l7nuZUj3ySUSN889fKlxhQ= +github.com/aaronland/go-artisanal-integers-proxy v0.2.0/go.mod h1:7Pkt553bRIgRMzkyPzPzvPDweCxMG6wx96qMBLlCk/Y= +github.com/aaronland/go-brooklynintegers-api v1.0.1 h1:HrEo98HD5YOfC/slzkROCxMuZTeCpT3srf1G+eO9sX8= +github.com/aaronland/go-brooklynintegers-api v1.0.1/go.mod h1:aZ4tIFeMdAQRSLZYfGdAiDeBWUHDQkFdqZ9091mk8H8= +github.com/aaronland/go-brooklynintegers-api v1.0.2/go.mod h1:JlR7i6vciy3W0aMnid7cN/Ls9Pz/vaq1lNj9sCENQf0= +github.com/aaronland/go-brooklynintegers-api v1.1.0 h1:eyoSZjn3Qiy79H+1rG/HtkEShNBZkPUWs4YKpFWkuD8= +github.com/aaronland/go-brooklynintegers-api v1.1.0/go.mod h1:agceH8JW8PcdHGCyKEDmOntccB3m7xUKrUejHpxAs6U= +github.com/aaronland/go-brooklynintegers-api v1.2.4 h1:KcRWO9kWTL6iNmZVTdPZVo7ngN0O9FFTKoQrFSjPMsU= +github.com/aaronland/go-brooklynintegers-api v1.2.4/go.mod h1:hNUn5nueKQM23ptExy20p5qDpRPhWg8RbjwW2BuXWmw= +github.com/aaronland/go-londonintegers-api v0.1.0/go.mod h1:E0VIcwks+So4FL1FYAQzrO5/OVOUsFPsqW85UrZArSE= +github.com/aaronland/go-missionintegers-api v0.1.0/go.mod h1:LZEM5+MkPX5RehLxTEv+3Y3cqMSYEk86qBa+aVecnKw= +github.com/aaronland/go-missionintegers-api v0.1.1/go.mod h1:CvByrizvklOxK6QD+Z4RNqACxHqqVjiB/GdWQfrB4Mc= +github.com/aaronland/go-pool v0.0.0-20191128211702-88306299c758 h1:m/JUyvxsCbgOyhecvs9WXFvZy9dj8BKu4T96J53d/ao= +github.com/aaronland/go-pool v0.0.0-20191128211702-88306299c758/go.mod h1:hL9EPOZJ6WVHaz7D0Jw1Dn1vaCOOSZNrYBTKMgDKYRk= +github.com/aaronland/go-roster v0.0.1 h1:r1l4n1HfWvEtOXZvhfXX0Won9Xf6QJsigdUdzOtuy/M= +github.com/aaronland/go-roster v0.0.1/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-roster v0.0.2 h1:2Fu7v4VQLRLRL/Zgr6R9S5JxsW75Ab/K88QtMVX532s= +github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-string v0.1.1 h1:btdr18owWCBN14ojKx3p+PBCKfm9qIggYEguPLUb2wE= +github.com/aaronland/go-string v0.1.1/go.mod h1:2aMIWdTqk63jZsaLLy+p9dsB1MDRqx4sHYoLtkwyYUo= +github.com/aaronland/go-uid v0.0.2 h1:5H3wtTBi58lkW5bqbaFR8Hp1MXfcraoJRlxKoUDeVfg= +github.com/aaronland/go-uid v0.0.2/go.mod h1:Kb/J05tYHWxp+Dkpod+oRkBKnxyw+szODwIQKIjvhj0= +github.com/aaronland/go-uid-artisanal v0.0.0-20191128230022-67bc446aa49d h1:2Sa8kTm10DVvAPESKu0XhQHNOBKpGxpkqLb7TvFMa4I= +github.com/aaronland/go-uid-artisanal v0.0.0-20191128230022-67bc446aa49d/go.mod h1:/fkI7C9H/GTB/TlLmNsKjHoNyXnYlkb/iG4Qp3tSCmE= +github.com/akrylysov/algnhsa v0.0.0-20190319020909-05b3d192e9a7/go.mod h1:HhzjNA0EjUWcwHTUMwqrpeAdIF3gRmpH0HpWx1hYJSc= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/aws/aws-lambda-go v1.9.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A= +github.com/aws/aws-lambda-go v1.10.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/g8rswimmer/error-chain v1.0.0 h1:WnwnunlvqtGPHVHmBfbmUyAgrtag8Y6nNpwLWmtSYOQ= +github.com/g8rswimmer/error-chain v1.0.0/go.mod h1:XPJ/brUsL7yzc5VRlIxtf9GvoUqnOKVI9fg2MB5DWx8= +github.com/go-ini/ini v1.42.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce h1:prjrVgOk2Yg6w+PflHoszQNLTUh4kaByUcEWM/9uin4= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874 h1:em+tTnzgU7N22woTBMcSJAOW7tRHAkK597W+MD/CpK8= +github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mmcloughlin/geohash v0.9.0 h1:FihR004p/aE1Sju6gcVq5OLDqGcMnpBY+8moBqIsVOs= +github.com/mmcloughlin/geohash v0.9.0/go.mod h1:oNZxQo5yWJh0eMQEP/8hwQuVx9Z9tjwFUqcTB1SmG0c= +github.com/mmcloughlin/geohash v0.10.0 h1:9w1HchfDfdeLc+jFEf/04D27KP7E2QmpDu52wPbJWRE= +github.com/mmcloughlin/geohash v0.10.0/go.mod h1:oNZxQo5yWJh0eMQEP/8hwQuVx9Z9tjwFUqcTB1SmG0c= +github.com/natefinch/atomic v0.0.0-20150920032501-a62ce929ffcc h1:7xGrl4tTpBQu5Zjll08WupHyq+Sp0Z/adtyf1cfk3Q8= +github.com/natefinch/atomic v0.0.0-20150920032501-a62ce929ffcc/go.mod h1:1rLVY/DWf3U6vSZgH16S7pymfrhK2lcUlXjgGglw/lY= +github.com/natefinch/atomic v0.0.0-20200526193002-18c0533a5b09 h1:DXR0VtCesBD2ss3toN9OEeXszpQmW9dc3SvUbUfiBC0= +github.com/natefinch/atomic v0.0.0-20200526193002-18c0533a5b09/go.mod h1:1rLVY/DWf3U6vSZgH16S7pymfrhK2lcUlXjgGglw/lY= +github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= +github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= +github.com/paulmach/go.geojson v1.4.0 h1:5x5moCkCtDo5x8af62P9IOAYGQcYHtxz2QJ3x1DoCgY= +github.com/paulmach/go.geojson v1.4.0/go.mod h1:YaKx1hKpWF+T2oj2lFJPsW/t1Q5e1jQI61eoQSTwpIs= +github.com/paulmach/orb v0.1.5 h1:GUcATabvxciqEzGd+c01/9ek3B6pUp9OdcIHFSDDSSg= +github.com/paulmach/orb v0.1.5/go.mod h1:pPwxxs3zoAyosNSbNKn1jiXV2+oovRDObDKfTvRegDI= +github.com/paulmach/orb v0.1.7 h1:Lwv10ANhqpTH3Kw5qow4YpSW5RLAx67nNGgbJpv/GC0= +github.com/paulmach/orb v0.1.7/go.mod h1:qakeIafyxF4NlRIgpXp3awhLCNuqhl3lyNpkWws2BNQ= +github.com/paulmach/orb v0.2.1 h1:Pp9UuWpUlGVRXzRC5eFlOgdlOXd/a3ALWC3UFLM3gOc= +github.com/paulmach/orb v0.2.1/go.mod h1:91bG5A8qKNOiZtlKc0BqKMB3O5kWfRQorTwo8BZ2B/0= +github.com/paulmach/orb v0.2.2 h1:PblToKAbU0xHVypex/GdZfibA1CeCfN5s0UjxyWExdo= +github.com/paulmach/orb v0.2.2/go.mod h1:FkcWtplUAIVqAuhAOV2d3rpbnQyliDOjOcLW9dUrfdU= +github.com/paulmach/orb v0.4.0 h1:ilp1MQjRapLJ1+qcays1nZpe0mvkCY+b8JU/qBKRZ1A= +github.com/paulmach/orb v0.4.0/go.mod h1:FkcWtplUAIVqAuhAOV2d3rpbnQyliDOjOcLW9dUrfdU= +github.com/paulmach/protoscan v0.2.0/go.mod h1:2c55sl1Hu6/tgRfc8Y8zADsxuSCYC2IrPh0JCqP/yrw= +github.com/paulmach/protoscan v0.2.1-0.20210522164731-4e53c6875432/go.mod h1:2sV+uZ/oQh66m4XJVZm5iqUZ62BN88Ex1E+TTS0nLzI= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sfomuseum/go-edtf v0.2.1 h1:wIbFlBK5jbqQOR3D79iTB+dZTBcs7DPFigPPimgkepg= +github.com/sfomuseum/go-edtf v0.2.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v0.2.2 h1:8n1UekTCU6fkgAf3bWqG5RyQxOd9hRhy4lg91aQ3kMk= +github.com/sfomuseum/go-edtf v0.2.2/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v0.2.3 h1:wpcpwl1RD9W/sXFDi4zpoIpQcIwIk8em9CGwa7YWv4g= +github.com/sfomuseum/go-edtf v0.2.3/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v0.2.4/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v0.3.1 h1:22DEXVvGhnpF7PD4dvpgKH0/oD8u9I+a4cXCwy1x2f4= +github.com/sfomuseum/go-edtf v0.3.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-flags v0.7.0/go.mod h1:ML3DTNbF9xnjExSdS/9FtVLjIUhRU5gm/ehzISv+t2w= +github.com/sfomuseum/go-sfomuseum-export v0.1.1 h1:mNFv4M1i8MGAKN2Y5xxbsFe3ugfDvrdjJ+xZaZl6ILU= +github.com/sfomuseum/go-sfomuseum-export v0.1.1/go.mod h1:lemoo7V/Q8RKFcK9UeUIcEfCXg18VfbnMPLcIsAHmag= +github.com/sfomuseum/go-sfomuseum-export v0.2.0 h1:rIchyjzXe1ZI8ocl3d0FmlAczdmJgMGneGHuExince4= +github.com/sfomuseum/go-sfomuseum-export v0.2.0/go.mod h1:+rBVh5lS1+w6JoiibxaSG6nR8Ov/s80gGd1f8Ae5zjQ= +github.com/sfomuseum/go-sfomuseum-export v0.2.1 h1:N2wmvEIsNd3SxSAXY+I+nWidqhFeYtZy/0F00ox8R28= +github.com/sfomuseum/go-sfomuseum-export v0.2.1/go.mod h1:e4+S/FnEI5eHRKltjNefGkOlUXe3CmFW7MCT1b7WfVs= +github.com/sfomuseum/go-sfomuseum-export v0.2.2 h1:jSdkL9w9cvCmMvU+VvnBxNoN8ifHfrSlegcdjhe/iqU= +github.com/sfomuseum/go-sfomuseum-export v0.2.2/go.mod h1:raQF0pKd6Tm3RAZKKuQ2+YeKqP0AQ3sdgKPrTQchHcI= +github.com/sfomuseum/go-sfomuseum-export v0.2.3 h1:9SGkbLNcxhMwh8pe7qhBtuA2CzMXSbMj5m6W2eNta1o= +github.com/sfomuseum/go-sfomuseum-export v0.2.3/go.mod h1:popNmXuKhXKgBJ/gR5dRCGUbmRhm6OTavJXkaRpuWU8= +github.com/sfomuseum/go-sfomuseum-export v0.2.4 h1:ZflMeRm9Hit4ojrLnELdGNzs6Q0oyqIbrAa18FSLqoM= +github.com/sfomuseum/go-sfomuseum-export v0.2.4/go.mod h1:6ekO6fQlvADbwoCR+eIIHWpT8pnhGUTT3X7T0x2UEHg= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.0.0 h1:ytxsXZCOn9YBGNwagT2vs0lTLfkwJe287TiOT9NUjeM= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.0.0/go.mod h1:/pZ5N6GQLlGe5WYibq0otoN/2pLt21g5C5V7tEgRniE= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.1.1 h1:Vj24/vnZUf3aDeN0q6pbg8BgTzWgbyCUigmLNzSCYic= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.1.1/go.mod h1:Xm7cR9hjn0SDJV9qKztUFIrcSB6awuz5Ki6mCo9DfCs= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.2.0 h1:6/iRgTR2//LwDT22pT6dkovqox47ygF9O2s1ivaWrdI= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.2.0/go.mod h1:2jpe+4jCP3cfdcD6pTBmWEzuf5ZR816q2d2xWOQe1w4= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.2.1 h1:LfF5NrNYJs4pcjs4Q9LGMFnF41I7Vj+/51d6UP1azko= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.2.1/go.mod h1:2jpe+4jCP3cfdcD6pTBmWEzuf5ZR816q2d2xWOQe1w4= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.4 h1:MYq77kpAZgKi3xxS+f9YRRUmZQL+dteOnMnp01Wj028= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.4/go.mod h1:H+sfGmhMFS9kemMSHbtU4nlNZbqx26+yrtbosySX6v8= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.5 h1:+1gBm40z4vYVu9f64Sj85kJcCCa7U73X+75RebGD9Kk= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.5/go.mod h1:QRC8o0NIJWo4thmMBl7karbsmH0wJREIEQwGe9dbG1A= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.6 h1:EF3N7AyGTDxo/yoXFhLnY/I0qH/g5DjVS1QMzasxOf8= +github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.6/go.mod h1:WWJDFbaouciMMx7+70FkC/iyxum9ElV8TvcBPNDOgLE= +github.com/skelterjohn/geom v0.0.0-20180103142417-96f3e8a219c5 h1:qQF/q/+xaKD4CAVz3zfuvpij8U4ihSGIhHfOROI4NFc= +github.com/skelterjohn/geom v0.0.0-20180103142417-96f3e8a219c5/go.mod h1:w8cQIijHlvvZM7afYlixPThHAdD+AkRFw3Mb9yQ2Y+I= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/gjson v1.2.1/go.mod h1:c/nTNbUr0E0OrXEhq1pwa8iEgc2DOt4ZZqAt1HtCkPA= +github.com/tidwall/gjson v1.3.2 h1:+7p3qQFaH3fOMXAJSrdZwGKcOO/lYdGS0HqGhPqDdTI= +github.com/tidwall/gjson v1.3.2/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.3.4 h1:On5waDnyKKk3SWE4EthbjjirAWXp43xx5cKCUZY1eZw= +github.com/tidwall/gjson v1.3.4/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.3.5 h1:2oW9FBNu8qt9jy5URgrzsVx/T/KSn3qn/smJQ0crlDQ= +github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.6.1 h1:LRbvNuNuvAiISWg6gxLEFuCe72UKy5hDqhxW/8183ws= +github.com/tidwall/gjson v1.6.1/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0= +github.com/tidwall/gjson v1.6.7 h1:Mb1M9HZCRWEcXQ8ieJo7auYyyiSux6w9XN3AdTpxJrE= +github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= +github.com/tidwall/gjson v1.6.8 h1:CTmXMClGYPAmln7652e69B7OLXfTi5ABcPPwjIWUv7w= +github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= +github.com/tidwall/gjson v1.7.4/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/gjson v1.7.5 h1:zmAN/xmX7OtpAkv4Ovfso60r/BiCi5IErCDYGNJu+uc= +github.com/tidwall/gjson v1.7.5/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/gjson v1.8.0 h1:Qt+orfosKn0rbNTZqHYDqBrmm3UDA4KRkv70fDzG+PQ= +github.com/tidwall/gjson v1.8.0/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/gjson v1.9.1/go.mod h1:jydLKE7s8J0+1/5jC4eXcuFlzKizGrCKvLmBVX/5oXc= +github.com/tidwall/gjson v1.9.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo= +github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M= +github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= +github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU= +github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8= +github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.0.4 h1:UcdIRXff12Lpnu3OLtZvnc03g4vH2suXDXhBwBqmzYg= +github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y= +github.com/tidwall/sjson v1.1.4 h1:bTSsPLdAYF5QNLSwYsKfBKKTnlGbIuhqL3CpRsjzGhg= +github.com/tidwall/sjson v1.1.4/go.mod h1:wXpKXu8CtDjKAZ+3DrKY5ROCorDFahq8l0tey/Lx1fg= +github.com/tidwall/sjson v1.1.5 h1:wsUceI/XDyZk3J1FUvuuYlK62zJv2HO2Pzb8A5EWdUE= +github.com/tidwall/sjson v1.1.5/go.mod h1:VuJzsZnTowhSxWdOgsAnb886i4AjEyTkk7tNtsL7EYE= +github.com/tidwall/sjson v1.1.6 h1:8fDdlahON04OZBlTQCIatW8FstSFJz8oxidj5h0rmSQ= +github.com/tidwall/sjson v1.1.6/go.mod h1:KN3FZ7odvXIHPbJdhNorK/M9lWweVUbXsXXhrJ/kGOA= +github.com/tidwall/sjson v1.1.7 h1:sgVPwu/yygHJ2m1pJDLgGM/h+1F5odx5Q9ljG3imRm8= +github.com/tidwall/sjson v1.1.7/go.mod h1:w/yG+ezBeTdUxiKs5NcPicO9diP38nk96QBAbIIGeFs= +github.com/tidwall/sjson v1.2.2 h1:H1Llj/C9G+BoUN2DsybLHjWvr9dx4Uazavf0sXQ+rOs= +github.com/tidwall/sjson v1.2.2/go.mod h1:jmW2RZpbKuExPFUHeFSBMiovT9ZyOziEHDRkbsdp0B0= +github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc= +github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= +github.com/tomtaylor/go-whosonfirst-format v0.2.0 h1:UD/kP2dFApJFkgo/gGC08/7t018bP7PHQreDVoTYLTs= +github.com/tomtaylor/go-whosonfirst-format v0.2.0/go.mod h1:fjMnbCrPWx3EHMHWoyqH12A/nxAvWbdIPHjXBMteDm4= +github.com/whosonfirst/algnhsa v0.1.0/go.mod h1:swLBXxaVTv3s6dJLhekdQCuCTshUew+xHjptRC21RG0= +github.com/whosonfirst/go-whosonfirst-cli v0.1.0/go.mod h1:Edy+amD+fMq1QS1yxB3u8maA8I93q/LG7JRNh+fsdfc= +github.com/whosonfirst/go-whosonfirst-export v0.1.1 h1:N2eXZH4rH3zDWBSIwYsFy1ROKe3twd82kTYc8JnnLj8= +github.com/whosonfirst/go-whosonfirst-export v0.1.1/go.mod h1:WUei94AxfPppqom4s7Y3VVTV2o6NsGjdpCaR+zyD89s= +github.com/whosonfirst/go-whosonfirst-export v0.3.0 h1:+Ub2G9QXY6ZXhfAnfLnf1dbC1YFqowq3Z+cKR8LCSTM= +github.com/whosonfirst/go-whosonfirst-export v0.3.0/go.mod h1:UO/uZcV+kGoDZPYKSb05Yj28e1sk4r8aQvCyIjBQOxc= +github.com/whosonfirst/go-whosonfirst-export v0.3.4 h1:/09Ny6HIOpPAzqCIPIOVplwekSbCTSA/wi7wJU4lwmI= +github.com/whosonfirst/go-whosonfirst-export v0.3.4/go.mod h1:y3FiLZ95MVzfE4OyPm2aWzZ7Uld74FrsQbjhFKEwgL8= +github.com/whosonfirst/go-whosonfirst-export v0.3.5 h1:OjWTF1Wt6OGvKAGl7VtuljdGhQG8Daay7VMx2k9NCis= +github.com/whosonfirst/go-whosonfirst-export v0.3.5/go.mod h1:XmkUCwpzlHNUWURdOeWcDrDQlWmdNe09lIvVIzrpYCI= +github.com/whosonfirst/go-whosonfirst-export v0.3.6 h1:KsbYGXTm9pgdO2tv9sAdfJFNSOpLr/IrTOSDS7+FF/4= +github.com/whosonfirst/go-whosonfirst-export v0.3.6/go.mod h1:XmkUCwpzlHNUWURdOeWcDrDQlWmdNe09lIvVIzrpYCI= +github.com/whosonfirst/go-whosonfirst-export v0.3.7 h1:+0nDg+eb0YUvjltK5Yu0/JPjWCQshGHspfev0lAMUP4= +github.com/whosonfirst/go-whosonfirst-export v0.3.7/go.mod h1:XmkUCwpzlHNUWURdOeWcDrDQlWmdNe09lIvVIzrpYCI= +github.com/whosonfirst/go-whosonfirst-export v0.4.0 h1:d+2V+wGjRH2ldCLCFb/JTl2jYGEBxSaWZlwDDeWfI8U= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.0.0 h1:xxrZUyNOAuMeNrUvXgQtTSde/Z2nS0AKHqqfhYRmhjs= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.0.0/go.mod h1:hLZ4MkFDW5hy1hskAkWp41ix49f0/euccCMFO1d29m0= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.1.0 h1:5l3x4LmvW4rI6K4GeEclbZHlhBXXoobOm9Xi4W1Ivi4= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.1.0/go.mod h1:hLZ4MkFDW5hy1hskAkWp41ix49f0/euccCMFO1d29m0= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.0 h1:lgjoKIDSFu110++cQaqsQnHahU4cU6y0liGiSfihUAI= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.0/go.mod h1:ec4uJ6eXFuGhD80THlh9kb5iZTCw6x8uNRdS/7Fl4BE= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.1 h1:NVzXfQ5e/szXXXHoD16ctqPOYyO65B3pEDV2NG55fyI= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.1/go.mod h1:ec4uJ6eXFuGhD80THlh9kb5iZTCw6x8uNRdS/7Fl4BE= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.3.5/go.mod h1:O/2L+z5U6TGBRiKThePlJ5/3n/TZJ9Tcu3ZybW9WB7I= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.0 h1:54mWDJ5byeTi43Xv4bTwUBRl7Jh78ubTxe4DgsUwW3M= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.0/go.mod h1:a5KG4HeagwCyyyDx9K41QjYrnNmqv0gWQUmm1ZdgaSU= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.1 h1:Xel8DH2SRCeSBgUlxgVJMt0wxS7yeIeYIBT8avQ927Q= +github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.1/go.mod h1:ZT5g5W34H4ymvxkSQXNJ+DPSl61J+u/5/uS9QxRLiPw= +github.com/whosonfirst/go-whosonfirst-flags v0.1.0 h1:llb2wtsI2y+gHZCmWaamMCx4YDRE8ZXQRRYqC7qB4so= +github.com/whosonfirst/go-whosonfirst-flags v0.1.0/go.mod h1:bovMiQphaVhqemXFmNVf9Ts0tqnWtzHRFMUSKX+zTE8= +github.com/whosonfirst/go-whosonfirst-flags v0.2.0/go.mod h1:ECd0AJJZIlybmjTGB9z+CPz9pSiMTwxur7fPKmDnoqI= +github.com/whosonfirst/go-whosonfirst-flags v0.4.2 h1:HWjy/0MfAQMdCj4M9hi3LAITgK/D+cuDWGHP37mFeZo= +github.com/whosonfirst/go-whosonfirst-flags v0.4.2/go.mod h1:kewFjxBiE00SqjjIanm5DPI81SYvx93wVb3ogwV/PMk= +github.com/whosonfirst/go-whosonfirst-format v0.3.0 h1:PEhduZdcTBYynvIQPARBTkEQ8csJnipLgILq/F98o/0= +github.com/whosonfirst/go-whosonfirst-format v0.3.0/go.mod h1:OVt+Nc3jg+XIcrOuWHPvA3Vz4eEJ6uBzwlFlIdw4+Ak= +github.com/whosonfirst/go-whosonfirst-format v0.3.6/go.mod h1:eTEqWH2Mw6xf0AopaMM5WRlkotUioyioK2JlYbVlsl8= +github.com/whosonfirst/go-whosonfirst-format v0.3.7 h1:SkiUt2s0LqvH5JP7586+Rz7SgKwtRoFt7aGfWFFemoI= +github.com/whosonfirst/go-whosonfirst-format v0.3.7/go.mod h1:lMBIXCnD9ZA+wCNtu6XFYoq5DTfnEALO8k6OkEn11MM= +github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.12.0 h1:aYsgIq/g4fU5rVdumMTqG9ysJxwhW085buzaMxP5mjs= +github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.12.0/go.mod h1:hC145O2TiPTU8zemHRriKOkG972BNwEowqjxqHeWDwM= +github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.12.3 h1:v4BLn+kM/BB2x1ZiMLlPAiBcFjmWnEGJmnIGqvZC/LI= +github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.12.3/go.mod h1:/F8jdjew5bCB9J6G0xyMMEay+pQv/WuARYhASMKZbR4= +github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.14.1 h1:Bp5gwvIZXkfGhS4Kv1Cs8R5PNo1EipISPOsDDPSrKQQ= +github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.14.1/go.mod h1:UkzipFE8gZC9NU1PLIE4DUwjFHOlafkoNxd2Ng0ZIjc= +github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.15.1 h1:Kxsd+B6U97YRbIlpBxrZpXNXDYqJYwEBxhgUUzlQky0= +github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.15.1/go.mod h1:zAXmgT1EjBAt5HawVNyr3/N53j5iVqxFVha8VBhkra0= +github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.16.3 h1:EaLfTJqWj7q3bVCNil+F9QtVylxiyWNlo09ZEUDtf+E= +github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.16.3/go.mod h1:R3GximAGJWLCITU2eh3I5Vtyze/usjOl5LTGQCDI89Y= +github.com/whosonfirst/go-whosonfirst-hash v0.1.0 h1:FpnclPIb+8M1uhSXfl3z8nYcG/3O59vgfkdV+m0hQpA= +github.com/whosonfirst/go-whosonfirst-hash v0.1.0/go.mod h1:1ZdCFZTnQt5bwnsj2daB9yHilKOKToVh+Tyj/Z8TbUk= +github.com/whosonfirst/go-whosonfirst-id v0.0.2 h1:MYtBPYtOND/KSLYeaoURWyh2OkyVqwpOXSuNj9vNf9Q= +github.com/whosonfirst/go-whosonfirst-id v0.0.2/go.mod h1:/Oq+Gbvlf33mixjc1aMqAAaOh1JB+wWlNRptbSqP0vI= +github.com/whosonfirst/go-whosonfirst-id v0.0.3 h1:sIsUkVPDbR9lgWcgQ9e4C7K4wlpSOGzALHp3iNid8ds= +github.com/whosonfirst/go-whosonfirst-id v0.0.3/go.mod h1:JuDIBvv0gzygE83XjX8Ym7JnX6OTO1X1efikSwTh8Ic= +github.com/whosonfirst/go-whosonfirst-log v0.1.0 h1:mWYI5hn16uyeLxBmPsLSvYV4rQKK/cxGVhM+bC2ZoGc= +github.com/whosonfirst/go-whosonfirst-log v0.1.0/go.mod h1:pmgBbxZSnjGVy2nsUJBBMcFagxwIKLlmRsW7ClkXmac= +github.com/whosonfirst/go-whosonfirst-placetypes v0.1.0 h1:zuSk8eqeEkg42sIZ4EF71IMtphdTbG80qJsXhuZXXbM= +github.com/whosonfirst/go-whosonfirst-placetypes v0.1.0/go.mod h1:Jdmug2QQLbrmg+UcYGz8k575GnrOEg63vZVS46e5fMs= +github.com/whosonfirst/go-whosonfirst-placetypes v0.2.4/go.mod h1:yl0zZ5tfK80C0kl34pJcPB3mZC5XXR7ybQJ5OJyEcDU= +github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0 h1:68kuizK8FXjfEIOKlqWemhs7gyMBIgpLJDbCZF8+8Ok= +github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0/go.mod h1:ez0VFkGFbgT2/z2oi3PIuW6FewsZ2+5glyfDD79XEHk= +github.com/whosonfirst/go-whosonfirst-pool v0.1.0/go.mod h1:6LeQYv7hVK16LVevMuOuaLRfgI3JDtaoVxaMMVqRS38= +github.com/whosonfirst/go-whosonfirst-sources v0.1.0 h1:JuKLa6KWke22jBfJ1pM9WQHoz1/3pbDv2C+aR+THPPQ= +github.com/whosonfirst/go-whosonfirst-sources v0.1.0/go.mod h1:EUMHyGzUmqPPxlMmOp+28BFeoBdxxE0HCKRd67lkqGM= +github.com/whosonfirst/go-whosonfirst-spr v0.1.0 h1:5qE629nCiucF2upy5NjPOEl9cFatsljykYY0l2JKgAk= +github.com/whosonfirst/go-whosonfirst-spr v0.1.0/go.mod h1:R8GtEVz1GVSnwwOjzcoVUd172ZK26Q7hQSLI6SGG7lM= +github.com/whosonfirst/go-whosonfirst-spr/v2 v2.0.0 h1:UQ1n/uODS50mckZpXYe5GKm8XwoUUC1jRcNN8oiW2uc= +github.com/whosonfirst/go-whosonfirst-spr/v2 v2.0.0/go.mod h1:tveSSFDn8XoiCeAMarSCn769lA6e3Y0/Qi8S19Jz7Gw= +github.com/whosonfirst/go-whosonfirst-uri v0.1.0 h1:JMlpam0x1hVrFBMTAPY3edIHz7azfMK8lLI2kM9BgbI= +github.com/whosonfirst/go-whosonfirst-uri v0.1.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= +github.com/whosonfirst/go-whosonfirst-uri v0.2.0 h1:iODHdyvW+8IXqHZTixZ/9GEZy1dVKGj6dMRg7fn0d2M= +github.com/whosonfirst/go-whosonfirst-uri v0.2.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= +github.com/whosonfirst/go-whosonfirst-uri v1.0.1 h1:hVEDRuW9WhqvTksDi092OO9UecX7PAMDrD47KPEqAg0= +github.com/whosonfirst/go-whosonfirst-uri v1.0.1/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= +github.com/whosonfirst/go-whosonfirst-uri v1.1.0 h1:kNYOmKSm3u2asUOeq7yXL1Q8gFKkPIl8A0qinKrGV/8= +github.com/whosonfirst/go-whosonfirst-uri v1.1.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= +github.com/whosonfirst/go-writer v0.0.2 h1:ZWPMCUyQS8Khvyhz34iAsEhvRFFWo5JvraQOU/0kf5U= +github.com/whosonfirst/go-writer v0.0.2/go.mod h1:icuZIaxlsSAb8TnAzZFYt2G4ObYeI3vBmcNRimB92sY= +github.com/whosonfirst/go-writer v0.2.0 h1:3RCym51cVwbhTpAZ7XKoWsXcodbEbKGDWYUpHoXyEOQ= +github.com/whosonfirst/go-writer v0.2.0/go.mod h1:NGPaud/M3Q6IKLDj2X0PbKKpfWRF9Zneups/BMCG0+0= +github.com/whosonfirst/go-writer v0.4.0 h1:pwZWJVvmRzdvTwoHKxRO4VY013ltp9NA7nsTTK4X/L8= +github.com/whosonfirst/go-writer v0.4.0/go.mod h1:kFzhremCFtnkJdmviwJEPLFYKQ5+vq6ocJPxt1bHPFY= +github.com/whosonfirst/go-writer v0.4.1 h1:pAZ/cwaCM129PfwYy28ggCIRfL98OkrYxNnAxz2dksg= +github.com/whosonfirst/go-writer v0.4.1/go.mod h1:kFzhremCFtnkJdmviwJEPLFYKQ5+vq6ocJPxt1bHPFY= +github.com/whosonfirst/go-writer v0.5.0 h1:+pcSBpTR6KST+HaGrIiQXCC4u2G+S5Ry8BHVgQ56jhc= +github.com/whosonfirst/go-writer v0.5.0/go.mod h1:TDK4n9E2JPxiGlmSAdi8BQUSlpawEPMF5grpFDjfqRA= +github.com/whosonfirst/go-writer v0.7.1 h1:09JAP/ryd3xpBIWQ9tRAWfgytxN6gNjVnfwu47v0dmM= +github.com/whosonfirst/go-writer v0.7.1/go.mod h1:Qj0rZgdoFagSJ1xwhm60KyTgMU4DK5C6q5n8zKpgnj8= +github.com/whosonfirst/go-writer v0.8.0 h1:Tgibn65KrLqfC5YSIxZfXNsNFdk8bvP3/LpqbERU0FY= +github.com/whosonfirst/go-writer v0.8.0/go.mod h1:Qj0rZgdoFagSJ1xwhm60KyTgMU4DK5C6q5n8zKpgnj8= +github.com/whosonfirst/warning v0.1.0 h1:NgMa6a6Xv7FdDNgpqK5j/FDo6qrcFzFtidAExDqPfC0= +github.com/whosonfirst/warning v0.1.0/go.mod h1:cAez7FpC/UEUrbiOXZO15v2JM8eijtFHQlN93AGFy1k= +github.com/whosonfirst/warning v0.1.1 h1:h29zL3VNL9VUHztkAAndzblhrDHyik9z47OuUR2Vovw= +github.com/whosonfirst/warning v0.1.1/go.mod h1:/unEMzhB9YaMeEwTJpzLN3kM5LiSxdJhKEsf/OQhn6s= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= +go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/vendor/github.com/sfomuseum/go-sfomuseum-writer/writer.go b/vendor/github.com/sfomuseum/go-sfomuseum-writer/writer.go new file mode 100644 index 0000000..6cc4273 --- /dev/null +++ b/vendor/github.com/sfomuseum/go-sfomuseum-writer/writer.go @@ -0,0 +1,56 @@ +package writer + +import ( + "bytes" + "context" + "errors" + "github.com/whosonfirst/go-whosonfirst-export/v2" + _ "github.com/sfomuseum/go-sfomuseum-export/v2" + "github.com/tidwall/gjson" + "github.com/whosonfirst/go-whosonfirst-geojson-v2" + "github.com/whosonfirst/go-whosonfirst-uri" + go_writer "github.com/whosonfirst/go-writer" +) + +func WriteFeature(ctx context.Context, wr go_writer.Writer, f geojson.Feature) (int64, error) { + return WriteFeatureBytes(ctx, wr, f.Bytes()) +} + +func WriteFeatureBytes(ctx context.Context, wr go_writer.Writer, body []byte) (int64, error) { + + ex, err := export.NewExporter(ctx, "sfomuseum://") + + if err != nil { + return -1, err + } + + ex_body, err := ex.Export(ctx, body) + + if err != nil { + return -1, err + } + + id_rsp := gjson.GetBytes(ex_body, "properties.wof:id") + + if !id_rsp.Exists() { + return -1, errors.New("Missing 'properties.wof:id' property") + } + + id := id_rsp.Int() + + rel_path, err := uri.Id2RelPath(id) + + if err != nil { + return -1, err + } + + br := bytes.NewReader(ex_body) + + _, err = wr.Write(ctx, rel_path, br) + + if err != nil { + return -1, err + } + + return id, nil +} diff --git a/vendor/github.com/tidwall/sjson/LICENSE b/vendor/github.com/tidwall/sjson/LICENSE new file mode 100644 index 0000000..89593c7 --- /dev/null +++ b/vendor/github.com/tidwall/sjson/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Josh Baker + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. + diff --git a/vendor/github.com/tidwall/sjson/README.md b/vendor/github.com/tidwall/sjson/README.md new file mode 100644 index 0000000..4598424 --- /dev/null +++ b/vendor/github.com/tidwall/sjson/README.md @@ -0,0 +1,278 @@ +
+ +set a json value quickly
+ +SJSON is a Go package that provides a [very fast](#performance) and simple way to set a value in a json document. +For quickly retrieving json values check out [GJSON](https://github.com/tidwall/gjson). + +For a command line interface check out [JJ](https://github.com/tidwall/jj). + +Getting Started +=============== + +Installing +---------- + +To start using SJSON, install Go and run `go get`: + +```sh +$ go get -u github.com/tidwall/sjson +``` + +This will retrieve the library. + +Set a value +----------- +Set sets the value for the specified path. +A path is in dot syntax, such as "name.last" or "age". +This function expects that the json is well-formed and validated. +Invalid json will not panic, but it may return back unexpected results. +Invalid paths may return an error. + +```go +package main + +import "github.com/tidwall/sjson" + +const json = `{"name":{"first":"Janet","last":"Prichard"},"age":47}` + +func main() { + value, _ := sjson.Set(json, "name.last", "Anderson") + println(value) +} +``` + +This will print: + +```json +{"name":{"first":"Janet","last":"Anderson"},"age":47} +``` + +Path syntax +----------- + +A path is a series of keys separated by a dot. +The dot and colon characters can be escaped with ``\``. + +```json +{ + "name": {"first": "Tom", "last": "Anderson"}, + "age":37, + "children": ["Sara","Alex","Jack"], + "fav.movie": "Deer Hunter", + "friends": [ + {"first": "James", "last": "Murphy"}, + {"first": "Roger", "last": "Craig"} + ] +} +``` +``` +"name.last" >> "Anderson" +"age" >> 37 +"children.1" >> "Alex" +"friends.1.last" >> "Craig" +``` + +The `-1` key can be used to append a value to an existing array: + +``` +"children.-1" >> appends a new value to the end of the children array +``` + +Normally number keys are used to modify arrays, but it's possible to force a numeric object key by using the colon character: + +```json +{ + "users":{ + "2313":{"name":"Sara"}, + "7839":{"name":"Andy"} + } +} +``` + +A colon path would look like: + +``` +"users.:2313.name" >> "Sara" +``` + +Supported types +--------------- + +Pretty much any type is supported: + +```go +sjson.Set(`{"key":true}`, "key", nil) +sjson.Set(`{"key":true}`, "key", false) +sjson.Set(`{"key":true}`, "key", 1) +sjson.Set(`{"key":true}`, "key", 10.5) +sjson.Set(`{"key":true}`, "key", "hello") +sjson.Set(`{"key":true}`, "key", []string{"hello", "world"}) +sjson.Set(`{"key":true}`, "key", map[string]interface{}{"hello":"world"}) +``` + +When a type is not recognized, SJSON will fallback to the `encoding/json` Marshaller. + + +Examples +-------- + +Set a value from empty document: +```go +value, _ := sjson.Set("", "name", "Tom") +println(value) + +// Output: +// {"name":"Tom"} +``` + +Set a nested value from empty document: +```go +value, _ := sjson.Set("", "name.last", "Anderson") +println(value) + +// Output: +// {"name":{"last":"Anderson"}} +``` + +Set a new value: +```go +value, _ := sjson.Set(`{"name":{"last":"Anderson"}}`, "name.first", "Sara") +println(value) + +// Output: +// {"name":{"first":"Sara","last":"Anderson"}} +``` + +Update an existing value: +```go +value, _ := sjson.Set(`{"name":{"last":"Anderson"}}`, "name.last", "Smith") +println(value) + +// Output: +// {"name":{"last":"Smith"}} +``` + +Set a new array value: +```go +value, _ := sjson.Set(`{"friends":["Andy","Carol"]}`, "friends.2", "Sara") +println(value) + +// Output: +// {"friends":["Andy","Carol","Sara"] +``` + +Append an array value by using the `-1` key in a path: +```go +value, _ := sjson.Set(`{"friends":["Andy","Carol"]}`, "friends.-1", "Sara") +println(value) + +// Output: +// {"friends":["Andy","Carol","Sara"] +``` + +Append an array value that is past the end: +```go +value, _ := sjson.Set(`{"friends":["Andy","Carol"]}`, "friends.4", "Sara") +println(value) + +// Output: +// {"friends":["Andy","Carol",null,null,"Sara"] +``` + +Delete a value: +```go +value, _ := sjson.Delete(`{"name":{"first":"Sara","last":"Anderson"}}`, "name.first") +println(value) + +// Output: +// {"name":{"last":"Anderson"}} +``` + +Delete an array value: +```go +value, _ := sjson.Delete(`{"friends":["Andy","Carol"]}`, "friends.1") +println(value) + +// Output: +// {"friends":["Andy"]} +``` + +Delete the last array value: +```go +value, _ := sjson.Delete(`{"friends":["Andy","Carol"]}`, "friends.-1") +println(value) + +// Output: +// {"friends":["Andy"]} +``` + +## Performance + +Benchmarks of SJSON alongside [encoding/json](https://golang.org/pkg/encoding/json/), +[ffjson](https://github.com/pquerna/ffjson), +[EasyJSON](https://github.com/mailru/easyjson), +and [Gabs](https://github.com/Jeffail/gabs) + +``` +Benchmark_SJSON-8 3000000 805 ns/op 1077 B/op 3 allocs/op +Benchmark_SJSON_ReplaceInPlace-8 3000000 449 ns/op 0 B/op 0 allocs/op +Benchmark_JSON_Map-8 300000 21236 ns/op 6392 B/op 150 allocs/op +Benchmark_JSON_Struct-8 300000 14691 ns/op 1789 B/op 24 allocs/op +Benchmark_Gabs-8 300000 21311 ns/op 6752 B/op 150 allocs/op +Benchmark_FFJSON-8 300000 17673 ns/op 3589 B/op 47 allocs/op +Benchmark_EasyJSON-8 1500000 3119 ns/op 1061 B/op 13 allocs/op +``` + +JSON document used: + +```json +{ + "widget": { + "debug": "on", + "window": { + "title": "Sample Konfabulator Widget", + "name": "main_window", + "width": 500, + "height": 500 + }, + "image": { + "src": "Images/Sun.png", + "hOffset": 250, + "vOffset": 250, + "alignment": "center" + }, + "text": { + "data": "Click Here", + "size": 36, + "style": "bold", + "vOffset": 100, + "alignment": "center", + "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" + } + } +} +``` + +Each operation was rotated though one of the following search paths: + +``` +widget.window.name +widget.image.hOffset +widget.text.onMouseUp +``` + +*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.7 and can be be found [here](https://github.com/tidwall/sjson-benchmarks)*. + +## Contact +Josh Baker [@tidwall](http://twitter.com/tidwall) + +## License + +SJSON source code is available under the MIT [License](/LICENSE). diff --git a/vendor/github.com/tidwall/sjson/go.mod b/vendor/github.com/tidwall/sjson/go.mod new file mode 100644 index 0000000..534cb26 --- /dev/null +++ b/vendor/github.com/tidwall/sjson/go.mod @@ -0,0 +1,8 @@ +module github.com/tidwall/sjson + +go 1.14 + +require ( + github.com/tidwall/gjson v1.12.1 + github.com/tidwall/pretty v1.2.0 +) diff --git a/vendor/github.com/tidwall/sjson/go.sum b/vendor/github.com/tidwall/sjson/go.sum new file mode 100644 index 0000000..1a9d4de --- /dev/null +++ b/vendor/github.com/tidwall/sjson/go.sum @@ -0,0 +1,6 @@ +github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo= +github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= diff --git a/vendor/github.com/tidwall/sjson/logo.png b/vendor/github.com/tidwall/sjson/logo.png new file mode 100644 index 0000000..b5aa257 Binary files /dev/null and b/vendor/github.com/tidwall/sjson/logo.png differ diff --git a/vendor/github.com/tidwall/sjson/sjson.go b/vendor/github.com/tidwall/sjson/sjson.go new file mode 100644 index 0000000..a55eef3 --- /dev/null +++ b/vendor/github.com/tidwall/sjson/sjson.go @@ -0,0 +1,737 @@ +// Package sjson provides setting json values. +package sjson + +import ( + jsongo "encoding/json" + "sort" + "strconv" + "unsafe" + + "github.com/tidwall/gjson" +) + +type errorType struct { + msg string +} + +func (err *errorType) Error() string { + return err.msg +} + +// Options represents additional options for the Set and Delete functions. +type Options struct { + // Optimistic is a hint that the value likely exists which + // allows for the sjson to perform a fast-track search and replace. + Optimistic bool + // ReplaceInPlace is a hint to replace the input json rather than + // allocate a new json byte slice. When this field is specified + // the input json will not longer be valid and it should not be used + // In the case when the destination slice doesn't have enough free + // bytes to replace the data in place, a new bytes slice will be + // created under the hood. + // The Optimistic flag must be set to true and the input must be a + // byte slice in order to use this field. + ReplaceInPlace bool +} + +type pathResult struct { + part string // current key part + gpart string // gjson get part + path string // remaining path + force bool // force a string key + more bool // there is more path to parse +} + +func isSimpleChar(ch byte) bool { + switch ch { + case '|', '#', '@', '*', '?': + return false + default: + return true + } +} + +func parsePath(path string) (res pathResult, simple bool) { + var r pathResult + if len(path) > 0 && path[0] == ':' { + r.force = true + path = path[1:] + } + for i := 0; i < len(path); i++ { + if path[i] == '.' { + r.part = path[:i] + r.gpart = path[:i] + r.path = path[i+1:] + r.more = true + return r, true + } + if !isSimpleChar(path[i]) { + return r, false + } + if path[i] == '\\' { + // go into escape mode. this is a slower path that + // strips off the escape character from the part. + epart := []byte(path[:i]) + gpart := []byte(path[:i+1]) + i++ + if i < len(path) { + epart = append(epart, path[i]) + gpart = append(gpart, path[i]) + i++ + for ; i < len(path); i++ { + if path[i] == '\\' { + gpart = append(gpart, '\\') + i++ + if i < len(path) { + epart = append(epart, path[i]) + gpart = append(gpart, path[i]) + } + continue + } else if path[i] == '.' { + r.part = string(epart) + r.gpart = string(gpart) + r.path = path[i+1:] + r.more = true + return r, true + } else if !isSimpleChar(path[i]) { + return r, false + } + epart = append(epart, path[i]) + gpart = append(gpart, path[i]) + } + } + // append the last part + r.part = string(epart) + r.gpart = string(gpart) + return r, true + } + } + r.part = path + r.gpart = path + return r, true +} + +func mustMarshalString(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] < ' ' || s[i] > 0x7f || s[i] == '"' || s[i] == '\\' { + return true + } + } + return false +} + +// appendStringify makes a json string and appends to buf. +func appendStringify(buf []byte, s string) []byte { + if mustMarshalString(s) { + b, _ := jsongo.Marshal(s) + return append(buf, b...) + } + buf = append(buf, '"') + buf = append(buf, s...) + buf = append(buf, '"') + return buf +} + +// appendBuild builds a json block from a json path. +func appendBuild(buf []byte, array bool, paths []pathResult, raw string, + stringify bool) []byte { + if !array { + buf = appendStringify(buf, paths[0].part) + buf = append(buf, ':') + } + if len(paths) > 1 { + n, numeric := atoui(paths[1]) + if numeric || (!paths[1].force && paths[1].part == "-1") { + buf = append(buf, '[') + buf = appendRepeat(buf, "null,", n) + buf = appendBuild(buf, true, paths[1:], raw, stringify) + buf = append(buf, ']') + } else { + buf = append(buf, '{') + buf = appendBuild(buf, false, paths[1:], raw, stringify) + buf = append(buf, '}') + } + } else { + if stringify { + buf = appendStringify(buf, raw) + } else { + buf = append(buf, raw...) + } + } + return buf +} + +// atoui does a rip conversion of string -> unigned int. +func atoui(r pathResult) (n int, ok bool) { + if r.force { + return 0, false + } + for i := 0; i < len(r.part); i++ { + if r.part[i] < '0' || r.part[i] > '9' { + return 0, false + } + n = n*10 + int(r.part[i]-'0') + } + return n, true +} + +// appendRepeat repeats string "n" times and appends to buf. +func appendRepeat(buf []byte, s string, n int) []byte { + for i := 0; i < n; i++ { + buf = append(buf, s...) + } + return buf +} + +// trim does a rip trim +func trim(s string) string { + for len(s) > 0 { + if s[0] <= ' ' { + s = s[1:] + continue + } + break + } + for len(s) > 0 { + if s[len(s)-1] <= ' ' { + s = s[:len(s)-1] + continue + } + break + } + return s +} + +// deleteTailItem deletes the previous key or comma. +func deleteTailItem(buf []byte) ([]byte, bool) { +loop: + for i := len(buf) - 1; i >= 0; i-- { + // look for either a ',',':','[' + switch buf[i] { + case '[': + return buf, true + case ',': + return buf[:i], false + case ':': + // delete tail string + i-- + for ; i >= 0; i-- { + if buf[i] == '"' { + i-- + for ; i >= 0; i-- { + if buf[i] == '"' { + i-- + if i >= 0 && buf[i] == '\\' { + i-- + continue + } + for ; i >= 0; i-- { + // look for either a ',','{' + switch buf[i] { + case '{': + return buf[:i+1], true + case ',': + return buf[:i], false + } + } + } + } + break + } + } + break loop + } + } + return buf, false +} + +var errNoChange = &errorType{"no change"} + +func appendRawPaths(buf []byte, jstr string, paths []pathResult, raw string, + stringify, del bool) ([]byte, error) { + var err error + var res gjson.Result + var found bool + if del { + if paths[0].part == "-1" && !paths[0].force { + res = gjson.Get(jstr, "#") + if res.Int() > 0 { + res = gjson.Get(jstr, strconv.FormatInt(int64(res.Int()-1), 10)) + found = true + } + } + } + if !found { + res = gjson.Get(jstr, paths[0].gpart) + } + if res.Index > 0 { + if len(paths) > 1 { + buf = append(buf, jstr[:res.Index]...) + buf, err = appendRawPaths(buf, res.Raw, paths[1:], raw, + stringify, del) + if err != nil { + return nil, err + } + buf = append(buf, jstr[res.Index+len(res.Raw):]...) + return buf, nil + } + buf = append(buf, jstr[:res.Index]...) + var exidx int // additional forward stripping + if del { + var delNextComma bool + buf, delNextComma = deleteTailItem(buf) + if delNextComma { + i, j := res.Index+len(res.Raw), 0 + for ; i < len(jstr); i, j = i+1, j+1 { + if jstr[i] <= ' ' { + continue + } + if jstr[i] == ',' { + exidx = j + 1 + } + break + } + } + } else { + if stringify { + buf = appendStringify(buf, raw) + } else { + buf = append(buf, raw...) + } + } + buf = append(buf, jstr[res.Index+len(res.Raw)+exidx:]...) + return buf, nil + } + if del { + return nil, errNoChange + } + n, numeric := atoui(paths[0]) + isempty := true + for i := 0; i < len(jstr); i++ { + if jstr[i] > ' ' { + isempty = false + break + } + } + if isempty { + if numeric { + jstr = "[]" + } else { + jstr = "{}" + } + } + jsres := gjson.Parse(jstr) + if jsres.Type != gjson.JSON { + if numeric { + jstr = "[]" + } else { + jstr = "{}" + } + jsres = gjson.Parse(jstr) + } + var comma bool + for i := 1; i < len(jsres.Raw); i++ { + if jsres.Raw[i] <= ' ' { + continue + } + if jsres.Raw[i] == '}' || jsres.Raw[i] == ']' { + break + } + comma = true + break + } + switch jsres.Raw[0] { + default: + return nil, &errorType{"json must be an object or array"} + case '{': + end := len(jsres.Raw) - 1 + for ; end > 0; end-- { + if jsres.Raw[end] == '}' { + break + } + } + buf = append(buf, jsres.Raw[:end]...) + if comma { + buf = append(buf, ',') + } + buf = appendBuild(buf, false, paths, raw, stringify) + buf = append(buf, '}') + return buf, nil + case '[': + var appendit bool + if !numeric { + if paths[0].part == "-1" && !paths[0].force { + appendit = true + } else { + return nil, &errorType{ + "cannot set array element for non-numeric key '" + + paths[0].part + "'"} + } + } + if appendit { + njson := trim(jsres.Raw) + if njson[len(njson)-1] == ']' { + njson = njson[:len(njson)-1] + } + buf = append(buf, njson...) + if comma { + buf = append(buf, ',') + } + + buf = appendBuild(buf, true, paths, raw, stringify) + buf = append(buf, ']') + return buf, nil + } + buf = append(buf, '[') + ress := jsres.Array() + for i := 0; i < len(ress); i++ { + if i > 0 { + buf = append(buf, ',') + } + buf = append(buf, ress[i].Raw...) + } + if len(ress) == 0 { + buf = appendRepeat(buf, "null,", n-len(ress)) + } else { + buf = appendRepeat(buf, ",null", n-len(ress)) + if comma { + buf = append(buf, ',') + } + } + buf = appendBuild(buf, true, paths, raw, stringify) + buf = append(buf, ']') + return buf, nil + } +} + +func isOptimisticPath(path string) bool { + for i := 0; i < len(path); i++ { + if path[i] < '.' || path[i] > 'z' { + return false + } + if path[i] > '9' && path[i] < 'A' { + return false + } + if path[i] > 'z' { + return false + } + } + return true +} + +// Set sets a json value for the specified path. +// A path is in dot syntax, such as "name.last" or "age". +// This function expects that the json is well-formed, and does not validate. +// Invalid json will not panic, but it may return back unexpected results. +// An error is returned if the path is not valid. +// +// A path is a series of keys separated by a dot. +// +// { +// "name": {"first": "Tom", "last": "Anderson"}, +// "age":37, +// "children": ["Sara","Alex","Jack"], +// "friends": [ +// {"first": "James", "last": "Murphy"}, +// {"first": "Roger", "last": "Craig"} +// ] +// } +// "name.last" >> "Anderson" +// "age" >> 37 +// "children.1" >> "Alex" +// +func Set(json, path string, value interface{}) (string, error) { + return SetOptions(json, path, value, nil) +} + +// SetBytes sets a json value for the specified path. +// If working with bytes, this method preferred over +// Set(string(data), path, value) +func SetBytes(json []byte, path string, value interface{}) ([]byte, error) { + return SetBytesOptions(json, path, value, nil) +} + +// SetRaw sets a raw json value for the specified path. +// This function works the same as Set except that the value is set as a +// raw block of json. This allows for setting premarshalled json objects. +func SetRaw(json, path, value string) (string, error) { + return SetRawOptions(json, path, value, nil) +} + +// SetRawOptions sets a raw json value for the specified path with options. +// This furnction works the same as SetOptions except that the value is set +// as a raw block of json. This allows for setting premarshalled json objects. +func SetRawOptions(json, path, value string, opts *Options) (string, error) { + var optimistic bool + if opts != nil { + optimistic = opts.Optimistic + } + res, err := set(json, path, value, false, false, optimistic, false) + if err == errNoChange { + return json, nil + } + return string(res), err +} + +// SetRawBytes sets a raw json value for the specified path. +// If working with bytes, this method preferred over +// SetRaw(string(data), path, value) +func SetRawBytes(json []byte, path string, value []byte) ([]byte, error) { + return SetRawBytesOptions(json, path, value, nil) +} + +type dtype struct{} + +// Delete deletes a value from json for the specified path. +func Delete(json, path string) (string, error) { + return Set(json, path, dtype{}) +} + +// DeleteBytes deletes a value from json for the specified path. +func DeleteBytes(json []byte, path string) ([]byte, error) { + return SetBytes(json, path, dtype{}) +} + +type stringHeader struct { + data unsafe.Pointer + len int +} + +type sliceHeader struct { + data unsafe.Pointer + len int + cap int +} + +func set(jstr, path, raw string, + stringify, del, optimistic, inplace bool) ([]byte, error) { + if path == "" { + return []byte(jstr), &errorType{"path cannot be empty"} + } + if !del && optimistic && isOptimisticPath(path) { + res := gjson.Get(jstr, path) + if res.Exists() && res.Index > 0 { + sz := len(jstr) - len(res.Raw) + len(raw) + if stringify { + sz += 2 + } + if inplace && sz <= len(jstr) { + if !stringify || !mustMarshalString(raw) { + jsonh := *(*stringHeader)(unsafe.Pointer(&jstr)) + jsonbh := sliceHeader{ + data: jsonh.data, len: jsonh.len, cap: jsonh.len} + jbytes := *(*[]byte)(unsafe.Pointer(&jsonbh)) + if stringify { + jbytes[res.Index] = '"' + copy(jbytes[res.Index+1:], []byte(raw)) + jbytes[res.Index+1+len(raw)] = '"' + copy(jbytes[res.Index+1+len(raw)+1:], + jbytes[res.Index+len(res.Raw):]) + } else { + copy(jbytes[res.Index:], []byte(raw)) + copy(jbytes[res.Index+len(raw):], + jbytes[res.Index+len(res.Raw):]) + } + return jbytes[:sz], nil + } + return []byte(jstr), nil + } + buf := make([]byte, 0, sz) + buf = append(buf, jstr[:res.Index]...) + if stringify { + buf = appendStringify(buf, raw) + } else { + buf = append(buf, raw...) + } + buf = append(buf, jstr[res.Index+len(res.Raw):]...) + return buf, nil + } + } + var paths []pathResult + r, simple := parsePath(path) + if simple { + paths = append(paths, r) + for r.more { + r, simple = parsePath(r.path) + if !simple { + break + } + paths = append(paths, r) + } + } + if !simple { + if del { + return []byte(jstr), + &errorType{"cannot delete value from a complex path"} + } + return setComplexPath(jstr, path, raw, stringify) + } + njson, err := appendRawPaths(nil, jstr, paths, raw, stringify, del) + if err != nil { + return []byte(jstr), err + } + return njson, nil +} + +func setComplexPath(jstr, path, raw string, stringify bool) ([]byte, error) { + res := gjson.Get(jstr, path) + if !res.Exists() || !(res.Index != 0 || len(res.Indexes) != 0) { + return []byte(jstr), errNoChange + } + if res.Index != 0 { + njson := []byte(jstr[:res.Index]) + if stringify { + njson = appendStringify(njson, raw) + } else { + njson = append(njson, raw...) + } + njson = append(njson, jstr[res.Index+len(res.Raw):]...) + jstr = string(njson) + } + if len(res.Indexes) > 0 { + type val struct { + index int + res gjson.Result + } + vals := make([]val, 0, len(res.Indexes)) + res.ForEach(func(_, vres gjson.Result) bool { + vals = append(vals, val{res: vres}) + return true + }) + if len(res.Indexes) != len(vals) { + return []byte(jstr), errNoChange + } + for i := 0; i < len(res.Indexes); i++ { + vals[i].index = res.Indexes[i] + } + sort.SliceStable(vals, func(i, j int) bool { + return vals[i].index > vals[j].index + }) + for _, val := range vals { + vres := val.res + index := val.index + njson := []byte(jstr[:index]) + if stringify { + njson = appendStringify(njson, raw) + } else { + njson = append(njson, raw...) + } + njson = append(njson, jstr[index+len(vres.Raw):]...) + jstr = string(njson) + } + } + return []byte(jstr), nil +} + +// SetOptions sets a json value for the specified path with options. +// A path is in dot syntax, such as "name.last" or "age". +// This function expects that the json is well-formed, and does not validate. +// Invalid json will not panic, but it may return back unexpected results. +// An error is returned if the path is not valid. +func SetOptions(json, path string, value interface{}, + opts *Options) (string, error) { + if opts != nil { + if opts.ReplaceInPlace { + // it's not safe to replace bytes in-place for strings + // copy the Options and set options.ReplaceInPlace to false. + nopts := *opts + opts = &nopts + opts.ReplaceInPlace = false + } + } + jsonh := *(*stringHeader)(unsafe.Pointer(&json)) + jsonbh := sliceHeader{data: jsonh.data, len: jsonh.len, cap: jsonh.len} + jsonb := *(*[]byte)(unsafe.Pointer(&jsonbh)) + res, err := SetBytesOptions(jsonb, path, value, opts) + return string(res), err +} + +// SetBytesOptions sets a json value for the specified path with options. +// If working with bytes, this method preferred over +// SetOptions(string(data), path, value) +func SetBytesOptions(json []byte, path string, value interface{}, + opts *Options) ([]byte, error) { + var optimistic, inplace bool + if opts != nil { + optimistic = opts.Optimistic + inplace = opts.ReplaceInPlace + } + jstr := *(*string)(unsafe.Pointer(&json)) + var res []byte + var err error + switch v := value.(type) { + default: + b, merr := jsongo.Marshal(value) + if merr != nil { + return nil, merr + } + raw := *(*string)(unsafe.Pointer(&b)) + res, err = set(jstr, path, raw, false, false, optimistic, inplace) + case dtype: + res, err = set(jstr, path, "", false, true, optimistic, inplace) + case string: + res, err = set(jstr, path, v, true, false, optimistic, inplace) + case []byte: + raw := *(*string)(unsafe.Pointer(&v)) + res, err = set(jstr, path, raw, true, false, optimistic, inplace) + case bool: + if v { + res, err = set(jstr, path, "true", false, false, optimistic, inplace) + } else { + res, err = set(jstr, path, "false", false, false, optimistic, inplace) + } + case int8: + res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), + false, false, optimistic, inplace) + case int16: + res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), + false, false, optimistic, inplace) + case int32: + res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), + false, false, optimistic, inplace) + case int64: + res, err = set(jstr, path, strconv.FormatInt(int64(v), 10), + false, false, optimistic, inplace) + case uint8: + res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), + false, false, optimistic, inplace) + case uint16: + res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), + false, false, optimistic, inplace) + case uint32: + res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), + false, false, optimistic, inplace) + case uint64: + res, err = set(jstr, path, strconv.FormatUint(uint64(v), 10), + false, false, optimistic, inplace) + case float32: + res, err = set(jstr, path, strconv.FormatFloat(float64(v), 'f', -1, 64), + false, false, optimistic, inplace) + case float64: + res, err = set(jstr, path, strconv.FormatFloat(float64(v), 'f', -1, 64), + false, false, optimistic, inplace) + } + if err == errNoChange { + return json, nil + } + return res, err +} + +// SetRawBytesOptions sets a raw json value for the specified path with options. +// If working with bytes, this method preferred over +// SetRawOptions(string(data), path, value, opts) +func SetRawBytesOptions(json []byte, path string, value []byte, + opts *Options) ([]byte, error) { + jstr := *(*string)(unsafe.Pointer(&json)) + vstr := *(*string)(unsafe.Pointer(&value)) + var optimistic, inplace bool + if opts != nil { + optimistic = opts.Optimistic + inplace = opts.ReplaceInPlace + } + res, err := set(jstr, path, vstr, false, false, optimistic, inplace) + if err == errNoChange { + return json, nil + } + return res, err +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/.gitignore b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/.gitignore new file mode 100644 index 0000000..f385b1c --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/.gitignore @@ -0,0 +1,6 @@ +*~ +pkg +src +*.bak +!vendor/src +bin/wof-* diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/LICENSE b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/LICENSE new file mode 100644 index 0000000..80e3c75 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2017, Mapzen +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/Makefile b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/Makefile new file mode 100644 index 0000000..0737d80 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/Makefile @@ -0,0 +1,2 @@ +tools: + go build -o bin/wof-export-feature cmd/wof-export-feature/main.go diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/README.md b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/README.md new file mode 100644 index 0000000..dc5c7b9 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/README.md @@ -0,0 +1,94 @@ +# go-whosonfirst-export + +Go package for exporting Who's On First documents. + +## What is this? + +go-whosonfirst-export is a Go package for exporting Who's On First documents in Go. It is a port of the [py-mapzen-whosonfirst-geojson](https://github.com/whosonfirst/py-mapzen-whosonfirst-geojson) package and _mmmmmmmaybe_ some or all of the [py-mapzen-whosonfirst-export](https://github.com/whosonfirst/py-mapzen-whosonfirst-geojson) package. + +## Important + +This package is still in flux. It is starting to settle down with the `v2` release but it might still change. + +## Documentation + +[![Go Reference](https://pkg.go.dev/badge/github.com/whosonfirst/go-whosonfirst-export.svg)](https://pkg.go.dev/github.com/whosonfirst/go-whosonfirst-export) + +## Example + +### Simple + +_Error handling removed for the sake of brevity._ + +``` +import ( + "context" + "github.com/whosonfirst/go-whosonfirst-export/v2" + "io/ioutil" + "os +) + +func main() { + + ctx := context.Background() + + path := "some.geojson" + fh, _ := os.Open(path) + defer fh.Close() + + body, _ := ioutil.ReadAll(fh) + + opts, _ := export.NewDefaultOptions(ctx) + export.Export(body, opts, os.Stdout) +} +``` + +### Exporter + +``` +import ( + "context" + "github.com/whosonfirst/go-whosonfirst-export/v2" + "io/ioutil" + "os +) + +func main() { + + ctx := context.Background() + + ex, _ := export.NewExporter(ctx, "whosonfirst://") + + path := "some.geojson" + fh, _ := os.Open(path) + defer fh.Close() + + body, _ := ioutil.ReadAll(fh) + + body, _ = ex.Export(ctx, body) + os.Stdout.Write(body) +} +``` + +## Interfaces + +### Exporter + +``` +type Exporter interface { + Export(context.Context, []byte) ([]byte, error) + ExportFeature(context.Context, interface{}) ([]byte, error) +} +``` + +## To do + +This package needs to hold hands with the `go-whosonfirst-validate` package. + +## See also + +* https://github.com/tidwall/pretty +* https://github.com/tidwall/gjson +* https://github.com/tidwall/pretty/issues/2 +* https://gist.github.com/tidwall/ca6ca1dd0cb780f0be4d134f8e4eb7bc +* https://github.com/whosonfirst/go-whosonfirst-validate \ No newline at end of file diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/doc.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/doc.go new file mode 100644 index 0000000..9ec36b0 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/doc.go @@ -0,0 +1,27 @@ +// go-whosonfirst-export is a Go package for exporting Who's On First documents in Go. +// +// Example +// +// import ( +// "context" +// "github.com/whosonfirst/go-whosonfirst-export/v2" +// "io" +// "os +// ) +// +// func main() { +// +// ctx := context.Background() +// +// ex, _ := export.NewExporter(ctx, "whosonfirst://") +// +// path := "some.geojson" +// fh, _ := os.Open(path) +// defer fh.Close() +// +// body, _ := io.ReadAll(fh) +// +// body, _ = ex.Export(ctx, body) +// os.Stdout.Write(body) +// } +package export diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/export.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/export.go new file mode 100644 index 0000000..124786d --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/export.go @@ -0,0 +1,164 @@ +package export + +import ( + "bytes" + "encoding/json" + _ "fmt" + "github.com/whosonfirst/go-whosonfirst-export/v2/properties" + format "github.com/whosonfirst/go-whosonfirst-format" + "io" +) + +func Export(feature []byte, opts *Options, wr io.Writer) error { + + var err error + + feature, err = prepareWithoutTimestamps(feature, opts) + + if err != nil { + return err + } + + feature, err = prepareTimestamps(feature, opts) + + if err != nil { + return err + } + + feature, err = Format(feature, opts) + + if err != nil { + return err + } + + r := bytes.NewReader(feature) + _, err = io.Copy(wr, r) + + return err +} + +// ExportChanged returns a boolean which indicates whether the file was changed +// by comparing it to the `existingFeature` byte slice, before the lastmodified +// timestamp is incremented. If the `feature` is identical to `existingFeature` +// it doesn't write to the `io.Writer`. + +func ExportChanged(feature []byte, existingFeature []byte, opts *Options, wr io.Writer) (changed bool, err error) { + + changed = false + + feature, err = prepareWithoutTimestamps(feature, opts) + + if err != nil { + return + } + + feature, err = Format(feature, opts) + + if err != nil { + return + } + + changed = !bytes.Equal(feature, existingFeature) + + if !changed { + return + } + + feature, err = prepareTimestamps(feature, opts) + + if err != nil { + return + } + + feature, err = Format(feature, opts) + + if err != nil { + return + } + + r := bytes.NewReader(feature) + _, err = io.Copy(wr, r) + + return +} + +func Prepare(feature []byte, opts *Options) ([]byte, error) { + var err error + + feature, err = prepareWithoutTimestamps(feature, opts) + if err != nil { + return nil, err + } + + feature, err = prepareTimestamps(feature, opts) + if err != nil { + return nil, err + } + + return feature, nil +} + +func Format(feature []byte, opts *Options) ([]byte, error) { + var f format.Feature + json.Unmarshal(feature, &f) + return format.FormatFeature(&f) +} + +func prepareWithoutTimestamps(feature []byte, opts *Options) ([]byte, error) { + + var err error + + feature, err = properties.EnsureWOFId(feature, opts.IDProvider) + + if err != nil { + return nil, err + } + + feature, err = properties.EnsureRequired(feature) + + if err != nil { + return nil, err + } + + feature, err = properties.EnsureEDTF(feature) + + if err != nil { + return nil, err + } + + feature, err = properties.EnsureParentId(feature) + + if err != nil { + return nil, err + } + + feature, err = properties.EnsureHierarchy(feature) + + if err != nil { + return nil, err + } + + feature, err = properties.EnsureBelongsTo(feature) + + if err != nil { + return nil, err + } + + feature, err = properties.EnsureSupersedes(feature) + + if err != nil { + return nil, err + } + + feature, err = properties.EnsureSupersededBy(feature) + + if err != nil { + return nil, err + } + + return feature, nil +} + +func prepareTimestamps(feature []byte, opts *Options) ([]byte, error) { + return properties.EnsureTimestamps(feature) +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/exporter.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/exporter.go new file mode 100644 index 0000000..45ea97b --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/exporter.go @@ -0,0 +1,68 @@ +package export + +import ( + "context" + "github.com/aaronland/go-roster" + "net/url" +) + +type Exporter interface { + Export(context.Context, []byte) ([]byte, error) + ExportFeature(context.Context, interface{}) ([]byte, error) +} + +var exporter_roster roster.Roster + +type ExporterInitializationFunc func(ctx context.Context, uri string) (Exporter, error) + +func RegisterExporter(ctx context.Context, scheme string, init_func ExporterInitializationFunc) error { + + err := ensureExporterRoster() + + if err != nil { + return err + } + + return exporter_roster.Register(ctx, scheme, init_func) +} + +func ensureExporterRoster() error { + + if exporter_roster == nil { + + r, err := roster.NewDefaultRoster() + + if err != nil { + return err + } + + exporter_roster = r + } + + return nil +} + +func NewExporter(ctx context.Context, uri string) (Exporter, error) { + + u, err := url.Parse(uri) + + if err != nil { + return nil, err + } + + scheme := u.Scheme + + i, err := exporter_roster.Driver(ctx, scheme) + + if err != nil { + return nil, err + } + + init_func := i.(ExporterInitializationFunc) + return init_func(ctx, uri) +} + +func Exporters() []string { + ctx := context.Background() + return exporter_roster.Drivers(ctx) +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/feature.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/feature.go new file mode 100644 index 0000000..6af1dd2 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/feature.go @@ -0,0 +1,9 @@ +package export + +type Feature struct { + Type string `json:"type"` + Id int64 `json:"id"` + Properties interface{} `json:"properties"` + Bbox []float64 `json:"bbox,omitempty"` + Geometry interface{} `json:"geometry"` +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/go.mod b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/go.mod new file mode 100644 index 0000000..8b5ce64 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/go.mod @@ -0,0 +1,13 @@ +module github.com/whosonfirst/go-whosonfirst-export/v2 + +go 1.16 + +require ( + github.com/aaronland/go-roster v0.0.2 + github.com/paulmach/orb v0.4.0 + github.com/sfomuseum/go-edtf v0.3.1 + github.com/tidwall/gjson v1.14.0 + github.com/tidwall/sjson v1.2.4 + github.com/whosonfirst/go-whosonfirst-format v0.3.7 + github.com/whosonfirst/go-whosonfirst-id v0.0.3 +) diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/go.sum b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/go.sum new file mode 100644 index 0000000..7b4d2d6 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/go.sum @@ -0,0 +1,118 @@ +github.com/aaronland/go-artisanal-integers v0.1.0/go.mod h1:00F0qOpuZZkzWiSSEQYk6Ul1Oc5kwgcYgsfYRmuR+wY= +github.com/aaronland/go-artisanal-integers v0.1.1 h1:bLQmWqcqgPT1NOJFwJtZZ9O/QTnttO54ODiWIVuOW1Y= +github.com/aaronland/go-artisanal-integers v0.1.1/go.mod h1:ZTeFI+Ck+q+Dp11Htld5aU6V+YwEzxzprsBO0t9GPp8= +github.com/aaronland/go-artisanal-integers-proxy v0.2.0 h1:3gQznMIWKNXbm3iMVKVC9l7nuZUj3ySUSN889fKlxhQ= +github.com/aaronland/go-artisanal-integers-proxy v0.2.0/go.mod h1:7Pkt553bRIgRMzkyPzPzvPDweCxMG6wx96qMBLlCk/Y= +github.com/aaronland/go-brooklynintegers-api v1.0.2/go.mod h1:JlR7i6vciy3W0aMnid7cN/Ls9Pz/vaq1lNj9sCENQf0= +github.com/aaronland/go-brooklynintegers-api v1.1.0/go.mod h1:agceH8JW8PcdHGCyKEDmOntccB3m7xUKrUejHpxAs6U= +github.com/aaronland/go-brooklynintegers-api v1.2.4 h1:KcRWO9kWTL6iNmZVTdPZVo7ngN0O9FFTKoQrFSjPMsU= +github.com/aaronland/go-brooklynintegers-api v1.2.4/go.mod h1:hNUn5nueKQM23ptExy20p5qDpRPhWg8RbjwW2BuXWmw= +github.com/aaronland/go-londonintegers-api v0.1.0/go.mod h1:E0VIcwks+So4FL1FYAQzrO5/OVOUsFPsqW85UrZArSE= +github.com/aaronland/go-missionintegers-api v0.1.0/go.mod h1:LZEM5+MkPX5RehLxTEv+3Y3cqMSYEk86qBa+aVecnKw= +github.com/aaronland/go-missionintegers-api v0.1.1 h1:zn6ohxxdUp3UXD8kv7ZXceS6CbGemtyDjvMT1VLezKI= +github.com/aaronland/go-missionintegers-api v0.1.1/go.mod h1:CvByrizvklOxK6QD+Z4RNqACxHqqVjiB/GdWQfrB4Mc= +github.com/aaronland/go-pool v0.0.0-20191128211702-88306299c758 h1:m/JUyvxsCbgOyhecvs9WXFvZy9dj8BKu4T96J53d/ao= +github.com/aaronland/go-pool v0.0.0-20191128211702-88306299c758/go.mod h1:hL9EPOZJ6WVHaz7D0Jw1Dn1vaCOOSZNrYBTKMgDKYRk= +github.com/aaronland/go-roster v0.0.1/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-roster v0.0.2 h1:2Fu7v4VQLRLRL/Zgr6R9S5JxsW75Ab/K88QtMVX532s= +github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-string v0.1.1 h1:btdr18owWCBN14ojKx3p+PBCKfm9qIggYEguPLUb2wE= +github.com/aaronland/go-string v0.1.1/go.mod h1:2aMIWdTqk63jZsaLLy+p9dsB1MDRqx4sHYoLtkwyYUo= +github.com/aaronland/go-uid v0.0.2 h1:5H3wtTBi58lkW5bqbaFR8Hp1MXfcraoJRlxKoUDeVfg= +github.com/aaronland/go-uid v0.0.2/go.mod h1:Kb/J05tYHWxp+Dkpod+oRkBKnxyw+szODwIQKIjvhj0= +github.com/aaronland/go-uid-artisanal v0.0.0-20191128230022-67bc446aa49d h1:2Sa8kTm10DVvAPESKu0XhQHNOBKpGxpkqLb7TvFMa4I= +github.com/aaronland/go-uid-artisanal v0.0.0-20191128230022-67bc446aa49d/go.mod h1:/fkI7C9H/GTB/TlLmNsKjHoNyXnYlkb/iG4Qp3tSCmE= +github.com/akrylysov/algnhsa v0.0.0-20190319020909-05b3d192e9a7/go.mod h1:HhzjNA0EjUWcwHTUMwqrpeAdIF3gRmpH0HpWx1hYJSc= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/aws/aws-lambda-go v1.9.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A= +github.com/aws/aws-lambda-go v1.10.0/go.mod h1:zUsUQhAUjYzR8AuduJPCfhBuKWUaDbQiPOG+ouzmE1A= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/paulmach/orb v0.4.0 h1:ilp1MQjRapLJ1+qcays1nZpe0mvkCY+b8JU/qBKRZ1A= +github.com/paulmach/orb v0.4.0/go.mod h1:FkcWtplUAIVqAuhAOV2d3rpbnQyliDOjOcLW9dUrfdU= +github.com/paulmach/protoscan v0.2.1-0.20210522164731-4e53c6875432/go.mod h1:2sV+uZ/oQh66m4XJVZm5iqUZ62BN88Ex1E+TTS0nLzI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sfomuseum/go-edtf v0.3.1 h1:22DEXVvGhnpF7PD4dvpgKH0/oD8u9I+a4cXCwy1x2f4= +github.com/sfomuseum/go-edtf v0.3.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/gjson v1.2.1/go.mod h1:c/nTNbUr0E0OrXEhq1pwa8iEgc2DOt4ZZqAt1HtCkPA= +github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w= +github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc= +github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM= +github.com/whosonfirst/algnhsa v0.1.0/go.mod h1:swLBXxaVTv3s6dJLhekdQCuCTshUew+xHjptRC21RG0= +github.com/whosonfirst/go-whosonfirst-format v0.3.7 h1:SkiUt2s0LqvH5JP7586+Rz7SgKwtRoFt7aGfWFFemoI= +github.com/whosonfirst/go-whosonfirst-format v0.3.7/go.mod h1:lMBIXCnD9ZA+wCNtu6XFYoq5DTfnEALO8k6OkEn11MM= +github.com/whosonfirst/go-whosonfirst-id v0.0.3 h1:sIsUkVPDbR9lgWcgQ9e4C7K4wlpSOGzALHp3iNid8ds= +github.com/whosonfirst/go-whosonfirst-id v0.0.3/go.mod h1:JuDIBvv0gzygE83XjX8Ym7JnX6OTO1X1efikSwTh8Ic= +github.com/whosonfirst/go-whosonfirst-log v0.1.0 h1:mWYI5hn16uyeLxBmPsLSvYV4rQKK/cxGVhM+bC2ZoGc= +github.com/whosonfirst/go-whosonfirst-log v0.1.0/go.mod h1:pmgBbxZSnjGVy2nsUJBBMcFagxwIKLlmRsW7ClkXmac= +github.com/whosonfirst/go-whosonfirst-pool v0.1.0/go.mod h1:6LeQYv7hVK16LVevMuOuaLRfgI3JDtaoVxaMMVqRS38= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= +go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/options.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/options.go new file mode 100644 index 0000000..976f1b5 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/options.go @@ -0,0 +1,30 @@ +package export + +import ( + "context" + "github.com/whosonfirst/go-whosonfirst-id" +) + +type Options struct { + IDProvider id.Provider +} + +func NewDefaultOptions(ctx context.Context) (*Options, error) { + + provider, err := id.NewProvider(ctx) + + if err != nil { + return nil, err + } + + return NewDefaultOptionsWithProvider(ctx, provider) +} + +func NewDefaultOptionsWithProvider(ctx context.Context, provider id.Provider) (*Options, error) { + + opts := &Options{ + IDProvider: provider, + } + + return opts, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties.go new file mode 100644 index 0000000..5ab4023 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties.go @@ -0,0 +1,100 @@ +package export + +import ( + "bytes" + "context" + "encoding/json" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +func EnsureProperties(ctx context.Context, body []byte, to_ensure map[string]interface{}) ([]byte, error) { + + to_assign := make(map[string]interface{}) + + for path, v := range to_ensure { + + rsp := gjson.GetBytes(body, path) + + if rsp.Exists() { + continue + } + + to_assign[path] = v + } + + return AssignProperties(ctx, body, to_assign) +} + +func AssignProperties(ctx context.Context, body []byte, to_assign map[string]interface{}) ([]byte, error) { + + var err error + + for path, v := range to_assign { + + body, err = sjson.SetBytes(body, path, v) + + if err != nil { + return nil, err + } + } + + return body, nil +} + +func AssignPropertiesIfChanged(ctx context.Context, body []byte, to_assign map[string]interface{}) (bool, []byte, error) { + + var err error + + changed := false + + for path, v := range to_assign { + + rsp := gjson.GetBytes(body, path) + + if rsp.Exists() { + + old, err := json.Marshal(rsp.Value()) + + if err != nil { + return changed, nil, err + } + + new, err := json.Marshal(v) + + if bytes.Compare(old, new) == 0 { + continue + } + + if err != nil { + return changed, nil, err + } + } + + body, err = sjson.SetBytes(body, path, v) + + if err != nil { + return changed, nil, err + } + + changed = true + } + + return changed, body, nil +} + +func RemoveProperties(ctx context.Context, body []byte, to_remove []string) ([]byte, error) { + + var err error + + for _, path := range to_remove { + + body, err = sjson.DeleteBytes(body, path) + + if err != nil { + return nil, err + } + } + + return body, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/belongsto.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/belongsto.go new file mode 100644 index 0000000..7d0a504 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/belongsto.go @@ -0,0 +1,100 @@ +package properties + +import ( + "errors" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +func EnsureBelongsTo(feature []byte) ([]byte, error) { + + belongsto := make([]int64, 0) + + wofid_rsp := gjson.GetBytes(feature, "properties.wof:id") + + if !wofid_rsp.Exists() { + return nil, errors.New("Missing properties.wof:id") + } + + wofid := wofid_rsp.Int() + + // Load the existing belongsto array, if it exists + + belongsToRsp := gjson.GetBytes(feature, "properties.wof:belongsto") + + if belongsToRsp.Exists() { + + belongsToRsp.ForEach(func(key gjson.Result, value gjson.Result) bool { + if value.Type == gjson.Number { + id := value.Int() + belongsto = append(belongsto, id) + } + + return true + }) + } + + rsp := gjson.GetBytes(feature, "properties.wof:hierarchy") + + if rsp.Exists() { + + ids := make([]int64, 0) + + for _, h := range rsp.Array() { + h.ForEach(func(key gjson.Result, value gjson.Result) bool { + + if value.Type == gjson.Number { + + id := value.Int() + + if id > 0 && id != wofid { + ids = append(ids, id) + } + } + + return true + }) + } + + // Add all the IDs we've not seen before + for _, id := range ids { + if !sliceContains(belongsto, id) { + belongsto = append(belongsto, id) + } + } + + // Remove all the IDs we no longer want in the list - in reverse, + // because Golang. + for i := len(belongsto) - 1; i >= 0; i-- { + id := belongsto[i] + + if !sliceContains(ids, id) { + belongsto = append(belongsto[:i], belongsto[i+1:]...) + } + } + } + + tz_rsp := gjson.GetBytes(feature, "properties.wof:timezones") + + if tz_rsp.Exists() { + + for _, i := range tz_rsp.Array() { + + id := i.Int() + if !sliceContains(belongsto, id) { + belongsto = append(belongsto, id) + } + } + } + + return sjson.SetBytes(feature, "properties.wof:belongsto", belongsto) +} + +func sliceContains(s []int64, e int64) bool { + for _, a := range s { + if a == e { + return true + } + } + return false +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/created.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/created.go new file mode 100644 index 0000000..2a1df4c --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/created.go @@ -0,0 +1,27 @@ +package properties + +import ( + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" + "time" +) + +func EnsureCreated(feature []byte) ([]byte, error) { + + var err error + + now := int32(time.Now().Unix()) + + created := gjson.GetBytes(feature, "properties.wof:created") + + if !created.Exists() { + + feature, err = sjson.SetBytes(feature, "properties.wof:created", now) + + if err != nil { + return nil, err + } + } + + return feature, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/edtf.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/edtf.go new file mode 100644 index 0000000..c29db67 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/edtf.go @@ -0,0 +1,143 @@ +package properties + +import ( + "github.com/sfomuseum/go-edtf" + "github.com/sfomuseum/go-edtf/parser" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +const date_fmt string = "2006-01-02" + +func EnsureEDTF(feature []byte) ([]byte, error) { + + var err error + + feature, err = EnsureInception(feature) + + if err != nil { + return nil, err + } + + feature, err = EnsureCessation(feature) + + if err != nil { + return nil, err + } + + return feature, nil +} + +func EnsureInception(feature []byte) ([]byte, error) { + + path := "properties.edtf:inception" + rsp := gjson.GetBytes(feature, path) + + if !rsp.Exists() { + return sjson.SetBytes(feature, path, edtf.UNKNOWN) + } + + edtf_str := rsp.String() + + switch edtf_str { + case edtf.UNKNOWN, edtf.OPEN: + return feature, nil + default: + // carry on + } + + d, err := parser.ParseString(edtf_str) + + if err != nil { + return nil, err + } + + lower_t, err := d.Lower() + + if err != nil { + return nil, err + } + + if lower_t != nil { + + feature, err = sjson.SetBytes(feature, "properties.date:inception_lower", lower_t.Format(date_fmt)) + + if err != nil { + return nil, err + } + } + + upper_t, err := d.Upper() + + if err != nil { + return nil, err + } + + if upper_t != nil { + + feature, err = sjson.SetBytes(feature, "properties.date:inception_upper", upper_t.Format(date_fmt)) + + if err != nil { + return nil, err + } + } + + return feature, nil +} + +func EnsureCessation(feature []byte) ([]byte, error) { + + path := "properties.edtf:cessation" + rsp := gjson.GetBytes(feature, path) + + if !rsp.Exists() { + return sjson.SetBytes(feature, path, edtf.UNKNOWN) + } + + edtf_str := rsp.String() + + switch edtf_str { + case edtf.UNKNOWN, edtf.OPEN: + return feature, nil + default: + // carry on + } + + d, err := parser.ParseString(edtf_str) + + if err != nil { + return nil, err + } + + lower_t, err := d.Lower() + + if err != nil { + return nil, err + } + + if lower_t != nil { + + feature, err = sjson.SetBytes(feature, "properties.date:cessation_lower", lower_t.Format(date_fmt)) + + if err != nil { + return nil, err + } + } + + upper_t, err := d.Upper() + + if err != nil { + return nil, err + } + + if upper_t != nil { + + feature, err = sjson.SetBytes(feature, "properties.date:cessation_upper", upper_t.Format(date_fmt)) + + if err != nil { + return nil, err + } + } + + return feature, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/geom.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/geom.go new file mode 100644 index 0000000..9c818b7 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/geom.go @@ -0,0 +1,114 @@ +package properties + +import ( + "crypto/md5" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "github.com/paulmach/orb/geojson" + "github.com/paulmach/orb/planar" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" + _ "log" +) + +func EnsureSrcGeom(feature []byte) ([]byte, error) { + + path := "properties.src:geom" + + rsp := gjson.GetBytes(feature, path) + + if rsp.Exists() { + return feature, nil + } + + return sjson.SetBytes(feature, path, "unknown") +} + +func EnsureGeomHash(feature []byte) ([]byte, error) { + + rsp := gjson.GetBytes(feature, "geometry") + + if !rsp.Exists() { + return nil, errors.New("missing geometry!") + } + + enc, err := json.Marshal(rsp.Value()) + + if err != nil { + return nil, err + } + + hash := md5.Sum(enc) + geom_hash := hex.EncodeToString(hash[:]) + + return sjson.SetBytes(feature, "properties.wof:geomhash", geom_hash) +} + +func EnsureGeomCoords(feature []byte) ([]byte, error) { + + // https://github.com/paulmach/orb/blob/master/geojson/feature.go + // https://github.com/paulmach/orb/blob/master/planar/area.go + + var err error + + f, err := geojson.UnmarshalFeature(feature) + + if err != nil { + return nil, err + } + + centroid, area := planar.CentroidArea(f.Geometry) + + feature, err = sjson.SetBytes(feature, "properties.geom:latitude", centroid.Y()) + + if err != nil { + return nil, err + } + + feature, err = sjson.SetBytes(feature, "properties.geom:longitude", centroid.X()) + + if err != nil { + return nil, err + } + + feature, err = sjson.SetBytes(feature, "properties.geom:area", area) + + if err != nil { + return nil, err + } + + bounds := f.Geometry.Bound() + + min := bounds.Min + max := bounds.Max + + minx := min.X() + miny := min.Y() + maxx := max.X() + maxy := max.Y() + + bbox := []float64{ + minx, + miny, + maxx, + maxy, + } + + str_bbox := fmt.Sprintf("%.06f,%.06f,%.06f,%.06f", minx, miny, maxx, maxy) + + feature, err = sjson.SetBytes(feature, "properties.geom:bbox", str_bbox) + + if err != nil { + return nil, err + } + + feature, err = sjson.SetBytes(feature, "bbox", bbox) + + if err != nil { + return nil, err + } + + return feature, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/hierarchy.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/hierarchy.go new file mode 100644 index 0000000..cd052b2 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/hierarchy.go @@ -0,0 +1,86 @@ +package properties + +import ( + "errors" + "fmt" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +type Hierarchy map[string]int64 +type Hierarchies []Hierarchy + +func EnsureHierarchy(feature []byte) ([]byte, error) { + + pt_rsp := gjson.GetBytes(feature, "properties.wof:placetype") + + if !pt_rsp.Exists() { + return feature, errors.New("missing wof:placetype") + } + + pt := pt_rsp.String() + + id_rsp := gjson.GetBytes(feature, "properties.wof:id") + + if !id_rsp.Exists() { + return feature, errors.New("missing wof:id") + } + + id := id_rsp.Int() + + key := fmt.Sprintf("%s_id", pt) + + if pt == "custom" { + + alt_rsp := gjson.GetBytes(feature, "properties.wof:placetype_alt") + + if alt_rsp.Exists() { + key = fmt.Sprintf("%s_id", alt_rsp.String()) + } + } + + hierarchies := make([]Hierarchy, 0) + + hier_rsp := gjson.GetBytes(feature, "properties.wof:hierarchy") + + if hier_rsp.Exists() { + + for _, possible := range hier_rsp.Array() { + + h := make(map[string]int64) + + for k, r := range possible.Map() { + + if k == "custom_id" { + + alt_rsp := gjson.GetBytes(feature, "properties.wof:placetype_alt") + + if alt_rsp.Exists() { + k = fmt.Sprintf("%s_id", alt_rsp.String()) + } + } + + v, exists := h[k] + + if exists { + return nil, fmt.Errorf("Hierarchy key '%s' already set with value '%d' (trying to set '%d')", k, v, r.Int()) + } + + h[k] = r.Int() + } + + hierarchies = append(hierarchies, h) + } + } + + if len(hierarchies) == 0 { + h := make(map[string]int64) + hierarchies = append(hierarchies, h) + } + + for _, h := range hierarchies { + h[key] = id + } + + return sjson.SetBytes(feature, "properties.wof:hierarchy", hierarchies) +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/lastmodified.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/lastmodified.go new file mode 100644 index 0000000..ed5ddce --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/lastmodified.go @@ -0,0 +1,21 @@ +package properties + +import ( + "github.com/tidwall/sjson" + "time" +) + +func EnsureLastModified(feature []byte) ([]byte, error) { + + var err error + + now := int32(time.Now().Unix()) + + feature, err = sjson.SetBytes(feature, "properties.wof:lastmodified", now) + + if err != nil { + return nil, err + } + + return feature, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/name.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/name.go new file mode 100644 index 0000000..94e1e54 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/name.go @@ -0,0 +1,18 @@ +package properties + +import ( + "errors" + "github.com/tidwall/gjson" + _ "github.com/tidwall/sjson" +) + +func EnsureName(feature []byte) ([]byte, error) { + + rsp := gjson.GetBytes(feature, "properties.wof:name") + + if !rsp.Exists() { + return feature, errors.New("missing wof:name") + } + + return feature, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/parentid.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/parentid.go new file mode 100644 index 0000000..144ab1d --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/parentid.go @@ -0,0 +1,17 @@ +package properties + +import ( + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +func EnsureParentId(feature []byte) ([]byte, error) { + + rsp := gjson.GetBytes(feature, "properties.wof:parent_id") + + if rsp.Exists() { + return feature, nil + } + + return sjson.SetBytes(feature, "properties.wof:parent_id", -1) +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/placetype.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/placetype.go new file mode 100644 index 0000000..2e33e56 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/placetype.go @@ -0,0 +1,18 @@ +package properties + +import ( + "errors" + "github.com/tidwall/gjson" + _ "github.com/tidwall/sjson" +) + +func EnsurePlacetype(feature []byte) ([]byte, error) { + + rsp := gjson.GetBytes(feature, "properties.wof:placetype") + + if !rsp.Exists() { + return feature, errors.New("missing wof:placetype") + } + + return feature, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/properties.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/properties.go new file mode 100644 index 0000000..c42cef7 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/properties.go @@ -0,0 +1,72 @@ +package properties + +import () + +func EnsureRequired(feature []byte) ([]byte, error) { + + var err error + + feature, err = EnsureName(feature) + + if err != nil { + return nil, err + } + + feature, err = EnsurePlacetype(feature) + + if err != nil { + return nil, err + } + + feature, err = EnsureGeom(feature) + + if err != nil { + return nil, err + } + + return feature, nil +} + +func EnsureGeom(feature []byte) ([]byte, error) { + + var err error + + feature, err = EnsureSrcGeom(feature) + + if err != nil { + return nil, err + } + + feature, err = EnsureGeomHash(feature) + + if err != nil { + return nil, err + } + + feature, err = EnsureGeomCoords(feature) + + if err != nil { + return nil, err + } + + return feature, nil +} + +func EnsureTimestamps(feature []byte) ([]byte, error) { + + var err error + + feature, err = EnsureCreated(feature) + + if err != nil { + return nil, err + } + + feature, err = EnsureLastModified(feature) + + if err != nil { + return nil, err + } + + return feature, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/supersedes.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/supersedes.go new file mode 100644 index 0000000..006e468 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/supersedes.go @@ -0,0 +1,32 @@ +package properties + +import ( + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +func EnsureSupersedes(feature []byte) ([]byte, error) { + + supersedes := make([]int64, 0) + + rsp := gjson.GetBytes(feature, "properties.wof:supersedes") + + if rsp.Exists() { + return feature, nil + } + + return sjson.SetBytes(feature, "properties.wof:supersedes", supersedes) +} + +func EnsureSupersededBy(feature []byte) ([]byte, error) { + + superseded_by := make([]int64, 0) + + rsp := gjson.GetBytes(feature, "properties.wof:superseded_by") + + if rsp.Exists() { + return feature, nil + } + + return sjson.SetBytes(feature, "properties.wof:superseded_by", superseded_by) +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/wofid.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/wofid.go new file mode 100644 index 0000000..9dfcf2c --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/properties/wofid.go @@ -0,0 +1,51 @@ +package properties + +import ( + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" + "github.com/whosonfirst/go-whosonfirst-id" +) + +func EnsureWOFId(feature []byte, provider id.Provider) ([]byte, error) { + + var err error + + var wof_id int64 + + rsp := gjson.GetBytes(feature, "properties.wof:id") + + if rsp.Exists() { + + wof_id = rsp.Int() + + } else { + + i, err := provider.NewID() + + if err != nil { + return nil, err + } + + wof_id = i + + feature, err = sjson.SetBytes(feature, "properties.wof:id", wof_id) + + if err != nil { + return nil, err + } + } + + id := gjson.GetBytes(feature, "id") + + if !id.Exists() { + + feature, err = sjson.SetBytes(feature, "id", wof_id) + + if err != nil { + return nil, err + } + + } + + return feature, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/supersede.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/supersede.go new file mode 100644 index 0000000..3970dd5 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/supersede.go @@ -0,0 +1,145 @@ +package export + +import ( + "context" + "fmt" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +func SupersedeRecord(ctx context.Context, ex Exporter, old_body []byte) ([]byte, []byte, error) { + + id_rsp := gjson.GetBytes(old_body, "properties.wof:id") + + if !id_rsp.Exists() { + return nil, nil, fmt.Errorf("Failed to derive old properties.wof:id property for record being superseded") + } + + old_id := id_rsp.Int() + + // Create the new record + + new_body := old_body + + new_body, err := sjson.DeleteBytes(new_body, "properties.wof:id") + + if err != nil { + return nil, nil, err + } + + new_body, err = ex.Export(ctx, new_body) + + if err != nil { + return nil, nil, err + } + + id_rsp = gjson.GetBytes(new_body, "properties.wof:id") + + if !id_rsp.Exists() { + return nil, nil, fmt.Errorf("Failed to derive new properties.wof:id property for record superseding '%d'", old_id) + } + + new_id := id_rsp.Int() + + // Update the new record + + new_body, err = sjson.SetBytes(new_body, "properties.wof:supersedes", []int64{old_id}) + + if err != nil { + return nil, nil, err + } + + // Update the old record + + to_update := map[string]interface{}{ + "properties.mz:is_current": 0, + "properties.wof:superseded_by": []int64{new_id}, + } + + old_body, err = AssignProperties(ctx, old_body, to_update) + + if err != nil { + return nil, nil, err + } + + return old_body, new_body, nil +} + +func SupersedeRecordWithParent(ctx context.Context, ex Exporter, to_supersede_f []byte, parent_f []byte) ([]byte, []byte, error) { + + id_rsp := gjson.GetBytes(parent_f, "properties.wof:id") + + if !id_rsp.Exists() { + return nil, nil, fmt.Errorf("Parent feature is missing properties.wof:id") + } + + parent_id := id_rsp.Int() + + hier_rsp := gjson.GetBytes(parent_f, "properties.wof:hierarchy") + + if !hier_rsp.Exists() { + return nil, nil, fmt.Errorf("Parent feature is missing properties.wof:hierarchy") + } + + parent_hierarchy := hier_rsp.Value() + + inception_rsp := gjson.GetBytes(parent_f, "properties.edtf:inception") + + if !inception_rsp.Exists() { + return nil, nil, fmt.Errorf("Parent record is missing properties.edtf:inception") + } + + cessation_rsp := gjson.GetBytes(parent_f, "properties.edtf:cessation") + + if !cessation_rsp.Exists() { + return nil, nil, fmt.Errorf("Parent record is missing properties.edtf:cessation") + } + + inception := inception_rsp.String() + cessation := cessation_rsp.String() + + to_update_old := map[string]interface{}{ + "properties.edtf:cessation": inception, + } + + to_update_new := map[string]interface{}{ + "properties.wof:parent_id": parent_id, + "properties.wof:hierarchy": parent_hierarchy, + "properties.edtf:inception": inception, + "properties.edtf:cessation": cessation, + } + + // + + superseded_f, superseding_f, err := SupersedeRecord(ctx, ex, to_supersede_f) + + if err != nil { + return nil, nil, fmt.Errorf("Failed to supersede record %v", err) + } + + superseded_f, err = AssignProperties(ctx, superseded_f, to_update_old) + + if err != nil { + return nil, nil, fmt.Errorf("Failed to assign properties for new record, ") + } + + name_rsp := gjson.GetBytes(superseding_f, "properties.wof:name") + + if !name_rsp.Exists() { + return nil, nil, fmt.Errorf("Failed to retrieve wof:name for new record") + } + + name := name_rsp.String() + label := fmt.Sprintf("%s (%s)", name, inception) + + to_update_new["properties.wof:label"] = label + + superseding_f, err = AssignProperties(ctx, superseding_f, to_update_new) + + if err != nil { + return nil, nil, fmt.Errorf("Failed to assign updated properties for new record, ") + } + + return superseded_f, superseding_f, nil + +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/whosonfirst.go b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/whosonfirst.go new file mode 100644 index 0000000..ab35bf5 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-export/v2/whosonfirst.go @@ -0,0 +1,74 @@ +package export + +import ( + "context" + "encoding/json" + "net/url" +) + +type WhosOnFirstExporter struct { + Exporter + options *Options +} + +func init() { + + ctx := context.Background() + + err := RegisterExporter(ctx, "whosonfirst", NewWhosOnFirstExporter) + + if err != nil { + panic(err) + } +} + +func NewWhosOnFirstExporter(ctx context.Context, uri string) (Exporter, error) { + + _, err := url.Parse(uri) + + if err != nil { + return nil, err + } + + opts, err := NewDefaultOptions(ctx) + + if err != nil { + return nil, err + } + + ex := WhosOnFirstExporter{ + options: opts, + } + + return &ex, nil +} + +func (ex *WhosOnFirstExporter) ExportFeature(ctx context.Context, feature interface{}) ([]byte, error) { + + body, err := json.Marshal(feature) + + if err != nil { + return nil, err + } + + return ex.Export(ctx, body) +} + +func (ex *WhosOnFirstExporter) Export(ctx context.Context, feature []byte) ([]byte, error) { + + var err error + + feature, err = Prepare(feature, ex.options) + + if err != nil { + return nil, err + } + + feature, err = Format(feature, ex.options) + + if err != nil { + return nil, err + } + + return feature, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-format/.gitignore b/vendor/github.com/whosonfirst/go-whosonfirst-format/.gitignore new file mode 100644 index 0000000..a5d8f72 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-format/.gitignore @@ -0,0 +1,2 @@ +bin/ +dist/ diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-format/.goreleaser.yml b/vendor/github.com/whosonfirst/go-whosonfirst-format/.goreleaser.yml new file mode 100644 index 0000000..4841b94 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-format/.goreleaser.yml @@ -0,0 +1,36 @@ +before: + hooks: + - go mod tidy +builds: + - + id: wof-format + binary: wof-format + env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin + main: ./cmd +archives: + - + id: wof-format + builds: + - wof-format + replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 + format: binary +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ incpatch .Tag }}-next" +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-format/Makefile b/vendor/github.com/whosonfirst/go-whosonfirst-format/Makefile new file mode 100644 index 0000000..53a8f31 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-format/Makefile @@ -0,0 +1,7 @@ +.PHONY: build +build: + go build -v -o bin/wof-format ./cmd + +.PHONY: test +test: + go test -v ./test/... diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-format/README.md b/vendor/github.com/whosonfirst/go-whosonfirst-format/README.md new file mode 100644 index 0000000..7c877fb --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-format/README.md @@ -0,0 +1,37 @@ +# go-whosonfirst-format + +Standardised GeoJSON formatting for Whos On First files. + +Usable as both a library and a binary. + +## Library usage + +```golang +func main() { + inputBytes, err := ioutil.ReadFile(inputPath) + if err != nil { + panic(err) + } + + var feature format.Feature + + json.Unmarshal(inputBytes, &feature) + if err != nil { + panic(err) + } + + outputBytes, err := format.FormatFeature(&feature) + if err != nil { + panic(err) + } + + fmt.Printf("%s", outputBytes) +} +``` + +## Binary usage + +```shell +make build +cat input.geojson | ./build/wof-format > output.geojson +``` \ No newline at end of file diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-format/format.go b/vendor/github.com/whosonfirst/go-whosonfirst-format/format.go new file mode 100644 index 0000000..5dbea36 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-format/format.go @@ -0,0 +1,108 @@ +package format + +import ( + "bytes" + "encoding/json" + "fmt" + + "github.com/tidwall/pretty" +) + +// Feature represents a WOF Feature, ready to be encoded to JSON +type Feature struct { + Type string `json:"type"` + ID int64 `json:"id"` + Properties interface{} `json:"properties"` + Bbox interface{} `json:"bbox,omitempty"` + Geometry interface{} `json:"geometry"` +} + +// two space indent +const indent = " " + +// FormatFeature transforms a byte array `b` into a correctly formatted WOF file +func FormatBytes(b []byte) ([]byte, error) { + + var f *Feature + err := json.Unmarshal(b, &f) + + if err != nil { + return nil, fmt.Errorf("Failed to unmarshal bytes in to Feature, %w", err) + } + + return FormatFeature(f) +} + +// FormatFeature transforms a Feature into a correctly formatted WOF file +func FormatFeature(feature *Feature) ([]byte, error) { + var buf bytes.Buffer + + _, err := buf.WriteString("{\n") + if err != nil { + return buf.Bytes(), err + } + + err = writeKey(&buf, "id", feature.ID, true, false) + if err != nil { + return buf.Bytes(), err + } + + err = writeKey(&buf, "type", feature.Type, true, false) + if err != nil { + return buf.Bytes(), err + } + + err = writeKey(&buf, "properties", feature.Properties, true, false) + if err != nil { + return buf.Bytes(), err + } + + err = writeKey(&buf, "bbox", feature.Bbox, true, false) + if err != nil { + return buf.Bytes(), err + } + + err = writeKey(&buf, "geometry", feature.Geometry, false, true) + if err != nil { + return buf.Bytes(), err + } + + _, err = buf.WriteString("\n}\n") + if err != nil { + return buf.Bytes(), err + } + + return buf.Bytes(), nil +} + +func writeKey(buf *bytes.Buffer, key string, value interface{}, usePretty, lastLine bool) error { + valueJSON, err := json.Marshal(value) + if err != nil { + return err + } + + if usePretty { + prefix := indent + prettyOpts := &pretty.Options{Indent: indent, SortKeys: true, Prefix: prefix} + valueJSON = pretty.PrettyOptions(valueJSON, prettyOpts) + // Trim the newline that comes back from pretty, so we can control it last + valueJSON = valueJSON[:len(valueJSON)-1] + // Trim the first prefix + valueJSON = valueJSON[len(indent):] + } else { + valueJSON = pretty.Ugly(valueJSON) + } + + trailing := ",\n" + if lastLine { + trailing = "" + } + + _, err = buf.WriteString(indent) + if err != nil { + return err + } + + _, err = fmt.Fprintf(buf, "\"%s\": %s%s", key, valueJSON, trailing) + return err +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-format/go.mod b/vendor/github.com/whosonfirst/go-whosonfirst-format/go.mod new file mode 100644 index 0000000..776a812 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-format/go.mod @@ -0,0 +1,9 @@ +module github.com/whosonfirst/go-whosonfirst-format + +go 1.16 + +require ( + github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 + github.com/sergi/go-diff v1.2.0 // indirect + github.com/tidwall/pretty v1.2.0 +) diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-format/go.sum b/vendor/github.com/whosonfirst/go-whosonfirst-format/go.sum new file mode 100644 index 0000000..7e223c5 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-format/go.sum @@ -0,0 +1,25 @@ +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-id/.gitignore b/vendor/github.com/whosonfirst/go-whosonfirst-id/.gitignore new file mode 100644 index 0000000..f385b1c --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-id/.gitignore @@ -0,0 +1,6 @@ +*~ +pkg +src +*.bak +!vendor/src +bin/wof-* diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-id/LICENSE b/vendor/github.com/whosonfirst/go-whosonfirst-id/LICENSE new file mode 100644 index 0000000..d057e1b --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-id/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2019, Aaron Straup Cope +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-id/README.md b/vendor/github.com/whosonfirst/go-whosonfirst-id/README.md new file mode 100644 index 0000000..861235a --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-id/README.md @@ -0,0 +1,83 @@ +# go-whosonfirst-id + +Go package for generating valid Who's On First IDs. + +## What is this? + +This is a common Go package for generating valid Who's On First (WOF) identifiers. + +Under the hood it uses a [go-uid.Provider](https://github.com/aaronland/go-uid) for generating those IDs, specifically a [go-uid-artisanal](https://github.com/aaronland/go-uid-artisanal) provider. + +This allows you to specify alternative and/or multiple artisanal integer providers (the default provider for WOF is [Brooklyn Integers](https://brooklynintegers.com/)) as well as a customizable pool of pre-generated and caches IDs using the [go-artisanal-integers-proxy](https://github.com/aaronland/go-artisanal-integers-proxy) and [go-pool](https://github.com/aaronland?utf8=%E2%9C%93&q=go-pool&type=&language=) packages. + +Note: The use of the [go-uid.Provider](https://github.com/aaronland/go-uid) interface might be overkill. We'll see. + +## Example + +_Error handling omitted for the sake of brevity._ + +### Simple + +``` +package main + +import ( + "context" + "fmt" + "testing" +) + +func main() { + + ctx := context.Background() + pr, _ := NewProvider(ctx) + + id, _ := pr.NewID() + fmt.Println(id) +} +``` + +### Fancy + +The default `Provider` does not pre-generate or cache IDs. To do so create a custom `Provider` that does, use the handy `NewProviderWithURI` method: + +``` +package main + +import ( + "context" + "fmt" + "testing" + _ "github.com/aaronland/go-missionintegers-api" +) + +func main() { + + ctx := context.Background() + + uri := "artisanal:///?client=missionintegers%3A%2F%2F&minimum=5&pool=memory%3A%2F%2F" + cl, _ := NewProviderWithURI(ctx, uri) + + id, _ := cl.NextInt() + fmt.Println(id) +} +``` + +This expects a valid [go-uid-artisanal](https://github.com/aaronland/go-uid-artisanal) URI string. + +## Interfaces + +### Provider + +``` +type Provider interface { + NewID() (int64, error) +} +``` + +## See also + +* https://github.com/aaronland/go-artisanal-integers +* https://github.com/aaronland/go-artisanal-integers-proxy +* https://github.com/aaronland/go-uid-artisanal +* https://github.com/aaronland/go-brooklynintegers-api \ No newline at end of file diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-id/go.mod b/vendor/github.com/whosonfirst/go-whosonfirst-id/go.mod new file mode 100644 index 0000000..68429f8 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-id/go.mod @@ -0,0 +1,9 @@ +module github.com/whosonfirst/go-whosonfirst-id + +go 1.16 + +require ( + github.com/aaronland/go-brooklynintegers-api v1.2.4 + github.com/aaronland/go-uid v0.0.3 + github.com/aaronland/go-uid-artisanal v0.0.1 +) diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-id/go.sum b/vendor/github.com/whosonfirst/go-whosonfirst-id/go.sum new file mode 100644 index 0000000..2851e2e --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-id/go.sum @@ -0,0 +1,67 @@ +github.com/aaronland/go-artisanal-integers v0.1.1 h1:bLQmWqcqgPT1NOJFwJtZZ9O/QTnttO54ODiWIVuOW1Y= +github.com/aaronland/go-artisanal-integers v0.1.1/go.mod h1:ZTeFI+Ck+q+Dp11Htld5aU6V+YwEzxzprsBO0t9GPp8= +github.com/aaronland/go-artisanal-integers-proxy v0.2.5 h1:jkQ0p8TLCTPFH8rqFqYWMu3Qzr5ZzZWT9KhehzT091k= +github.com/aaronland/go-artisanal-integers-proxy v0.2.5/go.mod h1:mldeud4G0Yn4a+VKZ+CHrg5mw3u5OIOok25q5OKsOrM= +github.com/aaronland/go-brooklynintegers-api v1.2.1/go.mod h1:vFyhY89Uc0LDZEaEam5EQ+2La2VlkTvSfExuZgZhmX4= +github.com/aaronland/go-brooklynintegers-api v1.2.4 h1:KcRWO9kWTL6iNmZVTdPZVo7ngN0O9FFTKoQrFSjPMsU= +github.com/aaronland/go-brooklynintegers-api v1.2.4/go.mod h1:hNUn5nueKQM23ptExy20p5qDpRPhWg8RbjwW2BuXWmw= +github.com/aaronland/go-londonintegers-api v0.1.1/go.mod h1:N7Y0jrx+ouRAMrFcdH4nvJH6vrszj8/3yOOe0F8EV1E= +github.com/aaronland/go-missionintegers-api v0.1.1 h1:zn6ohxxdUp3UXD8kv7ZXceS6CbGemtyDjvMT1VLezKI= +github.com/aaronland/go-missionintegers-api v0.1.1/go.mod h1:CvByrizvklOxK6QD+Z4RNqACxHqqVjiB/GdWQfrB4Mc= +github.com/aaronland/go-pool v1.0.0 h1:RupGLoRO5EHzPZ08zZgiLeDXPhErUAtPonzVLM2D6yM= +github.com/aaronland/go-pool v1.0.0/go.mod h1:5EzZAfp1v2N+EyyGQ3868fxNxBL5+b4OUmVgnJZpMFo= +github.com/aaronland/go-roster v0.0.1/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-roster v0.0.2 h1:2Fu7v4VQLRLRL/Zgr6R9S5JxsW75Ab/K88QtMVX532s= +github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-string v0.1.2 h1:RSr/mQNbLgF37H0RV+nF7j2kILRRFkCmr8Jwq4lw92k= +github.com/aaronland/go-string v0.1.2/go.mod h1:2aMIWdTqk63jZsaLLy+p9dsB1MDRqx4sHYoLtkwyYUo= +github.com/aaronland/go-uid v0.0.3 h1:MIcdw+Jp8tVx+m9wrExxl2y8l5KbzsTTOUCDNOnNRnk= +github.com/aaronland/go-uid v0.0.3/go.mod h1:VccCcqEWQgE9fr42fwnWIPBRMQlN1Yx+GLUQBPR3xNA= +github.com/aaronland/go-uid-artisanal v0.0.1 h1:WRDDfSO7vqWnkMYFCYEjU2TCs6csDuBHoo7o/jDOcWE= +github.com/aaronland/go-uid-artisanal v0.0.1/go.mod h1:WbAHDcfpYJ673t5kXgZn0zH7XiBjoLdvOMgngVQpCcg= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= +github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/gjson v1.3.5/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M= +github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/whosonfirst/go-whosonfirst-log v0.1.0 h1:mWYI5hn16uyeLxBmPsLSvYV4rQKK/cxGVhM+bC2ZoGc= +github.com/whosonfirst/go-whosonfirst-log v0.1.0/go.mod h1:pmgBbxZSnjGVy2nsUJBBMcFagxwIKLlmRsW7ClkXmac= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/ratelimit v0.1.0/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= +go.uber.org/ratelimit v0.2.0 h1:UQE2Bgi7p2B85uP5dC2bbRtig0C+OeNRnNEafLjsLPA= +go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-id/id.go b/vendor/github.com/whosonfirst/go-whosonfirst-id/id.go new file mode 100644 index 0000000..8da237a --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-id/id.go @@ -0,0 +1,69 @@ +package id + +import ( + "context" + _ "github.com/aaronland/go-brooklynintegers-api" + "github.com/aaronland/go-uid" + "github.com/aaronland/go-uid-artisanal" + "strconv" +) + +type Provider interface { + NewID() (int64, error) +} + +type WOFProvider struct { + Provider + uid_provider uid.Provider +} + +func NewProvider(ctx context.Context) (Provider, error) { + + opts := &artisanal.ArtisanalProviderURIOptions{ + Pool: "memory://", + Minimum: 0, + Clients: []string{ + "brooklynintegers://", + }, + } + + uri, err := artisanal.NewArtisanalProviderURI(opts) + + if err != nil { + return nil, err + } + + // str_uri ends up looking like this: + // artisanal:?client=brooklynintegers%3A%2F%2F&minimum=5&pool=memory%3A%2F%2F + + str_uri := uri.String() + + return NewProviderWithURI(ctx, str_uri) +} + +func NewProviderWithURI(ctx context.Context, uri string) (Provider, error) { + + uid_pr, err := uid.NewProvider(ctx, uri) + + if err != nil { + return nil, err + } + + wof_pr := &WOFProvider{ + uid_provider: uid_pr, + } + + return wof_pr, nil +} + +func (wof_pr *WOFProvider) NewID() (int64, error) { + + uid, err := wof_pr.uid_provider.UID() + + if err != nil { + return -1, err + } + + str_id := uid.String() + return strconv.ParseInt(str_id, 10, 64) +} diff --git a/vendor/github.com/whosonfirst/go-writer/.gitignore b/vendor/github.com/whosonfirst/go-writer/.gitignore new file mode 100644 index 0000000..afa44cd --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/.gitignore @@ -0,0 +1,11 @@ +*~ +pkg +src +!vendor/src +bin +!bin/.gitignore +*.log +*.json +.travis.yml +*.db +testdata/*.txt \ No newline at end of file diff --git a/vendor/github.com/whosonfirst/go-writer/LICENSE b/vendor/github.com/whosonfirst/go-writer/LICENSE new file mode 100644 index 0000000..29b6a83 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2019, Aaron Straup Cope +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/github.com/whosonfirst/go-writer/Makefile b/vendor/github.com/whosonfirst/go-writer/Makefile new file mode 100644 index 0000000..e69de29 diff --git a/vendor/github.com/whosonfirst/go-writer/README.md b/vendor/github.com/whosonfirst/go-writer/README.md new file mode 100644 index 0000000..3b5dd6f --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/README.md @@ -0,0 +1,27 @@ +# go-whosonfirst-writer + +## Important + +Work in progress. Documentation to follow + +## Interfaces + +### WriterInitializationFunc + +``` +type WriterInitializationFunc func(ctx context.Context, uri string) (Writer, error) +``` + +### Writer + +``` +type Writer interface { + Write(context.Context, string, io.ReadSeeker) (int64, error) + Close() error + WriterURI(string) string +} +``` + +## See also + +* https://github.com/whosonfirst/go-reader diff --git a/vendor/github.com/whosonfirst/go-writer/cwd.go b/vendor/github.com/whosonfirst/go-writer/cwd.go new file mode 100644 index 0000000..ab5dbb3 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/cwd.go @@ -0,0 +1,66 @@ +package writer + +import ( + "context" + "fmt" + "io" + "os" +) + +type CwdWriter struct { + Writer + writer Writer +} + +func init() { + + ctx := context.Background() + + schemes := []string{ + "cwd", + } + + for _, scheme := range schemes { + + err := RegisterWriter(ctx, scheme, NewCwdWriter) + + if err != nil { + panic(err) + } + } +} + +func NewCwdWriter(ctx context.Context, uri string) (Writer, error) { + + cwd, err := os.Getwd() + + if err != nil { + return nil, fmt.Errorf("Failed to derive current working directory, %w", err) + } + + uri = fmt.Sprintf("fs://%s", cwd) + fs_wr, err := NewFileWriter(ctx, uri) + + if err != nil { + return nil, fmt.Errorf("Failed to create new FS writer, %w", err) + } + + wr := &CwdWriter{ + writer: fs_wr, + } + + return wr, nil +} + +func (wr *CwdWriter) Write(ctx context.Context, path string, fh io.ReadSeeker) (int64, error) { + + return wr.writer.Write(ctx, path, fh) +} + +func (wr *CwdWriter) WriterURI(ctx context.Context, path string) string { + return wr.writer.WriterURI(ctx, path) +} + +func (wr *CwdWriter) Close(ctx context.Context) error { + return wr.writer.Close(ctx) +} diff --git a/vendor/github.com/whosonfirst/go-writer/doc.go b/vendor/github.com/whosonfirst/go-writer/doc.go new file mode 100644 index 0000000..ff9bd73 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/doc.go @@ -0,0 +1,2 @@ +// Package writer provides a common interface for writing data to one or more sources. +package writer diff --git a/vendor/github.com/whosonfirst/go-writer/fs.go b/vendor/github.com/whosonfirst/go-writer/fs.go new file mode 100644 index 0000000..68f60f3 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/fs.go @@ -0,0 +1,135 @@ +package writer + +import ( + "context" + "errors" + "fmt" + "github.com/natefinch/atomic" + "io" + "math/rand" + "net/url" + "os" + "path/filepath" +) + +type FileWriter struct { + Writer + root string + dir_mode os.FileMode + file_mode os.FileMode +} + +func init() { + + ctx := context.Background() + + schemes := []string{ + "fs", + } + + for _, scheme := range schemes { + + err := RegisterWriter(ctx, scheme, NewFileWriter) + + if err != nil { + panic(err) + } + } +} + +func NewFileWriter(ctx context.Context, uri string) (Writer, error) { + + u, err := url.Parse(uri) + + if err != nil { + return nil, err + } + + root := u.Path + info, err := os.Stat(root) + + if err != nil { + return nil, err + } + + if !info.IsDir() { + return nil, errors.New("root is not a directory") + } + + // check for dir/file mode query parameters here + + wr := &FileWriter{ + dir_mode: 0755, + file_mode: 0644, + root: root, + } + + return wr, nil +} + +func (wr *FileWriter) Write(ctx context.Context, path string, fh io.ReadSeeker) (int64, error) { + + abs_path := wr.WriterURI(ctx, path) + abs_root := filepath.Dir(abs_path) + + _, err := os.Stat(abs_root) + + if os.IsNotExist(err) { + + err = os.MkdirAll(abs_root, wr.dir_mode) + + if err != nil { + return 0, err + } + } + + // So this... we can't do this because of cross-device (filesystem) limitations + // under Unix. That is /tmp may be on a different filesystem than abs_path + // tmp_file, err := os.CreateTemp("", filepath.Base(abs_path)) + // tmp_path := tmp_file.Name() + + tmp_suffix := fmt.Sprintf("tmp%d", rand.Int63()) + tmp_path := fmt.Sprintf("%s.%s", abs_path, tmp_suffix) + + tmp_file, err := os.OpenFile(tmp_path, os.O_RDWR|os.O_CREATE, 0600) + + if err != nil { + return 0, err + } + + defer os.Remove(tmp_path) + + b, err := io.Copy(tmp_file, fh) + + if err != nil { + return 0, err + } + + err = tmp_file.Close() + + if err != nil { + return 0, err + } + + err = os.Chmod(tmp_path, wr.file_mode) + + if err != nil { + return 0, err + } + + err = atomic.ReplaceFile(tmp_path, abs_path) + + if err != nil { + return 0, err + } + + return b, nil +} + +func (wr *FileWriter) WriterURI(ctx context.Context, path string) string { + return filepath.Join(wr.root, path) +} + +func (wr *FileWriter) Close(ctx context.Context) error { + return nil +} diff --git a/vendor/github.com/whosonfirst/go-writer/go.mod b/vendor/github.com/whosonfirst/go-writer/go.mod new file mode 100644 index 0000000..b66e549 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/go.mod @@ -0,0 +1,9 @@ +module github.com/whosonfirst/go-writer + +go 1.16 + +require ( + github.com/aaronland/go-roster v0.0.2 + github.com/g8rswimmer/error-chain v1.0.0 + github.com/natefinch/atomic v1.0.1 +) diff --git a/vendor/github.com/whosonfirst/go-writer/go.sum b/vendor/github.com/whosonfirst/go-writer/go.sum new file mode 100644 index 0000000..7d0f513 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/go.sum @@ -0,0 +1,38 @@ +github.com/aaronland/go-roster v0.0.1 h1:r1l4n1HfWvEtOXZvhfXX0Won9Xf6QJsigdUdzOtuy/M= +github.com/aaronland/go-roster v0.0.1/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/aaronland/go-roster v0.0.2 h1:2Fu7v4VQLRLRL/Zgr6R9S5JxsW75Ab/K88QtMVX532s= +github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= +github.com/facebookgo/atomicfile v0.0.0-20151019000000-2de1f203e7d5e386a6833233882782932729f27e h1:bYAD+4OJX4+LUrmLhpNFiicL4B0mnswQe5QaI6rxJ4A= +github.com/facebookgo/atomicfile v0.0.0-20151019000000-2de1f203e7d5e386a6833233882782932729f27e/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= +github.com/g8rswimmer/error-chain v1.0.0 h1:WnwnunlvqtGPHVHmBfbmUyAgrtag8Y6nNpwLWmtSYOQ= +github.com/g8rswimmer/error-chain v1.0.0/go.mod h1:XPJ/brUsL7yzc5VRlIxtf9GvoUqnOKVI9fg2MB5DWx8= +github.com/go-ini/ini v1.42.0 h1:TWr1wGj35+UiWHlBA8er89seFXxzwFn11spilrrj+38= +github.com/go-ini/ini v1.42.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/natefinch/atomic v0.0.0-20150920032501-a62ce929ffcc h1:7xGrl4tTpBQu5Zjll08WupHyq+Sp0Z/adtyf1cfk3Q8= +github.com/natefinch/atomic v0.0.0-20150920032501-a62ce929ffcc/go.mod h1:1rLVY/DWf3U6vSZgH16S7pymfrhK2lcUlXjgGglw/lY= +github.com/natefinch/atomic v0.0.0-20200526193002-18c0533a5b09 h1:DXR0VtCesBD2ss3toN9OEeXszpQmW9dc3SvUbUfiBC0= +github.com/natefinch/atomic v0.0.0-20200526193002-18c0533a5b09/go.mod h1:1rLVY/DWf3U6vSZgH16S7pymfrhK2lcUlXjgGglw/lY= +github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= +github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/whosonfirst/go-whosonfirst-cache v0.1.0 h1:ryWTsHj7gAEjwHC/WjsjROpFflsz3SCa7W9Qnk4EU7k= +github.com/whosonfirst/go-whosonfirst-cache v0.1.0/go.mod h1:P5Tx34j2M50qX/kTfXY516apwGzJGkFSBYQI7TGArKw= +github.com/whosonfirst/go-whosonfirst-cli v0.1.0 h1:Wwj9z0R/ryHmPmpVm5jCbXdG4agJzKMWXDtPVReN/KA= +github.com/whosonfirst/go-whosonfirst-cli v0.1.0/go.mod h1:Edy+amD+fMq1QS1yxB3u8maA8I93q/LG7JRNh+fsdfc= +github.com/whosonfirst/go-whosonfirst-reader v0.0.0-20191122203133-047f20452865 h1:1GYjmjunRhDm1E4/aM/AIhjBij8C9kMqufjS1G2P0fs= +github.com/whosonfirst/go-whosonfirst-reader v0.0.0-20191122203133-047f20452865/go.mod h1:xYzBn6llLD/uS6Zhh0H4LAqddEJHXdQSUIxywTnhpOU= +github.com/whosonfirst/go-whosonfirst-sources v0.1.0 h1:JuKLa6KWke22jBfJ1pM9WQHoz1/3pbDv2C+aR+THPPQ= +github.com/whosonfirst/go-whosonfirst-sources v0.1.0/go.mod h1:EUMHyGzUmqPPxlMmOp+28BFeoBdxxE0HCKRd67lkqGM= +github.com/whosonfirst/go-whosonfirst-uri v0.1.0 h1:JMlpam0x1hVrFBMTAPY3edIHz7azfMK8lLI2kM9BgbI= +github.com/whosonfirst/go-whosonfirst-uri v0.1.0/go.mod h1:8eaDVcc4v+HHHEDaRbApdmhPwM4/JQllw2PktvZcPVs= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/vendor/github.com/whosonfirst/go-writer/io.go b/vendor/github.com/whosonfirst/go-writer/io.go new file mode 100644 index 0000000..5ce1a2f --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/io.go @@ -0,0 +1,74 @@ +package writer + +import ( + "context" + "errors" + "io" +) + +const IOWRITER_TARGET_KEY string = "github.com/whosonfirst/go-writer#io_writer" + +type IOWriter struct { + Writer +} + +func init() { + + ctx := context.Background() + err := RegisterWriter(ctx, "io", NewIOWriter) + + if err != nil { + panic(err) + } +} + +func NewIOWriter(ctx context.Context, uri string) (Writer, error) { + + wr := &IOWriter{} + return wr, nil +} + +func (wr *IOWriter) Write(ctx context.Context, uri string, fh io.ReadSeeker) (int64, error) { + + target, err := GetIOWriterFromContext(ctx) + + if err != nil { + return 0, err + } + + return io.Copy(target, fh) +} + +func (wr *IOWriter) WriterURI(ctx context.Context, uri string) string { + return uri +} + +func (wr *IOWriter) Close(ctx context.Context) error { + return nil +} + +func SetIOWriterWithContext(ctx context.Context, wr io.Writer) (context.Context, error) { + + ctx = context.WithValue(ctx, IOWRITER_TARGET_KEY, wr) + return ctx, nil +} + +func GetIOWriterFromContext(ctx context.Context) (io.Writer, error) { + + v := ctx.Value(IOWRITER_TARGET_KEY) + + if v == nil { + return nil, errors.New("Missing writer") + } + + var target io.Writer + + switch v.(type) { + case io.Writer: + target = v.(io.Writer) + default: + return nil, errors.New("Invalid writer") + } + + return target, nil +} diff --git a/vendor/github.com/whosonfirst/go-writer/multi.go b/vendor/github.com/whosonfirst/go-writer/multi.go new file mode 100644 index 0000000..4217ce4 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/multi.go @@ -0,0 +1,97 @@ +package writer + +import ( + "context" + "fmt" + chain "github.com/g8rswimmer/error-chain" + "io" +) + +// Type MultiWriter holds mutltiple Writer instances. +type MultiWriter struct { + Writer + writers []Writer +} + +// NewMultiWriter returns a Writer instance that will send all writes to each instance in 'writers'. +// Writes happen synchronolously in the order in which the underlying Writer instances are specified. +func NewMultiWriter(writers ...Writer) Writer { + + wr := &MultiWriter{ + writers: writers, + } + + return wr +} + +func (mw *MultiWriter) Write(ctx context.Context, key string, fh io.ReadSeeker) (int64, error) { + + errors := make([]error, 0) + count := int64(0) + + for _, wr := range mw.writers { + + i, err := wr.Write(ctx, key, fh) + + if err != nil { + errors = append(errors, err) + continue + } + + count += i + _, err = fh.Seek(0, 0) + + if err != nil { + return count, err + } + } + + if len(errors) > 0 { + + err := fmt.Errorf("One or more Write operations failed") + err = errorChain(err, errors...) + + return count, err + } + + return count, nil +} + +func (mw *MultiWriter) WriterURI(ctx context.Context, key string) string { + return "" +} + +func (mw *MultiWriter) Close(ctx context.Context) error { + + errors := make([]error, 0) + + for _, wr := range mw.writers { + + err := wr.Close(ctx) + + if err != nil { + errors = append(errors, err) + } + } + + if len(errors) > 0 { + + err := fmt.Errorf("One or more Close operations failed") + err = errorChain(err, errors...) + + return err + } + + return nil +} + +func errorChain(first error, others ...error) error { + ec := chain.New() + ec.Add(first) + + for _, e := range others { + ec.Add(e) + } + + return ec +} diff --git a/vendor/github.com/whosonfirst/go-writer/null.go b/vendor/github.com/whosonfirst/go-writer/null.go new file mode 100644 index 0000000..cd45a45 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/null.go @@ -0,0 +1,38 @@ +package writer + +import ( + "context" + "io" +) + +type NullWriter struct { + Writer +} + +func init() { + + ctx := context.Background() + err := RegisterWriter(ctx, "null", NewNullWriter) + + if err != nil { + panic(err) + } +} + +func NewNullWriter(ctx context.Context, uri string) (Writer, error) { + + wr := &NullWriter{} + return wr, nil +} + +func (wr *NullWriter) Write(ctx context.Context, uri string, fh io.ReadSeeker) (int64, error) { + return io.Copy(io.Discard, fh) +} + +func (wr *NullWriter) WriterURI(ctx context.Context, uri string) string { + return uri +} + +func (wr *NullWriter) Close(ctx context.Context) error { + return nil +} diff --git a/vendor/github.com/whosonfirst/go-writer/repo.go b/vendor/github.com/whosonfirst/go-writer/repo.go new file mode 100644 index 0000000..e99617f --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/repo.go @@ -0,0 +1,37 @@ +package writer + +import ( + "context" + "fmt" + "net/url" + "path/filepath" +) + +func init() { + + ctx := context.Background() + + err := RegisterWriter(ctx, "repo", NewRepoWriter) + + if err != nil { + panic(err) + } + +} + +// NewRepoWriter is a convenience method to update 'uri' by appending a `data` +// directory to its path and changing its scheme to `fs://` before invoking +// NewWriter with the updated URI. +func NewRepoWriter(ctx context.Context, uri string) (Writer, error) { + + u, err := url.Parse(uri) + + if err != nil { + return nil, err + } + + root := filepath.Join(u.Path, "data") + + uri = fmt.Sprintf("fs://%s", root) + return NewWriter(ctx, uri) +} diff --git a/vendor/github.com/whosonfirst/go-writer/stdout.go b/vendor/github.com/whosonfirst/go-writer/stdout.go new file mode 100644 index 0000000..8922a4c --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/stdout.go @@ -0,0 +1,39 @@ +package writer + +import ( + "context" + "io" + "os" +) + +type StdoutWriter struct { + Writer +} + +func init() { + + ctx := context.Background() + err := RegisterWriter(ctx, "stdout", NewStdoutWriter) + + if err != nil { + panic(err) + } +} + +func NewStdoutWriter(ctx context.Context, uri string) (Writer, error) { + + wr := &StdoutWriter{} + return wr, nil +} + +func (wr *StdoutWriter) Write(ctx context.Context, uri string, fh io.ReadSeeker) (int64, error) { + return io.Copy(os.Stdout, fh) +} + +func (wr *StdoutWriter) WriterURI(ctx context.Context, uri string) string { + return uri +} + +func (wr *StdoutWriter) Close(ctx context.Context) error { + return nil +} diff --git a/vendor/github.com/whosonfirst/go-writer/writer.go b/vendor/github.com/whosonfirst/go-writer/writer.go new file mode 100644 index 0000000..9826f58 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-writer/writer.go @@ -0,0 +1,119 @@ +package writer + +import ( + "context" + "fmt" + "github.com/aaronland/go-roster" + "io" + "net/url" + "sort" + "strings" +) + +var writer_roster roster.Roster + +type WriterInitializationFunc func(ctx context.Context, uri string) (Writer, error) + +type Writer interface { + Write(context.Context, string, io.ReadSeeker) (int64, error) + WriterURI(context.Context, string) string + Close(context.Context) error +} + +func NewService(ctx context.Context, uri string) (Writer, error) { + + err := ensureWriterRoster() + + if err != nil { + return nil, err + } + + parsed, err := url.Parse(uri) + + if err != nil { + return nil, err + } + + scheme := parsed.Scheme + + i, err := writer_roster.Driver(ctx, scheme) + + if err != nil { + return nil, err + } + + init_func := i.(WriterInitializationFunc) + return init_func(ctx, uri) +} + +func RegisterWriter(ctx context.Context, scheme string, init_func WriterInitializationFunc) error { + + err := ensureWriterRoster() + + if err != nil { + return err + } + + return writer_roster.Register(ctx, scheme, init_func) +} + +func ensureWriterRoster() error { + + if writer_roster == nil { + + r, err := roster.NewDefaultRoster() + + if err != nil { + return err + } + + writer_roster = r + } + + return nil +} + +func NewWriter(ctx context.Context, uri string) (Writer, error) { + + u, err := url.Parse(uri) + + if err != nil { + return nil, err + } + + scheme := u.Scheme + + i, err := writer_roster.Driver(ctx, scheme) + + if err != nil { + return nil, err + } + + init_func := i.(WriterInitializationFunc) + return init_func(ctx, uri) +} + +func Writers() []string { + ctx := context.Background() + return writer_roster.Drivers(ctx) +} + +func Schemes() []string { + + ctx := context.Background() + schemes := []string{} + + err := ensureWriterRoster() + + if err != nil { + return schemes + } + + for _, dr := range writer_roster.Drivers(ctx) { + scheme := fmt.Sprintf("%s://", strings.ToLower(dr)) + schemes = append(schemes, scheme) + } + + sort.Strings(schemes) + return schemes +} diff --git a/vendor/go.uber.org/ratelimit/.gitignore b/vendor/go.uber.org/ratelimit/.gitignore new file mode 100644 index 0000000..aa346ac --- /dev/null +++ b/vendor/go.uber.org/ratelimit/.gitignore @@ -0,0 +1,6 @@ +/bin +/vendor +cover.html +cover.out + +*.swp diff --git a/vendor/go.uber.org/ratelimit/CHANGELOG.md b/vendor/go.uber.org/ratelimit/CHANGELOG.md new file mode 100644 index 0000000..b2b89cf --- /dev/null +++ b/vendor/go.uber.org/ratelimit/CHANGELOG.md @@ -0,0 +1,23 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## v0.2.0 - 2021-03-02 +### Added +- Allow configuring the limiter with custom slack. + [#64](https://github.com/uber-go/ratelimit/pull/64) +- Allow configuring the limiter per arbitrary time duration. + [#54](https://github.com/uber-go/ratelimit/pull/54) +### Changed +- Switched from Glide to Go Modules. +### Fixed +- Fix not working slack. + [#60](https://github.com/uber-go/ratelimit/pull/60) + +## v0.1.0 +### Fixed +- Changed the import path for `go.uber.org/atomic` to its newer, canonical + import path. + [#18](https://github.com/uber-go/ratelimit/issues/18) diff --git a/vendor/go.uber.org/ratelimit/LICENSE b/vendor/go.uber.org/ratelimit/LICENSE new file mode 100644 index 0000000..0f3edc8 --- /dev/null +++ b/vendor/go.uber.org/ratelimit/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Uber Technologies, Inc. + +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: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +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. \ No newline at end of file diff --git a/vendor/go.uber.org/ratelimit/Makefile b/vendor/go.uber.org/ratelimit/Makefile new file mode 100644 index 0000000..5bab5d7 --- /dev/null +++ b/vendor/go.uber.org/ratelimit/Makefile @@ -0,0 +1,46 @@ +# Directory to put `go install`ed binaries in. +export GOBIN ?= $(shell pwd)/bin + +GO_FILES := $(shell \ + find . '(' -path '*/.*' -o -path './vendor' ')' -prune \ + -o -name '*.go' -print | cut -b3-) + +.PHONY: bench +bench: + go test -bench=. ./... + +bin/golint: tools/go.mod + @cd tools && go install golang.org/x/lint/golint + +bin/staticcheck: tools/go.mod + @cd tools && go install honnef.co/go/tools/cmd/staticcheck + +.PHONY: build +build: + go build ./... + +.PHONY: cover +cover: + go test -coverprofile=cover.out -coverpkg=./... -v ./... + go tool cover -html=cover.out -o cover.html + +.PHONY: gofmt +gofmt: + $(eval FMT_LOG := $(shell mktemp -t gofmt.XXXXX)) + @gofmt -e -s -l $(GO_FILES) > $(FMT_LOG) || true + @[ ! -s "$(FMT_LOG)" ] || (echo "gofmt failed:" | cat - $(FMT_LOG) && false) + +.PHONY: golint +golint: bin/golint + @$(GOBIN)/golint -set_exit_status ./... + +.PHONY: lint +lint: gofmt golint staticcheck + +.PHONY: staticcheck +staticcheck: bin/staticcheck + @$(GOBIN)/staticcheck ./... + +.PHONY: test +test: + go test -race ./... diff --git a/vendor/go.uber.org/ratelimit/README.md b/vendor/go.uber.org/ratelimit/README.md new file mode 100644 index 0000000..a05a2a8 --- /dev/null +++ b/vendor/go.uber.org/ratelimit/README.md @@ -0,0 +1,46 @@ +# Go rate limiter [![GoDoc][doc-img]][doc] [![Coverage Status][cov-img]][cov] ![test][test-img] + +This package provides a Golang implementation of the leaky-bucket rate limit algorithm. +This implementation refills the bucket based on the time elapsed between +requests instead of requiring an interval clock to fill the bucket discretely. + +Create a rate limiter with a maximum number of operations to perform per second. +Call Take() before each operation. Take will sleep until you can continue. + +```go +import ( + "fmt" + "time" + + "go.uber.org/ratelimit" +) + +func main() { + rl := ratelimit.New(100) // per second + + prev := time.Now() + for i := 0; i < 10; i++ { + now := rl.Take() + fmt.Println(i, now.Sub(prev)) + prev = now + } + + // Output: + // 0 0 + // 1 10ms + // 2 10ms + // 3 10ms + // 4 10ms + // 5 10ms + // 6 10ms + // 7 10ms + // 8 10ms + // 9 10ms +} +``` + +[cov-img]: https://codecov.io/gh/uber-go/ratelimit/branch/master/graph/badge.svg?token=zhLeUjjrm2 +[cov]: https://codecov.io/gh/uber-go/ratelimit +[doc-img]: https://pkg.go.dev/badge/go.uber.org/ratelimit +[doc]: https://pkg.go.dev/go.uber.org/ratelimit +[test-img]: https://github.com/uber-go/ratelimit/workflows/test/badge.svg diff --git a/vendor/go.uber.org/ratelimit/go.mod b/vendor/go.uber.org/ratelimit/go.mod new file mode 100644 index 0000000..7487c42 --- /dev/null +++ b/vendor/go.uber.org/ratelimit/go.mod @@ -0,0 +1,9 @@ +module go.uber.org/ratelimit + +go 1.14 + +require ( + github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 + github.com/stretchr/testify v1.6.1 + go.uber.org/atomic v1.7.0 +) diff --git a/vendor/go.uber.org/ratelimit/go.sum b/vendor/go.uber.org/ratelimit/go.sum new file mode 100644 index 0000000..15512ea --- /dev/null +++ b/vendor/go.uber.org/ratelimit/go.sum @@ -0,0 +1,17 @@ +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/vendor/go.uber.org/ratelimit/limiter_atomic.go b/vendor/go.uber.org/ratelimit/limiter_atomic.go new file mode 100644 index 0000000..745aa4c --- /dev/null +++ b/vendor/go.uber.org/ratelimit/limiter_atomic.go @@ -0,0 +1,110 @@ +// Copyright (c) 2016,2020 Uber Technologies, Inc. +// +// 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: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// 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. + +package ratelimit // import "go.uber.org/ratelimit" + +import ( + "time" + + "sync/atomic" + "unsafe" +) + +type state struct { + last time.Time + sleepFor time.Duration +} + +type atomicLimiter struct { + state unsafe.Pointer + //lint:ignore U1000 Padding is unused but it is crucial to maintain performance + // of this rate limiter in case of collocation with other frequently accessed memory. + padding [56]byte // cache line size - state pointer size = 64 - 8; created to avoid false sharing. + + perRequest time.Duration + maxSlack time.Duration + clock Clock +} + +// newAtomicBased returns a new atomic based limiter. +func newAtomicBased(rate int, opts ...Option) *atomicLimiter { + // TODO consider moving config building to the implementation + // independent code. + config := buildConfig(opts) + perRequest := config.per / time.Duration(rate) + l := &atomicLimiter{ + perRequest: perRequest, + maxSlack: -1 * time.Duration(config.slack) * perRequest, + clock: config.clock, + } + + initialState := state{ + last: time.Time{}, + sleepFor: 0, + } + atomic.StorePointer(&l.state, unsafe.Pointer(&initialState)) + return l +} + +// Take blocks to ensure that the time spent between multiple +// Take calls is on average time.Second/rate. +func (t *atomicLimiter) Take() time.Time { + var ( + newState state + taken bool + interval time.Duration + ) + for !taken { + now := t.clock.Now() + + previousStatePointer := atomic.LoadPointer(&t.state) + oldState := (*state)(previousStatePointer) + + newState = state{ + last: now, + sleepFor: oldState.sleepFor, + } + + // If this is our first request, then we allow it. + if oldState.last.IsZero() { + taken = atomic.CompareAndSwapPointer(&t.state, previousStatePointer, unsafe.Pointer(&newState)) + continue + } + + // sleepFor calculates how much time we should sleep based on + // the perRequest budget and how long the last request took. + // Since the request may take longer than the budget, this number + // can get negative, and is summed across requests. + newState.sleepFor += t.perRequest - now.Sub(oldState.last) + // We shouldn't allow sleepFor to get too negative, since it would mean that + // a service that slowed down a lot for a short period of time would get + // a much higher RPS following that. + if newState.sleepFor < t.maxSlack { + newState.sleepFor = t.maxSlack + } + if newState.sleepFor > 0 { + newState.last = newState.last.Add(newState.sleepFor) + interval, newState.sleepFor = newState.sleepFor, 0 + } + taken = atomic.CompareAndSwapPointer(&t.state, previousStatePointer, unsafe.Pointer(&newState)) + } + t.clock.Sleep(interval) + return newState.last +} diff --git a/vendor/go.uber.org/ratelimit/limiter_mutexbased.go b/vendor/go.uber.org/ratelimit/limiter_mutexbased.go new file mode 100644 index 0000000..1408f1c --- /dev/null +++ b/vendor/go.uber.org/ratelimit/limiter_mutexbased.go @@ -0,0 +1,88 @@ +// Copyright (c) 2016,2020 Uber Technologies, Inc. +// +// 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: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// 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. + +package ratelimit // import "go.uber.org/ratelimit" + +import ( + "sync" + "time" +) + +type mutexLimiter struct { + sync.Mutex + last time.Time + sleepFor time.Duration + perRequest time.Duration + maxSlack time.Duration + clock Clock +} + +// newMutexBased returns a new atomic based limiter. +func newMutexBased(rate int, opts ...Option) *mutexLimiter { + // TODO consider moving config building to the implementation + // independent code. + config := buildConfig(opts) + perRequest := config.per / time.Duration(rate) + l := &mutexLimiter{ + perRequest: perRequest, + maxSlack: -1 * time.Duration(config.slack) * perRequest, + clock: config.clock, + } + return l +} + +// Take blocks to ensure that the time spent between multiple +// Take calls is on average time.Second/rate. +func (t *mutexLimiter) Take() time.Time { + t.Lock() + defer t.Unlock() + + now := t.clock.Now() + + // If this is our first request, then we allow it. + if t.last.IsZero() { + t.last = now + return t.last + } + + // sleepFor calculates how much time we should sleep based on + // the perRequest budget and how long the last request took. + // Since the request may take longer than the budget, this number + // can get negative, and is summed across requests. + t.sleepFor += t.perRequest - now.Sub(t.last) + + // We shouldn't allow sleepFor to get too negative, since it would mean that + // a service that slowed down a lot for a short period of time would get + // a much higher RPS following that. + if t.sleepFor < t.maxSlack { + t.sleepFor = t.maxSlack + } + + // If sleepFor is positive, then we should sleep now. + if t.sleepFor > 0 { + t.clock.Sleep(t.sleepFor) + t.last = now.Add(t.sleepFor) + t.sleepFor = 0 + } else { + t.last = now + } + + return t.last +} diff --git a/vendor/go.uber.org/ratelimit/ratelimit.go b/vendor/go.uber.org/ratelimit/ratelimit.go new file mode 100644 index 0000000..b5b16e5 --- /dev/null +++ b/vendor/go.uber.org/ratelimit/ratelimit.go @@ -0,0 +1,135 @@ +// Copyright (c) 2016,2020 Uber Technologies, Inc. +// +// 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: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// 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. + +package ratelimit // import "go.uber.org/ratelimit" + +import ( + "time" + + "github.com/andres-erbsen/clock" +) + +// Note: This file is inspired by: +// https://github.com/prashantv/go-bench/blob/master/ratelimit + +// Limiter is used to rate-limit some process, possibly across goroutines. +// The process is expected to call Take() before every iteration, which +// may block to throttle the goroutine. +type Limiter interface { + // Take should block to make sure that the RPS is met. + Take() time.Time +} + +// Clock is the minimum necessary interface to instantiate a rate limiter with +// a clock or mock clock, compatible with clocks created using +// github.com/andres-erbsen/clock. +type Clock interface { + Now() time.Time + Sleep(time.Duration) +} + +// config configures a limiter. +type config struct { + clock Clock + slack int + per time.Duration +} + +// New returns a Limiter that will limit to the given RPS. +func New(rate int, opts ...Option) Limiter { + return newAtomicBased(rate, opts...) +} + +// buildConfig combines defaults with options. +func buildConfig(opts []Option) config { + c := config{ + clock: clock.New(), + slack: 10, + per: time.Second, + } + + for _, opt := range opts { + opt.apply(&c) + } + return c +} + +// Option configures a Limiter. +type Option interface { + apply(*config) +} + +type clockOption struct { + clock Clock +} + +func (o clockOption) apply(c *config) { + c.clock = o.clock +} + +// WithClock returns an option for ratelimit.New that provides an alternate +// Clock implementation, typically a mock Clock for testing. +func WithClock(clock Clock) Option { + return clockOption{clock: clock} +} + +type slackOption int + +func (o slackOption) apply(c *config) { + c.slack = int(o) +} + +// WithoutSlack configures the limiter to be strict and not to accumulate +// previously "unspent" requests for future bursts of traffic. +var WithoutSlack Option = slackOption(0) + +// WithSlack configures custom slack. +// Slack allows the limiter to accumulate "unspent" requests +// for future bursts of traffic. +func WithSlack(slack int) Option { + return slackOption(slack) +} + +type perOption time.Duration + +func (p perOption) apply(c *config) { + c.per = time.Duration(p) +} + +// Per allows configuring limits for different time windows. +// +// The default window is one second, so New(100) produces a one hundred per +// second (100 Hz) rate limiter. +// +// New(2, Per(60*time.Second)) creates a 2 per minute rate limiter. +func Per(per time.Duration) Option { + return perOption(per) +} + +type unlimited struct{} + +// NewUnlimited returns a RateLimiter that is not limited. +func NewUnlimited() Limiter { + return unlimited{} +} + +func (unlimited) Take() time.Time { + return time.Now() +} diff --git a/vendor/modules.txt b/vendor/modules.txt index ea8e9a8..ed38f62 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,5 +1,13 @@ +# github.com/aaronland/go-artisanal-integers v0.1.1 +github.com/aaronland/go-artisanal-integers +# github.com/aaronland/go-artisanal-integers-proxy v0.2.5 +github.com/aaronland/go-artisanal-integers-proxy/service +# github.com/aaronland/go-brooklynintegers-api v1.2.4 +github.com/aaronland/go-brooklynintegers-api # github.com/aaronland/go-json-query v0.1.2 github.com/aaronland/go-json-query +# github.com/aaronland/go-pool v1.0.0 +github.com/aaronland/go-pool # github.com/aaronland/go-roster v0.0.2 ## explicit github.com/aaronland/go-roster @@ -7,6 +15,18 @@ github.com/aaronland/go-roster ## explicit github.com/aaronland/go-sqlite github.com/aaronland/go-sqlite/database +# github.com/aaronland/go-string v0.1.2 +github.com/aaronland/go-string/random +# github.com/aaronland/go-uid v0.0.3 +github.com/aaronland/go-uid +# github.com/aaronland/go-uid-artisanal v0.0.1 +github.com/aaronland/go-uid-artisanal +# github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 +github.com/andres-erbsen/clock +# github.com/cenkalti/backoff/v4 v4.1.2 +github.com/cenkalti/backoff/v4 +# github.com/g8rswimmer/error-chain v1.0.0 +github.com/g8rswimmer/error-chain # github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce github.com/hashicorp/errwrap # github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874 @@ -15,6 +35,8 @@ github.com/hashicorp/go-multierror github.com/mattn/go-sqlite3 # github.com/mmcloughlin/geohash v0.10.0 github.com/mmcloughlin/geohash +# github.com/natefinch/atomic v1.0.1 +github.com/natefinch/atomic # github.com/paulmach/go.geojson v1.4.0 github.com/paulmach/go.geojson # github.com/paulmach/orb v0.5.0 @@ -33,11 +55,17 @@ github.com/sfomuseum/go-edtf/level2 github.com/sfomuseum/go-edtf/parser github.com/sfomuseum/go-edtf/re github.com/sfomuseum/go-edtf/tests +# github.com/sfomuseum/go-sfomuseum-export/v2 v2.3.6 +github.com/sfomuseum/go-sfomuseum-export/v2 +github.com/sfomuseum/go-sfomuseum-export/v2/properties # github.com/sfomuseum/go-sfomuseum-geojson v0.1.3 github.com/sfomuseum/go-sfomuseum-geojson/feature # github.com/sfomuseum/go-sfomuseum-reader v0.0.2 ## explicit github.com/sfomuseum/go-sfomuseum-reader +# github.com/sfomuseum/go-sfomuseum-writer v0.2.7 +## explicit +github.com/sfomuseum/go-sfomuseum-writer # github.com/skelterjohn/geom v0.0.0-20180103142417-96f3e8a219c5 github.com/skelterjohn/geom # github.com/tidwall/gjson v1.14.1 @@ -47,6 +75,8 @@ github.com/tidwall/gjson github.com/tidwall/match # github.com/tidwall/pretty v1.2.0 github.com/tidwall/pretty +# github.com/tidwall/sjson v1.2.4 +github.com/tidwall/sjson # github.com/twpayne/go-geom v1.4.1 github.com/twpayne/go-geom github.com/twpayne/go-geom/encoding/geojson @@ -60,12 +90,18 @@ github.com/whosonfirst/go-reader github.com/whosonfirst/go-rfc-5646 # github.com/whosonfirst/go-whosonfirst-crawl v0.2.1 github.com/whosonfirst/go-whosonfirst-crawl +# github.com/whosonfirst/go-whosonfirst-export/v2 v2.4.2 +## explicit +github.com/whosonfirst/go-whosonfirst-export/v2 +github.com/whosonfirst/go-whosonfirst-export/v2/properties # github.com/whosonfirst/go-whosonfirst-feature v0.0.20 ## explicit github.com/whosonfirst/go-whosonfirst-feature/properties # github.com/whosonfirst/go-whosonfirst-flags v0.4.3 github.com/whosonfirst/go-whosonfirst-flags github.com/whosonfirst/go-whosonfirst-flags/existential +# github.com/whosonfirst/go-whosonfirst-format v0.3.7 +github.com/whosonfirst/go-whosonfirst-format # github.com/whosonfirst/go-whosonfirst-geojson-v2 v0.16.4 github.com/whosonfirst/go-whosonfirst-geojson-v2 github.com/whosonfirst/go-whosonfirst-geojson-v2/feature @@ -75,6 +111,9 @@ github.com/whosonfirst/go-whosonfirst-geojson-v2/properties/whosonfirst github.com/whosonfirst/go-whosonfirst-geojson-v2/utils # github.com/whosonfirst/go-whosonfirst-hash v0.1.0 github.com/whosonfirst/go-whosonfirst-hash +# github.com/whosonfirst/go-whosonfirst-id v0.0.4 +## explicit +github.com/whosonfirst/go-whosonfirst-id # github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.2 ## explicit github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter @@ -106,7 +145,12 @@ github.com/whosonfirst/go-whosonfirst-sqlite-index/v2 # github.com/whosonfirst/go-whosonfirst-uri v1.2.0 ## explicit github.com/whosonfirst/go-whosonfirst-uri +# github.com/whosonfirst/go-writer v0.8.0 +## explicit +github.com/whosonfirst/go-writer # github.com/whosonfirst/walk v0.0.1 github.com/whosonfirst/walk # github.com/whosonfirst/warning v0.1.1 github.com/whosonfirst/warning +# go.uber.org/ratelimit v0.2.0 +go.uber.org/ratelimit