diff --git a/.gqlgenc.yml b/.gqlgenc.yml new file mode 100644 index 000000000..9d10817b5 --- /dev/null +++ b/.gqlgenc.yml @@ -0,0 +1,13 @@ +model: + filename: ./pkg/scraper/stashbox/graphql/generated_models.go +client: + filename: ./pkg/scraper/stashbox/graphql/generated_client.go +models: + Date: + model: github.com/99designs/gqlgen/graphql.String +endpoint: + # This points to stashdb.org currently, but can be directed at any stash-box + # instance. It is used for generation only. + url: https://stashdb.org/graphql +query: + - "./graphql/stash-box/*.graphql" diff --git a/Makefile b/Makefile index 44a3904b9..03d86daeb 100644 --- a/Makefile +++ b/Makefile @@ -63,6 +63,11 @@ generate: go generate -mod=vendor cd ui/v2.5 && yarn run gqlgen +# Regenerates stash-box client files +.PHONY: generate-stash-box-client +generate-stash-box-client: + go run -mod=vendor github.com/Yamashou/gqlgenc + # Runs gofmt -w on the project's source code, modifying any files that do not match its style. .PHONY: fmt fmt: diff --git a/go.mod b/go.mod index 61580fe4e..08c335f7e 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,8 @@ module github.com/stashapp/stash require ( - github.com/99designs/gqlgen v0.9.0 + github.com/99designs/gqlgen v0.12.2 + github.com/Yamashou/gqlgenc v0.0.0-20200902035953-4dbef3551953 github.com/antchfx/htmlquery v1.2.3 github.com/bmatcuk/doublestar/v2 v2.0.1 github.com/chromedp/cdproto v0.0.0-20200608134039-8a80cdaf865c @@ -14,7 +15,6 @@ require ( github.com/gorilla/sessions v1.2.0 github.com/gorilla/websocket v1.4.2 github.com/h2non/filetype v1.0.8 - github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a github.com/jmoiron/sqlx v1.2.0 github.com/json-iterator/go v1.1.9 @@ -27,13 +27,13 @@ require ( github.com/spf13/viper v1.7.0 github.com/stretchr/testify v1.5.1 github.com/tidwall/gjson v1.6.0 - github.com/vektah/gqlparser v1.1.2 - github.com/vektra/mockery v1.1.2 // indirect + github.com/vektah/gqlparser/v2 v2.0.1 github.com/vektra/mockery/v2 v2.2.1 - golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/image v0.0.0-20190802002840-cff245a6509b - golang.org/x/net v0.0.0-20200602114024-627f9648deb9 - gopkg.in/yaml.v2 v2.2.4 + golang.org/x/net v0.0.0-20200822124328-c89045814202 + golang.org/x/tools v0.0.0-20200915031644-64986481280e // indirect + gopkg.in/yaml.v2 v2.3.0 ) replace git.apache.org/thrift.git => github.com/apache/thrift v0.0.0-20180902110319-2566ecd5d999 diff --git a/go.sum b/go.sum index 1829c755d..7a51679a7 100644 --- a/go.sum +++ b/go.sum @@ -18,8 +18,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= -github.com/99designs/gqlgen v0.9.0 h1:g1arBPML74Vqv0L3Q+TqIhGXLspV+2MYtRLkBxuZrlE= -github.com/99designs/gqlgen v0.9.0/go.mod h1:HrrG7ic9EgLPsULxsZh/Ti+p0HNWgR3XRuvnD0pb5KY= +github.com/99designs/gqlgen v0.12.2 h1:aOdpsiCycFtCnAv8CAI1exnKrIDHMqtMzQoXeTziY4o= +github.com/99designs/gqlgen v0.12.2/go.mod h1:7zdGo6ry9u1YBp/qlb2uxSU5Mt2jQKLcBETQiKk+Bxo= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -30,8 +30,14 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/Yamashou/gqlgenc v0.0.0-20200902035953-4dbef3551953 h1:+iPJDL28FxZhEdtJ9qykrMt/oDiOvlzTa0zV06nUcFM= +github.com/Yamashou/gqlgenc v0.0.0-20200902035953-4dbef3551953/go.mod h1:kaTsk10p2hJWwrB2t7vMsk1lXj9KAHaDYRtJQiB+Ick= github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/agnivade/levenshtein v1.0.3 h1:M5ZnqLOoZR8ygVq0FfkXsNOKzMCk0xRiow0R5+5VkQ0= +github.com/agnivade/levenshtein v1.0.3/go.mod h1:4SFRZbbXWLF4MU1T9Qg0pGgH3Pjs+t6ie5efyrwRJXs= +github.com/agnivade/levenshtein v1.1.0 h1:n6qGwyHG61v3ABce1rPVZklEYRT8NFpCMrpZdBUbYGM= +github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -44,6 +50,8 @@ github.com/antchfx/xpath v1.1.6 h1:6sVh6hB5T6phw1pFpHRQ+C4bd8sNI+O58flqtg7h0R0= github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= github.com/apache/thrift v0.0.0-20180902110319-2566ecd5d999/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -77,6 +85,8 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg= @@ -93,6 +103,9 @@ 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/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc= github.com/disintegration/imaging v1.6.0 h1:nVPXRUUQ36Z7MNf0O77UzgnOb1mkMMor7lmJMJXc/mA= github.com/disintegration/imaging v1.6.0/go.mod h1:xuIt+sRxDFrHS0drzXUlCJthkJ8k7lkkUojDSR247MQ= @@ -372,6 +385,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 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.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -383,6 +398,7 @@ github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -396,8 +412,6 @@ github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ= -github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -455,6 +469,7 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= @@ -482,6 +497,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= @@ -510,9 +526,14 @@ github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/markbates/sigtx v1.0.0/go.mod h1:QF1Hv6Ic6Ca6W+T+DL0Y/ypborFKyvUY9HmuCD4VeTc= github.com/markbates/willie v1.0.9/go.mod h1:fsrFVWl91+gXpx/6dv715j7i11fYPfZ9ZGfH0DQzY7w= +github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007 h1:reVOUXwnhsYv/8UqjvhrMOu5CNT9UapHFLbQ2JcXsmg= +github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= @@ -571,6 +592,8 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -604,7 +627,11 @@ github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.18.0 h1:CbAm3kP2Tptby1i9sYy2MGRg0uxIN9cyDb59Ys7W8z8= github.com/rs/zerolog v1.18.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -612,6 +639,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs= 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.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= @@ -637,6 +666,7 @@ github.com/shurcooL/octicon v0.0.0-20180602230221-c42b0e3b24d9/go.mod h1:eWdoE5J github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= @@ -650,7 +680,9 @@ github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= @@ -684,6 +716,7 @@ github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 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/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= @@ -701,14 +734,14 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= -github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k= +github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e h1:+w0Zm/9gaWpEAyDlU1eKOuk5twTjAjuevXqcJJw8hrg= github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U= -github.com/vektah/gqlparser v1.1.2 h1:ZsyLGn7/7jDNI+y4SEhI4yAxRChlv15pUHMjijT+e68= -github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -github.com/vektra/mockery v1.1.2 h1:uc0Yn67rJpjt8U/mAZimdCKn9AeA97BOkjpmtBSlfP4= -github.com/vektra/mockery v1.1.2/go.mod h1:VcfZjKaFOPO+MpN4ZvwPjs4c48lkq1o3Ym8yHZJu0jU= +github.com/vektah/gqlparser v1.3.1 h1:8b0IcD3qZKWJQHSzynbDlrtP3IxVydZ2DZepCGofqfU= +github.com/vektah/gqlparser v1.3.1/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74= +github.com/vektah/gqlparser/v2 v2.0.1 h1:xgl5abVnsd4hkN9rk65OJID9bfcLSMuTaTcZj777q1o= +github.com/vektah/gqlparser/v2 v2.0.1/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms= github.com/vektra/mockery/v2 v2.2.1 h1:EYgPvxyYkm/0JKs62qlVc9pO+ljb8biPbDWabk5/PmI= github.com/vektra/mockery/v2 v2.2.1/go.mod h1:rBZUbbhMbiSX1WlCGsOgAi6xjuJGxB7KKbnoL0XNYW8= github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= @@ -717,6 +750,8 @@ github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -752,18 +787,16 @@ golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/Le golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +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/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190118043309-183bebdce1b2 h1:FNSSV4jv1PrPsiM2iKGpqLPPgYACqh9Muav7Pollk1k= -golang.org/x/image v0.0.0-20190118043309-183bebdce1b2/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -779,8 +812,11 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= +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-20180816102801-aaf60122140d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -812,11 +848,13 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgP golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +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-20200421231249-e086a090c8fd h1:QPwSajcTUrFriMF1nJ3XzgoqakqQEsnZf9LdXdi2nkI= golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -833,6 +871,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= 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-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -859,6 +899,7 @@ golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190116161447-11f53e031339 h1:g/Jesu8+QLnA0CPzF3E1pURg0Byr7i6jLoX5sqjcAh0= golang.org/x/sys v0.0.0-20190116161447-11f53e031339/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -933,12 +974,24 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589 h1:rjUrONFu4kLchcZTfp3/96bR8bW8dIa8uz3cR5n0cgM= +golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200323144430-8dcfad9e016e h1:ssd5ulOvVWlh4kDSUF2SqzmMeWfjmwDXM+uGw/aQjRE= golang.org/x/tools v0.0.0-20200323144430-8dcfad9e016e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3 h1:OjYQxZBKJFs+sJbHkvSGIKNMkZXDJQ9JsMpebGhkafI= +golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200915031644-64986481280e h1:tfSNPIxC48Azhz4nLSPskz/yE9R6ftFRK8pfgfqWUAc= +golang.org/x/tools v0.0.0-20200915031644-64986481280e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= @@ -956,6 +1009,7 @@ google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO50 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -984,6 +1038,8 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= @@ -1000,6 +1056,9 @@ 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 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/graphql/documents/queries/scrapers/scrapers.graphql b/graphql/documents/queries/scrapers/scrapers.graphql index 9904f31f5..0aaceba84 100644 --- a/graphql/documents/queries/scrapers/scrapers.graphql +++ b/graphql/documents/queries/scrapers/scrapers.graphql @@ -66,3 +66,9 @@ query ScrapeMovieURL($url: String!) { ...ScrapedMovieData } } + +query QueryStashBoxScene($input: StashBoxQueryInput!) { + queryStashBoxScene(input: $input) { + ...ScrapedSceneData + } +} \ No newline at end of file diff --git a/graphql/schema/schema.graphql b/graphql/schema/schema.graphql index 656b24f95..ac1e2d696 100644 --- a/graphql/schema/schema.graphql +++ b/graphql/schema/schema.graphql @@ -79,6 +79,9 @@ type Query { """Scrape a list of performers from a query""" scrapeFreeonesPerformerList(query: String!): [String!]! + """Query StashBox for scenes""" + queryStashBoxScene(input: StashBoxQueryInput!): [ScrapedScene!]! + # Plugins """List loaded plugins""" plugins: [Plugin!] diff --git a/graphql/schema/types/scraper.graphql b/graphql/schema/types/scraper.graphql index 6a7dcaa0b..d5c0ad397 100644 --- a/graphql/schema/types/scraper.graphql +++ b/graphql/schema/types/scraper.graphql @@ -24,7 +24,6 @@ type Scraper { movie: ScraperSpec } - type ScrapedScenePerformer { """Set if performer matched""" stored_id: ID @@ -88,3 +87,12 @@ type ScrapedScene { performers: [ScrapedScenePerformer!] movies: [ScrapedSceneMovie!] } + +input StashBoxQueryInput { + """Index of the configured stash-box instance to use""" + stash_box_index: Int! + """Instructs query by scene fingerprints""" + scene_ids: [ID!] + """Query by query string""" + q: String +} diff --git a/graphql/stash-box/query.graphql b/graphql/stash-box/query.graphql new file mode 100644 index 000000000..4424ce8db --- /dev/null +++ b/graphql/stash-box/query.graphql @@ -0,0 +1,139 @@ +fragment URLFragment on URL { + url + type +} + +fragment ImageFragment on Image { + id + url + width + height +} + +fragment StudioFragment on Studio { + name + id + urls { + ...URLFragment + } + images { + ...ImageFragment + } +} + +fragment TagFragment on Tag { + name + id +} + +fragment FuzzyDateFragment on FuzzyDate { + date + accuracy +} + +fragment MeasurementsFragment on Measurements { + band_size + cup_size + waist + hip +} + +fragment BodyModificationFragment on BodyModification { + location + description +} + +fragment PerformerFragment on Performer { + id + name + disambiguation + aliases + gender + urls { + ...URLFragment + } + images { + ...ImageFragment + } + birthdate { + ...FuzzyDateFragment + } + ethnicity + country + eye_color + hair_color + height + measurements { + ...MeasurementsFragment + } + breast_type + career_start_year + career_end_year + tattoos { + ...BodyModificationFragment + } + piercings { + ...BodyModificationFragment + } +} + +fragment PerformerAppearanceFragment on PerformerAppearance { + as + performer { + ...PerformerFragment + } +} + +fragment FingerprintFragment on Fingerprint { + algorithm + hash + duration +} + +fragment SceneFragment on Scene { + id + title + details + duration + date + urls { + ...URLFragment + } + images { + ...ImageFragment + } + studio { + ...StudioFragment + } + tags { + ...TagFragment + } + performers { + ...PerformerAppearanceFragment + } + fingerprints { + ...FingerprintFragment + } +} + +query FindSceneByFingerprint($fingerprint: FingerprintQueryInput!) { + findSceneByFingerprint(fingerprint: $fingerprint) { + ...SceneFragment + } +} + +query FindScenesByFingerprints($fingerprints: [String!]!) { + findScenesByFingerprints(fingerprints: $fingerprints) { + ...SceneFragment + } +} + +query SearchScene($term: String!) { + searchScene(term: $term) { + ...SceneFragment + } +} + +mutation SubmitFingerprint($input: FingerprintSubmission!) { + submitFingerprint(input: $input) +} diff --git a/pkg/api/resolver_query_scraper.go b/pkg/api/resolver_query_scraper.go index c66f2ebc6..ecbf0371a 100644 --- a/pkg/api/resolver_query_scraper.go +++ b/pkg/api/resolver_query_scraper.go @@ -2,10 +2,13 @@ package api import ( "context" + "fmt" "github.com/stashapp/stash/pkg/manager" + "github.com/stashapp/stash/pkg/manager/config" "github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/scraper" + "github.com/stashapp/stash/pkg/scraper/stashbox" ) // deprecated @@ -72,3 +75,23 @@ func (r *queryResolver) ScrapeSceneURL(ctx context.Context, url string) (*models func (r *queryResolver) ScrapeMovieURL(ctx context.Context, url string) (*models.ScrapedMovie, error) { return manager.GetInstance().ScraperCache.ScrapeMovieURL(url) } + +func (r *queryResolver) QueryStashBoxScene(ctx context.Context, input models.StashBoxQueryInput) ([]*models.ScrapedScene, error) { + boxes := config.GetStashBoxes() + + if input.StashBoxIndex < 0 || input.StashBoxIndex >= len(boxes) { + return nil, fmt.Errorf("invalid stash_box_index %d", input.StashBoxIndex) + } + + client := stashbox.NewClient(*boxes[input.StashBoxIndex]) + + if len(input.SceneIds) > 0 { + return client.FindStashBoxScenesByFingerprints(input.SceneIds) + } + + if input.Q != nil { + return client.QueryStashBoxScene(*input.Q) + } + + return nil, nil +} diff --git a/pkg/api/server.go b/pkg/api/server.go index df713c516..02b44c07d 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -129,16 +129,12 @@ func Start() { message := fmt.Sprintf("Internal system error. Error <%v>", err) return errors.New(message) }) - requestMiddleware := handler.RequestMiddleware(func(ctx context.Context, next func(ctx context.Context) []byte) []byte { - //api.GetRequestContext(ctx).Variables[] - return next(ctx) - }) websocketUpgrader := handler.WebsocketUpgrader(websocket.Upgrader{ CheckOrigin: func(r *http.Request) bool { return true }, }) - gqlHandler := handler.GraphQL(models.NewExecutableSchema(models.Config{Resolvers: &Resolver{}}), recoverFunc, requestMiddleware, websocketUpgrader) + gqlHandler := handler.GraphQL(models.NewExecutableSchema(models.Config{Resolvers: &Resolver{}}), recoverFunc, websocketUpgrader) r.Handle("/graphql", gqlHandler) r.Handle("/playground", handler.Playground("GraphQL playground", "/graphql")) diff --git a/pkg/models/scraped.go b/pkg/models/scraped.go new file mode 100644 index 000000000..c2167e902 --- /dev/null +++ b/pkg/models/scraped.go @@ -0,0 +1,87 @@ +package models + +import "strconv" + +// MatchScrapedScenePerformer matches the provided performer with the +// performers in the database and sets the ID field if one is found. +func MatchScrapedScenePerformer(p *ScrapedScenePerformer) error { + qb := NewPerformerQueryBuilder() + + performers, err := qb.FindByNames([]string{p.Name}, nil, true) + + if err != nil { + return err + } + + if len(performers) != 1 { + // ignore - cannot match + return nil + } + + id := strconv.Itoa(performers[0].ID) + p.ID = &id + return nil +} + +// MatchScrapedSceneStudio matches the provided studio with the studios +// in the database and sets the ID field if one is found. +func MatchScrapedSceneStudio(s *ScrapedSceneStudio) error { + qb := NewStudioQueryBuilder() + + studio, err := qb.FindByName(s.Name, nil, true) + + if err != nil { + return err + } + + if studio == nil { + // ignore - cannot match + return nil + } + + id := strconv.Itoa(studio.ID) + s.ID = &id + return nil +} + +// MatchScrapedSceneMovie matches the provided movie with the movies +// in the database and sets the ID field if one is found. +func MatchScrapedSceneMovie(m *ScrapedSceneMovie) error { + qb := NewMovieQueryBuilder() + + movies, err := qb.FindByNames([]string{m.Name}, nil, true) + + if err != nil { + return err + } + + if len(movies) != 1 { + // ignore - cannot match + return nil + } + + id := strconv.Itoa(movies[0].ID) + m.ID = &id + return nil +} + +// MatchScrapedSceneTag matches the provided tag with the tags +// in the database and sets the ID field if one is found. +func MatchScrapedSceneTag(s *ScrapedSceneTag) error { + qb := NewTagQueryBuilder() + + tag, err := qb.FindByName(s.Name, nil, true) + + if err != nil { + return err + } + + if tag == nil { + // ignore - cannot match + return nil + } + + id := strconv.Itoa(tag.ID) + s.ID = &id + return nil +} diff --git a/pkg/scraper/scrapers.go b/pkg/scraper/scrapers.go index 64788bccc..e6cc65640 100644 --- a/pkg/scraper/scrapers.go +++ b/pkg/scraper/scrapers.go @@ -214,106 +214,30 @@ func (c Cache) ScrapePerformerURL(url string) (*models.ScrapedPerformer, error) return nil, nil } -func matchPerformer(p *models.ScrapedScenePerformer) error { - qb := models.NewPerformerQueryBuilder() - - performers, err := qb.FindByNames([]string{p.Name}, nil, true) - - if err != nil { - return err - } - - if len(performers) != 1 { - // ignore - cannot match - return nil - } - - id := strconv.Itoa(performers[0].ID) - p.ID = &id - return nil -} - -func matchStudio(s *models.ScrapedSceneStudio) error { - qb := models.NewStudioQueryBuilder() - - studio, err := qb.FindByName(s.Name, nil, true) - - if err != nil { - return err - } - - if studio == nil { - // ignore - cannot match - return nil - } - - id := strconv.Itoa(studio.ID) - s.ID = &id - return nil -} - -func matchMovie(m *models.ScrapedSceneMovie) error { - qb := models.NewMovieQueryBuilder() - - movies, err := qb.FindByNames([]string{m.Name}, nil, true) - - if err != nil { - return err - } - - if len(movies) != 1 { - // ignore - cannot match - return nil - } - - id := strconv.Itoa(movies[0].ID) - m.ID = &id - return nil -} - -func matchTag(s *models.ScrapedSceneTag) error { - qb := models.NewTagQueryBuilder() - - tag, err := qb.FindByName(s.Name, nil, true) - - if err != nil { - return err - } - - if tag == nil { - // ignore - cannot match - return nil - } - - id := strconv.Itoa(tag.ID) - s.ID = &id - return nil -} - func (c Cache) postScrapeScene(ret *models.ScrapedScene) error { for _, p := range ret.Performers { - err := matchPerformer(p) + err := models.MatchScrapedScenePerformer(p) if err != nil { return err } } for _, p := range ret.Movies { - err := matchMovie(p) + err := models.MatchScrapedSceneMovie(p) if err != nil { return err } } for _, t := range ret.Tags { - err := matchTag(t) + err := models.MatchScrapedSceneTag(t) if err != nil { return err } } if ret.Studio != nil { - err := matchStudio(ret.Studio) + err := models.MatchScrapedSceneStudio(ret.Studio) if err != nil { return err } diff --git a/pkg/scraper/stashbox/graphql/generated_client.go b/pkg/scraper/stashbox/graphql/generated_client.go new file mode 100644 index 000000000..4ea84ce63 --- /dev/null +++ b/pkg/scraper/stashbox/graphql/generated_client.go @@ -0,0 +1,559 @@ +// Code generated by github.com/Yamashou/gqlgenc, DO NOT EDIT. + +package graphql + +import ( + "context" + "net/http" + + "github.com/Yamashou/gqlgenc/client" +) + +type Client struct { + Client *client.Client +} + +func NewClient(cli *http.Client, baseURL string, options ...client.HTTPRequestOption) *Client { + return &Client{Client: client.NewClient(cli, baseURL, options...)} +} + +type Query struct { + FindPerformer *Performer "json:\"findPerformer\" graphql:\"findPerformer\"" + QueryPerformers QueryPerformersResultType "json:\"queryPerformers\" graphql:\"queryPerformers\"" + FindStudio *Studio "json:\"findStudio\" graphql:\"findStudio\"" + QueryStudios QueryStudiosResultType "json:\"queryStudios\" graphql:\"queryStudios\"" + FindTag *Tag "json:\"findTag\" graphql:\"findTag\"" + QueryTags QueryTagsResultType "json:\"queryTags\" graphql:\"queryTags\"" + FindScene *Scene "json:\"findScene\" graphql:\"findScene\"" + FindSceneByFingerprint []*Scene "json:\"findSceneByFingerprint\" graphql:\"findSceneByFingerprint\"" + FindScenesByFingerprints []*Scene "json:\"findScenesByFingerprints\" graphql:\"findScenesByFingerprints\"" + QueryScenes QueryScenesResultType "json:\"queryScenes\" graphql:\"queryScenes\"" + FindEdit *Edit "json:\"findEdit\" graphql:\"findEdit\"" + QueryEdits QueryEditsResultType "json:\"queryEdits\" graphql:\"queryEdits\"" + FindUser *User "json:\"findUser\" graphql:\"findUser\"" + QueryUsers QueryUsersResultType "json:\"queryUsers\" graphql:\"queryUsers\"" + Me *User "json:\"me\" graphql:\"me\"" + SearchPerformer []*Performer "json:\"searchPerformer\" graphql:\"searchPerformer\"" + SearchScene []*Scene "json:\"searchScene\" graphql:\"searchScene\"" + Version Version "json:\"version\" graphql:\"version\"" +} + +type Mutation struct { + SceneCreate *Scene "json:\"sceneCreate\" graphql:\"sceneCreate\"" + SceneUpdate *Scene "json:\"sceneUpdate\" graphql:\"sceneUpdate\"" + SceneDestroy bool "json:\"sceneDestroy\" graphql:\"sceneDestroy\"" + PerformerCreate *Performer "json:\"performerCreate\" graphql:\"performerCreate\"" + PerformerUpdate *Performer "json:\"performerUpdate\" graphql:\"performerUpdate\"" + PerformerDestroy bool "json:\"performerDestroy\" graphql:\"performerDestroy\"" + StudioCreate *Studio "json:\"studioCreate\" graphql:\"studioCreate\"" + StudioUpdate *Studio "json:\"studioUpdate\" graphql:\"studioUpdate\"" + StudioDestroy bool "json:\"studioDestroy\" graphql:\"studioDestroy\"" + TagCreate *Tag "json:\"tagCreate\" graphql:\"tagCreate\"" + TagUpdate *Tag "json:\"tagUpdate\" graphql:\"tagUpdate\"" + TagDestroy bool "json:\"tagDestroy\" graphql:\"tagDestroy\"" + UserCreate *User "json:\"userCreate\" graphql:\"userCreate\"" + UserUpdate *User "json:\"userUpdate\" graphql:\"userUpdate\"" + UserDestroy bool "json:\"userDestroy\" graphql:\"userDestroy\"" + ImageCreate *Image "json:\"imageCreate\" graphql:\"imageCreate\"" + ImageUpdate *Image "json:\"imageUpdate\" graphql:\"imageUpdate\"" + ImageDestroy bool "json:\"imageDestroy\" graphql:\"imageDestroy\"" + RegenerateAPIKey string "json:\"regenerateAPIKey\" graphql:\"regenerateAPIKey\"" + ChangePassword bool "json:\"changePassword\" graphql:\"changePassword\"" + SceneEdit Edit "json:\"sceneEdit\" graphql:\"sceneEdit\"" + PerformerEdit Edit "json:\"performerEdit\" graphql:\"performerEdit\"" + StudioEdit Edit "json:\"studioEdit\" graphql:\"studioEdit\"" + TagEdit Edit "json:\"tagEdit\" graphql:\"tagEdit\"" + EditVote Edit "json:\"editVote\" graphql:\"editVote\"" + EditComment Edit "json:\"editComment\" graphql:\"editComment\"" + ApplyEdit Edit "json:\"applyEdit\" graphql:\"applyEdit\"" + CancelEdit Edit "json:\"cancelEdit\" graphql:\"cancelEdit\"" + SubmitFingerprint bool "json:\"submitFingerprint\" graphql:\"submitFingerprint\"" +} +type URLFragment struct { + URL string "json:\"url\" graphql:\"url\"" + Type string "json:\"type\" graphql:\"type\"" +} +type ImageFragment struct { + ID string "json:\"id\" graphql:\"id\"" + URL string "json:\"url\" graphql:\"url\"" + Width *int "json:\"width\" graphql:\"width\"" + Height *int "json:\"height\" graphql:\"height\"" +} +type StudioFragment struct { + Name string "json:\"name\" graphql:\"name\"" + ID string "json:\"id\" graphql:\"id\"" + Urls []*URLFragment "json:\"urls\" graphql:\"urls\"" + Images []*ImageFragment "json:\"images\" graphql:\"images\"" +} +type TagFragment struct { + Name string "json:\"name\" graphql:\"name\"" + ID string "json:\"id\" graphql:\"id\"" +} +type FuzzyDateFragment struct { + Date string "json:\"date\" graphql:\"date\"" + Accuracy DateAccuracyEnum "json:\"accuracy\" graphql:\"accuracy\"" +} +type MeasurementsFragment struct { + BandSize *int "json:\"band_size\" graphql:\"band_size\"" + CupSize *string "json:\"cup_size\" graphql:\"cup_size\"" + Waist *int "json:\"waist\" graphql:\"waist\"" + Hip *int "json:\"hip\" graphql:\"hip\"" +} +type BodyModificationFragment struct { + Location string "json:\"location\" graphql:\"location\"" + Description *string "json:\"description\" graphql:\"description\"" +} +type PerformerFragment struct { + ID string "json:\"id\" graphql:\"id\"" + Name string "json:\"name\" graphql:\"name\"" + Disambiguation *string "json:\"disambiguation\" graphql:\"disambiguation\"" + Aliases []string "json:\"aliases\" graphql:\"aliases\"" + Gender *GenderEnum "json:\"gender\" graphql:\"gender\"" + Urls []*URLFragment "json:\"urls\" graphql:\"urls\"" + Images []*ImageFragment "json:\"images\" graphql:\"images\"" + Birthdate *FuzzyDateFragment "json:\"birthdate\" graphql:\"birthdate\"" + Ethnicity *EthnicityEnum "json:\"ethnicity\" graphql:\"ethnicity\"" + Country *string "json:\"country\" graphql:\"country\"" + EyeColor *EyeColorEnum "json:\"eye_color\" graphql:\"eye_color\"" + HairColor *HairColorEnum "json:\"hair_color\" graphql:\"hair_color\"" + Height *int "json:\"height\" graphql:\"height\"" + Measurements MeasurementsFragment "json:\"measurements\" graphql:\"measurements\"" + BreastType *BreastTypeEnum "json:\"breast_type\" graphql:\"breast_type\"" + CareerStartYear *int "json:\"career_start_year\" graphql:\"career_start_year\"" + CareerEndYear *int "json:\"career_end_year\" graphql:\"career_end_year\"" + Tattoos []*BodyModificationFragment "json:\"tattoos\" graphql:\"tattoos\"" + Piercings []*BodyModificationFragment "json:\"piercings\" graphql:\"piercings\"" +} +type PerformerAppearanceFragment struct { + As *string "json:\"as\" graphql:\"as\"" + Performer PerformerFragment "json:\"performer\" graphql:\"performer\"" +} +type FingerprintFragment struct { + Algorithm FingerprintAlgorithm "json:\"algorithm\" graphql:\"algorithm\"" + Hash string "json:\"hash\" graphql:\"hash\"" + Duration int "json:\"duration\" graphql:\"duration\"" +} +type SceneFragment struct { + ID string "json:\"id\" graphql:\"id\"" + Title *string "json:\"title\" graphql:\"title\"" + Details *string "json:\"details\" graphql:\"details\"" + Duration *int "json:\"duration\" graphql:\"duration\"" + Date *string "json:\"date\" graphql:\"date\"" + Urls []*URLFragment "json:\"urls\" graphql:\"urls\"" + Images []*ImageFragment "json:\"images\" graphql:\"images\"" + Studio *StudioFragment "json:\"studio\" graphql:\"studio\"" + Tags []*TagFragment "json:\"tags\" graphql:\"tags\"" + Performers []*PerformerAppearanceFragment "json:\"performers\" graphql:\"performers\"" + Fingerprints []*FingerprintFragment "json:\"fingerprints\" graphql:\"fingerprints\"" +} +type FindSceneByFingerprint struct { + FindSceneByFingerprint []*SceneFragment "json:\"findSceneByFingerprint\" graphql:\"findSceneByFingerprint\"" +} +type FindScenesByFingerprints struct { + FindScenesByFingerprints []*SceneFragment "json:\"findScenesByFingerprints\" graphql:\"findScenesByFingerprints\"" +} +type SearchScene struct { + SearchScene []*SceneFragment "json:\"searchScene\" graphql:\"searchScene\"" +} +type SubmitFingerprintPayload struct { + SubmitFingerprint bool "json:\"submitFingerprint\" graphql:\"submitFingerprint\"" +} + +const FindSceneByFingerprintQuery = `query FindSceneByFingerprint ($fingerprint: FingerprintQueryInput!) { + findSceneByFingerprint(fingerprint: $fingerprint) { + ... SceneFragment + } +} +fragment SceneFragment on Scene { + id + title + details + duration + date + urls { + ... URLFragment + } + images { + ... ImageFragment + } + studio { + ... StudioFragment + } + tags { + ... TagFragment + } + performers { + ... PerformerAppearanceFragment + } + fingerprints { + ... FingerprintFragment + } +} +fragment TagFragment on Tag { + name + id +} +fragment PerformerFragment on Performer { + id + name + disambiguation + aliases + gender + urls { + ... URLFragment + } + images { + ... ImageFragment + } + birthdate { + ... FuzzyDateFragment + } + ethnicity + country + eye_color + hair_color + height + measurements { + ... MeasurementsFragment + } + breast_type + career_start_year + career_end_year + tattoos { + ... BodyModificationFragment + } + piercings { + ... BodyModificationFragment + } +} +fragment BodyModificationFragment on BodyModification { + location + description +} +fragment MeasurementsFragment on Measurements { + band_size + cup_size + waist + hip +} +fragment FingerprintFragment on Fingerprint { + algorithm + hash + duration +} +fragment URLFragment on URL { + url + type +} +fragment ImageFragment on Image { + id + url + width + height +} +fragment StudioFragment on Studio { + name + id + urls { + ... URLFragment + } + images { + ... ImageFragment + } +} +fragment PerformerAppearanceFragment on PerformerAppearance { + as + performer { + ... PerformerFragment + } +} +fragment FuzzyDateFragment on FuzzyDate { + date + accuracy +} +` + +func (c *Client) FindSceneByFingerprint(ctx context.Context, fingerprint FingerprintQueryInput, httpRequestOptions ...client.HTTPRequestOption) (*FindSceneByFingerprint, error) { + vars := map[string]interface{}{ + "fingerprint": fingerprint, + } + + var res FindSceneByFingerprint + if err := c.Client.Post(ctx, FindSceneByFingerprintQuery, &res, vars, httpRequestOptions...); err != nil { + return nil, err + } + + return &res, nil +} + +const FindScenesByFingerprintsQuery = `query FindScenesByFingerprints ($fingerprints: [String!]!) { + findScenesByFingerprints(fingerprints: $fingerprints) { + ... SceneFragment + } +} +fragment ImageFragment on Image { + id + url + width + height +} +fragment StudioFragment on Studio { + name + id + urls { + ... URLFragment + } + images { + ... ImageFragment + } +} +fragment TagFragment on Tag { + name + id +} +fragment MeasurementsFragment on Measurements { + band_size + cup_size + waist + hip +} +fragment BodyModificationFragment on BodyModification { + location + description +} +fragment SceneFragment on Scene { + id + title + details + duration + date + urls { + ... URLFragment + } + images { + ... ImageFragment + } + studio { + ... StudioFragment + } + tags { + ... TagFragment + } + performers { + ... PerformerAppearanceFragment + } + fingerprints { + ... FingerprintFragment + } +} +fragment PerformerAppearanceFragment on PerformerAppearance { + as + performer { + ... PerformerFragment + } +} +fragment PerformerFragment on Performer { + id + name + disambiguation + aliases + gender + urls { + ... URLFragment + } + images { + ... ImageFragment + } + birthdate { + ... FuzzyDateFragment + } + ethnicity + country + eye_color + hair_color + height + measurements { + ... MeasurementsFragment + } + breast_type + career_start_year + career_end_year + tattoos { + ... BodyModificationFragment + } + piercings { + ... BodyModificationFragment + } +} +fragment FuzzyDateFragment on FuzzyDate { + date + accuracy +} +fragment FingerprintFragment on Fingerprint { + algorithm + hash + duration +} +fragment URLFragment on URL { + url + type +} +` + +func (c *Client) FindScenesByFingerprints(ctx context.Context, fingerprints []string, httpRequestOptions ...client.HTTPRequestOption) (*FindScenesByFingerprints, error) { + vars := map[string]interface{}{ + "fingerprints": fingerprints, + } + + var res FindScenesByFingerprints + if err := c.Client.Post(ctx, FindScenesByFingerprintsQuery, &res, vars, httpRequestOptions...); err != nil { + return nil, err + } + + return &res, nil +} + +const SearchSceneQuery = `query SearchScene ($term: String!) { + searchScene(term: $term) { + ... SceneFragment + } +} +fragment FuzzyDateFragment on FuzzyDate { + date + accuracy +} +fragment MeasurementsFragment on Measurements { + band_size + cup_size + waist + hip +} +fragment FingerprintFragment on Fingerprint { + algorithm + hash + duration +} +fragment SceneFragment on Scene { + id + title + details + duration + date + urls { + ... URLFragment + } + images { + ... ImageFragment + } + studio { + ... StudioFragment + } + tags { + ... TagFragment + } + performers { + ... PerformerAppearanceFragment + } + fingerprints { + ... FingerprintFragment + } +} +fragment TagFragment on Tag { + name + id +} +fragment PerformerAppearanceFragment on PerformerAppearance { + as + performer { + ... PerformerFragment + } +} +fragment PerformerFragment on Performer { + id + name + disambiguation + aliases + gender + urls { + ... URLFragment + } + images { + ... ImageFragment + } + birthdate { + ... FuzzyDateFragment + } + ethnicity + country + eye_color + hair_color + height + measurements { + ... MeasurementsFragment + } + breast_type + career_start_year + career_end_year + tattoos { + ... BodyModificationFragment + } + piercings { + ... BodyModificationFragment + } +} +fragment URLFragment on URL { + url + type +} +fragment ImageFragment on Image { + id + url + width + height +} +fragment StudioFragment on Studio { + name + id + urls { + ... URLFragment + } + images { + ... ImageFragment + } +} +fragment BodyModificationFragment on BodyModification { + location + description +} +` + +func (c *Client) SearchScene(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchScene, error) { + vars := map[string]interface{}{ + "term": term, + } + + var res SearchScene + if err := c.Client.Post(ctx, SearchSceneQuery, &res, vars, httpRequestOptions...); err != nil { + return nil, err + } + + return &res, nil +} + +const SubmitFingerprintQuery = `mutation SubmitFingerprint ($input: FingerprintSubmission!) { + submitFingerprint(input: $input) +} +` + +func (c *Client) SubmitFingerprint(ctx context.Context, input FingerprintSubmission, httpRequestOptions ...client.HTTPRequestOption) (*SubmitFingerprintPayload, error) { + vars := map[string]interface{}{ + "input": input, + } + + var res SubmitFingerprintPayload + if err := c.Client.Post(ctx, SubmitFingerprintQuery, &res, vars, httpRequestOptions...); err != nil { + return nil, err + } + + return &res, nil +} diff --git a/pkg/scraper/stashbox/graphql/generated_models.go b/pkg/scraper/stashbox/graphql/generated_models.go new file mode 100644 index 000000000..a8715092b --- /dev/null +++ b/pkg/scraper/stashbox/graphql/generated_models.go @@ -0,0 +1,1427 @@ +// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. + +package graphql + +import ( + "fmt" + "io" + "strconv" + "time" +) + +type EditDetails interface { + IsEditDetails() +} + +type EditTarget interface { + IsEditTarget() +} + +type ApplyEditInput struct { + ID string `json:"id"` +} + +type BodyModification struct { + Location string `json:"location"` + Description *string `json:"description"` +} + +type BodyModificationCriterionInput struct { + Location *string `json:"location"` + Description *string `json:"description"` + Modifier CriterionModifier `json:"modifier"` +} + +type BodyModificationInput struct { + Location string `json:"location"` + Description *string `json:"description"` +} + +type BreastTypeCriterionInput struct { + Value *BreastTypeEnum `json:"value"` + Modifier CriterionModifier `json:"modifier"` +} + +type CancelEditInput struct { + ID string `json:"id"` +} + +type DateCriterionInput struct { + Value string `json:"value"` + Modifier CriterionModifier `json:"modifier"` +} + +type Edit struct { + ID string `json:"id"` + User *User `json:"user"` + // Object being edited - null if creating a new object + Target EditTarget `json:"target"` + TargetType TargetTypeEnum `json:"target_type"` + // Objects to merge with the target. Only applicable to merges + MergeSources []EditTarget `json:"merge_sources"` + Operation OperationEnum `json:"operation"` + Details EditDetails `json:"details"` + Comments []*EditComment `json:"comments"` + Votes []*VoteComment `json:"votes"` + // = Accepted - Rejected + VoteCount int `json:"vote_count"` + Status VoteStatusEnum `json:"status"` + Applied bool `json:"applied"` + Created time.Time `json:"created"` +} + +type EditComment struct { + User *User `json:"user"` + Date time.Time `json:"date"` + Comment string `json:"comment"` +} + +type EditCommentInput struct { + ID string `json:"id"` + Comment string `json:"comment"` +} + +type EditFilterType struct { + // Filter by user id + UserID *string `json:"user_id"` + // Filter by status + Status *VoteStatusEnum `json:"status"` + // Filter by operation + Operation *OperationEnum `json:"operation"` + // Filter by vote count + VoteCount *IntCriterionInput `json:"vote_count"` + // Filter by applied status + Applied *bool `json:"applied"` + // Filter by target type + TargetType *TargetTypeEnum `json:"target_type"` + // Filter by target id + TargetID *string `json:"target_id"` +} + +type EditInput struct { + // Not required for create type + ID *string `json:"id"` + Operation OperationEnum `json:"operation"` + // Required for amending an existing edit + EditID *string `json:"edit_id"` + // Only required for merge type + MergeSourceIds []string `json:"merge_source_ids"` + Comment *string `json:"comment"` +} + +type EditVoteInput struct { + ID string `json:"id"` + Comment *string `json:"comment"` + Type VoteTypeEnum `json:"type"` +} + +type EthnicityCriterionInput struct { + Value *EthnicityEnum `json:"value"` + Modifier CriterionModifier `json:"modifier"` +} + +type EyeColorCriterionInput struct { + Value *EyeColorEnum `json:"value"` + Modifier CriterionModifier `json:"modifier"` +} + +type Fingerprint struct { + Hash string `json:"hash"` + Algorithm FingerprintAlgorithm `json:"algorithm"` + Duration int `json:"duration"` +} + +type FingerprintInput struct { + Hash string `json:"hash"` + Algorithm FingerprintAlgorithm `json:"algorithm"` + Duration int `json:"duration"` +} + +type FingerprintQueryInput struct { + Hash string `json:"hash"` + Algorithm FingerprintAlgorithm `json:"algorithm"` +} + +type FingerprintSubmission struct { + SceneID string `json:"scene_id"` + Fingerprint *FingerprintInput `json:"fingerprint"` +} + +type FuzzyDate struct { + Date string `json:"date"` + Accuracy DateAccuracyEnum `json:"accuracy"` +} + +type FuzzyDateInput struct { + Date string `json:"date"` + Accuracy DateAccuracyEnum `json:"accuracy"` +} + +type HairColorCriterionInput struct { + Value *HairColorEnum `json:"value"` + Modifier CriterionModifier `json:"modifier"` +} + +type IDCriterionInput struct { + Value []string `json:"value"` + Modifier CriterionModifier `json:"modifier"` +} + +type Image struct { + ID string `json:"id"` + URL string `json:"url"` + Width *int `json:"width"` + Height *int `json:"height"` +} + +type ImageCreateInput struct { + URL string `json:"url"` +} + +type ImageDestroyInput struct { + ID string `json:"id"` +} + +type ImageUpdateInput struct { + ID string `json:"id"` + URL string `json:"url"` +} + +type IntCriterionInput struct { + Value int `json:"value"` + Modifier CriterionModifier `json:"modifier"` +} + +type Measurements struct { + CupSize *string `json:"cup_size"` + BandSize *int `json:"band_size"` + Waist *int `json:"waist"` + Hip *int `json:"hip"` +} + +type MeasurementsInput struct { + CupSize *string `json:"cup_size"` + BandSize *int `json:"band_size"` + Waist *int `json:"waist"` + Hip *int `json:"hip"` +} + +type MultiIDCriterionInput struct { + Value []string `json:"value"` + Modifier CriterionModifier `json:"modifier"` +} + +type Performer struct { + ID string `json:"id"` + Name string `json:"name"` + Disambiguation *string `json:"disambiguation"` + Aliases []string `json:"aliases"` + Gender *GenderEnum `json:"gender"` + Urls []*URL `json:"urls"` + Birthdate *FuzzyDate `json:"birthdate"` + Age *int `json:"age"` + Ethnicity *EthnicityEnum `json:"ethnicity"` + Country *string `json:"country"` + EyeColor *EyeColorEnum `json:"eye_color"` + HairColor *HairColorEnum `json:"hair_color"` + // Height in cm + Height *int `json:"height"` + Measurements *Measurements `json:"measurements"` + BreastType *BreastTypeEnum `json:"breast_type"` + CareerStartYear *int `json:"career_start_year"` + CareerEndYear *int `json:"career_end_year"` + Tattoos []*BodyModification `json:"tattoos"` + Piercings []*BodyModification `json:"piercings"` + Images []*Image `json:"images"` + Deleted bool `json:"deleted"` +} + +func (Performer) IsEditTarget() {} + +type PerformerAppearance struct { + Performer *Performer `json:"performer"` + // Performing as alias + As *string `json:"as"` +} + +type PerformerAppearanceInput struct { + PerformerID string `json:"performer_id"` + // Performing as alias + As *string `json:"as"` +} + +type PerformerCreateInput struct { + Name string `json:"name"` + Disambiguation *string `json:"disambiguation"` + Aliases []string `json:"aliases"` + Gender *GenderEnum `json:"gender"` + Urls []*URLInput `json:"urls"` + Birthdate *FuzzyDateInput `json:"birthdate"` + Ethnicity *EthnicityEnum `json:"ethnicity"` + Country *string `json:"country"` + EyeColor *EyeColorEnum `json:"eye_color"` + HairColor *HairColorEnum `json:"hair_color"` + Height *int `json:"height"` + Measurements *MeasurementsInput `json:"measurements"` + BreastType *BreastTypeEnum `json:"breast_type"` + CareerStartYear *int `json:"career_start_year"` + CareerEndYear *int `json:"career_end_year"` + Tattoos []*BodyModificationInput `json:"tattoos"` + Piercings []*BodyModificationInput `json:"piercings"` + ImageIds []string `json:"image_ids"` +} + +type PerformerDestroyInput struct { + ID string `json:"id"` +} + +type PerformerEdit struct { + Name *string `json:"name"` + Disambiguation *string `json:"disambiguation"` + AddedAliases []string `json:"added_aliases"` + RemovedAliases []string `json:"removed_aliases"` + Gender *GenderEnum `json:"gender"` + AddedUrls []*URL `json:"added_urls"` + RemovedUrls []*URL `json:"removed_urls"` + Birthdate *FuzzyDate `json:"birthdate"` + Ethnicity *EthnicityEnum `json:"ethnicity"` + Country *string `json:"country"` + EyeColor *EyeColorEnum `json:"eye_color"` + HairColor *HairColorEnum `json:"hair_color"` + // Height in cm + Height *int `json:"height"` + Measurements *Measurements `json:"measurements"` + BreastType *BreastTypeEnum `json:"breast_type"` + CareerStartYear *int `json:"career_start_year"` + CareerEndYear *int `json:"career_end_year"` + AddedTattoos []*BodyModification `json:"added_tattoos"` + RemovedTattoos []*BodyModification `json:"removed_tattoos"` + AddedPiercings []*BodyModification `json:"added_piercings"` + RemovedPiercings []*BodyModification `json:"removed_piercings"` + AddedImages []*Image `json:"added_images"` + RemovedImages []*Image `json:"removed_images"` +} + +func (PerformerEdit) IsEditDetails() {} + +type PerformerEditDetailsInput struct { + Name *string `json:"name"` + Disambiguation *string `json:"disambiguation"` + Aliases []string `json:"aliases"` + Gender *GenderEnum `json:"gender"` + Urls []*URLInput `json:"urls"` + Birthdate *FuzzyDateInput `json:"birthdate"` + Ethnicity *EthnicityEnum `json:"ethnicity"` + Country *string `json:"country"` + EyeColor *EyeColorEnum `json:"eye_color"` + HairColor *HairColorEnum `json:"hair_color"` + Height *int `json:"height"` + Measurements *MeasurementsInput `json:"measurements"` + BreastType *BreastTypeEnum `json:"breast_type"` + CareerStartYear *int `json:"career_start_year"` + CareerEndYear *int `json:"career_end_year"` + Tattoos []*BodyModificationInput `json:"tattoos"` + Piercings []*BodyModificationInput `json:"piercings"` + ImageIds []string `json:"image_ids"` +} + +type PerformerEditInput struct { + Edit *EditInput `json:"edit"` + // Not required for destroy type + Details *PerformerEditDetailsInput `json:"details"` +} + +type PerformerFilterType struct { + // Searches name and aliases - assumes like query unless quoted + Names *string `json:"names"` + // Searches name only - assumes like query unless quoted + Name *string `json:"name"` + // Search aliases only - assumes like query unless quoted + Alias *string `json:"alias"` + Disambiguation *StringCriterionInput `json:"disambiguation"` + Gender *GenderEnum `json:"gender"` + // Filter to search urls - assumes like query unless quoted + URL *string `json:"url"` + Birthdate *DateCriterionInput `json:"birthdate"` + BirthYear *IntCriterionInput `json:"birth_year"` + Age *IntCriterionInput `json:"age"` + Ethnicity *EthnicityCriterionInput `json:"ethnicity"` + Country *StringCriterionInput `json:"country"` + EyeColor *EyeColorCriterionInput `json:"eye_color"` + HairColor *HairColorCriterionInput `json:"hair_color"` + Height *IntCriterionInput `json:"height"` + CupSize *StringCriterionInput `json:"cup_size"` + BandSize *IntCriterionInput `json:"band_size"` + WaistSize *IntCriterionInput `json:"waist_size"` + HipSize *IntCriterionInput `json:"hip_size"` + BreastType *BreastTypeCriterionInput `json:"breast_type"` + CareerStartYear *IntCriterionInput `json:"career_start_year"` + CareerEndYear *IntCriterionInput `json:"career_end_year"` + Tattoos *BodyModificationCriterionInput `json:"tattoos"` + Piercings *BodyModificationCriterionInput `json:"piercings"` +} + +type PerformerUpdateInput struct { + ID string `json:"id"` + Name *string `json:"name"` + Disambiguation *string `json:"disambiguation"` + Aliases []string `json:"aliases"` + Gender *GenderEnum `json:"gender"` + Urls []*URLInput `json:"urls"` + Birthdate *FuzzyDateInput `json:"birthdate"` + Ethnicity *EthnicityEnum `json:"ethnicity"` + Country *string `json:"country"` + EyeColor *EyeColorEnum `json:"eye_color"` + HairColor *HairColorEnum `json:"hair_color"` + Height *int `json:"height"` + Measurements *MeasurementsInput `json:"measurements"` + BreastType *BreastTypeEnum `json:"breast_type"` + CareerStartYear *int `json:"career_start_year"` + CareerEndYear *int `json:"career_end_year"` + Tattoos []*BodyModificationInput `json:"tattoos"` + Piercings []*BodyModificationInput `json:"piercings"` + ImageIds []string `json:"image_ids"` +} + +type QueryEditsResultType struct { + Count int `json:"count"` + Edits []*Edit `json:"edits"` +} + +type QueryPerformersResultType struct { + Count int `json:"count"` + Performers []*Performer `json:"performers"` +} + +type QueryScenesResultType struct { + Count int `json:"count"` + Scenes []*Scene `json:"scenes"` +} + +type QuerySpec struct { + Page *int `json:"page"` + PerPage *int `json:"per_page"` + Sort *string `json:"sort"` + Direction *SortDirectionEnum `json:"direction"` +} + +type QueryStudiosResultType struct { + Count int `json:"count"` + Studios []*Studio `json:"studios"` +} + +type QueryTagsResultType struct { + Count int `json:"count"` + Tags []*Tag `json:"tags"` +} + +type QueryUsersResultType struct { + Count int `json:"count"` + Users []*User `json:"users"` +} + +type RoleCriterionInput struct { + Value []RoleEnum `json:"value"` + Modifier CriterionModifier `json:"modifier"` +} + +type Scene struct { + ID string `json:"id"` + Title *string `json:"title"` + Details *string `json:"details"` + Date *string `json:"date"` + Urls []*URL `json:"urls"` + Studio *Studio `json:"studio"` + Tags []*Tag `json:"tags"` + Images []*Image `json:"images"` + Performers []*PerformerAppearance `json:"performers"` + Fingerprints []*Fingerprint `json:"fingerprints"` + Duration *int `json:"duration"` + Director *string `json:"director"` + Deleted bool `json:"deleted"` +} + +func (Scene) IsEditTarget() {} + +type SceneCreateInput struct { + Title *string `json:"title"` + Details *string `json:"details"` + Urls []*URLInput `json:"urls"` + Date *string `json:"date"` + StudioID *string `json:"studio_id"` + Performers []*PerformerAppearanceInput `json:"performers"` + TagIds []string `json:"tag_ids"` + ImageIds []string `json:"image_ids"` + Fingerprints []*FingerprintInput `json:"fingerprints"` + Duration *int `json:"duration"` + Director *string `json:"director"` +} + +type SceneDestroyInput struct { + ID string `json:"id"` +} + +type SceneEdit struct { + Title *string `json:"title"` + Details *string `json:"details"` + AddedUrls []*URL `json:"added_urls"` + RemovedUrls []*URL `json:"removed_urls"` + Date *string `json:"date"` + StudioID *string `json:"studio_id"` + // Added or modified performer appearance entries + AddedPerformers []*PerformerAppearance `json:"added_performers"` + RemovedPerformers []*PerformerAppearance `json:"removed_performers"` + AddedTags []*Tag `json:"added_tags"` + RemovedTags []*Tag `json:"removed_tags"` + AddedImages []*Image `json:"added_images"` + RemovedImages []*Image `json:"removed_images"` + AddedFingerprints []*Fingerprint `json:"added_fingerprints"` + RemovedFingerprints []*Fingerprint `json:"removed_fingerprints"` + Duration *int `json:"duration"` + Director *string `json:"director"` +} + +func (SceneEdit) IsEditDetails() {} + +type SceneEditDetailsInput struct { + Title *string `json:"title"` + Details *string `json:"details"` + Urls []*URLInput `json:"urls"` + Date *string `json:"date"` + StudioID *string `json:"studio_id"` + Performers []*PerformerAppearanceInput `json:"performers"` + TagIds []string `json:"tag_ids"` + ImageIds []string `json:"image_ids"` + Fingerprints []*FingerprintInput `json:"fingerprints"` + Duration *int `json:"duration"` + Director *string `json:"director"` +} + +type SceneEditInput struct { + Edit *EditInput `json:"edit"` + // Not required for destroy type + Details *SceneEditDetailsInput `json:"details"` + Duration *int `json:"duration"` +} + +type SceneFilterType struct { + // Filter to search title and details - assumes like query unless quoted + Text *string `json:"text"` + // Filter to search title - assumes like query unless quoted + Title *string `json:"title"` + // Filter to search urls - assumes like query unless quoted + URL *string `json:"url"` + // Filter by date + Date *DateCriterionInput `json:"date"` + // Filter to only include scenes with this studio + Studios *MultiIDCriterionInput `json:"studios"` + // Filter to only include scenes with these tags + Tags *MultiIDCriterionInput `json:"tags"` + // Filter to only include scenes with these performers + Performers *MultiIDCriterionInput `json:"performers"` + // Filter to include scenes with performer appearing as alias + Alias *StringCriterionInput `json:"alias"` +} + +type SceneUpdateInput struct { + ID string `json:"id"` + Title *string `json:"title"` + Details *string `json:"details"` + Urls []*URLInput `json:"urls"` + Date *string `json:"date"` + StudioID *string `json:"studio_id"` + Performers []*PerformerAppearanceInput `json:"performers"` + TagIds []string `json:"tag_ids"` + ImageIds []string `json:"image_ids"` + Fingerprints []*FingerprintInput `json:"fingerprints"` + Duration *int `json:"duration"` + Director *string `json:"director"` +} + +type StringCriterionInput struct { + Value string `json:"value"` + Modifier CriterionModifier `json:"modifier"` +} + +type Studio struct { + ID string `json:"id"` + Name string `json:"name"` + Urls []*URL `json:"urls"` + Parent *Studio `json:"parent"` + ChildStudios []*Studio `json:"child_studios"` + Images []*Image `json:"images"` + Deleted bool `json:"deleted"` +} + +func (Studio) IsEditTarget() {} + +type StudioCreateInput struct { + Name string `json:"name"` + Urls []*URLInput `json:"urls"` + ParentID *string `json:"parent_id"` + ChildStudioIds []string `json:"child_studio_ids"` + ImageIds []string `json:"image_ids"` +} + +type StudioDestroyInput struct { + ID string `json:"id"` +} + +type StudioEdit struct { + Name *string `json:"name"` + // Added and modified URLs + AddedUrls []*URL `json:"added_urls"` + RemovedUrls []*URL `json:"removed_urls"` + Parent *Studio `json:"parent"` + AddedChildStudios []*Studio `json:"added_child_studios"` + RemovedChildStudios []*Studio `json:"removed_child_studios"` + AddedImages []*Image `json:"added_images"` + RemovedImages []*Image `json:"removed_images"` +} + +func (StudioEdit) IsEditDetails() {} + +type StudioEditDetailsInput struct { + Name *string `json:"name"` + Urls []*URLInput `json:"urls"` + ParentID *string `json:"parent_id"` + ChildStudioIds []string `json:"child_studio_ids"` + ImageIds []string `json:"image_ids"` +} + +type StudioEditInput struct { + Edit *EditInput `json:"edit"` + // Not required for destroy type + Details *StudioEditDetailsInput `json:"details"` +} + +type StudioFilterType struct { + // Filter to search name - assumes like query unless quoted + Name *string `json:"name"` + // Filter to search url - assumes like query unless quoted + URL *string `json:"url"` + Parent *IDCriterionInput `json:"parent"` +} + +type StudioUpdateInput struct { + ID string `json:"id"` + Name *string `json:"name"` + Urls []*URLInput `json:"urls"` + ParentID *string `json:"parent_id"` + ChildStudioIds []string `json:"child_studio_ids"` + ImageIds []string `json:"image_ids"` +} + +type Tag struct { + ID string `json:"id"` + Name string `json:"name"` + Description *string `json:"description"` + Aliases []string `json:"aliases"` + Deleted bool `json:"deleted"` + Edits []*Edit `json:"edits"` +} + +func (Tag) IsEditTarget() {} + +type TagCreateInput struct { + Name string `json:"name"` + Description *string `json:"description"` + Aliases []string `json:"aliases"` +} + +type TagDestroyInput struct { + ID string `json:"id"` +} + +type TagEdit struct { + Name *string `json:"name"` + Description *string `json:"description"` + AddedAliases []string `json:"added_aliases"` + RemovedAliases []string `json:"removed_aliases"` +} + +func (TagEdit) IsEditDetails() {} + +type TagEditDetailsInput struct { + Name *string `json:"name"` + Description *string `json:"description"` + Aliases []string `json:"aliases"` +} + +type TagEditInput struct { + Edit *EditInput `json:"edit"` + // Not required for destroy type + Details *TagEditDetailsInput `json:"details"` +} + +type TagFilterType struct { + // Filter to search name, aliases and description - assumes like query unless quoted + Text *string `json:"text"` + // Searches name and aliases - assumes like query unless quoted + Names *string `json:"names"` + // Filter to search name - assumes like query unless quoted + Name *string `json:"name"` +} + +type TagUpdateInput struct { + ID string `json:"id"` + Name *string `json:"name"` + Description *string `json:"description"` + Aliases []string `json:"aliases"` +} + +type URL struct { + URL string `json:"url"` + Type string `json:"type"` +} + +type URLInput struct { + URL string `json:"url"` + Type string `json:"type"` +} + +type User struct { + ID string `json:"id"` + Name string `json:"name"` + // Should not be visible to other users + Roles []RoleEnum `json:"roles"` + // Should not be visible to other users + Email *string `json:"email"` + // Should not be visible to other users + APIKey *string `json:"api_key"` + SuccessfulEdits int `json:"successful_edits"` + UnsuccessfulEdits int `json:"unsuccessful_edits"` + SuccessfulVotes int `json:"successful_votes"` + // Votes on unsuccessful edits + UnsuccessfulVotes int `json:"unsuccessful_votes"` + // Calls to the API from this user over a configurable time period + APICalls int `json:"api_calls"` +} + +type UserChangePasswordInput struct { + // Password in plain text + ExistingPassword string `json:"existing_password"` + NewPassword string `json:"new_password"` +} + +type UserCreateInput struct { + Name string `json:"name"` + // Password in plain text + Password string `json:"password"` + Roles []RoleEnum `json:"roles"` + Email string `json:"email"` +} + +type UserDestroyInput struct { + ID string `json:"id"` +} + +type UserFilterType struct { + // Filter to search user name - assumes like query unless quoted + Name *string `json:"name"` + // Filter to search email - assumes like query unless quoted + Email *string `json:"email"` + // Filter by roles + Roles *RoleCriterionInput `json:"roles"` + // Filter by api key + APIKey *string `json:"apiKey"` + // Filter by successful edits + SuccessfulEdits *IntCriterionInput `json:"successful_edits"` + // Filter by unsuccessful edits + UnsuccessfulEdits *IntCriterionInput `json:"unsuccessful_edits"` + // Filter by votes on successful edits + SuccessfulVotes *IntCriterionInput `json:"successful_votes"` + // Filter by votes on unsuccessful edits + UnsuccessfulVotes *IntCriterionInput `json:"unsuccessful_votes"` + // Filter by number of API calls + APICalls *IntCriterionInput `json:"api_calls"` +} + +type UserUpdateInput struct { + ID string `json:"id"` + Name *string `json:"name"` + // Password in plain text + Password *string `json:"password"` + Roles []RoleEnum `json:"roles"` + Email *string `json:"email"` +} + +type Version struct { + Hash string `json:"hash"` + BuildTime string `json:"build_time"` + Version string `json:"version"` +} + +type VoteComment struct { + User *User `json:"user"` + Date *string `json:"date"` + Comment *string `json:"comment"` + Type *VoteTypeEnum `json:"type"` +} + +type BreastTypeEnum string + +const ( + BreastTypeEnumNatural BreastTypeEnum = "NATURAL" + BreastTypeEnumFake BreastTypeEnum = "FAKE" + BreastTypeEnumNa BreastTypeEnum = "NA" +) + +var AllBreastTypeEnum = []BreastTypeEnum{ + BreastTypeEnumNatural, + BreastTypeEnumFake, + BreastTypeEnumNa, +} + +func (e BreastTypeEnum) IsValid() bool { + switch e { + case BreastTypeEnumNatural, BreastTypeEnumFake, BreastTypeEnumNa: + return true + } + return false +} + +func (e BreastTypeEnum) String() string { + return string(e) +} + +func (e *BreastTypeEnum) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = BreastTypeEnum(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid BreastTypeEnum", str) + } + return nil +} + +func (e BreastTypeEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type CriterionModifier string + +const ( + // = + CriterionModifierEquals CriterionModifier = "EQUALS" + // != + CriterionModifierNotEquals CriterionModifier = "NOT_EQUALS" + // > + CriterionModifierGreaterThan CriterionModifier = "GREATER_THAN" + // < + CriterionModifierLessThan CriterionModifier = "LESS_THAN" + // IS NULL + CriterionModifierIsNull CriterionModifier = "IS_NULL" + // IS NOT NULL + CriterionModifierNotNull CriterionModifier = "NOT_NULL" + // INCLUDES ALL + CriterionModifierIncludesAll CriterionModifier = "INCLUDES_ALL" + CriterionModifierIncludes CriterionModifier = "INCLUDES" + CriterionModifierExcludes CriterionModifier = "EXCLUDES" +) + +var AllCriterionModifier = []CriterionModifier{ + CriterionModifierEquals, + CriterionModifierNotEquals, + CriterionModifierGreaterThan, + CriterionModifierLessThan, + CriterionModifierIsNull, + CriterionModifierNotNull, + CriterionModifierIncludesAll, + CriterionModifierIncludes, + CriterionModifierExcludes, +} + +func (e CriterionModifier) IsValid() bool { + switch e { + case CriterionModifierEquals, CriterionModifierNotEquals, CriterionModifierGreaterThan, CriterionModifierLessThan, CriterionModifierIsNull, CriterionModifierNotNull, CriterionModifierIncludesAll, CriterionModifierIncludes, CriterionModifierExcludes: + return true + } + return false +} + +func (e CriterionModifier) String() string { + return string(e) +} + +func (e *CriterionModifier) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = CriterionModifier(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid CriterionModifier", str) + } + return nil +} + +func (e CriterionModifier) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type DateAccuracyEnum string + +const ( + DateAccuracyEnumYear DateAccuracyEnum = "YEAR" + DateAccuracyEnumMonth DateAccuracyEnum = "MONTH" + DateAccuracyEnumDay DateAccuracyEnum = "DAY" +) + +var AllDateAccuracyEnum = []DateAccuracyEnum{ + DateAccuracyEnumYear, + DateAccuracyEnumMonth, + DateAccuracyEnumDay, +} + +func (e DateAccuracyEnum) IsValid() bool { + switch e { + case DateAccuracyEnumYear, DateAccuracyEnumMonth, DateAccuracyEnumDay: + return true + } + return false +} + +func (e DateAccuracyEnum) String() string { + return string(e) +} + +func (e *DateAccuracyEnum) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = DateAccuracyEnum(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid DateAccuracyEnum", str) + } + return nil +} + +func (e DateAccuracyEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type EthnicityEnum string + +const ( + EthnicityEnumCaucasian EthnicityEnum = "CAUCASIAN" + EthnicityEnumBlack EthnicityEnum = "BLACK" + EthnicityEnumAsian EthnicityEnum = "ASIAN" + EthnicityEnumIndian EthnicityEnum = "INDIAN" + EthnicityEnumLatin EthnicityEnum = "LATIN" + EthnicityEnumMiddleEastern EthnicityEnum = "MIDDLE_EASTERN" + EthnicityEnumMixed EthnicityEnum = "MIXED" + EthnicityEnumOther EthnicityEnum = "OTHER" +) + +var AllEthnicityEnum = []EthnicityEnum{ + EthnicityEnumCaucasian, + EthnicityEnumBlack, + EthnicityEnumAsian, + EthnicityEnumIndian, + EthnicityEnumLatin, + EthnicityEnumMiddleEastern, + EthnicityEnumMixed, + EthnicityEnumOther, +} + +func (e EthnicityEnum) IsValid() bool { + switch e { + case EthnicityEnumCaucasian, EthnicityEnumBlack, EthnicityEnumAsian, EthnicityEnumIndian, EthnicityEnumLatin, EthnicityEnumMiddleEastern, EthnicityEnumMixed, EthnicityEnumOther: + return true + } + return false +} + +func (e EthnicityEnum) String() string { + return string(e) +} + +func (e *EthnicityEnum) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = EthnicityEnum(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid EthnicityEnum", str) + } + return nil +} + +func (e EthnicityEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type EyeColorEnum string + +const ( + EyeColorEnumBlue EyeColorEnum = "BLUE" + EyeColorEnumBrown EyeColorEnum = "BROWN" + EyeColorEnumGrey EyeColorEnum = "GREY" + EyeColorEnumGreen EyeColorEnum = "GREEN" + EyeColorEnumHazel EyeColorEnum = "HAZEL" + EyeColorEnumRed EyeColorEnum = "RED" +) + +var AllEyeColorEnum = []EyeColorEnum{ + EyeColorEnumBlue, + EyeColorEnumBrown, + EyeColorEnumGrey, + EyeColorEnumGreen, + EyeColorEnumHazel, + EyeColorEnumRed, +} + +func (e EyeColorEnum) IsValid() bool { + switch e { + case EyeColorEnumBlue, EyeColorEnumBrown, EyeColorEnumGrey, EyeColorEnumGreen, EyeColorEnumHazel, EyeColorEnumRed: + return true + } + return false +} + +func (e EyeColorEnum) String() string { + return string(e) +} + +func (e *EyeColorEnum) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = EyeColorEnum(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid EyeColorEnum", str) + } + return nil +} + +func (e EyeColorEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type FingerprintAlgorithm string + +const ( + FingerprintAlgorithmMd5 FingerprintAlgorithm = "MD5" + FingerprintAlgorithmOshash FingerprintAlgorithm = "OSHASH" +) + +var AllFingerprintAlgorithm = []FingerprintAlgorithm{ + FingerprintAlgorithmMd5, + FingerprintAlgorithmOshash, +} + +func (e FingerprintAlgorithm) IsValid() bool { + switch e { + case FingerprintAlgorithmMd5, FingerprintAlgorithmOshash: + return true + } + return false +} + +func (e FingerprintAlgorithm) String() string { + return string(e) +} + +func (e *FingerprintAlgorithm) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = FingerprintAlgorithm(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid FingerprintAlgorithm", str) + } + return nil +} + +func (e FingerprintAlgorithm) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type GenderEnum string + +const ( + GenderEnumMale GenderEnum = "MALE" + GenderEnumFemale GenderEnum = "FEMALE" + GenderEnumTransgenderMale GenderEnum = "TRANSGENDER_MALE" + GenderEnumTransgenderFemale GenderEnum = "TRANSGENDER_FEMALE" + GenderEnumIntersex GenderEnum = "INTERSEX" +) + +var AllGenderEnum = []GenderEnum{ + GenderEnumMale, + GenderEnumFemale, + GenderEnumTransgenderMale, + GenderEnumTransgenderFemale, + GenderEnumIntersex, +} + +func (e GenderEnum) IsValid() bool { + switch e { + case GenderEnumMale, GenderEnumFemale, GenderEnumTransgenderMale, GenderEnumTransgenderFemale, GenderEnumIntersex: + return true + } + return false +} + +func (e GenderEnum) String() string { + return string(e) +} + +func (e *GenderEnum) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = GenderEnum(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid GenderEnum", str) + } + return nil +} + +func (e GenderEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type HairColorEnum string + +const ( + HairColorEnumBlonde HairColorEnum = "BLONDE" + HairColorEnumBrunette HairColorEnum = "BRUNETTE" + HairColorEnumBlack HairColorEnum = "BLACK" + HairColorEnumRed HairColorEnum = "RED" + HairColorEnumAuburn HairColorEnum = "AUBURN" + HairColorEnumGrey HairColorEnum = "GREY" + HairColorEnumBald HairColorEnum = "BALD" + HairColorEnumVarious HairColorEnum = "VARIOUS" + HairColorEnumOther HairColorEnum = "OTHER" +) + +var AllHairColorEnum = []HairColorEnum{ + HairColorEnumBlonde, + HairColorEnumBrunette, + HairColorEnumBlack, + HairColorEnumRed, + HairColorEnumAuburn, + HairColorEnumGrey, + HairColorEnumBald, + HairColorEnumVarious, + HairColorEnumOther, +} + +func (e HairColorEnum) IsValid() bool { + switch e { + case HairColorEnumBlonde, HairColorEnumBrunette, HairColorEnumBlack, HairColorEnumRed, HairColorEnumAuburn, HairColorEnumGrey, HairColorEnumBald, HairColorEnumVarious, HairColorEnumOther: + return true + } + return false +} + +func (e HairColorEnum) String() string { + return string(e) +} + +func (e *HairColorEnum) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = HairColorEnum(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid HairColorEnum", str) + } + return nil +} + +func (e HairColorEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type OperationEnum string + +const ( + OperationEnumCreate OperationEnum = "CREATE" + OperationEnumModify OperationEnum = "MODIFY" + OperationEnumDestroy OperationEnum = "DESTROY" + OperationEnumMerge OperationEnum = "MERGE" +) + +var AllOperationEnum = []OperationEnum{ + OperationEnumCreate, + OperationEnumModify, + OperationEnumDestroy, + OperationEnumMerge, +} + +func (e OperationEnum) IsValid() bool { + switch e { + case OperationEnumCreate, OperationEnumModify, OperationEnumDestroy, OperationEnumMerge: + return true + } + return false +} + +func (e OperationEnum) String() string { + return string(e) +} + +func (e *OperationEnum) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = OperationEnum(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid OperationEnum", str) + } + return nil +} + +func (e OperationEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type RoleEnum string + +const ( + RoleEnumRead RoleEnum = "READ" + RoleEnumVote RoleEnum = "VOTE" + RoleEnumEdit RoleEnum = "EDIT" + RoleEnumModify RoleEnum = "MODIFY" + RoleEnumAdmin RoleEnum = "ADMIN" +) + +var AllRoleEnum = []RoleEnum{ + RoleEnumRead, + RoleEnumVote, + RoleEnumEdit, + RoleEnumModify, + RoleEnumAdmin, +} + +func (e RoleEnum) IsValid() bool { + switch e { + case RoleEnumRead, RoleEnumVote, RoleEnumEdit, RoleEnumModify, RoleEnumAdmin: + return true + } + return false +} + +func (e RoleEnum) String() string { + return string(e) +} + +func (e *RoleEnum) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = RoleEnum(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid RoleEnum", str) + } + return nil +} + +func (e RoleEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type SortDirectionEnum string + +const ( + SortDirectionEnumAsc SortDirectionEnum = "ASC" + SortDirectionEnumDesc SortDirectionEnum = "DESC" +) + +var AllSortDirectionEnum = []SortDirectionEnum{ + SortDirectionEnumAsc, + SortDirectionEnumDesc, +} + +func (e SortDirectionEnum) IsValid() bool { + switch e { + case SortDirectionEnumAsc, SortDirectionEnumDesc: + return true + } + return false +} + +func (e SortDirectionEnum) String() string { + return string(e) +} + +func (e *SortDirectionEnum) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = SortDirectionEnum(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid SortDirectionEnum", str) + } + return nil +} + +func (e SortDirectionEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type TargetTypeEnum string + +const ( + TargetTypeEnumScene TargetTypeEnum = "SCENE" + TargetTypeEnumStudio TargetTypeEnum = "STUDIO" + TargetTypeEnumPerformer TargetTypeEnum = "PERFORMER" + TargetTypeEnumTag TargetTypeEnum = "TAG" +) + +var AllTargetTypeEnum = []TargetTypeEnum{ + TargetTypeEnumScene, + TargetTypeEnumStudio, + TargetTypeEnumPerformer, + TargetTypeEnumTag, +} + +func (e TargetTypeEnum) IsValid() bool { + switch e { + case TargetTypeEnumScene, TargetTypeEnumStudio, TargetTypeEnumPerformer, TargetTypeEnumTag: + return true + } + return false +} + +func (e TargetTypeEnum) String() string { + return string(e) +} + +func (e *TargetTypeEnum) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = TargetTypeEnum(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid TargetTypeEnum", str) + } + return nil +} + +func (e TargetTypeEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type VoteStatusEnum string + +const ( + VoteStatusEnumAccepted VoteStatusEnum = "ACCEPTED" + VoteStatusEnumRejected VoteStatusEnum = "REJECTED" + VoteStatusEnumPending VoteStatusEnum = "PENDING" + VoteStatusEnumImmediateAccepted VoteStatusEnum = "IMMEDIATE_ACCEPTED" + VoteStatusEnumImmediateRejected VoteStatusEnum = "IMMEDIATE_REJECTED" +) + +var AllVoteStatusEnum = []VoteStatusEnum{ + VoteStatusEnumAccepted, + VoteStatusEnumRejected, + VoteStatusEnumPending, + VoteStatusEnumImmediateAccepted, + VoteStatusEnumImmediateRejected, +} + +func (e VoteStatusEnum) IsValid() bool { + switch e { + case VoteStatusEnumAccepted, VoteStatusEnumRejected, VoteStatusEnumPending, VoteStatusEnumImmediateAccepted, VoteStatusEnumImmediateRejected: + return true + } + return false +} + +func (e VoteStatusEnum) String() string { + return string(e) +} + +func (e *VoteStatusEnum) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = VoteStatusEnum(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid VoteStatusEnum", str) + } + return nil +} + +func (e VoteStatusEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type VoteTypeEnum string + +const ( + VoteTypeEnumComment VoteTypeEnum = "COMMENT" + VoteTypeEnumAccept VoteTypeEnum = "ACCEPT" + VoteTypeEnumReject VoteTypeEnum = "REJECT" + // Immediately accepts the edit - bypassing the vote + VoteTypeEnumImmediateAccept VoteTypeEnum = "IMMEDIATE_ACCEPT" + // Immediately rejects the edit - bypassing the vote + VoteTypeEnumImmediateReject VoteTypeEnum = "IMMEDIATE_REJECT" +) + +var AllVoteTypeEnum = []VoteTypeEnum{ + VoteTypeEnumComment, + VoteTypeEnumAccept, + VoteTypeEnumReject, + VoteTypeEnumImmediateAccept, + VoteTypeEnumImmediateReject, +} + +func (e VoteTypeEnum) IsValid() bool { + switch e { + case VoteTypeEnumComment, VoteTypeEnumAccept, VoteTypeEnumReject, VoteTypeEnumImmediateAccept, VoteTypeEnumImmediateReject: + return true + } + return false +} + +func (e VoteTypeEnum) String() string { + return string(e) +} + +func (e *VoteTypeEnum) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = VoteTypeEnum(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid VoteTypeEnum", str) + } + return nil +} + +func (e VoteTypeEnum) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} diff --git a/pkg/scraper/stashbox/stash_box.go b/pkg/scraper/stashbox/stash_box.go new file mode 100644 index 000000000..d2c9a3e78 --- /dev/null +++ b/pkg/scraper/stashbox/stash_box.go @@ -0,0 +1,315 @@ +package stashbox + +import ( + "context" + "fmt" + "io/ioutil" + "net/http" + "strconv" + "strings" + "time" + + "github.com/Yamashou/gqlgenc/client" + + "github.com/stashapp/stash/pkg/logger" + "github.com/stashapp/stash/pkg/models" + "github.com/stashapp/stash/pkg/scraper/stashbox/graphql" + "github.com/stashapp/stash/pkg/utils" +) + +// Timeout to get the image. Includes transfer time. May want to make this +// configurable at some point. +const imageGetTimeout = time.Second * 30 + +// Client represents the client interface to a stash-box server instance. +type Client struct { + client *graphql.Client +} + +// NewClient returns a new instance of a stash-box client. +func NewClient(box models.StashBox) *Client { + authHeader := func(req *http.Request) { + req.Header.Set("ApiKey", box.APIKey) + } + + client := &graphql.Client{ + Client: client.NewClient(http.DefaultClient, box.Endpoint, authHeader), + } + + return &Client{ + client: client, + } +} + +// QueryStashBoxScene queries stash-box for scenes using a query string. +func (c Client) QueryStashBoxScene(queryStr string) ([]*models.ScrapedScene, error) { + scenes, err := c.client.SearchScene(context.TODO(), queryStr) + if err != nil { + return nil, err + } + + sceneFragments := scenes.SearchScene + + var ret []*models.ScrapedScene + for _, s := range sceneFragments { + ss, err := sceneFragmentToScrapedScene(s) + if err != nil { + return nil, err + } + ret = append(ret, ss) + } + + return ret, nil +} + +// FindStashBoxScenesByFingerprints queries stash-box for scenes using every +// scene's MD5 checksum and/or oshash. +func (c Client) FindStashBoxScenesByFingerprints(sceneIDs []string) ([]*models.ScrapedScene, error) { + qb := models.NewSceneQueryBuilder() + + var fingerprints []string + + for _, sceneID := range sceneIDs { + idInt, _ := strconv.Atoi(sceneID) + scene, err := qb.Find(idInt) + if err != nil { + return nil, err + } + + if scene == nil { + return nil, fmt.Errorf("scene with id %d not found", idInt) + } + + if scene.Checksum.Valid { + fingerprints = append(fingerprints, scene.Checksum.String) + } + + if scene.OSHash.Valid { + fingerprints = append(fingerprints, scene.OSHash.String) + } + } + + return c.findStashBoxScenesByFingerprints(fingerprints) +} + +func (c Client) findStashBoxScenesByFingerprints(fingerprints []string) ([]*models.ScrapedScene, error) { + scenes, err := c.client.FindScenesByFingerprints(context.TODO(), fingerprints) + + if err != nil { + return nil, err + } + + sceneFragments := scenes.FindScenesByFingerprints + + var ret []*models.ScrapedScene + for _, s := range sceneFragments { + ss, err := sceneFragmentToScrapedScene(s) + if err != nil { + return nil, err + } + ret = append(ret, ss) + } + + return ret, nil +} + +func findURL(urls []*graphql.URLFragment, urlType string) *string { + for _, u := range urls { + if u.Type == urlType { + ret := u.URL + return &ret + } + } + + return nil +} + +func enumToStringPtr(e fmt.Stringer) *string { + if e != nil { + ret := e.String() + return &ret + } + + return nil +} + +func formatMeasurements(m graphql.MeasurementsFragment) *string { + if m.BandSize != nil && m.CupSize != nil && m.Hip != nil && m.Waist != nil { + ret := fmt.Sprintf("%d%s-%d-%d", *m.BandSize, *m.CupSize, *m.Waist, *m.Hip) + return &ret + } + + return nil +} + +func formatCareerLength(start, end *int) *string { + if start == nil && end == nil { + return nil + } + + var ret string + if end == nil { + ret = fmt.Sprintf("%d -", *start) + } else { + ret = fmt.Sprintf("%d - %d", *start, *end) + } + + return &ret +} + +func formatBodyModifications(m []*graphql.BodyModificationFragment) *string { + if len(m) == 0 { + return nil + } + + var retSlice []string + for _, f := range m { + if f.Description == nil { + retSlice = append(retSlice, f.Location) + } else { + retSlice = append(retSlice, fmt.Sprintf("%s, %s", f.Location, *f.Description)) + } + } + + ret := strings.Join(retSlice, "; ") + return &ret +} + +func fetchImage(url string) (*string, error) { + client := &http.Client{ + Timeout: imageGetTimeout, + } + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + + resp, err := client.Do(req) + + if err != nil { + return nil, err + } + + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + // determine the image type and set the base64 type + contentType := resp.Header.Get("Content-Type") + if contentType == "" { + contentType = http.DetectContentType(body) + } + + img := "data:" + contentType + ";base64," + utils.GetBase64StringFromData(body) + return &img, nil +} + +func performerFragmentToScrapedScenePerformer(p graphql.PerformerFragment) *models.ScrapedScenePerformer { + sp := &models.ScrapedScenePerformer{ + Name: p.Name, + Country: p.Country, + Measurements: formatMeasurements(p.Measurements), + CareerLength: formatCareerLength(p.CareerStartYear, p.CareerEndYear), + Tattoos: formatBodyModifications(p.Tattoos), + Piercings: formatBodyModifications(p.Piercings), + Twitter: findURL(p.Urls, "TWITTER"), + // TODO - Image - should be returned as a set of URLs. Will need a + // graphql schema change to accommodate this. Leave off for now. + } + + if p.Height != nil { + hs := strconv.Itoa(*p.Height) + sp.Height = &hs + } + + if p.Birthdate != nil { + b := p.Birthdate.Date + sp.Birthdate = &b + } + + if p.Gender != nil { + sp.Gender = enumToStringPtr(p.Gender) + } + + if p.Ethnicity != nil { + sp.Ethnicity = enumToStringPtr(p.Ethnicity) + } + + if p.EyeColor != nil { + sp.EyeColor = enumToStringPtr(p.EyeColor) + } + + if p.BreastType != nil { + sp.FakeTits = enumToStringPtr(p.BreastType) + } + + return sp +} + +func getFirstImage(images []*graphql.ImageFragment) *string { + ret, err := fetchImage(images[0].URL) + if err != nil { + logger.Warnf("Error fetching image %s: %s", images[0].URL, err.Error()) + } + + return ret +} + +func sceneFragmentToScrapedScene(s *graphql.SceneFragment) (*models.ScrapedScene, error) { + ss := &models.ScrapedScene{ + Title: s.Title, + Date: s.Date, + Details: s.Details, + URL: findURL(s.Urls, "STUDIO"), + // Image + // stash_id + } + + if len(s.Images) > 0 { + // TODO - #454 code sorts images by aspect ratio according to a wanted + // orientation. I'm just grabbing the first for now + ss.Image = getFirstImage(s.Images) + } + + if s.Studio != nil { + ss.Studio = &models.ScrapedSceneStudio{ + Name: s.Studio.Name, + URL: findURL(s.Studio.Urls, "HOME"), + } + + err := models.MatchScrapedSceneStudio(ss.Studio) + if err != nil { + return nil, err + } + } + + for _, p := range s.Performers { + sp := performerFragmentToScrapedScenePerformer(p.Performer) + + err := models.MatchScrapedScenePerformer(sp) + if err != nil { + return nil, err + } + + ss.Performers = append(ss.Performers, sp) + } + + for _, t := range s.Tags { + st := &models.ScrapedSceneTag{ + Name: t.Name, + } + + err := models.MatchScrapedSceneTag(st) + if err != nil { + return nil, err + } + + ss.Tags = append(ss.Tags, st) + } + + return ss, nil +} diff --git a/tools.go b/tools.go index 5e0f780d9..9bc7b212d 100644 --- a/tools.go +++ b/tools.go @@ -4,5 +4,6 @@ package main import ( _ "github.com/99designs/gqlgen" + _ "github.com/Yamashou/gqlgenc" _ "github.com/vektra/mockery/v2" ) diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx index ab7ea6b3d..3299e4bca 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx @@ -14,6 +14,8 @@ import { useListSceneScrapers, useSceneUpdate, mutateReloadScrapers, + useConfiguration, + queryStashBoxScene, } from "src/core/StashService"; import { PerformerSelect, @@ -62,6 +64,8 @@ export const SceneEditPanel: React.FC = (props: IProps) => { const [coverImagePreview, setCoverImagePreview] = useState(); + const stashConfig = useConfiguration(); + // Network state const [isLoading, setIsLoading] = useState(true); @@ -117,7 +121,7 @@ export const SceneEditPanel: React.FC = (props: IProps) => { ); setQueryableScrapers(newQueryableScrapers); - }, [Scrapers]); + }, [Scrapers, stashConfig]); useEffect(() => { let changed = false; @@ -251,11 +255,40 @@ export const SceneEditPanel: React.FC = (props: IProps) => { ImageUtils.onImageChange(event, onImageLoad); } + async function onScrapeStashBoxClicked(stashBoxIndex: number) { + setIsLoading(true); + try { + const result = await queryStashBoxScene(stashBoxIndex, props.scene.id); + if (!result.data || !result.data.queryStashBoxScene) { + return; + } + + if (result.data.queryStashBoxScene.length > 0) { + setScrapedScene(result.data.queryStashBoxScene[0]); + } else { + Toast.success({ + content: "No scenes found", + }); + } + } catch (e) { + Toast.error(e); + } finally { + setIsLoading(false); + } + } + + // function onStashBoxQueryClicked(/* stashBoxIndex: number */) { + // TODO + // } + async function onScrapeClicked(scraper: GQL.Scraper) { setIsLoading(true); try { const result = await queryScrapeScene(scraper.id, getSceneInput()); if (!result.data || !result.data.scrapeScene) { + Toast.success({ + content: "No scenes found", + }); return; } setScrapedScene(result.data.scrapeScene); @@ -309,8 +342,23 @@ export const SceneEditPanel: React.FC = (props: IProps) => { } function renderScraperMenu() { + const stashBoxes = stashConfig.data?.configuration.general.stashBoxes ?? []; + + // TODO - change name based on stashbox configuration return ( - + + {stashBoxes.map((s, index) => ( + onScrapeStashBoxClicked(index)} + > + stash-box + + ))} {queryableScrapers.map((s) => ( onScrapeClicked(s)}> {s.name} @@ -326,6 +374,44 @@ export const SceneEditPanel: React.FC = (props: IProps) => { ); } + function maybeRenderStashboxQueryButton() { + // const stashBoxes = stashConfig.data?.configuration.general.stashBoxes ?? []; + // if (stashBoxes.length === 0) { + // return; + // } + // TODO - hide this button for now, with the view to add it when we get + // the query dialog going + // if (stashBoxes.length === 1) { + // return ( + // + // ); + // } + // // TODO - change name based on stashbox configuration + // return ( + // + // + // + // + // + // {stashBoxes.map((s, index) => ( + // onStashBoxQueryClicked(index)} + // > + // stash-box + // + // ))} + // + // + // ); + } + function urlScrapable(scrapedUrl: string): boolean { return (Scrapers?.data?.listSceneScrapers ?? []).some((s) => (s?.scene?.urls ?? []).some((u) => scrapedUrl.includes(u)) @@ -432,7 +518,7 @@ export const SceneEditPanel: React.FC = (props: IProps) => {
{maybeRenderScrapeDialog()}
-
+
@@ -444,7 +530,10 @@ export const SceneEditPanel: React.FC = (props: IProps) => { Delete
- {renderScraperMenu()} + + {maybeRenderStashboxQueryButton()} + {renderScraperMenu()} +
diff --git a/ui/v2.5/src/core/StashService.ts b/ui/v2.5/src/core/StashService.ts index 797efa047..2c7097789 100644 --- a/ui/v2.5/src/core/StashService.ts +++ b/ui/v2.5/src/core/StashService.ts @@ -498,6 +498,17 @@ export const queryScrapeScene = ( fetchPolicy: "network-only", }); +export const queryStashBoxScene = (stashBoxIndex: number, sceneID: string) => + client.query({ + query: GQL.QueryStashBoxSceneDocument, + variables: { + input: { + stash_box_index: stashBoxIndex, + scene_ids: [sceneID], + }, + }, + }); + export const mutateReloadScrapers = () => client.mutate({ mutation: GQL.ReloadScrapersDocument, diff --git a/vendor/github.com/99designs/gqlgen/.gitignore b/vendor/github.com/99designs/gqlgen/.gitignore index 3dbd96815..b918d6a6f 100644 --- a/vendor/github.com/99designs/gqlgen/.gitignore +++ b/vendor/github.com/99designs/gqlgen/.gitignore @@ -4,6 +4,8 @@ /integration/node_modules /integration/schema-fetched.graphql /example/chat/package-lock.json +/example/federation/package-lock.json +/example/federation/node_modules /codegen/gen /gen diff --git a/vendor/github.com/99designs/gqlgen/.golangci.yml b/vendor/github.com/99designs/gqlgen/.golangci.yml index 2239d630a..8d5138680 100644 --- a/vendor/github.com/99designs/gqlgen/.golangci.yml +++ b/vendor/github.com/99designs/gqlgen/.golangci.yml @@ -1,3 +1,39 @@ +run: + tests: true + skip-dirs: + - bin + linters-settings: errcheck: ignore: fmt:.*,[rR]ead|[wW]rite|[cC]lose,io:Copy + +linters: + disable-all: true + enable: + - bodyclose + - deadcode + - depguard + - dupl + - errcheck + - gocritic + - gofmt + - goimports + - gosimple + - govet + - ineffassign + - interfacer + - misspell + - nakedret + - prealloc + - staticcheck + - structcheck + - unconvert + - unused + - varcheck + +issues: + exclude-rules: + # Exclude some linters from running on tests files. + - path: _test\.go + linters: + - dupl diff --git a/vendor/github.com/99designs/gqlgen/LICENSE b/vendor/github.com/99designs/gqlgen/LICENSE index 18e1b2493..10bb21c07 100644 --- a/vendor/github.com/99designs/gqlgen/LICENSE +++ b/vendor/github.com/99designs/gqlgen/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018 Adam Scarr +Copyright (c) 2020 gqlgen authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/github.com/99designs/gqlgen/README.md b/vendor/github.com/99designs/gqlgen/README.md index 0b302bdd5..0543bc373 100644 --- a/vendor/github.com/99designs/gqlgen/README.md +++ b/vendor/github.com/99designs/gqlgen/README.md @@ -1,20 +1,24 @@ -# gqlgen [![CircleCI](https://badgen.net/circleci/github/99designs/gqlgen/master)](https://circleci.com/gh/99designs/gqlgen) [![Read the Docs](https://badgen.net/badge/docs/available/green)](http://gqlgen.com/) +# gqlgen [![Continuous Integration](https://github.com/99designs/gqlgen/workflows/Continuous%20Integration/badge.svg)](https://github.com/99designs/gqlgen/actions) [![Read the Docs](https://badgen.net/badge/docs/available/green)](http://gqlgen.com/) [![GoDoc](https://godoc.org/github.com/99designs/gqlgen?status.svg)](https://godoc.org/github.com/99designs/gqlgen) + +![gqlgen](https://user-images.githubusercontent.com/46195831/89802919-0bb8ef00-db2a-11ea-8ba4-88e7a58b2fd2.png) ## What is gqlgen? -[gqlgen](https://github.com/99designs/gqlgen) is a Go library for building GraphQL servers without any fuss. gqlgen is: +[gqlgen](https://github.com/99designs/gqlgen) is a Go library for building GraphQL servers without any fuss.
- - **Schema first** — Define your API using the GraphQL [Schema Definition Language](http://graphql.org/learn/schema/). - - **Type safe** — You should never see `map[string]interface{}` here. - - **Codegen** — Let us generate the boring bits, so you can build your app quickly. +- **gqlgen is based on a Schema first approach** — You get to Define your API using the GraphQL [Schema Definition Language](http://graphql.org/learn/schema/). +- **gqlgen priortizes Type safety** — You should never see `map[string]interface{}` here. +- **gqlgen enables Codegen** — We generate the boring bits, so you can focus on building your app quickly. -[Feature Comparison](https://gqlgen.com/feature-comparison/) +Still not convinced enough to use **gqlgen**? Compare **gqlgen** with other Go graphql [implementations](https://gqlgen.com/feature-comparison/) ## Getting Started +- To install gqlgen run the comand `go get github.com/99designs/gqlgen` in your project directory.
+- You could initialize a new project using the recommended folder structure by running this command `go run github.com/99designs/gqlgen init`. -First work your way through the [Getting Started](https://gqlgen.com/getting-started/) tutorial. - -If you can't find what your looking for, look at our [examples](https://github.com/99designs/gqlgen/tree/master/example) for example usage of gqlgen. +You could find a more comprehensive guide to help you get started [here](https://gqlgen.com/getting-started/).
+We also have a couple of real-world [examples](https://github.com/99designs/gqlgen/tree/master/example) that show how to GraphQL applicatons with **gqlgen** seamlessly, +You can see these [examples](https://github.com/99designs/gqlgen/tree/master/example) here or visit [godoc](https://godoc.org/github.com/99designs/gqlgen). ## Reporting Issues @@ -22,10 +26,88 @@ If you think you've found a bug, or something isn't behaving the way you think i ## Contributing -Read our [Contribution Guidelines](https://github.com/99designs/gqlgen/blob/master/CONTRIBUTING.md) for information on how you can help out gqlgen. +We welcome contributions, Read our [Contribution Guidelines](https://github.com/99designs/gqlgen/blob/master/CONTRIBUTING.md) to learn more about contributing to **gqlgen** +## Frequently asked questions + +### How do I prevent fetching child objects that might not be used? + +When you have nested or recursive schema like this: + +```graphql +type User { + id: ID! + name: String! + friends: [User!]! +} +``` + +You need to tell gqlgen that it should only fetch friends if the user requested it. There are two ways to do this; + +- #### Using Custom Models + +Write a custom model that omits the friends field: + +```go +type User struct { + ID int + Name string +} +``` + +And reference the model in `gqlgen.yml`: + +```yaml +# gqlgen.yml +models: + User: + model: github.com/you/pkg/model.User # go import path to the User struct above +``` + +- #### Using Explicit Resolvers + +If you want to Keep using the generated model, mark the field as requiring a resolver explicitly in `gqlgen.yml` like this: + +```yaml +# gqlgen.yml +models: + User: + fields: + friends: + resolver: true # force a resolver to be generated +``` + +After doing either of the above and running generate we will need to provide a resolver for friends: + +```go +func (r *userResolver) Friends(ctx context.Context, obj *User) ([]*User, error) { + // select * from user where friendid = obj.ID + return friends, nil +} +``` + +### Can I change the type of the ID from type String to Type Int? + +Yes! You can by remapping it in config as seen below: + +```yaml +models: + ID: # The GraphQL type ID is backed by + model: + - github.com/99designs/gqlgen/graphql.IntID # An go integer + - github.com/99designs/gqlgen/graphql.ID # or a go string +``` + +This means gqlgen will be able to automatically bind to strings or ints for models you have written yourself, but the +first model in this list is used as the default type and it will always be used when: + +- Generating models based on schema +- As arguments in resolvers + +There isnt any way around this, gqlgen has no way to know what you want in a given context. ## Other Resources - - [Christopher Biscardi @ Gophercon UK 2018](https://youtu.be/FdURVezcdcw) - - [Introducing gqlgen: a GraphQL Server Generator for Go](https://99designs.com.au/blog/engineering/gqlgen-a-graphql-server-generator-for-go/) - - [GraphQL workshop for Golang developers by Iván Corrales Solera](https://graphql-go.wesovilabs.com) +- [Christopher Biscardi @ Gophercon UK 2018](https://youtu.be/FdURVezcdcw) +- [Introducing gqlgen: a GraphQL Server Generator for Go](https://99designs.com.au/blog/engineering/gqlgen-a-graphql-server-generator-for-go/) +- [Dive into GraphQL by Iván Corrales Solera](https://medium.com/@ivan.corrales.solera/dive-into-graphql-9bfedf22e1a) +- [Sample Project built on gqlgen with Postgres by Oleg Shalygin](https://github.com/oshalygin/gqlgen-pg-todo-example) diff --git a/vendor/github.com/99designs/gqlgen/api/generate.go b/vendor/github.com/99designs/gqlgen/api/generate.go index 3dd083f52..3a19c017d 100644 --- a/vendor/github.com/99designs/gqlgen/api/generate.go +++ b/vendor/github.com/99designs/gqlgen/api/generate.go @@ -6,25 +6,60 @@ import ( "github.com/99designs/gqlgen/codegen" "github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/plugin" + "github.com/99designs/gqlgen/plugin/federation" "github.com/99designs/gqlgen/plugin/modelgen" "github.com/99designs/gqlgen/plugin/resolvergen" "github.com/pkg/errors" - "golang.org/x/tools/go/packages" ) func Generate(cfg *config.Config, option ...Option) error { _ = syscall.Unlink(cfg.Exec.Filename) - _ = syscall.Unlink(cfg.Model.Filename) + if cfg.Model.IsDefined() { + _ = syscall.Unlink(cfg.Model.Filename) + } - plugins := []plugin.Plugin{ - modelgen.New(), - resolvergen.New(), + plugins := []plugin.Plugin{} + if cfg.Model.IsDefined() { + plugins = append(plugins, modelgen.New()) + } + plugins = append(plugins, resolvergen.New()) + if cfg.Federation.IsDefined() { + plugins = append([]plugin.Plugin{federation.New()}, plugins...) } for _, o := range option { o(cfg, &plugins) } + for _, p := range plugins { + if inj, ok := p.(plugin.EarlySourceInjector); ok { + if s := inj.InjectSourceEarly(); s != nil { + cfg.Sources = append(cfg.Sources, s) + } + } + } + + if err := cfg.LoadSchema(); err != nil { + return errors.Wrap(err, "failed to load schema") + } + + for _, p := range plugins { + if inj, ok := p.(plugin.LateSourceInjector); ok { + if s := inj.InjectSourceLate(cfg.Schema); s != nil { + cfg.Sources = append(cfg.Sources, s) + } + } + } + + // LoadSchema again now we have everything + if err := cfg.LoadSchema(); err != nil { + return errors.Wrap(err, "failed to load schema") + } + + if err := cfg.Init(); err != nil { + return errors.Wrap(err, "generating core failed") + } + for _, p := range plugins { if mut, ok := p.(plugin.ConfigMutator); ok { err := mut.MutateConfig(cfg) @@ -36,7 +71,7 @@ func Generate(cfg *config.Config, option ...Option) error { // Merge again now that the generated models have been injected into the typemap data, err := codegen.BuildData(cfg) if err != nil { - return errors.Wrap(err, "merging failed") + return errors.Wrap(err, "merging type systems failed") } if err = codegen.GenerateCode(data); err != nil { @@ -52,8 +87,14 @@ func Generate(cfg *config.Config, option ...Option) error { } } - if err := validate(cfg); err != nil { - return errors.Wrap(err, "validation failed") + if err = codegen.GenerateCode(data); err != nil { + return errors.Wrap(err, "generating core failed") + } + + if !cfg.SkipValidation { + if err := validate(cfg); err != nil { + return errors.Wrap(err, "validation failed") + } } return nil @@ -68,9 +109,11 @@ func validate(cfg *config.Config) error { if cfg.Resolver.IsDefined() { roots = append(roots, cfg.Resolver.ImportPath()) } - _, err := packages.Load(&packages.Config{Mode: packages.LoadTypes | packages.LoadSyntax}, roots...) - if err != nil { - return errors.Wrap(err, "validation failed") + + cfg.Packages.LoadAll(roots...) + errs := cfg.Packages.Errors() + if len(errs) > 0 { + return errs } return nil } diff --git a/vendor/github.com/99designs/gqlgen/appveyor.yml b/vendor/github.com/99designs/gqlgen/appveyor.yml deleted file mode 100644 index db4751114..000000000 --- a/vendor/github.com/99designs/gqlgen/appveyor.yml +++ /dev/null @@ -1,32 +0,0 @@ -version: "{build}" - -# Source Config - -skip_branch_with_pr: true -clone_folder: c:\projects\gqlgen - -# Build host - -environment: - GOPATH: c:\gopath - GOVERSION: 1.11.5 - PATH: '%PATH%;c:\gopath\bin' - -init: - - git config --global core.autocrlf input - -# Build - -install: - # Install the specific Go version. - - rmdir c:\go /s /q - - appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.msi - - msiexec /i go%GOVERSION%.windows-amd64.msi /q - - go version - -build: false -deploy: false - -test_script: - - go generate ./... - - go test -timeout 20m ./... diff --git a/vendor/github.com/99designs/gqlgen/cmd/ambient.go b/vendor/github.com/99designs/gqlgen/cmd/ambient.go index 7838fdf16..0f3655d34 100644 --- a/vendor/github.com/99designs/gqlgen/cmd/ambient.go +++ b/vendor/github.com/99designs/gqlgen/cmd/ambient.go @@ -5,6 +5,6 @@ import ( // don't prune unused code for us. Both lists should be kept in sync. _ "github.com/99designs/gqlgen/graphql" _ "github.com/99designs/gqlgen/graphql/introspection" - _ "github.com/vektah/gqlparser" - _ "github.com/vektah/gqlparser/ast" + _ "github.com/vektah/gqlparser/v2" + _ "github.com/vektah/gqlparser/v2/ast" ) diff --git a/vendor/github.com/99designs/gqlgen/cmd/gen.go b/vendor/github.com/99designs/gqlgen/cmd/gen.go index c69858b44..b875bb43d 100644 --- a/vendor/github.com/99designs/gqlgen/cmd/gen.go +++ b/vendor/github.com/99designs/gqlgen/cmd/gen.go @@ -1,44 +1,43 @@ package cmd import ( - "fmt" "os" "github.com/99designs/gqlgen/api" "github.com/99designs/gqlgen/codegen/config" "github.com/pkg/errors" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) -var genCmd = cli.Command{ +var genCmd = &cli.Command{ Name: "generate", Usage: "generate a graphql server based on schema", Flags: []cli.Flag{ - cli.BoolFlag{Name: "verbose, v", Usage: "show logs"}, - cli.StringFlag{Name: "config, c", Usage: "the config filename"}, + &cli.BoolFlag{Name: "verbose, v", Usage: "show logs"}, + &cli.StringFlag{Name: "config, c", Usage: "the config filename"}, }, - Action: func(ctx *cli.Context) { + Action: func(ctx *cli.Context) error { var cfg *config.Config var err error if configFilename := ctx.String("config"); configFilename != "" { cfg, err = config.LoadConfig(configFilename) if err != nil { - fmt.Fprintln(os.Stderr, err.Error()) - os.Exit(1) + return err } } else { cfg, err = config.LoadConfigFromDefaultLocations() if os.IsNotExist(errors.Cause(err)) { - cfg = config.DefaultConfig() - } else if err != nil { - fmt.Fprintln(os.Stderr, err.Error()) - os.Exit(2) + cfg, err = config.LoadDefaultConfig() + } + + if err != nil { + return err } } if err = api.Generate(cfg); err != nil { - fmt.Fprintln(os.Stderr, err.Error()) - os.Exit(3) + return err } + return nil }, } diff --git a/vendor/github.com/99designs/gqlgen/cmd/init.go b/vendor/github.com/99designs/gqlgen/cmd/init.go index e07bed970..121805af5 100644 --- a/vendor/github.com/99designs/gqlgen/cmd/init.go +++ b/vendor/github.com/99designs/gqlgen/cmd/init.go @@ -3,28 +3,79 @@ package cmd import ( "bytes" "fmt" + "html/template" "io/ioutil" "os" + "path/filepath" "strings" "github.com/99designs/gqlgen/api" - "github.com/99designs/gqlgen/plugin/servergen" - "github.com/99designs/gqlgen/codegen/config" - "github.com/pkg/errors" - "github.com/urfave/cli" - yaml "gopkg.in/yaml.v2" + "github.com/99designs/gqlgen/internal/code" + "github.com/99designs/gqlgen/plugin/servergen" + "github.com/urfave/cli/v2" ) -var configComment = ` -# .gqlgen.yml example -# -# Refer to https://gqlgen.com/config/ -# for detailed .gqlgen.yml documentation. -` +var configTemplate = template.Must(template.New("name").Parse( + `# Where are all the schema files located? globs are supported eg src/**/*.graphqls +schema: + - graph/*.graphqls -var schemaDefault = ` -# GraphQL schema example +# Where should the generated server code go? +exec: + filename: graph/generated/generated.go + package: generated + +# Uncomment to enable federation +# federation: +# filename: graph/generated/federation.go +# package: generated + +# Where should any generated models go? +model: + filename: graph/model/models_gen.go + package: model + +# Where should the resolver implementations go? +resolver: + layout: follow-schema + dir: graph + package: graph + +# Optional: turn on use ` + "`" + `gqlgen:"fieldName"` + "`" + ` tags in your models +# struct_tag: json + +# Optional: turn on to use []Thing instead of []*Thing +# omit_slice_element_pointers: false + +# Optional: set to speed up generation time by not performing a final validation pass. +# skip_validation: true + +# gqlgen will search for any type names in the schema in these go packages +# if they match it will use them, otherwise it will generate them. +autobind: + - "{{.}}/graph/model" + +# This section declares type mapping between the GraphQL and go type systems +# +# The first line in each type will be used as defaults for resolver arguments and +# modelgen, the others will be allowed when binding to fields. Configure them to +# your liking +models: + ID: + model: + - github.com/99designs/gqlgen/graphql.ID + - github.com/99designs/gqlgen/graphql.Int + - github.com/99designs/gqlgen/graphql.Int64 + - github.com/99designs/gqlgen/graphql.Int32 + Int: + model: + - github.com/99designs/gqlgen/graphql.Int + - github.com/99designs/gqlgen/graphql.Int64 + - github.com/99designs/gqlgen/graphql.Int32 +`)) + +var schemaDefault = `# GraphQL schema example # # https://gqlgen.com/getting-started/ @@ -54,91 +105,95 @@ type Mutation { } ` -var initCmd = cli.Command{ +var initCmd = &cli.Command{ Name: "init", Usage: "create a new gqlgen project", Flags: []cli.Flag{ - cli.BoolFlag{Name: "verbose, v", Usage: "show logs"}, - cli.StringFlag{Name: "config, c", Usage: "the config filename"}, - cli.StringFlag{Name: "server", Usage: "where to write the server stub to", Value: "server/server.go"}, - cli.StringFlag{Name: "schema", Usage: "where to write the schema stub to", Value: "schema.graphql"}, + &cli.BoolFlag{Name: "verbose, v", Usage: "show logs"}, + &cli.StringFlag{Name: "config, c", Usage: "the config filename"}, + &cli.StringFlag{Name: "server", Usage: "where to write the server stub to", Value: "server.go"}, + &cli.StringFlag{Name: "schema", Usage: "where to write the schema stub to", Value: "graph/schema.graphqls"}, }, - Action: func(ctx *cli.Context) { - initSchema(ctx.String("schema")) - config := initConfig(ctx) + Action: func(ctx *cli.Context) error { + configFilename := ctx.String("config") + serverFilename := ctx.String("server") - GenerateGraphServer(config, ctx.String("server")) + pkgName := code.ImportPathForDir(".") + if pkgName == "" { + return fmt.Errorf("unable to determine import path for current directory, you probably need to run go mod init first") + } + + if err := initSchema(ctx.String("schema")); err != nil { + return err + } + if !configExists(configFilename) { + if err := initConfig(configFilename, pkgName); err != nil { + return err + } + } + + GenerateGraphServer(serverFilename) + return nil }, } -func GenerateGraphServer(cfg *config.Config, serverFilename string) { - err := api.Generate(cfg, api.AddPlugin(servergen.New(serverFilename))) +func GenerateGraphServer(serverFilename string) { + cfg, err := config.LoadConfigFromDefaultLocations() if err != nil { fmt.Fprintln(os.Stderr, err.Error()) } + if err := api.Generate(cfg, api.AddPlugin(servergen.New(serverFilename))); err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + } + fmt.Fprintf(os.Stdout, "Exec \"go run ./%s\" to start GraphQL server\n", serverFilename) } -func initConfig(ctx *cli.Context) *config.Config { +func configExists(configFilename string) bool { var cfg *config.Config - var err error - configFilename := ctx.String("config") + if configFilename != "" { - cfg, err = config.LoadConfig(configFilename) + cfg, _ = config.LoadConfig(configFilename) } else { - cfg, err = config.LoadConfigFromDefaultLocations() - } - - if cfg != nil { - fmt.Fprintf(os.Stderr, "init failed: a configuration file already exists\n") - os.Exit(1) - } - - if !os.IsNotExist(errors.Cause(err)) { - fmt.Fprintln(os.Stderr, err.Error()) - os.Exit(1) + cfg, _ = config.LoadConfigFromDefaultLocations() } + return cfg != nil +} +func initConfig(configFilename string, pkgName string) error { if configFilename == "" { configFilename = "gqlgen.yml" } - cfg = config.DefaultConfig() - cfg.Resolver = config.PackageConfig{ - Filename: "resolver.go", - Type: "Resolver", + if err := os.MkdirAll(filepath.Dir(configFilename), 0755); err != nil { + return fmt.Errorf("unable to create config dir: " + err.Error()) } var buf bytes.Buffer - buf.WriteString(strings.TrimSpace(configComment)) - buf.WriteString("\n\n") - var b []byte - b, err = yaml.Marshal(cfg) - if err != nil { - fmt.Fprintln(os.Stderr, "unable to marshal yaml: "+err.Error()) - os.Exit(1) - } - buf.Write(b) - - err = ioutil.WriteFile(configFilename, buf.Bytes(), 0644) - if err != nil { - fmt.Fprintln(os.Stderr, "unable to write cfg file: "+err.Error()) - os.Exit(1) + if err := configTemplate.Execute(&buf, pkgName); err != nil { + panic(err) } - return cfg + if err := ioutil.WriteFile(configFilename, buf.Bytes(), 0644); err != nil { + return fmt.Errorf("unable to write cfg file: " + err.Error()) + } + + return nil } -func initSchema(schemaFilename string) { +func initSchema(schemaFilename string) error { _, err := os.Stat(schemaFilename) if !os.IsNotExist(err) { - return + return nil } - err = ioutil.WriteFile(schemaFilename, []byte(strings.TrimSpace(schemaDefault)), 0644) - if err != nil { - fmt.Fprintln(os.Stderr, "unable to write schema file: "+err.Error()) - os.Exit(1) + if err := os.MkdirAll(filepath.Dir(schemaFilename), 0755); err != nil { + return fmt.Errorf("unable to create schema dir: " + err.Error()) } + + if err = ioutil.WriteFile(schemaFilename, []byte(strings.TrimSpace(schemaDefault)), 0644); err != nil { + return fmt.Errorf("unable to write schema file: " + err.Error()) + } + return nil } diff --git a/vendor/github.com/99designs/gqlgen/cmd/root.go b/vendor/github.com/99designs/gqlgen/cmd/root.go index dc2970ac8..2776aa284 100644 --- a/vendor/github.com/99designs/gqlgen/cmd/root.go +++ b/vendor/github.com/99designs/gqlgen/cmd/root.go @@ -7,9 +7,10 @@ import ( "os" "github.com/99designs/gqlgen/graphql" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" // Required since otherwise dep will prune away these unused packages before codegen has a chance to run + _ "github.com/99designs/gqlgen/graphql/handler" _ "github.com/99designs/gqlgen/handler" ) @@ -31,7 +32,7 @@ func Execute() { } app.Action = genCmd.Action - app.Commands = []cli.Command{ + app.Commands = []*cli.Command{ genCmd, initCmd, versionCmd, diff --git a/vendor/github.com/99designs/gqlgen/cmd/version.go b/vendor/github.com/99designs/gqlgen/cmd/version.go index 8b7442d4e..d3a05deda 100644 --- a/vendor/github.com/99designs/gqlgen/cmd/version.go +++ b/vendor/github.com/99designs/gqlgen/cmd/version.go @@ -4,13 +4,14 @@ import ( "fmt" "github.com/99designs/gqlgen/graphql" - "github.com/urfave/cli" + "github.com/urfave/cli/v2" ) -var versionCmd = cli.Command{ +var versionCmd = &cli.Command{ Name: "version", Usage: "print the version string", - Action: func(ctx *cli.Context) { + Action: func(ctx *cli.Context) error { fmt.Println(graphql.Version) + return nil }, } diff --git a/vendor/github.com/99designs/gqlgen/codegen/args.go b/vendor/github.com/99designs/gqlgen/codegen/args.go index d1498bddb..20a26e975 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/args.go +++ b/vendor/github.com/99designs/gqlgen/codegen/args.go @@ -8,7 +8,7 @@ import ( "github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/templates" "github.com/pkg/errors" - "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/v2/ast" ) type ArgSet struct { @@ -26,6 +26,22 @@ type FieldArgument struct { Value interface{} // value set in Data } +//ImplDirectives get not Builtin and location ARGUMENT_DEFINITION directive +func (f *FieldArgument) ImplDirectives() []*Directive { + d := make([]*Directive, 0) + for i := range f.Directives { + if !f.Directives[i].Builtin && f.Directives[i].IsLocation(ast.LocationArgumentDefinition) { + d = append(d, f.Directives[i]) + } + } + + return d +} + +func (f *FieldArgument) DirectiveObjName() string { + return "rawArgs" +} + func (f *FieldArgument) Stream() bool { return f.Object != nil && f.Object.Stream } diff --git a/vendor/github.com/99designs/gqlgen/codegen/args.gotpl b/vendor/github.com/99designs/gqlgen/codegen/args.gotpl index 4c7212182..b25d444b5 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/args.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/args.gotpl @@ -5,27 +5,20 @@ func (ec *executionContext) {{ $name }}(ctx context.Context, rawArgs map[string] {{- range $i, $arg := . }} var arg{{$i}} {{ $arg.TypeReference.GO | ref}} if tmp, ok := rawArgs[{{$arg.Name|quote}}]; ok { - {{- if $arg.Directives }} - getArg0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp) } - - {{- range $i, $directive := $arg.Directives }} - getArg{{add $i 1}} := func(ctx context.Context) (res interface{}, err error) { - {{- range $dArg := $directive.Args }} - {{- if and $dArg.TypeReference.IsPtr ( notNil "Value" $dArg ) }} - {{ $dArg.VarName }} := {{ $dArg.Value | dump }} - {{- end }} - {{- end }} - n := getArg{{$i}} - return ec.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs "tmp" "n" }}) - } - {{- end }} - - tmp, err = getArg{{$arg.Directives|len}}(ctx) + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField({{$arg.Name|quote}})) + {{- if $arg.ImplDirectives }} + directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp) } + {{ template "implDirectives" $arg }} + tmp, err = directive{{$arg.ImplDirectives|len}}(ctx) if err != nil { return nil, err } if data, ok := tmp.({{ $arg.TypeReference.GO | ref }}) ; ok { arg{{$i}} = data + {{- if $arg.TypeReference.IsNilable }} + } else if tmp == nil { + arg{{$i}} = nil + {{- end }} } else { return nil, fmt.Errorf(`unexpected type %T from directive, should be {{ $arg.TypeReference.GO }}`, tmp) } diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/binder.go b/vendor/github.com/99designs/gqlgen/codegen/config/binder.go index cea904ada..2be7b7bdd 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/config/binder.go +++ b/vendor/github.com/99designs/gqlgen/codegen/config/binder.go @@ -8,37 +8,24 @@ import ( "github.com/99designs/gqlgen/codegen/templates" "github.com/99designs/gqlgen/internal/code" "github.com/pkg/errors" - "github.com/vektah/gqlparser/ast" - "golang.org/x/tools/go/packages" + "github.com/vektah/gqlparser/v2/ast" ) // Binder connects graphql types to golang types using static analysis type Binder struct { - pkgs []*packages.Package + pkgs *code.Packages schema *ast.Schema cfg *Config References []*TypeReference + SawInvalid bool } -func (c *Config) NewBinder(s *ast.Schema) (*Binder, error) { - pkgs, err := packages.Load(&packages.Config{Mode: packages.LoadTypes | packages.LoadSyntax}, c.Models.ReferencedPackages()...) - if err != nil { - return nil, err - } - - for _, p := range pkgs { - for _, e := range p.Errors { - if e.Kind == packages.ListError { - return nil, p.Errors[0] - } - } - } - +func (c *Config) NewBinder() *Binder { return &Binder{ - pkgs: pkgs, - schema: s, + pkgs: c.Packages, + schema: c.Schema, cfg: c, - }, nil + } } func (b *Binder) TypePosition(typ types.Type) token.Position { @@ -58,11 +45,26 @@ func (b *Binder) ObjectPosition(typ types.Object) token.Position { Filename: "unknown", } } - pkg := b.getPkg(typ.Pkg().Path()) + pkg := b.pkgs.Load(typ.Pkg().Path()) return pkg.Fset.Position(typ.Pos()) } +func (b *Binder) FindTypeFromName(name string) (types.Type, error) { + pkgName, typeName := code.PkgAndType(name) + return b.FindType(pkgName, typeName) +} + func (b *Binder) FindType(pkgName string, typeName string) (types.Type, error) { + if pkgName == "" { + if typeName == "map[string]interface{}" { + return MapType, nil + } + + if typeName == "interface{}" { + return InterfaceType, nil + } + } + obj, err := b.FindObject(pkgName, typeName) if err != nil { return nil, err @@ -74,15 +76,6 @@ func (b *Binder) FindType(pkgName string, typeName string) (types.Type, error) { return obj.Type(), nil } -func (b *Binder) getPkg(find string) *packages.Package { - for _, p := range b.pkgs { - if code.NormalizeVendor(find) == code.NormalizeVendor(p.PkgPath) { - return p - } - } - return nil -} - var MapType = types.NewMap(types.Typ[types.String], types.NewInterfaceType(nil, nil).Complete()) var InterfaceType = types.NewInterfaceType(nil, nil) @@ -122,7 +115,7 @@ func (b *Binder) FindObject(pkgName string, typeName string) (types.Object, erro fullName = pkgName + "." + typeName } - pkg := b.getPkg(pkgName) + pkg := b.pkgs.LoadWithTypes(pkgName) if pkg == nil { return nil, errors.Errorf("required package was not loaded: %s", fullName) } @@ -173,7 +166,8 @@ func (b *Binder) PointerTo(ref *TypeReference) *TypeReference { type TypeReference struct { Definition *ast.Definition GQL *ast.Type - GO types.Type + GO types.Type // Type of the field being bound. Could be a pointer or a value type of Target. + Target types.Type // The actual type that we know how to bind to. May require pointer juggling when traversing to fields. CastType types.Type // Before calling marshalling functions cast from/to this base type Marshaler *types.Func // When using external marshalling functions this will point to the Marshal function Unmarshaler *types.Func // When using external marshalling functions this will point to the Unmarshal function @@ -184,6 +178,7 @@ func (ref *TypeReference) Elem() *TypeReference { if p, isPtr := ref.GO.(*types.Pointer); isPtr { return &TypeReference{ GO: p.Elem(), + Target: ref.Target, GQL: ref.GQL, CastType: ref.CastType, Definition: ref.Definition, @@ -196,6 +191,7 @@ func (ref *TypeReference) Elem() *TypeReference { if ref.IsSlice() { return &TypeReference{ GO: ref.GO.(*types.Slice).Elem(), + Target: ref.Target, GQL: ref.GQL.Elem, CastType: ref.CastType, Definition: ref.Definition, @@ -213,10 +209,7 @@ func (t *TypeReference) IsPtr() bool { } func (t *TypeReference) IsNilable() bool { - _, isPtr := t.GO.(*types.Pointer) - _, isMap := t.GO.(*types.Map) - _, isInterface := t.GO.(*types.Interface) - return isPtr || isMap || isInterface + return IsNilable(t.GO) } func (t *TypeReference) IsSlice() bool { @@ -244,7 +237,12 @@ func (t *TypeReference) UniquenessKey() string { nullability = "N" } - return nullability + t.Definition.Name + "2" + templates.TypeIdentifier(t.GO) + var elemNullability = "" + if t.GQL.Elem != nil && t.GQL.Elem.NonNull { + // Fix for #896 + elemNullability = "ᚄ" + } + return nullability + t.Definition.Name + "2" + templates.TypeIdentifier(t.GO) + elemNullability } func (t *TypeReference) MarshalFunc() string { @@ -271,6 +269,10 @@ func (t *TypeReference) UnmarshalFunc() string { return "unmarshal" + t.UniquenessKey() } +func (t *TypeReference) IsTargetNilable() bool { + return IsNilable(t.Target) +} + func (b *Binder) PushRef(ret *TypeReference) { b.References = append(b.References, ret) } @@ -292,6 +294,11 @@ func isIntf(t types.Type) bool { } func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret *TypeReference, err error) { + if !isValid(bindTarget) { + b.SawInvalid = true + return nil, fmt.Errorf("%s has an invalid type", schemaType.Name()) + } + var pkgName, typeName string def := b.schema.Types[schemaType.Name()] defer func() { @@ -350,7 +357,7 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret ref.GO = obj.Type() ref.IsMarshaler = true } else if underlying := basicUnderlying(obj.Type()); def.IsLeafType() && underlying != nil && underlying.Kind() == types.String { - // Special case for named types wrapping strings. Used by default enum implementations. + // TODO delete before v1. Backwards compatibility case for named types wrapping strings (see #595) ref.GO = obj.Type() ref.CastType = underlying @@ -366,6 +373,7 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret ref.GO = obj.Type() } + ref.Target = ref.GO ref.GO = b.CopyModifiersFromAst(schemaType, ref.GO) if bindTarget != nil { @@ -378,13 +386,21 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret return ref, nil } - return nil, fmt.Errorf("%s has type compatible with %s", schemaType.Name(), bindTarget.String()) + return nil, fmt.Errorf("%s is incompatible with %s", schemaType.Name(), bindTarget.String()) +} + +func isValid(t types.Type) bool { + basic, isBasic := t.(*types.Basic) + if !isBasic { + return true + } + return basic.Kind() != types.Invalid } func (b *Binder) CopyModifiersFromAst(t *ast.Type, base types.Type) types.Type { if t.Elem != nil { child := b.CopyModifiersFromAst(t.Elem, base) - if _, isStruct := child.Underlying().(*types.Struct); isStruct { + if _, isStruct := child.Underlying().(*types.Struct); isStruct && !b.cfg.OmitSliceElementPointers { child = types.NewPointer(child) } return types.NewSlice(child) @@ -395,13 +411,25 @@ func (b *Binder) CopyModifiersFromAst(t *ast.Type, base types.Type) types.Type { _, isInterface = named.Underlying().(*types.Interface) } - if !isInterface && !t.NonNull { + if !isInterface && !IsNilable(base) && !t.NonNull { return types.NewPointer(base) } return base } +func IsNilable(t types.Type) bool { + if namedType, isNamed := t.(*types.Named); isNamed { + return IsNilable(namedType.Underlying()) + } + _, isPtr := t.(*types.Pointer) + _, isMap := t.(*types.Map) + _, isInterface := t.(*types.Interface) + _, isSlice := t.(*types.Slice) + _, isChan := t.(*types.Chan) + return isPtr || isMap || isInterface || isSlice || isChan +} + func hasMethod(it types.Type, name string) bool { if ptr, isPtr := it.(*types.Pointer); isPtr { it = ptr.Elem() diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/config.go b/vendor/github.com/99designs/gqlgen/codegen/config/config.go index 1725adab0..ba939fcf5 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/config/config.go +++ b/vendor/github.com/99designs/gqlgen/codegen/config/config.go @@ -2,27 +2,38 @@ package config import ( "fmt" - "go/types" "io/ioutil" "os" "path/filepath" + "regexp" "sort" "strings" "github.com/99designs/gqlgen/internal/code" "github.com/pkg/errors" - "github.com/vektah/gqlparser" - "github.com/vektah/gqlparser/ast" - yaml "gopkg.in/yaml.v2" + "github.com/vektah/gqlparser/v2" + "github.com/vektah/gqlparser/v2/ast" + "gopkg.in/yaml.v2" ) type Config struct { - SchemaFilename StringList `yaml:"schema,omitempty"` - Exec PackageConfig `yaml:"exec"` - Model PackageConfig `yaml:"model"` - Resolver PackageConfig `yaml:"resolver,omitempty"` - Models TypeMap `yaml:"models,omitempty"` - StructTag string `yaml:"struct_tag,omitempty"` + SchemaFilename StringList `yaml:"schema,omitempty"` + Exec PackageConfig `yaml:"exec"` + Model PackageConfig `yaml:"model,omitempty"` + Federation PackageConfig `yaml:"federation,omitempty"` + Resolver ResolverConfig `yaml:"resolver,omitempty"` + AutoBind []string `yaml:"autobind"` + Models TypeMap `yaml:"models,omitempty"` + StructTag string `yaml:"struct_tag,omitempty"` + Directives map[string]DirectiveConfig `yaml:"directives,omitempty"` + OmitSliceElementPointers bool `yaml:"omit_slice_element_pointers,omitempty"` + SkipValidation bool `yaml:"skip_validation,omitempty"` + Sources []*ast.Source `yaml:"-"` + Packages *code.Packages `yaml:"-"` + Schema *ast.Schema `yaml:"-"` + + // Deprecated use Federation instead. Will be removed next release + Federated bool `yaml:"federated,omitempty"` } var cfgFilenames = []string{".gqlgen.yml", "gqlgen.yml", "gqlgen.yaml"} @@ -33,9 +44,30 @@ func DefaultConfig() *Config { SchemaFilename: StringList{"schema.graphql"}, Model: PackageConfig{Filename: "models_gen.go"}, Exec: PackageConfig{Filename: "generated.go"}, + Directives: map[string]DirectiveConfig{}, + Models: TypeMap{}, } } +// LoadDefaultConfig loads the default config so that it is ready to be used +func LoadDefaultConfig() (*Config, error) { + config := DefaultConfig() + + for _, filename := range config.SchemaFilename { + filename = filepath.ToSlash(filename) + var err error + var schemaRaw []byte + schemaRaw, err = ioutil.ReadFile(filename) + if err != nil { + return nil, errors.Wrap(err, "unable to open schema") + } + + config.Sources = append(config.Sources, &ast.Source{Name: filename, Input: string(schemaRaw)}) + } + + return config, nil +} + // LoadConfigFromDefaultLocations looks for a config file in the current directory, and all parent directories // walking up the tree. The closest config file will be returned. func LoadConfigFromDefaultLocations() (*Config, error) { @@ -51,6 +83,13 @@ func LoadConfigFromDefaultLocations() (*Config, error) { return LoadConfig(cfgFile) } +var path2regex = strings.NewReplacer( + `.`, `\.`, + `*`, `.+`, + `\`, `[\\/]`, + `/`, `[\\/]`, +) + // LoadConfig reads the gqlgen.yml config file func LoadConfig(filename string) (*Config, error) { config := DefaultConfig() @@ -64,12 +103,50 @@ func LoadConfig(filename string) (*Config, error) { return nil, errors.Wrap(err, "unable to parse config") } + defaultDirectives := map[string]DirectiveConfig{ + "skip": {SkipRuntime: true}, + "include": {SkipRuntime: true}, + "deprecated": {SkipRuntime: true}, + } + + for key, value := range defaultDirectives { + if _, defined := config.Directives[key]; !defined { + config.Directives[key] = value + } + } + preGlobbing := config.SchemaFilename config.SchemaFilename = StringList{} for _, f := range preGlobbing { - matches, err := filepath.Glob(f) - if err != nil { - return nil, errors.Wrapf(err, "failed to glob schema filename %s", f) + var matches []string + + // for ** we want to override default globbing patterns and walk all + // subdirectories to match schema files. + if strings.Contains(f, "**") { + pathParts := strings.SplitN(f, "**", 2) + rest := strings.TrimPrefix(strings.TrimPrefix(pathParts[1], `\`), `/`) + // turn the rest of the glob into a regex, anchored only at the end because ** allows + // for any number of dirs in between and walk will let us match against the full path name + globRe := regexp.MustCompile(path2regex.Replace(rest) + `$`) + + if err := filepath.Walk(pathParts[0], func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if globRe.MatchString(strings.TrimPrefix(path, pathParts[0])) { + matches = append(matches, path) + } + + return nil + }); err != nil { + return nil, errors.Wrapf(err, "failed to walk schema at root %s", pathParts[0]) + } + } else { + matches, err = filepath.Glob(f) + if err != nil { + return nil, errors.Wrapf(err, "failed to glob schema filename %s", f) + } } for _, m := range matches { @@ -80,13 +157,126 @@ func LoadConfig(filename string) (*Config, error) { } } + for _, filename := range config.SchemaFilename { + filename = filepath.ToSlash(filename) + var err error + var schemaRaw []byte + schemaRaw, err = ioutil.ReadFile(filename) + if err != nil { + return nil, errors.Wrap(err, "unable to open schema") + } + + config.Sources = append(config.Sources, &ast.Source{Name: filename, Input: string(schemaRaw)}) + } + return config, nil } -type PackageConfig struct { - Filename string `yaml:"filename,omitempty"` - Package string `yaml:"package,omitempty"` - Type string `yaml:"type,omitempty"` +func (c *Config) Init() error { + if c.Packages == nil { + c.Packages = &code.Packages{} + } + + if c.Schema == nil { + if err := c.LoadSchema(); err != nil { + return err + } + } + + err := c.injectTypesFromSchema() + if err != nil { + return err + } + + err = c.autobind() + if err != nil { + return err + } + + c.injectBuiltins() + + // prefetch all packages in one big packages.Load call + pkgs := []string{ + "github.com/99designs/gqlgen/graphql", + "github.com/99designs/gqlgen/graphql/introspection", + } + pkgs = append(pkgs, c.Models.ReferencedPackages()...) + pkgs = append(pkgs, c.AutoBind...) + c.Packages.LoadAll(pkgs...) + + // check everything is valid on the way out + err = c.check() + if err != nil { + return err + } + + return nil +} + +func (c *Config) injectTypesFromSchema() error { + c.Directives["goModel"] = DirectiveConfig{ + SkipRuntime: true, + } + + c.Directives["goField"] = DirectiveConfig{ + SkipRuntime: true, + } + + for _, schemaType := range c.Schema.Types { + if schemaType == c.Schema.Query || schemaType == c.Schema.Mutation || schemaType == c.Schema.Subscription { + continue + } + + if bd := schemaType.Directives.ForName("goModel"); bd != nil { + if ma := bd.Arguments.ForName("model"); ma != nil { + if mv, err := ma.Value.Value(nil); err == nil { + c.Models.Add(schemaType.Name, mv.(string)) + } + } + if ma := bd.Arguments.ForName("models"); ma != nil { + if mvs, err := ma.Value.Value(nil); err == nil { + for _, mv := range mvs.([]interface{}) { + c.Models.Add(schemaType.Name, mv.(string)) + } + } + } + } + + if schemaType.Kind == ast.Object || schemaType.Kind == ast.InputObject { + for _, field := range schemaType.Fields { + if fd := field.Directives.ForName("goField"); fd != nil { + forceResolver := c.Models[schemaType.Name].Fields[field.Name].Resolver + fieldName := c.Models[schemaType.Name].Fields[field.Name].FieldName + + if ra := fd.Arguments.ForName("forceResolver"); ra != nil { + if fr, err := ra.Value.Value(nil); err == nil { + forceResolver = fr.(bool) + } + } + + if na := fd.Arguments.ForName("name"); na != nil { + if fr, err := na.Value.Value(nil); err == nil { + fieldName = fr.(string) + } + } + + if c.Models[schemaType.Name].Fields == nil { + c.Models[schemaType.Name] = TypeMapEntry{ + Model: c.Models[schemaType.Name].Model, + Fields: map[string]TypeMapField{}, + } + } + + c.Models[schemaType.Name].Fields[field.Name] = TypeMapField{ + FieldName: fieldName, + Resolver: forceResolver, + } + } + } + } + } + + return nil } type TypeMapEntry struct { @@ -95,8 +285,9 @@ type TypeMapEntry struct { } type TypeMapField struct { - Resolver bool `yaml:"resolver"` - FieldName string `yaml:"fieldName"` + Resolver bool `yaml:"resolver"` + FieldName string `yaml:"fieldName"` + GeneratedMethod string `yaml:"-"` } type StringList []string @@ -128,90 +319,85 @@ func (a StringList) Has(file string) bool { return false } -func (c *PackageConfig) normalize() error { - if c.Filename == "" { - return errors.New("Filename is required") - } - c.Filename = abs(c.Filename) - // If Package is not set, first attempt to load the package at the output dir. If that fails - // fallback to just the base dir name of the output filename. - if c.Package == "" { - c.Package = code.NameForDir(c.Dir()) +func (c *Config) check() error { + if c.Models == nil { + c.Models = TypeMap{} } - return nil -} - -func (c *PackageConfig) ImportPath() string { - return code.ImportPathForDir(c.Dir()) -} - -func (c *PackageConfig) Dir() string { - return filepath.Dir(c.Filename) -} - -func (c *PackageConfig) Check() error { - if strings.ContainsAny(c.Package, "./\\") { - return fmt.Errorf("package should be the output package name only, do not include the output filename") - } - if c.Filename != "" && !strings.HasSuffix(c.Filename, ".go") { - return fmt.Errorf("filename should be path to a go source file") + type FilenamePackage struct { + Filename string + Package string + Declaree string } - return c.normalize() -} + fileList := map[string][]FilenamePackage{} -func (c *PackageConfig) Pkg() *types.Package { - return types.NewPackage(c.ImportPath(), c.Dir()) -} - -func (c *PackageConfig) IsDefined() bool { - return c.Filename != "" -} - -func (c *Config) Check() error { if err := c.Models.Check(); err != nil { return errors.Wrap(err, "config.models") } if err := c.Exec.Check(); err != nil { return errors.Wrap(err, "config.exec") } - if err := c.Model.Check(); err != nil { - return errors.Wrap(err, "config.model") + fileList[c.Exec.ImportPath()] = append(fileList[c.Exec.ImportPath()], FilenamePackage{ + Filename: c.Exec.Filename, + Package: c.Exec.Package, + Declaree: "exec", + }) + + if c.Model.IsDefined() { + if err := c.Model.Check(); err != nil { + return errors.Wrap(err, "config.model") + } + fileList[c.Model.ImportPath()] = append(fileList[c.Model.ImportPath()], FilenamePackage{ + Filename: c.Model.Filename, + Package: c.Model.Package, + Declaree: "model", + }) } if c.Resolver.IsDefined() { if err := c.Resolver.Check(); err != nil { return errors.Wrap(err, "config.resolver") } + fileList[c.Resolver.ImportPath()] = append(fileList[c.Resolver.ImportPath()], FilenamePackage{ + Filename: c.Resolver.Filename, + Package: c.Resolver.Package, + Declaree: "resolver", + }) } - - // check packages names against conflict, if present in the same dir - // and check filenames for uniqueness - packageConfigList := []PackageConfig{ - c.Model, - c.Exec, - c.Resolver, - } - filesMap := make(map[string]bool) - pkgConfigsByDir := make(map[string]PackageConfig) - for _, current := range packageConfigList { - _, fileFound := filesMap[current.Filename] - if fileFound { - return fmt.Errorf("filename %s defined more than once", current.Filename) + if c.Federation.IsDefined() { + if err := c.Federation.Check(); err != nil { + return errors.Wrap(err, "config.federation") } - filesMap[current.Filename] = true - previous, inSameDir := pkgConfigsByDir[current.Dir()] - if inSameDir && current.Package != previous.Package { - return fmt.Errorf("filenames %s and %s are in the same directory but have different package definitions", stripPath(current.Filename), stripPath(previous.Filename)) + fileList[c.Federation.ImportPath()] = append(fileList[c.Federation.ImportPath()], FilenamePackage{ + Filename: c.Federation.Filename, + Package: c.Federation.Package, + Declaree: "federation", + }) + if c.Federation.ImportPath() != c.Exec.ImportPath() { + return fmt.Errorf("federation and exec must be in the same package") } - pkgConfigsByDir[current.Dir()] = current + } + if c.Federated { + return fmt.Errorf("federated has been removed, instead use\nfederation:\n filename: path/to/federated.go") } - return c.normalize() -} + for importPath, pkg := range fileList { + for _, file1 := range pkg { + for _, file2 := range pkg { + if file1.Package != file2.Package { + return fmt.Errorf("%s and %s define the same import path (%s) with different package names (%s vs %s)", + file1.Declaree, + file2.Declaree, + importPath, + file1.Package, + file2.Package, + ) + } + } + } + } -func stripPath(path string) string { - return filepath.Base(path) + return nil } type TypeMap map[string]TypeMapEntry @@ -259,10 +445,14 @@ func (tm TypeMap) ReferencedPackages() []string { return pkgs } -func (tm TypeMap) Add(Name string, goType string) { - modelCfg := tm[Name] +func (tm TypeMap) Add(name string, goType string) { + modelCfg := tm[name] modelCfg.Model = append(modelCfg.Model, goType) - tm[Name] = modelCfg + tm[name] = modelCfg +} + +type DirectiveConfig struct { + SkipRuntime bool `yaml:"skip_runtime"` } func inStrSlice(haystack []string, needle string) bool { @@ -307,29 +497,54 @@ func findCfgInDir(dir string) string { return "" } -func (c *Config) normalize() error { - if err := c.Model.normalize(); err != nil { - return errors.Wrap(err, "model") +func (c *Config) autobind() error { + if len(c.AutoBind) == 0 { + return nil } - if err := c.Exec.normalize(); err != nil { - return errors.Wrap(err, "exec") - } + ps := c.Packages.LoadAll(c.AutoBind...) - if c.Resolver.IsDefined() { - if err := c.Resolver.normalize(); err != nil { - return errors.Wrap(err, "resolver") + for _, t := range c.Schema.Types { + if c.Models.UserDefined(t.Name) { + continue + } + + for i, p := range ps { + if p == nil { + return fmt.Errorf("unable to load %s - make sure you're using an import path to a package that exists", c.AutoBind[i]) + } + if t := p.Types.Scope().Lookup(t.Name); t != nil { + c.Models.Add(t.Name(), t.Pkg().Path()+"."+t.Name()) + break + } } } - if c.Models == nil { - c.Models = TypeMap{} + for i, t := range c.Models { + for j, m := range t.Model { + pkg, typename := code.PkgAndType(m) + + // skip anything that looks like an import path + if strings.Contains(pkg, "/") { + continue + } + + for _, p := range ps { + if p.Name != pkg { + continue + } + if t := p.Types.Scope().Lookup(typename); t != nil { + c.Models[i].Model[j] = t.Pkg().Path() + "." + t.Name() + break + } + } + } } return nil } -func (c *Config) InjectBuiltins(s *ast.Schema) { +func (c *Config) injectBuiltins() { builtins := TypeMap{ "__Directive": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Directive"}}, "__DirectiveLocation": {Model: StringList{"github.com/99designs/gqlgen/graphql.String"}}, @@ -370,35 +585,36 @@ func (c *Config) InjectBuiltins(s *ast.Schema) { } for typeName, entry := range extraBuiltins { - if t, ok := s.Types[typeName]; !c.Models.Exists(typeName) && ok && t.Kind == ast.Scalar { + if t, ok := c.Schema.Types[typeName]; !c.Models.Exists(typeName) && ok && t.Kind == ast.Scalar { c.Models[typeName] = entry } } } -func (c *Config) LoadSchema() (*ast.Schema, map[string]string, error) { - schemaStrings := map[string]string{} - - var sources []*ast.Source - - for _, filename := range c.SchemaFilename { - filename = filepath.ToSlash(filename) - var err error - var schemaRaw []byte - schemaRaw, err = ioutil.ReadFile(filename) - if err != nil { - fmt.Fprintln(os.Stderr, "unable to open schema: "+err.Error()) - os.Exit(1) - } - schemaStrings[filename] = string(schemaRaw) - sources = append(sources, &ast.Source{Name: filename, Input: schemaStrings[filename]}) +func (c *Config) LoadSchema() error { + if c.Packages != nil { + c.Packages = &code.Packages{} } - schema, err := gqlparser.LoadSchema(sources...) + if err := c.check(); err != nil { + return err + } + + schema, err := gqlparser.LoadSchema(c.Sources...) if err != nil { - return nil, nil, err + return err } - return schema, schemaStrings, nil + + if schema.Query == nil { + schema.Query = &ast.Definition{ + Kind: ast.Object, + Name: "Query", + } + schema.Types["Query"] = schema.Query + } + + c.Schema = schema + return nil } func abs(path string) string { diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/package.go b/vendor/github.com/99designs/gqlgen/codegen/config/package.go new file mode 100644 index 000000000..a96459381 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/codegen/config/package.go @@ -0,0 +1,62 @@ +package config + +import ( + "fmt" + "go/types" + "path/filepath" + "strings" + + "github.com/99designs/gqlgen/internal/code" +) + +type PackageConfig struct { + Filename string `yaml:"filename,omitempty"` + Package string `yaml:"package,omitempty"` +} + +func (c *PackageConfig) ImportPath() string { + if !c.IsDefined() { + return "" + } + return code.ImportPathForDir(c.Dir()) +} + +func (c *PackageConfig) Dir() string { + if !c.IsDefined() { + return "" + } + return filepath.Dir(c.Filename) +} + +func (c *PackageConfig) Pkg() *types.Package { + if !c.IsDefined() { + return nil + } + return types.NewPackage(c.ImportPath(), c.Package) +} + +func (c *PackageConfig) IsDefined() bool { + return c.Filename != "" +} + +func (c *PackageConfig) Check() error { + if strings.ContainsAny(c.Package, "./\\") { + return fmt.Errorf("package should be the output package name only, do not include the output filename") + } + if c.Filename == "" { + return fmt.Errorf("filename must be specified") + } + if !strings.HasSuffix(c.Filename, ".go") { + return fmt.Errorf("filename should be path to a go source file") + } + + c.Filename = abs(c.Filename) + + // If Package is not set, first attempt to load the package at the output dir. If that fails + // fallback to just the base dir name of the output filename. + if c.Package == "" { + c.Package = code.NameForDir(c.Dir()) + } + + return nil +} diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/resolver.go b/vendor/github.com/99designs/gqlgen/codegen/config/resolver.go new file mode 100644 index 000000000..cd03f1887 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/codegen/config/resolver.go @@ -0,0 +1,100 @@ +package config + +import ( + "fmt" + "go/types" + "path/filepath" + "strings" + + "github.com/99designs/gqlgen/internal/code" +) + +type ResolverConfig struct { + Filename string `yaml:"filename,omitempty"` + FilenameTemplate string `yaml:"filename_template,omitempty"` + Package string `yaml:"package,omitempty"` + Type string `yaml:"type,omitempty"` + Layout ResolverLayout `yaml:"layout,omitempty"` + DirName string `yaml:"dir"` +} + +type ResolverLayout string + +var ( + LayoutSingleFile ResolverLayout = "single-file" + LayoutFollowSchema ResolverLayout = "follow-schema" +) + +func (r *ResolverConfig) Check() error { + if r.Layout == "" { + r.Layout = LayoutSingleFile + } + if r.Type == "" { + r.Type = "Resolver" + } + + switch r.Layout { + case LayoutSingleFile: + if r.Filename == "" { + return fmt.Errorf("filename must be specified with layout=%s", r.Layout) + } + if !strings.HasSuffix(r.Filename, ".go") { + return fmt.Errorf("filename should be path to a go source file with layout=%s", r.Layout) + } + r.Filename = abs(r.Filename) + case LayoutFollowSchema: + if r.DirName == "" { + return fmt.Errorf("dirname must be specified with layout=%s", r.Layout) + } + r.DirName = abs(r.DirName) + if r.Filename == "" { + r.Filename = filepath.Join(r.DirName, "resolver.go") + } else { + r.Filename = abs(r.Filename) + } + default: + return fmt.Errorf("invalid layout %s. must be %s or %s", r.Layout, LayoutSingleFile, LayoutFollowSchema) + } + + if strings.ContainsAny(r.Package, "./\\") { + return fmt.Errorf("package should be the output package name only, do not include the output filename") + } + + if r.Package == "" && r.Dir() != "" { + r.Package = code.NameForDir(r.Dir()) + } + + return nil +} + +func (r *ResolverConfig) ImportPath() string { + if r.Dir() == "" { + return "" + } + return code.ImportPathForDir(r.Dir()) +} + +func (r *ResolverConfig) Dir() string { + switch r.Layout { + case LayoutSingleFile: + if r.Filename == "" { + return "" + } + return filepath.Dir(r.Filename) + case LayoutFollowSchema: + return r.DirName + default: + panic("invalid layout " + r.Layout) + } +} + +func (r *ResolverConfig) Pkg() *types.Package { + if r.Dir() == "" { + return nil + } + return types.NewPackage(r.ImportPath(), r.Package) +} + +func (r *ResolverConfig) IsDefined() bool { + return r.Filename != "" || r.DirName != "" +} diff --git a/vendor/github.com/99designs/gqlgen/codegen/data.go b/vendor/github.com/99designs/gqlgen/codegen/data.go index f2ea70b4a..bedbef9d4 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/data.go +++ b/vendor/github.com/99designs/gqlgen/codegen/data.go @@ -4,9 +4,10 @@ import ( "fmt" "sort" - "github.com/99designs/gqlgen/codegen/config" "github.com/pkg/errors" - "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/v2/ast" + + "github.com/99designs/gqlgen/codegen/config" ) // Data is a unified model of the code to be generated. Plugins may modify this structure to do things like implement @@ -14,8 +15,7 @@ import ( type Data struct { Config *config.Config Schema *ast.Schema - SchemaStr map[string]string - Directives map[string]*Directive + Directives DirectiveList Objects Objects Inputs Objects Interfaces map[string]*Interface @@ -30,7 +30,6 @@ type Data struct { type builder struct { Config *config.Config Schema *ast.Schema - SchemaStr map[string]string Binder *config.Binder Directives map[string]*Directive } @@ -38,26 +37,12 @@ type builder struct { func BuildData(cfg *config.Config) (*Data, error) { b := builder{ Config: cfg, + Schema: cfg.Schema, } + b.Binder = b.Config.NewBinder() + var err error - b.Schema, b.SchemaStr, err = cfg.LoadSchema() - if err != nil { - return nil, err - } - - err = cfg.Check() - if err != nil { - return nil, err - } - - cfg.InjectBuiltins(b.Schema) - - b.Binder, err = b.Config.NewBinder(b.Schema) - if err != nil { - return nil, err - } - b.Directives, err = b.buildDirectives() if err != nil { return nil, err @@ -74,7 +59,6 @@ func BuildData(cfg *config.Config) (*Data, error) { Config: cfg, Directives: dataDirectives, Schema: b.Schema, - SchemaStr: b.SchemaStr, Interfaces: map[string]*Interface{}, } @@ -96,7 +80,10 @@ func BuildData(cfg *config.Config) (*Data, error) { s.Inputs = append(s.Inputs, input) case ast.Union, ast.Interface: - s.Interfaces[schemaType.Name] = b.buildInterface(schemaType) + s.Interfaces[schemaType.Name], err = b.buildInterface(schemaType) + if err != nil { + return nil, errors.Wrap(err, "unable to bind to interface") + } } } @@ -118,10 +105,7 @@ func BuildData(cfg *config.Config) (*Data, error) { return nil, err } - s.ReferencedTypes, err = b.buildTypes() - if err != nil { - return nil, err - } + s.ReferencedTypes = b.buildTypes() sort.Slice(s.Objects, func(i, j int) bool { return s.Objects[i].Definition.Name < s.Objects[j].Definition.Name @@ -131,6 +115,17 @@ func BuildData(cfg *config.Config) (*Data, error) { return s.Inputs[i].Definition.Name < s.Inputs[j].Definition.Name }) + if b.Binder.SawInvalid { + // if we have a syntax error, show it + err := cfg.Packages.Errors() + if len(err) > 0 { + return nil, err + } + + // otherwise show a generic error message + return nil, fmt.Errorf("invalid types were encountered while traversing the go source code, this probably means the invalid code generated isnt correct. add try adding -v to debug") + } + return &s, nil } diff --git a/vendor/github.com/99designs/gqlgen/codegen/directive.go b/vendor/github.com/99designs/gqlgen/codegen/directive.go index 5a27e8ace..5d4c038ff 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/directive.go +++ b/vendor/github.com/99designs/gqlgen/codegen/directive.go @@ -7,15 +7,46 @@ import ( "github.com/99designs/gqlgen/codegen/templates" "github.com/pkg/errors" - "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/v2/ast" ) +type DirectiveList map[string]*Directive + +//LocationDirectives filter directives by location +func (dl DirectiveList) LocationDirectives(location string) DirectiveList { + return locationDirectives(dl, ast.DirectiveLocation(location)) +} + type Directive struct { + *ast.DirectiveDefinition Name string Args []*FieldArgument Builtin bool } +//IsLocation check location directive +func (d *Directive) IsLocation(location ...ast.DirectiveLocation) bool { + for _, l := range d.Locations { + for _, a := range location { + if l == a { + return true + } + } + } + + return false +} + +func locationDirectives(directives DirectiveList, location ...ast.DirectiveLocation) map[string]*Directive { + mDirectives := make(map[string]*Directive) + for name, d := range directives { + if d.IsLocation(location...) { + mDirectives[name] = d + } + } + return mDirectives +} + func (b *builder) buildDirectives() (map[string]*Directive, error) { directives := make(map[string]*Directive, len(b.Schema.Directives)) @@ -24,11 +55,6 @@ func (b *builder) buildDirectives() (map[string]*Directive, error) { return nil, errors.Errorf("directive with name %s already exists", name) } - var builtin bool - if name == "skip" || name == "include" || name == "deprecated" { - builtin = true - } - var args []*FieldArgument for _, arg := range dir.Arguments { tr, err := b.Binder.TypeReference(arg.Type, nil) @@ -53,9 +79,10 @@ func (b *builder) buildDirectives() (map[string]*Directive, error) { } directives[name] = &Directive{ - Name: name, - Args: args, - Builtin: builtin, + DirectiveDefinition: dir, + Name: name, + Args: args, + Builtin: b.Config.Directives[name].SkipRuntime, } } @@ -92,8 +119,10 @@ func (b *builder) getDirectives(list ast.DirectiveList) ([]*Directive, error) { }) } dirs[i] = &Directive{ - Name: d.Name, - Args: args, + Name: d.Name, + Args: args, + DirectiveDefinition: list[i].Definition, + Builtin: b.Config.Directives[d.Name].SkipRuntime, } } @@ -119,18 +148,12 @@ func (d *Directive) CallArgs() string { return strings.Join(args, ", ") } -func (d *Directive) ResolveArgs(obj string, next string) string { - args := []string{"ctx", obj, next} +func (d *Directive) ResolveArgs(obj string, next int) string { + args := []string{"ctx", obj, fmt.Sprintf("directive%d", next)} for _, arg := range d.Args { - dArg := "&" + arg.VarName - if !arg.TypeReference.IsPtr() { - if arg.Value != nil { - dArg = templates.Dump(arg.Value) - } else { - dArg = templates.Dump(arg.Default) - } - } else if arg.Value == nil && arg.Default == nil { + dArg := arg.VarName + if arg.Value == nil && arg.Default == nil { dArg = "nil" } @@ -144,7 +167,7 @@ func (d *Directive) Declaration() string { res := ucFirst(d.Name) + " func(ctx context.Context, obj interface{}, next graphql.Resolver" for _, arg := range d.Args { - res += fmt.Sprintf(", %s %s", arg.Name, templates.CurrentImports.LookupType(arg.TypeReference.GO)) + res += fmt.Sprintf(", %s %s", templates.ToGoPrivate(arg.Name), templates.CurrentImports.LookupType(arg.TypeReference.GO)) } res += ") (res interface{}, err error)" diff --git a/vendor/github.com/99designs/gqlgen/codegen/directives.gotpl b/vendor/github.com/99designs/gqlgen/codegen/directives.gotpl new file mode 100644 index 000000000..e6d2455f6 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/codegen/directives.gotpl @@ -0,0 +1,149 @@ +{{ define "implDirectives" }}{{ $in := .DirectiveObjName }} + {{- range $i, $directive := .ImplDirectives -}} + directive{{add $i 1}} := func(ctx context.Context) (interface{}, error) { + {{- range $arg := $directive.Args }} + {{- if notNil "Value" $arg }} + {{ $arg.VarName }}, err := ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, {{ $arg.Value | dump }}) + if err != nil{ + return nil, err + } + {{- else if notNil "Default" $arg }} + {{ $arg.VarName }}, err := ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, {{ $arg.Default | dump }}) + if err != nil{ + return nil, err + } + {{- end }} + {{- end }} + if ec.directives.{{$directive.Name|ucFirst}} == nil { + return nil, errors.New("directive {{$directive.Name}} is not implemented") + } + return ec.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs $in $i }}) + } + {{ end -}} +{{ end }} + +{{define "queryDirectives"}} + for _, d := range obj.Directives { + switch d.Name { + {{- range $directive := . }} + case "{{$directive.Name}}": + {{- if $directive.Args }} + rawArgs := d.ArgumentMap(ec.Variables) + args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + {{- end }} + n := next + next = func(ctx context.Context) (interface{}, error) { + if ec.directives.{{$directive.Name|ucFirst}} == nil { + return nil, errors.New("directive {{$directive.Name}} is not implemented") + } + return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}}) + } + {{- end }} + } + } + tmp, err := next(ctx) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if data, ok := tmp.(graphql.Marshaler); ok { + return data + } + ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp) + return graphql.Null +{{end}} + +{{ if .Directives.LocationDirectives "QUERY" }} +func (ec *executionContext) _queryMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) graphql.Marshaler { + {{ template "queryDirectives" .Directives.LocationDirectives "QUERY" }} +} +{{ end }} + +{{ if .Directives.LocationDirectives "MUTATION" }} +func (ec *executionContext) _mutationMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) graphql.Marshaler { + {{ template "queryDirectives" .Directives.LocationDirectives "MUTATION" }} +} +{{ end }} + +{{ if .Directives.LocationDirectives "SUBSCRIPTION" }} +func (ec *executionContext) _subscriptionMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) func() graphql.Marshaler { + for _, d := range obj.Directives { + switch d.Name { + {{- range $directive := .Directives.LocationDirectives "SUBSCRIPTION" }} + case "{{$directive.Name}}": + {{- if $directive.Args }} + rawArgs := d.ArgumentMap(ec.Variables) + args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs) + if err != nil { + ec.Error(ctx, err) + return func() graphql.Marshaler { + return graphql.Null + } + } + {{- end }} + n := next + next = func(ctx context.Context) (interface{}, error) { + if ec.directives.{{$directive.Name|ucFirst}} == nil { + return nil, errors.New("directive {{$directive.Name}} is not implemented") + } + return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}}) + } + {{- end }} + } + } + tmp, err := next(ctx) + if err != nil { + ec.Error(ctx, err) + return func() graphql.Marshaler { + return graphql.Null + } + } + if data, ok := tmp.(func() graphql.Marshaler); ok { + return data + } + ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp) + return func() graphql.Marshaler { + return graphql.Null + } +} +{{ end }} + +{{ if .Directives.LocationDirectives "FIELD" }} + func (ec *executionContext) _fieldMiddleware(ctx context.Context, obj interface{}, next graphql.Resolver) interface{} { + {{- if .Directives.LocationDirectives "FIELD" }} + fc := graphql.GetFieldContext(ctx) + for _, d := range fc.Field.Directives { + switch d.Name { + {{- range $directive := .Directives.LocationDirectives "FIELD" }} + case "{{$directive.Name}}": + {{- if $directive.Args }} + rawArgs := d.ArgumentMap(ec.Variables) + args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs) + if err != nil { + ec.Error(ctx, err) + return nil + } + {{- end }} + n := next + next = func(ctx context.Context) (interface{}, error) { + if ec.directives.{{$directive.Name|ucFirst}} == nil { + return nil, errors.New("directive {{$directive.Name}} is not implemented") + } + return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}}) + } + {{- end }} + } + } + {{- end }} + res, err := ec.ResolverMiddleware(ctx, next) + if err != nil { + ec.Error(ctx, err) + return nil + } + return res + } +{{ end }} diff --git a/vendor/github.com/99designs/gqlgen/codegen/field.go b/vendor/github.com/99designs/gqlgen/codegen/field.go index f5f7b2213..26ed6b551 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/field.go +++ b/vendor/github.com/99designs/gqlgen/codegen/field.go @@ -11,7 +11,7 @@ import ( "github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/templates" "github.com/pkg/errors" - "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/v2/ast" ) type Field struct { @@ -27,6 +27,7 @@ type Field struct { NoErr bool // If this is bound to a go method, does that method have an error as the second argument Object *Object // A link back to the parent object Default interface{} // The default value + Stream bool // does this field return a channel? Directives []*Directive } @@ -73,17 +74,26 @@ func (b *builder) buildField(obj *Object, field *ast.FieldDefinition) (*Field, e return &f, nil } -func (b *builder) bindField(obj *Object, f *Field) error { +func (b *builder) bindField(obj *Object, f *Field) (errret error) { defer func() { if f.TypeReference == nil { tr, err := b.Binder.TypeReference(f.Type, nil) if err != nil { - panic(err) + errret = err } f.TypeReference = tr } + if f.TypeReference != nil { + dirs, err := b.getDirectives(f.TypeReference.Definition.Directives) + if err != nil { + errret = err + } + f.Directives = append(dirs, f.Directives...) + } }() + f.Stream = obj.Stream + switch { case f.Name == "__schema": f.GoFieldType = GoFieldMethod @@ -95,6 +105,18 @@ func (b *builder) bindField(obj *Object, f *Field) error { f.GoReceiverName = "ec" f.GoFieldName = "introspectType" return nil + case f.Name == "_entities": + f.GoFieldType = GoFieldMethod + f.GoReceiverName = "ec" + f.GoFieldName = "__resolve_entities" + f.MethodHasContext = true + return nil + case f.Name == "_service": + f.GoFieldType = GoFieldMethod + f.GoReceiverName = "ec" + f.GoFieldName = "__resolve__service" + f.MethodHasContext = true + return nil case obj.Root: f.IsResolver = true return nil @@ -181,75 +203,155 @@ func (b *builder) bindField(obj *Object, f *Field) error { } } -// findField attempts to match the name to a struct field with the following -// priorites: -// 1. Any method with a matching name -// 2. Any Fields with a struct tag (see config.StructTag) -// 3. Any fields with a matching name -// 4. Same logic again for embedded fields -func (b *builder) findBindTarget(named *types.Named, name string) (types.Object, error) { - for i := 0; i < named.NumMethods(); i++ { - method := named.Method(i) - if !method.Exported() { - continue - } - - if !strings.EqualFold(method.Name(), name) { - continue - } - - return method, nil +// findBindTarget attempts to match the name to a field or method on a Type +// with the following priorites: +// 1. Any Fields with a struct tag (see config.StructTag). Errors if more than one match is found +// 2. Any method or field with a matching name. Errors if more than one match is found +// 3. Same logic again for embedded fields +func (b *builder) findBindTarget(t types.Type, name string) (types.Object, error) { + // NOTE: a struct tag will override both methods and fields + // Bind to struct tag + found, err := b.findBindStructTagTarget(t, name) + if found != nil || err != nil { + return found, err } - strukt, ok := named.Underlying().(*types.Struct) - if !ok { - return nil, fmt.Errorf("not a struct") + // Search for a method to bind to + foundMethod, err := b.findBindMethodTarget(t, name) + if err != nil { + return nil, err } - return b.findBindStructTarget(strukt, name) + + // Search for a field to bind to + foundField, err := b.findBindFieldTarget(t, name) + if err != nil { + return nil, err + } + + switch { + case foundField == nil && foundMethod != nil: + // Bind to method + return foundMethod, nil + case foundField != nil && foundMethod == nil: + // Bind to field + return foundField, nil + case foundField != nil && foundMethod != nil: + // Error + return nil, errors.Errorf("found more than one way to bind for %s", name) + } + + // Search embeds + return b.findBindEmbedsTarget(t, name) } -func (b *builder) findBindStructTarget(strukt *types.Struct, name string) (types.Object, error) { - // struct tags have the highest priority - if b.Config.StructTag != "" { - var foundField *types.Var - for i := 0; i < strukt.NumFields(); i++ { - field := strukt.Field(i) - if !field.Exported() { +func (b *builder) findBindStructTagTarget(in types.Type, name string) (types.Object, error) { + if b.Config.StructTag == "" { + return nil, nil + } + + switch t := in.(type) { + case *types.Named: + return b.findBindStructTagTarget(t.Underlying(), name) + case *types.Struct: + var found types.Object + for i := 0; i < t.NumFields(); i++ { + field := t.Field(i) + if !field.Exported() || field.Embedded() { continue } - tags := reflect.StructTag(strukt.Tag(i)) + tags := reflect.StructTag(t.Tag(i)) if val, ok := tags.Lookup(b.Config.StructTag); ok && equalFieldName(val, name) { - if foundField != nil { + if found != nil { return nil, errors.Errorf("tag %s is ambigious; multiple fields have the same tag value of %s", b.Config.StructTag, val) } - foundField = field + found = field } } - if foundField != nil { - return foundField, nil - } + + return found, nil } - // Then matching field names - for i := 0; i < strukt.NumFields(); i++ { - field := strukt.Field(i) - if !field.Exported() { - continue - } - if equalFieldName(field.Name(), name) { // aqui! - return field, nil + return nil, nil +} + +func (b *builder) findBindMethodTarget(in types.Type, name string) (types.Object, error) { + switch t := in.(type) { + case *types.Named: + if _, ok := t.Underlying().(*types.Interface); ok { + return b.findBindMethodTarget(t.Underlying(), name) } + + return b.findBindMethoderTarget(t.Method, t.NumMethods(), name) + case *types.Interface: + // FIX-ME: Should use ExplicitMethod here? What's the difference? + return b.findBindMethoderTarget(t.Method, t.NumMethods(), name) } - // Then look in embedded structs - for i := 0; i < strukt.NumFields(); i++ { - field := strukt.Field(i) - if !field.Exported() { + return nil, nil +} + +func (b *builder) findBindMethoderTarget(methodFunc func(i int) *types.Func, methodCount int, name string) (types.Object, error) { + var found types.Object + for i := 0; i < methodCount; i++ { + method := methodFunc(i) + if !method.Exported() || !strings.EqualFold(method.Name(), name) { continue } - if !field.Anonymous() { + if found != nil { + return nil, errors.Errorf("found more than one matching method to bind for %s", name) + } + + found = method + } + + return found, nil +} + +func (b *builder) findBindFieldTarget(in types.Type, name string) (types.Object, error) { + switch t := in.(type) { + case *types.Named: + return b.findBindFieldTarget(t.Underlying(), name) + case *types.Struct: + var found types.Object + for i := 0; i < t.NumFields(); i++ { + field := t.Field(i) + if !field.Exported() || !equalFieldName(field.Name(), name) { + continue + } + + if found != nil { + return nil, errors.Errorf("found more than one matching field to bind for %s", name) + } + + found = field + } + + return found, nil + } + + return nil, nil +} + +func (b *builder) findBindEmbedsTarget(in types.Type, name string) (types.Object, error) { + switch t := in.(type) { + case *types.Named: + return b.findBindEmbedsTarget(t.Underlying(), name) + case *types.Struct: + return b.findBindStructEmbedsTarget(t, name) + case *types.Interface: + return b.findBindInterfaceEmbedsTarget(t, name) + } + + return nil, nil +} + +func (b *builder) findBindStructEmbedsTarget(strukt *types.Struct, name string) (types.Object, error) { + var found types.Object + for i := 0; i < strukt.NumFields(); i++ { + field := strukt.Field(i) + if !field.Embedded() { continue } @@ -258,33 +360,68 @@ func (b *builder) findBindStructTarget(strukt *types.Struct, name string) (types fieldType = ptr.Elem() } - switch fieldType := fieldType.(type) { - case *types.Named: - f, err := b.findBindTarget(fieldType, name) - if err != nil { - return nil, err - } - if f != nil { - return f, nil - } - case *types.Struct: - f, err := b.findBindStructTarget(fieldType, name) - if err != nil { - return nil, err - } - if f != nil { - return f, nil - } - default: - panic(fmt.Errorf("unknown embedded field type %T", field.Type())) + f, err := b.findBindTarget(fieldType, name) + if err != nil { + return nil, err + } + + if f != nil && found != nil { + return nil, errors.Errorf("found more than one way to bind for %s", name) + } + + if f != nil { + found = f } } - return nil, nil + return found, nil +} + +func (b *builder) findBindInterfaceEmbedsTarget(iface *types.Interface, name string) (types.Object, error) { + var found types.Object + for i := 0; i < iface.NumEmbeddeds(); i++ { + embeddedType := iface.EmbeddedType(i) + + f, err := b.findBindTarget(embeddedType, name) + if err != nil { + return nil, err + } + + if f != nil && found != nil { + return nil, errors.Errorf("found more than one way to bind for %s", name) + } + + if f != nil { + found = f + } + } + + return found, nil } func (f *Field) HasDirectives() bool { - return len(f.Directives) > 0 + return len(f.ImplDirectives()) > 0 +} + +func (f *Field) DirectiveObjName() string { + if f.Object.Root { + return "nil" + } + return f.GoReceiverName +} + +func (f *Field) ImplDirectives() []*Directive { + var d []*Directive + loc := ast.LocationFieldDefinition + if f.Object.IsInputType() { + loc = ast.LocationInputFieldDefinition + } + for i := range f.Directives { + if !f.Directives[i].Builtin && f.Directives[i].IsLocation(loc, ast.LocationObject) { + d = append(d, f.Directives[i]) + } + } + return d } func (f *Field) IsReserved() bool { @@ -338,7 +475,7 @@ func (f *Field) ShortResolverDeclaration() string { res := "(ctx context.Context" if !f.Object.Root { - res += fmt.Sprintf(", obj *%s", templates.CurrentImports.LookupType(f.Object.Type)) + res += fmt.Sprintf(", obj %s", templates.CurrentImports.LookupType(f.Object.Reference())) } for _, arg := range f.Args { res += fmt.Sprintf(", %s %s", arg.VarName, templates.CurrentImports.LookupType(arg.TypeReference.GO)) @@ -354,7 +491,7 @@ func (f *Field) ShortResolverDeclaration() string { } func (f *Field) ComplexitySignature() string { - res := fmt.Sprintf("func(childComplexity int") + res := "func(childComplexity int" for _, arg := range f.Args { res += fmt.Sprintf(", %s %s", arg.VarName, templates.CurrentImports.LookupType(arg.TypeReference.GO)) } @@ -363,16 +500,16 @@ func (f *Field) ComplexitySignature() string { } func (f *Field) ComplexityArgs() string { - var args []string - for _, arg := range f.Args { - args = append(args, "args["+strconv.Quote(arg.Name)+"].("+templates.CurrentImports.LookupType(arg.TypeReference.GO)+")") + args := make([]string, len(f.Args)) + for i, arg := range f.Args { + args[i] = "args[" + strconv.Quote(arg.Name) + "].(" + templates.CurrentImports.LookupType(arg.TypeReference.GO) + ")" } return strings.Join(args, ", ") } func (f *Field) CallArgs() string { - var args []string + args := make([]string, 0, len(f.Args)+2) if f.IsResolver { args = append(args, "rctx") @@ -380,10 +517,8 @@ func (f *Field) CallArgs() string { if !f.Object.Root { args = append(args, "obj") } - } else { - if f.MethodHasContext { - args = append(args, "ctx") - } + } else if f.MethodHasContext { + args = append(args, "ctx") } for _, arg := range f.Args { diff --git a/vendor/github.com/99designs/gqlgen/codegen/field.gotpl b/vendor/github.com/99designs/gqlgen/codegen/field.gotpl index 9718a08aa..993625b74 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/field.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/field.gotpl @@ -1,29 +1,57 @@ {{- range $object := .Objects }}{{- range $field := $object.Fields }} -{{- if $object.Stream }} - func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Context, field graphql.CollectedField) func() graphql.Marshaler { - ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ - Field: field, - Args: nil, - }) - {{- if $field.Args }} - rawArgs := field.ArgumentMap(ec.Variables) - args, err := ec.{{ $field.ArgsFunc }}(ctx,rawArgs) - if err != nil { - ec.Error(ctx, err) - return nil - } - {{- end }} - // FIXME: subscriptions are missing request middleware stack https://github.com/99designs/gqlgen/issues/259 - // and Tracer stack - rctx := ctx - results, err := ec.resolvers.{{ $field.ShortInvocation }} +func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Context, field graphql.CollectedField{{ if not $object.Root }}, obj {{$object.Reference | ref}}{{end}}) (ret {{ if $object.Stream }}func(){{ end }}graphql.Marshaler) { + {{- $null := "graphql.Null" }} + {{- if $object.Stream }} + {{- $null = "nil" }} + {{- end }} + defer func () { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = {{ $null }} + } + }() + fc := &graphql.FieldContext{ + Object: {{$object.Name|quote}}, + Field: field, + Args: nil, + IsMethod: {{or $field.IsMethod $field.IsResolver}}, + } + + ctx = graphql.WithFieldContext(ctx, fc) + {{- if $field.Args }} + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.{{ $field.ArgsFunc }}(ctx,rawArgs) if err != nil { ec.Error(ctx, err) - return nil + return {{ $null }} } + fc.Args = args + {{- end }} + {{- if $.Directives.LocationDirectives "FIELD" }} + resTmp := ec._fieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) { + {{ template "field" $field }} + }) + {{ else }} + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + {{ template "field" $field }} + }) + if err != nil { + ec.Error(ctx, err) + return {{ $null }} + } + {{- end }} + if resTmp == nil { + {{- if $field.TypeReference.GQL.NonNull }} + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + {{- end }} + return {{ $null }} + } + {{- if $object.Stream }} return func() graphql.Marshaler { - res, ok := <-results + res, ok := <-resTmp.(<-chan {{$field.TypeReference.GO | ref}}) if !ok { return nil } @@ -35,66 +63,60 @@ w.Write([]byte{'}'}) }) } - } -{{ else }} - func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Context, field graphql.CollectedField{{ if not $object.Root }}, obj {{$object.Reference | ref}}{{end}}) graphql.Marshaler { - ctx = ec.Tracer.StartFieldExecution(ctx, field) - defer func () { ec.Tracer.EndFieldExecution(ctx) }() - rctx := &graphql.ResolverContext{ - Object: {{$object.Name|quote}}, - Field: field, - Args: nil, - IsMethod: {{or $field.IsMethod $field.IsResolver}}, - } - ctx = graphql.WithResolverContext(ctx, rctx) - {{- if $field.Args }} - rawArgs := field.ArgumentMap(ec.Variables) - args, err := ec.{{ $field.ArgsFunc }}(ctx,rawArgs) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - rctx.Args = args - {{- end }} - ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) - resTmp := ec.FieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - {{- if $field.IsResolver }} - return ec.resolvers.{{ $field.ShortInvocation }} - {{- else if $field.IsMap }} - switch v := {{$field.GoReceiverName}}[{{$field.Name|quote}}].(type) { - case {{$field.TypeReference.GO | ref}}: - return v, nil - case {{$field.TypeReference.Elem.GO | ref}}: - return &v, nil - case nil: - return ({{$field.TypeReference.GO | ref}})(nil), nil - default: - return nil, fmt.Errorf("unexpected type %T for field %s", v, {{ $field.Name | quote}}) - } - {{- else if $field.IsMethod }} - {{- if $field.NoErr }} - return {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }}), nil - {{- else }} - return {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }}) - {{- end }} - {{- else if $field.IsVariable }} - return {{$field.GoReceiverName}}.{{$field.GoFieldName}}, nil - {{- end }} - }) - if resTmp == nil { - {{- if $field.TypeReference.GQL.NonNull }} - if !ec.HasError(rctx) { - ec.Errorf(ctx, "must not be null") - } - {{- end }} - return graphql.Null - } + {{- else }} res := resTmp.({{$field.TypeReference.GO | ref}}) - rctx.Result = res - ctx = ec.Tracer.StartFieldChildExecution(ctx) + fc.Result = res return ec.{{ $field.TypeReference.MarshalFunc }}(ctx, field.Selections, res) - } -{{ end }} + {{- end }} +} {{- end }}{{- end}} + +{{ define "field" }} + {{- if .HasDirectives -}} + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + {{ template "fieldDefinition" . }} + } + {{ template "implDirectives" . }} + tmp, err := directive{{.ImplDirectives|len}}(rctx) + if err != nil { + return nil, err + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.({{if .Stream}}<-chan {{end}}{{ .TypeReference.GO | ref }}) ; ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be {{if .Stream}}<-chan {{end}}{{ .TypeReference.GO }}`, tmp) + {{- else -}} + ctx = rctx // use context from middleware stack in children + {{ template "fieldDefinition" . }} + {{- end -}} +{{ end }} + +{{ define "fieldDefinition" }} + {{- if .IsResolver -}} + return ec.resolvers.{{ .ShortInvocation }} + {{- else if .IsMap -}} + switch v := {{.GoReceiverName}}[{{.Name|quote}}].(type) { + case {{if .Stream}}<-chan {{end}}{{.TypeReference.GO | ref}}: + return v, nil + case {{if .Stream}}<-chan {{end}}{{.TypeReference.Elem.GO | ref}}: + return &v, nil + case nil: + return ({{.TypeReference.GO | ref}})(nil), nil + default: + return nil, fmt.Errorf("unexpected type %T for field %s", v, {{ .Name | quote}}) + } + {{- else if .IsMethod -}} + {{- if .NoErr -}} + return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }}), nil + {{- else -}} + return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }}) + {{- end -}} + {{- else if .IsVariable -}} + return {{.GoReceiverName}}.{{.GoFieldName}}, nil + {{- end }} +{{- end }} diff --git a/vendor/github.com/99designs/gqlgen/codegen/generate.go b/vendor/github.com/99designs/gqlgen/codegen/generate.go index eafa3f874..f1ed2ca27 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/generate.go +++ b/vendor/github.com/99designs/gqlgen/codegen/generate.go @@ -11,5 +11,6 @@ func GenerateCode(data *Data) error { Data: data, RegionTags: true, GeneratedHeader: true, + Packages: data.Config.Packages, }) } diff --git a/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl b/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl index 5753f1d13..864d15deb 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl @@ -8,8 +8,8 @@ {{ reserveImport "errors" }} {{ reserveImport "bytes" }} -{{ reserveImport "github.com/vektah/gqlparser" }} -{{ reserveImport "github.com/vektah/gqlparser/ast" }} +{{ reserveImport "github.com/vektah/gqlparser/v2" "gqlparser" }} +{{ reserveImport "github.com/vektah/gqlparser/v2/ast" }} {{ reserveImport "github.com/99designs/gqlgen/graphql" }} {{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }} @@ -39,7 +39,7 @@ type ResolverRoot interface { type DirectiveRoot struct { {{ range $directive := .Directives }} - {{ $directive.Declaration }} + {{- $directive.Declaration }} {{ end }} } @@ -112,129 +112,86 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return 0, false } -func (e *executableSchema) Query(ctx context.Context, op *ast.OperationDefinition) *graphql.Response { - {{- if .QueryRoot }} - ec := executionContext{graphql.GetRequestContext(ctx), e} +func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { + rc := graphql.GetOperationContext(ctx) + ec := executionContext{rc, e} + first := true - buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { - data := ec._{{.QueryRoot.Name}}(ctx, op.SelectionSet) + switch rc.Operation.Operation { + {{- if .QueryRoot }} case ast.Query: + return func(ctx context.Context) *graphql.Response { + if !first { return nil } + first = false + {{ if .Directives.LocationDirectives "QUERY" -}} + data := ec._queryMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){ + return ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet), nil + }) + {{- else -}} + data := ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet) + {{- end }} var buf bytes.Buffer data.MarshalGQL(&buf) - return buf.Bytes() - }) - - return &graphql.Response{ - Data: buf, - Errors: ec.Errors, - Extensions: ec.Extensions, - } - {{- else }} - return graphql.ErrorResponse(ctx, "queries are not supported") - {{- end }} -} - -func (e *executableSchema) Mutation(ctx context.Context, op *ast.OperationDefinition) *graphql.Response { - {{- if .MutationRoot }} - ec := executionContext{graphql.GetRequestContext(ctx), e} - - buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { - data := ec._{{.MutationRoot.Name}}(ctx, op.SelectionSet) - var buf bytes.Buffer - data.MarshalGQL(&buf) - return buf.Bytes() - }) - - return &graphql.Response{ - Data: buf, - Errors: ec.Errors, - Extensions: ec.Extensions, - } - {{- else }} - return graphql.ErrorResponse(ctx, "mutations are not supported") - {{- end }} -} - -func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDefinition) func() *graphql.Response { - {{- if .SubscriptionRoot }} - ec := executionContext{graphql.GetRequestContext(ctx), e} - - next := ec._{{.SubscriptionRoot.Name}}(ctx, op.SelectionSet) - if ec.Errors != nil { - return graphql.OneShot(&graphql.Response{Data: []byte("null"), Errors: ec.Errors}) - } - - var buf bytes.Buffer - return func() *graphql.Response { - buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { - buf.Reset() - data := next() - - if data == nil { - return nil - } - data.MarshalGQL(&buf) - return buf.Bytes() - }) - - if buf == nil { - return nil - } return &graphql.Response{ - Data: buf, - Errors: ec.Errors, - Extensions: ec.Extensions, + Data: buf.Bytes(), } } - {{- else }} - return graphql.OneShot(graphql.ErrorResponse(ctx, "subscriptions are not supported")) - {{- end }} + {{ end }} + + {{- if .MutationRoot }} case ast.Mutation: + return func(ctx context.Context) *graphql.Response { + if !first { return nil } + first = false + {{ if .Directives.LocationDirectives "MUTATION" -}} + data := ec._mutationMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){ + return ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet), nil + }) + {{- else -}} + data := ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet) + {{- end }} + var buf bytes.Buffer + data.MarshalGQL(&buf) + + return &graphql.Response{ + Data: buf.Bytes(), + } + } + {{ end }} + + {{- if .SubscriptionRoot }} case ast.Subscription: + {{ if .Directives.LocationDirectives "SUBSCRIPTION" -}} + next := ec._subscriptionMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){ + return ec._{{.SubscriptionRoot.Name}}(ctx, rc.Operation.SelectionSet),nil + }) + {{- else -}} + next := ec._{{.SubscriptionRoot.Name}}(ctx, rc.Operation.SelectionSet) + {{- end }} + + var buf bytes.Buffer + return func(ctx context.Context) *graphql.Response { + buf.Reset() + data := next() + + if data == nil { + return nil + } + data.MarshalGQL(&buf) + + return &graphql.Response{ + Data: buf.Bytes(), + } + } + {{ end }} + default: + return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation")) + } } type executionContext struct { - *graphql.RequestContext + *graphql.OperationContext *executableSchema } -func (ec *executionContext) FieldMiddleware(ctx context.Context, obj interface{}, next graphql.Resolver) (ret interface{}) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - {{- if .Directives }} - rctx := graphql.GetResolverContext(ctx) - for _, d := range rctx.Field.Definition.Directives { - switch d.Name { - {{- range $directive := .Directives }} - case "{{$directive.Name}}": - if ec.directives.{{$directive.Name|ucFirst}} != nil { - {{- if $directive.Args }} - rawArgs := d.ArgumentMap(ec.Variables) - args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs) - if err != nil { - ec.Error(ctx, err) - return nil - } - {{- end }} - n := next - next = func(ctx context.Context) (interface{}, error) { - return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}}) - } - } - {{- end }} - } - } - {{- end }} - res, err := ec.ResolverMiddleware(ctx, next) - if err != nil { - ec.Error(ctx, err) - return nil - } - return res -} - func (ec *executionContext) introspectSchema() (*introspection.Schema, error) { if ec.DisableIntrospection { return nil, errors.New("introspection disabled") @@ -249,8 +206,9 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil } -var parsedSchema = gqlparser.MustLoadSchema( - {{- range $filename, $schema := .SchemaStr }} - &ast.Source{Name: {{$filename|quote}}, Input: {{$schema|rawQuote}}}, - {{- end }} -) +var sources = []*ast.Source{ +{{- range $source := .Config.Sources }} + {Name: {{$source.Name|quote}}, Input: {{$source.Input|rawQuote}}, BuiltIn: {{$source.BuiltIn}}}, +{{- end }} +} +var parsedSchema = gqlparser.MustLoadSchema(sources...) diff --git a/vendor/github.com/99designs/gqlgen/codegen/input.gotpl b/vendor/github.com/99designs/gqlgen/codegen/input.gotpl index c8ac7ad3a..56f9347c4 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/input.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/input.gotpl @@ -1,8 +1,8 @@ {{- range $input := .Inputs }} {{- if not .HasUnmarshal }} - func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, v interface{}) ({{.Type | ref}}, error) { + func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, obj interface{}) ({{.Type | ref}}, error) { var it {{.Type | ref}} - var asMap = v.(map[string]interface{}) + var asMap = obj.(map[string]interface{}) {{ range $field := .Fields}} {{- if $field.Default}} if _, present := asMap[{{$field.Name|quote}}] ; !present { @@ -16,27 +16,21 @@ {{- range $field := .Fields }} case {{$field.Name|quote}}: var err error - {{- if $field.Directives }} - getField0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) } - {{- range $i, $directive := $field.Directives }} - getField{{add $i 1}} := func(ctx context.Context) (res interface{}, err error) { - {{- range $dArg := $directive.Args }} - {{- if and $dArg.TypeReference.IsPtr ( notNil "Value" $dArg ) }} - {{ $dArg.VarName }} := {{ $dArg.Value | dump }} - {{- end }} - {{- end }} - n := getField{{$i}} - return ec.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs "it" "n" }}) - } - {{- end }} - - tmp, err := getField{{$field.Directives|len}}(ctx) + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField({{$field.Name|quote}})) + {{- if $field.ImplDirectives }} + directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) } + {{ template "implDirectives" $field }} + tmp, err := directive{{$field.ImplDirectives|len}}(ctx) if err != nil { return it, err } if data, ok := tmp.({{ $field.TypeReference.GO | ref }}) ; ok { it.{{$field.GoFieldName}} = data + {{- if $field.TypeReference.IsNilable }} + } else if tmp == nil { + it.{{$field.GoFieldName}} = nil + {{- end }} } else { return it, fmt.Errorf(`unexpected type %T from directive, should be {{ $field.TypeReference.GO }}`, tmp) } diff --git a/vendor/github.com/99designs/gqlgen/codegen/interface.go b/vendor/github.com/99designs/gqlgen/codegen/interface.go index f59e8ed07..a55ce1e6b 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/interface.go +++ b/vendor/github.com/99designs/gqlgen/codegen/interface.go @@ -1,9 +1,13 @@ package codegen import ( + "fmt" "go/types" - "github.com/vektah/gqlparser/ast" + "github.com/pkg/errors" + "github.com/vektah/gqlparser/v2/ast" + + "github.com/99designs/gqlgen/codegen/config" ) type Interface struct { @@ -16,11 +20,11 @@ type Interface struct { type InterfaceImplementor struct { *ast.Definition - Interface *Interface - Type types.Type + Type types.Type + TakeRef bool } -func (b *builder) buildInterface(typ *ast.Definition) *Interface { +func (b *builder) buildInterface(typ *ast.Definition) (*Interface, error) { obj, err := b.Binder.DefaultUserObject(typ.Name) if err != nil { panic(err) @@ -32,32 +36,53 @@ func (b *builder) buildInterface(typ *ast.Definition) *Interface { InTypemap: b.Config.Models.UserDefined(typ.Name), } + interfaceType, err := findGoInterface(i.Type) + if interfaceType == nil || err != nil { + return nil, fmt.Errorf("%s is not an interface", i.Type) + } + for _, implementor := range b.Schema.GetPossibleTypes(typ) { obj, err := b.Binder.DefaultUserObject(implementor.Name) if err != nil { - panic(err) + return nil, fmt.Errorf("%s has no backing go type", implementor.Name) } - i.Implementors = append(i.Implementors, InterfaceImplementor{ - Definition: implementor, - Type: obj, - Interface: i, - }) + implementorType, err := findGoNamedType(obj) + if err != nil { + return nil, errors.Wrapf(err, "can not find backing go type %s", obj.String()) + } else if implementorType == nil { + return nil, fmt.Errorf("can not find backing go type %s", obj.String()) + } + + anyValid := false + + // first check if the value receiver can be nil, eg can we type switch on case Thing: + if types.Implements(implementorType, interfaceType) { + i.Implementors = append(i.Implementors, InterfaceImplementor{ + Definition: implementor, + Type: obj, + TakeRef: !types.IsInterface(obj), + }) + anyValid = true + } + + // then check if the pointer receiver can be nil, eg can we type switch on case *Thing: + if types.Implements(types.NewPointer(implementorType), interfaceType) { + i.Implementors = append(i.Implementors, InterfaceImplementor{ + Definition: implementor, + Type: types.NewPointer(obj), + }) + anyValid = true + } + + if !anyValid { + return nil, fmt.Errorf("%s does not satisfy the interface %s", implementorType.String(), i.Type.String()) + } } - return i + return i, nil } -func (i *InterfaceImplementor) ValueReceiver() bool { - interfaceType, err := findGoInterface(i.Interface.Type) - if interfaceType == nil || err != nil { - return true - } - - implementorType, err := findGoNamedType(i.Type) - if implementorType == nil || err != nil { - return true - } - - return types.Implements(implementorType, interfaceType) +func (i *InterfaceImplementor) CanBeNil() bool { + return config.IsNilable(i.Type) } diff --git a/vendor/github.com/99designs/gqlgen/codegen/interface.gotpl b/vendor/github.com/99designs/gqlgen/codegen/interface.gotpl index 81a580765..e9d560c8f 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/interface.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/interface.gotpl @@ -1,16 +1,17 @@ {{- range $interface := .Interfaces }} -func (ec *executionContext) _{{$interface.Name}}(ctx context.Context, sel ast.SelectionSet, obj *{{$interface.Type | ref}}) graphql.Marshaler { - switch obj := (*obj).(type) { +func (ec *executionContext) _{{$interface.Name}}(ctx context.Context, sel ast.SelectionSet, obj {{$interface.Type | ref}}) graphql.Marshaler { + switch obj := (obj).(type) { case nil: return graphql.Null {{- range $implementor := $interface.Implementors }} - {{- if $implementor.ValueReceiver }} - case {{$implementor.Type | ref}}: - return ec._{{$implementor.Name}}(ctx, sel, &obj) - {{- end}} - case *{{$implementor.Type | ref}}: - return ec._{{$implementor.Name}}(ctx, sel, obj) + case {{$implementor.Type | ref}}: + {{- if $implementor.CanBeNil }} + if obj == nil { + return graphql.Null + } + {{- end }} + return ec._{{$implementor.Name}}(ctx, sel, {{ if $implementor.TakeRef }}&{{ end }}obj) {{- end }} default: panic(fmt.Errorf("unexpected type %T", obj)) diff --git a/vendor/github.com/99designs/gqlgen/codegen/object.go b/vendor/github.com/99designs/gqlgen/codegen/object.go index 539c3164c..7b91c9004 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/object.go +++ b/vendor/github.com/99designs/gqlgen/codegen/object.go @@ -8,7 +8,7 @@ import ( "github.com/99designs/gqlgen/codegen/config" "github.com/pkg/errors" - "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/v2/ast" ) type GoFieldType int @@ -82,11 +82,9 @@ func (b *builder) buildObject(typ *ast.Definition) (*Object, error) { } func (o *Object) Reference() types.Type { - switch o.Type.(type) { - case *types.Pointer, *types.Slice, *types.Map: + if config.IsNilable(o.Type) { return o.Type } - return types.NewPointer(o.Type) } @@ -114,8 +112,7 @@ func (o *Object) HasUnmarshal() bool { return true } for i := 0; i < o.Type.(*types.Named).NumMethods(); i++ { - switch o.Type.(*types.Named).Method(i).Name() { - case "UnmarshalGQL": + if o.Type.(*types.Named).Method(i).Name() == "UnmarshalGQL" { return true } } diff --git a/vendor/github.com/99designs/gqlgen/codegen/object.gotpl b/vendor/github.com/99designs/gqlgen/codegen/object.gotpl index 98a75740e..33775a0b4 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/object.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/object.gotpl @@ -4,8 +4,8 @@ var {{ $object.Name|lcFirst}}Implementors = {{$object.Implementors}} {{- if .Stream }} func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.SelectionSet) func() graphql.Marshaler { - fields := graphql.CollectFields(ec.RequestContext, sel, {{$object.Name|lcFirst}}Implementors) - ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ + fields := graphql.CollectFields(ec.OperationContext, sel, {{$object.Name|lcFirst}}Implementors) + ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ Object: {{$object.Name|quote}}, }) if len(fields) != 1 { @@ -24,9 +24,9 @@ func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.Selec } {{- else }} func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.SelectionSet{{ if not $object.Root }},obj {{$object.Reference | ref }}{{ end }}) graphql.Marshaler { - fields := graphql.CollectFields(ec.RequestContext, sel, {{$object.Name|lcFirst}}Implementors) + fields := graphql.CollectFields(ec.OperationContext, sel, {{$object.Name|lcFirst}}Implementors) {{if $object.Root}} - ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{ + ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ Object: {{$object.Name|quote}}, }) {{end}} diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/import.go b/vendor/github.com/99designs/gqlgen/codegen/templates/import.go index effe9a0df..17bd96ab2 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/templates/import.go +++ b/vendor/github.com/99designs/gqlgen/codegen/templates/import.go @@ -4,6 +4,7 @@ import ( "fmt" "go/types" "strconv" + "strings" "github.com/99designs/gqlgen/internal/code" ) @@ -15,12 +16,13 @@ type Import struct { } type Imports struct { - imports []*Import - destDir string + imports []*Import + destDir string + packages *code.Packages } func (i *Import) String() string { - if i.Alias == i.Name { + if strings.HasSuffix(i.Path, i.Alias) { return strconv.Quote(i.Path) } @@ -48,7 +50,7 @@ func (s *Imports) Reserve(path string, aliases ...string) (string, error) { return "", nil } - name := code.NameForPackage(path) + name := s.packages.NameForPackage(path) var alias string if len(aliases) != 1 { alias = name @@ -93,7 +95,7 @@ func (s *Imports) Lookup(path string) string { } imp := &Import{ - Name: code.NameForPackage(path), + Name: s.packages.NameForPackage(path), Path: path, } s.imports = append(s.imports, imp) diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go b/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go index f2fcb568e..79b0c5c7d 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go +++ b/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go @@ -15,6 +15,8 @@ import ( "text/template" "unicode" + "github.com/99designs/gqlgen/internal/code" + "github.com/99designs/gqlgen/internal/imports" "github.com/pkg/errors" ) @@ -40,9 +42,16 @@ type Options struct { Filename string RegionTags bool GeneratedHeader bool + // PackageDoc is documentation written above the package line + PackageDoc string + // FileNotice is notice written below the package line + FileNotice string // Data will be passed to the template execution. Data interface{} Funcs template.FuncMap + + // Packages cache, you can find me on config.Config + Packages *code.Packages } // Render renders a gql plugin template from the given Options. Render is an @@ -53,7 +62,7 @@ func Render(cfg Options) error { if CurrentImports != nil { panic(fmt.Errorf("recursive or concurrent call to RenderToFile detected")) } - CurrentImports = &Imports{destDir: filepath.Dir(cfg.Filename)} + CurrentImports = &Imports{packages: cfg.Packages, destDir: filepath.Dir(cfg.Filename)} // load path relative to calling source file _, callerFile, _, _ := runtime.Caller(1) @@ -131,9 +140,16 @@ func Render(cfg Options) error { if cfg.GeneratedHeader { result.WriteString("// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.\n\n") } + if cfg.PackageDoc != "" { + result.WriteString(cfg.PackageDoc + "\n") + } result.WriteString("package ") result.WriteString(cfg.PackageName) result.WriteString("\n\n") + if cfg.FileNotice != "" { + result.WriteString(cfg.FileNotice) + result.WriteString("\n\n") + } result.WriteString("import (\n") result.WriteString(CurrentImports.String()) result.WriteString(")\n") @@ -143,7 +159,13 @@ func Render(cfg Options) error { } CurrentImports = nil - return write(cfg.Filename, result.Bytes()) + err = write(cfg.Filename, result.Bytes(), cfg.Packages) + if err != nil { + return err + } + + cfg.Packages.Evict(code.ImportPathForDir(filepath.Dir(cfg.Filename))) + return nil } func center(width int, pad string, s string) string { @@ -157,8 +179,8 @@ func center(width int, pad string, s string) string { func Funcs() template.FuncMap { return template.FuncMap{ - "ucFirst": ucFirst, - "lcFirst": lcFirst, + "ucFirst": UcFirst, + "lcFirst": LcFirst, "quote": strconv.Quote, "rawQuote": rawQuote, "dump": Dump, @@ -180,7 +202,7 @@ func Funcs() template.FuncMap { } } -func ucFirst(s string) string { +func UcFirst(s string) string { if s == "" { return "" } @@ -189,7 +211,7 @@ func ucFirst(s string) string { return string(r) } -func lcFirst(s string) string { +func LcFirst(s string) string { if s == "" { return "" } @@ -211,6 +233,7 @@ var pkgReplacer = strings.NewReplacer( "/", "ᚋ", ".", "ᚗ", "-", "ᚑ", + "~", "א", ) func TypeIdentifier(t types.Type) string { @@ -260,6 +283,9 @@ func Call(p *types.Func) string { } func ToGo(name string) string { + if name == "_" { + return "_" + } runes := make([]rune, 0, len(name)) wordWalker(name, func(info *wordInfo) { @@ -270,7 +296,7 @@ func ToGo(name string) string { if strings.ToUpper(word) == word || strings.ToLower(word) == word { // FOO or foo → Foo // FOo → FOo - word = ucFirst(strings.ToLower(word)) + word = UcFirst(strings.ToLower(word)) } } runes = append(runes, []rune(word)...) @@ -280,24 +306,28 @@ func ToGo(name string) string { } func ToGoPrivate(name string) string { + if name == "_" { + return "_" + } runes := make([]rune, 0, len(name)) first := true wordWalker(name, func(info *wordInfo) { word := info.Word - if first { + switch { + case first: if strings.ToUpper(word) == word || strings.ToLower(word) == word { // ID → id, CAMEL → camel word = strings.ToLower(info.Word) } else { // ITicket → iTicket - word = lcFirst(info.Word) + word = LcFirst(info.Word) } first = false - } else if info.MatchCommonInitial { + case info.MatchCommonInitial: word = strings.ToUpper(word) - } else if !info.HasCommonInitial { - word = ucFirst(strings.ToLower(word)) + case !info.HasCommonInitial: + word = UcFirst(strings.ToLower(word)) } runes = append(runes, []rune(word)...) }) @@ -314,14 +344,15 @@ type wordInfo struct { // This function is based on the following code. // https://github.com/golang/lint/blob/06c8688daad7faa9da5a0c2f163a3d14aac986ca/lint.go#L679 func wordWalker(str string, f func(*wordInfo)) { - runes := []rune(str) + runes := []rune(strings.TrimFunc(str, isDelimiter)) w, i := 0, 0 // index of start of word, scan hasCommonInitial := false for i+1 <= len(runes) { eow := false // whether we hit the end of a word - if i+1 == len(runes) { + switch { + case i+1 == len(runes): eow = true - } else if isDelimiter(runes[i+1]) { + case isDelimiter(runes[i+1]): // underscore; shift the remainder forward over any run of underscores eow = true n := 1 @@ -336,7 +367,7 @@ func wordWalker(str string, f func(*wordInfo)) { copy(runes[i+1:], runes[i+n+1:]) runes = runes[:len(runes)-n] - } else if unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]) { + case unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]): // lower->non-lower eow = true } @@ -429,6 +460,7 @@ var commonInitialisms = map[string]bool{ "IP": true, "JSON": true, "LHS": true, + "PGP": true, "QPS": true, "RAM": true, "RHS": true, @@ -549,13 +581,13 @@ func render(filename string, tpldata interface{}) (*bytes.Buffer, error) { return buf, t.Execute(buf, tpldata) } -func write(filename string, b []byte) error { +func write(filename string, b []byte, packages *code.Packages) error { err := os.MkdirAll(filepath.Dir(filename), 0755) if err != nil { return errors.Wrap(err, "failed to create directory") } - formatted, err := imports.Prune(filename, b) + formatted, err := imports.Prune(filename, b, packages) if err != nil { fmt.Fprintf(os.Stderr, "gofmt failed on %s: %s\n", filepath.Base(filename), err.Error()) formatted = b diff --git a/vendor/github.com/99designs/gqlgen/codegen/type.go b/vendor/github.com/99designs/gqlgen/codegen/type.go index e00837323..06b370be7 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/type.go +++ b/vendor/github.com/99designs/gqlgen/codegen/type.go @@ -1,18 +1,32 @@ package codegen import ( + "fmt" + "github.com/99designs/gqlgen/codegen/config" ) -func (b *builder) buildTypes() (map[string]*config.TypeReference, error) { +func (b *builder) buildTypes() map[string]*config.TypeReference { ret := map[string]*config.TypeReference{} - for _, ref := range b.Binder.References { - for ref != nil { - ret[ref.UniquenessKey()] = ref + processType(ret, ref) + } + return ret +} - ref = ref.Elem() +func processType(ret map[string]*config.TypeReference, ref *config.TypeReference) { + key := ref.UniquenessKey() + if existing, found := ret[key]; found { + // Simplistic check of content which is obviously different. + existingGQL := fmt.Sprintf("%v", existing.GQL) + newGQL := fmt.Sprintf("%v", ref.GQL) + if existingGQL != newGQL { + panic(fmt.Sprintf("non-unique key \"%s\", trying to replace %s with %s", key, existingGQL, newGQL)) } } - return ret, nil + ret[key] = ref + + if ref.IsSlice() { + processType(ret, ref.Elem()) + } } diff --git a/vendor/github.com/99designs/gqlgen/codegen/type.gotpl b/vendor/github.com/99designs/gqlgen/codegen/type.gotpl index cb2782c39..2bd0c1943 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/type.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/type.gotpl @@ -1,13 +1,10 @@ {{- range $type := .ReferencedTypes }} {{ with $type.UnmarshalFunc }} func (ec *executionContext) {{ . }}(ctx context.Context, v interface{}) ({{ $type.GO | ref }}, error) { - {{- if $type.IsNilable }} + {{- if and $type.IsNilable (not $type.GQL.NonNull) }} if v == nil { return nil, nil } {{- end }} - {{- if $type.IsPtr }} - res, err := ec.{{ $type.Elem.UnmarshalFunc }}(ctx, v) - return &res, err - {{- else if $type.IsSlice }} + {{- if $type.IsSlice }} var vSlice []interface{} if v != nil { if tmp1, ok := v.([]interface{}); ok { @@ -19,9 +16,10 @@ var err error res := make([]{{$type.GO.Elem | ref}}, len(vSlice)) for i := range vSlice { + ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithIndex(i)) res[i], err = ec.{{ $type.Elem.UnmarshalFunc }}(ctx, vSlice[i]) if err != nil { - return nil, err + return nil, graphql.WrapErrorWithInputPath(ctx, err) } } return res, nil @@ -29,17 +27,38 @@ {{- if $type.Unmarshaler }} {{- if $type.CastType }} tmp, err := {{ $type.Unmarshaler | call }}(v) - return {{ $type.GO | ref }}(tmp), err + {{- if $type.IsNilable }} + res := {{ $type.Elem.GO | ref }}(tmp) + {{- else}} + res := {{ $type.GO | ref }}(tmp) + {{- end }} {{- else}} - return {{ $type.Unmarshaler | call }}(v) + res, err := {{ $type.Unmarshaler | call }}(v) + {{- end }} + {{- if and $type.IsTargetNilable (not $type.IsNilable) }} + return *res, graphql.WrapErrorWithInputPath(ctx, err) + {{- else if and (not $type.IsTargetNilable) $type.IsNilable }} + return &res, graphql.WrapErrorWithInputPath(ctx, err) + {{- else}} + return res, graphql.WrapErrorWithInputPath(ctx, err) {{- end }} {{- else if eq ($type.GO | ref) "map[string]interface{}" }} return v.(map[string]interface{}), nil - {{- else if $type.IsMarshaler -}} - var res {{ $type.GO | ref }} - return res, res.UnmarshalGQL(v) + {{- else if $type.IsMarshaler }} + {{- if $type.IsNilable }} + var res = new({{ $type.Elem.GO | ref }}) + {{- else}} + var res {{ $type.GO | ref }} + {{- end }} + err := res.UnmarshalGQL(v) + return res, graphql.WrapErrorWithInputPath(ctx, err) {{- else }} - return ec.unmarshalInput{{ $type.GQL.Name }}(ctx, v) + res, err := ec.unmarshalInput{{ $type.GQL.Name }}(ctx, v) + {{- if $type.IsNilable }} + return &res, graphql.WrapErrorWithInputPath(ctx, err) + {{- else}} + return res, graphql.WrapErrorWithInputPath(ctx, err) + {{- end }} {{- end }} {{- end }} } @@ -47,17 +66,6 @@ {{ with $type.MarshalFunc }} func (ec *executionContext) {{ . }}(ctx context.Context, sel ast.SelectionSet, v {{ $type.GO | ref }}) graphql.Marshaler { - {{- if $type.IsNilable }} - if v == nil { - {{- if $type.GQL.NonNull }} - if !ec.HasError(graphql.GetResolverContext(ctx)) { - ec.Errorf(ctx, "must not be null") - } - {{- end }} - return graphql.Null - } - {{- end }} - {{- if $type.IsSlice }} {{- if not $type.GQL.NonNull }} if v == nil { @@ -75,11 +83,11 @@ for i := range v { {{- if not $type.IsScalar }} i := i - rctx := &graphql.ResolverContext{ + fc := &graphql.FieldContext{ Index: &i, Result: &v[i], } - ctx := graphql.WithResolverContext(ctx, rctx) + ctx := graphql.WithFieldContext(ctx, fc) f := func(i int) { defer func() { if r := recover(); r != nil { @@ -104,22 +112,35 @@ {{ if not $type.IsScalar }} wg.Wait() {{ end }} return ret {{- else }} - + {{- if $type.IsNilable }} + if v == nil { + {{- if $type.GQL.NonNull }} + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + {{- end }} + return graphql.Null + } + {{- end }} {{- if $type.IsMarshaler }} return v {{- else if $type.Marshaler }} - {{- if $type.IsPtr }} - return ec.{{ $type.Elem.MarshalFunc }}(ctx, sel, *v) - {{- else if $type.GQL.NonNull }} - res := {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}(v){{else}}v{{- end }}) + {{- $v := "v" }} + {{- if and $type.IsTargetNilable (not $type.IsNilable) }} + {{- $v = "&v" }} + {{- else if and (not $type.IsTargetNilable) $type.IsNilable }} + {{- $v = "*v" }} + {{- end }} + {{- if $type.GQL.NonNull }} + res := {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}({{ $v }}){{else}}{{ $v }}{{- end }}) if res == graphql.Null { - if !ec.HasError(graphql.GetResolverContext(ctx)) { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "must not be null") } } return res {{- else }} - return {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}(v){{else}}v{{- end }}) + return {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}({{ $v }}){{else}}{{ $v }}{{- end }}) {{- end }} {{- else }} return ec._{{$type.Definition.Name}}(ctx, sel, {{ if not $type.IsNilable}}&{{end}} v) diff --git a/vendor/github.com/99designs/gqlgen/complexity/complexity.go b/vendor/github.com/99designs/gqlgen/complexity/complexity.go index d5b46bf45..1877aae5f 100644 --- a/vendor/github.com/99designs/gqlgen/complexity/complexity.go +++ b/vendor/github.com/99designs/gqlgen/complexity/complexity.go @@ -2,7 +2,7 @@ package complexity import ( "github.com/99designs/gqlgen/graphql" - "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/v2/ast" ) func Calculate(es graphql.ExecutableSchema, op *ast.OperationDefinition, vars map[string]interface{}) int { diff --git a/vendor/github.com/99designs/gqlgen/go.mod b/vendor/github.com/99designs/gqlgen/go.mod index 9ff313d86..16affcf04 100644 --- a/vendor/github.com/99designs/gqlgen/go.mod +++ b/vendor/github.com/99designs/gqlgen/go.mod @@ -1,14 +1,19 @@ module github.com/99designs/gqlgen +go 1.12 + require ( - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/agnivade/levenshtein v1.0.3 // indirect github.com/go-chi/chi v3.3.2+incompatible github.com/gogo/protobuf v1.0.0 // indirect github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f // indirect github.com/gorilla/mux v1.6.1 // indirect - github.com/gorilla/websocket v1.2.0 + github.com/gorilla/websocket v1.4.2 github.com/hashicorp/golang-lru v0.5.0 - github.com/kr/pretty v0.1.0 // indirect + github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 + github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007 + github.com/mattn/go-colorable v0.1.4 + github.com/mattn/go-isatty v0.0.12 github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047 github.com/opentracing/basictracer-go v1.0.0 // indirect github.com/opentracing/opentracing-go v1.0.2 @@ -16,13 +21,13 @@ require ( github.com/rs/cors v1.6.0 github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371 // indirect github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0 // indirect - github.com/stretchr/testify v1.3.0 - github.com/urfave/cli v1.20.0 + github.com/stretchr/testify v1.4.0 + github.com/urfave/cli/v2 v2.1.1 github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e - github.com/vektah/gqlparser v1.1.2 - golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect - gopkg.in/yaml.v2 v2.2.2 + github.com/vektah/gqlparser v1.3.1 + github.com/vektah/gqlparser/v2 v2.0.1 + golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589 + gopkg.in/yaml.v2 v2.2.4 sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755 sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67 // indirect ) diff --git a/vendor/github.com/99designs/gqlgen/go.sum b/vendor/github.com/99designs/gqlgen/go.sum index b2d54b1f7..02d393c3b 100644 --- a/vendor/github.com/99designs/gqlgen/go.sum +++ b/vendor/github.com/99designs/gqlgen/go.sum @@ -1,11 +1,20 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/agnivade/levenshtein v1.0.3 h1:M5ZnqLOoZR8ygVq0FfkXsNOKzMCk0xRiow0R5+5VkQ0= +github.com/agnivade/levenshtein v1.0.3/go.mod h1:4SFRZbbXWLF4MU1T9Qg0pGgH3Pjs+t6ie5efyrwRJXs= 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/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c h1:TUuUh0Xgj97tLMNtWtNvI9mIV6isjEb9lBMNv+77IGM= +github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/go-chi/chi v3.3.2+incompatible h1:uQNcQN3NsV1j4ANsPh42P4ew4t6rnRbJb8frvpp31qQ= github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/gogo/protobuf v1.0.0 h1:2jyBKDKU/8v3v2xVR2PtiWQviFUyiaGk2rpfyFT8rTM= @@ -14,8 +23,8 @@ github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f h1:9oNbS1z4rVpbnkH github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.1 h1:KOwqsTYZdeuMacU7CxjMNYEKeBvLbxW+psodrbcEa3A= github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ= -github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -23,6 +32,15 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs= +github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007 h1:reVOUXwnhsYv/8UqjvhrMOu5CNT9UapHFLbQ2JcXsmg= +github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= +github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047 h1:zCoDWFD5nrJJVjbXiDZcVhOBSzKn3o9LgRLLMRNuru8= github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo= @@ -35,46 +53,61 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371 h1:SWV2fHctRpRrp49VXJ6UZja7gU9QLHwRpIPBN89SKEo= github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0 h1:JJV9CsgM9EC9w2iVkwuz+sMx8yRFe89PJRUrv6hPCIA= github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/vektah/dataloaden v0.2.0 h1:lhynDrG7c8mNLahboCo0Wq82tMjmu5yOUv2ds/tBmss= -github.com/vektah/dataloaden v0.2.0/go.mod h1:vxM6NuRlgiR0M6wbVTJeKp9vQIs81ZMfCYO+4yq/jbE= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k= +github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e h1:+w0Zm/9gaWpEAyDlU1eKOuk5twTjAjuevXqcJJw8hrg= github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U= -github.com/vektah/gqlparser v1.1.2 h1:ZsyLGn7/7jDNI+y4SEhI4yAxRChlv15pUHMjijT+e68= -github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/vektah/gqlparser v1.3.1 h1:8b0IcD3qZKWJQHSzynbDlrtP3IxVydZ2DZepCGofqfU= +github.com/vektah/gqlparser v1.3.1/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74= +github.com/vektah/gqlparser/v2 v2.0.1 h1:xgl5abVnsd4hkN9rk65OJID9bfcLSMuTaTcZj777q1o= +github.com/vektah/gqlparser/v2 v2.0.1/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/net v0.0.0-20180404174746-b3c676e531a6 h1:mge3qS/eMvcfyIAzTMOAy0XUzWG6Lk0N4M8zjuSmdco= -golang.org/x/net v0.0.0-20180404174746-b3c676e531a6/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= 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 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= +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-20190222072716-a9d3bda3a223/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-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6 h1:iZgcI2DDp6zW5v9Z/5+f0NuqoxNdmzg4hivjk2WLXpY= golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190125232054-dbeab5af4b8d3204d444b78cafaba18a9a062a50/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190511041617-99f201b6807e h1:wTxRxdzKt8fn3IQa3+kVlPJMxK2hJj2Orm+M2Mzw9eg= -golang.org/x/tools v0.0.0-20190511041617-99f201b6807e/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd h1:oMEQDWVXVNpceQoVd1JN3CQ7LYJJzs5qWqZIUcxXHHw= golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589 h1:rjUrONFu4kLchcZTfp3/96bR8bW8dIa8uz3cR5n0cgM= +golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +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 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755 h1:d2maSb13hr/ArmfK3rW+wNUKKfytCol7W1/vDHxMPiE= sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67 h1:e1sMhtVq9AfcEy8AXNb8eSg6gbzfdpYhoNqnPJa+GzI= diff --git a/vendor/github.com/99designs/gqlgen/graphql/cache.go b/vendor/github.com/99designs/gqlgen/graphql/cache.go new file mode 100644 index 000000000..fe86ca350 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/cache.go @@ -0,0 +1,29 @@ +package graphql + +import "context" + +// Cache is a shared store for APQ and query AST caching +type Cache interface { + // Get looks up a key's value from the cache. + Get(ctx context.Context, key string) (value interface{}, ok bool) + + // Add adds a value to the cache. + Add(ctx context.Context, key string, value interface{}) +} + +// MapCache is the simplest implementation of a cache, because it can not evict it should only be used in tests +type MapCache map[string]interface{} + +// Get looks up a key's value from the cache. +func (m MapCache) Get(ctx context.Context, key string) (value interface{}, ok bool) { + v, ok := m[key] + return v, ok +} + +// Add adds a value to the cache. +func (m MapCache) Add(ctx context.Context, key string, value interface{}) { m[key] = value } + +type NoCache struct{} + +func (n NoCache) Get(ctx context.Context, key string) (value interface{}, ok bool) { return nil, false } +func (n NoCache) Add(ctx context.Context, key string, value interface{}) {} diff --git a/vendor/github.com/99designs/gqlgen/graphql/context.go b/vendor/github.com/99designs/gqlgen/graphql/context.go deleted file mode 100644 index 356f5175b..000000000 --- a/vendor/github.com/99designs/gqlgen/graphql/context.go +++ /dev/null @@ -1,274 +0,0 @@ -package graphql - -import ( - "context" - "fmt" - "sync" - - "github.com/vektah/gqlparser/ast" - "github.com/vektah/gqlparser/gqlerror" -) - -type Resolver func(ctx context.Context) (res interface{}, err error) -type FieldMiddleware func(ctx context.Context, next Resolver) (res interface{}, err error) -type RequestMiddleware func(ctx context.Context, next func(ctx context.Context) []byte) []byte -type ComplexityLimitFunc func(ctx context.Context) int - -type RequestContext struct { - RawQuery string - Variables map[string]interface{} - Doc *ast.QueryDocument - - ComplexityLimit int - OperationComplexity int - DisableIntrospection bool - - // ErrorPresenter will be used to generate the error - // message from errors given to Error(). - ErrorPresenter ErrorPresenterFunc - Recover RecoverFunc - ResolverMiddleware FieldMiddleware - DirectiveMiddleware FieldMiddleware - RequestMiddleware RequestMiddleware - Tracer Tracer - - errorsMu sync.Mutex - Errors gqlerror.List - extensionsMu sync.Mutex - Extensions map[string]interface{} -} - -func DefaultResolverMiddleware(ctx context.Context, next Resolver) (res interface{}, err error) { - return next(ctx) -} - -func DefaultDirectiveMiddleware(ctx context.Context, next Resolver) (res interface{}, err error) { - return next(ctx) -} - -func DefaultRequestMiddleware(ctx context.Context, next func(ctx context.Context) []byte) []byte { - return next(ctx) -} - -func NewRequestContext(doc *ast.QueryDocument, query string, variables map[string]interface{}) *RequestContext { - return &RequestContext{ - Doc: doc, - RawQuery: query, - Variables: variables, - ResolverMiddleware: DefaultResolverMiddleware, - DirectiveMiddleware: DefaultDirectiveMiddleware, - RequestMiddleware: DefaultRequestMiddleware, - Recover: DefaultRecover, - ErrorPresenter: DefaultErrorPresenter, - Tracer: &NopTracer{}, - } -} - -type key string - -const ( - request key = "request_context" - resolver key = "resolver_context" -) - -func GetRequestContext(ctx context.Context) *RequestContext { - if val, ok := ctx.Value(request).(*RequestContext); ok { - return val - } - return nil -} - -func WithRequestContext(ctx context.Context, rc *RequestContext) context.Context { - return context.WithValue(ctx, request, rc) -} - -type ResolverContext struct { - Parent *ResolverContext - // The name of the type this field belongs to - Object string - // These are the args after processing, they can be mutated in middleware to change what the resolver will get. - Args map[string]interface{} - // The raw field - Field CollectedField - // The index of array in path. - Index *int - // The result object of resolver - Result interface{} - // IsMethod indicates if the resolver is a method - IsMethod bool -} - -func (r *ResolverContext) Path() []interface{} { - var path []interface{} - for it := r; it != nil; it = it.Parent { - if it.Index != nil { - path = append(path, *it.Index) - } else if it.Field.Field != nil { - path = append(path, it.Field.Alias) - } - } - - // because we are walking up the chain, all the elements are backwards, do an inplace flip. - for i := len(path)/2 - 1; i >= 0; i-- { - opp := len(path) - 1 - i - path[i], path[opp] = path[opp], path[i] - } - - return path -} - -func GetResolverContext(ctx context.Context) *ResolverContext { - if val, ok := ctx.Value(resolver).(*ResolverContext); ok { - return val - } - return nil -} - -func WithResolverContext(ctx context.Context, rc *ResolverContext) context.Context { - rc.Parent = GetResolverContext(ctx) - return context.WithValue(ctx, resolver, rc) -} - -// This is just a convenient wrapper method for CollectFields -func CollectFieldsCtx(ctx context.Context, satisfies []string) []CollectedField { - resctx := GetResolverContext(ctx) - return CollectFields(GetRequestContext(ctx), resctx.Field.Selections, satisfies) -} - -// CollectAllFields returns a slice of all GraphQL field names that were selected for the current resolver context. -// The slice will contain the unique set of all field names requested regardless of fragment type conditions. -func CollectAllFields(ctx context.Context) []string { - resctx := GetResolverContext(ctx) - collected := CollectFields(GetRequestContext(ctx), resctx.Field.Selections, nil) - uniq := make([]string, 0, len(collected)) -Next: - for _, f := range collected { - for _, name := range uniq { - if name == f.Name { - continue Next - } - } - uniq = append(uniq, f.Name) - } - return uniq -} - -// Errorf sends an error string to the client, passing it through the formatter. -func (c *RequestContext) Errorf(ctx context.Context, format string, args ...interface{}) { - c.errorsMu.Lock() - defer c.errorsMu.Unlock() - - c.Errors = append(c.Errors, c.ErrorPresenter(ctx, fmt.Errorf(format, args...))) -} - -// Error sends an error to the client, passing it through the formatter. -func (c *RequestContext) Error(ctx context.Context, err error) { - c.errorsMu.Lock() - defer c.errorsMu.Unlock() - - c.Errors = append(c.Errors, c.ErrorPresenter(ctx, err)) -} - -// HasError returns true if the current field has already errored -func (c *RequestContext) HasError(rctx *ResolverContext) bool { - c.errorsMu.Lock() - defer c.errorsMu.Unlock() - path := rctx.Path() - - for _, err := range c.Errors { - if equalPath(err.Path, path) { - return true - } - } - return false -} - -// GetErrors returns a list of errors that occurred in the current field -func (c *RequestContext) GetErrors(rctx *ResolverContext) gqlerror.List { - c.errorsMu.Lock() - defer c.errorsMu.Unlock() - path := rctx.Path() - - var errs gqlerror.List - for _, err := range c.Errors { - if equalPath(err.Path, path) { - errs = append(errs, err) - } - } - return errs -} - -func equalPath(a []interface{}, b []interface{}) bool { - if len(a) != len(b) { - return false - } - - for i := 0; i < len(a); i++ { - if a[i] != b[i] { - return false - } - } - - return true -} - -// AddError is a convenience method for adding an error to the current response -func AddError(ctx context.Context, err error) { - GetRequestContext(ctx).Error(ctx, err) -} - -// AddErrorf is a convenience method for adding an error to the current response -func AddErrorf(ctx context.Context, format string, args ...interface{}) { - GetRequestContext(ctx).Errorf(ctx, format, args...) -} - -// RegisterExtension registers an extension, returns error if extension has already been registered -func (c *RequestContext) RegisterExtension(key string, value interface{}) error { - c.extensionsMu.Lock() - defer c.extensionsMu.Unlock() - - if c.Extensions == nil { - c.Extensions = make(map[string]interface{}) - } - - if _, ok := c.Extensions[key]; ok { - return fmt.Errorf("extension already registered for key %s", key) - } - - c.Extensions[key] = value - return nil -} - -// ChainFieldMiddleware add chain by FieldMiddleware -func ChainFieldMiddleware(handleFunc ...FieldMiddleware) FieldMiddleware { - n := len(handleFunc) - - if n > 1 { - lastI := n - 1 - return func(ctx context.Context, next Resolver) (interface{}, error) { - var ( - chainHandler Resolver - curI int - ) - chainHandler = func(currentCtx context.Context) (interface{}, error) { - if curI == lastI { - return next(currentCtx) - } - curI++ - res, err := handleFunc[curI](currentCtx, chainHandler) - curI-- - return res, err - - } - return handleFunc[0](ctx, chainHandler) - } - } - - if n == 1 { - return handleFunc[0] - } - - return func(ctx context.Context, next Resolver) (interface{}, error) { - return next(ctx) - } -} diff --git a/vendor/github.com/99designs/gqlgen/graphql/context_field.go b/vendor/github.com/99designs/gqlgen/graphql/context_field.go new file mode 100644 index 000000000..3c3385042 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/context_field.go @@ -0,0 +1,92 @@ +package graphql + +import ( + "context" + "time" + + "github.com/vektah/gqlparser/v2/ast" +) + +type key string + +const resolverCtx key = "resolver_context" + +// Deprecated: Use FieldContext instead +type ResolverContext = FieldContext + +type FieldContext struct { + Parent *FieldContext + // The name of the type this field belongs to + Object string + // These are the args after processing, they can be mutated in middleware to change what the resolver will get. + Args map[string]interface{} + // The raw field + Field CollectedField + // The index of array in path. + Index *int + // The result object of resolver + Result interface{} + // IsMethod indicates if the resolver is a method + IsMethod bool +} + +type FieldStats struct { + // When field execution started + Started time.Time + + // When argument marshaling finished + ArgumentsCompleted time.Time + + // When the field completed running all middleware. Not available inside field middleware! + Completed time.Time +} + +func (r *FieldContext) Path() ast.Path { + var path ast.Path + for it := r; it != nil; it = it.Parent { + if it.Index != nil { + path = append(path, ast.PathIndex(*it.Index)) + } else if it.Field.Field != nil { + path = append(path, ast.PathName(it.Field.Alias)) + } + } + + // because we are walking up the chain, all the elements are backwards, do an inplace flip. + for i := len(path)/2 - 1; i >= 0; i-- { + opp := len(path) - 1 - i + path[i], path[opp] = path[opp], path[i] + } + + return path +} + +// Deprecated: Use GetFieldContext instead +func GetResolverContext(ctx context.Context) *ResolverContext { + return GetFieldContext(ctx) +} + +func GetFieldContext(ctx context.Context) *FieldContext { + if val, ok := ctx.Value(resolverCtx).(*FieldContext); ok { + return val + } + return nil +} + +func WithFieldContext(ctx context.Context, rc *FieldContext) context.Context { + rc.Parent = GetFieldContext(ctx) + return context.WithValue(ctx, resolverCtx, rc) +} + +func equalPath(a ast.Path, b ast.Path) bool { + if len(a) != len(b) { + return false + } + + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + return false + } + } + + return true +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/context_field_input.go b/vendor/github.com/99designs/gqlgen/graphql/context_field_input.go new file mode 100644 index 000000000..0ed6f8b66 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/context_field_input.go @@ -0,0 +1,85 @@ +package graphql + +import ( + "context" + + "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" +) + +const fieldInputCtx key = "field_input_context" + +type FieldInputContext struct { + ParentField *FieldContext + ParentInput *FieldInputContext + Field *string + Index *int +} + +func (fic *FieldInputContext) Path() ast.Path { + var inputPath ast.Path + for it := fic; it != nil; it = it.ParentInput { + if it.Index != nil { + inputPath = append(inputPath, ast.PathIndex(*it.Index)) + } else if it.Field != nil { + inputPath = append(inputPath, ast.PathName(*it.Field)) + } + } + + // because we are walking up the chain, all the elements are backwards, do an inplace flip. + for i := len(inputPath)/2 - 1; i >= 0; i-- { + opp := len(inputPath) - 1 - i + inputPath[i], inputPath[opp] = inputPath[opp], inputPath[i] + } + + if fic.ParentField != nil { + fieldPath := fic.ParentField.Path() + return append(fieldPath, inputPath...) + + } + + return inputPath +} + +func NewFieldInputWithField(field string) *FieldInputContext { + return &FieldInputContext{Field: &field} +} + +func NewFieldInputWithIndex(index int) *FieldInputContext { + return &FieldInputContext{Index: &index} +} + +func WithFieldInputContext(ctx context.Context, fic *FieldInputContext) context.Context { + if fieldContext := GetFieldContext(ctx); fieldContext != nil { + fic.ParentField = fieldContext + } + if fieldInputContext := GetFieldInputContext(ctx); fieldInputContext != nil { + fic.ParentInput = fieldInputContext + } + + return context.WithValue(ctx, fieldInputCtx, fic) +} + +func GetFieldInputContext(ctx context.Context) *FieldInputContext { + if val, ok := ctx.Value(fieldInputCtx).(*FieldInputContext); ok { + return val + } + return nil +} + +func WrapErrorWithInputPath(ctx context.Context, err error) error { + if err == nil { + return nil + } + + inputContext := GetFieldInputContext(ctx) + path := inputContext.Path() + if gerr, ok := err.(*gqlerror.Error); ok { + if gerr.Path == nil { + gerr.Path = path + } + return gerr + } else { + return gqlerror.WrapPath(path, err) + } +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/context_operation.go b/vendor/github.com/99designs/gqlgen/graphql/context_operation.go new file mode 100644 index 000000000..d19b9fd34 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/context_operation.go @@ -0,0 +1,107 @@ +package graphql + +import ( + "context" + "errors" + + "github.com/vektah/gqlparser/v2/ast" +) + +// Deprecated: Please update all references to OperationContext instead +type RequestContext = OperationContext + +type OperationContext struct { + RawQuery string + Variables map[string]interface{} + OperationName string + Doc *ast.QueryDocument + + Operation *ast.OperationDefinition + DisableIntrospection bool + Recover RecoverFunc + ResolverMiddleware FieldMiddleware + + Stats Stats +} + +func (c *OperationContext) Validate(ctx context.Context) error { + if c.Doc == nil { + return errors.New("field 'Doc'is required") + } + if c.RawQuery == "" { + return errors.New("field 'RawQuery' is required") + } + if c.Variables == nil { + c.Variables = make(map[string]interface{}) + } + if c.ResolverMiddleware == nil { + return errors.New("field 'ResolverMiddleware' is required") + } + if c.Recover == nil { + c.Recover = DefaultRecover + } + + return nil +} + +const operationCtx key = "operation_context" + +// Deprecated: Please update all references to GetOperationContext instead +func GetRequestContext(ctx context.Context) *RequestContext { + return GetOperationContext(ctx) +} + +func GetOperationContext(ctx context.Context) *OperationContext { + if val, ok := ctx.Value(operationCtx).(*OperationContext); ok && val != nil { + return val + } + panic("missing operation context") +} + +func WithOperationContext(ctx context.Context, rc *OperationContext) context.Context { + return context.WithValue(ctx, operationCtx, rc) +} + +// HasOperationContext checks if the given context is part of an ongoing operation +// +// Some errors can happen outside of an operation, eg json unmarshal errors. +func HasOperationContext(ctx context.Context) bool { + _, ok := ctx.Value(operationCtx).(*OperationContext) + return ok +} + +// This is just a convenient wrapper method for CollectFields +func CollectFieldsCtx(ctx context.Context, satisfies []string) []CollectedField { + resctx := GetFieldContext(ctx) + return CollectFields(GetOperationContext(ctx), resctx.Field.Selections, satisfies) +} + +// CollectAllFields returns a slice of all GraphQL field names that were selected for the current resolver context. +// The slice will contain the unique set of all field names requested regardless of fragment type conditions. +func CollectAllFields(ctx context.Context) []string { + resctx := GetFieldContext(ctx) + collected := CollectFields(GetOperationContext(ctx), resctx.Field.Selections, nil) + uniq := make([]string, 0, len(collected)) +Next: + for _, f := range collected { + for _, name := range uniq { + if name == f.Name { + continue Next + } + } + uniq = append(uniq, f.Name) + } + return uniq +} + +// Errorf sends an error string to the client, passing it through the formatter. +// Deprecated: use graphql.AddErrorf(ctx, err) instead +func (c *OperationContext) Errorf(ctx context.Context, format string, args ...interface{}) { + AddErrorf(ctx, format, args...) +} + +// Error sends an error to the client, passing it through the formatter. +// Deprecated: use graphql.AddError(ctx, err) instead +func (c *OperationContext) Error(ctx context.Context, err error) { + AddError(ctx, err) +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/context_response.go b/vendor/github.com/99designs/gqlgen/graphql/context_response.go new file mode 100644 index 000000000..cc952ed72 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/context_response.go @@ -0,0 +1,157 @@ +package graphql + +import ( + "context" + "fmt" + "sync" + + "github.com/vektah/gqlparser/v2/gqlerror" +) + +type responseContext struct { + errorPresenter ErrorPresenterFunc + recover RecoverFunc + + errors gqlerror.List + errorsMu sync.Mutex + + extensions map[string]interface{} + extensionsMu sync.Mutex +} + +const resultCtx key = "result_context" + +func getResponseContext(ctx context.Context) *responseContext { + val, ok := ctx.Value(resultCtx).(*responseContext) + if !ok { + panic("missing response context") + } + return val +} + +func WithResponseContext(ctx context.Context, presenterFunc ErrorPresenterFunc, recoverFunc RecoverFunc) context.Context { + return context.WithValue(ctx, resultCtx, &responseContext{ + errorPresenter: presenterFunc, + recover: recoverFunc, + }) +} + +// AddErrorf writes a formatted error to the client, first passing it through the error presenter. +func AddErrorf(ctx context.Context, format string, args ...interface{}) { + c := getResponseContext(ctx) + + c.errorsMu.Lock() + defer c.errorsMu.Unlock() + + c.errors = append(c.errors, c.errorPresenter(ctx, fmt.Errorf(format, args...))) +} + +// AddError sends an error to the client, first passing it through the error presenter. +func AddError(ctx context.Context, err error) { + c := getResponseContext(ctx) + + c.errorsMu.Lock() + defer c.errorsMu.Unlock() + + c.errors = append(c.errors, c.errorPresenter(ctx, err)) +} + +func Recover(ctx context.Context, err interface{}) (userMessage error) { + c := getResponseContext(ctx) + return c.recover(ctx, err) +} + +// HasFieldError returns true if the given field has already errored +func HasFieldError(ctx context.Context, rctx *FieldContext) bool { + c := getResponseContext(ctx) + + c.errorsMu.Lock() + defer c.errorsMu.Unlock() + + if len(c.errors) == 0 { + return false + } + + path := rctx.Path() + for _, err := range c.errors { + if equalPath(err.Path, path) { + return true + } + } + return false +} + +// GetFieldErrors returns a list of errors that occurred in the given field +func GetFieldErrors(ctx context.Context, rctx *FieldContext) gqlerror.List { + c := getResponseContext(ctx) + + c.errorsMu.Lock() + defer c.errorsMu.Unlock() + + if len(c.errors) == 0 { + return nil + } + + path := rctx.Path() + var errs gqlerror.List + for _, err := range c.errors { + if equalPath(err.Path, path) { + errs = append(errs, err) + } + } + return errs +} + +func GetErrors(ctx context.Context) gqlerror.List { + resCtx := getResponseContext(ctx) + resCtx.errorsMu.Lock() + defer resCtx.errorsMu.Unlock() + + if len(resCtx.errors) == 0 { + return nil + } + + errs := resCtx.errors + cpy := make(gqlerror.List, len(errs)) + for i := range errs { + errCpy := *errs[i] + cpy[i] = &errCpy + } + return cpy +} + +// RegisterExtension allows you to add a new extension into the graphql response +func RegisterExtension(ctx context.Context, key string, value interface{}) { + c := getResponseContext(ctx) + c.extensionsMu.Lock() + defer c.extensionsMu.Unlock() + + if c.extensions == nil { + c.extensions = make(map[string]interface{}) + } + + if _, ok := c.extensions[key]; ok { + panic(fmt.Errorf("extension already registered for key %s", key)) + } + + c.extensions[key] = value +} + +// GetExtensions returns any extensions registered in the current result context +func GetExtensions(ctx context.Context) map[string]interface{} { + ext := getResponseContext(ctx).extensions + if ext == nil { + return map[string]interface{}{} + } + + return ext +} + +func GetExtension(ctx context.Context, name string) interface{} { + ext := getResponseContext(ctx).extensions + if ext == nil { + return nil + } + + return ext[name] +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/errcode/codes.go b/vendor/github.com/99designs/gqlgen/graphql/errcode/codes.go new file mode 100644 index 000000000..774ab7a9e --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/errcode/codes.go @@ -0,0 +1,49 @@ +package errcode + +import ( + "github.com/vektah/gqlparser/v2/gqlerror" +) + +const ValidationFailed = "GRAPHQL_VALIDATION_FAILED" +const ParseFailed = "GRAPHQL_PARSE_FAILED" + +type ErrorKind int + +const ( + // issues with graphql (validation, parsing). 422s in http, GQL_ERROR in websocket + KindProtocol ErrorKind = iota + // user errors, 200s in http, GQL_DATA in websocket + KindUser +) + +var codeType = map[string]ErrorKind{ + ValidationFailed: KindProtocol, + ParseFailed: KindProtocol, +} + +// RegisterErrorType should be called by extensions that want to customize the http status codes for errors they return +func RegisterErrorType(code string, kind ErrorKind) { + codeType[code] = kind +} + +// Set the error code on a given graphql error extension +func Set(err *gqlerror.Error, value string) { + if err.Extensions == nil { + err.Extensions = map[string]interface{}{} + } + + err.Extensions["code"] = value +} + +// get the kind of the first non User error, defaults to User if no errors have a custom extension +func GetErrorKind(errs gqlerror.List) ErrorKind { + for _, err := range errs { + if code, ok := err.Extensions["code"].(string); ok { + if kind, ok := codeType[code]; ok && kind != KindUser { + return kind + } + } + } + + return KindUser +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/error.go b/vendor/github.com/99designs/gqlgen/graphql/error.go index af8b4ce40..201058a2f 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/error.go +++ b/vendor/github.com/99designs/gqlgen/graphql/error.go @@ -3,10 +3,10 @@ package graphql import ( "context" - "github.com/vektah/gqlparser/gqlerror" + "github.com/vektah/gqlparser/v2/gqlerror" ) -type ErrorPresenterFunc func(context.Context, error) *gqlerror.Error +type ErrorPresenterFunc func(ctx context.Context, err error) *gqlerror.Error type ExtendedError interface { Extensions() map[string]interface{} @@ -15,7 +15,7 @@ type ExtendedError interface { func DefaultErrorPresenter(ctx context.Context, err error) *gqlerror.Error { if gqlerr, ok := err.(*gqlerror.Error); ok { if gqlerr.Path == nil { - gqlerr.Path = GetResolverContext(ctx).Path() + gqlerr.Path = GetFieldContext(ctx).Path() } return gqlerr } @@ -27,7 +27,7 @@ func DefaultErrorPresenter(ctx context.Context, err error) *gqlerror.Error { return &gqlerror.Error{ Message: err.Error(), - Path: GetResolverContext(ctx).Path(), + Path: GetFieldContext(ctx).Path(), Extensions: extensions, } } diff --git a/vendor/github.com/99designs/gqlgen/graphql/exec.go b/vendor/github.com/99designs/gqlgen/graphql/executable_schema.go similarity index 77% rename from vendor/github.com/99designs/gqlgen/graphql/exec.go rename to vendor/github.com/99designs/gqlgen/graphql/executable_schema.go index 3e00a4d57..dc53b6881 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/exec.go +++ b/vendor/github.com/99designs/gqlgen/graphql/executable_schema.go @@ -1,29 +1,29 @@ +//go:generate go run github.com/matryer/moq -out executable_schema_mock.go . ExecutableSchema + package graphql import ( "context" "fmt" - "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/v2/ast" ) type ExecutableSchema interface { Schema() *ast.Schema Complexity(typeName, fieldName string, childComplexity int, args map[string]interface{}) (int, bool) - Query(ctx context.Context, op *ast.OperationDefinition) *Response - Mutation(ctx context.Context, op *ast.OperationDefinition) *Response - Subscription(ctx context.Context, op *ast.OperationDefinition) func() *Response + Exec(ctx context.Context) ResponseHandler } // CollectFields returns the set of fields from an ast.SelectionSet where all collected fields satisfy at least one of the GraphQL types // passed through satisfies. Providing an empty or nil slice for satisfies will return collect all fields regardless of fragment // type conditions. -func CollectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []string) []CollectedField { +func CollectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies []string) []CollectedField { return collectFields(reqCtx, selSet, satisfies, map[string]bool{}) } -func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []string, visited map[string]bool) []CollectedField { +func collectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies []string, visited map[string]bool) []CollectedField { groupedFields := make([]CollectedField, 0, len(selSet)) for _, sel := range selSet { @@ -32,7 +32,7 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies [] if !shouldIncludeNode(sel.Directives, reqCtx.Variables) { continue } - f := getOrCreateAndAppendField(&groupedFields, sel.Alias, func() CollectedField { + f := getOrCreateAndAppendField(&groupedFields, sel.Alias, sel.ObjectDefinition, func() CollectedField { return CollectedField{Field: sel} }) @@ -45,7 +45,7 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies [] continue } for _, childField := range collectFields(reqCtx, sel.SelectionSet, satisfies, visited) { - f := getOrCreateAndAppendField(&groupedFields, childField.Name, func() CollectedField { return childField }) + f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.ObjectDefinition, func() CollectedField { return childField }) f.Selections = append(f.Selections, childField.Selections...) } @@ -70,7 +70,7 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies [] } for _, childField := range collectFields(reqCtx, fragment.SelectionSet, satisfies, visited) { - f := getOrCreateAndAppendField(&groupedFields, childField.Name, func() CollectedField { return childField }) + f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.ObjectDefinition, func() CollectedField { return childField }) f.Selections = append(f.Selections, childField.Selections...) } default: @@ -96,9 +96,9 @@ func instanceOf(val string, satisfies []string) bool { return false } -func getOrCreateAndAppendField(c *[]CollectedField, name string, creator func() CollectedField) *CollectedField { +func getOrCreateAndAppendField(c *[]CollectedField, name string, objectDefinition *ast.Definition, creator func() CollectedField) *CollectedField { for i, cf := range *c { - if cf.Alias == name { + if cf.Alias == name && (cf.ObjectDefinition == objectDefinition || (cf.ObjectDefinition != nil && objectDefinition != nil && cf.ObjectDefinition.Name == objectDefinition.Name)) { return &(*c)[i] } } diff --git a/vendor/github.com/99designs/gqlgen/graphql/executable_schema_mock.go b/vendor/github.com/99designs/gqlgen/graphql/executable_schema_mock.go new file mode 100644 index 000000000..0c021d3d0 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/executable_schema_mock.go @@ -0,0 +1,175 @@ +// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package graphql + +import ( + "context" + "github.com/vektah/gqlparser/v2/ast" + "sync" +) + +var ( + lockExecutableSchemaMockComplexity sync.RWMutex + lockExecutableSchemaMockExec sync.RWMutex + lockExecutableSchemaMockSchema sync.RWMutex +) + +// Ensure, that ExecutableSchemaMock does implement ExecutableSchema. +// If this is not the case, regenerate this file with moq. +var _ ExecutableSchema = &ExecutableSchemaMock{} + +// ExecutableSchemaMock is a mock implementation of ExecutableSchema. +// +// func TestSomethingThatUsesExecutableSchema(t *testing.T) { +// +// // make and configure a mocked ExecutableSchema +// mockedExecutableSchema := &ExecutableSchemaMock{ +// ComplexityFunc: func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool) { +// panic("mock out the Complexity method") +// }, +// ExecFunc: func(ctx context.Context) ResponseHandler { +// panic("mock out the Exec method") +// }, +// SchemaFunc: func() *ast.Schema { +// panic("mock out the Schema method") +// }, +// } +// +// // use mockedExecutableSchema in code that requires ExecutableSchema +// // and then make assertions. +// +// } +type ExecutableSchemaMock struct { + // ComplexityFunc mocks the Complexity method. + ComplexityFunc func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool) + + // ExecFunc mocks the Exec method. + ExecFunc func(ctx context.Context) ResponseHandler + + // SchemaFunc mocks the Schema method. + SchemaFunc func() *ast.Schema + + // calls tracks calls to the methods. + calls struct { + // Complexity holds details about calls to the Complexity method. + Complexity []struct { + // TypeName is the typeName argument value. + TypeName string + // FieldName is the fieldName argument value. + FieldName string + // ChildComplexity is the childComplexity argument value. + ChildComplexity int + // Args is the args argument value. + Args map[string]interface{} + } + // Exec holds details about calls to the Exec method. + Exec []struct { + // Ctx is the ctx argument value. + Ctx context.Context + } + // Schema holds details about calls to the Schema method. + Schema []struct { + } + } +} + +// Complexity calls ComplexityFunc. +func (mock *ExecutableSchemaMock) Complexity(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool) { + if mock.ComplexityFunc == nil { + panic("ExecutableSchemaMock.ComplexityFunc: method is nil but ExecutableSchema.Complexity was just called") + } + callInfo := struct { + TypeName string + FieldName string + ChildComplexity int + Args map[string]interface{} + }{ + TypeName: typeName, + FieldName: fieldName, + ChildComplexity: childComplexity, + Args: args, + } + lockExecutableSchemaMockComplexity.Lock() + mock.calls.Complexity = append(mock.calls.Complexity, callInfo) + lockExecutableSchemaMockComplexity.Unlock() + return mock.ComplexityFunc(typeName, fieldName, childComplexity, args) +} + +// ComplexityCalls gets all the calls that were made to Complexity. +// Check the length with: +// len(mockedExecutableSchema.ComplexityCalls()) +func (mock *ExecutableSchemaMock) ComplexityCalls() []struct { + TypeName string + FieldName string + ChildComplexity int + Args map[string]interface{} +} { + var calls []struct { + TypeName string + FieldName string + ChildComplexity int + Args map[string]interface{} + } + lockExecutableSchemaMockComplexity.RLock() + calls = mock.calls.Complexity + lockExecutableSchemaMockComplexity.RUnlock() + return calls +} + +// Exec calls ExecFunc. +func (mock *ExecutableSchemaMock) Exec(ctx context.Context) ResponseHandler { + if mock.ExecFunc == nil { + panic("ExecutableSchemaMock.ExecFunc: method is nil but ExecutableSchema.Exec was just called") + } + callInfo := struct { + Ctx context.Context + }{ + Ctx: ctx, + } + lockExecutableSchemaMockExec.Lock() + mock.calls.Exec = append(mock.calls.Exec, callInfo) + lockExecutableSchemaMockExec.Unlock() + return mock.ExecFunc(ctx) +} + +// ExecCalls gets all the calls that were made to Exec. +// Check the length with: +// len(mockedExecutableSchema.ExecCalls()) +func (mock *ExecutableSchemaMock) ExecCalls() []struct { + Ctx context.Context +} { + var calls []struct { + Ctx context.Context + } + lockExecutableSchemaMockExec.RLock() + calls = mock.calls.Exec + lockExecutableSchemaMockExec.RUnlock() + return calls +} + +// Schema calls SchemaFunc. +func (mock *ExecutableSchemaMock) Schema() *ast.Schema { + if mock.SchemaFunc == nil { + panic("ExecutableSchemaMock.SchemaFunc: method is nil but ExecutableSchema.Schema was just called") + } + callInfo := struct { + }{} + lockExecutableSchemaMockSchema.Lock() + mock.calls.Schema = append(mock.calls.Schema, callInfo) + lockExecutableSchemaMockSchema.Unlock() + return mock.SchemaFunc() +} + +// SchemaCalls gets all the calls that were made to Schema. +// Check the length with: +// len(mockedExecutableSchema.SchemaCalls()) +func (mock *ExecutableSchemaMock) SchemaCalls() []struct { +} { + var calls []struct { + } + lockExecutableSchemaMockSchema.RLock() + calls = mock.calls.Schema + lockExecutableSchemaMockSchema.RUnlock() + return calls +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/executor/executor.go b/vendor/github.com/99designs/gqlgen/graphql/executor/executor.go new file mode 100644 index 000000000..b3163a4bd --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/executor/executor.go @@ -0,0 +1,191 @@ +package executor + +import ( + "context" + + "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/errcode" + "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" + "github.com/vektah/gqlparser/v2/parser" + "github.com/vektah/gqlparser/v2/validator" +) + +// Executor executes graphql queries against a schema. +type Executor struct { + es graphql.ExecutableSchema + extensions []graphql.HandlerExtension + ext extensions + + errorPresenter graphql.ErrorPresenterFunc + recoverFunc graphql.RecoverFunc + queryCache graphql.Cache +} + +var _ graphql.GraphExecutor = &Executor{} + +// New creates a new Executor with the given schema, and a default error and +// recovery callbacks, and no query cache or extensions. +func New(es graphql.ExecutableSchema) *Executor { + e := &Executor{ + es: es, + errorPresenter: graphql.DefaultErrorPresenter, + recoverFunc: graphql.DefaultRecover, + queryCache: graphql.NoCache{}, + ext: processExtensions(nil), + } + return e +} + +func (e *Executor) CreateOperationContext(ctx context.Context, params *graphql.RawParams) (*graphql.OperationContext, gqlerror.List) { + rc := &graphql.OperationContext{ + DisableIntrospection: true, + Recover: e.recoverFunc, + ResolverMiddleware: e.ext.fieldMiddleware, + Stats: graphql.Stats{ + Read: params.ReadTime, + OperationStart: graphql.GetStartTime(ctx), + }, + } + ctx = graphql.WithOperationContext(ctx, rc) + + for _, p := range e.ext.operationParameterMutators { + if err := p.MutateOperationParameters(ctx, params); err != nil { + return rc, gqlerror.List{err} + } + } + + rc.RawQuery = params.Query + rc.OperationName = params.OperationName + + var listErr gqlerror.List + rc.Doc, listErr = e.parseQuery(ctx, &rc.Stats, params.Query) + if len(listErr) != 0 { + return rc, listErr + } + + rc.Operation = rc.Doc.Operations.ForName(params.OperationName) + if rc.Operation == nil { + return rc, gqlerror.List{gqlerror.Errorf("operation %s not found", params.OperationName)} + } + + var err *gqlerror.Error + rc.Variables, err = validator.VariableValues(e.es.Schema(), rc.Operation, params.Variables) + if err != nil { + errcode.Set(err, errcode.ValidationFailed) + return rc, gqlerror.List{err} + } + rc.Stats.Validation.End = graphql.Now() + + for _, p := range e.ext.operationContextMutators { + if err := p.MutateOperationContext(ctx, rc); err != nil { + return rc, gqlerror.List{err} + } + } + + return rc, nil +} + +func (e *Executor) DispatchOperation(ctx context.Context, rc *graphql.OperationContext) (graphql.ResponseHandler, context.Context) { + ctx = graphql.WithOperationContext(ctx, rc) + + var innerCtx context.Context + res := e.ext.operationMiddleware(ctx, func(ctx context.Context) graphql.ResponseHandler { + innerCtx = ctx + + tmpResponseContext := graphql.WithResponseContext(ctx, e.errorPresenter, e.recoverFunc) + responses := e.es.Exec(tmpResponseContext) + if errs := graphql.GetErrors(tmpResponseContext); errs != nil { + return graphql.OneShot(&graphql.Response{Errors: errs}) + } + + return func(ctx context.Context) *graphql.Response { + ctx = graphql.WithResponseContext(ctx, e.errorPresenter, e.recoverFunc) + resp := e.ext.responseMiddleware(ctx, func(ctx context.Context) *graphql.Response { + resp := responses(ctx) + if resp == nil { + return nil + } + resp.Errors = append(resp.Errors, graphql.GetErrors(ctx)...) + resp.Extensions = graphql.GetExtensions(ctx) + return resp + }) + if resp == nil { + return nil + } + + return resp + } + }) + + return res, innerCtx +} + +func (e *Executor) DispatchError(ctx context.Context, list gqlerror.List) *graphql.Response { + ctx = graphql.WithResponseContext(ctx, e.errorPresenter, e.recoverFunc) + for _, gErr := range list { + graphql.AddError(ctx, gErr) + } + + resp := e.ext.responseMiddleware(ctx, func(ctx context.Context) *graphql.Response { + resp := &graphql.Response{ + Errors: list, + } + resp.Extensions = graphql.GetExtensions(ctx) + return resp + }) + + return resp +} + +func (e *Executor) PresentRecoveredError(ctx context.Context, err interface{}) *gqlerror.Error { + return e.errorPresenter(ctx, e.recoverFunc(ctx, err)) +} + +func (e *Executor) SetQueryCache(cache graphql.Cache) { + e.queryCache = cache +} + +func (e *Executor) SetErrorPresenter(f graphql.ErrorPresenterFunc) { + e.errorPresenter = f +} + +func (e *Executor) SetRecoverFunc(f graphql.RecoverFunc) { + e.recoverFunc = f +} + +// parseQuery decodes the incoming query and validates it, pulling from cache if present. +// +// NOTE: This should NOT look at variables, they will change per request. It should only parse and validate +// the raw query string. +func (e *Executor) parseQuery(ctx context.Context, stats *graphql.Stats, query string) (*ast.QueryDocument, gqlerror.List) { + stats.Parsing.Start = graphql.Now() + + if doc, ok := e.queryCache.Get(ctx, query); ok { + now := graphql.Now() + + stats.Parsing.End = now + stats.Validation.Start = now + return doc.(*ast.QueryDocument), nil + } + + doc, err := parser.ParseQuery(&ast.Source{Input: query}) + if err != nil { + errcode.Set(err, errcode.ParseFailed) + return nil, gqlerror.List{err} + } + stats.Parsing.End = graphql.Now() + + stats.Validation.Start = graphql.Now() + listErr := validator.Validate(e.es.Schema(), doc) + if len(listErr) != 0 { + for _, e := range listErr { + errcode.Set(e, errcode.ValidationFailed) + } + return nil, listErr + } + + e.queryCache.Add(ctx, query, doc) + + return doc, nil +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/executor/extensions.go b/vendor/github.com/99designs/gqlgen/graphql/executor/extensions.go new file mode 100644 index 000000000..30a48ce80 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/executor/extensions.go @@ -0,0 +1,159 @@ +package executor + +import ( + "context" + "fmt" + + "github.com/99designs/gqlgen/graphql" +) + +// Use adds the given extension to this Executor. +func (e *Executor) Use(extension graphql.HandlerExtension) { + if err := extension.Validate(e.es); err != nil { + panic(err) + } + + switch extension.(type) { + case graphql.OperationParameterMutator, + graphql.OperationContextMutator, + graphql.OperationInterceptor, + graphql.FieldInterceptor, + graphql.ResponseInterceptor: + e.extensions = append(e.extensions, extension) + e.ext = processExtensions(e.extensions) + + default: + panic(fmt.Errorf("cannot Use %T as a gqlgen handler extension because it does not implement any extension hooks", extension)) + } +} + +// AroundFields is a convenience method for creating an extension that only implements field middleware +func (e *Executor) AroundFields(f graphql.FieldMiddleware) { + e.Use(aroundFieldFunc(f)) +} + +// AroundOperations is a convenience method for creating an extension that only implements operation middleware +func (e *Executor) AroundOperations(f graphql.OperationMiddleware) { + e.Use(aroundOpFunc(f)) +} + +// AroundResponses is a convenience method for creating an extension that only implements response middleware +func (e *Executor) AroundResponses(f graphql.ResponseMiddleware) { + e.Use(aroundRespFunc(f)) +} + +type extensions struct { + operationMiddleware graphql.OperationMiddleware + responseMiddleware graphql.ResponseMiddleware + fieldMiddleware graphql.FieldMiddleware + operationParameterMutators []graphql.OperationParameterMutator + operationContextMutators []graphql.OperationContextMutator +} + +func processExtensions(exts []graphql.HandlerExtension) extensions { + e := extensions{ + operationMiddleware: func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler { + return next(ctx) + }, + responseMiddleware: func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response { + return next(ctx) + }, + fieldMiddleware: func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { + return next(ctx) + }, + } + + // this loop goes backwards so the first extension is the outer most middleware and runs first. + for i := len(exts) - 1; i >= 0; i-- { + p := exts[i] + if p, ok := p.(graphql.OperationInterceptor); ok { + previous := e.operationMiddleware + e.operationMiddleware = func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler { + return p.InterceptOperation(ctx, func(ctx context.Context) graphql.ResponseHandler { + return previous(ctx, next) + }) + } + } + + if p, ok := p.(graphql.ResponseInterceptor); ok { + previous := e.responseMiddleware + e.responseMiddleware = func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response { + return p.InterceptResponse(ctx, func(ctx context.Context) *graphql.Response { + return previous(ctx, next) + }) + } + } + + if p, ok := p.(graphql.FieldInterceptor); ok { + previous := e.fieldMiddleware + e.fieldMiddleware = func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { + return p.InterceptField(ctx, func(ctx context.Context) (res interface{}, err error) { + return previous(ctx, next) + }) + } + } + } + + for _, p := range exts { + if p, ok := p.(graphql.OperationParameterMutator); ok { + e.operationParameterMutators = append(e.operationParameterMutators, p) + } + + if p, ok := p.(graphql.OperationContextMutator); ok { + e.operationContextMutators = append(e.operationContextMutators, p) + } + } + + return e +} + +type aroundOpFunc func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler + +func (r aroundOpFunc) ExtensionName() string { + return "InlineOperationFunc" +} + +func (r aroundOpFunc) Validate(schema graphql.ExecutableSchema) error { + if r == nil { + return fmt.Errorf("OperationFunc can not be nil") + } + return nil +} + +func (r aroundOpFunc) InterceptOperation(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler { + return r(ctx, next) +} + +type aroundRespFunc func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response + +func (r aroundRespFunc) ExtensionName() string { + return "InlineResponseFunc" +} + +func (r aroundRespFunc) Validate(schema graphql.ExecutableSchema) error { + if r == nil { + return fmt.Errorf("ResponseFunc can not be nil") + } + return nil +} + +func (r aroundRespFunc) InterceptResponse(ctx context.Context, next graphql.ResponseHandler) *graphql.Response { + return r(ctx, next) +} + +type aroundFieldFunc func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) + +func (f aroundFieldFunc) ExtensionName() string { + return "InlineFieldFunc" +} + +func (f aroundFieldFunc) Validate(schema graphql.ExecutableSchema) error { + if f == nil { + return fmt.Errorf("FieldFunc can not be nil") + } + return nil +} + +func (f aroundFieldFunc) InterceptField(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { + return f(ctx, next) +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler.go b/vendor/github.com/99designs/gqlgen/graphql/handler.go new file mode 100644 index 000000000..e74af2f03 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/handler.go @@ -0,0 +1,123 @@ +package graphql + +import ( + "context" + "net/http" + "strconv" + "strings" + + "github.com/vektah/gqlparser/v2/gqlerror" +) + +type ( + OperationMiddleware func(ctx context.Context, next OperationHandler) ResponseHandler + OperationHandler func(ctx context.Context) ResponseHandler + + ResponseHandler func(ctx context.Context) *Response + ResponseMiddleware func(ctx context.Context, next ResponseHandler) *Response + + Resolver func(ctx context.Context) (res interface{}, err error) + FieldMiddleware func(ctx context.Context, next Resolver) (res interface{}, err error) + + RawParams struct { + Query string `json:"query"` + OperationName string `json:"operationName"` + Variables map[string]interface{} `json:"variables"` + Extensions map[string]interface{} `json:"extensions"` + + ReadTime TraceTiming `json:"-"` + } + + GraphExecutor interface { + CreateOperationContext(ctx context.Context, params *RawParams) (*OperationContext, gqlerror.List) + DispatchOperation(ctx context.Context, rc *OperationContext) (ResponseHandler, context.Context) + DispatchError(ctx context.Context, list gqlerror.List) *Response + } + + // HandlerExtension adds functionality to the http handler. See the list of possible hook points below + // Its important to understand the lifecycle of a graphql request and the terminology we use in gqlgen + // before working with these + // + // +--- REQUEST POST /graphql --------------------------------------------+ + // | +- OPERATION query OpName { viewer { name } } -----------------------+ | + // | | RESPONSE { "data": { "viewer": { "name": "bob" } } } | | + // | +- OPERATION subscription OpName2 { chat { message } } --------------+ | + // | | RESPONSE { "data": { "chat": { "message": "hello" } } } | | + // | | RESPONSE { "data": { "chat": { "message": "byee" } } } | | + // | +--------------------------------------------------------------------+ | + // +------------------------------------------------------------------------+ + HandlerExtension interface { + // ExtensionName should be a CamelCase string version of the extension which may be shown in stats and logging. + ExtensionName() string + // Validate is called when adding an extension to the server, it allows validation against the servers schema. + Validate(schema ExecutableSchema) error + } + + // OperationParameterMutator is called before creating a request context. allows manipulating the raw query + // on the way in. + OperationParameterMutator interface { + MutateOperationParameters(ctx context.Context, request *RawParams) *gqlerror.Error + } + + // OperationContextMutator is called after creating the request context, but before executing the root resolver. + OperationContextMutator interface { + MutateOperationContext(ctx context.Context, rc *OperationContext) *gqlerror.Error + } + + // OperationInterceptor is called for each incoming query, for basic requests the writer will be invoked once, + // for subscriptions it will be invoked multiple times. + OperationInterceptor interface { + InterceptOperation(ctx context.Context, next OperationHandler) ResponseHandler + } + + // ResponseInterceptor is called around each graphql operation response. This can be called many times for a single + // operation the case of subscriptions. + ResponseInterceptor interface { + InterceptResponse(ctx context.Context, next ResponseHandler) *Response + } + + // FieldInterceptor called around each field + FieldInterceptor interface { + InterceptField(ctx context.Context, next Resolver) (res interface{}, err error) + } + + // Transport provides support for different wire level encodings of graphql requests, eg Form, Get, Post, Websocket + Transport interface { + Supports(r *http.Request) bool + Do(w http.ResponseWriter, r *http.Request, exec GraphExecutor) + } +) + +type Status int + +func (p *RawParams) AddUpload(upload Upload, key, path string) *gqlerror.Error { + if !strings.HasPrefix(path, "variables.") { + return gqlerror.Errorf("invalid operations paths for key %s", key) + } + + var ptr interface{} = p.Variables + parts := strings.Split(path, ".") + + // skip the first part (variables) because we started there + for i, p := range parts[1:] { + last := i == len(parts)-2 + if ptr == nil { + return gqlerror.Errorf("path is missing \"variables.\" prefix, key: %s, path: %s", key, path) + } + if index, parseNbrErr := strconv.Atoi(p); parseNbrErr == nil { + if last { + ptr.([]interface{})[index] = upload + } else { + ptr = ptr.([]interface{})[index] + } + } else { + if last { + ptr.(map[string]interface{})[p] = upload + } else { + ptr = ptr.(map[string]interface{})[p] + } + } + } + + return nil +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go b/vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go new file mode 100644 index 000000000..83f4c1bfc --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go @@ -0,0 +1,112 @@ +package extension + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "fmt" + + "github.com/99designs/gqlgen/graphql/errcode" + + "github.com/vektah/gqlparser/v2/gqlerror" + + "github.com/99designs/gqlgen/graphql" + "github.com/mitchellh/mapstructure" +) + +const errPersistedQueryNotFound = "PersistedQueryNotFound" +const errPersistedQueryNotFoundCode = "PERSISTED_QUERY_NOT_FOUND" + +// AutomaticPersistedQuery saves client upload by optimistically sending only the hashes of queries, if the server +// does not yet know what the query is for the hash it will respond telling the client to send the query along with the +// hash in the next request. +// see https://github.com/apollographql/apollo-link-persisted-queries +type AutomaticPersistedQuery struct { + Cache graphql.Cache +} + +type ApqStats struct { + // The hash of the incoming query + Hash string + + // SentQuery is true if the incoming request sent the full query + SentQuery bool +} + +const apqExtension = "APQ" + +var _ interface { + graphql.OperationParameterMutator + graphql.HandlerExtension +} = AutomaticPersistedQuery{} + +func (a AutomaticPersistedQuery) ExtensionName() string { + return "AutomaticPersistedQuery" +} + +func (a AutomaticPersistedQuery) Validate(schema graphql.ExecutableSchema) error { + if a.Cache == nil { + return fmt.Errorf("AutomaticPersistedQuery.Cache can not be nil") + } + return nil +} + +func (a AutomaticPersistedQuery) MutateOperationParameters(ctx context.Context, rawParams *graphql.RawParams) *gqlerror.Error { + if rawParams.Extensions["persistedQuery"] == nil { + return nil + } + + var extension struct { + Sha256 string `mapstructure:"sha256Hash"` + Version int64 `mapstructure:"version"` + } + + if err := mapstructure.Decode(rawParams.Extensions["persistedQuery"], &extension); err != nil { + return gqlerror.Errorf("invalid APQ extension data") + } + + if extension.Version != 1 { + return gqlerror.Errorf("unsupported APQ version") + } + + fullQuery := false + if rawParams.Query == "" { + // client sent optimistic query hash without query string, get it from the cache + query, ok := a.Cache.Get(ctx, extension.Sha256) + if !ok { + err := gqlerror.Errorf(errPersistedQueryNotFound) + errcode.Set(err, errPersistedQueryNotFoundCode) + return err + } + rawParams.Query = query.(string) + } else { + // client sent optimistic query hash with query string, verify and store it + if computeQueryHash(rawParams.Query) != extension.Sha256 { + return gqlerror.Errorf("provided APQ hash does not match query") + } + a.Cache.Add(ctx, extension.Sha256, rawParams.Query) + fullQuery = true + } + + graphql.GetOperationContext(ctx).Stats.SetExtension(apqExtension, &ApqStats{ + Hash: extension.Sha256, + SentQuery: fullQuery, + }) + + return nil +} + +func GetApqStats(ctx context.Context) *ApqStats { + rc := graphql.GetOperationContext(ctx) + if rc == nil { + return nil + } + + s, _ := rc.Stats.GetExtension(apqExtension).(*ApqStats) + return s +} + +func computeQueryHash(query string) string { + b := sha256.Sum256([]byte(query)) + return hex.EncodeToString(b[:]) +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/extension/complexity.go b/vendor/github.com/99designs/gqlgen/graphql/handler/extension/complexity.go new file mode 100644 index 000000000..2d853802b --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/extension/complexity.go @@ -0,0 +1,88 @@ +package extension + +import ( + "context" + "fmt" + + "github.com/99designs/gqlgen/complexity" + "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/errcode" + "github.com/vektah/gqlparser/v2/gqlerror" +) + +const errComplexityLimit = "COMPLEXITY_LIMIT_EXCEEDED" + +// ComplexityLimit allows you to define a limit on query complexity +// +// If a query is submitted that exceeds the limit, a 422 status code will be returned. +type ComplexityLimit struct { + Func func(ctx context.Context, rc *graphql.OperationContext) int + + es graphql.ExecutableSchema +} + +var _ interface { + graphql.OperationContextMutator + graphql.HandlerExtension +} = &ComplexityLimit{} + +const complexityExtension = "ComplexityLimit" + +type ComplexityStats struct { + // The calculated complexity for this request + Complexity int + + // The complexity limit for this request returned by the extension func + ComplexityLimit int +} + +// FixedComplexityLimit sets a complexity limit that does not change +func FixedComplexityLimit(limit int) *ComplexityLimit { + return &ComplexityLimit{ + Func: func(ctx context.Context, rc *graphql.OperationContext) int { + return limit + }, + } +} + +func (c ComplexityLimit) ExtensionName() string { + return complexityExtension +} + +func (c *ComplexityLimit) Validate(schema graphql.ExecutableSchema) error { + if c.Func == nil { + return fmt.Errorf("ComplexityLimit func can not be nil") + } + c.es = schema + return nil +} + +func (c ComplexityLimit) MutateOperationContext(ctx context.Context, rc *graphql.OperationContext) *gqlerror.Error { + op := rc.Doc.Operations.ForName(rc.OperationName) + complexity := complexity.Calculate(c.es, op, rc.Variables) + + limit := c.Func(ctx, rc) + + rc.Stats.SetExtension(complexityExtension, &ComplexityStats{ + Complexity: complexity, + ComplexityLimit: limit, + }) + + if complexity > limit { + err := gqlerror.Errorf("operation has complexity %d, which exceeds the limit of %d", complexity, limit) + errcode.Set(err, errComplexityLimit) + return err + } + + return nil +} + +func GetComplexityStats(ctx context.Context) *ComplexityStats { + rc := graphql.GetOperationContext(ctx) + if rc == nil { + return nil + } + + s, _ := rc.Stats.GetExtension(complexityExtension).(*ComplexityStats) + return s +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/extension/introspection.go b/vendor/github.com/99designs/gqlgen/graphql/handler/extension/introspection.go new file mode 100644 index 000000000..acc5db2fb --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/extension/introspection.go @@ -0,0 +1,29 @@ +package extension + +import ( + "context" + + "github.com/99designs/gqlgen/graphql" + "github.com/vektah/gqlparser/v2/gqlerror" +) + +// EnableIntrospection enables clients to reflect all of the types available on the graph. +type Introspection struct{} + +var _ interface { + graphql.OperationContextMutator + graphql.HandlerExtension +} = Introspection{} + +func (c Introspection) ExtensionName() string { + return "Introspection" +} + +func (c Introspection) Validate(schema graphql.ExecutableSchema) error { + return nil +} + +func (c Introspection) MutateOperationContext(ctx context.Context, rc *graphql.OperationContext) *gqlerror.Error { + rc.DisableIntrospection = false + return nil +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/lru/lru.go b/vendor/github.com/99designs/gqlgen/graphql/handler/lru/lru.go new file mode 100644 index 000000000..e2b1561ac --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/lru/lru.go @@ -0,0 +1,32 @@ +package lru + +import ( + "context" + + "github.com/99designs/gqlgen/graphql" + lru "github.com/hashicorp/golang-lru" +) + +type LRU struct { + lru *lru.Cache +} + +var _ graphql.Cache = &LRU{} + +func New(size int) *LRU { + cache, err := lru.New(size) + if err != nil { + // An error is only returned for non-positive cache size + // and we already checked for that. + panic("unexpected error creating cache: " + err.Error()) + } + return &LRU{cache} +} + +func (l LRU) Get(ctx context.Context, key string) (value interface{}, ok bool) { + return l.lru.Get(key) +} + +func (l LRU) Add(ctx context.Context, key string, value interface{}) { + l.lru.Add(key, value) +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/server.go b/vendor/github.com/99designs/gqlgen/graphql/handler/server.go new file mode 100644 index 000000000..640b2781c --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/server.go @@ -0,0 +1,180 @@ +package handler + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "time" + + "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/executor" + "github.com/99designs/gqlgen/graphql/handler/extension" + "github.com/99designs/gqlgen/graphql/handler/lru" + "github.com/99designs/gqlgen/graphql/handler/transport" + "github.com/vektah/gqlparser/v2/gqlerror" +) + +type ( + Server struct { + transports []graphql.Transport + exec *executor.Executor + } +) + +func New(es graphql.ExecutableSchema) *Server { + return &Server{ + exec: executor.New(es), + } +} + +func NewDefaultServer(es graphql.ExecutableSchema) *Server { + srv := New(es) + + srv.AddTransport(transport.Websocket{ + KeepAlivePingInterval: 10 * time.Second, + }) + srv.AddTransport(transport.Options{}) + srv.AddTransport(transport.GET{}) + srv.AddTransport(transport.POST{}) + srv.AddTransport(transport.MultipartForm{}) + + srv.SetQueryCache(lru.New(1000)) + + srv.Use(extension.Introspection{}) + srv.Use(extension.AutomaticPersistedQuery{ + Cache: lru.New(100), + }) + + return srv +} + +func (s *Server) AddTransport(transport graphql.Transport) { + s.transports = append(s.transports, transport) +} + +func (s *Server) SetErrorPresenter(f graphql.ErrorPresenterFunc) { + s.exec.SetErrorPresenter(f) +} + +func (s *Server) SetRecoverFunc(f graphql.RecoverFunc) { + s.exec.SetRecoverFunc(f) +} + +func (s *Server) SetQueryCache(cache graphql.Cache) { + s.exec.SetQueryCache(cache) +} + +func (s *Server) Use(extension graphql.HandlerExtension) { + s.exec.Use(extension) +} + +// AroundFields is a convenience method for creating an extension that only implements field middleware +func (s *Server) AroundFields(f graphql.FieldMiddleware) { + s.exec.AroundFields(f) +} + +// AroundOperations is a convenience method for creating an extension that only implements operation middleware +func (s *Server) AroundOperations(f graphql.OperationMiddleware) { + s.exec.AroundOperations(f) +} + +// AroundResponses is a convenience method for creating an extension that only implements response middleware +func (s *Server) AroundResponses(f graphql.ResponseMiddleware) { + s.exec.AroundResponses(f) +} + +func (s *Server) getTransport(r *http.Request) graphql.Transport { + for _, t := range s.transports { + if t.Supports(r) { + return t + } + } + return nil +} + +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + defer func() { + if err := recover(); err != nil { + err := s.exec.PresentRecoveredError(r.Context(), err) + resp := &graphql.Response{Errors: []*gqlerror.Error{err}} + b, _ := json.Marshal(resp) + w.WriteHeader(http.StatusUnprocessableEntity) + w.Write(b) + } + }() + + r = r.WithContext(graphql.StartOperationTrace(r.Context())) + + transport := s.getTransport(r) + if transport == nil { + sendErrorf(w, http.StatusBadRequest, "transport not supported") + return + } + + transport.Do(w, r, s.exec) +} + +func sendError(w http.ResponseWriter, code int, errors ...*gqlerror.Error) { + w.WriteHeader(code) + b, err := json.Marshal(&graphql.Response{Errors: errors}) + if err != nil { + panic(err) + } + w.Write(b) +} + +func sendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) { + sendError(w, code, &gqlerror.Error{Message: fmt.Sprintf(format, args...)}) +} + +type OperationFunc func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler + +func (r OperationFunc) ExtensionName() string { + return "InlineOperationFunc" +} + +func (r OperationFunc) Validate(schema graphql.ExecutableSchema) error { + if r == nil { + return fmt.Errorf("OperationFunc can not be nil") + } + return nil +} + +func (r OperationFunc) InterceptOperation(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler { + return r(ctx, next) +} + +type ResponseFunc func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response + +func (r ResponseFunc) ExtensionName() string { + return "InlineResponseFunc" +} + +func (r ResponseFunc) Validate(schema graphql.ExecutableSchema) error { + if r == nil { + return fmt.Errorf("ResponseFunc can not be nil") + } + return nil +} + +func (r ResponseFunc) InterceptResponse(ctx context.Context, next graphql.ResponseHandler) *graphql.Response { + return r(ctx, next) +} + +type FieldFunc func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) + +func (f FieldFunc) ExtensionName() string { + return "InlineFieldFunc" +} + +func (f FieldFunc) Validate(schema graphql.ExecutableSchema) error { + if f == nil { + return fmt.Errorf("FieldFunc can not be nil") + } + return nil +} + +func (f FieldFunc) InterceptField(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { + return f(ctx, next) +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/error.go b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/error.go new file mode 100644 index 000000000..b1aeaf144 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/error.go @@ -0,0 +1,26 @@ +package transport + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/99designs/gqlgen/graphql" + "github.com/vektah/gqlparser/v2/gqlerror" +) + +// SendError sends a best effort error to a raw response writer. It assumes the client can understand the standard +// json error response +func SendError(w http.ResponseWriter, code int, errors ...*gqlerror.Error) { + w.WriteHeader(code) + b, err := json.Marshal(&graphql.Response{Errors: errors}) + if err != nil { + panic(err) + } + w.Write(b) +} + +// SendErrorf wraps SendError to add formatted messages +func SendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) { + SendError(w, code, &gqlerror.Error{Message: fmt.Sprintf(format, args...)}) +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_form.go b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_form.go new file mode 100644 index 000000000..4afc154bd --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_form.go @@ -0,0 +1,208 @@ +package transport + +import ( + "encoding/json" + "io" + "io/ioutil" + "mime" + "net/http" + "os" + "strings" + + "github.com/99designs/gqlgen/graphql" +) + +// MultipartForm the Multipart request spec https://github.com/jaydenseric/graphql-multipart-request-spec +type MultipartForm struct { + // MaxUploadSize sets the maximum number of bytes used to parse a request body + // as multipart/form-data. + MaxUploadSize int64 + + // MaxMemory defines the maximum number of bytes used to parse a request body + // as multipart/form-data in memory, with the remainder stored on disk in + // temporary files. + MaxMemory int64 +} + +var _ graphql.Transport = MultipartForm{} + +func (f MultipartForm) Supports(r *http.Request) bool { + if r.Header.Get("Upgrade") != "" { + return false + } + + mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) + if err != nil { + return false + } + + return r.Method == "POST" && mediaType == "multipart/form-data" +} + +func (f MultipartForm) maxUploadSize() int64 { + if f.MaxUploadSize == 0 { + return 32 << 20 + } + return f.MaxUploadSize +} + +func (f MultipartForm) maxMemory() int64 { + if f.MaxMemory == 0 { + return 32 << 20 + } + return f.MaxMemory +} + +func (f MultipartForm) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) { + w.Header().Set("Content-Type", "application/json") + + start := graphql.Now() + + var err error + if r.ContentLength > f.maxUploadSize() { + writeJsonError(w, "failed to parse multipart form, request body too large") + return + } + r.Body = http.MaxBytesReader(w, r.Body, f.maxUploadSize()) + if err = r.ParseMultipartForm(f.maxMemory()); err != nil { + w.WriteHeader(http.StatusUnprocessableEntity) + if strings.Contains(err.Error(), "request body too large") { + writeJsonError(w, "failed to parse multipart form, request body too large") + return + } + writeJsonError(w, "failed to parse multipart form") + return + } + defer r.Body.Close() + + var params graphql.RawParams + + if err = jsonDecode(strings.NewReader(r.Form.Get("operations")), ¶ms); err != nil { + w.WriteHeader(http.StatusUnprocessableEntity) + writeJsonError(w, "operations form field could not be decoded") + return + } + + var uploadsMap = map[string][]string{} + if err = json.Unmarshal([]byte(r.Form.Get("map")), &uploadsMap); err != nil { + w.WriteHeader(http.StatusUnprocessableEntity) + writeJsonError(w, "map form field could not be decoded") + return + } + + var upload graphql.Upload + for key, paths := range uploadsMap { + if len(paths) == 0 { + w.WriteHeader(http.StatusUnprocessableEntity) + writeJsonErrorf(w, "invalid empty operations paths list for key %s", key) + return + } + file, header, err := r.FormFile(key) + if err != nil { + w.WriteHeader(http.StatusUnprocessableEntity) + writeJsonErrorf(w, "failed to get key %s from form", key) + return + } + defer file.Close() + + if len(paths) == 1 { + upload = graphql.Upload{ + File: file, + Size: header.Size, + Filename: header.Filename, + ContentType: header.Header.Get("Content-Type"), + } + + if err := params.AddUpload(upload, key, paths[0]); err != nil { + w.WriteHeader(http.StatusUnprocessableEntity) + writeJsonGraphqlError(w, err) + return + } + } else { + if r.ContentLength < f.maxMemory() { + fileBytes, err := ioutil.ReadAll(file) + if err != nil { + w.WriteHeader(http.StatusUnprocessableEntity) + writeJsonErrorf(w, "failed to read file for key %s", key) + return + } + for _, path := range paths { + upload = graphql.Upload{ + File: &bytesReader{s: &fileBytes, i: 0, prevRune: -1}, + Size: header.Size, + Filename: header.Filename, + ContentType: header.Header.Get("Content-Type"), + } + + if err := params.AddUpload(upload, key, path); err != nil { + w.WriteHeader(http.StatusUnprocessableEntity) + writeJsonGraphqlError(w, err) + return + } + } + } else { + tmpFile, err := ioutil.TempFile(os.TempDir(), "gqlgen-") + if err != nil { + w.WriteHeader(http.StatusUnprocessableEntity) + writeJsonErrorf(w, "failed to create temp file for key %s", key) + return + } + tmpName := tmpFile.Name() + defer func() { + _ = os.Remove(tmpName) + }() + _, err = io.Copy(tmpFile, file) + if err != nil { + w.WriteHeader(http.StatusUnprocessableEntity) + if err := tmpFile.Close(); err != nil { + writeJsonErrorf(w, "failed to copy to temp file and close temp file for key %s", key) + return + } + writeJsonErrorf(w, "failed to copy to temp file for key %s", key) + return + } + if err := tmpFile.Close(); err != nil { + w.WriteHeader(http.StatusUnprocessableEntity) + writeJsonErrorf(w, "failed to close temp file for key %s", key) + return + } + for _, path := range paths { + pathTmpFile, err := os.Open(tmpName) + if err != nil { + w.WriteHeader(http.StatusUnprocessableEntity) + writeJsonErrorf(w, "failed to open temp file for key %s", key) + return + } + defer pathTmpFile.Close() + upload = graphql.Upload{ + File: pathTmpFile, + Size: header.Size, + Filename: header.Filename, + ContentType: header.Header.Get("Content-Type"), + } + + if err := params.AddUpload(upload, key, path); err != nil { + w.WriteHeader(http.StatusUnprocessableEntity) + writeJsonGraphqlError(w, err) + return + } + } + } + } + } + + params.ReadTime = graphql.TraceTiming{ + Start: start, + End: graphql.Now(), + } + + rc, gerr := exec.CreateOperationContext(r.Context(), ¶ms) + if gerr != nil { + resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), gerr) + w.WriteHeader(statusFor(gerr)) + writeJson(w, resp) + return + } + responses, ctx := exec.DispatchOperation(r.Context(), rc) + writeJson(w, responses(ctx)) +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go new file mode 100644 index 000000000..d97c89c63 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go @@ -0,0 +1,87 @@ +package transport + +import ( + "encoding/json" + "io" + "net/http" + "strings" + + "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/errcode" + "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" +) + +// GET implements the GET side of the default HTTP transport +// defined in https://github.com/APIs-guru/graphql-over-http#get +type GET struct{} + +var _ graphql.Transport = GET{} + +func (h GET) Supports(r *http.Request) bool { + if r.Header.Get("Upgrade") != "" { + return false + } + + return r.Method == "GET" +} + +func (h GET) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) { + w.Header().Set("Content-Type", "application/json") + + raw := &graphql.RawParams{ + Query: r.URL.Query().Get("query"), + OperationName: r.URL.Query().Get("operationName"), + } + raw.ReadTime.Start = graphql.Now() + + if variables := r.URL.Query().Get("variables"); variables != "" { + if err := jsonDecode(strings.NewReader(variables), &raw.Variables); err != nil { + w.WriteHeader(http.StatusBadRequest) + writeJsonError(w, "variables could not be decoded") + return + } + } + + if extensions := r.URL.Query().Get("extensions"); extensions != "" { + if err := jsonDecode(strings.NewReader(extensions), &raw.Extensions); err != nil { + w.WriteHeader(http.StatusBadRequest) + writeJsonError(w, "extensions could not be decoded") + return + } + } + + raw.ReadTime.End = graphql.Now() + + rc, err := exec.CreateOperationContext(r.Context(), raw) + if err != nil { + w.WriteHeader(statusFor(err)) + resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), err) + writeJson(w, resp) + return + } + op := rc.Doc.Operations.ForName(rc.OperationName) + if op.Operation != ast.Query { + w.WriteHeader(http.StatusNotAcceptable) + writeJsonError(w, "GET requests only allow query operations") + return + } + + responses, ctx := exec.DispatchOperation(r.Context(), rc) + writeJson(w, responses(ctx)) +} + +func jsonDecode(r io.Reader, val interface{}) error { + dec := json.NewDecoder(r) + dec.UseNumber() + return dec.Decode(val) +} + +func statusFor(errs gqlerror.List) int { + switch errcode.GetErrorKind(errs) { + case errcode.KindProtocol: + return http.StatusUnprocessableEntity + default: + return http.StatusOK + } +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_post.go b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_post.go new file mode 100644 index 000000000..70d971ac8 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_post.go @@ -0,0 +1,54 @@ +package transport + +import ( + "mime" + "net/http" + + "github.com/99designs/gqlgen/graphql" +) + +// POST implements the POST side of the default HTTP transport +// defined in https://github.com/APIs-guru/graphql-over-http#post +type POST struct{} + +var _ graphql.Transport = POST{} + +func (h POST) Supports(r *http.Request) bool { + if r.Header.Get("Upgrade") != "" { + return false + } + + mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) + if err != nil { + return false + } + + return r.Method == "POST" && mediaType == "application/json" +} + +func (h POST) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) { + w.Header().Set("Content-Type", "application/json") + + var params *graphql.RawParams + start := graphql.Now() + if err := jsonDecode(r.Body, ¶ms); err != nil { + w.WriteHeader(http.StatusBadRequest) + writeJsonErrorf(w, "json body could not be decoded: "+err.Error()) + return + } + params.ReadTime = graphql.TraceTiming{ + Start: start, + End: graphql.Now(), + } + + rc, err := exec.CreateOperationContext(r.Context(), params) + if err != nil { + w.WriteHeader(statusFor(err)) + resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), err) + writeJson(w, resp) + return + } + ctx := graphql.WithOperationContext(r.Context(), rc) + responses, ctx := exec.DispatchOperation(ctx, rc) + writeJson(w, responses(ctx)) +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/options.go b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/options.go new file mode 100644 index 000000000..674a00c7f --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/options.go @@ -0,0 +1,26 @@ +package transport + +import ( + "net/http" + + "github.com/99designs/gqlgen/graphql" +) + +// Options responds to http OPTIONS and HEAD requests +type Options struct{} + +var _ graphql.Transport = Options{} + +func (o Options) Supports(r *http.Request) bool { + return r.Method == "HEAD" || r.Method == "OPTIONS" +} + +func (o Options) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) { + switch r.Method { + case http.MethodOptions: + w.WriteHeader(http.StatusOK) + w.Header().Set("Allow", "OPTIONS, GET, POST") + case http.MethodHead: + w.WriteHeader(http.StatusMethodNotAllowed) + } +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/reader.go b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/reader.go new file mode 100644 index 000000000..d3261e283 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/reader.go @@ -0,0 +1,25 @@ +package transport + +import ( + "errors" + "io" +) + +type bytesReader struct { + s *[]byte + i int64 // current reading index + prevRune int // index of previous rune; or < 0 +} + +func (r *bytesReader) Read(b []byte) (n int, err error) { + if r.s == nil { + return 0, errors.New("byte slice pointer is nil") + } + if r.i >= int64(len(*r.s)) { + return 0, io.EOF + } + r.prevRune = -1 + n = copy(b, (*r.s)[r.i:]) + r.i += int64(n) + return +} diff --git a/vendor/github.com/99designs/gqlgen/graphql/handler/transport/util.go b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/util.go new file mode 100644 index 000000000..ce845c196 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/util.go @@ -0,0 +1,30 @@ +package transport + +import ( + "encoding/json" + "fmt" + "io" + + "github.com/99designs/gqlgen/graphql" + "github.com/vektah/gqlparser/v2/gqlerror" +) + +func writeJson(w io.Writer, response *graphql.Response) { + b, err := json.Marshal(response) + if err != nil { + panic(err) + } + w.Write(b) +} + +func writeJsonError(w io.Writer, msg string) { + writeJson(w, &graphql.Response{Errors: gqlerror.List{{Message: msg}}}) +} + +func writeJsonErrorf(w io.Writer, format string, args ...interface{}) { + writeJson(w, &graphql.Response{Errors: gqlerror.List{{Message: fmt.Sprintf(format, args...)}}}) +} + +func writeJsonGraphqlError(w io.Writer, err ...*gqlerror.Error) { + writeJson(w, &graphql.Response{Errors: err}) +} diff --git a/vendor/github.com/99designs/gqlgen/handler/websocket.go b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket.go similarity index 56% rename from vendor/github.com/99designs/gqlgen/handler/websocket.go rename to vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket.go index 58f38e5d4..3089a8779 100644 --- a/vendor/github.com/99designs/gqlgen/handler/websocket.go +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket.go @@ -1,4 +1,4 @@ -package handler +package transport import ( "bytes" @@ -11,12 +11,9 @@ import ( "time" "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/errcode" "github.com/gorilla/websocket" - "github.com/hashicorp/golang-lru" - "github.com/vektah/gqlparser" - "github.com/vektah/gqlparser/ast" - "github.com/vektah/gqlparser/gqlerror" - "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/gqlerror" ) const ( @@ -32,42 +29,53 @@ const ( connectionKeepAliveMsg = "ka" // Server -> Client ) -type operationMessage struct { - Payload json.RawMessage `json:"payload,omitempty"` - ID string `json:"id,omitempty"` - Type string `json:"type"` +type ( + Websocket struct { + Upgrader websocket.Upgrader + InitFunc WebsocketInitFunc + KeepAlivePingInterval time.Duration + } + wsConnection struct { + Websocket + ctx context.Context + conn *websocket.Conn + active map[string]context.CancelFunc + mu sync.Mutex + keepAliveTicker *time.Ticker + exec graphql.GraphExecutor + + initPayload InitPayload + } + operationMessage struct { + Payload json.RawMessage `json:"payload,omitempty"` + ID string `json:"id,omitempty"` + Type string `json:"type"` + } + WebsocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, error) +) + +var _ graphql.Transport = Websocket{} + +func (t Websocket) Supports(r *http.Request) bool { + return r.Header.Get("Upgrade") != "" } -type wsConnection struct { - ctx context.Context - conn *websocket.Conn - exec graphql.ExecutableSchema - active map[string]context.CancelFunc - mu sync.Mutex - cfg *Config - cache *lru.Cache - keepAliveTicker *time.Ticker - - initPayload InitPayload -} - -func connectWs(exec graphql.ExecutableSchema, w http.ResponseWriter, r *http.Request, cfg *Config, cache *lru.Cache) { - ws, err := cfg.upgrader.Upgrade(w, r, http.Header{ +func (t Websocket) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) { + ws, err := t.Upgrader.Upgrade(w, r, http.Header{ "Sec-Websocket-Protocol": []string{"graphql-ws"}, }) if err != nil { log.Printf("unable to upgrade %T to websocket %s: ", w, err.Error()) - sendErrorf(w, http.StatusBadRequest, "unable to upgrade") + SendErrorf(w, http.StatusBadRequest, "unable to upgrade") return } conn := wsConnection{ - active: map[string]context.CancelFunc{}, - exec: exec, - conn: ws, - ctx: r.Context(), - cfg: cfg, - cache: cache, + active: map[string]context.CancelFunc{}, + conn: ws, + ctx: r.Context(), + exec: exec, + Websocket: t, } if !conn.init() { @@ -94,7 +102,18 @@ func (c *wsConnection) init() bool { } } + if c.InitFunc != nil { + ctx, err := c.InitFunc(c.ctx, c.initPayload) + if err != nil { + c.sendConnectionError(err.Error()) + c.close(websocket.CloseNormalClosure, "terminated") + return false + } + c.ctx = ctx + } + c.write(&operationMessage{Type: connectionAckMsg}) + c.write(&operationMessage{Type: connectionKeepAliveMsg}) case connectionTerminateMsg: c.close(websocket.CloseNormalClosure, "terminated") return false @@ -117,18 +136,22 @@ func (c *wsConnection) run() { // We create a cancellation that will shutdown the keep-alive when we leave // this function. ctx, cancel := context.WithCancel(c.ctx) - defer cancel() + defer func() { + cancel() + c.close(websocket.CloseAbnormalClosure, "unexpected closure") + }() // Create a timer that will fire every interval to keep the connection alive. - if c.cfg.connectionKeepAlivePingInterval != 0 { + if c.KeepAlivePingInterval != 0 { c.mu.Lock() - c.keepAliveTicker = time.NewTicker(c.cfg.connectionKeepAlivePingInterval) + c.keepAliveTicker = time.NewTicker(c.KeepAlivePingInterval) c.mu.Unlock() go c.keepAlive(ctx) } for { + start := graphql.Now() message := c.readOp() if message == nil { return @@ -136,19 +159,14 @@ func (c *wsConnection) run() { switch message.Type { case startMsg: - if !c.subscribe(message) { - return - } + c.subscribe(start, message) case stopMsg: c.mu.Lock() closer := c.active[message.ID] c.mu.Unlock() - if closer == nil { - c.sendError(message.ID, gqlerror.Errorf("%s is not running, cannot stop", message.ID)) - continue + if closer != nil { + closer() } - - closer() case connectionTerminateMsg: c.close(websocket.CloseNormalClosure, "terminated") return @@ -172,108 +190,90 @@ func (c *wsConnection) keepAlive(ctx context.Context) { } } -func (c *wsConnection) subscribe(message *operationMessage) bool { - var reqParams params - if err := jsonDecode(bytes.NewReader(message.Payload), &reqParams); err != nil { - c.sendConnectionError("invalid json") - return false +func (c *wsConnection) subscribe(start time.Time, message *operationMessage) { + ctx := graphql.StartOperationTrace(c.ctx) + var params *graphql.RawParams + if err := jsonDecode(bytes.NewReader(message.Payload), ¶ms); err != nil { + c.sendError(message.ID, &gqlerror.Error{Message: "invalid json"}) + c.complete(message.ID) + return } - var ( - doc *ast.QueryDocument - cacheHit bool - ) - if c.cache != nil { - val, ok := c.cache.Get(reqParams.Query) - if ok { - doc = val.(*ast.QueryDocument) - cacheHit = true - } - } - if !cacheHit { - var qErr gqlerror.List - doc, qErr = gqlparser.LoadQuery(c.exec.Schema(), reqParams.Query) - if qErr != nil { - c.sendError(message.ID, qErr...) - return true - } - if c.cache != nil { - c.cache.Add(reqParams.Query, doc) - } + params.ReadTime = graphql.TraceTiming{ + Start: start, + End: graphql.Now(), } - op := doc.Operations.ForName(reqParams.OperationName) - if op == nil { - c.sendError(message.ID, gqlerror.Errorf("operation %s not found", reqParams.OperationName)) - return true - } - - vars, err := validator.VariableValues(c.exec.Schema(), op, reqParams.Variables) + rc, err := c.exec.CreateOperationContext(ctx, params) if err != nil { - c.sendError(message.ID, err) - return true + resp := c.exec.DispatchError(graphql.WithOperationContext(ctx, rc), err) + switch errcode.GetErrorKind(err) { + case errcode.KindProtocol: + c.sendError(message.ID, resp.Errors...) + default: + c.sendResponse(message.ID, &graphql.Response{Errors: err}) + } + + c.complete(message.ID) + return } - reqCtx := c.cfg.newRequestContext(c.exec, doc, op, reqParams.Query, vars) - ctx := graphql.WithRequestContext(c.ctx, reqCtx) + + ctx = graphql.WithOperationContext(ctx, rc) if c.initPayload != nil { ctx = withInitPayload(ctx, c.initPayload) } - if op.Operation != ast.Subscription { - var result *graphql.Response - if op.Operation == ast.Query { - result = c.exec.Query(ctx, op) - } else { - result = c.exec.Mutation(ctx, op) - } - - c.sendData(message.ID, result) - c.write(&operationMessage{ID: message.ID, Type: completeMsg}) - return true - } - ctx, cancel := context.WithCancel(ctx) c.mu.Lock() c.active[message.ID] = cancel c.mu.Unlock() + go func() { defer func() { if r := recover(); r != nil { - userErr := reqCtx.Recover(ctx, r) + userErr := rc.Recover(ctx, r) c.sendError(message.ID, &gqlerror.Error{Message: userErr.Error()}) } }() - next := c.exec.Subscription(ctx, op) - for result := next(); result != nil; result = next() { - c.sendData(message.ID, result) - } + responses, ctx := c.exec.DispatchOperation(ctx, rc) + for { + response := responses(ctx) + if response == nil { + break + } - c.write(&operationMessage{ID: message.ID, Type: completeMsg}) + c.sendResponse(message.ID, response) + } + c.complete(message.ID) c.mu.Lock() delete(c.active, message.ID) c.mu.Unlock() cancel() }() - - return true } -func (c *wsConnection) sendData(id string, response *graphql.Response) { +func (c *wsConnection) sendResponse(id string, response *graphql.Response) { b, err := json.Marshal(response) if err != nil { - c.sendError(id, gqlerror.Errorf("unable to encode json response: %s", err.Error())) - return + panic(err) } + c.write(&operationMessage{ + Payload: b, + ID: id, + Type: dataMsg, + }) +} - c.write(&operationMessage{Type: dataMsg, ID: id, Payload: b}) +func (c *wsConnection) complete(id string) { + c.write(&operationMessage{ID: id, Type: completeMsg}) } func (c *wsConnection) sendError(id string, errors ...*gqlerror.Error) { - var errs []error - for _, err := range errors { - errs = append(errs, err) + errs := make([]error, len(errors)) + for i, err := range errors { + errs[i] = err } b, err := json.Marshal(errs) if err != nil { @@ -293,8 +293,10 @@ func (c *wsConnection) sendConnectionError(format string, args ...interface{}) { func (c *wsConnection) readOp() *operationMessage { _, r, err := c.conn.NextReader() - if err != nil { - c.sendConnectionError("invalid json") + if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) { + return nil + } else if err != nil { + c.sendConnectionError("invalid json: %T %s", err, err.Error()) return nil } message := operationMessage{} diff --git a/vendor/github.com/99designs/gqlgen/handler/context.go b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_init.go similarity index 78% rename from vendor/github.com/99designs/gqlgen/handler/context.go rename to vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_init.go index 2992aa3d4..a5f84ba2d 100644 --- a/vendor/github.com/99designs/gqlgen/handler/context.go +++ b/vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_init.go @@ -1,4 +1,4 @@ -package handler +package transport import "context" @@ -14,12 +14,12 @@ type InitPayload map[string]interface{} // GetString safely gets a string value from the payload. It returns an empty string if the // payload is nil or the value isn't set. -func (payload InitPayload) GetString(key string) string { - if payload == nil { +func (p InitPayload) GetString(key string) string { + if p == nil { return "" } - if value, ok := payload[key]; ok { + if value, ok := p[key]; ok { res, _ := value.(string) return res } @@ -29,12 +29,12 @@ func (payload InitPayload) GetString(key string) string { // Authorization is a short hand for getting the Authorization header from the // payload. -func (payload InitPayload) Authorization() string { - if value := payload.GetString("Authorization"); value != "" { +func (p InitPayload) Authorization() string { + if value := p.GetString("Authorization"); value != "" { return value } - if value := payload.GetString("authorization"); value != "" { + if value := p.GetString("authorization"); value != "" { return value } diff --git a/vendor/github.com/99designs/gqlgen/graphql/id.go b/vendor/github.com/99designs/gqlgen/graphql/id.go index 4f532037d..2e78a5ec4 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/id.go +++ b/vendor/github.com/99designs/gqlgen/graphql/id.go @@ -20,6 +20,8 @@ func UnmarshalID(v interface{}) (string, error) { return string(v), nil case int: return strconv.Itoa(v), nil + case int64: + return strconv.FormatInt(v, 10), nil case float64: return fmt.Sprintf("%f", v), nil case bool: diff --git a/vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go b/vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go index ca0b065f8..5239c9283 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go +++ b/vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go @@ -1,7 +1,7 @@ // introspection implements the spec defined in https://github.com/facebook/graphql/blob/master/spec/Section%204%20--%20Introspection.md#schema-introspection package introspection -import "github.com/vektah/gqlparser/ast" +import "github.com/vektah/gqlparser/v2/ast" type ( Directive struct { diff --git a/vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go b/vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go index b5d2c4822..044e91d6e 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go +++ b/vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go @@ -3,7 +3,7 @@ package introspection import ( "strings" - "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/v2/ast" ) type Schema struct { @@ -11,7 +11,7 @@ type Schema struct { } func (s *Schema) Types() []Type { - var types []Type + types := make([]Type, 0, len(s.schema.Types)) for _, typ := range s.schema.Types { if strings.HasPrefix(typ.Name, "__") { continue @@ -34,7 +34,7 @@ func (s *Schema) SubscriptionType() *Type { } func (s *Schema) Directives() []Directive { - var res []Directive + res := make([]Directive, 0, len(s.schema.Directives)) for _, d := range s.schema.Directives { res = append(res, s.directiveFromDef(d)) @@ -44,19 +44,19 @@ func (s *Schema) Directives() []Directive { } func (s *Schema) directiveFromDef(d *ast.DirectiveDefinition) Directive { - var locs []string - for _, loc := range d.Locations { - locs = append(locs, string(loc)) + locs := make([]string, len(d.Locations)) + for i, loc := range d.Locations { + locs[i] = string(loc) } - var args []InputValue - for _, arg := range d.Arguments { - args = append(args, InputValue{ + args := make([]InputValue, len(d.Arguments)) + for i, arg := range d.Arguments { + args[i] = InputValue{ Name: arg.Name, Description: arg.Description, DefaultValue: defaultValue(arg.DefaultValue), Type: WrapTypeFromType(s.schema, arg.Type), - }) + } } return Directive{ diff --git a/vendor/github.com/99designs/gqlgen/graphql/introspection/type.go b/vendor/github.com/99designs/gqlgen/graphql/introspection/type.go index 9aceebdc9..f842fa645 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/introspection/type.go +++ b/vendor/github.com/99designs/gqlgen/graphql/introspection/type.go @@ -3,7 +3,7 @@ package introspection import ( "strings" - "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/v2/ast" ) type Type struct { @@ -152,6 +152,10 @@ func (t *Type) EnumValues(includeDeprecated bool) []EnumValue { res := []EnumValue{} for _, val := range t.def.EnumValues { + if !includeDeprecated && val.Directives.ForName("deprecated") != nil { + continue + } + res = append(res, EnumValue{ Name: val.Name, Description: val.Description, diff --git a/vendor/github.com/99designs/gqlgen/graphql/oneshot.go b/vendor/github.com/99designs/gqlgen/graphql/oneshot.go index dd31f5baa..01fa15f89 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/oneshot.go +++ b/vendor/github.com/99designs/gqlgen/graphql/oneshot.go @@ -1,9 +1,11 @@ package graphql -func OneShot(resp *Response) func() *Response { +import "context" + +func OneShot(resp *Response) ResponseHandler { var oneshot bool - return func() *Response { + return func(context context.Context) *Response { if oneshot { return nil } diff --git a/vendor/github.com/99designs/gqlgen/handler/playground.go b/vendor/github.com/99designs/gqlgen/graphql/playground/playground.go similarity index 92% rename from vendor/github.com/99designs/gqlgen/handler/playground.go rename to vendor/github.com/99designs/gqlgen/graphql/playground/playground.go index 0e1ca7686..45bbbd4f1 100644 --- a/vendor/github.com/99designs/gqlgen/handler/playground.go +++ b/vendor/github.com/99designs/gqlgen/graphql/playground/playground.go @@ -1,4 +1,4 @@ -package handler +package playground import ( "html/template" @@ -11,7 +11,7 @@ var page = template.Must(template.New("graphiql").Parse(` - @@ -33,6 +33,7 @@ var page = template.Must(template.New("graphiql").Parse(` GraphQLPlayground.init(root, { endpoint: location.protocol + '//' + location.host + '{{.endpoint}}', subscriptionsEndpoint: wsProto + '//' + location.host + '{{.endpoint }}', + shareEnabled: true, settings: { 'request.credentials': 'same-origin' } @@ -43,7 +44,7 @@ var page = template.Must(template.New("graphiql").Parse(` `)) -func Playground(title string, endpoint string) http.HandlerFunc { +func Handler(title string, endpoint string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "text/html") err := page.Execute(w, map[string]string{ diff --git a/vendor/github.com/99designs/gqlgen/graphql/response.go b/vendor/github.com/99designs/gqlgen/graphql/response.go index 6fe55d56d..0d36049a3 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/response.go +++ b/vendor/github.com/99designs/gqlgen/graphql/response.go @@ -5,7 +5,7 @@ import ( "encoding/json" "fmt" - "github.com/vektah/gqlparser/gqlerror" + "github.com/vektah/gqlparser/v2/gqlerror" ) // Errors are intentionally serialized first based on the advice in diff --git a/vendor/github.com/99designs/gqlgen/graphql/stats.go b/vendor/github.com/99designs/gqlgen/graphql/stats.go new file mode 100644 index 000000000..a52e143eb --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/graphql/stats.go @@ -0,0 +1,60 @@ +package graphql + +import ( + "context" + "fmt" + "time" +) + +type Stats struct { + OperationStart time.Time + Read TraceTiming + Parsing TraceTiming + Validation TraceTiming + + // Stats collected by handler extensions. Dont use directly, the extension should provide a type safe way to + // access this. + extension map[string]interface{} +} + +type TraceTiming struct { + Start time.Time + End time.Time +} + +var ctxTraceStart key = "trace_start" + +// StartOperationTrace captures the current time and stores it in context. This will eventually be added to request +// context but we want to grab it as soon as possible. For transports that can only handle a single graphql query +// per http requests you dont need to call this at all, the server will do it for you. For transports that handle +// multiple (eg batching, subscriptions) this should be called before decoding each request. +func StartOperationTrace(ctx context.Context) context.Context { + return context.WithValue(ctx, ctxTraceStart, Now()) +} + +// GetStartTime should only be called by the handler package, it will be set into request context +// as Stats.Start +func GetStartTime(ctx context.Context) time.Time { + t, ok := ctx.Value(ctxTraceStart).(time.Time) + if !ok { + panic(fmt.Sprintf("missing start time: %T", ctx.Value(ctxTraceStart))) + } + return t +} + +func (c *Stats) SetExtension(name string, data interface{}) { + if c.extension == nil { + c.extension = map[string]interface{}{} + } + c.extension[name] = data +} + +func (c *Stats) GetExtension(name string) interface{} { + if c.extension == nil { + return nil + } + return c.extension[name] +} + +// Now is time.Now, except in tests. Then it can be whatever you want it to be. +var Now = time.Now diff --git a/vendor/github.com/99designs/gqlgen/graphql/tracer.go b/vendor/github.com/99designs/gqlgen/graphql/tracer.go deleted file mode 100644 index 0597ce8cc..000000000 --- a/vendor/github.com/99designs/gqlgen/graphql/tracer.go +++ /dev/null @@ -1,58 +0,0 @@ -package graphql - -import ( - "context" -) - -var _ Tracer = (*NopTracer)(nil) - -type Tracer interface { - StartOperationParsing(ctx context.Context) context.Context - EndOperationParsing(ctx context.Context) - StartOperationValidation(ctx context.Context) context.Context - EndOperationValidation(ctx context.Context) - StartOperationExecution(ctx context.Context) context.Context - StartFieldExecution(ctx context.Context, field CollectedField) context.Context - StartFieldResolverExecution(ctx context.Context, rc *ResolverContext) context.Context - StartFieldChildExecution(ctx context.Context) context.Context - EndFieldExecution(ctx context.Context) - EndOperationExecution(ctx context.Context) -} - -type NopTracer struct{} - -func (NopTracer) StartOperationParsing(ctx context.Context) context.Context { - return ctx -} - -func (NopTracer) EndOperationParsing(ctx context.Context) { -} - -func (NopTracer) StartOperationValidation(ctx context.Context) context.Context { - return ctx -} - -func (NopTracer) EndOperationValidation(ctx context.Context) { -} - -func (NopTracer) StartOperationExecution(ctx context.Context) context.Context { - return ctx -} - -func (NopTracer) StartFieldExecution(ctx context.Context, field CollectedField) context.Context { - return ctx -} - -func (NopTracer) StartFieldResolverExecution(ctx context.Context, rc *ResolverContext) context.Context { - return ctx -} - -func (NopTracer) StartFieldChildExecution(ctx context.Context) context.Context { - return ctx -} - -func (NopTracer) EndFieldExecution(ctx context.Context) { -} - -func (NopTracer) EndOperationExecution(ctx context.Context) { -} diff --git a/vendor/github.com/99designs/gqlgen/graphql/upload.go b/vendor/github.com/99designs/gqlgen/graphql/upload.go index 22d610314..62f71c0dc 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/upload.go +++ b/vendor/github.com/99designs/gqlgen/graphql/upload.go @@ -6,9 +6,10 @@ import ( ) type Upload struct { - File io.Reader - Filename string - Size int64 + File io.Reader + Filename string + Size int64 + ContentType string } func MarshalUpload(f Upload) Marshaler { diff --git a/vendor/github.com/99designs/gqlgen/graphql/version.go b/vendor/github.com/99designs/gqlgen/graphql/version.go index 11dc6b019..49954bbb6 100644 --- a/vendor/github.com/99designs/gqlgen/graphql/version.go +++ b/vendor/github.com/99designs/gqlgen/graphql/version.go @@ -1,3 +1,3 @@ package graphql -const Version = "v0.9.0" +const Version = "v0.12.2" diff --git a/vendor/github.com/99designs/gqlgen/handler/graphql.go b/vendor/github.com/99designs/gqlgen/handler/graphql.go deleted file mode 100644 index a22542225..000000000 --- a/vendor/github.com/99designs/gqlgen/handler/graphql.go +++ /dev/null @@ -1,709 +0,0 @@ -package handler - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "mime" - "net/http" - "os" - "strconv" - "strings" - "time" - - "github.com/99designs/gqlgen/complexity" - "github.com/99designs/gqlgen/graphql" - "github.com/gorilla/websocket" - lru "github.com/hashicorp/golang-lru" - "github.com/vektah/gqlparser/ast" - "github.com/vektah/gqlparser/gqlerror" - "github.com/vektah/gqlparser/parser" - "github.com/vektah/gqlparser/validator" -) - -type params struct { - Query string `json:"query"` - OperationName string `json:"operationName"` - Variables map[string]interface{} `json:"variables"` -} - -type Config struct { - cacheSize int - upgrader websocket.Upgrader - recover graphql.RecoverFunc - errorPresenter graphql.ErrorPresenterFunc - resolverHook graphql.FieldMiddleware - requestHook graphql.RequestMiddleware - tracer graphql.Tracer - complexityLimit int - complexityLimitFunc graphql.ComplexityLimitFunc - disableIntrospection bool - connectionKeepAlivePingInterval time.Duration - uploadMaxMemory int64 - uploadMaxSize int64 -} - -func (c *Config) newRequestContext(es graphql.ExecutableSchema, doc *ast.QueryDocument, op *ast.OperationDefinition, query string, variables map[string]interface{}) *graphql.RequestContext { - reqCtx := graphql.NewRequestContext(doc, query, variables) - reqCtx.DisableIntrospection = c.disableIntrospection - - if hook := c.recover; hook != nil { - reqCtx.Recover = hook - } - - if hook := c.errorPresenter; hook != nil { - reqCtx.ErrorPresenter = hook - } - - if hook := c.resolverHook; hook != nil { - reqCtx.ResolverMiddleware = hook - } - - if hook := c.requestHook; hook != nil { - reqCtx.RequestMiddleware = hook - } - - if hook := c.tracer; hook != nil { - reqCtx.Tracer = hook - } - - if c.complexityLimit > 0 || c.complexityLimitFunc != nil { - reqCtx.ComplexityLimit = c.complexityLimit - operationComplexity := complexity.Calculate(es, op, variables) - reqCtx.OperationComplexity = operationComplexity - } - - return reqCtx -} - -type Option func(cfg *Config) - -func WebsocketUpgrader(upgrader websocket.Upgrader) Option { - return func(cfg *Config) { - cfg.upgrader = upgrader - } -} - -func RecoverFunc(recover graphql.RecoverFunc) Option { - return func(cfg *Config) { - cfg.recover = recover - } -} - -// ErrorPresenter transforms errors found while resolving into errors that will be returned to the user. It provides -// a good place to add any extra fields, like error.type, that might be desired by your frontend. Check the default -// implementation in graphql.DefaultErrorPresenter for an example. -func ErrorPresenter(f graphql.ErrorPresenterFunc) Option { - return func(cfg *Config) { - cfg.errorPresenter = f - } -} - -// IntrospectionEnabled = false will forbid clients from calling introspection endpoints. Can be useful in prod when you dont -// want clients introspecting the full schema. -func IntrospectionEnabled(enabled bool) Option { - return func(cfg *Config) { - cfg.disableIntrospection = !enabled - } -} - -// ComplexityLimit sets a maximum query complexity that is allowed to be executed. -// If a query is submitted that exceeds the limit, a 422 status code will be returned. -func ComplexityLimit(limit int) Option { - return func(cfg *Config) { - cfg.complexityLimit = limit - } -} - -// ComplexityLimitFunc allows you to define a function to dynamically set the maximum query complexity that is allowed -// to be executed. -// If a query is submitted that exceeds the limit, a 422 status code will be returned. -func ComplexityLimitFunc(complexityLimitFunc graphql.ComplexityLimitFunc) Option { - return func(cfg *Config) { - cfg.complexityLimitFunc = complexityLimitFunc - } -} - -// ResolverMiddleware allows you to define a function that will be called around every resolver, -// useful for logging. -func ResolverMiddleware(middleware graphql.FieldMiddleware) Option { - return func(cfg *Config) { - if cfg.resolverHook == nil { - cfg.resolverHook = middleware - return - } - - lastResolve := cfg.resolverHook - cfg.resolverHook = func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { - return lastResolve(ctx, func(ctx context.Context) (res interface{}, err error) { - return middleware(ctx, next) - }) - } - } -} - -// RequestMiddleware allows you to define a function that will be called around the root request, -// after the query has been parsed. This is useful for logging -func RequestMiddleware(middleware graphql.RequestMiddleware) Option { - return func(cfg *Config) { - if cfg.requestHook == nil { - cfg.requestHook = middleware - return - } - - lastResolve := cfg.requestHook - cfg.requestHook = func(ctx context.Context, next func(ctx context.Context) []byte) []byte { - return lastResolve(ctx, func(ctx context.Context) []byte { - return middleware(ctx, next) - }) - } - } -} - -// Tracer allows you to add a request/resolver tracer that will be called around the root request, -// calling resolver. This is useful for tracing -func Tracer(tracer graphql.Tracer) Option { - return func(cfg *Config) { - if cfg.tracer == nil { - cfg.tracer = tracer - - } else { - lastResolve := cfg.tracer - cfg.tracer = &tracerWrapper{ - tracer1: lastResolve, - tracer2: tracer, - } - } - - opt := RequestMiddleware(func(ctx context.Context, next func(ctx context.Context) []byte) []byte { - ctx = tracer.StartOperationExecution(ctx) - resp := next(ctx) - tracer.EndOperationExecution(ctx) - - return resp - }) - opt(cfg) - } -} - -type tracerWrapper struct { - tracer1 graphql.Tracer - tracer2 graphql.Tracer -} - -func (tw *tracerWrapper) StartOperationParsing(ctx context.Context) context.Context { - ctx = tw.tracer1.StartOperationParsing(ctx) - ctx = tw.tracer2.StartOperationParsing(ctx) - return ctx -} - -func (tw *tracerWrapper) EndOperationParsing(ctx context.Context) { - tw.tracer2.EndOperationParsing(ctx) - tw.tracer1.EndOperationParsing(ctx) -} - -func (tw *tracerWrapper) StartOperationValidation(ctx context.Context) context.Context { - ctx = tw.tracer1.StartOperationValidation(ctx) - ctx = tw.tracer2.StartOperationValidation(ctx) - return ctx -} - -func (tw *tracerWrapper) EndOperationValidation(ctx context.Context) { - tw.tracer2.EndOperationValidation(ctx) - tw.tracer1.EndOperationValidation(ctx) -} - -func (tw *tracerWrapper) StartOperationExecution(ctx context.Context) context.Context { - ctx = tw.tracer1.StartOperationExecution(ctx) - ctx = tw.tracer2.StartOperationExecution(ctx) - return ctx -} - -func (tw *tracerWrapper) StartFieldExecution(ctx context.Context, field graphql.CollectedField) context.Context { - ctx = tw.tracer1.StartFieldExecution(ctx, field) - ctx = tw.tracer2.StartFieldExecution(ctx, field) - return ctx -} - -func (tw *tracerWrapper) StartFieldResolverExecution(ctx context.Context, rc *graphql.ResolverContext) context.Context { - ctx = tw.tracer1.StartFieldResolverExecution(ctx, rc) - ctx = tw.tracer2.StartFieldResolverExecution(ctx, rc) - return ctx -} - -func (tw *tracerWrapper) StartFieldChildExecution(ctx context.Context) context.Context { - ctx = tw.tracer1.StartFieldChildExecution(ctx) - ctx = tw.tracer2.StartFieldChildExecution(ctx) - return ctx -} - -func (tw *tracerWrapper) EndFieldExecution(ctx context.Context) { - tw.tracer2.EndFieldExecution(ctx) - tw.tracer1.EndFieldExecution(ctx) -} - -func (tw *tracerWrapper) EndOperationExecution(ctx context.Context) { - tw.tracer2.EndOperationExecution(ctx) - tw.tracer1.EndOperationExecution(ctx) -} - -// CacheSize sets the maximum size of the query cache. -// If size is less than or equal to 0, the cache is disabled. -func CacheSize(size int) Option { - return func(cfg *Config) { - cfg.cacheSize = size - } -} - -// UploadMaxSize sets the maximum number of bytes used to parse a request body -// as multipart/form-data. -func UploadMaxSize(size int64) Option { - return func(cfg *Config) { - cfg.uploadMaxSize = size - } -} - -// UploadMaxMemory sets the maximum number of bytes used to parse a request body -// as multipart/form-data in memory, with the remainder stored on disk in -// temporary files. -func UploadMaxMemory(size int64) Option { - return func(cfg *Config) { - cfg.uploadMaxMemory = size - } -} - -// WebsocketKeepAliveDuration allows you to reconfigure the keepalive behavior. -// By default, keepalive is enabled with a DefaultConnectionKeepAlivePingInterval -// duration. Set handler.connectionKeepAlivePingInterval = 0 to disable keepalive -// altogether. -func WebsocketKeepAliveDuration(duration time.Duration) Option { - return func(cfg *Config) { - cfg.connectionKeepAlivePingInterval = duration - } -} - -const DefaultCacheSize = 1000 -const DefaultConnectionKeepAlivePingInterval = 25 * time.Second - -// DefaultUploadMaxMemory is the maximum number of bytes used to parse a request body -// as multipart/form-data in memory, with the remainder stored on disk in -// temporary files. -const DefaultUploadMaxMemory = 32 << 20 - -// DefaultUploadMaxSize is maximum number of bytes used to parse a request body -// as multipart/form-data. -const DefaultUploadMaxSize = 32 << 20 - -func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc { - cfg := &Config{ - cacheSize: DefaultCacheSize, - uploadMaxMemory: DefaultUploadMaxMemory, - uploadMaxSize: DefaultUploadMaxSize, - connectionKeepAlivePingInterval: DefaultConnectionKeepAlivePingInterval, - upgrader: websocket.Upgrader{ - ReadBufferSize: 1024, - WriteBufferSize: 1024, - }, - } - - for _, option := range options { - option(cfg) - } - - var cache *lru.Cache - if cfg.cacheSize > 0 { - var err error - cache, err = lru.New(cfg.cacheSize) - if err != nil { - // An error is only returned for non-positive cache size - // and we already checked for that. - panic("unexpected error creating cache: " + err.Error()) - } - } - if cfg.tracer == nil { - cfg.tracer = &graphql.NopTracer{} - } - - handler := &graphqlHandler{ - cfg: cfg, - cache: cache, - exec: exec, - } - - return handler.ServeHTTP -} - -var _ http.Handler = (*graphqlHandler)(nil) - -type graphqlHandler struct { - cfg *Config - cache *lru.Cache - exec graphql.ExecutableSchema -} - -func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - if r.Method == http.MethodOptions { - w.Header().Set("Allow", "OPTIONS, GET, POST") - w.WriteHeader(http.StatusOK) - return - } - - if strings.Contains(r.Header.Get("Upgrade"), "websocket") { - connectWs(gh.exec, w, r, gh.cfg, gh.cache) - return - } - - w.Header().Set("Content-Type", "application/json") - var reqParams params - switch r.Method { - case http.MethodGet: - reqParams.Query = r.URL.Query().Get("query") - reqParams.OperationName = r.URL.Query().Get("operationName") - - if variables := r.URL.Query().Get("variables"); variables != "" { - if err := jsonDecode(strings.NewReader(variables), &reqParams.Variables); err != nil { - sendErrorf(w, http.StatusBadRequest, "variables could not be decoded") - return - } - } - case http.MethodPost: - mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) - if err != nil { - sendErrorf(w, http.StatusBadRequest, "error parsing request Content-Type") - return - } - - switch mediaType { - case "application/json": - if err := jsonDecode(r.Body, &reqParams); err != nil { - sendErrorf(w, http.StatusBadRequest, "json body could not be decoded: "+err.Error()) - return - } - - case "multipart/form-data": - var closers []io.Closer - var tmpFiles []string - defer func() { - for i := len(closers) - 1; 0 <= i; i-- { - _ = closers[i].Close() - } - for _, tmpFile := range tmpFiles { - _ = os.Remove(tmpFile) - } - }() - if err := processMultipart(w, r, &reqParams, &closers, &tmpFiles, gh.cfg.uploadMaxSize, gh.cfg.uploadMaxMemory); err != nil { - sendErrorf(w, http.StatusBadRequest, "multipart body could not be decoded: "+err.Error()) - return - } - default: - sendErrorf(w, http.StatusBadRequest, "unsupported Content-Type: "+mediaType) - return - } - default: - w.WriteHeader(http.StatusMethodNotAllowed) - return - } - - ctx := r.Context() - - var doc *ast.QueryDocument - var cacheHit bool - if gh.cache != nil { - val, ok := gh.cache.Get(reqParams.Query) - if ok { - doc = val.(*ast.QueryDocument) - cacheHit = true - } - } - - ctx, doc, gqlErr := gh.parseOperation(ctx, &parseOperationArgs{ - Query: reqParams.Query, - CachedDoc: doc, - }) - if gqlErr != nil { - sendError(w, http.StatusUnprocessableEntity, gqlErr) - return - } - - ctx, op, vars, listErr := gh.validateOperation(ctx, &validateOperationArgs{ - Doc: doc, - OperationName: reqParams.OperationName, - CacheHit: cacheHit, - R: r, - Variables: reqParams.Variables, - }) - if len(listErr) != 0 { - sendError(w, http.StatusUnprocessableEntity, listErr...) - return - } - - if gh.cache != nil && !cacheHit { - gh.cache.Add(reqParams.Query, doc) - } - - reqCtx := gh.cfg.newRequestContext(gh.exec, doc, op, reqParams.Query, vars) - ctx = graphql.WithRequestContext(ctx, reqCtx) - - defer func() { - if err := recover(); err != nil { - userErr := reqCtx.Recover(ctx, err) - sendErrorf(w, http.StatusUnprocessableEntity, userErr.Error()) - } - }() - - if gh.cfg.complexityLimitFunc != nil { - reqCtx.ComplexityLimit = gh.cfg.complexityLimitFunc(ctx) - } - - if reqCtx.ComplexityLimit > 0 && reqCtx.OperationComplexity > reqCtx.ComplexityLimit { - sendErrorf(w, http.StatusUnprocessableEntity, "operation has complexity %d, which exceeds the limit of %d", reqCtx.OperationComplexity, reqCtx.ComplexityLimit) - return - } - - switch op.Operation { - case ast.Query: - b, err := json.Marshal(gh.exec.Query(ctx, op)) - if err != nil { - panic(err) - } - w.Write(b) - case ast.Mutation: - b, err := json.Marshal(gh.exec.Mutation(ctx, op)) - if err != nil { - panic(err) - } - w.Write(b) - default: - sendErrorf(w, http.StatusBadRequest, "unsupported operation type") - } -} - -type parseOperationArgs struct { - Query string - CachedDoc *ast.QueryDocument -} - -func (gh *graphqlHandler) parseOperation(ctx context.Context, args *parseOperationArgs) (context.Context, *ast.QueryDocument, *gqlerror.Error) { - ctx = gh.cfg.tracer.StartOperationParsing(ctx) - defer func() { gh.cfg.tracer.EndOperationParsing(ctx) }() - - if args.CachedDoc != nil { - return ctx, args.CachedDoc, nil - } - - doc, gqlErr := parser.ParseQuery(&ast.Source{Input: args.Query}) - if gqlErr != nil { - return ctx, nil, gqlErr - } - - return ctx, doc, nil -} - -type validateOperationArgs struct { - Doc *ast.QueryDocument - OperationName string - CacheHit bool - R *http.Request - Variables map[string]interface{} -} - -func (gh *graphqlHandler) validateOperation(ctx context.Context, args *validateOperationArgs) (context.Context, *ast.OperationDefinition, map[string]interface{}, gqlerror.List) { - ctx = gh.cfg.tracer.StartOperationValidation(ctx) - defer func() { gh.cfg.tracer.EndOperationValidation(ctx) }() - - if !args.CacheHit { - listErr := validator.Validate(gh.exec.Schema(), args.Doc) - if len(listErr) != 0 { - return ctx, nil, nil, listErr - } - } - - op := args.Doc.Operations.ForName(args.OperationName) - if op == nil { - return ctx, nil, nil, gqlerror.List{gqlerror.Errorf("operation %s not found", args.OperationName)} - } - - if op.Operation != ast.Query && args.R.Method == http.MethodGet { - return ctx, nil, nil, gqlerror.List{gqlerror.Errorf("GET requests only allow query operations")} - } - - vars, err := validator.VariableValues(gh.exec.Schema(), op, args.Variables) - if err != nil { - return ctx, nil, nil, gqlerror.List{err} - } - - return ctx, op, vars, nil -} - -func jsonDecode(r io.Reader, val interface{}) error { - dec := json.NewDecoder(r) - dec.UseNumber() - return dec.Decode(val) -} - -func sendError(w http.ResponseWriter, code int, errors ...*gqlerror.Error) { - w.WriteHeader(code) - b, err := json.Marshal(&graphql.Response{Errors: errors}) - if err != nil { - panic(err) - } - w.Write(b) -} - -func sendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) { - sendError(w, code, &gqlerror.Error{Message: fmt.Sprintf(format, args...)}) -} - -type bytesReader struct { - s *[]byte - i int64 // current reading index - prevRune int // index of previous rune; or < 0 -} - -func (r *bytesReader) Read(b []byte) (n int, err error) { - if r.s == nil { - return 0, errors.New("byte slice pointer is nil") - } - if r.i >= int64(len(*r.s)) { - return 0, io.EOF - } - r.prevRune = -1 - n = copy(b, (*r.s)[r.i:]) - r.i += int64(n) - return -} - -func processMultipart(w http.ResponseWriter, r *http.Request, request *params, closers *[]io.Closer, tmpFiles *[]string, uploadMaxSize, uploadMaxMemory int64) error { - var err error - if r.ContentLength > uploadMaxSize { - return errors.New("failed to parse multipart form, request body too large") - } - r.Body = http.MaxBytesReader(w, r.Body, uploadMaxSize) - if err = r.ParseMultipartForm(uploadMaxMemory); err != nil { - if strings.Contains(err.Error(), "request body too large") { - return errors.New("failed to parse multipart form, request body too large") - } - return errors.New("failed to parse multipart form") - } - *closers = append(*closers, r.Body) - - if err = jsonDecode(strings.NewReader(r.Form.Get("operations")), &request); err != nil { - return errors.New("operations form field could not be decoded") - } - - var uploadsMap = map[string][]string{} - if err = json.Unmarshal([]byte(r.Form.Get("map")), &uploadsMap); err != nil { - return errors.New("map form field could not be decoded") - } - - var upload graphql.Upload - for key, paths := range uploadsMap { - if len(paths) == 0 { - return fmt.Errorf("invalid empty operations paths list for key %s", key) - } - file, header, err := r.FormFile(key) - if err != nil { - return fmt.Errorf("failed to get key %s from form", key) - } - *closers = append(*closers, file) - - if len(paths) == 1 { - upload = graphql.Upload{ - File: file, - Size: header.Size, - Filename: header.Filename, - } - err = addUploadToOperations(request, upload, key, paths[0]) - if err != nil { - return err - } - } else { - if r.ContentLength < uploadMaxMemory { - fileBytes, err := ioutil.ReadAll(file) - if err != nil { - return fmt.Errorf("failed to read file for key %s", key) - } - for _, path := range paths { - upload = graphql.Upload{ - File: &bytesReader{s: &fileBytes, i: 0, prevRune: -1}, - Size: header.Size, - Filename: header.Filename, - } - err = addUploadToOperations(request, upload, key, path) - if err != nil { - return err - } - } - } else { - tmpFile, err := ioutil.TempFile(os.TempDir(), "gqlgen-") - if err != nil { - return fmt.Errorf("failed to create temp file for key %s", key) - } - tmpName := tmpFile.Name() - *tmpFiles = append(*tmpFiles, tmpName) - _, err = io.Copy(tmpFile, file) - if err != nil { - if err := tmpFile.Close(); err != nil { - return fmt.Errorf("failed to copy to temp file and close temp file for key %s", key) - } - return fmt.Errorf("failed to copy to temp file for key %s", key) - } - if err := tmpFile.Close(); err != nil { - return fmt.Errorf("failed to close temp file for key %s", key) - } - for _, path := range paths { - pathTmpFile, err := os.Open(tmpName) - if err != nil { - return fmt.Errorf("failed to open temp file for key %s", key) - } - *closers = append(*closers, pathTmpFile) - upload = graphql.Upload{ - File: pathTmpFile, - Size: header.Size, - Filename: header.Filename, - } - err = addUploadToOperations(request, upload, key, path) - if err != nil { - return err - } - } - } - } - } - return nil -} - -func addUploadToOperations(request *params, upload graphql.Upload, key, path string) error { - if !strings.HasPrefix(path, "variables.") { - return fmt.Errorf("invalid operations paths for key %s", key) - } - - var ptr interface{} = request.Variables - parts := strings.Split(path, ".") - - // skip the first part (variables) because we started there - for i, p := range parts[1:] { - last := i == len(parts)-2 - if ptr == nil { - return fmt.Errorf("path is missing \"variables.\" prefix, key: %s, path: %s", key, path) - } - if index, parseNbrErr := strconv.Atoi(p); parseNbrErr == nil { - if last { - ptr.([]interface{})[index] = upload - } else { - ptr = ptr.([]interface{})[index] - } - } else { - if last { - ptr.(map[string]interface{})[p] = upload - } else { - ptr = ptr.(map[string]interface{})[p] - } - } - } - - return nil -} diff --git a/vendor/github.com/99designs/gqlgen/handler/handler.go b/vendor/github.com/99designs/gqlgen/handler/handler.go new file mode 100644 index 000000000..892df5398 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/handler/handler.go @@ -0,0 +1,247 @@ +package handler + +import ( + "context" + "net/http" + "time" + + "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/handler" + "github.com/99designs/gqlgen/graphql/handler/extension" + "github.com/99designs/gqlgen/graphql/handler/lru" + "github.com/99designs/gqlgen/graphql/handler/transport" + "github.com/99designs/gqlgen/graphql/playground" + "github.com/gorilla/websocket" +) + +// Deprecated: switch to graphql/handler.New +func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc { + var cfg Config + cfg.cacheSize = 1000 + + for _, option := range options { + option(&cfg) + } + + srv := handler.New(exec) + + srv.AddTransport(transport.Websocket{ + Upgrader: cfg.upgrader, + InitFunc: cfg.websocketInitFunc, + KeepAlivePingInterval: cfg.connectionKeepAlivePingInterval, + }) + srv.AddTransport(transport.Options{}) + srv.AddTransport(transport.GET{}) + srv.AddTransport(transport.POST{}) + srv.AddTransport(transport.MultipartForm{ + MaxUploadSize: cfg.uploadMaxSize, + MaxMemory: cfg.uploadMaxMemory, + }) + + if cfg.cacheSize != 0 { + srv.SetQueryCache(lru.New(cfg.cacheSize)) + } + if cfg.recover != nil { + srv.SetRecoverFunc(cfg.recover) + } + if cfg.errorPresenter != nil { + srv.SetErrorPresenter(cfg.errorPresenter) + } + for _, hook := range cfg.fieldHooks { + srv.AroundFields(hook) + } + for _, hook := range cfg.requestHooks { + srv.AroundResponses(hook) + } + if cfg.complexityLimit != 0 { + srv.Use(extension.FixedComplexityLimit(cfg.complexityLimit)) + } else if cfg.complexityLimitFunc != nil { + srv.Use(&extension.ComplexityLimit{ + Func: func(ctx context.Context, rc *graphql.OperationContext) int { + return cfg.complexityLimitFunc(graphql.WithOperationContext(ctx, rc)) + }, + }) + } + if !cfg.disableIntrospection { + srv.Use(extension.Introspection{}) + } + if cfg.apqCache != nil { + srv.Use(extension.AutomaticPersistedQuery{Cache: apqAdapter{cfg.apqCache}}) + } + return srv.ServeHTTP +} + +// Deprecated: switch to graphql/handler.New +type Config struct { + cacheSize int + upgrader websocket.Upgrader + websocketInitFunc transport.WebsocketInitFunc + connectionKeepAlivePingInterval time.Duration + recover graphql.RecoverFunc + errorPresenter graphql.ErrorPresenterFunc + fieldHooks []graphql.FieldMiddleware + requestHooks []graphql.ResponseMiddleware + complexityLimit int + complexityLimitFunc func(ctx context.Context) int + disableIntrospection bool + uploadMaxMemory int64 + uploadMaxSize int64 + apqCache PersistedQueryCache +} + +// Deprecated: switch to graphql/handler.New +type Option func(cfg *Config) + +// Deprecated: switch to graphql/handler.New +func WebsocketUpgrader(upgrader websocket.Upgrader) Option { + return func(cfg *Config) { + cfg.upgrader = upgrader + } +} + +// Deprecated: switch to graphql/handler.New +func RecoverFunc(recover graphql.RecoverFunc) Option { + return func(cfg *Config) { + cfg.recover = recover + } +} + +// ErrorPresenter transforms errors found while resolving into errors that will be returned to the user. It provides +// a good place to add any extra fields, like error.type, that might be desired by your frontend. Check the default +// implementation in graphql.DefaultErrorPresenter for an example. +// Deprecated: switch to graphql/handler.New +func ErrorPresenter(f graphql.ErrorPresenterFunc) Option { + return func(cfg *Config) { + cfg.errorPresenter = f + } +} + +// IntrospectionEnabled = false will forbid clients from calling introspection endpoints. Can be useful in prod when you dont +// want clients introspecting the full schema. +// Deprecated: switch to graphql/handler.New +func IntrospectionEnabled(enabled bool) Option { + return func(cfg *Config) { + cfg.disableIntrospection = !enabled + } +} + +// ComplexityLimit sets a maximum query complexity that is allowed to be executed. +// If a query is submitted that exceeds the limit, a 422 status code will be returned. +// Deprecated: switch to graphql/handler.New +func ComplexityLimit(limit int) Option { + return func(cfg *Config) { + cfg.complexityLimit = limit + } +} + +// ComplexityLimitFunc allows you to define a function to dynamically set the maximum query complexity that is allowed +// to be executed. +// If a query is submitted that exceeds the limit, a 422 status code will be returned. +// Deprecated: switch to graphql/handler.New +func ComplexityLimitFunc(complexityLimitFunc func(ctx context.Context) int) Option { + return func(cfg *Config) { + cfg.complexityLimitFunc = complexityLimitFunc + } +} + +// ResolverMiddleware allows you to define a function that will be called around every resolver, +// useful for logging. +// Deprecated: switch to graphql/handler.New +func ResolverMiddleware(middleware graphql.FieldMiddleware) Option { + return func(cfg *Config) { + cfg.fieldHooks = append(cfg.fieldHooks, middleware) + } +} + +// RequestMiddleware allows you to define a function that will be called around the root request, +// after the query has been parsed. This is useful for logging +// Deprecated: switch to graphql/handler.New +func RequestMiddleware(middleware graphql.ResponseMiddleware) Option { + return func(cfg *Config) { + cfg.requestHooks = append(cfg.requestHooks, middleware) + } +} + +// WebsocketInitFunc is called when the server receives connection init message from the client. +// This can be used to check initial payload to see whether to accept the websocket connection. +// Deprecated: switch to graphql/handler.New +func WebsocketInitFunc(websocketInitFunc transport.WebsocketInitFunc) Option { + return func(cfg *Config) { + cfg.websocketInitFunc = websocketInitFunc + } +} + +// CacheSize sets the maximum size of the query cache. +// If size is less than or equal to 0, the cache is disabled. +// Deprecated: switch to graphql/handler.New +func CacheSize(size int) Option { + return func(cfg *Config) { + cfg.cacheSize = size + } +} + +// UploadMaxSize sets the maximum number of bytes used to parse a request body +// as multipart/form-data. +// Deprecated: switch to graphql/handler.New +func UploadMaxSize(size int64) Option { + return func(cfg *Config) { + cfg.uploadMaxSize = size + } +} + +// UploadMaxMemory sets the maximum number of bytes used to parse a request body +// as multipart/form-data in memory, with the remainder stored on disk in +// temporary files. +// Deprecated: switch to graphql/handler.New +func UploadMaxMemory(size int64) Option { + return func(cfg *Config) { + cfg.uploadMaxMemory = size + } +} + +// WebsocketKeepAliveDuration allows you to reconfigure the keepalive behavior. +// By default, keepalive is enabled with a DefaultConnectionKeepAlivePingInterval +// duration. Set handler.connectionKeepAlivePingInterval = 0 to disable keepalive +// altogether. +// Deprecated: switch to graphql/handler.New +func WebsocketKeepAliveDuration(duration time.Duration) Option { + return func(cfg *Config) { + cfg.connectionKeepAlivePingInterval = duration + } +} + +// Add cache that will hold queries for automatic persisted queries (APQ) +// Deprecated: switch to graphql/handler.New +func EnablePersistedQueryCache(cache PersistedQueryCache) Option { + return func(cfg *Config) { + cfg.apqCache = cache + } +} + +func GetInitPayload(ctx context.Context) transport.InitPayload { + return transport.GetInitPayload(ctx) +} + +type apqAdapter struct { + PersistedQueryCache +} + +func (a apqAdapter) Get(ctx context.Context, key string) (value interface{}, ok bool) { + return a.PersistedQueryCache.Get(ctx, key) +} +func (a apqAdapter) Add(ctx context.Context, key string, value interface{}) { + a.PersistedQueryCache.Add(ctx, key, value.(string)) +} + +type PersistedQueryCache interface { + Add(ctx context.Context, hash string, query string) + Get(ctx context.Context, hash string) (string, bool) +} + +// Deprecated: use playground.Handler instead +func Playground(title string, endpoint string) http.HandlerFunc { + return playground.Handler(title, endpoint) +} + +// Deprecated: use transport.InitPayload instead +type InitPayload = transport.InitPayload diff --git a/vendor/github.com/99designs/gqlgen/handler/mock.go b/vendor/github.com/99designs/gqlgen/handler/mock.go deleted file mode 100644 index 3e70cf036..000000000 --- a/vendor/github.com/99designs/gqlgen/handler/mock.go +++ /dev/null @@ -1,57 +0,0 @@ -package handler - -import ( - "context" - - "github.com/99designs/gqlgen/graphql" - "github.com/vektah/gqlparser" - "github.com/vektah/gqlparser/ast" -) - -type executableSchemaMock struct { - MutationFunc func(ctx context.Context, op *ast.OperationDefinition) *graphql.Response -} - -var _ graphql.ExecutableSchema = &executableSchemaMock{} - -func (e *executableSchemaMock) Schema() *ast.Schema { - return gqlparser.MustLoadSchema(&ast.Source{Input: ` - schema { query: Query, mutation: Mutation } - type Query { - empty: String! - } - scalar Upload - type File { - id: Int! - } - input UploadFile { - id: Int! - file: Upload! - } - type Mutation { - singleUpload(file: Upload!): File! - singleUploadWithPayload(req: UploadFile!): File! - multipleUpload(files: [Upload!]!): [File!]! - multipleUploadWithPayload(req: [UploadFile!]!): [File!]! - } - `}) -} - -func (e *executableSchemaMock) Complexity(typeName, field string, childComplexity int, args map[string]interface{}) (int, bool) { - return 0, false -} - -func (e *executableSchemaMock) Query(ctx context.Context, op *ast.OperationDefinition) *graphql.Response { - return graphql.ErrorResponse(ctx, "queries are not supported") -} - -func (e *executableSchemaMock) Mutation(ctx context.Context, op *ast.OperationDefinition) *graphql.Response { - return e.MutationFunc(ctx, op) -} - -func (e *executableSchemaMock) Subscription(ctx context.Context, op *ast.OperationDefinition) func() *graphql.Response { - return func() *graphql.Response { - <-ctx.Done() - return nil - } -} diff --git a/vendor/github.com/99designs/gqlgen/handler/stub.go b/vendor/github.com/99designs/gqlgen/handler/stub.go deleted file mode 100644 index d237e1889..000000000 --- a/vendor/github.com/99designs/gqlgen/handler/stub.go +++ /dev/null @@ -1,51 +0,0 @@ -package handler - -import ( - "context" - - "github.com/99designs/gqlgen/graphql" - "github.com/vektah/gqlparser" - "github.com/vektah/gqlparser/ast" -) - -type executableSchemaStub struct { - NextResp chan struct{} -} - -var _ graphql.ExecutableSchema = &executableSchemaStub{} - -func (e *executableSchemaStub) Schema() *ast.Schema { - return gqlparser.MustLoadSchema(&ast.Source{Input: ` - schema { query: Query } - type Query { - me: User! - user(id: Int): User! - } - type User { name: String! } - `}) -} - -func (e *executableSchemaStub) Complexity(typeName, field string, childComplexity int, args map[string]interface{}) (int, bool) { - return 0, false -} - -func (e *executableSchemaStub) Query(ctx context.Context, op *ast.OperationDefinition) *graphql.Response { - return &graphql.Response{Data: []byte(`{"name":"test"}`)} -} - -func (e *executableSchemaStub) Mutation(ctx context.Context, op *ast.OperationDefinition) *graphql.Response { - return graphql.ErrorResponse(ctx, "mutations are not supported") -} - -func (e *executableSchemaStub) Subscription(ctx context.Context, op *ast.OperationDefinition) func() *graphql.Response { - return func() *graphql.Response { - select { - case <-ctx.Done(): - return nil - case <-e.NextResp: - return &graphql.Response{ - Data: []byte(`{"name":"test"}`), - } - } - } -} diff --git a/vendor/github.com/99designs/gqlgen/internal/code/imports.go b/vendor/github.com/99designs/gqlgen/internal/code/imports.go index 75c30fe1e..b56d80fc5 100644 --- a/vendor/github.com/99designs/gqlgen/internal/code/imports.go +++ b/vendor/github.com/99designs/gqlgen/internal/code/imports.go @@ -1,7 +1,6 @@ package code import ( - "errors" "go/build" "go/parser" "go/token" @@ -9,13 +8,8 @@ import ( "path/filepath" "regexp" "strings" - "sync" - - "golang.org/x/tools/go/packages" ) -var nameForPackageCache = sync.Map{} - var gopaths []string func init() { @@ -51,33 +45,50 @@ func NameForDir(dir string) string { return SanitizePackageName(filepath.Base(dir)) } -// ImportPathForDir takes a path and returns a golang import path for the package -func ImportPathForDir(dir string) (res string) { +// goModuleRoot returns the root of the current go module if there is a go.mod file in the directory tree +// If not, it returns false +func goModuleRoot(dir string) (string, bool) { dir, err := filepath.Abs(dir) if err != nil { panic(err) } dir = filepath.ToSlash(dir) - modDir := dir assumedPart := "" for { - f, err := ioutil.ReadFile(filepath.Join(modDir, "/", "go.mod")) + f, err := ioutil.ReadFile(filepath.Join(modDir, "go.mod")) if err == nil { // found it, stop searching - return string(modregex.FindSubmatch(f)[1]) + assumedPart + return string(modregex.FindSubmatch(f)[1]) + assumedPart, true } assumedPart = "/" + filepath.Base(modDir) + assumedPart - modDir, err = filepath.Abs(filepath.Join(modDir, "..")) + parentDir, err := filepath.Abs(filepath.Join(modDir, "..")) if err != nil { panic(err) } - // Walked all the way to the root and didnt find anything :'( - if modDir == "/" { + if parentDir == modDir { + // Walked all the way to the root and didnt find anything :'( break } + modDir = parentDir + } + return "", false +} + +// ImportPathForDir takes a path and returns a golang import path for the package +func ImportPathForDir(dir string) (res string) { + dir, err := filepath.Abs(dir) + + if err != nil { + panic(err) + } + dir = filepath.ToSlash(dir) + + modDir, ok := goModuleRoot(dir) + if ok { + return modDir } for _, gopath := range gopaths { @@ -89,26 +100,4 @@ func ImportPathForDir(dir string) (res string) { return "" } -var modregex = regexp.MustCompile("module (.*)\n") - -// NameForPackage returns the package name for a given import path. This can be really slow. -func NameForPackage(importPath string) string { - if importPath == "" { - panic(errors.New("import path can not be empty")) - } - if v, ok := nameForPackageCache.Load(importPath); ok { - return v.(string) - } - importPath = QualifyPackagePath(importPath) - p, _ := packages.Load(&packages.Config{ - Mode: packages.NeedName, - }, importPath) - - if len(p) != 1 || p[0].Name == "" { - return SanitizePackageName(filepath.Base(importPath)) - } - - nameForPackageCache.Store(importPath, p[0].Name) - - return p[0].Name -} +var modregex = regexp.MustCompile(`module ([^\s]*)`) diff --git a/vendor/github.com/99designs/gqlgen/internal/code/packages.go b/vendor/github.com/99designs/gqlgen/internal/code/packages.go new file mode 100644 index 000000000..b14c45ad2 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/internal/code/packages.go @@ -0,0 +1,173 @@ +package code + +import ( + "bytes" + "path/filepath" + + "github.com/pkg/errors" + "golang.org/x/tools/go/packages" +) + +var mode = packages.NeedName | + packages.NeedFiles | + packages.NeedImports | + packages.NeedTypes | + packages.NeedSyntax | + packages.NeedTypesInfo + +// Packages is a wrapper around x/tools/go/packages that maintains a (hopefully prewarmed) cache of packages +// that can be invalidated as writes are made and packages are known to change. +type Packages struct { + packages map[string]*packages.Package + importToName map[string]string + loadErrors []error + + numLoadCalls int // stupid test steam. ignore. + numNameCalls int // stupid test steam. ignore. +} + +// LoadAll will call packages.Load and return the package data for the given packages, +// but if the package already have been loaded it will return cached values instead. +func (p *Packages) LoadAll(importPaths ...string) []*packages.Package { + if p.packages == nil { + p.packages = map[string]*packages.Package{} + } + + missing := make([]string, 0, len(importPaths)) + for _, path := range importPaths { + if _, ok := p.packages[path]; ok { + continue + } + missing = append(missing, path) + } + + if len(missing) > 0 { + p.numLoadCalls++ + pkgs, err := packages.Load(&packages.Config{Mode: mode}, missing...) + if err != nil { + p.loadErrors = append(p.loadErrors, err) + } + + for _, pkg := range pkgs { + p.addToCache(pkg) + } + } + + res := make([]*packages.Package, 0, len(importPaths)) + for _, path := range importPaths { + res = append(res, p.packages[NormalizeVendor(path)]) + } + return res +} + +func (p *Packages) addToCache(pkg *packages.Package) { + imp := NormalizeVendor(pkg.PkgPath) + p.packages[imp] = pkg + for _, imp := range pkg.Imports { + if _, found := p.packages[NormalizeVendor(imp.PkgPath)]; !found { + p.addToCache(imp) + } + } +} + +// Load works the same as LoadAll, except a single package at a time. +func (p *Packages) Load(importPath string) *packages.Package { + pkgs := p.LoadAll(importPath) + if len(pkgs) == 0 { + return nil + } + return pkgs[0] +} + +// LoadWithTypes tries a standard load, which may not have enough type info (TypesInfo== nil) available if the imported package is a +// second order dependency. Fortunately this doesnt happen very often, so we can just issue a load when we detect it. +func (p *Packages) LoadWithTypes(importPath string) *packages.Package { + pkg := p.Load(importPath) + if pkg == nil || pkg.TypesInfo == nil { + p.numLoadCalls++ + pkgs, err := packages.Load(&packages.Config{Mode: mode}, importPath) + if err != nil { + p.loadErrors = append(p.loadErrors, err) + return nil + } + p.addToCache(pkgs[0]) + pkg = pkgs[0] + } + return pkg +} + +// NameForPackage looks up the package name from the package stanza in the go files at the given import path. +func (p *Packages) NameForPackage(importPath string) string { + if importPath == "" { + panic(errors.New("import path can not be empty")) + } + if p.importToName == nil { + p.importToName = map[string]string{} + } + + importPath = NormalizeVendor(importPath) + + // if its in the name cache use it + if name := p.importToName[importPath]; name != "" { + return name + } + + // otherwise we might have already loaded the full package data for it cached + pkg := p.packages[importPath] + + if pkg == nil { + // otherwise do a name only lookup for it but dont put it in the package cache. + p.numNameCalls++ + pkgs, err := packages.Load(&packages.Config{Mode: packages.NeedName}, importPath) + if err != nil { + p.loadErrors = append(p.loadErrors, err) + } else { + pkg = pkgs[0] + } + } + + if pkg == nil || pkg.Name == "" { + return SanitizePackageName(filepath.Base(importPath)) + } + + p.importToName[importPath] = pkg.Name + + return pkg.Name +} + +// Evict removes a given package import path from the cache, along with any packages that depend on it. Further calls +// to Load will fetch it from disk. +func (p *Packages) Evict(importPath string) { + delete(p.packages, importPath) + + for _, pkg := range p.packages { + for _, imported := range pkg.Imports { + if imported.PkgPath == importPath { + p.Evict(pkg.PkgPath) + } + } + } +} + +// Errors returns any errors that were returned by Load, either from the call itself or any of the loaded packages. +func (p *Packages) Errors() PkgErrors { + var res []error //nolint:prealloc + res = append(res, p.loadErrors...) + for _, pkg := range p.packages { + for _, err := range pkg.Errors { + res = append(res, err) + } + } + return res +} + +type PkgErrors []error + +func (p PkgErrors) Error() string { + var b bytes.Buffer + b.WriteString("packages.Load: ") + for _, e := range p { + b.WriteString(e.Error() + "\n") + } + return b.String() +} diff --git a/vendor/github.com/99designs/gqlgen/internal/code/util.go b/vendor/github.com/99designs/gqlgen/internal/code/util.go index 2be83a23c..cbe40858e 100644 --- a/vendor/github.com/99designs/gqlgen/internal/code/util.go +++ b/vendor/github.com/99designs/gqlgen/internal/code/util.go @@ -41,6 +41,11 @@ func NormalizeVendor(pkg string) string { func QualifyPackagePath(importPath string) string { wd, _ := os.Getwd() + // in go module mode, the import path doesn't need fixing + if _, ok := goModuleRoot(wd); ok { + return importPath + } + pkg, err := build.Import(importPath, wd, 0) if err != nil { return importPath diff --git a/vendor/github.com/99designs/gqlgen/internal/imports/prune.go b/vendor/github.com/99designs/gqlgen/internal/imports/prune.go index d678870ef..d42a41579 100644 --- a/vendor/github.com/99designs/gqlgen/internal/imports/prune.go +++ b/vendor/github.com/99designs/gqlgen/internal/imports/prune.go @@ -24,7 +24,7 @@ func (fn visitFn) Visit(node ast.Node) ast.Visitor { } // Prune removes any unused imports -func Prune(filename string, src []byte) ([]byte, error) { +func Prune(filename string, src []byte, packages *code.Packages) ([]byte, error) { fset := token.NewFileSet() file, err := parser.ParseFile(fset, filename, src, parser.ParseComments|parser.AllErrors) @@ -32,10 +32,7 @@ func Prune(filename string, src []byte) ([]byte, error) { return nil, err } - unused, err := getUnusedImports(file, filename) - if err != nil { - return nil, err - } + unused := getUnusedImports(file, packages) for ipath, name := range unused { astutil.DeleteNamedImport(fset, file, name, ipath) } @@ -49,7 +46,7 @@ func Prune(filename string, src []byte) ([]byte, error) { return imports.Process(filename, buf.Bytes(), &imports.Options{FormatOnly: true, Comments: true, TabIndent: true, TabWidth: 8}) } -func getUnusedImports(file ast.Node, filename string) (map[string]string, error) { +func getUnusedImports(file ast.Node, packages *code.Packages) map[string]string { imported := map[string]*ast.ImportSpec{} used := map[string]bool{} @@ -68,7 +65,7 @@ func getUnusedImports(file ast.Node, filename string) (map[string]string, error) break } - local := code.NameForPackage(ipath) + local := packages.NameForPackage(ipath) imported[local] = v case *ast.SelectorExpr: @@ -99,5 +96,5 @@ func getUnusedImports(file ast.Node, filename string) (map[string]string, error) } } - return unusedImport, nil + return unusedImport } diff --git a/vendor/github.com/99designs/gqlgen/internal/rewrite/rewriter.go b/vendor/github.com/99designs/gqlgen/internal/rewrite/rewriter.go new file mode 100644 index 000000000..1b9adb171 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/internal/rewrite/rewriter.go @@ -0,0 +1,195 @@ +package rewrite + +import ( + "bytes" + "fmt" + "go/ast" + "go/token" + "io/ioutil" + "path/filepath" + "strconv" + "strings" + + "github.com/99designs/gqlgen/internal/code" + "golang.org/x/tools/go/packages" +) + +type Rewriter struct { + pkg *packages.Package + files map[string]string + copied map[ast.Decl]bool +} + +func New(dir string) (*Rewriter, error) { + importPath := code.ImportPathForDir(dir) + if importPath == "" { + return nil, fmt.Errorf("import path not found for directory: %q", dir) + } + pkgs, err := packages.Load(&packages.Config{ + Mode: packages.NeedSyntax | packages.NeedTypes, + }, importPath) + if err != nil { + return nil, err + } + if len(pkgs) == 0 { + return nil, fmt.Errorf("package not found for importPath: %s", importPath) + } + + return &Rewriter{ + pkg: pkgs[0], + files: map[string]string{}, + copied: map[ast.Decl]bool{}, + }, nil +} + +func (r *Rewriter) getSource(start, end token.Pos) string { + startPos := r.pkg.Fset.Position(start) + endPos := r.pkg.Fset.Position(end) + + if startPos.Filename != endPos.Filename { + panic("cant get source spanning multiple files") + } + + file := r.getFile(startPos.Filename) + return file[startPos.Offset:endPos.Offset] +} + +func (r *Rewriter) getFile(filename string) string { + if _, ok := r.files[filename]; !ok { + b, err := ioutil.ReadFile(filename) + if err != nil { + panic(fmt.Errorf("unable to load file, already exists: %s", err.Error())) + } + + r.files[filename] = string(b) + + } + + return r.files[filename] +} + +func (r *Rewriter) GetMethodBody(structname string, methodname string) string { + for _, f := range r.pkg.Syntax { + for _, d := range f.Decls { + d, isFunc := d.(*ast.FuncDecl) + if !isFunc { + continue + } + if d.Name.Name != methodname { + continue + } + if d.Recv == nil || len(d.Recv.List) == 0 { + continue + } + recv := d.Recv.List[0].Type + if star, isStar := recv.(*ast.StarExpr); isStar { + recv = star.X + } + ident, ok := recv.(*ast.Ident) + if !ok { + continue + } + + if ident.Name != structname { + continue + } + + r.copied[d] = true + + return r.getSource(d.Body.Pos()+1, d.Body.End()-1) + } + } + + return "" +} + +func (r *Rewriter) MarkStructCopied(name string) { + for _, f := range r.pkg.Syntax { + for _, d := range f.Decls { + d, isGen := d.(*ast.GenDecl) + if !isGen { + continue + } + if d.Tok != token.TYPE || len(d.Specs) == 0 { + continue + } + + spec, isTypeSpec := d.Specs[0].(*ast.TypeSpec) + if !isTypeSpec { + continue + } + + if spec.Name.Name != name { + continue + } + + r.copied[d] = true + } + } +} + +func (r *Rewriter) ExistingImports(filename string) []Import { + filename, err := filepath.Abs(filename) + if err != nil { + panic(err) + } + for _, f := range r.pkg.Syntax { + pos := r.pkg.Fset.Position(f.Pos()) + + if filename != pos.Filename { + continue + } + + var imps []Import + for _, i := range f.Imports { + name := "" + if i.Name != nil { + name = i.Name.Name + } + path, err := strconv.Unquote(i.Path.Value) + if err != nil { + panic(err) + } + imps = append(imps, Import{name, path}) + } + return imps + } + return nil +} + +func (r *Rewriter) RemainingSource(filename string) string { + filename, err := filepath.Abs(filename) + if err != nil { + panic(err) + } + for _, f := range r.pkg.Syntax { + pos := r.pkg.Fset.Position(f.Pos()) + + if filename != pos.Filename { + continue + } + + var buf bytes.Buffer + + for _, d := range f.Decls { + if r.copied[d] { + continue + } + + if d, isGen := d.(*ast.GenDecl); isGen && d.Tok == token.IMPORT { + continue + } + + buf.WriteString(r.getSource(d.Pos(), d.End())) + buf.WriteString("\n") + } + + return strings.TrimSpace(buf.String()) + } + return "" +} + +type Import struct { + Alias string + ImportPath string +} diff --git a/vendor/github.com/99designs/gqlgen/plugin/federation/federation.go b/vendor/github.com/99designs/gqlgen/plugin/federation/federation.go new file mode 100644 index 000000000..7d9abc977 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/plugin/federation/federation.go @@ -0,0 +1,311 @@ +package federation + +import ( + "fmt" + "sort" + "strings" + + "github.com/vektah/gqlparser/v2/ast" + + "github.com/99designs/gqlgen/codegen" + "github.com/99designs/gqlgen/codegen/config" + "github.com/99designs/gqlgen/codegen/templates" + "github.com/99designs/gqlgen/plugin" +) + +type federation struct { + Entities []*Entity +} + +// New returns a federation plugin that injects +// federated directives and types into the schema +func New() plugin.Plugin { + return &federation{} +} + +// Name returns the plugin name +func (f *federation) Name() string { + return "federation" +} + +// MutateConfig mutates the configuration +func (f *federation) MutateConfig(cfg *config.Config) error { + builtins := config.TypeMap{ + "_Service": { + Model: config.StringList{ + "github.com/99designs/gqlgen/plugin/federation/fedruntime.Service", + }, + }, + "_Entity": { + Model: config.StringList{ + "github.com/99designs/gqlgen/plugin/federation/fedruntime.Entity", + }, + }, + "Entity": { + Model: config.StringList{ + "github.com/99designs/gqlgen/plugin/federation/fedruntime.Entity", + }, + }, + "_Any": { + Model: config.StringList{"github.com/99designs/gqlgen/graphql.Map"}, + }, + } + for typeName, entry := range builtins { + if cfg.Models.Exists(typeName) { + return fmt.Errorf("%v already exists which must be reserved when Federation is enabled", typeName) + } + cfg.Models[typeName] = entry + } + cfg.Directives["external"] = config.DirectiveConfig{SkipRuntime: true} + cfg.Directives["requires"] = config.DirectiveConfig{SkipRuntime: true} + cfg.Directives["provides"] = config.DirectiveConfig{SkipRuntime: true} + cfg.Directives["key"] = config.DirectiveConfig{SkipRuntime: true} + cfg.Directives["extends"] = config.DirectiveConfig{SkipRuntime: true} + + return nil +} + +func (f *federation) InjectSourceEarly() *ast.Source { + return &ast.Source{ + Name: "federation/directives.graphql", + Input: ` +scalar _Any +scalar _FieldSet + +directive @external on FIELD_DEFINITION +directive @requires(fields: _FieldSet!) on FIELD_DEFINITION +directive @provides(fields: _FieldSet!) on FIELD_DEFINITION +directive @key(fields: _FieldSet!) on OBJECT | INTERFACE +directive @extends on OBJECT +`, + BuiltIn: true, + } +} + +// InjectSources creates a GraphQL Entity type with all +// the fields that had the @key directive +func (f *federation) InjectSourceLate(schema *ast.Schema) *ast.Source { + f.setEntities(schema) + + entities := "" + resolvers := "" + for i, e := range f.Entities { + if i != 0 { + entities += " | " + } + entities += e.Name + + if e.ResolverName != "" { + resolverArgs := "" + for _, field := range e.KeyFields { + resolverArgs += fmt.Sprintf("%s: %s,", field.Field.Name, field.Field.Type.String()) + } + resolvers += fmt.Sprintf("\t%s(%s): %s!\n", e.ResolverName, resolverArgs, e.Def.Name) + } + + } + + if len(f.Entities) == 0 { + // It's unusual for a service not to have any entities, but + // possible if it only exports top-level queries and mutations. + return nil + } + + // resolvers can be empty if a service defines only "empty + // extend" types. This should be rare. + if resolvers != "" { + resolvers = ` +# fake type to build resolver interfaces for users to implement +type Entity { + ` + resolvers + ` +} +` + } + + return &ast.Source{ + Name: "federation/entity.graphql", + BuiltIn: true, + Input: ` +# a union of all types that use the @key directive +union _Entity = ` + entities + ` +` + resolvers + ` +type _Service { + sdl: String +} + +extend type Query { + _entities(representations: [_Any!]!): [_Entity]! + _service: _Service! +} +`, + } +} + +// Entity represents a federated type +// that was declared in the GQL schema. +type Entity struct { + Name string // The same name as the type declaration + KeyFields []*KeyField // The fields declared in @key. + ResolverName string // The resolver name, such as FindUserByID + Def *ast.Definition + Requires []*Requires +} + +type KeyField struct { + Field *ast.FieldDefinition + TypeReference *config.TypeReference // The Go representation of that field type +} + +// Requires represents an @requires clause +type Requires struct { + Name string // the name of the field + Fields []*RequireField // the name of the sibling fields +} + +// RequireField is similar to an entity but it is a field not +// an object +type RequireField struct { + Name string // The same name as the type declaration + NameGo string // The Go struct field name + TypeReference *config.TypeReference // The Go representation of that field type +} + +func (e *Entity) allFieldsAreExternal() bool { + for _, field := range e.Def.Fields { + if field.Directives.ForName("external") == nil { + return false + } + } + return true +} + +func (f *federation) GenerateCode(data *codegen.Data) error { + if len(f.Entities) > 0 { + if data.Objects.ByName("Entity") != nil { + data.Objects.ByName("Entity").Root = true + } + for _, e := range f.Entities { + obj := data.Objects.ByName(e.Def.Name) + for _, field := range obj.Fields { + // Storing key fields in a slice rather than a map + // to preserve insertion order at the tradeoff of higher + // lookup complexity. + keyField := f.getKeyField(e.KeyFields, field.Name) + if keyField != nil { + keyField.TypeReference = field.TypeReference + } + for _, r := range e.Requires { + for _, rf := range r.Fields { + if rf.Name == field.Name { + rf.TypeReference = field.TypeReference + rf.NameGo = field.GoFieldName + } + } + } + } + } + } + + return templates.Render(templates.Options{ + PackageName: data.Config.Federation.Package, + Filename: data.Config.Federation.Filename, + Data: f, + GeneratedHeader: true, + Packages: data.Config.Packages, + }) +} + +func (f *federation) getKeyField(keyFields []*KeyField, fieldName string) *KeyField { + for _, field := range keyFields { + if field.Field.Name == fieldName { + return field + } + } + return nil +} + +func (f *federation) setEntities(schema *ast.Schema) { + for _, schemaType := range schema.Types { + if schemaType.Kind == ast.Object { + dir := schemaType.Directives.ForName("key") // TODO: interfaces + if dir != nil { + if len(dir.Arguments) > 1 { + panic("Multiple arguments are not currently supported in @key declaration.") + } + fieldName := dir.Arguments[0].Value.Raw // TODO: multiple arguments + if strings.Contains(fieldName, "{") { + panic("Nested fields are not currently supported in @key declaration.") + } + + requires := []*Requires{} + for _, f := range schemaType.Fields { + dir := f.Directives.ForName("requires") + if dir == nil { + continue + } + fields := strings.Split(dir.Arguments[0].Value.Raw, " ") + requireFields := []*RequireField{} + for _, f := range fields { + requireFields = append(requireFields, &RequireField{ + Name: f, + }) + } + requires = append(requires, &Requires{ + Name: f.Name, + Fields: requireFields, + }) + } + + fieldNames := strings.Split(fieldName, " ") + keyFields := make([]*KeyField, len(fieldNames)) + resolverName := fmt.Sprintf("find%sBy", schemaType.Name) + for i, f := range fieldNames { + field := schemaType.Fields.ForName(f) + + keyFields[i] = &KeyField{Field: field} + if i > 0 { + resolverName += "And" + } + resolverName += templates.ToGo(f) + + } + + e := &Entity{ + Name: schemaType.Name, + KeyFields: keyFields, + Def: schemaType, + ResolverName: resolverName, + Requires: requires, + } + // If our schema has a field with a type defined in + // another service, then we need to define an "empty + // extend" of that type in this service, so this service + // knows what the type is like. But the graphql-server + // will never ask us to actually resolve this "empty + // extend", so we don't require a resolver function for + // it. (Well, it will never ask in practice; it's + // unclear whether the spec guarantees this. See + // https://github.com/apollographql/apollo-server/issues/3852 + // ). Example: + // type MyType { + // myvar: TypeDefinedInOtherService + // } + // // Federation needs this type, but + // // it doesn't need a resolver for it! + // extend TypeDefinedInOtherService @key(fields: "id") { + // id: ID @external + // } + if e.allFieldsAreExternal() { + e.ResolverName = "" + } + + f.Entities = append(f.Entities, e) + } + } + } + + // make sure order remains stable across multiple builds + sort.Slice(f.Entities, func(i, j int) bool { + return f.Entities[i].Name < f.Entities[j].Name + }) +} diff --git a/vendor/github.com/99designs/gqlgen/plugin/federation/federation.gotpl b/vendor/github.com/99designs/gqlgen/plugin/federation/federation.gotpl new file mode 100644 index 000000000..96c25e857 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/plugin/federation/federation.gotpl @@ -0,0 +1,69 @@ +{{ reserveImport "context" }} +{{ reserveImport "errors" }} +{{ reserveImport "fmt" }} +{{ reserveImport "strings" }} + +{{ reserveImport "github.com/99designs/gqlgen/plugin/federation/fedruntime" }} + +func (ec *executionContext) __resolve__service(ctx context.Context) (fedruntime.Service, error) { + if ec.DisableIntrospection { + return fedruntime.Service{}, errors.New("federated introspection disabled") + } + + var sdl []string + + for _, src := range sources { + if src.BuiltIn { + continue + } + sdl = append(sdl, src.Input) + } + + return fedruntime.Service{ + SDL: strings.Join(sdl, "\n"), + }, nil +} + +{{if .Entities}} +func (ec *executionContext) __resolve_entities(ctx context.Context, representations []map[string]interface{}) ([]fedruntime.Entity, error) { + list := []fedruntime.Entity{} + for _, rep := range representations { + typeName, ok := rep["__typename"].(string) + if !ok { + return nil, errors.New("__typename must be an existing string") + } + switch typeName { + {{ range .Entities }} + {{ if .ResolverName }} + case "{{.Def.Name}}": + {{ range $i, $keyField := .KeyFields -}} + id{{$i}}, err := ec.{{.TypeReference.UnmarshalFunc}}(ctx, rep["{{$keyField.Field.Name}}"]) + if err != nil { + return nil, errors.New(fmt.Sprintf("Field %s undefined in schema.", "{{$keyField.Field.Name}}")) + } + {{end}} + + entity, err := ec.resolvers.Entity().{{.ResolverName | go}}(ctx, + {{ range $i, $_ := .KeyFields -}} id{{$i}}, {{end}}) + if err != nil { + return nil, err + } + + {{ range .Requires }} + {{ range .Fields}} + entity.{{.NameGo}}, err = ec.{{.TypeReference.UnmarshalFunc}}(ctx, rep["{{.Name}}"]) + if err != nil { + return nil, err + } + {{ end }} + {{ end }} + list = append(list, entity) + {{ end }} + {{ end }} + default: + return nil, errors.New("unknown type: "+typeName) + } + } + return list, nil +} +{{end}} diff --git a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go index bb400f1b7..e0ca18663 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go +++ b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go @@ -7,11 +7,16 @@ import ( "github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/templates" - "github.com/99designs/gqlgen/internal/code" "github.com/99designs/gqlgen/plugin" - "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/v2/ast" ) +type BuildMutateHook = func(b *ModelBuild) *ModelBuild + +func defaultBuildMutateHook(b *ModelBuild) *ModelBuild { + return b +} + type ModelBuild struct { PackageName string Interfaces []*Interface @@ -51,10 +56,14 @@ type EnumValue struct { } func New() plugin.Plugin { - return &Plugin{} + return &Plugin{ + MutateHook: defaultBuildMutateHook, + } } -type Plugin struct{} +type Plugin struct { + MutateHook BuildMutateHook +} var _ plugin.ConfigMutator = &Plugin{} @@ -63,31 +72,16 @@ func (m *Plugin) Name() string { } func (m *Plugin) MutateConfig(cfg *config.Config) error { - if err := cfg.Check(); err != nil { - return err - } - - schema, _, err := cfg.LoadSchema() - if err != nil { - return err - } - - cfg.InjectBuiltins(schema) - - binder, err := cfg.NewBinder(schema) - if err != nil { - return err - } + binder := cfg.NewBinder() b := &ModelBuild{ PackageName: cfg.Model.Package, } - for _, schemaType := range schema.Types { + for _, schemaType := range cfg.Schema.Types { if cfg.Models.UserDefined(schemaType.Name) { continue } - switch schemaType.Kind { case ast.Interface, ast.Union: it := &Interface{ @@ -97,25 +91,24 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error { b.Interfaces = append(b.Interfaces, it) case ast.Object, ast.InputObject: - if schemaType == schema.Query || schemaType == schema.Mutation || schemaType == schema.Subscription { + if schemaType == cfg.Schema.Query || schemaType == cfg.Schema.Mutation || schemaType == cfg.Schema.Subscription { continue } it := &Object{ Description: schemaType.Description, Name: schemaType.Name, } - - for _, implementor := range schema.GetImplements(schemaType) { + for _, implementor := range cfg.Schema.GetImplements(schemaType) { it.Implements = append(it.Implements, implementor.Name) } for _, field := range schemaType.Fields { var typ types.Type - fieldDef := schema.Types[field.Type.Name()] + fieldDef := cfg.Schema.Types[field.Type.Name()] if cfg.Models.UserDefined(field.Type.Name()) { - pkg, typeName := code.PkgAndType(cfg.Models[field.Type.Name()].Model[0]) - typ, err = binder.FindType(pkg, typeName) + var err error + typ, err = binder.FindTypeFromName(cfg.Models[field.Type.Name()].Model[0]) if err != nil { return err } @@ -196,7 +189,6 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error { b.Scalars = append(b.Scalars, schemaType.Name) } } - sort.Slice(b.Enums, func(i, j int) bool { return b.Enums[i].Name < b.Enums[j].Name }) sort.Slice(b.Models, func(i, j int) bool { return b.Models[i].Name < b.Models[j].Name }) sort.Slice(b.Interfaces, func(i, j int) bool { return b.Interfaces[i].Name < b.Interfaces[j].Name }) @@ -214,15 +206,20 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error { cfg.Models.Add(it, "github.com/99designs/gqlgen/graphql.String") } - if len(b.Models) == 0 && len(b.Enums) == 0 { + if len(b.Models) == 0 && len(b.Enums) == 0 && len(b.Interfaces) == 0 && len(b.Scalars) == 0 { return nil } + if m.MutateHook != nil { + b = m.MutateHook(b) + } + return templates.Render(templates.Options{ PackageName: cfg.Model.Package, Filename: cfg.Model.Filename, Data: b, GeneratedHeader: true, + Packages: cfg.Packages, }) } diff --git a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.gotpl b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.gotpl index 6df200ee0..e58d5b21a 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.gotpl +++ b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.gotpl @@ -7,8 +7,8 @@ {{ reserveImport "errors" }} {{ reserveImport "bytes" }} -{{ reserveImport "github.com/vektah/gqlparser" }} -{{ reserveImport "github.com/vektah/gqlparser/ast" }} +{{ reserveImport "github.com/vektah/gqlparser/v2" }} +{{ reserveImport "github.com/vektah/gqlparser/v2/ast" }} {{ reserveImport "github.com/99designs/gqlgen/graphql" }} {{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }} @@ -36,7 +36,7 @@ {{- end}} {{ range $enum := .Enums }} - {{ with .Description|go }} {{.|prefixLines "// "}} {{end}} + {{ with .Description }} {{.|prefixLines "// "}} {{end}} type {{.Name|go }} string const ( {{- range $value := .Values}} diff --git a/vendor/github.com/99designs/gqlgen/plugin/plugin.go b/vendor/github.com/99designs/gqlgen/plugin/plugin.go index a84bfd327..7de36bd8c 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/plugin.go +++ b/vendor/github.com/99designs/gqlgen/plugin/plugin.go @@ -5,6 +5,7 @@ package plugin import ( "github.com/99designs/gqlgen/codegen" "github.com/99designs/gqlgen/codegen/config" + "github.com/vektah/gqlparser/v2/ast" ) type Plugin interface { @@ -18,3 +19,13 @@ type ConfigMutator interface { type CodeGenerator interface { GenerateCode(cfg *codegen.Data) error } + +// EarlySourceInjector is used to inject things that are required for user schema files to compile. +type EarlySourceInjector interface { + InjectSourceEarly() *ast.Source +} + +// LateSourceInjector is used to inject more sources, after we have loaded the users schema. +type LateSourceInjector interface { + InjectSourceLate(schema *ast.Schema) *ast.Source +} diff --git a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go index 00a6d5c9d..204801efb 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go +++ b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go @@ -1,11 +1,14 @@ package resolvergen import ( - "log" "os" + "path/filepath" + "strings" "github.com/99designs/gqlgen/codegen" + "github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/templates" + "github.com/99designs/gqlgen/internal/rewrite" "github.com/99designs/gqlgen/plugin" "github.com/pkg/errors" ) @@ -19,35 +22,186 @@ type Plugin struct{} var _ plugin.CodeGenerator = &Plugin{} func (m *Plugin) Name() string { - return "resovlergen" + return "resolvergen" } + func (m *Plugin) GenerateCode(data *codegen.Data) error { if !data.Config.Resolver.IsDefined() { return nil } + switch data.Config.Resolver.Layout { + case config.LayoutSingleFile: + return m.generateSingleFile(data) + case config.LayoutFollowSchema: + return m.generatePerSchema(data) + } + + return nil +} + +func (m *Plugin) generateSingleFile(data *codegen.Data) error { + file := File{} + + if _, err := os.Stat(data.Config.Resolver.Filename); err == nil { + // file already exists and we dont support updating resolvers with layout = single so just return + return nil + } + + for _, o := range data.Objects { + if o.HasResolvers() { + file.Objects = append(file.Objects, o) + } + for _, f := range o.Fields { + if !f.IsResolver { + continue + } + + resolver := Resolver{o, f, `panic("not implemented")`} + file.Resolvers = append(file.Resolvers, &resolver) + } + } + resolverBuild := &ResolverBuild{ - Data: data, + File: &file, PackageName: data.Config.Resolver.Package, ResolverType: data.Config.Resolver.Type, + HasRoot: true, } - filename := data.Config.Resolver.Filename - if _, err := os.Stat(filename); os.IsNotExist(errors.Cause(err)) { - return templates.Render(templates.Options{ + return templates.Render(templates.Options{ + PackageName: data.Config.Resolver.Package, + FileNotice: `// THIS CODE IS A STARTING POINT ONLY. IT WILL NOT BE UPDATED WITH SCHEMA CHANGES.`, + Filename: data.Config.Resolver.Filename, + Data: resolverBuild, + Packages: data.Config.Packages, + }) +} + +func (m *Plugin) generatePerSchema(data *codegen.Data) error { + rewriter, err := rewrite.New(data.Config.Resolver.Dir()) + if err != nil { + return err + } + + files := map[string]*File{} + + for _, o := range data.Objects { + if o.HasResolvers() { + fn := gqlToResolverName(data.Config.Resolver.Dir(), o.Position.Src.Name, data.Config.Resolver.FilenameTemplate) + if files[fn] == nil { + files[fn] = &File{} + } + + rewriter.MarkStructCopied(templates.LcFirst(o.Name) + templates.UcFirst(data.Config.Resolver.Type)) + rewriter.GetMethodBody(data.Config.Resolver.Type, o.Name) + files[fn].Objects = append(files[fn].Objects, o) + } + for _, f := range o.Fields { + if !f.IsResolver { + continue + } + + structName := templates.LcFirst(o.Name) + templates.UcFirst(data.Config.Resolver.Type) + implementation := strings.TrimSpace(rewriter.GetMethodBody(structName, f.GoFieldName)) + if implementation == "" { + implementation = `panic(fmt.Errorf("not implemented"))` + } + + resolver := Resolver{o, f, implementation} + fn := gqlToResolverName(data.Config.Resolver.Dir(), f.Position.Src.Name, data.Config.Resolver.FilenameTemplate) + if files[fn] == nil { + files[fn] = &File{} + } + + files[fn].Resolvers = append(files[fn].Resolvers, &resolver) + } + } + + for filename, file := range files { + file.imports = rewriter.ExistingImports(filename) + file.RemainingSource = rewriter.RemainingSource(filename) + } + + for filename, file := range files { + resolverBuild := &ResolverBuild{ + File: file, + PackageName: data.Config.Resolver.Package, + ResolverType: data.Config.Resolver.Type, + } + + err := templates.Render(templates.Options{ PackageName: data.Config.Resolver.Package, - Filename: data.Config.Resolver.Filename, - Data: resolverBuild, + FileNotice: ` + // This file will be automatically regenerated based on the schema, any resolver implementations + // will be copied through when generating and any unknown code will be moved to the end.`, + Filename: filename, + Data: resolverBuild, + Packages: data.Config.Packages, }) + if err != nil { + return err + } } - log.Printf("Skipped resolver: %s already exists\n", filename) + if _, err := os.Stat(data.Config.Resolver.Filename); os.IsNotExist(errors.Cause(err)) { + err := templates.Render(templates.Options{ + PackageName: data.Config.Resolver.Package, + FileNotice: ` + // This file will not be regenerated automatically. + // + // It serves as dependency injection for your app, add any dependencies you require here.`, + Template: `type {{.}} struct {}`, + Filename: data.Config.Resolver.Filename, + Data: data.Config.Resolver.Type, + Packages: data.Config.Packages, + }) + if err != nil { + return err + } + } return nil } type ResolverBuild struct { - *codegen.Data - + *File + HasRoot bool PackageName string ResolverType string } + +type File struct { + // These are separated because the type definition of the resolver object may live in a different file from the + //resolver method implementations, for example when extending a type in a different graphql schema file + Objects []*codegen.Object + Resolvers []*Resolver + imports []rewrite.Import + RemainingSource string +} + +func (f *File) Imports() string { + for _, imp := range f.imports { + if imp.Alias == "" { + _, _ = templates.CurrentImports.Reserve(imp.ImportPath) + } else { + _, _ = templates.CurrentImports.Reserve(imp.ImportPath, imp.Alias) + } + } + return "" +} + +type Resolver struct { + Object *codegen.Object + Field *codegen.Field + Implementation string +} + +func gqlToResolverName(base string, gqlname, filenameTmpl string) string { + gqlname = filepath.Base(gqlname) + ext := filepath.Ext(gqlname) + if filenameTmpl == "" { + filenameTmpl = "{name}.resolvers.go" + } + filename := strings.ReplaceAll(filenameTmpl, "{name}", strings.TrimSuffix(gqlname, ext)) + return filepath.Join(base, filename) +} diff --git a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl index 7d95e6903..543bf136e 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl +++ b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl @@ -1,5 +1,3 @@ -// THIS CODE IS A STARTING POINT ONLY. IT WILL NOT BE UPDATED WITH SCHEMA CHANGES. - {{ reserveImport "context" }} {{ reserveImport "fmt" }} {{ reserveImport "io" }} @@ -9,32 +7,39 @@ {{ reserveImport "errors" }} {{ reserveImport "bytes" }} -{{ reserveImport "github.com/99designs/gqlgen/handler" }} -{{ reserveImport "github.com/vektah/gqlparser" }} -{{ reserveImport "github.com/vektah/gqlparser/ast" }} +{{ reserveImport "github.com/vektah/gqlparser/v2" }} +{{ reserveImport "github.com/vektah/gqlparser/v2/ast" }} {{ reserveImport "github.com/99designs/gqlgen/graphql" }} {{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }} -type {{.ResolverType}} struct {} +{{ .Imports }} + +{{ if .HasRoot }} + type {{.ResolverType}} struct {} +{{ end }} + +{{ range $resolver := .Resolvers -}} + func (r *{{lcFirst $resolver.Object.Name}}{{ucFirst $.ResolverType}}) {{$resolver.Field.GoFieldName}}{{ $resolver.Field.ShortResolverDeclaration }} { + {{ $resolver.Implementation }} + } -{{ range $object := .Objects -}} - {{- if $object.HasResolvers -}} - func (r *{{$.ResolverType}}) {{$object.Name}}() {{ $object.ResolverInterface | ref }} { - return &{{lcFirst $object.Name}}Resolver{r} - } - {{ end -}} {{ end }} {{ range $object := .Objects -}} - {{- if $object.HasResolvers -}} - type {{lcFirst $object.Name}}Resolver struct { *Resolver } - - {{ range $field := $object.Fields -}} - {{- if $field.IsResolver -}} - func (r *{{lcFirst $object.Name}}Resolver) {{$field.GoFieldName}}{{ $field.ShortResolverDeclaration }} { - panic("not implemented") - } - {{ end -}} - {{ end -}} - {{ end -}} + // {{$object.Name}} returns {{ $object.ResolverInterface | ref }} implementation. + func (r *{{$.ResolverType}}) {{$object.Name}}() {{ $object.ResolverInterface | ref }} { return &{{lcFirst $object.Name}}{{ucFirst $.ResolverType}}{r} } +{{ end }} + +{{ range $object := .Objects -}} + type {{lcFirst $object.Name}}{{ucFirst $.ResolverType}} struct { *{{$.ResolverType}} } +{{ end }} + +{{ if (ne .RemainingSource "") }} + // !!! WARNING !!! + // The code below was going to be deleted when updating resolvers. It has been copied here so you have + // one last chance to move it out of harms way if you want. There are two reasons this happens: + // - When renaming or deleting a resolver the old code will be put in here. You can safely delete + // it when you're done. + // - You have helper methods in this file. Move them out to keep these resolver files clean. + {{ .RemainingSource }} {{ end }} diff --git a/vendor/github.com/99designs/gqlgen/plugin/servergen/server.go b/vendor/github.com/99designs/gqlgen/plugin/servergen/server.go index 22289c025..029c9ae39 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/servergen/server.go +++ b/vendor/github.com/99designs/gqlgen/plugin/servergen/server.go @@ -34,6 +34,7 @@ func (m *Plugin) GenerateCode(data *codegen.Data) error { PackageName: "main", Filename: m.filename, Data: serverBuild, + Packages: data.Config.Packages, }) } diff --git a/vendor/github.com/99designs/gqlgen/plugin/servergen/server.gotpl b/vendor/github.com/99designs/gqlgen/plugin/servergen/server.gotpl index fca71c53c..a3ae2a877 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/servergen/server.gotpl +++ b/vendor/github.com/99designs/gqlgen/plugin/servergen/server.gotpl @@ -2,7 +2,8 @@ {{ reserveImport "log" }} {{ reserveImport "net/http" }} {{ reserveImport "os" }} -{{ reserveImport "github.com/99designs/gqlgen/handler" }} +{{ reserveImport "github.com/99designs/gqlgen/graphql/playground" }} +{{ reserveImport "github.com/99designs/gqlgen/graphql/handler" }} const defaultPort = "8080" @@ -12,8 +13,10 @@ func main() { port = defaultPort } - http.Handle("/", handler.Playground("GraphQL playground", "/query")) - http.Handle("/query", handler.GraphQL({{ lookupImport .ExecPackageName }}.NewExecutableSchema({{ lookupImport .ExecPackageName}}.Config{Resolvers: &{{ lookupImport .ResolverPackageName}}.Resolver{}}))) + srv := handler.NewDefaultServer({{ lookupImport .ExecPackageName }}.NewExecutableSchema({{ lookupImport .ExecPackageName}}.Config{Resolvers: &{{ lookupImport .ResolverPackageName}}.Resolver{}})) + + http.Handle("/", playground.Handler("GraphQL playground", "/query")) + http.Handle("/query", srv) log.Printf("connect to http://localhost:%s/ for GraphQL playground", port) log.Fatal(http.ListenAndServe(":" + port, nil)) diff --git a/vendor/github.com/99designs/gqlgen/tools.go b/vendor/github.com/99designs/gqlgen/tools.go index 912fc0d63..e63a71a80 100644 --- a/vendor/github.com/99designs/gqlgen/tools.go +++ b/vendor/github.com/99designs/gqlgen/tools.go @@ -2,4 +2,7 @@ package main -import _ "github.com/vektah/dataloaden" +import ( + _ "github.com/matryer/moq" + _ "github.com/vektah/dataloaden" +) diff --git a/vendor/github.com/Yamashou/gqlgenc/.gitignore b/vendor/github.com/Yamashou/gqlgenc/.gitignore new file mode 100644 index 000000000..15b3e741f --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/.gitignore @@ -0,0 +1,7 @@ +/.gqlgenc.yml +/models_gen.go +/**/.graphqlconfig +/schema.graphql +/client.go +/query/ +/.idea/ diff --git a/vendor/github.com/Yamashou/gqlgenc/.golangci.yml b/vendor/github.com/Yamashou/gqlgenc/.golangci.yml new file mode 100644 index 000000000..941fe3034 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/.golangci.yml @@ -0,0 +1,65 @@ +# See https://github.com/golangci/golangci-lint/blob/master/.golangci.example.yml +run: +linters-settings: + govet: + enable-all: true + disable: + - shadow + unused: + check-exported: true + unparam: + check-exported: true + varcheck: + exported-fields: true + structcheck: + exported-fields: true + nakedret: + max-func-lines: 1 + +linters: + enable-all: true + disable: + - testpackage + - nestif + - godot + - wsl + - lll + - dupl + - funlen + - gochecknoinits + - gochecknoglobals + - godox + - maligned + - gocognit + - gocyclo + - interfacer + - gomnd + - goerr113 + fast: false + +issues: + exclude-rules: + # Test + - path: _test\.go + text: "Using the variable on range scope `tt` in function literal" + linters: + - scopelint + - path: _test\.go + linters: + - unused + - structcheck + - path: introspection/type.go + linters: + - structcheck # These types fits IntrospectionQuery + - path: config/config.go + text: "`Query` is unused" # used in main.go + linters: + - structcheck + - path: graphqljson/graphql.go + text: "`Extensions` is unused" # used in line 48 + linters: + - structcheck + - path: introspection/query.go + text: "`Introspection` is unused" # used in config/config.go + linters: + - varcheck diff --git a/vendor/github.com/Yamashou/gqlgenc/LICENSE b/vendor/github.com/Yamashou/gqlgenc/LICENSE new file mode 100644 index 000000000..e16053d8f --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Yamashou + +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/Yamashou/gqlgenc/Makefile b/vendor/github.com/Yamashou/gqlgenc/Makefile new file mode 100644 index 000000000..453c30b40 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/Makefile @@ -0,0 +1,10 @@ +MAKEFLAGS=--no-builtin-rules --no-builtin-variables --always-make + +fmt: + gofumports -local github.com/Yamashou/gqlgenc -w . + +lint: + golangci-lint run + +test: + go test -v ./... diff --git a/vendor/github.com/Yamashou/gqlgenc/README.md b/vendor/github.com/Yamashou/gqlgenc/README.md new file mode 100644 index 000000000..598017976 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/README.md @@ -0,0 +1,118 @@ +# gqlgenc + +## What is gqlgenc ? + +This is Go library for building GraphQL client with [gqlgen](https://github.com/99designs/gqlgen) + +## Motivation + +Now, if you build GraphQL api client for Go, have choice: + + - [github.com/shurcooL/graphql](https://github.com/shurcooL/graphql) + - [github.com/machinebox/graphql](https://github.com/machinebox/graphql) + +These libraries are very simple and easy to handle. +However, as I work with [gqlgen](https://github.com/99designs/gqlgen) and [graphql-code-generator](https://graphql-code-generator.com/) every day, I find out the beauty of automatic generation. +So I want to automatically generate types. + +## Installation + +```shell script +go get -u github.com/Yamashou/gqlgenc +``` + +## How to use + +### Client Codes Only + +gqlgenc base is gqlgen with [plugins](https://gqlgen.com/reference/plugins/). So the setting is yaml in each format. +gqlgenc can be configured using a .gqlgenc.yml file, + +```yaml + +model: + package: generated + filename: ./models_gen.go # https://github.com/99designs/gqlgen/tree/master/plugin/modelgen +client: + package: generated + filename: ./client.go # Where should any generated client go? +models: + Int: + model: github.com/99designs/gqlgen/graphql.Int64 + Date: + model: github.com/99designs/gqlgen/graphql.Time +endpoint: + url: https://api.annict.com/graphql # Where do you want to send your request? + headers: # If you need header for getting introspection query, set it + Authorization: "Bearer ${ANNICT_KEY}" # support environment variables +query: + - "./query/*.graphql" # Where are all the query files located? +``` + +Execute the following command on same directory for .gqlgenc.yaml + +```shell script +gqlgenc +``` + +### With gqlgen + +Do this when creating a server and client for Go. +You create your own entrypoint for gqlgen. +This use case is very useful for testing your server. + + +```go +package main + +import ( + "fmt" + "os" + + "github.com/Yamashou/gqlgenc/clientgen" + + "github.com/99designs/gqlgen/api" + "github.com/99designs/gqlgen/codegen/config" +) + +func main() { + cfg, err := config.LoadConfigFromDefaultLocations() + if err != nil { + fmt.Fprintln(os.Stderr, "failed to load config", err.Error()) + os.Exit(2) + } + queries := []string{"client.query", "fragemt.query"} + clientPackage := config.PackageConfig{ + Filename: "./client.go", + Package: "gen", + } + + clientPlugin := clientgen.New(queries, clientPackage) + err = api.Generate(cfg, + api.AddPlugin(clientPlugin), + ) + if err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(3) + } +} +``` + +## Documents + +- [How to configure gqlgen using gqlgen.yml](https://gqlgen.com/config/) +- [How to write plugins for gqlgen](https://gqlgen.com/reference/plugins/) + + +## Comments + +### Japanese Comments +These codes have Japanese comments. Replace with English. + +### Subscription + +This client does not support subscription. If you need a subscription, please create an issue or pull request. + +### Pre-conditions + +[clientgen](https://github.com/Yamashou/gqlgenc/tree/master/clientgen) is created based on [modelgen](https://github.com/99designs/gqlgen/tree/master/plugin/modelgen). So if you don't have a modelgen, it may be a mysterious move. diff --git a/vendor/github.com/Yamashou/gqlgenc/client/client.go b/vendor/github.com/Yamashou/gqlgenc/client/client.go new file mode 100644 index 000000000..94cea8971 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/client/client.go @@ -0,0 +1,88 @@ +package client + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + + "github.com/Yamashou/gqlgenc/graphqljson" + "golang.org/x/xerrors" +) + +type HTTPRequestOption func(req *http.Request) + +type Client struct { + Client *http.Client + BaseURL string + HTTPRequestOptions []HTTPRequestOption +} + +// Request represents an outgoing GraphQL request +type Request struct { + Query string `json:"query"` + Variables map[string]interface{} `json:"variables,omitempty"` + OperationName string `json:"operationName,omitempty"` +} + +func NewClient(client *http.Client, baseURL string, options ...HTTPRequestOption) *Client { + return &Client{ + Client: client, + BaseURL: baseURL, + HTTPRequestOptions: options, + } +} + +func (c *Client) newRequest(ctx context.Context, query string, vars map[string]interface{}, httpRequestOptions []HTTPRequestOption) (*http.Request, error) { + r := &Request{ + Query: query, + Variables: vars, + OperationName: "", + } + + requestBody, err := json.Marshal(r) + if err != nil { + return nil, xerrors.Errorf("encode: %w", err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.BaseURL, bytes.NewBuffer(requestBody)) + if err != nil { + return nil, xerrors.Errorf("create request struct failed: %w", err) + } + + for _, httpRequestOption := range c.HTTPRequestOptions { + httpRequestOption(req) + } + for _, httpRequestOption := range httpRequestOptions { + httpRequestOption(req) + } + + return req, nil +} + +// Post sends a http POST request to the graphql endpoint with the given query then unpacks +// the response into the given object. +func (c *Client) Post(ctx context.Context, query string, respData interface{}, vars map[string]interface{}, httpRequestOptions ...HTTPRequestOption) error { + req, err := c.newRequest(ctx, query, vars, httpRequestOptions) + if err != nil { + return xerrors.Errorf("don't create request: %w", err) + } + req.Header.Set("Content-Type", "application/json; charset=utf-8") + req.Header.Set("Accept", "application/json; charset=utf-8") + + resp, err := c.Client.Do(req) + if err != nil { + return xerrors.Errorf("request failed: %w", err) + } + defer resp.Body.Close() + + if err := graphqljson.Unmarshal(resp.Body, respData); err != nil { + return err + } + + if resp.StatusCode < 200 || 299 < resp.StatusCode { + return xerrors.Errorf("http status code: %v", resp.StatusCode) + } + + return nil +} diff --git a/vendor/github.com/Yamashou/gqlgenc/clientgen/client.go b/vendor/github.com/Yamashou/gqlgenc/clientgen/client.go new file mode 100644 index 000000000..d037ccb55 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/clientgen/client.go @@ -0,0 +1,76 @@ +package clientgen + +import ( + "github.com/99designs/gqlgen/codegen/config" + "github.com/99designs/gqlgen/plugin" + "golang.org/x/xerrors" +) + +var _ plugin.ConfigMutator = &Plugin{} + +type Plugin struct { + queryFilePaths []string + Client config.PackageConfig +} + +func New(queryFilePaths []string, client config.PackageConfig) *Plugin { + return &Plugin{ + queryFilePaths: queryFilePaths, + Client: client, + } +} + +func (p *Plugin) Name() string { + return "clientgen" +} + +func (p *Plugin) MutateConfig(cfg *config.Config) error { + querySources, err := LoadQuerySources(p.queryFilePaths) + if err != nil { + return xerrors.Errorf("load query sources failed: %w", err) + } + + // 1. 全体のqueryDocumentを1度にparse + // 1. Parse document from source of query + queryDocument, err := ParseQueryDocuments(cfg.Schema, querySources) + if err != nil { + return xerrors.Errorf(": %w", err) + } + + // 2. OperationごとのqueryDocumentを作成 + // 2. Separate documents for each operation + queryDocuments, err := QueryDocumentsByOperations(cfg.Schema, queryDocument.Operations) + if err != nil { + return xerrors.Errorf("parse query document failed: %w", err) + } + + // 3. テンプレートと情報ソースを元にコード生成 + // 3. Generate code from template and document source + sourceGenerator := NewSourceGenerator(cfg, p.Client) + source := NewSource(cfg.Schema, queryDocument, sourceGenerator) + query, err := source.Query() + if err != nil { + return xerrors.Errorf("generating query object: %w", err) + } + + mutation, err := source.Mutation() + if err != nil { + return xerrors.Errorf("generating mutation object: %w", err) + } + + fragments, err := source.Fragments() + if err != nil { + return xerrors.Errorf("generating fragment failed: %w", err) + } + + operationResponses, err := source.OperationResponses() + if err != nil { + return xerrors.Errorf("generating operation response failed: %w", err) + } + + if err := RenderTemplate(cfg, query, mutation, fragments, source.Operations(queryDocuments), operationResponses, p.Client); err != nil { + return xerrors.Errorf("template failed: %w", err) + } + + return nil +} diff --git a/vendor/github.com/Yamashou/gqlgenc/clientgen/query.go b/vendor/github.com/Yamashou/gqlgenc/clientgen/query.go new file mode 100644 index 000000000..ea99bc5c6 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/clientgen/query.go @@ -0,0 +1,93 @@ +package clientgen + +import ( + "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/parser" + "github.com/vektah/gqlparser/v2/validator" + "golang.org/x/xerrors" +) + +func ParseQueryDocuments(schema *ast.Schema, querySources []*ast.Source) (*ast.QueryDocument, error) { + var queryDocument ast.QueryDocument + for _, querySource := range querySources { + query, gqlerr := parser.ParseQuery(querySource) + if gqlerr != nil { + return nil, xerrors.Errorf(": %w", gqlerr) + } + + mergeQueryDocument(&queryDocument, query) + } + + if errs := validator.Validate(schema, &queryDocument); errs != nil { + return nil, xerrors.Errorf(": %w", errs) + } + + return &queryDocument, nil +} + +func mergeQueryDocument(q, other *ast.QueryDocument) { + q.Operations = append(q.Operations, other.Operations...) + q.Fragments = append(q.Fragments, other.Fragments...) +} + +func QueryDocumentsByOperations(schema *ast.Schema, operations ast.OperationList) ([]*ast.QueryDocument, error) { + queryDocuments := make([]*ast.QueryDocument, 0, len(operations)) + for _, operation := range operations { + fragments := fragmentsInOperationDefinition(operation) + + queryDocument := &ast.QueryDocument{ + Operations: ast.OperationList{operation}, + Fragments: fragments, + Position: nil, + } + + if errs := validator.Validate(schema, queryDocument); errs != nil { + return nil, xerrors.Errorf(": %w", errs) + } + + queryDocuments = append(queryDocuments, queryDocument) + } + + return queryDocuments, nil +} + +func fragmentsInOperationDefinition(operation *ast.OperationDefinition) ast.FragmentDefinitionList { + fragments := fragmentsInOperationWalker(operation.SelectionSet) + uniqueFragments := fragmentsUnique(fragments) + + return uniqueFragments +} + +func fragmentsUnique(fragments ast.FragmentDefinitionList) ast.FragmentDefinitionList { + uniqueMap := make(map[string]*ast.FragmentDefinition) + for _, fragment := range fragments { + uniqueMap[fragment.Name] = fragment + } + + uniqueFragments := make(ast.FragmentDefinitionList, 0, len(uniqueMap)) + for _, fragment := range uniqueMap { + uniqueFragments = append(uniqueFragments, fragment) + } + + return uniqueFragments +} + +func fragmentsInOperationWalker(selectionSet ast.SelectionSet) ast.FragmentDefinitionList { + var fragments ast.FragmentDefinitionList + for _, selection := range selectionSet { + var selectionSet ast.SelectionSet + switch selection := selection.(type) { + case *ast.Field: + selectionSet = selection.SelectionSet + case *ast.InlineFragment: + selectionSet = selection.SelectionSet + case *ast.FragmentSpread: + fragments = append(fragments, selection.Definition) + selectionSet = selection.Definition.SelectionSet + } + + fragments = append(fragments, fragmentsInOperationWalker(selectionSet)...) + } + + return fragments +} diff --git a/vendor/github.com/Yamashou/gqlgenc/clientgen/query_source.go b/vendor/github.com/Yamashou/gqlgenc/clientgen/query_source.go new file mode 100644 index 000000000..946b744c0 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/clientgen/query_source.go @@ -0,0 +1,106 @@ +/* +Copyright (c) 2020 gqlgen authors + +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 clientgen + +import ( + "io/ioutil" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/99designs/gqlgen/codegen/config" + "github.com/vektah/gqlparser/v2/ast" + "golang.org/x/xerrors" +) + +var path2regex = strings.NewReplacer( + `.`, `\.`, + `*`, `.+`, + `\`, `[\\/]`, + `/`, `[\\/]`, +) + +// LoadQuerySourceなどは、gqlgenがLoadConfigでSchemaを読み込む時の実装をコピーして一部修正している +// **/test/*.graphqlなどに対応している +func LoadQuerySources(queryFileNames []string) ([]*ast.Source, error) { + var noGlobQueryFileNames config.StringList + + var err error + preGlobbing := queryFileNames + for _, f := range preGlobbing { + var matches []string + + // for ** we want to override default globbing patterns and walk all + // subdirectories to match schema files. + if strings.Contains(f, "**") { + pathParts := strings.SplitN(f, "**", 2) + rest := strings.TrimPrefix(strings.TrimPrefix(pathParts[1], `\`), `/`) + // turn the rest of the glob into a regex, anchored only at the end because ** allows + // for any number of dirs in between and walk will let us match against the full path name + globRe := regexp.MustCompile(path2regex.Replace(rest) + `$`) + + if err := filepath.Walk(pathParts[0], func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if globRe.MatchString(strings.TrimPrefix(path, pathParts[0])) { + matches = append(matches, path) + } + + return nil + }); err != nil { + return nil, xerrors.Errorf("failed to walk schema at root: %w", pathParts[0]) + } + } else { + matches, err = filepath.Glob(f) + if err != nil { + return nil, xerrors.Errorf("failed to glob schema filename %v: %w", f, err) + } + } + + for _, m := range matches { + if noGlobQueryFileNames.Has(m) { + continue + } + + noGlobQueryFileNames = append(noGlobQueryFileNames, m) + } + } + + querySources := make([]*ast.Source, 0, len(noGlobQueryFileNames)) + for _, filename := range noGlobQueryFileNames { + filename = filepath.ToSlash(filename) + var err error + var schemaRaw []byte + schemaRaw, err = ioutil.ReadFile(filename) + if err != nil { + return nil, xerrors.Errorf("unable to open schema: %w", err) + } + + querySources = append(querySources, &ast.Source{Name: filename, Input: string(schemaRaw)}) + } + + return querySources, nil +} diff --git a/vendor/github.com/Yamashou/gqlgenc/clientgen/source.go b/vendor/github.com/Yamashou/gqlgenc/clientgen/source.go new file mode 100644 index 000000000..534d94416 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/clientgen/source.go @@ -0,0 +1,193 @@ +package clientgen + +import ( + "bytes" + "fmt" + "go/types" + + "github.com/99designs/gqlgen/codegen/templates" + "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/formatter" + "golang.org/x/xerrors" +) + +type Source struct { + schema *ast.Schema + queryDocument *ast.QueryDocument + sourceGenerator *SourceGenerator +} + +func NewSource(schema *ast.Schema, queryDocument *ast.QueryDocument, sourceGenerator *SourceGenerator) *Source { + return &Source{ + schema: schema, + queryDocument: queryDocument, + sourceGenerator: sourceGenerator, + } +} + +type Fragment struct { + Name string + Type types.Type +} + +func (s *Source) Fragments() ([]*Fragment, error) { + fragments := make([]*Fragment, 0, len(s.queryDocument.Fragments)) + for _, fragment := range s.queryDocument.Fragments { + responseFields := s.sourceGenerator.NewResponseFields(fragment.SelectionSet) + if s.sourceGenerator.cfg.Models.Exists(fragment.Name) { + return nil, xerrors.New(fmt.Sprintf("%s is duplicated", fragment.Name)) + } + + fragment := &Fragment{ + Name: fragment.Name, + Type: responseFields.StructType(), + } + + fragments = append(fragments, fragment) + } + + for _, fragment := range fragments { + name := fragment.Name + s.sourceGenerator.cfg.Models.Add( + name, + fmt.Sprintf("%s.%s", s.sourceGenerator.client.Pkg(), templates.ToGo(name)), + ) + } + + return fragments, nil +} + +type Operation struct { + Name string + ResponseStructName string + Operation string + Args []*Argument + VariableDefinitions ast.VariableDefinitionList +} + +func NewOperation(operation *ast.OperationDefinition, queryDocument *ast.QueryDocument, args []*Argument) *Operation { + return &Operation{ + Name: operation.Name, + ResponseStructName: getResponseStructName(operation), + Operation: queryString(queryDocument), + Args: args, + VariableDefinitions: operation.VariableDefinitions, + } +} + +func (s *Source) Operations(queryDocuments []*ast.QueryDocument) []*Operation { + operations := make([]*Operation, 0, len(s.queryDocument.Operations)) + + queryDocumentsMap := queryDocumentMapByOperationName(queryDocuments) + operationArgsMap := s.operationArgsMapByOperationName() + for _, operation := range s.queryDocument.Operations { + queryDocument := queryDocumentsMap[operation.Name] + args := operationArgsMap[operation.Name] + operations = append(operations, NewOperation( + operation, + queryDocument, + args, + )) + } + + return operations +} + +func (s *Source) operationArgsMapByOperationName() map[string][]*Argument { + operationArgsMap := make(map[string][]*Argument) + for _, operation := range s.queryDocument.Operations { + operationArgsMap[operation.Name] = s.sourceGenerator.OperationArguments(operation.VariableDefinitions) + } + + return operationArgsMap +} + +func queryDocumentMapByOperationName(queryDocuments []*ast.QueryDocument) map[string]*ast.QueryDocument { + queryDocumentMap := make(map[string]*ast.QueryDocument) + for _, queryDocument := range queryDocuments { + operation := queryDocument.Operations[0] + queryDocumentMap[operation.Name] = queryDocument + } + + return queryDocumentMap +} + +func queryString(queryDocument *ast.QueryDocument) string { + var buf bytes.Buffer + astFormatter := formatter.NewFormatter(&buf) + astFormatter.FormatQueryDocument(queryDocument) + + return buf.String() +} + +type OperationResponse struct { + Name string + Type types.Type +} + +func (s *Source) OperationResponses() ([]*OperationResponse, error) { + operationResponse := make([]*OperationResponse, 0, len(s.queryDocument.Operations)) + for _, operation := range s.queryDocument.Operations { + responseFields := s.sourceGenerator.NewResponseFields(operation.SelectionSet) + name := getResponseStructName(operation) + if s.sourceGenerator.cfg.Models.Exists(name) { + return nil, xerrors.New(fmt.Sprintf("%s is duplicated", name)) + } + operationResponse = append(operationResponse, &OperationResponse{ + Name: name, + Type: responseFields.StructType(), + }) + } + + for _, operationResponse := range operationResponse { + name := operationResponse.Name + s.sourceGenerator.cfg.Models.Add( + name, + fmt.Sprintf("%s.%s", s.sourceGenerator.client.Pkg(), templates.ToGo(name)), + ) + } + + return operationResponse, nil +} + +type Query struct { + Name string + Type types.Type +} + +func (s *Source) Query() (*Query, error) { + fields, err := s.sourceGenerator.NewResponseFieldsByDefinition(s.schema.Query) + if err != nil { + return nil, xerrors.Errorf("generate failed for query struct type : %w", err) + } + + return &Query{ + Name: s.schema.Query.Name, + Type: fields.StructType(), + }, nil +} + +type Mutation struct { + Name string + Type types.Type +} + +func (s *Source) Mutation() (*Mutation, error) { + fields, err := s.sourceGenerator.NewResponseFieldsByDefinition(s.schema.Mutation) + if err != nil { + return nil, xerrors.Errorf("generate failed for mutation struct type : %w", err) + } + + return &Mutation{ + Name: s.schema.Mutation.Name, + Type: fields.StructType(), + }, nil +} + +func getResponseStructName(operation *ast.OperationDefinition) string { + if operation.Operation == ast.Mutation { + return fmt.Sprintf("%sPayload", operation.Name) + } + + return operation.Name +} diff --git a/vendor/github.com/Yamashou/gqlgenc/clientgen/source_generator.go b/vendor/github.com/Yamashou/gqlgenc/clientgen/source_generator.go new file mode 100644 index 000000000..f9be08150 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/clientgen/source_generator.go @@ -0,0 +1,204 @@ +package clientgen + +import ( + "fmt" + "go/types" + "strings" + + "github.com/99designs/gqlgen/codegen/config" + "github.com/99designs/gqlgen/codegen/templates" + "github.com/vektah/gqlparser/v2/ast" + "golang.org/x/xerrors" +) + +type Argument struct { + Variable string + Type types.Type +} + +type ResponseField struct { + Name string + IsFragmentSpread bool + IsInlineFragment bool + Type types.Type + Tags []string + ResponseFields ResponseFieldList +} + +type ResponseFieldList []*ResponseField + +func (rs ResponseFieldList) StructType() *types.Struct { + vars := make([]*types.Var, 0) + structTags := make([]string, 0) + for _, filed := range rs { + // クエリーのフィールドの子階層がFragmentの場合、このフィールドにそのFragmentの型を追加する + if filed.IsFragmentSpread { + typ := filed.ResponseFields.StructType().Underlying().(*types.Struct) + for j := 0; j < typ.NumFields(); j++ { + vars = append(vars, typ.Field(j)) + structTags = append(structTags, typ.Tag(j)) + } + } else { + vars = append(vars, types.NewVar(0, nil, templates.ToGo(filed.Name), filed.Type)) + structTags = append(structTags, strings.Join(filed.Tags, " ")) + } + } + + return types.NewStruct(vars, structTags) +} + +func (rs ResponseFieldList) IsFragment() bool { + if len(rs) != 1 { + return false + } + + return rs[0].IsInlineFragment || rs[0].IsFragmentSpread +} + +func (rs ResponseFieldList) IsBasicType() bool { + return len(rs) == 0 +} + +func (rs ResponseFieldList) IsStructType() bool { + return len(rs) > 0 && !rs.IsFragment() +} + +type SourceGenerator struct { + cfg *config.Config + binder *config.Binder + client config.PackageConfig +} + +func NewSourceGenerator(cfg *config.Config, client config.PackageConfig) *SourceGenerator { + return &SourceGenerator{ + cfg: cfg, + binder: cfg.NewBinder(), + client: client, + } +} + +func (r *SourceGenerator) NewResponseFields(selectionSet ast.SelectionSet) ResponseFieldList { + responseFields := make(ResponseFieldList, 0, len(selectionSet)) + for _, selection := range selectionSet { + responseFields = append(responseFields, r.NewResponseField(selection)) + } + + return responseFields +} + +func (r *SourceGenerator) NewResponseFieldsByDefinition(definition *ast.Definition) (ResponseFieldList, error) { + fields := make(ResponseFieldList, 0, len(definition.Fields)) + for _, field := range definition.Fields { + if field.Type.Name() == "__Schema" || field.Type.Name() == "__Type" { + continue + } + typ, err := r.binder.FindTypeFromName(r.cfg.Models[field.Type.Name()].Model[0]) + if err != nil { + return nil, xerrors.Errorf("not found type: %w", err) + } + tags := []string{ + fmt.Sprintf(`json:"%s"`, field.Name), + fmt.Sprintf(`graphql:"%s"`, field.Name), + } + + fields = append(fields, &ResponseField{ + Name: field.Name, + Type: r.binder.CopyModifiersFromAst(field.Type, typ), + Tags: tags, + }) + } + + return fields, nil +} + +func (r *SourceGenerator) NewResponseField(selection ast.Selection) *ResponseField { + switch selection := selection.(type) { + case *ast.Field: + fieldsResponseFields := r.NewResponseFields(selection.SelectionSet) + + var baseType types.Type + switch { + case fieldsResponseFields.IsBasicType(): + baseType = r.Type(selection.Definition.Type.Name()) + case fieldsResponseFields.IsFragment(): + // 子フィールドがFragmentの場合はこのFragmentがフィールドの型になる + // if a child field is fragment, this field type became fragment. + baseType = fieldsResponseFields[0].Type + case fieldsResponseFields.IsStructType(): + baseType = fieldsResponseFields.StructType() + default: + // ここにきたらバグ + // here is bug + panic("not match type") + } + + // GraphQLの定義がオプショナルのはtypeのポインタ型が返り、配列の定義場合はポインタのスライスの型になって返ってきます + // return pointer type then optional type or slice pointer then slice type of definition in GraphQL. + typ := r.binder.CopyModifiersFromAst(selection.Definition.Type, baseType) + + tags := []string{ + fmt.Sprintf(`json:"%s"`, selection.Alias), + fmt.Sprintf(`graphql:"%s"`, selection.Alias), + } + + return &ResponseField{ + Name: selection.Alias, + Type: typ, + Tags: tags, + ResponseFields: fieldsResponseFields, + } + + case *ast.FragmentSpread: + // この構造体はテンプレート側で使われることはなく、ast.FieldでFragment判定するために使用する + fieldsResponseFields := r.NewResponseFields(selection.Definition.SelectionSet) + typ := types.NewNamed( + types.NewTypeName(0, r.client.Pkg(), templates.ToGo(selection.Name), nil), + fieldsResponseFields.StructType(), + nil, + ) + + return &ResponseField{ + Name: selection.Name, + Type: typ, + IsFragmentSpread: true, + ResponseFields: fieldsResponseFields, + } + + case *ast.InlineFragment: + // InlineFragmentは子要素をそのままstructとしてもつので、ここで、構造体の型を作成します + fieldsResponseFields := r.NewResponseFields(selection.SelectionSet) + + return &ResponseField{ + Name: selection.TypeCondition, + Type: fieldsResponseFields.StructType(), + IsInlineFragment: true, + Tags: []string{fmt.Sprintf(`graphql:"... on %s"`, selection.TypeCondition)}, + ResponseFields: fieldsResponseFields, + } + } + + panic("unexpected selection type") +} + +func (r *SourceGenerator) OperationArguments(variableDefinitions ast.VariableDefinitionList) []*Argument { + argumentTypes := make([]*Argument, 0, len(variableDefinitions)) + for _, v := range variableDefinitions { + argumentTypes = append(argumentTypes, &Argument{ + Variable: v.Variable, + Type: r.binder.CopyModifiersFromAst(v.Type, r.Type(v.Type.Name())), + }) + } + + return argumentTypes +} + +// Typeの引数に渡すtypeNameは解析した結果からselectionなどから求めた型の名前を渡さなければいけない +func (r *SourceGenerator) Type(typeName string) types.Type { + goType, err := r.binder.FindTypeFromName(r.cfg.Models[typeName].Model[0]) + if err != nil { + // 実装として正しいtypeNameを渡していれば必ず見つかるはずなのでpanic + panic(fmt.Sprintf("%+v", err)) + } + + return goType +} diff --git a/vendor/github.com/Yamashou/gqlgenc/clientgen/template.go b/vendor/github.com/Yamashou/gqlgenc/clientgen/template.go new file mode 100644 index 000000000..3e8fca403 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/clientgen/template.go @@ -0,0 +1,27 @@ +package clientgen + +import ( + "github.com/99designs/gqlgen/codegen/config" + "github.com/99designs/gqlgen/codegen/templates" + "golang.org/x/xerrors" +) + +func RenderTemplate(cfg *config.Config, query *Query, mutation *Mutation, fragments []*Fragment, operations []*Operation, operationResponses []*OperationResponse, client config.PackageConfig) error { + if err := templates.Render(templates.Options{ + PackageName: client.Package, + Filename: client.Filename, + Data: map[string]interface{}{ + "Query": query, + "Mutation": mutation, + "Fragment": fragments, + "Operation": operations, + "OperationResponse": operationResponses, + }, + Packages: cfg.Packages, + PackageDoc: "// Code generated by github.com/Yamashou/gqlgenc, DO NOT EDIT.\n", + }); err != nil { + return xerrors.Errorf("%s generating failed: %w", client.Filename, err) + } + + return nil +} diff --git a/vendor/github.com/Yamashou/gqlgenc/clientgen/template.gotpl b/vendor/github.com/Yamashou/gqlgenc/clientgen/template.gotpl new file mode 100644 index 000000000..76495ee8a --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/clientgen/template.gotpl @@ -0,0 +1,54 @@ +{{ reserveImport "bytes" }} +{{ reserveImport "context" }} +{{ reserveImport "encoding/json" }} +{{ reserveImport "fmt" }} +{{ reserveImport "io" }} +{{ reserveImport "io/ioutil" }} +{{ reserveImport "net/http" }} +{{ reserveImport "net/url" }} +{{ reserveImport "path" }} +{{ reserveImport "time" }} + +{{ reserveImport "golang.org/x/xerrors" }} + +{{ reserveImport "github.com/Yamashou/gqlgenc/graphqljson" }} +{{ reserveImport "github.com/Yamashou/gqlgenc/client" }} + +type Client struct { + Client *client.Client +} + +func NewClient(cli *http.Client, baseURL string, options ...client.HTTPRequestOption) *Client { + return &Client{Client: client.NewClient(cli, baseURL, options...)} +} + +type {{ .Query.Name | go }} {{ .Query.Type | ref }} + +type {{ .Mutation.Name | go }} {{ .Mutation.Type | ref }} + +{{- range $name, $element := .Fragment }} + type {{ .Name | go }} {{ .Type | ref }} +{{- end }} + +{{- range $name, $element := .OperationResponse }} + type {{ .Name | go }} {{ .Type | ref }} +{{- end }} + +{{- range $model := .Operation}} +const {{ $model.Name|go }}Query = `{{ $model.Operation }}` + +func (c *Client) {{ $model.Name|go }} (ctx context.Context{{- range $arg := .Args }}, {{ $arg.Variable | goPrivate }} {{ $arg.Type | ref }} {{- end }}, httpRequestOptions ...client.HTTPRequestOption) (*{{ $model.ResponseStructName | go }}, error) { + vars := map[string]interface{}{ + {{- range $args := .VariableDefinitions}} + "{{ $args.Variable }}": {{ $args.Variable | goPrivate }}, + {{- end }} + } + + var res {{ $model.ResponseStructName | go }} + if err := c.Client.Post(ctx, {{ $model.Name|go }}Query, &res, vars, httpRequestOptions...); err != nil { + return nil, err + } + + return &res, nil +} +{{- end}} diff --git a/vendor/github.com/Yamashou/gqlgenc/config/config.go b/vendor/github.com/Yamashou/gqlgenc/config/config.go new file mode 100644 index 000000000..620b11ca3 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/config/config.go @@ -0,0 +1,123 @@ +package config + +import ( + "context" + "io/ioutil" + "net/http" + "os" + "path/filepath" + + "github.com/99designs/gqlgen/codegen/config" + "github.com/Yamashou/gqlgenc/client" + "github.com/Yamashou/gqlgenc/introspection" + "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/validator" + "golang.org/x/xerrors" + "gopkg.in/yaml.v2" +) + +type Config struct { + Model config.PackageConfig `yaml:"model,omitempty"` + Client config.PackageConfig `yaml:"client,omitempty"` + Models config.TypeMap `yaml:"models,omitempty"` + Endpoint EndPointConfig `yaml:"endpoint"` + Query []string `yaml:"query"` + + // gqlgen config struct + GQLConfig *config.Config `yaml:"-"` +} + +type EndPointConfig struct { + URL string `yaml:"url"` + Headers map[string]string `yaml:"headers,omitempty"` +} + +func findCfg(fileName string) (string, error) { + dir, err := os.Getwd() + if err != nil { + return "", xerrors.Errorf("unable to get working dir to findCfg: %w", err) + } + + cfg := findCfgInDir(dir, fileName) + + if cfg == "" { + return "", os.ErrNotExist + } + + return cfg, nil +} + +func findCfgInDir(dir, fileName string) string { + path := filepath.Join(dir, fileName) + + return path +} + +func LoadConfig(filename string) (*Config, error) { + var cfg Config + file, err := findCfg(filename) + if err != nil { + return nil, xerrors.Errorf("unable to get file path: %w", err) + } + b, err := ioutil.ReadFile(file) + if err != nil { + return nil, xerrors.Errorf("unable to read config: %w", err) + } + + confContent := []byte(os.ExpandEnv(string(b))) + if err := yaml.UnmarshalStrict(confContent, &cfg); err != nil { + return nil, xerrors.Errorf("unable to parse config: %w", err) + } + + cfg.GQLConfig = &config.Config{ + Model: cfg.Model, + Models: cfg.Models, + // TODO: gqlgen must be set exec but client not used + Exec: config.PackageConfig{Filename: "generated.go"}, + Directives: map[string]config.DirectiveConfig{}, + } + + if err := cfg.Client.Check(); err != nil { + return nil, xerrors.Errorf("config.exec: %w", err) + } + + return &cfg, nil +} + +func (c *Config) LoadSchema(ctx context.Context) error { + addHeader := func(req *http.Request) { + for key, value := range c.Endpoint.Headers { + req.Header.Set(key, value) + } + } + gqlclient := client.NewClient(http.DefaultClient, c.Endpoint.URL, addHeader) + schema, err := LoadRemoteSchema(ctx, gqlclient) + if err != nil { + return xerrors.Errorf("load remote schema failed: %w", err) + } + if schema.Query == nil { + schema.Query = &ast.Definition{ + Kind: ast.Object, + Name: "Query", + } + schema.Types["Query"] = schema.Query + } + + c.GQLConfig.Schema = schema + + return nil +} + +func LoadRemoteSchema(ctx context.Context, gqlclient *client.Client) (*ast.Schema, error) { + var res introspection.Query + if err := gqlclient.Post(ctx, introspection.Introspection, &res, nil); err != nil { + return nil, xerrors.Errorf("introspection query failed: %w", err) + } + + schema, err := validator.ValidateSchemaDocument(introspection.ParseIntrospectionQuery(res)) + if err != nil { + return nil, xerrors.Errorf("validation error: %w", err) + } + + return schema, nil +} diff --git a/vendor/github.com/Yamashou/gqlgenc/generator/generater.go b/vendor/github.com/Yamashou/gqlgenc/generator/generater.go new file mode 100644 index 000000000..075b54b12 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/generator/generater.go @@ -0,0 +1,40 @@ +package generator + +import ( + "context" + + "github.com/99designs/gqlgen/api" + "github.com/99designs/gqlgen/plugin" + "github.com/99designs/gqlgen/plugin/modelgen" + "github.com/Yamashou/gqlgenc/config" + "golang.org/x/xerrors" +) + +func Generate(ctx context.Context, cfg *config.Config, option ...api.Option) error { + var plugins []plugin.Plugin + if cfg.Model.IsDefined() { + plugins = append(plugins, modelgen.New()) + } + for _, o := range option { + o(cfg.GQLConfig, &plugins) + } + + if err := cfg.LoadSchema(ctx); err != nil { + return xerrors.Errorf("failed to load schema: %w\n", err) + } + + if err := cfg.GQLConfig.Init(); err != nil { + return xerrors.Errorf("generating core failed: %w\n", err) + } + + for _, p := range plugins { + if mut, ok := p.(plugin.ConfigMutator); ok { + err := mut.MutateConfig(cfg.GQLConfig) + if err != nil { + return xerrors.Errorf("%s failed: %w\n", p.Name(), err) + } + } + } + + return nil +} diff --git a/vendor/github.com/Yamashou/gqlgenc/go.mod b/vendor/github.com/Yamashou/gqlgenc/go.mod new file mode 100644 index 000000000..7b4208f7d --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/go.mod @@ -0,0 +1,14 @@ +module github.com/Yamashou/gqlgenc + +go 1.14 + +require ( + github.com/99designs/gqlgen v0.12.2 + github.com/agnivade/levenshtein v1.1.0 // indirect + github.com/google/go-cmp v0.5.2 + github.com/pkg/errors v0.9.1 // indirect + github.com/vektah/gqlparser/v2 v2.0.1 + golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 + gopkg.in/yaml.v2 v2.3.0 +) diff --git a/vendor/github.com/Yamashou/gqlgenc/go.sum b/vendor/github.com/Yamashou/gqlgenc/go.sum new file mode 100644 index 000000000..966cfd8d7 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/go.sum @@ -0,0 +1,122 @@ +github.com/99designs/gqlgen v0.12.2 h1:aOdpsiCycFtCnAv8CAI1exnKrIDHMqtMzQoXeTziY4o= +github.com/99designs/gqlgen v0.12.2/go.mod h1:7zdGo6ry9u1YBp/qlb2uxSU5Mt2jQKLcBETQiKk+Bxo= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/agnivade/levenshtein v1.0.3 h1:M5ZnqLOoZR8ygVq0FfkXsNOKzMCk0xRiow0R5+5VkQ0= +github.com/agnivade/levenshtein v1.0.3/go.mod h1:4SFRZbbXWLF4MU1T9Qg0pGgH3Pjs+t6ie5efyrwRJXs= +github.com/agnivade/levenshtein v1.1.0 h1:n6qGwyHG61v3ABce1rPVZklEYRT8NFpCMrpZdBUbYGM= +github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= +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/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +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/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c h1:TUuUh0Xgj97tLMNtWtNvI9mIV6isjEb9lBMNv+77IGM= +github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= +github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007 h1:reVOUXwnhsYv/8UqjvhrMOu5CNT9UapHFLbQ2JcXsmg= +github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047 h1:zCoDWFD5nrJJVjbXiDZcVhOBSzKn3o9LgRLLMRNuru8= +github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +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/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +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/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k= +github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e h1:+w0Zm/9gaWpEAyDlU1eKOuk5twTjAjuevXqcJJw8hrg= +github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U= +github.com/vektah/gqlparser v1.3.1 h1:8b0IcD3qZKWJQHSzynbDlrtP3IxVydZ2DZepCGofqfU= +github.com/vektah/gqlparser v1.3.1/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74= +github.com/vektah/gqlparser/v2 v2.0.1 h1:xgl5abVnsd4hkN9rk65OJID9bfcLSMuTaTcZj777q1o= +github.com/vektah/gqlparser/v2 v2.0.1/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= +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= +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-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20190222072716-a9d3bda3a223/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-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/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-20200114235610-7ae403b6b589 h1:rjUrONFu4kLchcZTfp3/96bR8bW8dIa8uz3cR5n0cgM= +golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3 h1:OjYQxZBKJFs+sJbHkvSGIKNMkZXDJQ9JsMpebGhkafI= +golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +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 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= +sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k= diff --git a/vendor/github.com/Yamashou/gqlgenc/graphqljson/graphql.go b/vendor/github.com/Yamashou/gqlgenc/graphqljson/graphql.go new file mode 100644 index 000000000..223176aa7 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/graphqljson/graphql.go @@ -0,0 +1,416 @@ +/* +MIT License + +Copyright (c) 2017 Dmitri Shuralyov + +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 jsonutil provides a function for decoding JSON +// into a GraphQL query data structure. +package graphqljson + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "reflect" + "strings" + + "golang.org/x/xerrors" +) + +// Reference: https://blog.gopheracademy.com/advent-2017/custom-json-unmarshaler-for-graphql-client/ + +// RawJSONError is a json formatted error from a GraphQL server. +type RawJSONError struct { + Response +} + +func (r RawJSONError) Error() string { + return fmt.Sprintf("data: %s, error: %s, extensions: %v", r.Data, r.Errors, r.Extensions) +} + +// Response is a GraphQL layer response from a handler. +type Response struct { + Data json.RawMessage + Errors Errors + Extensions map[string]interface{} +} + +func Unmarshal(r io.Reader, data interface{}) error { + resp := Response{} + decoder := json.NewDecoder(r) + if err := decoder.Decode(&resp); err != nil { + var buf bytes.Buffer + if _, e := io.Copy(&buf, decoder.Buffered()); e != nil { + return xerrors.Errorf(": %w", err) + } + + return xerrors.Errorf("%s", buf.String()) + } + + if len(resp.Errors) > 0 { + return xerrors.Errorf("response error: %w", resp.Errors) + } + + if err := UnmarshalData(resp.Data, data); err != nil { + return xerrors.Errorf("response mapping failed: %w", err) + } + + if resp.Errors != nil { + return RawJSONError{resp} + } + + return nil +} + +// UnmarshalGraphQL parses the JSON-encoded GraphQL response data and stores +// the result in the GraphQL query data structure pointed to by v. +// +// The implementation is created on top of the JSON tokenizer available +// in "encoding/json".Decoder. +func UnmarshalData(data json.RawMessage, v interface{}) error { + d := NewDecoder(bytes.NewBuffer(data)) + if err := d.Decode(v); err != nil { + return xerrors.Errorf(": %w", err) + } + + // TODO: この処理が本当に必要かは今後検討 + tok, err := d.jsonDecoder.Token() + switch err { + case io.EOF: + // Expect to get io.EOF. There shouldn't be any more + // tokens left after we've decoded v successfully. + return nil + case nil: + return xerrors.Errorf("invalid token '%v' after top-level value", tok) + } + + return xerrors.Errorf("invalid token '%v' after top-level value", tok) +} + +// decoder is a JSON decoder that performs custom unmarshaling behavior +// for GraphQL query data structures. It's implemented on top of a JSON tokenizer. +type Decoder struct { + jsonDecoder *json.Decoder + + // Stack of what part of input JSON we're in the middle of - objects, arrays. + parseState []json.Delim + + // Stacks of values where to unmarshal. + // The top of each stack is the reflect.Value where to unmarshal next JSON value. + // + // The reason there's more than one stack is because we might be unmarshaling + // a single JSON value into multiple GraphQL fragments or embedded structs, so + // we keep track of them all. + vs [][]reflect.Value +} + +func NewDecoder(r io.Reader) *Decoder { + jsonDecoder := json.NewDecoder(r) + jsonDecoder.UseNumber() + + return &Decoder{ + jsonDecoder: jsonDecoder, + } +} + +// Decode decodes a single JSON value from d.tokenizer into v. +func (d *Decoder) Decode(v interface{}) error { + rv := reflect.ValueOf(v) + if rv.Kind() != reflect.Ptr { + return xerrors.Errorf("cannot decode into non-pointer %T", v) + } + + d.vs = [][]reflect.Value{{rv.Elem()}} + if err := d.decode(); err != nil { + return xerrors.Errorf(": %w", err) + } + + return nil +} + +// decode decodes a single JSON value from d.tokenizer into d.vs. +func (d *Decoder) decode() error { + // The loop invariant is that the top of each d.vs stack + // is where we try to unmarshal the next JSON value we see. + for len(d.vs) > 0 { + tok, err := d.jsonDecoder.Token() + if err == io.EOF { + return xerrors.New("unexpected end of JSON input") + } else if err != nil { + return xerrors.Errorf(": %w", err) + } + + switch { + // Are we inside an object and seeing next key (rather than end of object)? + case d.state() == '{' && tok != json.Delim('}'): + key, ok := tok.(string) + if !ok { + return xerrors.New("unexpected non-key in JSON input") + } + + someFieldExist := false + for i := range d.vs { + v := d.vs[i][len(d.vs[i])-1] + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + var f reflect.Value + if v.Kind() == reflect.Struct { + f = fieldByGraphQLName(v, key) + if f.IsValid() { + someFieldExist = true + } + } + d.vs[i] = append(d.vs[i], f) + } + if !someFieldExist { + return xerrors.Errorf("struct field for %q doesn't exist in any of %v places to unmarshal", key, len(d.vs)) + } + + // We've just consumed the current token, which was the key. + // Read the next token, which should be the value, and let the rest of code process it. + tok, err = d.jsonDecoder.Token() + if err == io.EOF { + return xerrors.New("unexpected end of JSON input") + } else if err != nil { + return xerrors.Errorf(": %w", err) + } + + // Are we inside an array and seeing next value (rather than end of array)? + case d.state() == '[' && tok != json.Delim(']'): + someSliceExist := false + for i := range d.vs { + v := d.vs[i][len(d.vs[i])-1] + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + var f reflect.Value + if v.Kind() == reflect.Slice { + v.Set(reflect.Append(v, reflect.Zero(v.Type().Elem()))) // v = append(v, T). + f = v.Index(v.Len() - 1) + someSliceExist = true + } + d.vs[i] = append(d.vs[i], f) + } + if !someSliceExist { + return xerrors.Errorf("slice doesn't exist in any of %v places to unmarshal", len(d.vs)) + } + } + + switch tok := tok.(type) { + case string, json.Number, bool, nil: + // Value. + + for i := range d.vs { + v := d.vs[i][len(d.vs[i])-1] + if !v.IsValid() { + continue + } + err := unmarshalValue(tok, v) + if err != nil { + return xerrors.Errorf(": %w", err) + } + } + d.popAllVs() + + case json.Delim: + switch tok { + case '{': + // Start of object. + + d.pushState(tok) + + frontier := make([]reflect.Value, len(d.vs)) // Places to look for GraphQL fragments/embedded structs. + for i := range d.vs { + v := d.vs[i][len(d.vs[i])-1] + frontier[i] = v + // TODO: Do this recursively or not? Add a test case if needed. + if v.Kind() == reflect.Ptr && v.IsNil() { + v.Set(reflect.New(v.Type().Elem())) // v = new(T). + } + } + // Find GraphQL fragments/embedded structs recursively, adding to frontier + // as new ones are discovered and exploring them further. + for len(frontier) > 0 { + v := frontier[0] + frontier = frontier[1:] + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + if v.Kind() != reflect.Struct { + continue + } + for i := 0; i < v.NumField(); i++ { + if isGraphQLFragment(v.Type().Field(i)) || v.Type().Field(i).Anonymous { + // Add GraphQL fragment or embedded struct. + d.vs = append(d.vs, []reflect.Value{v.Field(i)}) + frontier = append(frontier, v.Field(i)) + } + } + } + case '[': + // Start of array. + + d.pushState(tok) + + for i := range d.vs { + v := d.vs[i][len(d.vs[i])-1] + // TODO: Confirm this is needed, write a test case. + // if v.Kind() == reflect.Ptr && v.IsNil() { + // v.Set(reflect.New(v.Type().Elem())) // v = new(T). + //} + + // Reset slice to empty (in case it had non-zero initial value). + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + if v.Kind() != reflect.Slice { + continue + } + v.Set(reflect.MakeSlice(v.Type(), 0, 0)) // v = make(T, 0, 0). + } + case '}', ']': + // End of object or array. + d.popAllVs() + d.popState() + default: + return xerrors.New("unexpected delimiter in JSON input") + } + default: + return xerrors.New("unexpected token in JSON input") + } + } + + return nil +} + +// pushState pushes a new parse state s onto the stack. +func (d *Decoder) pushState(s json.Delim) { + d.parseState = append(d.parseState, s) +} + +// popState pops a parse state (already obtained) off the stack. +// The stack must be non-empty. +func (d *Decoder) popState() { + d.parseState = d.parseState[:len(d.parseState)-1] +} + +// state reports the parse state on top of stack, or 0 if empty. +func (d *Decoder) state() json.Delim { + if len(d.parseState) == 0 { + return 0 + } + + return d.parseState[len(d.parseState)-1] +} + +// popAllVs pops from all d.vs stacks, keeping only non-empty ones. +func (d *Decoder) popAllVs() { + var nonEmpty [][]reflect.Value + for i := range d.vs { + d.vs[i] = d.vs[i][:len(d.vs[i])-1] + if len(d.vs[i]) > 0 { + nonEmpty = append(nonEmpty, d.vs[i]) + } + } + d.vs = nonEmpty +} + +// fieldByGraphQLName returns an exported struct field of struct v +// that matches GraphQL name, or invalid reflect.Value if none found. +func fieldByGraphQLName(v reflect.Value, name string) reflect.Value { + for i := 0; i < v.NumField(); i++ { + if v.Type().Field(i).PkgPath != "" { + // Skip unexported field. + continue + } + if hasGraphQLName(v.Type().Field(i), name) { + return v.Field(i) + } + } + + return reflect.Value{} +} + +// hasGraphQLName reports whether struct field f has GraphQL name. +func hasGraphQLName(f reflect.StructField, name string) bool { + value, ok := f.Tag.Lookup("graphql") + if !ok { + // TODO: caseconv package is relatively slow. Optimize it, then consider using it here. + // return caseconv.MixedCapsToLowerCamelCase(f.Name) == name + return strings.EqualFold(f.Name, name) + } + value = strings.TrimSpace(value) // TODO: Parse better. + if strings.HasPrefix(value, "...") { + // GraphQL fragment. It doesn't have a name. + return false + } + if i := strings.Index(value, "("); i != -1 { + value = value[:i] + } + if i := strings.Index(value, ":"); i != -1 { + value = value[:i] + } + + return strings.TrimSpace(value) == name +} + +// isGraphQLFragment reports whether struct field f is a GraphQL fragment. +func isGraphQLFragment(f reflect.StructField) bool { + value, ok := f.Tag.Lookup("graphql") + if !ok { + return false + } + value = strings.TrimSpace(value) // TODO: Parse better. + + return strings.HasPrefix(value, "...") +} + +// unmarshalValue unmarshals JSON value into v. +// v must be addressable and not obtained by the use of unexported +// struct fields, otherwise unmarshalValue will panic. +func unmarshalValue(value json.Token, v reflect.Value) error { + b, err := json.Marshal(value) // TODO: Short-circuit (if profiling says it's worth it). + if err != nil { + return xerrors.Errorf(": %w", err) + } + + return json.Unmarshal(b, v.Addr().Interface()) +} + +// Errors represents the "Errors" array in a response from a GraphQL server. +// If returned via error interface, the slice is expected to contain at least 1 element. +// +// Specification: https://facebook.github.io/graphql/#sec-Errors. +type Errors []struct { + Message string + Locations []struct { + Line int + Column int + } +} + +// Error implements error interface. +func (e Errors) Error() string { + return e[0].Message +} diff --git a/vendor/github.com/Yamashou/gqlgenc/introspection/parse.go b/vendor/github.com/Yamashou/gqlgenc/introspection/parse.go new file mode 100644 index 000000000..8ffb4649d --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/introspection/parse.go @@ -0,0 +1,289 @@ +package introspection + +import ( + "fmt" + + "github.com/vektah/gqlparser/v2/ast" +) + +func ParseIntrospectionQuery(query Query) *ast.SchemaDocument { + var doc ast.SchemaDocument + typeMap := query.Schema.Types.NameMap() + + doc.Schema = append(doc.Schema, parseSchemaDefinition(query, typeMap)) + + for _, typeVale := range typeMap { + doc.Definitions = append(doc.Definitions, parseTypeSystemDefinition(typeVale)) + } + + for _, directiveValue := range query.Schema.Directives { + doc.Directives = append(doc.Directives, parseDirectiveDefinition(directiveValue)) + } + + return &doc +} + +func parseSchemaDefinition(query Query, typeMap map[string]*FullType) *ast.SchemaDefinition { + def := ast.SchemaDefinition{} + + def.OperationTypes = append(def.OperationTypes, + parseOperationTypeDefinitionForQuery(typeMap[*query.Schema.QueryType.Name]), + parseOperationTypeDefinitionForMutation(typeMap[*query.Schema.MutationType.Name]), + ) + + return &def +} + +func parseOperationTypeDefinitionForQuery(fullType *FullType) *ast.OperationTypeDefinition { + var op ast.OperationTypeDefinition + op.Operation = ast.Query + op.Type = *fullType.Name + + return &op +} + +func parseOperationTypeDefinitionForMutation(fullType *FullType) *ast.OperationTypeDefinition { + var op ast.OperationTypeDefinition + op.Operation = ast.Mutation + op.Type = *fullType.Name + + return &op +} + +func parseDirectiveDefinition(directiveValue *DirectiveType) *ast.DirectiveDefinition { + args := make(ast.ArgumentDefinitionList, 0, len(directiveValue.Args)) + for _, arg := range directiveValue.Args { + argumentDefinition := buildInputValue(arg) + args = append(args, argumentDefinition) + } + locations := make([]ast.DirectiveLocation, 0, len(directiveValue.Locations)) + for _, locationValue := range directiveValue.Locations { + locations = append(locations, ast.DirectiveLocation(locationValue)) + } + + return &ast.DirectiveDefinition{ + Description: pointerString(directiveValue.Description), + Name: directiveValue.Name, + Arguments: args, + Locations: locations, + } +} + +func parseObjectFields(typeVale *FullType) ast.FieldList { + fieldList := make(ast.FieldList, 0, len(typeVale.Fields)) + for _, field := range typeVale.Fields { + typ := getType(&field.Type) + args := make(ast.ArgumentDefinitionList, 0, len(field.Args)) + for _, arg := range field.Args { + argumentDefinition := buildInputValue(arg) + args = append(args, argumentDefinition) + } + + fieldDefinition := &ast.FieldDefinition{ + Description: pointerString(field.Description), + Name: field.Name, + Arguments: args, + Type: typ, + } + fieldList = append(fieldList, fieldDefinition) + } + + return fieldList +} + +func parseInputObjectFields(typeVale *FullType) ast.FieldList { + fieldList := make(ast.FieldList, 0, len(typeVale.InputFields)) + for _, field := range typeVale.InputFields { + typ := getType(&field.Type) + fieldDefinition := &ast.FieldDefinition{ + Description: pointerString(field.Description), + Name: field.Name, + Type: typ, + } + fieldList = append(fieldList, fieldDefinition) + } + + return fieldList +} + +func parseObjectTypeDefinition(typeVale *FullType) *ast.Definition { + fieldList := parseObjectFields(typeVale) + interfaces := make([]string, 0, len(typeVale.Interfaces)) + for _, intf := range typeVale.Interfaces { + interfaces = append(interfaces, pointerString(intf.Name)) + } + + enums := make(ast.EnumValueList, 0, len(typeVale.EnumValues)) + for _, enum := range typeVale.EnumValues { + enumValue := &ast.EnumValueDefinition{ + Description: pointerString(enum.Description), + Name: enum.Name, + } + enums = append(enums, enumValue) + } + + return &ast.Definition{ + Kind: ast.Object, + Description: pointerString(typeVale.Description), + Name: pointerString(typeVale.Name), + Interfaces: interfaces, + Fields: fieldList, + EnumValues: enums, + Position: nil, + BuiltIn: true, + } +} + +func parseInterfaceTypeDefinition(typeVale *FullType) *ast.Definition { + fieldList := parseObjectFields(typeVale) + interfaces := make([]string, 0, len(typeVale.Interfaces)) + for _, intf := range typeVale.Interfaces { + interfaces = append(interfaces, pointerString(intf.Name)) + } + + return &ast.Definition{ + Kind: ast.Interface, + Description: pointerString(typeVale.Description), + Name: pointerString(typeVale.Name), + Interfaces: interfaces, + Fields: fieldList, + Position: nil, + BuiltIn: true, + } +} + +func parseInputObjectTypeDefinition(typeVale *FullType) *ast.Definition { + fieldList := parseInputObjectFields(typeVale) + interfaces := make([]string, 0, len(typeVale.Interfaces)) + for _, intf := range typeVale.Interfaces { + interfaces = append(interfaces, pointerString(intf.Name)) + } + + return &ast.Definition{ + Kind: ast.InputObject, + Description: pointerString(typeVale.Description), + Name: pointerString(typeVale.Name), + Interfaces: interfaces, + Fields: fieldList, + Position: nil, + BuiltIn: true, + } +} + +func parseUnionTypeDefinition(typeVale *FullType) *ast.Definition { + unions := make([]string, 0, len(typeVale.PossibleTypes)) + for _, unionValue := range typeVale.PossibleTypes { + unions = append(unions, *unionValue.Name) + } + + return &ast.Definition{ + Kind: ast.Union, + Description: pointerString(typeVale.Description), + Name: pointerString(typeVale.Name), + Types: unions, + Position: nil, + BuiltIn: true, + } +} + +func parseEnumTypeDefinition(typeVale *FullType) *ast.Definition { + enums := make(ast.EnumValueList, 0, len(typeVale.EnumValues)) + for _, enum := range typeVale.EnumValues { + enumValue := &ast.EnumValueDefinition{ + Description: pointerString(enum.Description), + Name: enum.Name, + } + enums = append(enums, enumValue) + } + + return &ast.Definition{ + Kind: ast.Enum, + Description: pointerString(typeVale.Description), + Name: pointerString(typeVale.Name), + EnumValues: enums, + Position: nil, + BuiltIn: true, + } +} + +func parseScalarTypeExtension(typeVale *FullType) *ast.Definition { + return &ast.Definition{ + Kind: ast.Scalar, + Description: pointerString(typeVale.Description), + Name: pointerString(typeVale.Name), + Position: nil, + BuiltIn: true, + } +} + +func parseTypeSystemDefinition(typeVale *FullType) *ast.Definition { + switch typeVale.Kind { + case TypeKindScalar: + return parseScalarTypeExtension(typeVale) + case TypeKindInterface: + return parseInterfaceTypeDefinition(typeVale) + case TypeKindEnum: + return parseEnumTypeDefinition(typeVale) + case TypeKindUnion: + return parseUnionTypeDefinition(typeVale) + case TypeKindObject: + return parseObjectTypeDefinition(typeVale) + case TypeKindInputObject: + return parseInputObjectTypeDefinition(typeVale) + case TypeKindList, TypeKindNonNull: + panic(fmt.Sprintf("not match Kind: %s", typeVale.Kind)) + } + + panic(fmt.Sprintf("not match Kind: %s", typeVale.Kind)) +} + +func pointerString(s *string) string { + if s == nil { + return "" + } + + return *s +} + +func buildInputValue(input *InputValue) *ast.ArgumentDefinition { + typ := getType(&input.Type) + + var defaultValue *ast.Value + if input.DefaultValue != nil { + defaultValue = &ast.Value{ + Raw: pointerString(input.DefaultValue), + Kind: ast.Variable, + } + } + + return &ast.ArgumentDefinition{ + Description: pointerString(input.Description), + Name: input.Name, + DefaultValue: defaultValue, + Type: typ, + } +} + +func getType(typeRef *TypeRef) *ast.Type { + if typeRef.Kind == TypeKindList { + itemRef := typeRef.OfType + if itemRef == nil { + panic("Decorated type deeper than introspection query.") + } + + return ast.ListType(getType(itemRef), nil) + } + + if typeRef.Kind == TypeKindNonNull { + nullableRef := typeRef.OfType + if nullableRef == nil { + panic("Decorated type deeper than introspection query.") + } + nullableType := getType(nullableRef) + nullableType.NonNull = true + + return nullableType + } + + return ast.NamedType(pointerString(typeRef.Name), nil) +} diff --git a/vendor/github.com/Yamashou/gqlgenc/introspection/query.go b/vendor/github.com/Yamashou/gqlgenc/introspection/query.go new file mode 100644 index 000000000..7bd126ac2 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/introspection/query.go @@ -0,0 +1,93 @@ +package introspection + +const Introspection = `query Query { + __schema { + queryType { name } + mutationType { name } + subscriptionType { name } + types { + ...FullType + } + directives { + name + description + locations + args { + ...InputValue + } + } + } + } + + fragment FullType on __Type { + kind + name + description + fields(includeDeprecated: true) { + name + description + args { + ...InputValue + } + type { + ...TypeRef + } + isDeprecated + deprecationReason + } + inputFields { + ...InputValue + } + interfaces { + ...TypeRef + } + enumValues(includeDeprecated: true) { + name + description + isDeprecated + deprecationReason + } + possibleTypes { + ...TypeRef + } + } + + fragment InputValue on __InputValue { + name + description + type { ...TypeRef } + defaultValue + } + + fragment TypeRef on __Type { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + ofType { + kind + name + } + } + } + } + } + } + } + }` diff --git a/vendor/github.com/Yamashou/gqlgenc/introspection/type.go b/vendor/github.com/Yamashou/gqlgenc/introspection/type.go new file mode 100644 index 000000000..789f72bf7 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/introspection/type.go @@ -0,0 +1,80 @@ +package introspection + +type TypeKind string + +const ( + TypeKindScalar TypeKind = "SCALAR" + TypeKindObject TypeKind = "OBJECT" + TypeKindInterface TypeKind = "INTERFACE" + TypeKindUnion TypeKind = "UNION" + TypeKindEnum TypeKind = "ENUM" + TypeKindInputObject TypeKind = "INPUT_OBJECT" + TypeKindList TypeKind = "LIST" + TypeKindNonNull TypeKind = "NON_NULL" +) + +type FullTypes []*FullType + +func (fs FullTypes) NameMap() map[string]*FullType { + typeMap := make(map[string]*FullType) + for _, typ := range fs { + typeMap[*typ.Name] = typ + } + + return typeMap +} + +type FullType struct { + Kind TypeKind + Name *string + Description *string + Fields []*FieldValue + InputFields []*InputValue + Interfaces []*TypeRef + EnumValues []*struct { + Name string + Description *string + IsDeprecated bool + DeprecationReason *string + } + PossibleTypes []*TypeRef +} + +type FieldValue struct { + Name string + Description *string + Args []*InputValue + Type TypeRef + IsDeprecated bool + DeprecationReason *string +} + +type InputValue struct { + Name string + Description *string + Type TypeRef + DefaultValue *string +} + +type TypeRef struct { + Kind TypeKind + Name *string + OfType *TypeRef +} + +type Query struct { + Schema struct { + QueryType struct{ Name *string } + MutationType *struct{ Name *string } + SubscriptionType *struct{ Name *string } + Types FullTypes + Directives []*DirectiveType + } `graphql:"__schema"` +} + +type DirectiveType struct { + Name string + Description *string + Locations []string + Args []*InputValue +} diff --git a/vendor/github.com/Yamashou/gqlgenc/main.go b/vendor/github.com/Yamashou/gqlgenc/main.go new file mode 100644 index 000000000..26747b167 --- /dev/null +++ b/vendor/github.com/Yamashou/gqlgenc/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "context" + "fmt" + "os" + + "github.com/99designs/gqlgen/api" + "github.com/Yamashou/gqlgenc/clientgen" + "github.com/Yamashou/gqlgenc/config" + "github.com/Yamashou/gqlgenc/generator" +) + +func main() { + ctx := context.Background() + cfg, err := config.LoadConfig(".gqlgenc.yml") + if err != nil { + fmt.Fprintf(os.Stderr, "%+v", err.Error()) + os.Exit(2) + } + + clientPlugin := clientgen.New(cfg.Query, cfg.Client) + if err := generator.Generate(ctx, cfg, api.AddPlugin(clientPlugin)); err != nil { + fmt.Fprintf(os.Stderr, "%+v", err.Error()) + os.Exit(4) + } +} diff --git a/vendor/github.com/agnivade/levenshtein/.travis.yml b/vendor/github.com/agnivade/levenshtein/.travis.yml index f830ec4ec..8ea828ed9 100644 --- a/vendor/github.com/agnivade/levenshtein/.travis.yml +++ b/vendor/github.com/agnivade/levenshtein/.travis.yml @@ -1,7 +1,23 @@ language: go +# See https://travis-ci.community/t/goos-js-goarch-wasm-go-run-fails-panic-newosproc-not-implemented/1651 +#addons: +# chrome: stable + +before_install: +- export GO111MODULE=on + +#install: +#- go get github.com/agnivade/wasmbrowsertest +#- mv $GOPATH/bin/wasmbrowsertest $GOPATH/bin/go_js_wasm_exec +#- export PATH=$GOPATH/bin:$PATH + go: -- 1.9.x -- 1.10.x - 1.11.x +- 1.12.x +- 1.13.x - tip + +script: +#- GOOS=js GOARCH=wasm go test -v +- go test -v diff --git a/vendor/github.com/agnivade/levenshtein/Makefile b/vendor/github.com/agnivade/levenshtein/Makefile index 4bef27dd1..5f6890d61 100644 --- a/vendor/github.com/agnivade/levenshtein/Makefile +++ b/vendor/github.com/agnivade/levenshtein/Makefile @@ -4,10 +4,12 @@ install: go install lint: - gofmt -l -s -w . && go tool vet -all . && golint + gofmt -l -s -w . && go vet . && golint -set_exit_status=1 . -test: - go test -race -v -coverprofile=coverage.txt -covermode=atomic +test: # The first 2 go gets are to support older Go versions + go get github.com/arbovm/levenshtein + go get github.com/dgryski/trifles/leven + GO111MODULE=on go test -race -v -coverprofile=coverage.txt -covermode=atomic bench: - go test -run=XXX -bench=. -benchmem + go test -run=XXX -bench=. -benchmem -count=5 diff --git a/vendor/github.com/agnivade/levenshtein/README.md b/vendor/github.com/agnivade/levenshtein/README.md index b0fd81df7..6c56689f7 100644 --- a/vendor/github.com/agnivade/levenshtein/README.md +++ b/vendor/github.com/agnivade/levenshtein/README.md @@ -6,6 +6,10 @@ levenshtein [![Build Status](https://travis-ci.org/agnivade/levenshtein.svg?bran The library is fully capable of working with non-ascii strings. But the strings are not normalized. That is left as a user-dependant use case. Please normalize the strings before passing it to the library if you have such a requirement. - https://blog.golang.org/normalization +#### Limitation + +As a performance optimization, the library can handle strings only up to 65536 characters (runes). This is only available on tip, and is not part of a tagged release yet. If you require such an optimization, please use the version at tip. + Install ------- @@ -38,10 +42,10 @@ Benchmarks ``` name time/op -Simple/ASCII-4 537ns ± 2% -Simple/French-4 956ns ± 0% -Simple/Nordic-4 1.95µs ± 1% -Simple/Tibetan-4 1.53µs ± 2% +Simple/ASCII-4 330ns ± 2% +Simple/French-4 617ns ± 2% +Simple/Nordic-4 1.16µs ± 4% +Simple/Tibetan-4 1.05µs ± 1% name alloc/op Simple/ASCII-4 96.0B ± 0% @@ -55,3 +59,22 @@ Simple/French-4 1.00 ± 0% Simple/Nordic-4 1.00 ± 0% Simple/Tibetan-4 1.00 ± 0% ``` + +Comparisons with other libraries +-------------------------------- + +``` +name time/op +Leven/ASCII/agniva-4 353ns ± 1% +Leven/ASCII/arbovm-4 485ns ± 1% +Leven/ASCII/dgryski-4 395ns ± 0% +Leven/French/agniva-4 648ns ± 1% +Leven/French/arbovm-4 791ns ± 0% +Leven/French/dgryski-4 682ns ± 0% +Leven/Nordic/agniva-4 1.28µs ± 1% +Leven/Nordic/arbovm-4 1.52µs ± 1% +Leven/Nordic/dgryski-4 1.32µs ± 1% +Leven/Tibetan/agniva-4 1.12µs ± 1% +Leven/Tibetan/arbovm-4 1.31µs ± 0% +Leven/Tibetan/dgryski-4 1.16µs ± 0% +``` diff --git a/vendor/github.com/agnivade/levenshtein/go.mod b/vendor/github.com/agnivade/levenshtein/go.mod index b2921fb35..4fcfe43e0 100644 --- a/vendor/github.com/agnivade/levenshtein/go.mod +++ b/vendor/github.com/agnivade/levenshtein/go.mod @@ -1 +1,8 @@ module github.com/agnivade/levenshtein + +go 1.13 + +require ( + github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 + github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 +) diff --git a/vendor/github.com/agnivade/levenshtein/go.sum b/vendor/github.com/agnivade/levenshtein/go.sum new file mode 100644 index 000000000..74d92aad1 --- /dev/null +++ b/vendor/github.com/agnivade/levenshtein/go.sum @@ -0,0 +1,4 @@ +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= diff --git a/vendor/github.com/agnivade/levenshtein/levenshtein.go b/vendor/github.com/agnivade/levenshtein/levenshtein.go index 6b08acade..5aecdb592 100644 --- a/vendor/github.com/agnivade/levenshtein/levenshtein.go +++ b/vendor/github.com/agnivade/levenshtein/levenshtein.go @@ -25,12 +25,10 @@ func ComputeDistance(a, b string) int { return 0 } - // We need to convert to []rune if the strings are non-ascii. + // We need to convert to []rune if the strings are non-ASCII. // This could be avoided by using utf8.RuneCountInString - // and then doing some juggling with rune indices. - // The primary challenge is keeping track of the previous rune. - // With a range loop, its not that easy. And with a for-loop - // we need to keep track of the inter-rune width using utf8.DecodeRuneInString + // and then doing some juggling with rune indices, + // but leads to far more bounds checks. It is a reasonable trade-off. s1 := []rune(a) s2 := []rune(b) @@ -42,21 +40,21 @@ func ComputeDistance(a, b string) int { lenS2 := len(s2) // init the row - x := make([]int, lenS1+1) - for i := 0; i <= lenS1; i++ { - x[i] = i + x := make([]uint16, lenS1+1) + // we start from 1 because index 0 is already 0. + for i := 1; i < len(x); i++ { + x[i] = uint16(i) } + // make a dummy bounds check to prevent the 2 bounds check down below. + // The one inside the loop is particularly costly. + _ = x[lenS1] // fill in the rest for i := 1; i <= lenS2; i++ { - prev := i - var current int - + prev := uint16(i) for j := 1; j <= lenS1; j++ { - - if s2[i-1] == s1[j-1] { - current = x[j-1] // match - } else { + current := x[j-1] // match + if s2[i-1] != s1[j-1] { current = min(min(x[j-1]+1, prev+1), x[j]+1) } x[j-1] = prev @@ -64,10 +62,10 @@ func ComputeDistance(a, b string) int { } x[lenS1] = prev } - return x[lenS1] + return int(x[lenS1]) } -func min(a, b int) int { +func min(a, b uint16) uint16 { if a < b { return a } diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md b/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md new file mode 100644 index 000000000..1cade6cef --- /dev/null +++ b/vendor/github.com/cpuguy83/go-md2man/v2/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Brian Goff + +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/cpuguy83/go-md2man/v2/md2man/md2man.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go new file mode 100644 index 000000000..b48005673 --- /dev/null +++ b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/md2man.go @@ -0,0 +1,14 @@ +package md2man + +import ( + "github.com/russross/blackfriday/v2" +) + +// Render converts a markdown document into a roff formatted document. +func Render(doc []byte) []byte { + renderer := NewRoffRenderer() + + return blackfriday.Run(doc, + []blackfriday.Option{blackfriday.WithRenderer(renderer), + blackfriday.WithExtensions(renderer.GetExtensions())}...) +} diff --git a/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go new file mode 100644 index 000000000..0668a66cf --- /dev/null +++ b/vendor/github.com/cpuguy83/go-md2man/v2/md2man/roff.go @@ -0,0 +1,345 @@ +package md2man + +import ( + "fmt" + "io" + "os" + "strings" + + "github.com/russross/blackfriday/v2" +) + +// roffRenderer implements the blackfriday.Renderer interface for creating +// roff format (manpages) from markdown text +type roffRenderer struct { + extensions blackfriday.Extensions + listCounters []int + firstHeader bool + defineTerm bool + listDepth int +} + +const ( + titleHeader = ".TH " + topLevelHeader = "\n\n.SH " + secondLevelHdr = "\n.SH " + otherHeader = "\n.SS " + crTag = "\n" + emphTag = "\\fI" + emphCloseTag = "\\fP" + strongTag = "\\fB" + strongCloseTag = "\\fP" + breakTag = "\n.br\n" + paraTag = "\n.PP\n" + hruleTag = "\n.ti 0\n\\l'\\n(.lu'\n" + linkTag = "\n\\[la]" + linkCloseTag = "\\[ra]" + codespanTag = "\\fB\\fC" + codespanCloseTag = "\\fR" + codeTag = "\n.PP\n.RS\n\n.nf\n" + codeCloseTag = "\n.fi\n.RE\n" + quoteTag = "\n.PP\n.RS\n" + quoteCloseTag = "\n.RE\n" + listTag = "\n.RS\n" + listCloseTag = "\n.RE\n" + arglistTag = "\n.TP\n" + tableStart = "\n.TS\nallbox;\n" + tableEnd = ".TE\n" + tableCellStart = "T{\n" + tableCellEnd = "\nT}\n" +) + +// NewRoffRenderer creates a new blackfriday Renderer for generating roff documents +// from markdown +func NewRoffRenderer() *roffRenderer { // nolint: golint + var extensions blackfriday.Extensions + + extensions |= blackfriday.NoIntraEmphasis + extensions |= blackfriday.Tables + extensions |= blackfriday.FencedCode + extensions |= blackfriday.SpaceHeadings + extensions |= blackfriday.Footnotes + extensions |= blackfriday.Titleblock + extensions |= blackfriday.DefinitionLists + return &roffRenderer{ + extensions: extensions, + } +} + +// GetExtensions returns the list of extensions used by this renderer implementation +func (r *roffRenderer) GetExtensions() blackfriday.Extensions { + return r.extensions +} + +// RenderHeader handles outputting the header at document start +func (r *roffRenderer) RenderHeader(w io.Writer, ast *blackfriday.Node) { + // disable hyphenation + out(w, ".nh\n") +} + +// RenderFooter handles outputting the footer at the document end; the roff +// renderer has no footer information +func (r *roffRenderer) RenderFooter(w io.Writer, ast *blackfriday.Node) { +} + +// RenderNode is called for each node in a markdown document; based on the node +// type the equivalent roff output is sent to the writer +func (r *roffRenderer) RenderNode(w io.Writer, node *blackfriday.Node, entering bool) blackfriday.WalkStatus { + + var walkAction = blackfriday.GoToNext + + switch node.Type { + case blackfriday.Text: + r.handleText(w, node, entering) + case blackfriday.Softbreak: + out(w, crTag) + case blackfriday.Hardbreak: + out(w, breakTag) + case blackfriday.Emph: + if entering { + out(w, emphTag) + } else { + out(w, emphCloseTag) + } + case blackfriday.Strong: + if entering { + out(w, strongTag) + } else { + out(w, strongCloseTag) + } + case blackfriday.Link: + if !entering { + out(w, linkTag+string(node.LinkData.Destination)+linkCloseTag) + } + case blackfriday.Image: + // ignore images + walkAction = blackfriday.SkipChildren + case blackfriday.Code: + out(w, codespanTag) + escapeSpecialChars(w, node.Literal) + out(w, codespanCloseTag) + case blackfriday.Document: + break + case blackfriday.Paragraph: + // roff .PP markers break lists + if r.listDepth > 0 { + return blackfriday.GoToNext + } + if entering { + out(w, paraTag) + } else { + out(w, crTag) + } + case blackfriday.BlockQuote: + if entering { + out(w, quoteTag) + } else { + out(w, quoteCloseTag) + } + case blackfriday.Heading: + r.handleHeading(w, node, entering) + case blackfriday.HorizontalRule: + out(w, hruleTag) + case blackfriday.List: + r.handleList(w, node, entering) + case blackfriday.Item: + r.handleItem(w, node, entering) + case blackfriday.CodeBlock: + out(w, codeTag) + escapeSpecialChars(w, node.Literal) + out(w, codeCloseTag) + case blackfriday.Table: + r.handleTable(w, node, entering) + case blackfriday.TableCell: + r.handleTableCell(w, node, entering) + case blackfriday.TableHead: + case blackfriday.TableBody: + case blackfriday.TableRow: + // no action as cell entries do all the nroff formatting + return blackfriday.GoToNext + default: + fmt.Fprintln(os.Stderr, "WARNING: go-md2man does not handle node type "+node.Type.String()) + } + return walkAction +} + +func (r *roffRenderer) handleText(w io.Writer, node *blackfriday.Node, entering bool) { + var ( + start, end string + ) + // handle special roff table cell text encapsulation + if node.Parent.Type == blackfriday.TableCell { + if len(node.Literal) > 30 { + start = tableCellStart + end = tableCellEnd + } else { + // end rows that aren't terminated by "tableCellEnd" with a cr if end of row + if node.Parent.Next == nil && !node.Parent.IsHeader { + end = crTag + } + } + } + out(w, start) + escapeSpecialChars(w, node.Literal) + out(w, end) +} + +func (r *roffRenderer) handleHeading(w io.Writer, node *blackfriday.Node, entering bool) { + if entering { + switch node.Level { + case 1: + if !r.firstHeader { + out(w, titleHeader) + r.firstHeader = true + break + } + out(w, topLevelHeader) + case 2: + out(w, secondLevelHdr) + default: + out(w, otherHeader) + } + } +} + +func (r *roffRenderer) handleList(w io.Writer, node *blackfriday.Node, entering bool) { + openTag := listTag + closeTag := listCloseTag + if node.ListFlags&blackfriday.ListTypeDefinition != 0 { + // tags for definition lists handled within Item node + openTag = "" + closeTag = "" + } + if entering { + r.listDepth++ + if node.ListFlags&blackfriday.ListTypeOrdered != 0 { + r.listCounters = append(r.listCounters, 1) + } + out(w, openTag) + } else { + if node.ListFlags&blackfriday.ListTypeOrdered != 0 { + r.listCounters = r.listCounters[:len(r.listCounters)-1] + } + out(w, closeTag) + r.listDepth-- + } +} + +func (r *roffRenderer) handleItem(w io.Writer, node *blackfriday.Node, entering bool) { + if entering { + if node.ListFlags&blackfriday.ListTypeOrdered != 0 { + out(w, fmt.Sprintf(".IP \"%3d.\" 5\n", r.listCounters[len(r.listCounters)-1])) + r.listCounters[len(r.listCounters)-1]++ + } else if node.ListFlags&blackfriday.ListTypeDefinition != 0 { + // state machine for handling terms and following definitions + // since blackfriday does not distinguish them properly, nor + // does it seperate them into separate lists as it should + if !r.defineTerm { + out(w, arglistTag) + r.defineTerm = true + } else { + r.defineTerm = false + } + } else { + out(w, ".IP \\(bu 2\n") + } + } else { + out(w, "\n") + } +} + +func (r *roffRenderer) handleTable(w io.Writer, node *blackfriday.Node, entering bool) { + if entering { + out(w, tableStart) + //call walker to count cells (and rows?) so format section can be produced + columns := countColumns(node) + out(w, strings.Repeat("l ", columns)+"\n") + out(w, strings.Repeat("l ", columns)+".\n") + } else { + out(w, tableEnd) + } +} + +func (r *roffRenderer) handleTableCell(w io.Writer, node *blackfriday.Node, entering bool) { + var ( + start, end string + ) + if node.IsHeader { + start = codespanTag + end = codespanCloseTag + } + if entering { + if node.Prev != nil && node.Prev.Type == blackfriday.TableCell { + out(w, "\t"+start) + } else { + out(w, start) + } + } else { + // need to carriage return if we are at the end of the header row + if node.IsHeader && node.Next == nil { + end = end + crTag + } + out(w, end) + } +} + +// because roff format requires knowing the column count before outputting any table +// data we need to walk a table tree and count the columns +func countColumns(node *blackfriday.Node) int { + var columns int + + node.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus { + switch node.Type { + case blackfriday.TableRow: + if !entering { + return blackfriday.Terminate + } + case blackfriday.TableCell: + if entering { + columns++ + } + default: + } + return blackfriday.GoToNext + }) + return columns +} + +func out(w io.Writer, output string) { + io.WriteString(w, output) // nolint: errcheck +} + +func needsBackslash(c byte) bool { + for _, r := range []byte("-_&\\~") { + if c == r { + return true + } + } + return false +} + +func escapeSpecialChars(w io.Writer, text []byte) { + for i := 0; i < len(text); i++ { + // escape initial apostrophe or period + if len(text) >= 1 && (text[0] == '\'' || text[0] == '.') { + out(w, "\\&") + } + + // directly copy normal characters + org := i + + for i < len(text) && !needsBackslash(text[i]) { + i++ + } + if i > org { + w.Write(text[org:i]) // nolint: errcheck + } + + // escape a character + if i >= len(text) { + break + } + + w.Write([]byte{'\\', text[i]}) // nolint: errcheck + } +} diff --git a/vendor/github.com/matryer/moq/.gitignore b/vendor/github.com/matryer/moq/.gitignore new file mode 100644 index 000000000..b15784e0c --- /dev/null +++ b/vendor/github.com/matryer/moq/.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 +*.test +*.prof +.vscode diff --git a/vendor/github.com/matryer/moq/.travis.yml b/vendor/github.com/matryer/moq/.travis.yml new file mode 100644 index 000000000..1bcf6df60 --- /dev/null +++ b/vendor/github.com/matryer/moq/.travis.yml @@ -0,0 +1,23 @@ +language: go + +sudo: false + +branches: + only: + - master + +go: + - 1.11.x + - 1.12.x + - 1.13.x + - tip + +before_install: + - go get golang.org/x/lint/golint + +before_script: + - go vet ./... + - golint ./... + +script: + - go test -v ./... diff --git a/vendor/github.com/matryer/moq/LICENSE b/vendor/github.com/matryer/moq/LICENSE new file mode 100644 index 000000000..157d9d25d --- /dev/null +++ b/vendor/github.com/matryer/moq/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Mat Ryer and David Hernandez + +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/matryer/moq/README.md b/vendor/github.com/matryer/moq/README.md new file mode 100644 index 000000000..5327c44e9 --- /dev/null +++ b/vendor/github.com/matryer/moq/README.md @@ -0,0 +1,110 @@ +![moq logo](moq-logo-small.png) [![Build Status](https://travis-ci.org/matryer/moq.svg?branch=master)](https://travis-ci.org/matryer/moq) [![Go Report Card](https://goreportcard.com/badge/github.com/matryer/moq)](https://goreportcard.com/report/github.com/matryer/moq) + +Interface mocking tool for go generate. + +By [Mat Ryer](https://twitter.com/matryer) and [David Hernandez](https://github.com/dahernan), with ideas lovingly stolen from [Ernesto Jimenez](https://github.com/ernesto-jimenez). + +### What is Moq? + +Moq is a tool that generates a struct from any interface. The struct can be used in test code as a mock of the interface. + +![Preview](preview.png) + +above: Moq generates the code on the right. + +You can read more in the [Meet Moq blog post](http://bit.ly/meetmoq). + +### Installing + +To start using Moq, just run go get: +``` +$ go get github.com/matryer/moq +``` + +### Usage + +``` +moq [flags] destination interface [interface2 [interface3 [...]]] + -out string + output file (default stdout) + -pkg string + package name (default will infer) +Specifying an alias for the mock is also supported with the format 'interface:alias' +Ex: moq -pkg different . MyInterface:MyMock +``` + +In a command line: + +``` +$ moq -out mocks_test.go . MyInterface +``` + +In code (for go generate): + +```go +package my + +//go:generate moq -out myinterface_moq_test.go . MyInterface + +type MyInterface interface { + Method1() error + Method2(i int) +} +``` + +Then run `go generate` for your package. + +### How to use it + +Mocking interfaces is a nice way to write unit tests where you can easily control the behaviour of the mocked object. + +Moq creates a struct that has a function field for each method, which you can declare in your test code. + +In this example, Moq generated the `EmailSenderMock` type: + +```go +func TestCompleteSignup(t *testing.T) { + + var sentTo string + + mockedEmailSender = &EmailSenderMock{ + SendFunc: func(to, subject, body string) error { + sentTo = to + return nil + }, + } + + CompleteSignUp("me@email.com", mockedEmailSender) + + callsToSend := len(mockedEmailSender.SendCalls()) + if callsToSend != 1 { + t.Errorf("Send was called %d times", callsToSend) + } + if sentTo != "me@email.com" { + t.Errorf("unexpected recipient: %s", sentTo) + } + +} + +func CompleteSignUp(to string, sender EmailSender) { + // TODO: this +} +``` + +The mocked structure implements the interface, where each method calls the associated function field. + +## Tips + +* Keep mocked logic inside the test that is using it +* Only mock the fields you need +* It will panic if a nil function gets called +* Name arguments in the interface for a better experience +* Use closured variables inside your test function to capture details about the calls to the methods +* Use `.MethodCalls()` to track the calls +* Use `go:generate` to invoke the `moq` command + +## License + +The Moq project (and all code) is licensed under the [MIT License](LICENSE). + +The Moq logo was created by [Chris Ryer](http://chrisryer.co.uk) and is licensed under the [Creative Commons Attribution 3.0 License](https://creativecommons.org/licenses/by/3.0/). diff --git a/vendor/github.com/matryer/moq/main.go b/vendor/github.com/matryer/moq/main.go new file mode 100644 index 000000000..cd246cc8f --- /dev/null +++ b/vendor/github.com/matryer/moq/main.go @@ -0,0 +1,77 @@ +package main + +import ( + "bytes" + "errors" + "flag" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + + "github.com/matryer/moq/pkg/moq" +) + +type userFlags struct { + outFile string + pkgName string + args []string +} + +func main() { + var flags userFlags + flag.StringVar(&flags.outFile, "out", "", "output file (default stdout)") + flag.StringVar(&flags.pkgName, "pkg", "", "package name (default will infer)") + + flag.Usage = func() { + fmt.Println(`moq [flags] destination interface [interface2 [interface3 [...]]]`) + flag.PrintDefaults() + fmt.Println(`Specifying an alias for the mock is also supported with the format 'interface:alias'`) + fmt.Println(`Ex: moq -pkg different . MyInterface:MyMock`) + } + + flag.Parse() + flags.args = flag.Args() + + if err := run(flags); err != nil { + fmt.Fprintln(os.Stderr, err) + flag.Usage() + os.Exit(1) + } +} + +func run(flags userFlags) error { + if len(flags.args) < 2 { + return errors.New("not enough arguments") + } + + var buf bytes.Buffer + var out io.Writer = os.Stdout + if flags.outFile != "" { + out = &buf + } + + destination := flags.args[0] + args := flags.args[1:] + m, err := moq.New(destination, flags.pkgName) + if err != nil { + return err + } + + if err = m.Mock(out, args...); err != nil { + return err + } + + if flags.outFile == "" { + return nil + } + + // create the file + err = os.MkdirAll(filepath.Dir(flags.outFile), 0755) + if err != nil { + return err + } + + return ioutil.WriteFile(flags.outFile, buf.Bytes(), 0644) +} diff --git a/vendor/github.com/matryer/moq/moq-logo-small.png b/vendor/github.com/matryer/moq/moq-logo-small.png new file mode 100644 index 000000000..7a71c177e Binary files /dev/null and b/vendor/github.com/matryer/moq/moq-logo-small.png differ diff --git a/vendor/github.com/matryer/moq/moq-logo.png b/vendor/github.com/matryer/moq/moq-logo.png new file mode 100644 index 000000000..7eae08f6f Binary files /dev/null and b/vendor/github.com/matryer/moq/moq-logo.png differ diff --git a/vendor/github.com/matryer/moq/pkg/moq/moq.go b/vendor/github.com/matryer/moq/pkg/moq/moq.go new file mode 100644 index 000000000..971c9421e --- /dev/null +++ b/vendor/github.com/matryer/moq/pkg/moq/moq.go @@ -0,0 +1,372 @@ +package moq + +import ( + "bytes" + "errors" + "fmt" + "go/format" + "go/types" + "io" + "os" + "path" + "path/filepath" + "strings" + "text/template" + + "golang.org/x/tools/go/packages" +) + +// This list comes from the golint codebase. Golint will complain about any of +// these being mixed-case, like "Id" instead of "ID". +var golintInitialisms = []string{ + "ACL", + "API", + "ASCII", + "CPU", + "CSS", + "DNS", + "EOF", + "GUID", + "HTML", + "HTTP", + "HTTPS", + "ID", + "IP", + "JSON", + "LHS", + "QPS", + "RAM", + "RHS", + "RPC", + "SLA", + "SMTP", + "SQL", + "SSH", + "TCP", + "TLS", + "TTL", + "UDP", + "UI", + "UID", + "UUID", + "URI", + "URL", + "UTF8", + "VM", + "XML", + "XMPP", + "XSRF", + "XSS", +} + +// Mocker can generate mock structs. +type Mocker struct { + srcPkg *packages.Package + tmpl *template.Template + pkgName string + pkgPath string + + imports map[string]bool +} + +// New makes a new Mocker for the specified package directory. +func New(src, packageName string) (*Mocker, error) { + srcPkg, err := pkgInfoFromPath(src, packages.LoadSyntax) + if err != nil { + return nil, fmt.Errorf("couldn't load source package: %s", err) + } + pkgPath, err := findPkgPath(packageName, srcPkg) + if err != nil { + return nil, fmt.Errorf("couldn't load mock package: %s", err) + } + + tmpl, err := template.New("moq").Funcs(templateFuncs).Parse(moqTemplate) + if err != nil { + return nil, err + } + return &Mocker{ + tmpl: tmpl, + srcPkg: srcPkg, + pkgName: preventZeroStr(packageName, srcPkg.Name), + pkgPath: pkgPath, + imports: make(map[string]bool), + }, nil +} + +func preventZeroStr(val, defaultVal string) string { + if val == "" { + return defaultVal + } + return val +} + +func findPkgPath(pkgInputVal string, srcPkg *packages.Package) (string, error) { + if pkgInputVal == "" { + return srcPkg.PkgPath, nil + } + if pkgInDir(".", pkgInputVal) { + return ".", nil + } + if pkgInDir(srcPkg.PkgPath, pkgInputVal) { + return srcPkg.PkgPath, nil + } + subdirectoryPath := filepath.Join(srcPkg.PkgPath, pkgInputVal) + if pkgInDir(subdirectoryPath, pkgInputVal) { + return subdirectoryPath, nil + } + return "", nil +} + +func pkgInDir(pkgName, dir string) bool { + currentPkg, err := pkgInfoFromPath(dir, packages.LoadFiles) + if err != nil { + return false + } + return currentPkg.Name == pkgName || currentPkg.Name+"_test" == pkgName +} + +// Mock generates a mock for the specified interface name. +func (m *Mocker) Mock(w io.Writer, names ...string) error { + if len(names) == 0 { + return errors.New("must specify one interface") + } + + doc := doc{ + PackageName: m.pkgName, + Imports: moqImports, + } + + mocksMethods := false + + tpkg := m.srcPkg.Types + for _, name := range names { + n, mockName := parseInterfaceName(name) + iface := tpkg.Scope().Lookup(n) + if iface == nil { + return fmt.Errorf("cannot find interface %s", n) + } + if !types.IsInterface(iface.Type()) { + return fmt.Errorf("%s (%s) not an interface", n, iface.Type().String()) + } + iiface := iface.Type().Underlying().(*types.Interface).Complete() + obj := obj{ + InterfaceName: n, + MockName: mockName, + } + for i := 0; i < iiface.NumMethods(); i++ { + mocksMethods = true + meth := iiface.Method(i) + sig := meth.Type().(*types.Signature) + method := &method{ + Name: meth.Name(), + } + obj.Methods = append(obj.Methods, method) + method.Params = m.extractArgs(sig, sig.Params(), "in%d") + method.Returns = m.extractArgs(sig, sig.Results(), "out%d") + } + doc.Objects = append(doc.Objects, obj) + } + + if mocksMethods { + doc.Imports = append(doc.Imports, "sync") + } + + for pkgToImport := range m.imports { + doc.Imports = append(doc.Imports, stripVendorPath(pkgToImport)) + } + + if tpkg.Name() != m.pkgName { + doc.SourcePackagePrefix = tpkg.Name() + "." + doc.Imports = append(doc.Imports, tpkg.Path()) + } + + var buf bytes.Buffer + err := m.tmpl.Execute(&buf, doc) + if err != nil { + return err + } + formatted, err := format.Source(buf.Bytes()) + if err != nil { + return fmt.Errorf("go/format: %s", err) + } + if _, err := w.Write(formatted); err != nil { + return err + } + return nil +} + +func (m *Mocker) packageQualifier(pkg *types.Package) string { + if m.pkgPath != "" && m.pkgPath == pkg.Path() { + return "" + } + path := pkg.Path() + if pkg.Path() == "." { + wd, err := os.Getwd() + if err == nil { + path = stripGopath(wd) + } + } + m.imports[path] = true + return pkg.Name() +} + +func (m *Mocker) extractArgs(sig *types.Signature, list *types.Tuple, nameFormat string) []*param { + var params []*param + listLen := list.Len() + for ii := 0; ii < listLen; ii++ { + p := list.At(ii) + name := p.Name() + if name == "" { + name = fmt.Sprintf(nameFormat, ii+1) + } + typename := types.TypeString(p.Type(), m.packageQualifier) + // check for final variadic argument + variadic := sig.Variadic() && ii == listLen-1 && typename[0:2] == "[]" + param := ¶m{ + Name: name, + Type: typename, + Variadic: variadic, + } + params = append(params, param) + } + return params +} + +func pkgInfoFromPath(src string, mode packages.LoadMode) (*packages.Package, error) { + conf := packages.Config{ + Mode: mode, + Dir: src, + } + pkgs, err := packages.Load(&conf) + if err != nil { + return nil, err + } + if len(pkgs) == 0 { + return nil, errors.New("No packages found") + } + if len(pkgs) > 1 { + return nil, errors.New("More than one package was found") + } + return pkgs[0], nil +} + +func parseInterfaceName(name string) (ifaceName, mockName string) { + parts := strings.SplitN(name, ":", 2) + ifaceName = parts[0] + mockName = ifaceName + "Mock" + if len(parts) == 2 { + mockName = parts[1] + } + return +} + +type doc struct { + PackageName string + SourcePackagePrefix string + Objects []obj + Imports []string +} + +type obj struct { + InterfaceName string + MockName string + Methods []*method +} +type method struct { + Name string + Params []*param + Returns []*param +} + +func (m *method) Arglist() string { + params := make([]string, len(m.Params)) + for i, p := range m.Params { + params[i] = p.String() + } + return strings.Join(params, ", ") +} + +func (m *method) ArgCallList() string { + params := make([]string, len(m.Params)) + for i, p := range m.Params { + params[i] = p.CallName() + } + return strings.Join(params, ", ") +} + +func (m *method) ReturnArglist() string { + params := make([]string, len(m.Returns)) + for i, p := range m.Returns { + params[i] = p.TypeString() + } + if len(m.Returns) > 1 { + return fmt.Sprintf("(%s)", strings.Join(params, ", ")) + } + return strings.Join(params, ", ") +} + +type param struct { + Name string + Type string + Variadic bool +} + +func (p param) String() string { + return fmt.Sprintf("%s %s", p.Name, p.TypeString()) +} + +func (p param) CallName() string { + if p.Variadic { + return p.Name + "..." + } + return p.Name +} + +func (p param) TypeString() string { + if p.Variadic { + return "..." + p.Type[2:] + } + return p.Type +} + +var templateFuncs = template.FuncMap{ + "Exported": func(s string) string { + if s == "" { + return "" + } + for _, initialism := range golintInitialisms { + if strings.ToUpper(s) == initialism { + return initialism + } + } + return strings.ToUpper(s[0:1]) + s[1:] + }, +} + +// stripVendorPath strips the vendor dir prefix from a package path. +// For example we might encounter an absolute path like +// github.com/foo/bar/vendor/github.com/pkg/errors which is resolved +// to github.com/pkg/errors. +func stripVendorPath(p string) string { + parts := strings.Split(p, "/vendor/") + if len(parts) == 1 { + return p + } + return strings.TrimLeft(path.Join(parts[1:]...), "/") +} + +// stripGopath takes the directory to a package and remove the gopath to get the +// canonical package name. +// +// taken from https://github.com/ernesto-jimenez/gogen +// Copyright (c) 2015 Ernesto Jiménez +func stripGopath(p string) string { + for _, gopath := range gopaths() { + p = strings.TrimPrefix(p, path.Join(gopath, "src")+"/") + } + return p +} + +func gopaths() []string { + return strings.Split(os.Getenv("GOPATH"), string(filepath.ListSeparator)) +} diff --git a/vendor/github.com/matryer/moq/pkg/moq/template.go b/vendor/github.com/matryer/moq/pkg/moq/template.go new file mode 100644 index 000000000..bc33de236 --- /dev/null +++ b/vendor/github.com/matryer/moq/pkg/moq/template.go @@ -0,0 +1,107 @@ +package moq + +// moqImports are the imports all moq files get. +var moqImports = []string{} + +// moqTemplate is the template for mocked code. +var moqTemplate = `// Code generated by moq; DO NOT EDIT. +// github.com/matryer/moq + +package {{.PackageName}} +{{- $sourcePackagePrefix := .SourcePackagePrefix}} + +import ( +{{- range .Imports }} + "{{.}}" +{{- end }} +) + +{{ range $i, $obj := .Objects -}} +var ( +{{- range .Methods }} + lock{{$obj.MockName}}{{.Name}} sync.RWMutex +{{- end }} +) + +// Ensure, that {{.MockName}} does implement {{$sourcePackagePrefix}}{{.InterfaceName}}. +// If this is not the case, regenerate this file with moq. +var _ {{$sourcePackagePrefix}}{{.InterfaceName}} = &{{.MockName}}{} + +// {{.MockName}} is a mock implementation of {{$sourcePackagePrefix}}{{.InterfaceName}}. +// +// func TestSomethingThatUses{{.InterfaceName}}(t *testing.T) { +// +// // make and configure a mocked {{$sourcePackagePrefix}}{{.InterfaceName}} +// mocked{{.InterfaceName}} := &{{.MockName}}{ {{ range .Methods }} +// {{.Name}}Func: func({{ .Arglist }}) {{.ReturnArglist}} { +// panic("mock out the {{.Name}} method") +// },{{- end }} +// } +// +// // use mocked{{.InterfaceName}} in code that requires {{$sourcePackagePrefix}}{{.InterfaceName}} +// // and then make assertions. +// +// } +type {{.MockName}} struct { +{{- range .Methods }} + // {{.Name}}Func mocks the {{.Name}} method. + {{.Name}}Func func({{ .Arglist }}) {{.ReturnArglist}} +{{ end }} + // calls tracks calls to the methods. + calls struct { +{{- range .Methods }} + // {{ .Name }} holds details about calls to the {{.Name}} method. + {{ .Name }} []struct { + {{- range .Params }} + // {{ .Name | Exported }} is the {{ .Name }} argument value. + {{ .Name | Exported }} {{ .Type }} + {{- end }} + } +{{- end }} + } +} +{{ range .Methods }} +// {{.Name}} calls {{.Name}}Func. +func (mock *{{$obj.MockName}}) {{.Name}}({{.Arglist}}) {{.ReturnArglist}} { + if mock.{{.Name}}Func == nil { + panic("{{$obj.MockName}}.{{.Name}}Func: method is nil but {{$obj.InterfaceName}}.{{.Name}} was just called") + } + callInfo := struct { + {{- range .Params }} + {{ .Name | Exported }} {{ .Type }} + {{- end }} + }{ + {{- range .Params }} + {{ .Name | Exported }}: {{ .Name }}, + {{- end }} + } + lock{{$obj.MockName}}{{.Name}}.Lock() + mock.calls.{{.Name}} = append(mock.calls.{{.Name}}, callInfo) + lock{{$obj.MockName}}{{.Name}}.Unlock() +{{- if .ReturnArglist }} + return mock.{{.Name}}Func({{.ArgCallList}}) +{{- else }} + mock.{{.Name}}Func({{.ArgCallList}}) +{{- end }} +} + +// {{.Name}}Calls gets all the calls that were made to {{.Name}}. +// Check the length with: +// len(mocked{{$obj.InterfaceName}}.{{.Name}}Calls()) +func (mock *{{$obj.MockName}}) {{.Name}}Calls() []struct { + {{- range .Params }} + {{ .Name | Exported }} {{ .Type }} + {{- end }} + } { + var calls []struct { + {{- range .Params }} + {{ .Name | Exported }} {{ .Type }} + {{- end }} + } + lock{{$obj.MockName}}{{.Name}}.RLock() + calls = mock.calls.{{.Name}} + lock{{$obj.MockName}}{{.Name}}.RUnlock() + return calls +} +{{ end -}} +{{ end -}}` diff --git a/vendor/github.com/matryer/moq/preview.png b/vendor/github.com/matryer/moq/preview.png new file mode 100644 index 000000000..8fa7a6274 Binary files /dev/null and b/vendor/github.com/matryer/moq/preview.png differ diff --git a/vendor/github.com/pkg/errors/.travis.yml b/vendor/github.com/pkg/errors/.travis.yml index d4b92663b..9159de03e 100644 --- a/vendor/github.com/pkg/errors/.travis.yml +++ b/vendor/github.com/pkg/errors/.travis.yml @@ -1,15 +1,10 @@ language: go go_import_path: github.com/pkg/errors go: - - 1.4.x - - 1.5.x - - 1.6.x - - 1.7.x - - 1.8.x - - 1.9.x - - 1.10.x - 1.11.x + - 1.12.x + - 1.13.x - tip script: - - go test -v ./... + - make check diff --git a/vendor/github.com/pkg/errors/Makefile b/vendor/github.com/pkg/errors/Makefile new file mode 100644 index 000000000..ce9d7cded --- /dev/null +++ b/vendor/github.com/pkg/errors/Makefile @@ -0,0 +1,44 @@ +PKGS := github.com/pkg/errors +SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS)) +GO := go + +check: test vet gofmt misspell unconvert staticcheck ineffassign unparam + +test: + $(GO) test $(PKGS) + +vet: | test + $(GO) vet $(PKGS) + +staticcheck: + $(GO) get honnef.co/go/tools/cmd/staticcheck + staticcheck -checks all $(PKGS) + +misspell: + $(GO) get github.com/client9/misspell/cmd/misspell + misspell \ + -locale GB \ + -error \ + *.md *.go + +unconvert: + $(GO) get github.com/mdempsky/unconvert + unconvert -v $(PKGS) + +ineffassign: + $(GO) get github.com/gordonklaus/ineffassign + find $(SRCDIRS) -name '*.go' | xargs ineffassign + +pedantic: check errcheck + +unparam: + $(GO) get mvdan.cc/unparam + unparam ./... + +errcheck: + $(GO) get github.com/kisielk/errcheck + errcheck $(PKGS) + +gofmt: + @echo Checking code is gofmted + @test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)" diff --git a/vendor/github.com/pkg/errors/README.md b/vendor/github.com/pkg/errors/README.md index 6483ba2af..54dfdcb12 100644 --- a/vendor/github.com/pkg/errors/README.md +++ b/vendor/github.com/pkg/errors/README.md @@ -41,11 +41,18 @@ default: [Read the package documentation for more information](https://godoc.org/github.com/pkg/errors). +## Roadmap + +With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows: + +- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible) +- 1.0. Final release. + ## Contributing -We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high. +Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports. -Before proposing a change, please discuss your change by raising an issue. +Before sending a PR, please discuss your change by raising an issue. ## License diff --git a/vendor/github.com/pkg/errors/errors.go b/vendor/github.com/pkg/errors/errors.go index 7421f326f..161aea258 100644 --- a/vendor/github.com/pkg/errors/errors.go +++ b/vendor/github.com/pkg/errors/errors.go @@ -82,7 +82,7 @@ // // if err, ok := err.(stackTracer); ok { // for _, f := range err.StackTrace() { -// fmt.Printf("%+s:%d", f) +// fmt.Printf("%+s:%d\n", f, f) // } // } // @@ -159,6 +159,9 @@ type withStack struct { func (w *withStack) Cause() error { return w.error } +// Unwrap provides compatibility for Go 1.13 error chains. +func (w *withStack) Unwrap() error { return w.error } + func (w *withStack) Format(s fmt.State, verb rune) { switch verb { case 'v': @@ -241,6 +244,9 @@ type withMessage struct { func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } func (w *withMessage) Cause() error { return w.cause } +// Unwrap provides compatibility for Go 1.13 error chains. +func (w *withMessage) Unwrap() error { return w.cause } + func (w *withMessage) Format(s fmt.State, verb rune) { switch verb { case 'v': diff --git a/vendor/github.com/pkg/errors/go113.go b/vendor/github.com/pkg/errors/go113.go new file mode 100644 index 000000000..be0d10d0c --- /dev/null +++ b/vendor/github.com/pkg/errors/go113.go @@ -0,0 +1,38 @@ +// +build go1.13 + +package errors + +import ( + stderrors "errors" +) + +// Is reports whether any error in err's chain matches target. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error is considered to match a target if it is equal to that target or if +// it implements a method Is(error) bool such that Is(target) returns true. +func Is(err, target error) bool { return stderrors.Is(err, target) } + +// As finds the first error in err's chain that matches target, and if so, sets +// target to that error value and returns true. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error matches target if the error's concrete value is assignable to the value +// pointed to by target, or if the error has a method As(interface{}) bool such that +// As(target) returns true. In the latter case, the As method is responsible for +// setting target. +// +// As will panic if target is not a non-nil pointer to either a type that implements +// error, or to any interface type. As returns false if err is nil. +func As(err error, target interface{}) bool { return stderrors.As(err, target) } + +// Unwrap returns the result of calling the Unwrap method on err, if err's +// type contains an Unwrap method returning error. +// Otherwise, Unwrap returns nil. +func Unwrap(err error) error { + return stderrors.Unwrap(err) +} diff --git a/vendor/github.com/pkg/errors/stack.go b/vendor/github.com/pkg/errors/stack.go index 2874a048c..779a8348f 100644 --- a/vendor/github.com/pkg/errors/stack.go +++ b/vendor/github.com/pkg/errors/stack.go @@ -5,10 +5,13 @@ import ( "io" "path" "runtime" + "strconv" "strings" ) // Frame represents a program counter inside a stack frame. +// For historical reasons if Frame is interpreted as a uintptr +// its value represents the program counter + 1. type Frame uintptr // pc returns the program counter for this frame; @@ -37,6 +40,15 @@ func (f Frame) line() int { return line } +// name returns the name of this function, if known. +func (f Frame) name() string { + fn := runtime.FuncForPC(f.pc()) + if fn == nil { + return "unknown" + } + return fn.Name() +} + // Format formats the frame according to the fmt.Formatter interface. // // %s source file @@ -54,22 +66,16 @@ func (f Frame) Format(s fmt.State, verb rune) { case 's': switch { case s.Flag('+'): - pc := f.pc() - fn := runtime.FuncForPC(pc) - if fn == nil { - io.WriteString(s, "unknown") - } else { - file, _ := fn.FileLine(pc) - fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file) - } + io.WriteString(s, f.name()) + io.WriteString(s, "\n\t") + io.WriteString(s, f.file()) default: io.WriteString(s, path.Base(f.file())) } case 'd': - fmt.Fprintf(s, "%d", f.line()) + io.WriteString(s, strconv.Itoa(f.line())) case 'n': - name := runtime.FuncForPC(f.pc()).Name() - io.WriteString(s, funcname(name)) + io.WriteString(s, funcname(f.name())) case 'v': f.Format(s, 's') io.WriteString(s, ":") @@ -77,6 +83,16 @@ func (f Frame) Format(s fmt.State, verb rune) { } } +// MarshalText formats a stacktrace Frame as a text string. The output is the +// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs. +func (f Frame) MarshalText() ([]byte, error) { + name := f.name() + if name == "unknown" { + return []byte(name), nil + } + return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil +} + // StackTrace is stack of Frames from innermost (newest) to outermost (oldest). type StackTrace []Frame @@ -94,18 +110,32 @@ func (st StackTrace) Format(s fmt.State, verb rune) { switch { case s.Flag('+'): for _, f := range st { - fmt.Fprintf(s, "\n%+v", f) + io.WriteString(s, "\n") + f.Format(s, verb) } case s.Flag('#'): fmt.Fprintf(s, "%#v", []Frame(st)) default: - fmt.Fprintf(s, "%v", []Frame(st)) + st.formatSlice(s, verb) } case 's': - fmt.Fprintf(s, "%s", []Frame(st)) + st.formatSlice(s, verb) } } +// formatSlice will format this StackTrace into the given buffer as a slice of +// Frame, only valid when called with '%s' or '%v'. +func (st StackTrace) formatSlice(s fmt.State, verb rune) { + io.WriteString(s, "[") + for i, f := range st { + if i > 0 { + io.WriteString(s, " ") + } + f.Format(s, verb) + } + io.WriteString(s, "]") +} + // stack represents a stack of program counters. type stack []uintptr diff --git a/vendor/github.com/russross/blackfriday/v2/.gitignore b/vendor/github.com/russross/blackfriday/v2/.gitignore new file mode 100644 index 000000000..75623dccc --- /dev/null +++ b/vendor/github.com/russross/blackfriday/v2/.gitignore @@ -0,0 +1,8 @@ +*.out +*.swp +*.8 +*.6 +_obj +_test* +markdown +tags diff --git a/vendor/github.com/russross/blackfriday/v2/.travis.yml b/vendor/github.com/russross/blackfriday/v2/.travis.yml new file mode 100644 index 000000000..b0b525a5a --- /dev/null +++ b/vendor/github.com/russross/blackfriday/v2/.travis.yml @@ -0,0 +1,17 @@ +sudo: false +language: go +go: + - "1.10.x" + - "1.11.x" + - tip +matrix: + fast_finish: true + allow_failures: + - go: tip +install: + - # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step). +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d -s .) + - go tool vet . + - go test -v ./... diff --git a/vendor/github.com/russross/blackfriday/v2/LICENSE.txt b/vendor/github.com/russross/blackfriday/v2/LICENSE.txt new file mode 100644 index 000000000..2885af360 --- /dev/null +++ b/vendor/github.com/russross/blackfriday/v2/LICENSE.txt @@ -0,0 +1,29 @@ +Blackfriday is distributed under the Simplified BSD License: + +> Copyright © 2011 Russ Ross +> All rights reserved. +> +> 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. +> +> 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/russross/blackfriday/v2/README.md b/vendor/github.com/russross/blackfriday/v2/README.md new file mode 100644 index 000000000..d5a8649bd --- /dev/null +++ b/vendor/github.com/russross/blackfriday/v2/README.md @@ -0,0 +1,291 @@ +Blackfriday [![Build Status](https://travis-ci.org/russross/blackfriday.svg?branch=master)](https://travis-ci.org/russross/blackfriday) +=========== + +Blackfriday is a [Markdown][1] processor implemented in [Go][2]. It +is paranoid about its input (so you can safely feed it user-supplied +data), it is fast, it supports common extensions (tables, smart +punctuation substitutions, etc.), and it is safe for all utf-8 +(unicode) input. + +HTML output is currently supported, along with Smartypants +extensions. + +It started as a translation from C of [Sundown][3]. + + +Installation +------------ + +Blackfriday is compatible with any modern Go release. With Go 1.7 and git +installed: + + go get gopkg.in/russross/blackfriday.v2 + +will download, compile, and install the package into your `$GOPATH` +directory hierarchy. Alternatively, you can achieve the same if you +import it into a project: + + import "gopkg.in/russross/blackfriday.v2" + +and `go get` without parameters. + + +Versions +-------- + +Currently maintained and recommended version of Blackfriday is `v2`. It's being +developed on its own branch: https://github.com/russross/blackfriday/tree/v2 and the +documentation is available at +https://godoc.org/gopkg.in/russross/blackfriday.v2. + +It is `go get`-able via via [gopkg.in][6] at `gopkg.in/russross/blackfriday.v2`, +but we highly recommend using package management tool like [dep][7] or +[Glide][8] and make use of semantic versioning. With package management you +should import `github.com/russross/blackfriday` and specify that you're using +version 2.0.0. + +Version 2 offers a number of improvements over v1: + +* Cleaned up API +* A separate call to [`Parse`][4], which produces an abstract syntax tree for + the document +* Latest bug fixes +* Flexibility to easily add your own rendering extensions + +Potential drawbacks: + +* Our benchmarks show v2 to be slightly slower than v1. Currently in the + ballpark of around 15%. +* API breakage. If you can't afford modifying your code to adhere to the new API + and don't care too much about the new features, v2 is probably not for you. +* Several bug fixes are trailing behind and still need to be forward-ported to + v2. See issue [#348](https://github.com/russross/blackfriday/issues/348) for + tracking. + +Usage +----- + +For the most sensible markdown processing, it is as simple as getting your input +into a byte slice and calling: + +```go +output := blackfriday.Run(input) +``` + +Your input will be parsed and the output rendered with a set of most popular +extensions enabled. If you want the most basic feature set, corresponding with +the bare Markdown specification, use: + +```go +output := blackfriday.Run(input, blackfriday.WithNoExtensions()) +``` + +### Sanitize untrusted content + +Blackfriday itself does nothing to protect against malicious content. If you are +dealing with user-supplied markdown, we recommend running Blackfriday's output +through HTML sanitizer such as [Bluemonday][5]. + +Here's an example of simple usage of Blackfriday together with Bluemonday: + +```go +import ( + "github.com/microcosm-cc/bluemonday" + "github.com/russross/blackfriday" +) + +// ... +unsafe := blackfriday.Run(input) +html := bluemonday.UGCPolicy().SanitizeBytes(unsafe) +``` + +### Custom options + +If you want to customize the set of options, use `blackfriday.WithExtensions`, +`blackfriday.WithRenderer` and `blackfriday.WithRefOverride`. + +You can also check out `blackfriday-tool` for a more complete example +of how to use it. Download and install it using: + + go get github.com/russross/blackfriday-tool + +This is a simple command-line tool that allows you to process a +markdown file using a standalone program. You can also browse the +source directly on github if you are just looking for some example +code: + +* + +Note that if you have not already done so, installing +`blackfriday-tool` will be sufficient to download and install +blackfriday in addition to the tool itself. The tool binary will be +installed in `$GOPATH/bin`. This is a statically-linked binary that +can be copied to wherever you need it without worrying about +dependencies and library versions. + + +Features +-------- + +All features of Sundown are supported, including: + +* **Compatibility**. The Markdown v1.0.3 test suite passes with + the `--tidy` option. Without `--tidy`, the differences are + mostly in whitespace and entity escaping, where blackfriday is + more consistent and cleaner. + +* **Common extensions**, including table support, fenced code + blocks, autolinks, strikethroughs, non-strict emphasis, etc. + +* **Safety**. Blackfriday is paranoid when parsing, making it safe + to feed untrusted user input without fear of bad things + happening. The test suite stress tests this and there are no + known inputs that make it crash. If you find one, please let me + know and send me the input that does it. + + NOTE: "safety" in this context means *runtime safety only*. In order to + protect yourself against JavaScript injection in untrusted content, see + [this example](https://github.com/russross/blackfriday#sanitize-untrusted-content). + +* **Fast processing**. It is fast enough to render on-demand in + most web applications without having to cache the output. + +* **Thread safety**. You can run multiple parsers in different + goroutines without ill effect. There is no dependence on global + shared state. + +* **Minimal dependencies**. Blackfriday only depends on standard + library packages in Go. The source code is pretty + self-contained, so it is easy to add to any project, including + Google App Engine projects. + +* **Standards compliant**. Output successfully validates using the + W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional. + + +Extensions +---------- + +In addition to the standard markdown syntax, this package +implements the following extensions: + +* **Intra-word emphasis supression**. The `_` character is + commonly used inside words when discussing code, so having + markdown interpret it as an emphasis command is usually the + wrong thing. Blackfriday lets you treat all emphasis markers as + normal characters when they occur inside a word. + +* **Tables**. Tables can be created by drawing them in the input + using a simple syntax: + + ``` + Name | Age + --------|------ + Bob | 27 + Alice | 23 + ``` + +* **Fenced code blocks**. In addition to the normal 4-space + indentation to mark code blocks, you can explicitly mark them + and supply a language (to make syntax highlighting simple). Just + mark it like this: + + ```go + func getTrue() bool { + return true + } + ``` + + You can use 3 or more backticks to mark the beginning of the + block, and the same number to mark the end of the block. + +* **Definition lists**. A simple definition list is made of a single-line + term followed by a colon and the definition for that term. + + Cat + : Fluffy animal everyone likes + + Internet + : Vector of transmission for pictures of cats + + Terms must be separated from the previous definition by a blank line. + +* **Footnotes**. A marker in the text that will become a superscript number; + a footnote definition that will be placed in a list of footnotes at the + end of the document. A footnote looks like this: + + This is a footnote.[^1] + + [^1]: the footnote text. + +* **Autolinking**. Blackfriday can find URLs that have not been + explicitly marked as links and turn them into links. + +* **Strikethrough**. Use two tildes (`~~`) to mark text that + should be crossed out. + +* **Hard line breaks**. With this extension enabled newlines in the input + translate into line breaks in the output. This extension is off by default. + +* **Smart quotes**. Smartypants-style punctuation substitution is + supported, turning normal double- and single-quote marks into + curly quotes, etc. + +* **LaTeX-style dash parsing** is an additional option, where `--` + is translated into `–`, and `---` is translated into + `—`. This differs from most smartypants processors, which + turn a single hyphen into an ndash and a double hyphen into an + mdash. + +* **Smart fractions**, where anything that looks like a fraction + is translated into suitable HTML (instead of just a few special + cases like most smartypant processors). For example, `4/5` + becomes `45`, which renders as + 45. + + +Other renderers +--------------- + +Blackfriday is structured to allow alternative rendering engines. Here +are a few of note: + +* [github_flavored_markdown](https://godoc.org/github.com/shurcooL/github_flavored_markdown): + provides a GitHub Flavored Markdown renderer with fenced code block + highlighting, clickable heading anchor links. + + It's not customizable, and its goal is to produce HTML output + equivalent to the [GitHub Markdown API endpoint](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode), + except the rendering is performed locally. + +* [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt, + but for markdown. + +* [LaTeX output](https://github.com/Ambrevar/Blackfriday-LaTeX): + renders output as LaTeX. + +* [Blackfriday-Confluence](https://github.com/kentaro-m/blackfriday-confluence): provides a [Confluence Wiki Markup](https://confluence.atlassian.com/doc/confluence-wiki-markup-251003035.html) renderer. + + +Todo +---- + +* More unit testing +* Improve unicode support. It does not understand all unicode + rules (about what constitutes a letter, a punctuation symbol, + etc.), so it may fail to detect word boundaries correctly in + some instances. It is safe on all utf-8 input. + + +License +------- + +[Blackfriday is distributed under the Simplified BSD License](LICENSE.txt) + + + [1]: https://daringfireball.net/projects/markdown/ "Markdown" + [2]: https://golang.org/ "Go Language" + [3]: https://github.com/vmg/sundown "Sundown" + [4]: https://godoc.org/gopkg.in/russross/blackfriday.v2#Parse "Parse func" + [5]: https://github.com/microcosm-cc/bluemonday "Bluemonday" + [6]: https://labix.org/gopkg.in "gopkg.in" diff --git a/vendor/github.com/russross/blackfriday/v2/block.go b/vendor/github.com/russross/blackfriday/v2/block.go new file mode 100644 index 000000000..b8607474e --- /dev/null +++ b/vendor/github.com/russross/blackfriday/v2/block.go @@ -0,0 +1,1590 @@ +// +// Blackfriday Markdown Processor +// Available at http://github.com/russross/blackfriday +// +// Copyright © 2011 Russ Ross . +// Distributed under the Simplified BSD License. +// See README.md for details. +// + +// +// Functions to parse block-level elements. +// + +package blackfriday + +import ( + "bytes" + "html" + "regexp" + "strings" + + "github.com/shurcooL/sanitized_anchor_name" +) + +const ( + charEntity = "&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});" + escapable = "[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]" +) + +var ( + reBackslashOrAmp = regexp.MustCompile("[\\&]") + reEntityOrEscapedChar = regexp.MustCompile("(?i)\\\\" + escapable + "|" + charEntity) +) + +// Parse block-level data. +// Note: this function and many that it calls assume that +// the input buffer ends with a newline. +func (p *Markdown) block(data []byte) { + // this is called recursively: enforce a maximum depth + if p.nesting >= p.maxNesting { + return + } + p.nesting++ + + // parse out one block-level construct at a time + for len(data) > 0 { + // prefixed heading: + // + // # Heading 1 + // ## Heading 2 + // ... + // ###### Heading 6 + if p.isPrefixHeading(data) { + data = data[p.prefixHeading(data):] + continue + } + + // block of preformatted HTML: + // + //
+ // ... + //
+ if data[0] == '<' { + if i := p.html(data, true); i > 0 { + data = data[i:] + continue + } + } + + // title block + // + // % stuff + // % more stuff + // % even more stuff + if p.extensions&Titleblock != 0 { + if data[0] == '%' { + if i := p.titleBlock(data, true); i > 0 { + data = data[i:] + continue + } + } + } + + // blank lines. note: returns the # of bytes to skip + if i := p.isEmpty(data); i > 0 { + data = data[i:] + continue + } + + // indented code block: + // + // func max(a, b int) int { + // if a > b { + // return a + // } + // return b + // } + if p.codePrefix(data) > 0 { + data = data[p.code(data):] + continue + } + + // fenced code block: + // + // ``` go + // func fact(n int) int { + // if n <= 1 { + // return n + // } + // return n * fact(n-1) + // } + // ``` + if p.extensions&FencedCode != 0 { + if i := p.fencedCodeBlock(data, true); i > 0 { + data = data[i:] + continue + } + } + + // horizontal rule: + // + // ------ + // or + // ****** + // or + // ______ + if p.isHRule(data) { + p.addBlock(HorizontalRule, nil) + var i int + for i = 0; i < len(data) && data[i] != '\n'; i++ { + } + data = data[i:] + continue + } + + // block quote: + // + // > A big quote I found somewhere + // > on the web + if p.quotePrefix(data) > 0 { + data = data[p.quote(data):] + continue + } + + // table: + // + // Name | Age | Phone + // ------|-----|--------- + // Bob | 31 | 555-1234 + // Alice | 27 | 555-4321 + if p.extensions&Tables != 0 { + if i := p.table(data); i > 0 { + data = data[i:] + continue + } + } + + // an itemized/unordered list: + // + // * Item 1 + // * Item 2 + // + // also works with + or - + if p.uliPrefix(data) > 0 { + data = data[p.list(data, 0):] + continue + } + + // a numbered/ordered list: + // + // 1. Item 1 + // 2. Item 2 + if p.oliPrefix(data) > 0 { + data = data[p.list(data, ListTypeOrdered):] + continue + } + + // definition lists: + // + // Term 1 + // : Definition a + // : Definition b + // + // Term 2 + // : Definition c + if p.extensions&DefinitionLists != 0 { + if p.dliPrefix(data) > 0 { + data = data[p.list(data, ListTypeDefinition):] + continue + } + } + + // anything else must look like a normal paragraph + // note: this finds underlined headings, too + data = data[p.paragraph(data):] + } + + p.nesting-- +} + +func (p *Markdown) addBlock(typ NodeType, content []byte) *Node { + p.closeUnmatchedBlocks() + container := p.addChild(typ, 0) + container.content = content + return container +} + +func (p *Markdown) isPrefixHeading(data []byte) bool { + if data[0] != '#' { + return false + } + + if p.extensions&SpaceHeadings != 0 { + level := 0 + for level < 6 && level < len(data) && data[level] == '#' { + level++ + } + if level == len(data) || data[level] != ' ' { + return false + } + } + return true +} + +func (p *Markdown) prefixHeading(data []byte) int { + level := 0 + for level < 6 && level < len(data) && data[level] == '#' { + level++ + } + i := skipChar(data, level, ' ') + end := skipUntilChar(data, i, '\n') + skip := end + id := "" + if p.extensions&HeadingIDs != 0 { + j, k := 0, 0 + // find start/end of heading id + for j = i; j < end-1 && (data[j] != '{' || data[j+1] != '#'); j++ { + } + for k = j + 1; k < end && data[k] != '}'; k++ { + } + // extract heading id iff found + if j < end && k < end { + id = string(data[j+2 : k]) + end = j + skip = k + 1 + for end > 0 && data[end-1] == ' ' { + end-- + } + } + } + for end > 0 && data[end-1] == '#' { + if isBackslashEscaped(data, end-1) { + break + } + end-- + } + for end > 0 && data[end-1] == ' ' { + end-- + } + if end > i { + if id == "" && p.extensions&AutoHeadingIDs != 0 { + id = sanitized_anchor_name.Create(string(data[i:end])) + } + block := p.addBlock(Heading, data[i:end]) + block.HeadingID = id + block.Level = level + } + return skip +} + +func (p *Markdown) isUnderlinedHeading(data []byte) int { + // test of level 1 heading + if data[0] == '=' { + i := skipChar(data, 1, '=') + i = skipChar(data, i, ' ') + if i < len(data) && data[i] == '\n' { + return 1 + } + return 0 + } + + // test of level 2 heading + if data[0] == '-' { + i := skipChar(data, 1, '-') + i = skipChar(data, i, ' ') + if i < len(data) && data[i] == '\n' { + return 2 + } + return 0 + } + + return 0 +} + +func (p *Markdown) titleBlock(data []byte, doRender bool) int { + if data[0] != '%' { + return 0 + } + splitData := bytes.Split(data, []byte("\n")) + var i int + for idx, b := range splitData { + if !bytes.HasPrefix(b, []byte("%")) { + i = idx // - 1 + break + } + } + + data = bytes.Join(splitData[0:i], []byte("\n")) + consumed := len(data) + data = bytes.TrimPrefix(data, []byte("% ")) + data = bytes.Replace(data, []byte("\n% "), []byte("\n"), -1) + block := p.addBlock(Heading, data) + block.Level = 1 + block.IsTitleblock = true + + return consumed +} + +func (p *Markdown) html(data []byte, doRender bool) int { + var i, j int + + // identify the opening tag + if data[0] != '<' { + return 0 + } + curtag, tagfound := p.htmlFindTag(data[1:]) + + // handle special cases + if !tagfound { + // check for an HTML comment + if size := p.htmlComment(data, doRender); size > 0 { + return size + } + + // check for an
tag + if size := p.htmlHr(data, doRender); size > 0 { + return size + } + + // no special case recognized + return 0 + } + + // look for an unindented matching closing tag + // followed by a blank line + found := false + /* + closetag := []byte("\n") + j = len(curtag) + 1 + for !found { + // scan for a closing tag at the beginning of a line + if skip := bytes.Index(data[j:], closetag); skip >= 0 { + j += skip + len(closetag) + } else { + break + } + + // see if it is the only thing on the line + if skip := p.isEmpty(data[j:]); skip > 0 { + // see if it is followed by a blank line/eof + j += skip + if j >= len(data) { + found = true + i = j + } else { + if skip := p.isEmpty(data[j:]); skip > 0 { + j += skip + found = true + i = j + } + } + } + } + */ + + // if not found, try a second pass looking for indented match + // but not if tag is "ins" or "del" (following original Markdown.pl) + if !found && curtag != "ins" && curtag != "del" { + i = 1 + for i < len(data) { + i++ + for i < len(data) && !(data[i-1] == '<' && data[i] == '/') { + i++ + } + + if i+2+len(curtag) >= len(data) { + break + } + + j = p.htmlFindEnd(curtag, data[i-1:]) + + if j > 0 { + i += j - 1 + found = true + break + } + } + } + + if !found { + return 0 + } + + // the end of the block has been found + if doRender { + // trim newlines + end := i + for end > 0 && data[end-1] == '\n' { + end-- + } + finalizeHTMLBlock(p.addBlock(HTMLBlock, data[:end])) + } + + return i +} + +func finalizeHTMLBlock(block *Node) { + block.Literal = block.content + block.content = nil +} + +// HTML comment, lax form +func (p *Markdown) htmlComment(data []byte, doRender bool) int { + i := p.inlineHTMLComment(data) + // needs to end with a blank line + if j := p.isEmpty(data[i:]); j > 0 { + size := i + j + if doRender { + // trim trailing newlines + end := size + for end > 0 && data[end-1] == '\n' { + end-- + } + block := p.addBlock(HTMLBlock, data[:end]) + finalizeHTMLBlock(block) + } + return size + } + return 0 +} + +// HR, which is the only self-closing block tag considered +func (p *Markdown) htmlHr(data []byte, doRender bool) int { + if len(data) < 4 { + return 0 + } + if data[0] != '<' || (data[1] != 'h' && data[1] != 'H') || (data[2] != 'r' && data[2] != 'R') { + return 0 + } + if data[3] != ' ' && data[3] != '/' && data[3] != '>' { + // not an
tag after all; at least not a valid one + return 0 + } + i := 3 + for i < len(data) && data[i] != '>' && data[i] != '\n' { + i++ + } + if i < len(data) && data[i] == '>' { + i++ + if j := p.isEmpty(data[i:]); j > 0 { + size := i + j + if doRender { + // trim newlines + end := size + for end > 0 && data[end-1] == '\n' { + end-- + } + finalizeHTMLBlock(p.addBlock(HTMLBlock, data[:end])) + } + return size + } + } + return 0 +} + +func (p *Markdown) htmlFindTag(data []byte) (string, bool) { + i := 0 + for i < len(data) && isalnum(data[i]) { + i++ + } + key := string(data[:i]) + if _, ok := blockTags[key]; ok { + return key, true + } + return "", false +} + +func (p *Markdown) htmlFindEnd(tag string, data []byte) int { + // assume data[0] == '<' && data[1] == '/' already tested + if tag == "hr" { + return 2 + } + // check if tag is a match + closetag := []byte("") + if !bytes.HasPrefix(data, closetag) { + return 0 + } + i := len(closetag) + + // check that the rest of the line is blank + skip := 0 + if skip = p.isEmpty(data[i:]); skip == 0 { + return 0 + } + i += skip + skip = 0 + + if i >= len(data) { + return i + } + + if p.extensions&LaxHTMLBlocks != 0 { + return i + } + if skip = p.isEmpty(data[i:]); skip == 0 { + // following line must be blank + return 0 + } + + return i + skip +} + +func (*Markdown) isEmpty(data []byte) int { + // it is okay to call isEmpty on an empty buffer + if len(data) == 0 { + return 0 + } + + var i int + for i = 0; i < len(data) && data[i] != '\n'; i++ { + if data[i] != ' ' && data[i] != '\t' { + return 0 + } + } + if i < len(data) && data[i] == '\n' { + i++ + } + return i +} + +func (*Markdown) isHRule(data []byte) bool { + i := 0 + + // skip up to three spaces + for i < 3 && data[i] == ' ' { + i++ + } + + // look at the hrule char + if data[i] != '*' && data[i] != '-' && data[i] != '_' { + return false + } + c := data[i] + + // the whole line must be the char or whitespace + n := 0 + for i < len(data) && data[i] != '\n' { + switch { + case data[i] == c: + n++ + case data[i] != ' ': + return false + } + i++ + } + + return n >= 3 +} + +// isFenceLine checks if there's a fence line (e.g., ``` or ``` go) at the beginning of data, +// and returns the end index if so, or 0 otherwise. It also returns the marker found. +// If info is not nil, it gets set to the syntax specified in the fence line. +func isFenceLine(data []byte, info *string, oldmarker string) (end int, marker string) { + i, size := 0, 0 + + // skip up to three spaces + for i < len(data) && i < 3 && data[i] == ' ' { + i++ + } + + // check for the marker characters: ~ or ` + if i >= len(data) { + return 0, "" + } + if data[i] != '~' && data[i] != '`' { + return 0, "" + } + + c := data[i] + + // the whole line must be the same char or whitespace + for i < len(data) && data[i] == c { + size++ + i++ + } + + // the marker char must occur at least 3 times + if size < 3 { + return 0, "" + } + marker = string(data[i-size : i]) + + // if this is the end marker, it must match the beginning marker + if oldmarker != "" && marker != oldmarker { + return 0, "" + } + + // TODO(shurcooL): It's probably a good idea to simplify the 2 code paths here + // into one, always get the info string, and discard it if the caller doesn't care. + if info != nil { + infoLength := 0 + i = skipChar(data, i, ' ') + + if i >= len(data) { + if i == len(data) { + return i, marker + } + return 0, "" + } + + infoStart := i + + if data[i] == '{' { + i++ + infoStart++ + + for i < len(data) && data[i] != '}' && data[i] != '\n' { + infoLength++ + i++ + } + + if i >= len(data) || data[i] != '}' { + return 0, "" + } + + // strip all whitespace at the beginning and the end + // of the {} block + for infoLength > 0 && isspace(data[infoStart]) { + infoStart++ + infoLength-- + } + + for infoLength > 0 && isspace(data[infoStart+infoLength-1]) { + infoLength-- + } + i++ + i = skipChar(data, i, ' ') + } else { + for i < len(data) && !isverticalspace(data[i]) { + infoLength++ + i++ + } + } + + *info = strings.TrimSpace(string(data[infoStart : infoStart+infoLength])) + } + + if i == len(data) { + return i, marker + } + if i > len(data) || data[i] != '\n' { + return 0, "" + } + return i + 1, marker // Take newline into account. +} + +// fencedCodeBlock returns the end index if data contains a fenced code block at the beginning, +// or 0 otherwise. It writes to out if doRender is true, otherwise it has no side effects. +// If doRender is true, a final newline is mandatory to recognize the fenced code block. +func (p *Markdown) fencedCodeBlock(data []byte, doRender bool) int { + var info string + beg, marker := isFenceLine(data, &info, "") + if beg == 0 || beg >= len(data) { + return 0 + } + + var work bytes.Buffer + work.Write([]byte(info)) + work.WriteByte('\n') + + for { + // safe to assume beg < len(data) + + // check for the end of the code block + fenceEnd, _ := isFenceLine(data[beg:], nil, marker) + if fenceEnd != 0 { + beg += fenceEnd + break + } + + // copy the current line + end := skipUntilChar(data, beg, '\n') + 1 + + // did we reach the end of the buffer without a closing marker? + if end >= len(data) { + return 0 + } + + // verbatim copy to the working buffer + if doRender { + work.Write(data[beg:end]) + } + beg = end + } + + if doRender { + block := p.addBlock(CodeBlock, work.Bytes()) // TODO: get rid of temp buffer + block.IsFenced = true + finalizeCodeBlock(block) + } + + return beg +} + +func unescapeChar(str []byte) []byte { + if str[0] == '\\' { + return []byte{str[1]} + } + return []byte(html.UnescapeString(string(str))) +} + +func unescapeString(str []byte) []byte { + if reBackslashOrAmp.Match(str) { + return reEntityOrEscapedChar.ReplaceAllFunc(str, unescapeChar) + } + return str +} + +func finalizeCodeBlock(block *Node) { + if block.IsFenced { + newlinePos := bytes.IndexByte(block.content, '\n') + firstLine := block.content[:newlinePos] + rest := block.content[newlinePos+1:] + block.Info = unescapeString(bytes.Trim(firstLine, "\n")) + block.Literal = rest + } else { + block.Literal = block.content + } + block.content = nil +} + +func (p *Markdown) table(data []byte) int { + table := p.addBlock(Table, nil) + i, columns := p.tableHeader(data) + if i == 0 { + p.tip = table.Parent + table.Unlink() + return 0 + } + + p.addBlock(TableBody, nil) + + for i < len(data) { + pipes, rowStart := 0, i + for ; i < len(data) && data[i] != '\n'; i++ { + if data[i] == '|' { + pipes++ + } + } + + if pipes == 0 { + i = rowStart + break + } + + // include the newline in data sent to tableRow + if i < len(data) && data[i] == '\n' { + i++ + } + p.tableRow(data[rowStart:i], columns, false) + } + + return i +} + +// check if the specified position is preceded by an odd number of backslashes +func isBackslashEscaped(data []byte, i int) bool { + backslashes := 0 + for i-backslashes-1 >= 0 && data[i-backslashes-1] == '\\' { + backslashes++ + } + return backslashes&1 == 1 +} + +func (p *Markdown) tableHeader(data []byte) (size int, columns []CellAlignFlags) { + i := 0 + colCount := 1 + for i = 0; i < len(data) && data[i] != '\n'; i++ { + if data[i] == '|' && !isBackslashEscaped(data, i) { + colCount++ + } + } + + // doesn't look like a table header + if colCount == 1 { + return + } + + // include the newline in the data sent to tableRow + j := i + if j < len(data) && data[j] == '\n' { + j++ + } + header := data[:j] + + // column count ignores pipes at beginning or end of line + if data[0] == '|' { + colCount-- + } + if i > 2 && data[i-1] == '|' && !isBackslashEscaped(data, i-1) { + colCount-- + } + + columns = make([]CellAlignFlags, colCount) + + // move on to the header underline + i++ + if i >= len(data) { + return + } + + if data[i] == '|' && !isBackslashEscaped(data, i) { + i++ + } + i = skipChar(data, i, ' ') + + // each column header is of form: / *:?-+:? *|/ with # dashes + # colons >= 3 + // and trailing | optional on last column + col := 0 + for i < len(data) && data[i] != '\n' { + dashes := 0 + + if data[i] == ':' { + i++ + columns[col] |= TableAlignmentLeft + dashes++ + } + for i < len(data) && data[i] == '-' { + i++ + dashes++ + } + if i < len(data) && data[i] == ':' { + i++ + columns[col] |= TableAlignmentRight + dashes++ + } + for i < len(data) && data[i] == ' ' { + i++ + } + if i == len(data) { + return + } + // end of column test is messy + switch { + case dashes < 3: + // not a valid column + return + + case data[i] == '|' && !isBackslashEscaped(data, i): + // marker found, now skip past trailing whitespace + col++ + i++ + for i < len(data) && data[i] == ' ' { + i++ + } + + // trailing junk found after last column + if col >= colCount && i < len(data) && data[i] != '\n' { + return + } + + case (data[i] != '|' || isBackslashEscaped(data, i)) && col+1 < colCount: + // something else found where marker was required + return + + case data[i] == '\n': + // marker is optional for the last column + col++ + + default: + // trailing junk found after last column + return + } + } + if col != colCount { + return + } + + p.addBlock(TableHead, nil) + p.tableRow(header, columns, true) + size = i + if size < len(data) && data[size] == '\n' { + size++ + } + return +} + +func (p *Markdown) tableRow(data []byte, columns []CellAlignFlags, header bool) { + p.addBlock(TableRow, nil) + i, col := 0, 0 + + if data[i] == '|' && !isBackslashEscaped(data, i) { + i++ + } + + for col = 0; col < len(columns) && i < len(data); col++ { + for i < len(data) && data[i] == ' ' { + i++ + } + + cellStart := i + + for i < len(data) && (data[i] != '|' || isBackslashEscaped(data, i)) && data[i] != '\n' { + i++ + } + + cellEnd := i + + // skip the end-of-cell marker, possibly taking us past end of buffer + i++ + + for cellEnd > cellStart && cellEnd-1 < len(data) && data[cellEnd-1] == ' ' { + cellEnd-- + } + + cell := p.addBlock(TableCell, data[cellStart:cellEnd]) + cell.IsHeader = header + cell.Align = columns[col] + } + + // pad it out with empty columns to get the right number + for ; col < len(columns); col++ { + cell := p.addBlock(TableCell, nil) + cell.IsHeader = header + cell.Align = columns[col] + } + + // silently ignore rows with too many cells +} + +// returns blockquote prefix length +func (p *Markdown) quotePrefix(data []byte) int { + i := 0 + for i < 3 && i < len(data) && data[i] == ' ' { + i++ + } + if i < len(data) && data[i] == '>' { + if i+1 < len(data) && data[i+1] == ' ' { + return i + 2 + } + return i + 1 + } + return 0 +} + +// blockquote ends with at least one blank line +// followed by something without a blockquote prefix +func (p *Markdown) terminateBlockquote(data []byte, beg, end int) bool { + if p.isEmpty(data[beg:]) <= 0 { + return false + } + if end >= len(data) { + return true + } + return p.quotePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0 +} + +// parse a blockquote fragment +func (p *Markdown) quote(data []byte) int { + block := p.addBlock(BlockQuote, nil) + var raw bytes.Buffer + beg, end := 0, 0 + for beg < len(data) { + end = beg + // Step over whole lines, collecting them. While doing that, check for + // fenced code and if one's found, incorporate it altogether, + // irregardless of any contents inside it + for end < len(data) && data[end] != '\n' { + if p.extensions&FencedCode != 0 { + if i := p.fencedCodeBlock(data[end:], false); i > 0 { + // -1 to compensate for the extra end++ after the loop: + end += i - 1 + break + } + } + end++ + } + if end < len(data) && data[end] == '\n' { + end++ + } + if pre := p.quotePrefix(data[beg:]); pre > 0 { + // skip the prefix + beg += pre + } else if p.terminateBlockquote(data, beg, end) { + break + } + // this line is part of the blockquote + raw.Write(data[beg:end]) + beg = end + } + p.block(raw.Bytes()) + p.finalize(block) + return end +} + +// returns prefix length for block code +func (p *Markdown) codePrefix(data []byte) int { + if len(data) >= 1 && data[0] == '\t' { + return 1 + } + if len(data) >= 4 && data[0] == ' ' && data[1] == ' ' && data[2] == ' ' && data[3] == ' ' { + return 4 + } + return 0 +} + +func (p *Markdown) code(data []byte) int { + var work bytes.Buffer + + i := 0 + for i < len(data) { + beg := i + for i < len(data) && data[i] != '\n' { + i++ + } + if i < len(data) && data[i] == '\n' { + i++ + } + + blankline := p.isEmpty(data[beg:i]) > 0 + if pre := p.codePrefix(data[beg:i]); pre > 0 { + beg += pre + } else if !blankline { + // non-empty, non-prefixed line breaks the pre + i = beg + break + } + + // verbatim copy to the working buffer + if blankline { + work.WriteByte('\n') + } else { + work.Write(data[beg:i]) + } + } + + // trim all the \n off the end of work + workbytes := work.Bytes() + eol := len(workbytes) + for eol > 0 && workbytes[eol-1] == '\n' { + eol-- + } + if eol != len(workbytes) { + work.Truncate(eol) + } + + work.WriteByte('\n') + + block := p.addBlock(CodeBlock, work.Bytes()) // TODO: get rid of temp buffer + block.IsFenced = false + finalizeCodeBlock(block) + + return i +} + +// returns unordered list item prefix +func (p *Markdown) uliPrefix(data []byte) int { + i := 0 + // start with up to 3 spaces + for i < len(data) && i < 3 && data[i] == ' ' { + i++ + } + if i >= len(data)-1 { + return 0 + } + // need one of {'*', '+', '-'} followed by a space or a tab + if (data[i] != '*' && data[i] != '+' && data[i] != '-') || + (data[i+1] != ' ' && data[i+1] != '\t') { + return 0 + } + return i + 2 +} + +// returns ordered list item prefix +func (p *Markdown) oliPrefix(data []byte) int { + i := 0 + + // start with up to 3 spaces + for i < 3 && i < len(data) && data[i] == ' ' { + i++ + } + + // count the digits + start := i + for i < len(data) && data[i] >= '0' && data[i] <= '9' { + i++ + } + if start == i || i >= len(data)-1 { + return 0 + } + + // we need >= 1 digits followed by a dot and a space or a tab + if data[i] != '.' || !(data[i+1] == ' ' || data[i+1] == '\t') { + return 0 + } + return i + 2 +} + +// returns definition list item prefix +func (p *Markdown) dliPrefix(data []byte) int { + if len(data) < 2 { + return 0 + } + i := 0 + // need a ':' followed by a space or a tab + if data[i] != ':' || !(data[i+1] == ' ' || data[i+1] == '\t') { + return 0 + } + for i < len(data) && data[i] == ' ' { + i++ + } + return i + 2 +} + +// parse ordered or unordered list block +func (p *Markdown) list(data []byte, flags ListType) int { + i := 0 + flags |= ListItemBeginningOfList + block := p.addBlock(List, nil) + block.ListFlags = flags + block.Tight = true + + for i < len(data) { + skip := p.listItem(data[i:], &flags) + if flags&ListItemContainsBlock != 0 { + block.ListData.Tight = false + } + i += skip + if skip == 0 || flags&ListItemEndOfList != 0 { + break + } + flags &= ^ListItemBeginningOfList + } + + above := block.Parent + finalizeList(block) + p.tip = above + return i +} + +// Returns true if the list item is not the same type as its parent list +func (p *Markdown) listTypeChanged(data []byte, flags *ListType) bool { + if p.dliPrefix(data) > 0 && *flags&ListTypeDefinition == 0 { + return true + } else if p.oliPrefix(data) > 0 && *flags&ListTypeOrdered == 0 { + return true + } else if p.uliPrefix(data) > 0 && (*flags&ListTypeOrdered != 0 || *flags&ListTypeDefinition != 0) { + return true + } + return false +} + +// Returns true if block ends with a blank line, descending if needed +// into lists and sublists. +func endsWithBlankLine(block *Node) bool { + // TODO: figure this out. Always false now. + for block != nil { + //if block.lastLineBlank { + //return true + //} + t := block.Type + if t == List || t == Item { + block = block.LastChild + } else { + break + } + } + return false +} + +func finalizeList(block *Node) { + block.open = false + item := block.FirstChild + for item != nil { + // check for non-final list item ending with blank line: + if endsWithBlankLine(item) && item.Next != nil { + block.ListData.Tight = false + break + } + // recurse into children of list item, to see if there are spaces + // between any of them: + subItem := item.FirstChild + for subItem != nil { + if endsWithBlankLine(subItem) && (item.Next != nil || subItem.Next != nil) { + block.ListData.Tight = false + break + } + subItem = subItem.Next + } + item = item.Next + } +} + +// Parse a single list item. +// Assumes initial prefix is already removed if this is a sublist. +func (p *Markdown) listItem(data []byte, flags *ListType) int { + // keep track of the indentation of the first line + itemIndent := 0 + if data[0] == '\t' { + itemIndent += 4 + } else { + for itemIndent < 3 && data[itemIndent] == ' ' { + itemIndent++ + } + } + + var bulletChar byte = '*' + i := p.uliPrefix(data) + if i == 0 { + i = p.oliPrefix(data) + } else { + bulletChar = data[i-2] + } + if i == 0 { + i = p.dliPrefix(data) + // reset definition term flag + if i > 0 { + *flags &= ^ListTypeTerm + } + } + if i == 0 { + // if in definition list, set term flag and continue + if *flags&ListTypeDefinition != 0 { + *flags |= ListTypeTerm + } else { + return 0 + } + } + + // skip leading whitespace on first line + for i < len(data) && data[i] == ' ' { + i++ + } + + // find the end of the line + line := i + for i > 0 && i < len(data) && data[i-1] != '\n' { + i++ + } + + // get working buffer + var raw bytes.Buffer + + // put the first line into the working buffer + raw.Write(data[line:i]) + line = i + + // process the following lines + containsBlankLine := false + sublist := 0 + codeBlockMarker := "" + +gatherlines: + for line < len(data) { + i++ + + // find the end of this line + for i < len(data) && data[i-1] != '\n' { + i++ + } + + // if it is an empty line, guess that it is part of this item + // and move on to the next line + if p.isEmpty(data[line:i]) > 0 { + containsBlankLine = true + line = i + continue + } + + // calculate the indentation + indent := 0 + indentIndex := 0 + if data[line] == '\t' { + indentIndex++ + indent += 4 + } else { + for indent < 4 && line+indent < i && data[line+indent] == ' ' { + indent++ + indentIndex++ + } + } + + chunk := data[line+indentIndex : i] + + if p.extensions&FencedCode != 0 { + // determine if in or out of codeblock + // if in codeblock, ignore normal list processing + _, marker := isFenceLine(chunk, nil, codeBlockMarker) + if marker != "" { + if codeBlockMarker == "" { + // start of codeblock + codeBlockMarker = marker + } else { + // end of codeblock. + codeBlockMarker = "" + } + } + // we are in a codeblock, write line, and continue + if codeBlockMarker != "" || marker != "" { + raw.Write(data[line+indentIndex : i]) + line = i + continue gatherlines + } + } + + // evaluate how this line fits in + switch { + // is this a nested list item? + case (p.uliPrefix(chunk) > 0 && !p.isHRule(chunk)) || + p.oliPrefix(chunk) > 0 || + p.dliPrefix(chunk) > 0: + + // to be a nested list, it must be indented more + // if not, it is either a different kind of list + // or the next item in the same list + if indent <= itemIndent { + if p.listTypeChanged(chunk, flags) { + *flags |= ListItemEndOfList + } else if containsBlankLine { + *flags |= ListItemContainsBlock + } + + break gatherlines + } + + if containsBlankLine { + *flags |= ListItemContainsBlock + } + + // is this the first item in the nested list? + if sublist == 0 { + sublist = raw.Len() + } + + // is this a nested prefix heading? + case p.isPrefixHeading(chunk): + // if the heading is not indented, it is not nested in the list + // and thus ends the list + if containsBlankLine && indent < 4 { + *flags |= ListItemEndOfList + break gatherlines + } + *flags |= ListItemContainsBlock + + // anything following an empty line is only part + // of this item if it is indented 4 spaces + // (regardless of the indentation of the beginning of the item) + case containsBlankLine && indent < 4: + if *flags&ListTypeDefinition != 0 && i < len(data)-1 { + // is the next item still a part of this list? + next := i + for next < len(data) && data[next] != '\n' { + next++ + } + for next < len(data)-1 && data[next] == '\n' { + next++ + } + if i < len(data)-1 && data[i] != ':' && data[next] != ':' { + *flags |= ListItemEndOfList + } + } else { + *flags |= ListItemEndOfList + } + break gatherlines + + // a blank line means this should be parsed as a block + case containsBlankLine: + raw.WriteByte('\n') + *flags |= ListItemContainsBlock + } + + // if this line was preceded by one or more blanks, + // re-introduce the blank into the buffer + if containsBlankLine { + containsBlankLine = false + raw.WriteByte('\n') + } + + // add the line into the working buffer without prefix + raw.Write(data[line+indentIndex : i]) + + line = i + } + + rawBytes := raw.Bytes() + + block := p.addBlock(Item, nil) + block.ListFlags = *flags + block.Tight = false + block.BulletChar = bulletChar + block.Delimiter = '.' // Only '.' is possible in Markdown, but ')' will also be possible in CommonMark + + // render the contents of the list item + if *flags&ListItemContainsBlock != 0 && *flags&ListTypeTerm == 0 { + // intermediate render of block item, except for definition term + if sublist > 0 { + p.block(rawBytes[:sublist]) + p.block(rawBytes[sublist:]) + } else { + p.block(rawBytes) + } + } else { + // intermediate render of inline item + if sublist > 0 { + child := p.addChild(Paragraph, 0) + child.content = rawBytes[:sublist] + p.block(rawBytes[sublist:]) + } else { + child := p.addChild(Paragraph, 0) + child.content = rawBytes + } + } + return line +} + +// render a single paragraph that has already been parsed out +func (p *Markdown) renderParagraph(data []byte) { + if len(data) == 0 { + return + } + + // trim leading spaces + beg := 0 + for data[beg] == ' ' { + beg++ + } + + end := len(data) + // trim trailing newline + if data[len(data)-1] == '\n' { + end-- + } + + // trim trailing spaces + for end > beg && data[end-1] == ' ' { + end-- + } + + p.addBlock(Paragraph, data[beg:end]) +} + +func (p *Markdown) paragraph(data []byte) int { + // prev: index of 1st char of previous line + // line: index of 1st char of current line + // i: index of cursor/end of current line + var prev, line, i int + tabSize := TabSizeDefault + if p.extensions&TabSizeEight != 0 { + tabSize = TabSizeDouble + } + // keep going until we find something to mark the end of the paragraph + for i < len(data) { + // mark the beginning of the current line + prev = line + current := data[i:] + line = i + + // did we find a reference or a footnote? If so, end a paragraph + // preceding it and report that we have consumed up to the end of that + // reference: + if refEnd := isReference(p, current, tabSize); refEnd > 0 { + p.renderParagraph(data[:i]) + return i + refEnd + } + + // did we find a blank line marking the end of the paragraph? + if n := p.isEmpty(current); n > 0 { + // did this blank line followed by a definition list item? + if p.extensions&DefinitionLists != 0 { + if i < len(data)-1 && data[i+1] == ':' { + return p.list(data[prev:], ListTypeDefinition) + } + } + + p.renderParagraph(data[:i]) + return i + n + } + + // an underline under some text marks a heading, so our paragraph ended on prev line + if i > 0 { + if level := p.isUnderlinedHeading(current); level > 0 { + // render the paragraph + p.renderParagraph(data[:prev]) + + // ignore leading and trailing whitespace + eol := i - 1 + for prev < eol && data[prev] == ' ' { + prev++ + } + for eol > prev && data[eol-1] == ' ' { + eol-- + } + + id := "" + if p.extensions&AutoHeadingIDs != 0 { + id = sanitized_anchor_name.Create(string(data[prev:eol])) + } + + block := p.addBlock(Heading, data[prev:eol]) + block.Level = level + block.HeadingID = id + + // find the end of the underline + for i < len(data) && data[i] != '\n' { + i++ + } + return i + } + } + + // if the next line starts a block of HTML, then the paragraph ends here + if p.extensions&LaxHTMLBlocks != 0 { + if data[i] == '<' && p.html(current, false) > 0 { + // rewind to before the HTML block + p.renderParagraph(data[:i]) + return i + } + } + + // if there's a prefixed heading or a horizontal rule after this, paragraph is over + if p.isPrefixHeading(current) || p.isHRule(current) { + p.renderParagraph(data[:i]) + return i + } + + // if there's a fenced code block, paragraph is over + if p.extensions&FencedCode != 0 { + if p.fencedCodeBlock(current, false) > 0 { + p.renderParagraph(data[:i]) + return i + } + } + + // if there's a definition list item, prev line is a definition term + if p.extensions&DefinitionLists != 0 { + if p.dliPrefix(current) != 0 { + ret := p.list(data[prev:], ListTypeDefinition) + return ret + } + } + + // if there's a list after this, paragraph is over + if p.extensions&NoEmptyLineBeforeBlock != 0 { + if p.uliPrefix(current) != 0 || + p.oliPrefix(current) != 0 || + p.quotePrefix(current) != 0 || + p.codePrefix(current) != 0 { + p.renderParagraph(data[:i]) + return i + } + } + + // otherwise, scan to the beginning of the next line + nl := bytes.IndexByte(data[i:], '\n') + if nl >= 0 { + i += nl + 1 + } else { + i += len(data[i:]) + } + } + + p.renderParagraph(data[:i]) + return i +} + +func skipChar(data []byte, start int, char byte) int { + i := start + for i < len(data) && data[i] == char { + i++ + } + return i +} + +func skipUntilChar(text []byte, start int, char byte) int { + i := start + for i < len(text) && text[i] != char { + i++ + } + return i +} diff --git a/vendor/github.com/russross/blackfriday/v2/doc.go b/vendor/github.com/russross/blackfriday/v2/doc.go new file mode 100644 index 000000000..5b3fa9876 --- /dev/null +++ b/vendor/github.com/russross/blackfriday/v2/doc.go @@ -0,0 +1,18 @@ +// Package blackfriday is a markdown processor. +// +// It translates plain text with simple formatting rules into an AST, which can +// then be further processed to HTML (provided by Blackfriday itself) or other +// formats (provided by the community). +// +// The simplest way to invoke Blackfriday is to call the Run function. It will +// take a text input and produce a text output in HTML (or other format). +// +// A slightly more sophisticated way to use Blackfriday is to create a Markdown +// processor and to call Parse, which returns a syntax tree for the input +// document. You can leverage Blackfriday's parsing for content extraction from +// markdown documents. You can assign a custom renderer and set various options +// to the Markdown processor. +// +// If you're interested in calling Blackfriday from command line, see +// https://github.com/russross/blackfriday-tool. +package blackfriday diff --git a/vendor/github.com/russross/blackfriday/v2/esc.go b/vendor/github.com/russross/blackfriday/v2/esc.go new file mode 100644 index 000000000..6385f27cb --- /dev/null +++ b/vendor/github.com/russross/blackfriday/v2/esc.go @@ -0,0 +1,34 @@ +package blackfriday + +import ( + "html" + "io" +) + +var htmlEscaper = [256][]byte{ + '&': []byte("&"), + '<': []byte("<"), + '>': []byte(">"), + '"': []byte("""), +} + +func escapeHTML(w io.Writer, s []byte) { + var start, end int + for end < len(s) { + escSeq := htmlEscaper[s[end]] + if escSeq != nil { + w.Write(s[start:end]) + w.Write(escSeq) + start = end + 1 + } + end++ + } + if start < len(s) && end <= len(s) { + w.Write(s[start:end]) + } +} + +func escLink(w io.Writer, text []byte) { + unesc := html.UnescapeString(string(text)) + escapeHTML(w, []byte(unesc)) +} diff --git a/vendor/github.com/russross/blackfriday/v2/go.mod b/vendor/github.com/russross/blackfriday/v2/go.mod new file mode 100644 index 000000000..620b74e0a --- /dev/null +++ b/vendor/github.com/russross/blackfriday/v2/go.mod @@ -0,0 +1 @@ +module github.com/russross/blackfriday/v2 diff --git a/vendor/github.com/russross/blackfriday/v2/html.go b/vendor/github.com/russross/blackfriday/v2/html.go new file mode 100644 index 000000000..284c87184 --- /dev/null +++ b/vendor/github.com/russross/blackfriday/v2/html.go @@ -0,0 +1,949 @@ +// +// Blackfriday Markdown Processor +// Available at http://github.com/russross/blackfriday +// +// Copyright © 2011 Russ Ross . +// Distributed under the Simplified BSD License. +// See README.md for details. +// + +// +// +// HTML rendering backend +// +// + +package blackfriday + +import ( + "bytes" + "fmt" + "io" + "regexp" + "strings" +) + +// HTMLFlags control optional behavior of HTML renderer. +type HTMLFlags int + +// HTML renderer configuration options. +const ( + HTMLFlagsNone HTMLFlags = 0 + SkipHTML HTMLFlags = 1 << iota // Skip preformatted HTML blocks + SkipImages // Skip embedded images + SkipLinks // Skip all links + Safelink // Only link to trusted protocols + NofollowLinks // Only link with rel="nofollow" + NoreferrerLinks // Only link with rel="noreferrer" + NoopenerLinks // Only link with rel="noopener" + HrefTargetBlank // Add a blank target + CompletePage // Generate a complete HTML page + UseXHTML // Generate XHTML output instead of HTML + FootnoteReturnLinks // Generate a link at the end of a footnote to return to the source + Smartypants // Enable smart punctuation substitutions + SmartypantsFractions // Enable smart fractions (with Smartypants) + SmartypantsDashes // Enable smart dashes (with Smartypants) + SmartypantsLatexDashes // Enable LaTeX-style dashes (with Smartypants) + SmartypantsAngledQuotes // Enable angled double quotes (with Smartypants) for double quotes rendering + SmartypantsQuotesNBSP // Enable « French guillemets » (with Smartypants) + TOC // Generate a table of contents +) + +var ( + htmlTagRe = regexp.MustCompile("(?i)^" + htmlTag) +) + +const ( + htmlTag = "(?:" + openTag + "|" + closeTag + "|" + htmlComment + "|" + + processingInstruction + "|" + declaration + "|" + cdata + ")" + closeTag = "]" + openTag = "<" + tagName + attribute + "*" + "\\s*/?>" + attribute = "(?:" + "\\s+" + attributeName + attributeValueSpec + "?)" + attributeValue = "(?:" + unquotedValue + "|" + singleQuotedValue + "|" + doubleQuotedValue + ")" + attributeValueSpec = "(?:" + "\\s*=" + "\\s*" + attributeValue + ")" + attributeName = "[a-zA-Z_:][a-zA-Z0-9:._-]*" + cdata = "" + declaration = "]*>" + doubleQuotedValue = "\"[^\"]*\"" + htmlComment = "|" + processingInstruction = "[<][?].*?[?][>]" + singleQuotedValue = "'[^']*'" + tagName = "[A-Za-z][A-Za-z0-9-]*" + unquotedValue = "[^\"'=<>`\\x00-\\x20]+" +) + +// HTMLRendererParameters is a collection of supplementary parameters tweaking +// the behavior of various parts of HTML renderer. +type HTMLRendererParameters struct { + // Prepend this text to each relative URL. + AbsolutePrefix string + // Add this text to each footnote anchor, to ensure uniqueness. + FootnoteAnchorPrefix string + // Show this text inside the tag for a footnote return link, if the + // HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string + // [return] is used. + FootnoteReturnLinkContents string + // If set, add this text to the front of each Heading ID, to ensure + // uniqueness. + HeadingIDPrefix string + // If set, add this text to the back of each Heading ID, to ensure uniqueness. + HeadingIDSuffix string + // Increase heading levels: if the offset is 1,

becomes

etc. + // Negative offset is also valid. + // Resulting levels are clipped between 1 and 6. + HeadingLevelOffset int + + Title string // Document title (used if CompletePage is set) + CSS string // Optional CSS file URL (used if CompletePage is set) + Icon string // Optional icon file URL (used if CompletePage is set) + + Flags HTMLFlags // Flags allow customizing this renderer's behavior +} + +// HTMLRenderer is a type that implements the Renderer interface for HTML output. +// +// Do not create this directly, instead use the NewHTMLRenderer function. +type HTMLRenderer struct { + HTMLRendererParameters + + closeTag string // how to end singleton tags: either " />" or ">" + + // Track heading IDs to prevent ID collision in a single generation. + headingIDs map[string]int + + lastOutputLen int + disableTags int + + sr *SPRenderer +} + +const ( + xhtmlClose = " />" + htmlClose = ">" +) + +// NewHTMLRenderer creates and configures an HTMLRenderer object, which +// satisfies the Renderer interface. +func NewHTMLRenderer(params HTMLRendererParameters) *HTMLRenderer { + // configure the rendering engine + closeTag := htmlClose + if params.Flags&UseXHTML != 0 { + closeTag = xhtmlClose + } + + if params.FootnoteReturnLinkContents == "" { + params.FootnoteReturnLinkContents = `[return]` + } + + return &HTMLRenderer{ + HTMLRendererParameters: params, + + closeTag: closeTag, + headingIDs: make(map[string]int), + + sr: NewSmartypantsRenderer(params.Flags), + } +} + +func isHTMLTag(tag []byte, tagname string) bool { + found, _ := findHTMLTagPos(tag, tagname) + return found +} + +// Look for a character, but ignore it when it's in any kind of quotes, it +// might be JavaScript +func skipUntilCharIgnoreQuotes(html []byte, start int, char byte) int { + inSingleQuote := false + inDoubleQuote := false + inGraveQuote := false + i := start + for i < len(html) { + switch { + case html[i] == char && !inSingleQuote && !inDoubleQuote && !inGraveQuote: + return i + case html[i] == '\'': + inSingleQuote = !inSingleQuote + case html[i] == '"': + inDoubleQuote = !inDoubleQuote + case html[i] == '`': + inGraveQuote = !inGraveQuote + } + i++ + } + return start +} + +func findHTMLTagPos(tag []byte, tagname string) (bool, int) { + i := 0 + if i < len(tag) && tag[0] != '<' { + return false, -1 + } + i++ + i = skipSpace(tag, i) + + if i < len(tag) && tag[i] == '/' { + i++ + } + + i = skipSpace(tag, i) + j := 0 + for ; i < len(tag); i, j = i+1, j+1 { + if j >= len(tagname) { + break + } + + if strings.ToLower(string(tag[i]))[0] != tagname[j] { + return false, -1 + } + } + + if i == len(tag) { + return false, -1 + } + + rightAngle := skipUntilCharIgnoreQuotes(tag, i, '>') + if rightAngle >= i { + return true, rightAngle + } + + return false, -1 +} + +func skipSpace(tag []byte, i int) int { + for i < len(tag) && isspace(tag[i]) { + i++ + } + return i +} + +func isRelativeLink(link []byte) (yes bool) { + // a tag begin with '#' + if link[0] == '#' { + return true + } + + // link begin with '/' but not '//', the second maybe a protocol relative link + if len(link) >= 2 && link[0] == '/' && link[1] != '/' { + return true + } + + // only the root '/' + if len(link) == 1 && link[0] == '/' { + return true + } + + // current directory : begin with "./" + if bytes.HasPrefix(link, []byte("./")) { + return true + } + + // parent directory : begin with "../" + if bytes.HasPrefix(link, []byte("../")) { + return true + } + + return false +} + +func (r *HTMLRenderer) ensureUniqueHeadingID(id string) string { + for count, found := r.headingIDs[id]; found; count, found = r.headingIDs[id] { + tmp := fmt.Sprintf("%s-%d", id, count+1) + + if _, tmpFound := r.headingIDs[tmp]; !tmpFound { + r.headingIDs[id] = count + 1 + id = tmp + } else { + id = id + "-1" + } + } + + if _, found := r.headingIDs[id]; !found { + r.headingIDs[id] = 0 + } + + return id +} + +func (r *HTMLRenderer) addAbsPrefix(link []byte) []byte { + if r.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' { + newDest := r.AbsolutePrefix + if link[0] != '/' { + newDest += "/" + } + newDest += string(link) + return []byte(newDest) + } + return link +} + +func appendLinkAttrs(attrs []string, flags HTMLFlags, link []byte) []string { + if isRelativeLink(link) { + return attrs + } + val := []string{} + if flags&NofollowLinks != 0 { + val = append(val, "nofollow") + } + if flags&NoreferrerLinks != 0 { + val = append(val, "noreferrer") + } + if flags&NoopenerLinks != 0 { + val = append(val, "noopener") + } + if flags&HrefTargetBlank != 0 { + attrs = append(attrs, "target=\"_blank\"") + } + if len(val) == 0 { + return attrs + } + attr := fmt.Sprintf("rel=%q", strings.Join(val, " ")) + return append(attrs, attr) +} + +func isMailto(link []byte) bool { + return bytes.HasPrefix(link, []byte("mailto:")) +} + +func needSkipLink(flags HTMLFlags, dest []byte) bool { + if flags&SkipLinks != 0 { + return true + } + return flags&Safelink != 0 && !isSafeLink(dest) && !isMailto(dest) +} + +func isSmartypantable(node *Node) bool { + pt := node.Parent.Type + return pt != Link && pt != CodeBlock && pt != Code +} + +func appendLanguageAttr(attrs []string, info []byte) []string { + if len(info) == 0 { + return attrs + } + endOfLang := bytes.IndexAny(info, "\t ") + if endOfLang < 0 { + endOfLang = len(info) + } + return append(attrs, fmt.Sprintf("class=\"language-%s\"", info[:endOfLang])) +} + +func (r *HTMLRenderer) tag(w io.Writer, name []byte, attrs []string) { + w.Write(name) + if len(attrs) > 0 { + w.Write(spaceBytes) + w.Write([]byte(strings.Join(attrs, " "))) + } + w.Write(gtBytes) + r.lastOutputLen = 1 +} + +func footnoteRef(prefix string, node *Node) []byte { + urlFrag := prefix + string(slugify(node.Destination)) + anchor := fmt.Sprintf(`%d`, urlFrag, node.NoteID) + return []byte(fmt.Sprintf(`%s`, urlFrag, anchor)) +} + +func footnoteItem(prefix string, slug []byte) []byte { + return []byte(fmt.Sprintf(`
  • `, prefix, slug)) +} + +func footnoteReturnLink(prefix, returnLink string, slug []byte) []byte { + const format = ` %s` + return []byte(fmt.Sprintf(format, prefix, slug, returnLink)) +} + +func itemOpenCR(node *Node) bool { + if node.Prev == nil { + return false + } + ld := node.Parent.ListData + return !ld.Tight && ld.ListFlags&ListTypeDefinition == 0 +} + +func skipParagraphTags(node *Node) bool { + grandparent := node.Parent.Parent + if grandparent == nil || grandparent.Type != List { + return false + } + tightOrTerm := grandparent.Tight || node.Parent.ListFlags&ListTypeTerm != 0 + return grandparent.Type == List && tightOrTerm +} + +func cellAlignment(align CellAlignFlags) string { + switch align { + case TableAlignmentLeft: + return "left" + case TableAlignmentRight: + return "right" + case TableAlignmentCenter: + return "center" + default: + return "" + } +} + +func (r *HTMLRenderer) out(w io.Writer, text []byte) { + if r.disableTags > 0 { + w.Write(htmlTagRe.ReplaceAll(text, []byte{})) + } else { + w.Write(text) + } + r.lastOutputLen = len(text) +} + +func (r *HTMLRenderer) cr(w io.Writer) { + if r.lastOutputLen > 0 { + r.out(w, nlBytes) + } +} + +var ( + nlBytes = []byte{'\n'} + gtBytes = []byte{'>'} + spaceBytes = []byte{' '} +) + +var ( + brTag = []byte("
    ") + brXHTMLTag = []byte("
    ") + emTag = []byte("") + emCloseTag = []byte("") + strongTag = []byte("") + strongCloseTag = []byte("") + delTag = []byte("") + delCloseTag = []byte("") + ttTag = []byte("") + ttCloseTag = []byte("") + aTag = []byte("") + preTag = []byte("
    ")
    +	preCloseTag        = []byte("
    ") + codeTag = []byte("") + codeCloseTag = []byte("") + pTag = []byte("

    ") + pCloseTag = []byte("

    ") + blockquoteTag = []byte("
    ") + blockquoteCloseTag = []byte("
    ") + hrTag = []byte("
    ") + hrXHTMLTag = []byte("
    ") + ulTag = []byte("
      ") + ulCloseTag = []byte("
    ") + olTag = []byte("
      ") + olCloseTag = []byte("
    ") + dlTag = []byte("
    ") + dlCloseTag = []byte("
    ") + liTag = []byte("
  • ") + liCloseTag = []byte("
  • ") + ddTag = []byte("
    ") + ddCloseTag = []byte("
    ") + dtTag = []byte("
    ") + dtCloseTag = []byte("
    ") + tableTag = []byte("") + tableCloseTag = []byte("
    ") + tdTag = []byte("") + thTag = []byte("") + theadTag = []byte("") + theadCloseTag = []byte("") + tbodyTag = []byte("") + tbodyCloseTag = []byte("") + trTag = []byte("") + trCloseTag = []byte("") + h1Tag = []byte("") + h2Tag = []byte("") + h3Tag = []byte("") + h4Tag = []byte("") + h5Tag = []byte("") + h6Tag = []byte("") + + footnotesDivBytes = []byte("\n
    \n\n") + footnotesCloseDivBytes = []byte("\n
    \n") +) + +func headingTagsFromLevel(level int) ([]byte, []byte) { + if level <= 1 { + return h1Tag, h1CloseTag + } + switch level { + case 2: + return h2Tag, h2CloseTag + case 3: + return h3Tag, h3CloseTag + case 4: + return h4Tag, h4CloseTag + case 5: + return h5Tag, h5CloseTag + } + return h6Tag, h6CloseTag +} + +func (r *HTMLRenderer) outHRTag(w io.Writer) { + if r.Flags&UseXHTML == 0 { + r.out(w, hrTag) + } else { + r.out(w, hrXHTMLTag) + } +} + +// RenderNode is a default renderer of a single node of a syntax tree. For +// block nodes it will be called twice: first time with entering=true, second +// time with entering=false, so that it could know when it's working on an open +// tag and when on close. It writes the result to w. +// +// The return value is a way to tell the calling walker to adjust its walk +// pattern: e.g. it can terminate the traversal by returning Terminate. Or it +// can ask the walker to skip a subtree of this node by returning SkipChildren. +// The typical behavior is to return GoToNext, which asks for the usual +// traversal to the next node. +func (r *HTMLRenderer) RenderNode(w io.Writer, node *Node, entering bool) WalkStatus { + attrs := []string{} + switch node.Type { + case Text: + if r.Flags&Smartypants != 0 { + var tmp bytes.Buffer + escapeHTML(&tmp, node.Literal) + r.sr.Process(w, tmp.Bytes()) + } else { + if node.Parent.Type == Link { + escLink(w, node.Literal) + } else { + escapeHTML(w, node.Literal) + } + } + case Softbreak: + r.cr(w) + // TODO: make it configurable via out(renderer.softbreak) + case Hardbreak: + if r.Flags&UseXHTML == 0 { + r.out(w, brTag) + } else { + r.out(w, brXHTMLTag) + } + r.cr(w) + case Emph: + if entering { + r.out(w, emTag) + } else { + r.out(w, emCloseTag) + } + case Strong: + if entering { + r.out(w, strongTag) + } else { + r.out(w, strongCloseTag) + } + case Del: + if entering { + r.out(w, delTag) + } else { + r.out(w, delCloseTag) + } + case HTMLSpan: + if r.Flags&SkipHTML != 0 { + break + } + r.out(w, node.Literal) + case Link: + // mark it but don't link it if it is not a safe link: no smartypants + dest := node.LinkData.Destination + if needSkipLink(r.Flags, dest) { + if entering { + r.out(w, ttTag) + } else { + r.out(w, ttCloseTag) + } + } else { + if entering { + dest = r.addAbsPrefix(dest) + var hrefBuf bytes.Buffer + hrefBuf.WriteString("href=\"") + escLink(&hrefBuf, dest) + hrefBuf.WriteByte('"') + attrs = append(attrs, hrefBuf.String()) + if node.NoteID != 0 { + r.out(w, footnoteRef(r.FootnoteAnchorPrefix, node)) + break + } + attrs = appendLinkAttrs(attrs, r.Flags, dest) + if len(node.LinkData.Title) > 0 { + var titleBuff bytes.Buffer + titleBuff.WriteString("title=\"") + escapeHTML(&titleBuff, node.LinkData.Title) + titleBuff.WriteByte('"') + attrs = append(attrs, titleBuff.String()) + } + r.tag(w, aTag, attrs) + } else { + if node.NoteID != 0 { + break + } + r.out(w, aCloseTag) + } + } + case Image: + if r.Flags&SkipImages != 0 { + return SkipChildren + } + if entering { + dest := node.LinkData.Destination + dest = r.addAbsPrefix(dest) + if r.disableTags == 0 { + //if options.safe && potentiallyUnsafe(dest) { + //out(w, ``)
+				//} else {
+				r.out(w, []byte(`<img src=`)) + } + } + case Code: + r.out(w, codeTag) + escapeHTML(w, node.Literal) + r.out(w, codeCloseTag) + case Document: + break + case Paragraph: + if skipParagraphTags(node) { + break + } + if entering { + // TODO: untangle this clusterfuck about when the newlines need + // to be added and when not. + if node.Prev != nil { + switch node.Prev.Type { + case HTMLBlock, List, Paragraph, Heading, CodeBlock, BlockQuote, HorizontalRule: + r.cr(w) + } + } + if node.Parent.Type == BlockQuote && node.Prev == nil { + r.cr(w) + } + r.out(w, pTag) + } else { + r.out(w, pCloseTag) + if !(node.Parent.Type == Item && node.Next == nil) { + r.cr(w) + } + } + case BlockQuote: + if entering { + r.cr(w) + r.out(w, blockquoteTag) + } else { + r.out(w, blockquoteCloseTag) + r.cr(w) + } + case HTMLBlock: + if r.Flags&SkipHTML != 0 { + break + } + r.cr(w) + r.out(w, node.Literal) + r.cr(w) + case Heading: + headingLevel := r.HTMLRendererParameters.HeadingLevelOffset + node.Level + openTag, closeTag := headingTagsFromLevel(headingLevel) + if entering { + if node.IsTitleblock { + attrs = append(attrs, `class="title"`) + } + if node.HeadingID != "" { + id := r.ensureUniqueHeadingID(node.HeadingID) + if r.HeadingIDPrefix != "" { + id = r.HeadingIDPrefix + id + } + if r.HeadingIDSuffix != "" { + id = id + r.HeadingIDSuffix + } + attrs = append(attrs, fmt.Sprintf(`id="%s"`, id)) + } + r.cr(w) + r.tag(w, openTag, attrs) + } else { + r.out(w, closeTag) + if !(node.Parent.Type == Item && node.Next == nil) { + r.cr(w) + } + } + case HorizontalRule: + r.cr(w) + r.outHRTag(w) + r.cr(w) + case List: + openTag := ulTag + closeTag := ulCloseTag + if node.ListFlags&ListTypeOrdered != 0 { + openTag = olTag + closeTag = olCloseTag + } + if node.ListFlags&ListTypeDefinition != 0 { + openTag = dlTag + closeTag = dlCloseTag + } + if entering { + if node.IsFootnotesList { + r.out(w, footnotesDivBytes) + r.outHRTag(w) + r.cr(w) + } + r.cr(w) + if node.Parent.Type == Item && node.Parent.Parent.Tight { + r.cr(w) + } + r.tag(w, openTag[:len(openTag)-1], attrs) + r.cr(w) + } else { + r.out(w, closeTag) + //cr(w) + //if node.parent.Type != Item { + // cr(w) + //} + if node.Parent.Type == Item && node.Next != nil { + r.cr(w) + } + if node.Parent.Type == Document || node.Parent.Type == BlockQuote { + r.cr(w) + } + if node.IsFootnotesList { + r.out(w, footnotesCloseDivBytes) + } + } + case Item: + openTag := liTag + closeTag := liCloseTag + if node.ListFlags&ListTypeDefinition != 0 { + openTag = ddTag + closeTag = ddCloseTag + } + if node.ListFlags&ListTypeTerm != 0 { + openTag = dtTag + closeTag = dtCloseTag + } + if entering { + if itemOpenCR(node) { + r.cr(w) + } + if node.ListData.RefLink != nil { + slug := slugify(node.ListData.RefLink) + r.out(w, footnoteItem(r.FootnoteAnchorPrefix, slug)) + break + } + r.out(w, openTag) + } else { + if node.ListData.RefLink != nil { + slug := slugify(node.ListData.RefLink) + if r.Flags&FootnoteReturnLinks != 0 { + r.out(w, footnoteReturnLink(r.FootnoteAnchorPrefix, r.FootnoteReturnLinkContents, slug)) + } + } + r.out(w, closeTag) + r.cr(w) + } + case CodeBlock: + attrs = appendLanguageAttr(attrs, node.Info) + r.cr(w) + r.out(w, preTag) + r.tag(w, codeTag[:len(codeTag)-1], attrs) + escapeHTML(w, node.Literal) + r.out(w, codeCloseTag) + r.out(w, preCloseTag) + if node.Parent.Type != Item { + r.cr(w) + } + case Table: + if entering { + r.cr(w) + r.out(w, tableTag) + } else { + r.out(w, tableCloseTag) + r.cr(w) + } + case TableCell: + openTag := tdTag + closeTag := tdCloseTag + if node.IsHeader { + openTag = thTag + closeTag = thCloseTag + } + if entering { + align := cellAlignment(node.Align) + if align != "" { + attrs = append(attrs, fmt.Sprintf(`align="%s"`, align)) + } + if node.Prev == nil { + r.cr(w) + } + r.tag(w, openTag, attrs) + } else { + r.out(w, closeTag) + r.cr(w) + } + case TableHead: + if entering { + r.cr(w) + r.out(w, theadTag) + } else { + r.out(w, theadCloseTag) + r.cr(w) + } + case TableBody: + if entering { + r.cr(w) + r.out(w, tbodyTag) + // XXX: this is to adhere to a rather silly test. Should fix test. + if node.FirstChild == nil { + r.cr(w) + } + } else { + r.out(w, tbodyCloseTag) + r.cr(w) + } + case TableRow: + if entering { + r.cr(w) + r.out(w, trTag) + } else { + r.out(w, trCloseTag) + r.cr(w) + } + default: + panic("Unknown node type " + node.Type.String()) + } + return GoToNext +} + +// RenderHeader writes HTML document preamble and TOC if requested. +func (r *HTMLRenderer) RenderHeader(w io.Writer, ast *Node) { + r.writeDocumentHeader(w) + if r.Flags&TOC != 0 { + r.writeTOC(w, ast) + } +} + +// RenderFooter writes HTML document footer. +func (r *HTMLRenderer) RenderFooter(w io.Writer, ast *Node) { + if r.Flags&CompletePage == 0 { + return + } + io.WriteString(w, "\n\n\n") +} + +func (r *HTMLRenderer) writeDocumentHeader(w io.Writer) { + if r.Flags&CompletePage == 0 { + return + } + ending := "" + if r.Flags&UseXHTML != 0 { + io.WriteString(w, "\n") + io.WriteString(w, "\n") + ending = " /" + } else { + io.WriteString(w, "\n") + io.WriteString(w, "\n") + } + io.WriteString(w, "\n") + io.WriteString(w, " ") + if r.Flags&Smartypants != 0 { + r.sr.Process(w, []byte(r.Title)) + } else { + escapeHTML(w, []byte(r.Title)) + } + io.WriteString(w, "\n") + io.WriteString(w, " \n") + io.WriteString(w, " \n") + if r.CSS != "" { + io.WriteString(w, " \n") + } + if r.Icon != "" { + io.WriteString(w, " \n") + } + io.WriteString(w, "\n") + io.WriteString(w, "\n\n") +} + +func (r *HTMLRenderer) writeTOC(w io.Writer, ast *Node) { + buf := bytes.Buffer{} + + inHeading := false + tocLevel := 0 + headingCount := 0 + + ast.Walk(func(node *Node, entering bool) WalkStatus { + if node.Type == Heading && !node.HeadingData.IsTitleblock { + inHeading = entering + if entering { + node.HeadingID = fmt.Sprintf("toc_%d", headingCount) + if node.Level == tocLevel { + buf.WriteString("\n\n
  • ") + } else if node.Level < tocLevel { + for node.Level < tocLevel { + tocLevel-- + buf.WriteString("
  • \n") + } + buf.WriteString("\n\n
  • ") + } else { + for node.Level > tocLevel { + tocLevel++ + buf.WriteString("\n") + } + + if buf.Len() > 0 { + io.WriteString(w, "\n") + } + r.lastOutputLen = buf.Len() +} diff --git a/vendor/github.com/russross/blackfriday/v2/inline.go b/vendor/github.com/russross/blackfriday/v2/inline.go new file mode 100644 index 000000000..4ed290792 --- /dev/null +++ b/vendor/github.com/russross/blackfriday/v2/inline.go @@ -0,0 +1,1228 @@ +// +// Blackfriday Markdown Processor +// Available at http://github.com/russross/blackfriday +// +// Copyright © 2011 Russ Ross . +// Distributed under the Simplified BSD License. +// See README.md for details. +// + +// +// Functions to parse inline elements. +// + +package blackfriday + +import ( + "bytes" + "regexp" + "strconv" +) + +var ( + urlRe = `((https?|ftp):\/\/|\/)[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+` + anchorRe = regexp.MustCompile(`^(]+")?\s?>` + urlRe + `<\/a>)`) + + // https://www.w3.org/TR/html5/syntax.html#character-references + // highest unicode code point in 17 planes (2^20): 1,114,112d = + // 7 dec digits or 6 hex digits + // named entity references can be 2-31 characters with stuff like < + // at one end and ∳ at the other. There + // are also sometimes numbers at the end, although this isn't inherent + // in the specification; there are never numbers anywhere else in + // current character references, though; see ¾ and ▒, etc. + // https://www.w3.org/TR/html5/syntax.html#named-character-references + // + // entity := "&" (named group | number ref) ";" + // named group := [a-zA-Z]{2,31}[0-9]{0,2} + // number ref := "#" (dec ref | hex ref) + // dec ref := [0-9]{1,7} + // hex ref := ("x" | "X") [0-9a-fA-F]{1,6} + htmlEntityRe = regexp.MustCompile(`&([a-zA-Z]{2,31}[0-9]{0,2}|#([0-9]{1,7}|[xX][0-9a-fA-F]{1,6}));`) +) + +// Functions to parse text within a block +// Each function returns the number of chars taken care of +// data is the complete block being rendered +// offset is the number of valid chars before the current cursor + +func (p *Markdown) inline(currBlock *Node, data []byte) { + // handlers might call us recursively: enforce a maximum depth + if p.nesting >= p.maxNesting || len(data) == 0 { + return + } + p.nesting++ + beg, end := 0, 0 + for end < len(data) { + handler := p.inlineCallback[data[end]] + if handler != nil { + if consumed, node := handler(p, data, end); consumed == 0 { + // No action from the callback. + end++ + } else { + // Copy inactive chars into the output. + currBlock.AppendChild(text(data[beg:end])) + if node != nil { + currBlock.AppendChild(node) + } + // Skip past whatever the callback used. + beg = end + consumed + end = beg + } + } else { + end++ + } + } + if beg < len(data) { + if data[end-1] == '\n' { + end-- + } + currBlock.AppendChild(text(data[beg:end])) + } + p.nesting-- +} + +// single and double emphasis parsing +func emphasis(p *Markdown, data []byte, offset int) (int, *Node) { + data = data[offset:] + c := data[0] + + if len(data) > 2 && data[1] != c { + // whitespace cannot follow an opening emphasis; + // strikethrough only takes two characters '~~' + if c == '~' || isspace(data[1]) { + return 0, nil + } + ret, node := helperEmphasis(p, data[1:], c) + if ret == 0 { + return 0, nil + } + + return ret + 1, node + } + + if len(data) > 3 && data[1] == c && data[2] != c { + if isspace(data[2]) { + return 0, nil + } + ret, node := helperDoubleEmphasis(p, data[2:], c) + if ret == 0 { + return 0, nil + } + + return ret + 2, node + } + + if len(data) > 4 && data[1] == c && data[2] == c && data[3] != c { + if c == '~' || isspace(data[3]) { + return 0, nil + } + ret, node := helperTripleEmphasis(p, data, 3, c) + if ret == 0 { + return 0, nil + } + + return ret + 3, node + } + + return 0, nil +} + +func codeSpan(p *Markdown, data []byte, offset int) (int, *Node) { + data = data[offset:] + + nb := 0 + + // count the number of backticks in the delimiter + for nb < len(data) && data[nb] == '`' { + nb++ + } + + // find the next delimiter + i, end := 0, 0 + for end = nb; end < len(data) && i < nb; end++ { + if data[end] == '`' { + i++ + } else { + i = 0 + } + } + + // no matching delimiter? + if i < nb && end >= len(data) { + return 0, nil + } + + // trim outside whitespace + fBegin := nb + for fBegin < end && data[fBegin] == ' ' { + fBegin++ + } + + fEnd := end - nb + for fEnd > fBegin && data[fEnd-1] == ' ' { + fEnd-- + } + + // render the code span + if fBegin != fEnd { + code := NewNode(Code) + code.Literal = data[fBegin:fEnd] + return end, code + } + + return end, nil +} + +// newline preceded by two spaces becomes
    +func maybeLineBreak(p *Markdown, data []byte, offset int) (int, *Node) { + origOffset := offset + for offset < len(data) && data[offset] == ' ' { + offset++ + } + + if offset < len(data) && data[offset] == '\n' { + if offset-origOffset >= 2 { + return offset - origOffset + 1, NewNode(Hardbreak) + } + return offset - origOffset, nil + } + return 0, nil +} + +// newline without two spaces works when HardLineBreak is enabled +func lineBreak(p *Markdown, data []byte, offset int) (int, *Node) { + if p.extensions&HardLineBreak != 0 { + return 1, NewNode(Hardbreak) + } + return 0, nil +} + +type linkType int + +const ( + linkNormal linkType = iota + linkImg + linkDeferredFootnote + linkInlineFootnote +) + +func isReferenceStyleLink(data []byte, pos int, t linkType) bool { + if t == linkDeferredFootnote { + return false + } + return pos < len(data)-1 && data[pos] == '[' && data[pos+1] != '^' +} + +func maybeImage(p *Markdown, data []byte, offset int) (int, *Node) { + if offset < len(data)-1 && data[offset+1] == '[' { + return link(p, data, offset) + } + return 0, nil +} + +func maybeInlineFootnote(p *Markdown, data []byte, offset int) (int, *Node) { + if offset < len(data)-1 && data[offset+1] == '[' { + return link(p, data, offset) + } + return 0, nil +} + +// '[': parse a link or an image or a footnote +func link(p *Markdown, data []byte, offset int) (int, *Node) { + // no links allowed inside regular links, footnote, and deferred footnotes + if p.insideLink && (offset > 0 && data[offset-1] == '[' || len(data)-1 > offset && data[offset+1] == '^') { + return 0, nil + } + + var t linkType + switch { + // special case: ![^text] == deferred footnote (that follows something with + // an exclamation point) + case p.extensions&Footnotes != 0 && len(data)-1 > offset && data[offset+1] == '^': + t = linkDeferredFootnote + // ![alt] == image + case offset >= 0 && data[offset] == '!': + t = linkImg + offset++ + // ^[text] == inline footnote + // [^refId] == deferred footnote + case p.extensions&Footnotes != 0: + if offset >= 0 && data[offset] == '^' { + t = linkInlineFootnote + offset++ + } else if len(data)-1 > offset && data[offset+1] == '^' { + t = linkDeferredFootnote + } + // [text] == regular link + default: + t = linkNormal + } + + data = data[offset:] + + var ( + i = 1 + noteID int + title, link, altContent []byte + textHasNl = false + ) + + if t == linkDeferredFootnote { + i++ + } + + // look for the matching closing bracket + for level := 1; level > 0 && i < len(data); i++ { + switch { + case data[i] == '\n': + textHasNl = true + + case data[i-1] == '\\': + continue + + case data[i] == '[': + level++ + + case data[i] == ']': + level-- + if level <= 0 { + i-- // compensate for extra i++ in for loop + } + } + } + + if i >= len(data) { + return 0, nil + } + + txtE := i + i++ + var footnoteNode *Node + + // skip any amount of whitespace or newline + // (this is much more lax than original markdown syntax) + for i < len(data) && isspace(data[i]) { + i++ + } + + // inline style link + switch { + case i < len(data) && data[i] == '(': + // skip initial whitespace + i++ + + for i < len(data) && isspace(data[i]) { + i++ + } + + linkB := i + + // look for link end: ' " ) + findlinkend: + for i < len(data) { + switch { + case data[i] == '\\': + i += 2 + + case data[i] == ')' || data[i] == '\'' || data[i] == '"': + break findlinkend + + default: + i++ + } + } + + if i >= len(data) { + return 0, nil + } + linkE := i + + // look for title end if present + titleB, titleE := 0, 0 + if data[i] == '\'' || data[i] == '"' { + i++ + titleB = i + + findtitleend: + for i < len(data) { + switch { + case data[i] == '\\': + i += 2 + + case data[i] == ')': + break findtitleend + + default: + i++ + } + } + + if i >= len(data) { + return 0, nil + } + + // skip whitespace after title + titleE = i - 1 + for titleE > titleB && isspace(data[titleE]) { + titleE-- + } + + // check for closing quote presence + if data[titleE] != '\'' && data[titleE] != '"' { + titleB, titleE = 0, 0 + linkE = i + } + } + + // remove whitespace at the end of the link + for linkE > linkB && isspace(data[linkE-1]) { + linkE-- + } + + // remove optional angle brackets around the link + if data[linkB] == '<' { + linkB++ + } + if data[linkE-1] == '>' { + linkE-- + } + + // build escaped link and title + if linkE > linkB { + link = data[linkB:linkE] + } + + if titleE > titleB { + title = data[titleB:titleE] + } + + i++ + + // reference style link + case isReferenceStyleLink(data, i, t): + var id []byte + altContentConsidered := false + + // look for the id + i++ + linkB := i + for i < len(data) && data[i] != ']' { + i++ + } + if i >= len(data) { + return 0, nil + } + linkE := i + + // find the reference + if linkB == linkE { + if textHasNl { + var b bytes.Buffer + + for j := 1; j < txtE; j++ { + switch { + case data[j] != '\n': + b.WriteByte(data[j]) + case data[j-1] != ' ': + b.WriteByte(' ') + } + } + + id = b.Bytes() + } else { + id = data[1:txtE] + altContentConsidered = true + } + } else { + id = data[linkB:linkE] + } + + // find the reference with matching id + lr, ok := p.getRef(string(id)) + if !ok { + return 0, nil + } + + // keep link and title from reference + link = lr.link + title = lr.title + if altContentConsidered { + altContent = lr.text + } + i++ + + // shortcut reference style link or reference or inline footnote + default: + var id []byte + + // craft the id + if textHasNl { + var b bytes.Buffer + + for j := 1; j < txtE; j++ { + switch { + case data[j] != '\n': + b.WriteByte(data[j]) + case data[j-1] != ' ': + b.WriteByte(' ') + } + } + + id = b.Bytes() + } else { + if t == linkDeferredFootnote { + id = data[2:txtE] // get rid of the ^ + } else { + id = data[1:txtE] + } + } + + footnoteNode = NewNode(Item) + if t == linkInlineFootnote { + // create a new reference + noteID = len(p.notes) + 1 + + var fragment []byte + if len(id) > 0 { + if len(id) < 16 { + fragment = make([]byte, len(id)) + } else { + fragment = make([]byte, 16) + } + copy(fragment, slugify(id)) + } else { + fragment = append([]byte("footnote-"), []byte(strconv.Itoa(noteID))...) + } + + ref := &reference{ + noteID: noteID, + hasBlock: false, + link: fragment, + title: id, + footnote: footnoteNode, + } + + p.notes = append(p.notes, ref) + + link = ref.link + title = ref.title + } else { + // find the reference with matching id + lr, ok := p.getRef(string(id)) + if !ok { + return 0, nil + } + + if t == linkDeferredFootnote { + lr.noteID = len(p.notes) + 1 + lr.footnote = footnoteNode + p.notes = append(p.notes, lr) + } + + // keep link and title from reference + link = lr.link + // if inline footnote, title == footnote contents + title = lr.title + noteID = lr.noteID + } + + // rewind the whitespace + i = txtE + 1 + } + + var uLink []byte + if t == linkNormal || t == linkImg { + if len(link) > 0 { + var uLinkBuf bytes.Buffer + unescapeText(&uLinkBuf, link) + uLink = uLinkBuf.Bytes() + } + + // links need something to click on and somewhere to go + if len(uLink) == 0 || (t == linkNormal && txtE <= 1) { + return 0, nil + } + } + + // call the relevant rendering function + var linkNode *Node + switch t { + case linkNormal: + linkNode = NewNode(Link) + linkNode.Destination = normalizeURI(uLink) + linkNode.Title = title + if len(altContent) > 0 { + linkNode.AppendChild(text(altContent)) + } else { + // links cannot contain other links, so turn off link parsing + // temporarily and recurse + insideLink := p.insideLink + p.insideLink = true + p.inline(linkNode, data[1:txtE]) + p.insideLink = insideLink + } + + case linkImg: + linkNode = NewNode(Image) + linkNode.Destination = uLink + linkNode.Title = title + linkNode.AppendChild(text(data[1:txtE])) + i++ + + case linkInlineFootnote, linkDeferredFootnote: + linkNode = NewNode(Link) + linkNode.Destination = link + linkNode.Title = title + linkNode.NoteID = noteID + linkNode.Footnote = footnoteNode + if t == linkInlineFootnote { + i++ + } + + default: + return 0, nil + } + + return i, linkNode +} + +func (p *Markdown) inlineHTMLComment(data []byte) int { + if len(data) < 5 { + return 0 + } + if data[0] != '<' || data[1] != '!' || data[2] != '-' || data[3] != '-' { + return 0 + } + i := 5 + // scan for an end-of-comment marker, across lines if necessary + for i < len(data) && !(data[i-2] == '-' && data[i-1] == '-' && data[i] == '>') { + i++ + } + // no end-of-comment marker + if i >= len(data) { + return 0 + } + return i + 1 +} + +func stripMailto(link []byte) []byte { + if bytes.HasPrefix(link, []byte("mailto://")) { + return link[9:] + } else if bytes.HasPrefix(link, []byte("mailto:")) { + return link[7:] + } else { + return link + } +} + +// autolinkType specifies a kind of autolink that gets detected. +type autolinkType int + +// These are the possible flag values for the autolink renderer. +const ( + notAutolink autolinkType = iota + normalAutolink + emailAutolink +) + +// '<' when tags or autolinks are allowed +func leftAngle(p *Markdown, data []byte, offset int) (int, *Node) { + data = data[offset:] + altype, end := tagLength(data) + if size := p.inlineHTMLComment(data); size > 0 { + end = size + } + if end > 2 { + if altype != notAutolink { + var uLink bytes.Buffer + unescapeText(&uLink, data[1:end+1-2]) + if uLink.Len() > 0 { + link := uLink.Bytes() + node := NewNode(Link) + node.Destination = link + if altype == emailAutolink { + node.Destination = append([]byte("mailto:"), link...) + } + node.AppendChild(text(stripMailto(link))) + return end, node + } + } else { + htmlTag := NewNode(HTMLSpan) + htmlTag.Literal = data[:end] + return end, htmlTag + } + } + + return end, nil +} + +// '\\' backslash escape +var escapeChars = []byte("\\`*_{}[]()#+-.!:|&<>~") + +func escape(p *Markdown, data []byte, offset int) (int, *Node) { + data = data[offset:] + + if len(data) > 1 { + if p.extensions&BackslashLineBreak != 0 && data[1] == '\n' { + return 2, NewNode(Hardbreak) + } + if bytes.IndexByte(escapeChars, data[1]) < 0 { + return 0, nil + } + + return 2, text(data[1:2]) + } + + return 2, nil +} + +func unescapeText(ob *bytes.Buffer, src []byte) { + i := 0 + for i < len(src) { + org := i + for i < len(src) && src[i] != '\\' { + i++ + } + + if i > org { + ob.Write(src[org:i]) + } + + if i+1 >= len(src) { + break + } + + ob.WriteByte(src[i+1]) + i += 2 + } +} + +// '&' escaped when it doesn't belong to an entity +// valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; +func entity(p *Markdown, data []byte, offset int) (int, *Node) { + data = data[offset:] + + end := 1 + + if end < len(data) && data[end] == '#' { + end++ + } + + for end < len(data) && isalnum(data[end]) { + end++ + } + + if end < len(data) && data[end] == ';' { + end++ // real entity + } else { + return 0, nil // lone '&' + } + + ent := data[:end] + // undo & escaping or it will be converted to &amp; by another + // escaper in the renderer + if bytes.Equal(ent, []byte("&")) { + ent = []byte{'&'} + } + + return end, text(ent) +} + +func linkEndsWithEntity(data []byte, linkEnd int) bool { + entityRanges := htmlEntityRe.FindAllIndex(data[:linkEnd], -1) + return entityRanges != nil && entityRanges[len(entityRanges)-1][1] == linkEnd +} + +// hasPrefixCaseInsensitive is a custom implementation of +// strings.HasPrefix(strings.ToLower(s), prefix) +// we rolled our own because ToLower pulls in a huge machinery of lowercasing +// anything from Unicode and that's very slow. Since this func will only be +// used on ASCII protocol prefixes, we can take shortcuts. +func hasPrefixCaseInsensitive(s, prefix []byte) bool { + if len(s) < len(prefix) { + return false + } + delta := byte('a' - 'A') + for i, b := range prefix { + if b != s[i] && b != s[i]+delta { + return false + } + } + return true +} + +var protocolPrefixes = [][]byte{ + []byte("http://"), + []byte("https://"), + []byte("ftp://"), + []byte("file://"), + []byte("mailto:"), +} + +const shortestPrefix = 6 // len("ftp://"), the shortest of the above + +func maybeAutoLink(p *Markdown, data []byte, offset int) (int, *Node) { + // quick check to rule out most false hits + if p.insideLink || len(data) < offset+shortestPrefix { + return 0, nil + } + for _, prefix := range protocolPrefixes { + endOfHead := offset + 8 // 8 is the len() of the longest prefix + if endOfHead > len(data) { + endOfHead = len(data) + } + if hasPrefixCaseInsensitive(data[offset:endOfHead], prefix) { + return autoLink(p, data, offset) + } + } + return 0, nil +} + +func autoLink(p *Markdown, data []byte, offset int) (int, *Node) { + // Now a more expensive check to see if we're not inside an anchor element + anchorStart := offset + offsetFromAnchor := 0 + for anchorStart > 0 && data[anchorStart] != '<' { + anchorStart-- + offsetFromAnchor++ + } + + anchorStr := anchorRe.Find(data[anchorStart:]) + if anchorStr != nil { + anchorClose := NewNode(HTMLSpan) + anchorClose.Literal = anchorStr[offsetFromAnchor:] + return len(anchorStr) - offsetFromAnchor, anchorClose + } + + // scan backward for a word boundary + rewind := 0 + for offset-rewind > 0 && rewind <= 7 && isletter(data[offset-rewind-1]) { + rewind++ + } + if rewind > 6 { // longest supported protocol is "mailto" which has 6 letters + return 0, nil + } + + origData := data + data = data[offset-rewind:] + + if !isSafeLink(data) { + return 0, nil + } + + linkEnd := 0 + for linkEnd < len(data) && !isEndOfLink(data[linkEnd]) { + linkEnd++ + } + + // Skip punctuation at the end of the link + if (data[linkEnd-1] == '.' || data[linkEnd-1] == ',') && data[linkEnd-2] != '\\' { + linkEnd-- + } + + // But don't skip semicolon if it's a part of escaped entity: + if data[linkEnd-1] == ';' && data[linkEnd-2] != '\\' && !linkEndsWithEntity(data, linkEnd) { + linkEnd-- + } + + // See if the link finishes with a punctuation sign that can be closed. + var copen byte + switch data[linkEnd-1] { + case '"': + copen = '"' + case '\'': + copen = '\'' + case ')': + copen = '(' + case ']': + copen = '[' + case '}': + copen = '{' + default: + copen = 0 + } + + if copen != 0 { + bufEnd := offset - rewind + linkEnd - 2 + + openDelim := 1 + + /* Try to close the final punctuation sign in this same line; + * if we managed to close it outside of the URL, that means that it's + * not part of the URL. If it closes inside the URL, that means it + * is part of the URL. + * + * Examples: + * + * foo http://www.pokemon.com/Pikachu_(Electric) bar + * => http://www.pokemon.com/Pikachu_(Electric) + * + * foo (http://www.pokemon.com/Pikachu_(Electric)) bar + * => http://www.pokemon.com/Pikachu_(Electric) + * + * foo http://www.pokemon.com/Pikachu_(Electric)) bar + * => http://www.pokemon.com/Pikachu_(Electric)) + * + * (foo http://www.pokemon.com/Pikachu_(Electric)) bar + * => foo http://www.pokemon.com/Pikachu_(Electric) + */ + + for bufEnd >= 0 && origData[bufEnd] != '\n' && openDelim != 0 { + if origData[bufEnd] == data[linkEnd-1] { + openDelim++ + } + + if origData[bufEnd] == copen { + openDelim-- + } + + bufEnd-- + } + + if openDelim == 0 { + linkEnd-- + } + } + + var uLink bytes.Buffer + unescapeText(&uLink, data[:linkEnd]) + + if uLink.Len() > 0 { + node := NewNode(Link) + node.Destination = uLink.Bytes() + node.AppendChild(text(uLink.Bytes())) + return linkEnd, node + } + + return linkEnd, nil +} + +func isEndOfLink(char byte) bool { + return isspace(char) || char == '<' +} + +var validUris = [][]byte{[]byte("http://"), []byte("https://"), []byte("ftp://"), []byte("mailto://")} +var validPaths = [][]byte{[]byte("/"), []byte("./"), []byte("../")} + +func isSafeLink(link []byte) bool { + for _, path := range validPaths { + if len(link) >= len(path) && bytes.Equal(link[:len(path)], path) { + if len(link) == len(path) { + return true + } else if isalnum(link[len(path)]) { + return true + } + } + } + + for _, prefix := range validUris { + // TODO: handle unicode here + // case-insensitive prefix test + if len(link) > len(prefix) && bytes.Equal(bytes.ToLower(link[:len(prefix)]), prefix) && isalnum(link[len(prefix)]) { + return true + } + } + + return false +} + +// return the length of the given tag, or 0 is it's not valid +func tagLength(data []byte) (autolink autolinkType, end int) { + var i, j int + + // a valid tag can't be shorter than 3 chars + if len(data) < 3 { + return notAutolink, 0 + } + + // begins with a '<' optionally followed by '/', followed by letter or number + if data[0] != '<' { + return notAutolink, 0 + } + if data[1] == '/' { + i = 2 + } else { + i = 1 + } + + if !isalnum(data[i]) { + return notAutolink, 0 + } + + // scheme test + autolink = notAutolink + + // try to find the beginning of an URI + for i < len(data) && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-') { + i++ + } + + if i > 1 && i < len(data) && data[i] == '@' { + if j = isMailtoAutoLink(data[i:]); j != 0 { + return emailAutolink, i + j + } + } + + if i > 2 && i < len(data) && data[i] == ':' { + autolink = normalAutolink + i++ + } + + // complete autolink test: no whitespace or ' or " + switch { + case i >= len(data): + autolink = notAutolink + case autolink != notAutolink: + j = i + + for i < len(data) { + if data[i] == '\\' { + i += 2 + } else if data[i] == '>' || data[i] == '\'' || data[i] == '"' || isspace(data[i]) { + break + } else { + i++ + } + + } + + if i >= len(data) { + return autolink, 0 + } + if i > j && data[i] == '>' { + return autolink, i + 1 + } + + // one of the forbidden chars has been found + autolink = notAutolink + } + i += bytes.IndexByte(data[i:], '>') + if i < 0 { + return autolink, 0 + } + return autolink, i + 1 +} + +// look for the address part of a mail autolink and '>' +// this is less strict than the original markdown e-mail address matching +func isMailtoAutoLink(data []byte) int { + nb := 0 + + // address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' + for i := 0; i < len(data); i++ { + if isalnum(data[i]) { + continue + } + + switch data[i] { + case '@': + nb++ + + case '-', '.', '_': + break + + case '>': + if nb == 1 { + return i + 1 + } + return 0 + default: + return 0 + } + } + + return 0 +} + +// look for the next emph char, skipping other constructs +func helperFindEmphChar(data []byte, c byte) int { + i := 0 + + for i < len(data) { + for i < len(data) && data[i] != c && data[i] != '`' && data[i] != '[' { + i++ + } + if i >= len(data) { + return 0 + } + // do not count escaped chars + if i != 0 && data[i-1] == '\\' { + i++ + continue + } + if data[i] == c { + return i + } + + if data[i] == '`' { + // skip a code span + tmpI := 0 + i++ + for i < len(data) && data[i] != '`' { + if tmpI == 0 && data[i] == c { + tmpI = i + } + i++ + } + if i >= len(data) { + return tmpI + } + i++ + } else if data[i] == '[' { + // skip a link + tmpI := 0 + i++ + for i < len(data) && data[i] != ']' { + if tmpI == 0 && data[i] == c { + tmpI = i + } + i++ + } + i++ + for i < len(data) && (data[i] == ' ' || data[i] == '\n') { + i++ + } + if i >= len(data) { + return tmpI + } + if data[i] != '[' && data[i] != '(' { // not a link + if tmpI > 0 { + return tmpI + } + continue + } + cc := data[i] + i++ + for i < len(data) && data[i] != cc { + if tmpI == 0 && data[i] == c { + return i + } + i++ + } + if i >= len(data) { + return tmpI + } + i++ + } + } + return 0 +} + +func helperEmphasis(p *Markdown, data []byte, c byte) (int, *Node) { + i := 0 + + // skip one symbol if coming from emph3 + if len(data) > 1 && data[0] == c && data[1] == c { + i = 1 + } + + for i < len(data) { + length := helperFindEmphChar(data[i:], c) + if length == 0 { + return 0, nil + } + i += length + if i >= len(data) { + return 0, nil + } + + if i+1 < len(data) && data[i+1] == c { + i++ + continue + } + + if data[i] == c && !isspace(data[i-1]) { + + if p.extensions&NoIntraEmphasis != 0 { + if !(i+1 == len(data) || isspace(data[i+1]) || ispunct(data[i+1])) { + continue + } + } + + emph := NewNode(Emph) + p.inline(emph, data[:i]) + return i + 1, emph + } + } + + return 0, nil +} + +func helperDoubleEmphasis(p *Markdown, data []byte, c byte) (int, *Node) { + i := 0 + + for i < len(data) { + length := helperFindEmphChar(data[i:], c) + if length == 0 { + return 0, nil + } + i += length + + if i+1 < len(data) && data[i] == c && data[i+1] == c && i > 0 && !isspace(data[i-1]) { + nodeType := Strong + if c == '~' { + nodeType = Del + } + node := NewNode(nodeType) + p.inline(node, data[:i]) + return i + 2, node + } + i++ + } + return 0, nil +} + +func helperTripleEmphasis(p *Markdown, data []byte, offset int, c byte) (int, *Node) { + i := 0 + origData := data + data = data[offset:] + + for i < len(data) { + length := helperFindEmphChar(data[i:], c) + if length == 0 { + return 0, nil + } + i += length + + // skip whitespace preceded symbols + if data[i] != c || isspace(data[i-1]) { + continue + } + + switch { + case i+2 < len(data) && data[i+1] == c && data[i+2] == c: + // triple symbol found + strong := NewNode(Strong) + em := NewNode(Emph) + strong.AppendChild(em) + p.inline(em, data[:i]) + return i + 3, strong + case (i+1 < len(data) && data[i+1] == c): + // double symbol found, hand over to emph1 + length, node := helperEmphasis(p, origData[offset-2:], c) + if length == 0 { + return 0, nil + } + return length - 2, node + default: + // single symbol found, hand over to emph2 + length, node := helperDoubleEmphasis(p, origData[offset-1:], c) + if length == 0 { + return 0, nil + } + return length - 1, node + } + } + return 0, nil +} + +func text(s []byte) *Node { + node := NewNode(Text) + node.Literal = s + return node +} + +func normalizeURI(s []byte) []byte { + return s // TODO: implement +} diff --git a/vendor/github.com/russross/blackfriday/v2/markdown.go b/vendor/github.com/russross/blackfriday/v2/markdown.go new file mode 100644 index 000000000..58d2e4538 --- /dev/null +++ b/vendor/github.com/russross/blackfriday/v2/markdown.go @@ -0,0 +1,950 @@ +// Blackfriday Markdown Processor +// Available at http://github.com/russross/blackfriday +// +// Copyright © 2011 Russ Ross . +// Distributed under the Simplified BSD License. +// See README.md for details. + +package blackfriday + +import ( + "bytes" + "fmt" + "io" + "strings" + "unicode/utf8" +) + +// +// Markdown parsing and processing +// + +// Version string of the package. Appears in the rendered document when +// CompletePage flag is on. +const Version = "2.0" + +// Extensions is a bitwise or'ed collection of enabled Blackfriday's +// extensions. +type Extensions int + +// These are the supported markdown parsing extensions. +// OR these values together to select multiple extensions. +const ( + NoExtensions Extensions = 0 + NoIntraEmphasis Extensions = 1 << iota // Ignore emphasis markers inside words + Tables // Render tables + FencedCode // Render fenced code blocks + Autolink // Detect embedded URLs that are not explicitly marked + Strikethrough // Strikethrough text using ~~test~~ + LaxHTMLBlocks // Loosen up HTML block parsing rules + SpaceHeadings // Be strict about prefix heading rules + HardLineBreak // Translate newlines into line breaks + TabSizeEight // Expand tabs to eight spaces instead of four + Footnotes // Pandoc-style footnotes + NoEmptyLineBeforeBlock // No need to insert an empty line to start a (code, quote, ordered list, unordered list) block + HeadingIDs // specify heading IDs with {#id} + Titleblock // Titleblock ala pandoc + AutoHeadingIDs // Create the heading ID from the text + BackslashLineBreak // Translate trailing backslashes into line breaks + DefinitionLists // Render definition lists + + CommonHTMLFlags HTMLFlags = UseXHTML | Smartypants | + SmartypantsFractions | SmartypantsDashes | SmartypantsLatexDashes + + CommonExtensions Extensions = NoIntraEmphasis | Tables | FencedCode | + Autolink | Strikethrough | SpaceHeadings | HeadingIDs | + BackslashLineBreak | DefinitionLists +) + +// ListType contains bitwise or'ed flags for list and list item objects. +type ListType int + +// These are the possible flag values for the ListItem renderer. +// Multiple flag values may be ORed together. +// These are mostly of interest if you are writing a new output format. +const ( + ListTypeOrdered ListType = 1 << iota + ListTypeDefinition + ListTypeTerm + + ListItemContainsBlock + ListItemBeginningOfList // TODO: figure out if this is of any use now + ListItemEndOfList +) + +// CellAlignFlags holds a type of alignment in a table cell. +type CellAlignFlags int + +// These are the possible flag values for the table cell renderer. +// Only a single one of these values will be used; they are not ORed together. +// These are mostly of interest if you are writing a new output format. +const ( + TableAlignmentLeft CellAlignFlags = 1 << iota + TableAlignmentRight + TableAlignmentCenter = (TableAlignmentLeft | TableAlignmentRight) +) + +// The size of a tab stop. +const ( + TabSizeDefault = 4 + TabSizeDouble = 8 +) + +// blockTags is a set of tags that are recognized as HTML block tags. +// Any of these can be included in markdown text without special escaping. +var blockTags = map[string]struct{}{ + "blockquote": {}, + "del": {}, + "div": {}, + "dl": {}, + "fieldset": {}, + "form": {}, + "h1": {}, + "h2": {}, + "h3": {}, + "h4": {}, + "h5": {}, + "h6": {}, + "iframe": {}, + "ins": {}, + "math": {}, + "noscript": {}, + "ol": {}, + "pre": {}, + "p": {}, + "script": {}, + "style": {}, + "table": {}, + "ul": {}, + + // HTML5 + "address": {}, + "article": {}, + "aside": {}, + "canvas": {}, + "figcaption": {}, + "figure": {}, + "footer": {}, + "header": {}, + "hgroup": {}, + "main": {}, + "nav": {}, + "output": {}, + "progress": {}, + "section": {}, + "video": {}, +} + +// Renderer is the rendering interface. This is mostly of interest if you are +// implementing a new rendering format. +// +// Only an HTML implementation is provided in this repository, see the README +// for external implementations. +type Renderer interface { + // RenderNode is the main rendering method. It will be called once for + // every leaf node and twice for every non-leaf node (first with + // entering=true, then with entering=false). The method should write its + // rendition of the node to the supplied writer w. + RenderNode(w io.Writer, node *Node, entering bool) WalkStatus + + // RenderHeader is a method that allows the renderer to produce some + // content preceding the main body of the output document. The header is + // understood in the broad sense here. For example, the default HTML + // renderer will write not only the HTML document preamble, but also the + // table of contents if it was requested. + // + // The method will be passed an entire document tree, in case a particular + // implementation needs to inspect it to produce output. + // + // The output should be written to the supplied writer w. If your + // implementation has no header to write, supply an empty implementation. + RenderHeader(w io.Writer, ast *Node) + + // RenderFooter is a symmetric counterpart of RenderHeader. + RenderFooter(w io.Writer, ast *Node) +} + +// Callback functions for inline parsing. One such function is defined +// for each character that triggers a response when parsing inline data. +type inlineParser func(p *Markdown, data []byte, offset int) (int, *Node) + +// Markdown is a type that holds extensions and the runtime state used by +// Parse, and the renderer. You can not use it directly, construct it with New. +type Markdown struct { + renderer Renderer + referenceOverride ReferenceOverrideFunc + refs map[string]*reference + inlineCallback [256]inlineParser + extensions Extensions + nesting int + maxNesting int + insideLink bool + + // Footnotes need to be ordered as well as available to quickly check for + // presence. If a ref is also a footnote, it's stored both in refs and here + // in notes. Slice is nil if footnotes not enabled. + notes []*reference + + doc *Node + tip *Node // = doc + oldTip *Node + lastMatchedContainer *Node // = doc + allClosed bool +} + +func (p *Markdown) getRef(refid string) (ref *reference, found bool) { + if p.referenceOverride != nil { + r, overridden := p.referenceOverride(refid) + if overridden { + if r == nil { + return nil, false + } + return &reference{ + link: []byte(r.Link), + title: []byte(r.Title), + noteID: 0, + hasBlock: false, + text: []byte(r.Text)}, true + } + } + // refs are case insensitive + ref, found = p.refs[strings.ToLower(refid)] + return ref, found +} + +func (p *Markdown) finalize(block *Node) { + above := block.Parent + block.open = false + p.tip = above +} + +func (p *Markdown) addChild(node NodeType, offset uint32) *Node { + return p.addExistingChild(NewNode(node), offset) +} + +func (p *Markdown) addExistingChild(node *Node, offset uint32) *Node { + for !p.tip.canContain(node.Type) { + p.finalize(p.tip) + } + p.tip.AppendChild(node) + p.tip = node + return node +} + +func (p *Markdown) closeUnmatchedBlocks() { + if !p.allClosed { + for p.oldTip != p.lastMatchedContainer { + parent := p.oldTip.Parent + p.finalize(p.oldTip) + p.oldTip = parent + } + p.allClosed = true + } +} + +// +// +// Public interface +// +// + +// Reference represents the details of a link. +// See the documentation in Options for more details on use-case. +type Reference struct { + // Link is usually the URL the reference points to. + Link string + // Title is the alternate text describing the link in more detail. + Title string + // Text is the optional text to override the ref with if the syntax used was + // [refid][] + Text string +} + +// ReferenceOverrideFunc is expected to be called with a reference string and +// return either a valid Reference type that the reference string maps to or +// nil. If overridden is false, the default reference logic will be executed. +// See the documentation in Options for more details on use-case. +type ReferenceOverrideFunc func(reference string) (ref *Reference, overridden bool) + +// New constructs a Markdown processor. You can use the same With* functions as +// for Run() to customize parser's behavior and the renderer. +func New(opts ...Option) *Markdown { + var p Markdown + for _, opt := range opts { + opt(&p) + } + p.refs = make(map[string]*reference) + p.maxNesting = 16 + p.insideLink = false + docNode := NewNode(Document) + p.doc = docNode + p.tip = docNode + p.oldTip = docNode + p.lastMatchedContainer = docNode + p.allClosed = true + // register inline parsers + p.inlineCallback[' '] = maybeLineBreak + p.inlineCallback['*'] = emphasis + p.inlineCallback['_'] = emphasis + if p.extensions&Strikethrough != 0 { + p.inlineCallback['~'] = emphasis + } + p.inlineCallback['`'] = codeSpan + p.inlineCallback['\n'] = lineBreak + p.inlineCallback['['] = link + p.inlineCallback['<'] = leftAngle + p.inlineCallback['\\'] = escape + p.inlineCallback['&'] = entity + p.inlineCallback['!'] = maybeImage + p.inlineCallback['^'] = maybeInlineFootnote + if p.extensions&Autolink != 0 { + p.inlineCallback['h'] = maybeAutoLink + p.inlineCallback['m'] = maybeAutoLink + p.inlineCallback['f'] = maybeAutoLink + p.inlineCallback['H'] = maybeAutoLink + p.inlineCallback['M'] = maybeAutoLink + p.inlineCallback['F'] = maybeAutoLink + } + if p.extensions&Footnotes != 0 { + p.notes = make([]*reference, 0) + } + return &p +} + +// Option customizes the Markdown processor's default behavior. +type Option func(*Markdown) + +// WithRenderer allows you to override the default renderer. +func WithRenderer(r Renderer) Option { + return func(p *Markdown) { + p.renderer = r + } +} + +// WithExtensions allows you to pick some of the many extensions provided by +// Blackfriday. You can bitwise OR them. +func WithExtensions(e Extensions) Option { + return func(p *Markdown) { + p.extensions = e + } +} + +// WithNoExtensions turns off all extensions and custom behavior. +func WithNoExtensions() Option { + return func(p *Markdown) { + p.extensions = NoExtensions + p.renderer = NewHTMLRenderer(HTMLRendererParameters{ + Flags: HTMLFlagsNone, + }) + } +} + +// WithRefOverride sets an optional function callback that is called every +// time a reference is resolved. +// +// In Markdown, the link reference syntax can be made to resolve a link to +// a reference instead of an inline URL, in one of the following ways: +// +// * [link text][refid] +// * [refid][] +// +// Usually, the refid is defined at the bottom of the Markdown document. If +// this override function is provided, the refid is passed to the override +// function first, before consulting the defined refids at the bottom. If +// the override function indicates an override did not occur, the refids at +// the bottom will be used to fill in the link details. +func WithRefOverride(o ReferenceOverrideFunc) Option { + return func(p *Markdown) { + p.referenceOverride = o + } +} + +// Run is the main entry point to Blackfriday. It parses and renders a +// block of markdown-encoded text. +// +// The simplest invocation of Run takes one argument, input: +// output := Run(input) +// This will parse the input with CommonExtensions enabled and render it with +// the default HTMLRenderer (with CommonHTMLFlags). +// +// Variadic arguments opts can customize the default behavior. Since Markdown +// type does not contain exported fields, you can not use it directly. Instead, +// use the With* functions. For example, this will call the most basic +// functionality, with no extensions: +// output := Run(input, WithNoExtensions()) +// +// You can use any number of With* arguments, even contradicting ones. They +// will be applied in order of appearance and the latter will override the +// former: +// output := Run(input, WithNoExtensions(), WithExtensions(exts), +// WithRenderer(yourRenderer)) +func Run(input []byte, opts ...Option) []byte { + r := NewHTMLRenderer(HTMLRendererParameters{ + Flags: CommonHTMLFlags, + }) + optList := []Option{WithRenderer(r), WithExtensions(CommonExtensions)} + optList = append(optList, opts...) + parser := New(optList...) + ast := parser.Parse(input) + var buf bytes.Buffer + parser.renderer.RenderHeader(&buf, ast) + ast.Walk(func(node *Node, entering bool) WalkStatus { + return parser.renderer.RenderNode(&buf, node, entering) + }) + parser.renderer.RenderFooter(&buf, ast) + return buf.Bytes() +} + +// Parse is an entry point to the parsing part of Blackfriday. It takes an +// input markdown document and produces a syntax tree for its contents. This +// tree can then be rendered with a default or custom renderer, or +// analyzed/transformed by the caller to whatever non-standard needs they have. +// The return value is the root node of the syntax tree. +func (p *Markdown) Parse(input []byte) *Node { + p.block(input) + // Walk the tree and finish up some of unfinished blocks + for p.tip != nil { + p.finalize(p.tip) + } + // Walk the tree again and process inline markdown in each block + p.doc.Walk(func(node *Node, entering bool) WalkStatus { + if node.Type == Paragraph || node.Type == Heading || node.Type == TableCell { + p.inline(node, node.content) + node.content = nil + } + return GoToNext + }) + p.parseRefsToAST() + return p.doc +} + +func (p *Markdown) parseRefsToAST() { + if p.extensions&Footnotes == 0 || len(p.notes) == 0 { + return + } + p.tip = p.doc + block := p.addBlock(List, nil) + block.IsFootnotesList = true + block.ListFlags = ListTypeOrdered + flags := ListItemBeginningOfList + // Note: this loop is intentionally explicit, not range-form. This is + // because the body of the loop will append nested footnotes to p.notes and + // we need to process those late additions. Range form would only walk over + // the fixed initial set. + for i := 0; i < len(p.notes); i++ { + ref := p.notes[i] + p.addExistingChild(ref.footnote, 0) + block := ref.footnote + block.ListFlags = flags | ListTypeOrdered + block.RefLink = ref.link + if ref.hasBlock { + flags |= ListItemContainsBlock + p.block(ref.title) + } else { + p.inline(block, ref.title) + } + flags &^= ListItemBeginningOfList | ListItemContainsBlock + } + above := block.Parent + finalizeList(block) + p.tip = above + block.Walk(func(node *Node, entering bool) WalkStatus { + if node.Type == Paragraph || node.Type == Heading { + p.inline(node, node.content) + node.content = nil + } + return GoToNext + }) +} + +// +// Link references +// +// This section implements support for references that (usually) appear +// as footnotes in a document, and can be referenced anywhere in the document. +// The basic format is: +// +// [1]: http://www.google.com/ "Google" +// [2]: http://www.github.com/ "Github" +// +// Anywhere in the document, the reference can be linked by referring to its +// label, i.e., 1 and 2 in this example, as in: +// +// This library is hosted on [Github][2], a git hosting site. +// +// Actual footnotes as specified in Pandoc and supported by some other Markdown +// libraries such as php-markdown are also taken care of. They look like this: +// +// This sentence needs a bit of further explanation.[^note] +// +// [^note]: This is the explanation. +// +// Footnotes should be placed at the end of the document in an ordered list. +// Finally, there are inline footnotes such as: +// +// Inline footnotes^[Also supported.] provide a quick inline explanation, +// but are rendered at the bottom of the document. +// + +// reference holds all information necessary for a reference-style links or +// footnotes. +// +// Consider this markdown with reference-style links: +// +// [link][ref] +// +// [ref]: /url/ "tooltip title" +// +// It will be ultimately converted to this HTML: +// +//

    link

    +// +// And a reference structure will be populated as follows: +// +// p.refs["ref"] = &reference{ +// link: "/url/", +// title: "tooltip title", +// } +// +// Alternatively, reference can contain information about a footnote. Consider +// this markdown: +// +// Text needing a footnote.[^a] +// +// [^a]: This is the note +// +// A reference structure will be populated as follows: +// +// p.refs["a"] = &reference{ +// link: "a", +// title: "This is the note", +// noteID: , +// } +// +// TODO: As you can see, it begs for splitting into two dedicated structures +// for refs and for footnotes. +type reference struct { + link []byte + title []byte + noteID int // 0 if not a footnote ref + hasBlock bool + footnote *Node // a link to the Item node within a list of footnotes + + text []byte // only gets populated by refOverride feature with Reference.Text +} + +func (r *reference) String() string { + return fmt.Sprintf("{link: %q, title: %q, text: %q, noteID: %d, hasBlock: %v}", + r.link, r.title, r.text, r.noteID, r.hasBlock) +} + +// Check whether or not data starts with a reference link. +// If so, it is parsed and stored in the list of references +// (in the render struct). +// Returns the number of bytes to skip to move past it, +// or zero if the first line is not a reference. +func isReference(p *Markdown, data []byte, tabSize int) int { + // up to 3 optional leading spaces + if len(data) < 4 { + return 0 + } + i := 0 + for i < 3 && data[i] == ' ' { + i++ + } + + noteID := 0 + + // id part: anything but a newline between brackets + if data[i] != '[' { + return 0 + } + i++ + if p.extensions&Footnotes != 0 { + if i < len(data) && data[i] == '^' { + // we can set it to anything here because the proper noteIds will + // be assigned later during the second pass. It just has to be != 0 + noteID = 1 + i++ + } + } + idOffset := i + for i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != ']' { + i++ + } + if i >= len(data) || data[i] != ']' { + return 0 + } + idEnd := i + // footnotes can have empty ID, like this: [^], but a reference can not be + // empty like this: []. Break early if it's not a footnote and there's no ID + if noteID == 0 && idOffset == idEnd { + return 0 + } + // spacer: colon (space | tab)* newline? (space | tab)* + i++ + if i >= len(data) || data[i] != ':' { + return 0 + } + i++ + for i < len(data) && (data[i] == ' ' || data[i] == '\t') { + i++ + } + if i < len(data) && (data[i] == '\n' || data[i] == '\r') { + i++ + if i < len(data) && data[i] == '\n' && data[i-1] == '\r' { + i++ + } + } + for i < len(data) && (data[i] == ' ' || data[i] == '\t') { + i++ + } + if i >= len(data) { + return 0 + } + + var ( + linkOffset, linkEnd int + titleOffset, titleEnd int + lineEnd int + raw []byte + hasBlock bool + ) + + if p.extensions&Footnotes != 0 && noteID != 0 { + linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize) + lineEnd = linkEnd + } else { + linkOffset, linkEnd, titleOffset, titleEnd, lineEnd = scanLinkRef(p, data, i) + } + if lineEnd == 0 { + return 0 + } + + // a valid ref has been found + + ref := &reference{ + noteID: noteID, + hasBlock: hasBlock, + } + + if noteID > 0 { + // reusing the link field for the id since footnotes don't have links + ref.link = data[idOffset:idEnd] + // if footnote, it's not really a title, it's the contained text + ref.title = raw + } else { + ref.link = data[linkOffset:linkEnd] + ref.title = data[titleOffset:titleEnd] + } + + // id matches are case-insensitive + id := string(bytes.ToLower(data[idOffset:idEnd])) + + p.refs[id] = ref + + return lineEnd +} + +func scanLinkRef(p *Markdown, data []byte, i int) (linkOffset, linkEnd, titleOffset, titleEnd, lineEnd int) { + // link: whitespace-free sequence, optionally between angle brackets + if data[i] == '<' { + i++ + } + linkOffset = i + for i < len(data) && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r' { + i++ + } + linkEnd = i + if data[linkOffset] == '<' && data[linkEnd-1] == '>' { + linkOffset++ + linkEnd-- + } + + // optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) + for i < len(data) && (data[i] == ' ' || data[i] == '\t') { + i++ + } + if i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != '\'' && data[i] != '"' && data[i] != '(' { + return + } + + // compute end-of-line + if i >= len(data) || data[i] == '\r' || data[i] == '\n' { + lineEnd = i + } + if i+1 < len(data) && data[i] == '\r' && data[i+1] == '\n' { + lineEnd++ + } + + // optional (space|tab)* spacer after a newline + if lineEnd > 0 { + i = lineEnd + 1 + for i < len(data) && (data[i] == ' ' || data[i] == '\t') { + i++ + } + } + + // optional title: any non-newline sequence enclosed in '"() alone on its line + if i+1 < len(data) && (data[i] == '\'' || data[i] == '"' || data[i] == '(') { + i++ + titleOffset = i + + // look for EOL + for i < len(data) && data[i] != '\n' && data[i] != '\r' { + i++ + } + if i+1 < len(data) && data[i] == '\n' && data[i+1] == '\r' { + titleEnd = i + 1 + } else { + titleEnd = i + } + + // step back + i-- + for i > titleOffset && (data[i] == ' ' || data[i] == '\t') { + i-- + } + if i > titleOffset && (data[i] == '\'' || data[i] == '"' || data[i] == ')') { + lineEnd = titleEnd + titleEnd = i + } + } + + return +} + +// The first bit of this logic is the same as Parser.listItem, but the rest +// is much simpler. This function simply finds the entire block and shifts it +// over by one tab if it is indeed a block (just returns the line if it's not). +// blockEnd is the end of the section in the input buffer, and contents is the +// extracted text that was shifted over one tab. It will need to be rendered at +// the end of the document. +func scanFootnote(p *Markdown, data []byte, i, indentSize int) (blockStart, blockEnd int, contents []byte, hasBlock bool) { + if i == 0 || len(data) == 0 { + return + } + + // skip leading whitespace on first line + for i < len(data) && data[i] == ' ' { + i++ + } + + blockStart = i + + // find the end of the line + blockEnd = i + for i < len(data) && data[i-1] != '\n' { + i++ + } + + // get working buffer + var raw bytes.Buffer + + // put the first line into the working buffer + raw.Write(data[blockEnd:i]) + blockEnd = i + + // process the following lines + containsBlankLine := false + +gatherLines: + for blockEnd < len(data) { + i++ + + // find the end of this line + for i < len(data) && data[i-1] != '\n' { + i++ + } + + // if it is an empty line, guess that it is part of this item + // and move on to the next line + if p.isEmpty(data[blockEnd:i]) > 0 { + containsBlankLine = true + blockEnd = i + continue + } + + n := 0 + if n = isIndented(data[blockEnd:i], indentSize); n == 0 { + // this is the end of the block. + // we don't want to include this last line in the index. + break gatherLines + } + + // if there were blank lines before this one, insert a new one now + if containsBlankLine { + raw.WriteByte('\n') + containsBlankLine = false + } + + // get rid of that first tab, write to buffer + raw.Write(data[blockEnd+n : i]) + hasBlock = true + + blockEnd = i + } + + if data[blockEnd-1] != '\n' { + raw.WriteByte('\n') + } + + contents = raw.Bytes() + + return +} + +// +// +// Miscellaneous helper functions +// +// + +// Test if a character is a punctuation symbol. +// Taken from a private function in regexp in the stdlib. +func ispunct(c byte) bool { + for _, r := range []byte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~") { + if c == r { + return true + } + } + return false +} + +// Test if a character is a whitespace character. +func isspace(c byte) bool { + return ishorizontalspace(c) || isverticalspace(c) +} + +// Test if a character is a horizontal whitespace character. +func ishorizontalspace(c byte) bool { + return c == ' ' || c == '\t' +} + +// Test if a character is a vertical character. +func isverticalspace(c byte) bool { + return c == '\n' || c == '\r' || c == '\f' || c == '\v' +} + +// Test if a character is letter. +func isletter(c byte) bool { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') +} + +// Test if a character is a letter or a digit. +// TODO: check when this is looking for ASCII alnum and when it should use unicode +func isalnum(c byte) bool { + return (c >= '0' && c <= '9') || isletter(c) +} + +// Replace tab characters with spaces, aligning to the next TAB_SIZE column. +// always ends output with a newline +func expandTabs(out *bytes.Buffer, line []byte, tabSize int) { + // first, check for common cases: no tabs, or only tabs at beginning of line + i, prefix := 0, 0 + slowcase := false + for i = 0; i < len(line); i++ { + if line[i] == '\t' { + if prefix == i { + prefix++ + } else { + slowcase = true + break + } + } + } + + // no need to decode runes if all tabs are at the beginning of the line + if !slowcase { + for i = 0; i < prefix*tabSize; i++ { + out.WriteByte(' ') + } + out.Write(line[prefix:]) + return + } + + // the slow case: we need to count runes to figure out how + // many spaces to insert for each tab + column := 0 + i = 0 + for i < len(line) { + start := i + for i < len(line) && line[i] != '\t' { + _, size := utf8.DecodeRune(line[i:]) + i += size + column++ + } + + if i > start { + out.Write(line[start:i]) + } + + if i >= len(line) { + break + } + + for { + out.WriteByte(' ') + column++ + if column%tabSize == 0 { + break + } + } + + i++ + } +} + +// Find if a line counts as indented or not. +// Returns number of characters the indent is (0 = not indented). +func isIndented(data []byte, indentSize int) int { + if len(data) == 0 { + return 0 + } + if data[0] == '\t' { + return 1 + } + if len(data) < indentSize { + return 0 + } + for i := 0; i < indentSize; i++ { + if data[i] != ' ' { + return 0 + } + } + return indentSize +} + +// Create a url-safe slug for fragments +func slugify(in []byte) []byte { + if len(in) == 0 { + return in + } + out := make([]byte, 0, len(in)) + sym := false + + for _, ch := range in { + if isalnum(ch) { + sym = false + out = append(out, ch) + } else if sym { + continue + } else { + out = append(out, '-') + sym = true + } + } + var a, b int + var ch byte + for a, ch = range out { + if ch != '-' { + break + } + } + for b = len(out) - 1; b > 0; b-- { + if out[b] != '-' { + break + } + } + return out[a : b+1] +} diff --git a/vendor/github.com/russross/blackfriday/v2/node.go b/vendor/github.com/russross/blackfriday/v2/node.go new file mode 100644 index 000000000..51b9e8c1b --- /dev/null +++ b/vendor/github.com/russross/blackfriday/v2/node.go @@ -0,0 +1,354 @@ +package blackfriday + +import ( + "bytes" + "fmt" +) + +// NodeType specifies a type of a single node of a syntax tree. Usually one +// node (and its type) corresponds to a single markdown feature, e.g. emphasis +// or code block. +type NodeType int + +// Constants for identifying different types of nodes. See NodeType. +const ( + Document NodeType = iota + BlockQuote + List + Item + Paragraph + Heading + HorizontalRule + Emph + Strong + Del + Link + Image + Text + HTMLBlock + CodeBlock + Softbreak + Hardbreak + Code + HTMLSpan + Table + TableCell + TableHead + TableBody + TableRow +) + +var nodeTypeNames = []string{ + Document: "Document", + BlockQuote: "BlockQuote", + List: "List", + Item: "Item", + Paragraph: "Paragraph", + Heading: "Heading", + HorizontalRule: "HorizontalRule", + Emph: "Emph", + Strong: "Strong", + Del: "Del", + Link: "Link", + Image: "Image", + Text: "Text", + HTMLBlock: "HTMLBlock", + CodeBlock: "CodeBlock", + Softbreak: "Softbreak", + Hardbreak: "Hardbreak", + Code: "Code", + HTMLSpan: "HTMLSpan", + Table: "Table", + TableCell: "TableCell", + TableHead: "TableHead", + TableBody: "TableBody", + TableRow: "TableRow", +} + +func (t NodeType) String() string { + return nodeTypeNames[t] +} + +// ListData contains fields relevant to a List and Item node type. +type ListData struct { + ListFlags ListType + Tight bool // Skip

    s around list item data if true + BulletChar byte // '*', '+' or '-' in bullet lists + Delimiter byte // '.' or ')' after the number in ordered lists + RefLink []byte // If not nil, turns this list item into a footnote item and triggers different rendering + IsFootnotesList bool // This is a list of footnotes +} + +// LinkData contains fields relevant to a Link node type. +type LinkData struct { + Destination []byte // Destination is what goes into a href + Title []byte // Title is the tooltip thing that goes in a title attribute + NoteID int // NoteID contains a serial number of a footnote, zero if it's not a footnote + Footnote *Node // If it's a footnote, this is a direct link to the footnote Node. Otherwise nil. +} + +// CodeBlockData contains fields relevant to a CodeBlock node type. +type CodeBlockData struct { + IsFenced bool // Specifies whether it's a fenced code block or an indented one + Info []byte // This holds the info string + FenceChar byte + FenceLength int + FenceOffset int +} + +// TableCellData contains fields relevant to a TableCell node type. +type TableCellData struct { + IsHeader bool // This tells if it's under the header row + Align CellAlignFlags // This holds the value for align attribute +} + +// HeadingData contains fields relevant to a Heading node type. +type HeadingData struct { + Level int // This holds the heading level number + HeadingID string // This might hold heading ID, if present + IsTitleblock bool // Specifies whether it's a title block +} + +// Node is a single element in the abstract syntax tree of the parsed document. +// It holds connections to the structurally neighboring nodes and, for certain +// types of nodes, additional information that might be needed when rendering. +type Node struct { + Type NodeType // Determines the type of the node + Parent *Node // Points to the parent + FirstChild *Node // Points to the first child, if any + LastChild *Node // Points to the last child, if any + Prev *Node // Previous sibling; nil if it's the first child + Next *Node // Next sibling; nil if it's the last child + + Literal []byte // Text contents of the leaf nodes + + HeadingData // Populated if Type is Heading + ListData // Populated if Type is List + CodeBlockData // Populated if Type is CodeBlock + LinkData // Populated if Type is Link + TableCellData // Populated if Type is TableCell + + content []byte // Markdown content of the block nodes + open bool // Specifies an open block node that has not been finished to process yet +} + +// NewNode allocates a node of a specified type. +func NewNode(typ NodeType) *Node { + return &Node{ + Type: typ, + open: true, + } +} + +func (n *Node) String() string { + ellipsis := "" + snippet := n.Literal + if len(snippet) > 16 { + snippet = snippet[:16] + ellipsis = "..." + } + return fmt.Sprintf("%s: '%s%s'", n.Type, snippet, ellipsis) +} + +// Unlink removes node 'n' from the tree. +// It panics if the node is nil. +func (n *Node) Unlink() { + if n.Prev != nil { + n.Prev.Next = n.Next + } else if n.Parent != nil { + n.Parent.FirstChild = n.Next + } + if n.Next != nil { + n.Next.Prev = n.Prev + } else if n.Parent != nil { + n.Parent.LastChild = n.Prev + } + n.Parent = nil + n.Next = nil + n.Prev = nil +} + +// AppendChild adds a node 'child' as a child of 'n'. +// It panics if either node is nil. +func (n *Node) AppendChild(child *Node) { + child.Unlink() + child.Parent = n + if n.LastChild != nil { + n.LastChild.Next = child + child.Prev = n.LastChild + n.LastChild = child + } else { + n.FirstChild = child + n.LastChild = child + } +} + +// InsertBefore inserts 'sibling' immediately before 'n'. +// It panics if either node is nil. +func (n *Node) InsertBefore(sibling *Node) { + sibling.Unlink() + sibling.Prev = n.Prev + if sibling.Prev != nil { + sibling.Prev.Next = sibling + } + sibling.Next = n + n.Prev = sibling + sibling.Parent = n.Parent + if sibling.Prev == nil { + sibling.Parent.FirstChild = sibling + } +} + +func (n *Node) isContainer() bool { + switch n.Type { + case Document: + fallthrough + case BlockQuote: + fallthrough + case List: + fallthrough + case Item: + fallthrough + case Paragraph: + fallthrough + case Heading: + fallthrough + case Emph: + fallthrough + case Strong: + fallthrough + case Del: + fallthrough + case Link: + fallthrough + case Image: + fallthrough + case Table: + fallthrough + case TableHead: + fallthrough + case TableBody: + fallthrough + case TableRow: + fallthrough + case TableCell: + return true + default: + return false + } +} + +func (n *Node) canContain(t NodeType) bool { + if n.Type == List { + return t == Item + } + if n.Type == Document || n.Type == BlockQuote || n.Type == Item { + return t != Item + } + if n.Type == Table { + return t == TableHead || t == TableBody + } + if n.Type == TableHead || n.Type == TableBody { + return t == TableRow + } + if n.Type == TableRow { + return t == TableCell + } + return false +} + +// WalkStatus allows NodeVisitor to have some control over the tree traversal. +// It is returned from NodeVisitor and different values allow Node.Walk to +// decide which node to go to next. +type WalkStatus int + +const ( + // GoToNext is the default traversal of every node. + GoToNext WalkStatus = iota + // SkipChildren tells walker to skip all children of current node. + SkipChildren + // Terminate tells walker to terminate the traversal. + Terminate +) + +// NodeVisitor is a callback to be called when traversing the syntax tree. +// Called twice for every node: once with entering=true when the branch is +// first visited, then with entering=false after all the children are done. +type NodeVisitor func(node *Node, entering bool) WalkStatus + +// Walk is a convenience method that instantiates a walker and starts a +// traversal of subtree rooted at n. +func (n *Node) Walk(visitor NodeVisitor) { + w := newNodeWalker(n) + for w.current != nil { + status := visitor(w.current, w.entering) + switch status { + case GoToNext: + w.next() + case SkipChildren: + w.entering = false + w.next() + case Terminate: + return + } + } +} + +type nodeWalker struct { + current *Node + root *Node + entering bool +} + +func newNodeWalker(root *Node) *nodeWalker { + return &nodeWalker{ + current: root, + root: root, + entering: true, + } +} + +func (nw *nodeWalker) next() { + if (!nw.current.isContainer() || !nw.entering) && nw.current == nw.root { + nw.current = nil + return + } + if nw.entering && nw.current.isContainer() { + if nw.current.FirstChild != nil { + nw.current = nw.current.FirstChild + nw.entering = true + } else { + nw.entering = false + } + } else if nw.current.Next == nil { + nw.current = nw.current.Parent + nw.entering = false + } else { + nw.current = nw.current.Next + nw.entering = true + } +} + +func dump(ast *Node) { + fmt.Println(dumpString(ast)) +} + +func dumpR(ast *Node, depth int) string { + if ast == nil { + return "" + } + indent := bytes.Repeat([]byte("\t"), depth) + content := ast.Literal + if content == nil { + content = ast.content + } + result := fmt.Sprintf("%s%s(%q)\n", indent, ast.Type, content) + for n := ast.FirstChild; n != nil; n = n.Next { + result += dumpR(n, depth+1) + } + return result +} + +func dumpString(ast *Node) string { + return dumpR(ast, 0) +} diff --git a/vendor/github.com/russross/blackfriday/v2/smartypants.go b/vendor/github.com/russross/blackfriday/v2/smartypants.go new file mode 100644 index 000000000..3a220e942 --- /dev/null +++ b/vendor/github.com/russross/blackfriday/v2/smartypants.go @@ -0,0 +1,457 @@ +// +// Blackfriday Markdown Processor +// Available at http://github.com/russross/blackfriday +// +// Copyright © 2011 Russ Ross . +// Distributed under the Simplified BSD License. +// See README.md for details. +// + +// +// +// SmartyPants rendering +// +// + +package blackfriday + +import ( + "bytes" + "io" +) + +// SPRenderer is a struct containing state of a Smartypants renderer. +type SPRenderer struct { + inSingleQuote bool + inDoubleQuote bool + callbacks [256]smartCallback +} + +func wordBoundary(c byte) bool { + return c == 0 || isspace(c) || ispunct(c) +} + +func tolower(c byte) byte { + if c >= 'A' && c <= 'Z' { + return c - 'A' + 'a' + } + return c +} + +func isdigit(c byte) bool { + return c >= '0' && c <= '9' +} + +func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote byte, isOpen *bool, addNBSP bool) bool { + // edge of the buffer is likely to be a tag that we don't get to see, + // so we treat it like text sometimes + + // enumerate all sixteen possibilities for (previousChar, nextChar) + // each can be one of {0, space, punct, other} + switch { + case previousChar == 0 && nextChar == 0: + // context is not any help here, so toggle + *isOpen = !*isOpen + case isspace(previousChar) && nextChar == 0: + // [ "] might be [ "foo...] + *isOpen = true + case ispunct(previousChar) && nextChar == 0: + // [!"] hmm... could be [Run!"] or [("...] + *isOpen = false + case /* isnormal(previousChar) && */ nextChar == 0: + // [a"] is probably a close + *isOpen = false + case previousChar == 0 && isspace(nextChar): + // [" ] might be [...foo" ] + *isOpen = false + case isspace(previousChar) && isspace(nextChar): + // [ " ] context is not any help here, so toggle + *isOpen = !*isOpen + case ispunct(previousChar) && isspace(nextChar): + // [!" ] is probably a close + *isOpen = false + case /* isnormal(previousChar) && */ isspace(nextChar): + // [a" ] this is one of the easy cases + *isOpen = false + case previousChar == 0 && ispunct(nextChar): + // ["!] hmm... could be ["$1.95] or ["!...] + *isOpen = false + case isspace(previousChar) && ispunct(nextChar): + // [ "!] looks more like [ "$1.95] + *isOpen = true + case ispunct(previousChar) && ispunct(nextChar): + // [!"!] context is not any help here, so toggle + *isOpen = !*isOpen + case /* isnormal(previousChar) && */ ispunct(nextChar): + // [a"!] is probably a close + *isOpen = false + case previousChar == 0 /* && isnormal(nextChar) */ : + // ["a] is probably an open + *isOpen = true + case isspace(previousChar) /* && isnormal(nextChar) */ : + // [ "a] this is one of the easy cases + *isOpen = true + case ispunct(previousChar) /* && isnormal(nextChar) */ : + // [!"a] is probably an open + *isOpen = true + default: + // [a'b] maybe a contraction? + *isOpen = false + } + + // Note that with the limited lookahead, this non-breaking + // space will also be appended to single double quotes. + if addNBSP && !*isOpen { + out.WriteString(" ") + } + + out.WriteByte('&') + if *isOpen { + out.WriteByte('l') + } else { + out.WriteByte('r') + } + out.WriteByte(quote) + out.WriteString("quo;") + + if addNBSP && *isOpen { + out.WriteString(" ") + } + + return true +} + +func (r *SPRenderer) smartSingleQuote(out *bytes.Buffer, previousChar byte, text []byte) int { + if len(text) >= 2 { + t1 := tolower(text[1]) + + if t1 == '\'' { + nextChar := byte(0) + if len(text) >= 3 { + nextChar = text[2] + } + if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) { + return 1 + } + } + + if (t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && (len(text) < 3 || wordBoundary(text[2])) { + out.WriteString("’") + return 0 + } + + if len(text) >= 3 { + t2 := tolower(text[2]) + + if ((t1 == 'r' && t2 == 'e') || (t1 == 'l' && t2 == 'l') || (t1 == 'v' && t2 == 'e')) && + (len(text) < 4 || wordBoundary(text[3])) { + out.WriteString("’") + return 0 + } + } + } + + nextChar := byte(0) + if len(text) > 1 { + nextChar = text[1] + } + if smartQuoteHelper(out, previousChar, nextChar, 's', &r.inSingleQuote, false) { + return 0 + } + + out.WriteByte(text[0]) + return 0 +} + +func (r *SPRenderer) smartParens(out *bytes.Buffer, previousChar byte, text []byte) int { + if len(text) >= 3 { + t1 := tolower(text[1]) + t2 := tolower(text[2]) + + if t1 == 'c' && t2 == ')' { + out.WriteString("©") + return 2 + } + + if t1 == 'r' && t2 == ')' { + out.WriteString("®") + return 2 + } + + if len(text) >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')' { + out.WriteString("™") + return 3 + } + } + + out.WriteByte(text[0]) + return 0 +} + +func (r *SPRenderer) smartDash(out *bytes.Buffer, previousChar byte, text []byte) int { + if len(text) >= 2 { + if text[1] == '-' { + out.WriteString("—") + return 1 + } + + if wordBoundary(previousChar) && wordBoundary(text[1]) { + out.WriteString("–") + return 0 + } + } + + out.WriteByte(text[0]) + return 0 +} + +func (r *SPRenderer) smartDashLatex(out *bytes.Buffer, previousChar byte, text []byte) int { + if len(text) >= 3 && text[1] == '-' && text[2] == '-' { + out.WriteString("—") + return 2 + } + if len(text) >= 2 && text[1] == '-' { + out.WriteString("–") + return 1 + } + + out.WriteByte(text[0]) + return 0 +} + +func (r *SPRenderer) smartAmpVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte, addNBSP bool) int { + if bytes.HasPrefix(text, []byte(""")) { + nextChar := byte(0) + if len(text) >= 7 { + nextChar = text[6] + } + if smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, addNBSP) { + return 5 + } + } + + if bytes.HasPrefix(text, []byte("�")) { + return 3 + } + + out.WriteByte('&') + return 0 +} + +func (r *SPRenderer) smartAmp(angledQuotes, addNBSP bool) func(*bytes.Buffer, byte, []byte) int { + var quote byte = 'd' + if angledQuotes { + quote = 'a' + } + + return func(out *bytes.Buffer, previousChar byte, text []byte) int { + return r.smartAmpVariant(out, previousChar, text, quote, addNBSP) + } +} + +func (r *SPRenderer) smartPeriod(out *bytes.Buffer, previousChar byte, text []byte) int { + if len(text) >= 3 && text[1] == '.' && text[2] == '.' { + out.WriteString("…") + return 2 + } + + if len(text) >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.' { + out.WriteString("…") + return 4 + } + + out.WriteByte(text[0]) + return 0 +} + +func (r *SPRenderer) smartBacktick(out *bytes.Buffer, previousChar byte, text []byte) int { + if len(text) >= 2 && text[1] == '`' { + nextChar := byte(0) + if len(text) >= 3 { + nextChar = text[2] + } + if smartQuoteHelper(out, previousChar, nextChar, 'd', &r.inDoubleQuote, false) { + return 1 + } + } + + out.WriteByte(text[0]) + return 0 +} + +func (r *SPRenderer) smartNumberGeneric(out *bytes.Buffer, previousChar byte, text []byte) int { + if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 { + // is it of the form digits/digits(word boundary)?, i.e., \d+/\d+\b + // note: check for regular slash (/) or fraction slash (⁄, 0x2044, or 0xe2 81 84 in utf-8) + // and avoid changing dates like 1/23/2005 into fractions. + numEnd := 0 + for len(text) > numEnd && isdigit(text[numEnd]) { + numEnd++ + } + if numEnd == 0 { + out.WriteByte(text[0]) + return 0 + } + denStart := numEnd + 1 + if len(text) > numEnd+3 && text[numEnd] == 0xe2 && text[numEnd+1] == 0x81 && text[numEnd+2] == 0x84 { + denStart = numEnd + 3 + } else if len(text) < numEnd+2 || text[numEnd] != '/' { + out.WriteByte(text[0]) + return 0 + } + denEnd := denStart + for len(text) > denEnd && isdigit(text[denEnd]) { + denEnd++ + } + if denEnd == denStart { + out.WriteByte(text[0]) + return 0 + } + if len(text) == denEnd || wordBoundary(text[denEnd]) && text[denEnd] != '/' { + out.WriteString("") + out.Write(text[:numEnd]) + out.WriteString("") + out.Write(text[denStart:denEnd]) + out.WriteString("") + return denEnd - 1 + } + } + + out.WriteByte(text[0]) + return 0 +} + +func (r *SPRenderer) smartNumber(out *bytes.Buffer, previousChar byte, text []byte) int { + if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 { + if text[0] == '1' && text[1] == '/' && text[2] == '2' { + if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' { + out.WriteString("½") + return 2 + } + } + + if text[0] == '1' && text[1] == '/' && text[2] == '4' { + if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h') { + out.WriteString("¼") + return 2 + } + } + + if text[0] == '3' && text[1] == '/' && text[2] == '4' { + if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's') { + out.WriteString("¾") + return 2 + } + } + } + + out.WriteByte(text[0]) + return 0 +} + +func (r *SPRenderer) smartDoubleQuoteVariant(out *bytes.Buffer, previousChar byte, text []byte, quote byte) int { + nextChar := byte(0) + if len(text) > 1 { + nextChar = text[1] + } + if !smartQuoteHelper(out, previousChar, nextChar, quote, &r.inDoubleQuote, false) { + out.WriteString(""") + } + + return 0 +} + +func (r *SPRenderer) smartDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int { + return r.smartDoubleQuoteVariant(out, previousChar, text, 'd') +} + +func (r *SPRenderer) smartAngledDoubleQuote(out *bytes.Buffer, previousChar byte, text []byte) int { + return r.smartDoubleQuoteVariant(out, previousChar, text, 'a') +} + +func (r *SPRenderer) smartLeftAngle(out *bytes.Buffer, previousChar byte, text []byte) int { + i := 0 + + for i < len(text) && text[i] != '>' { + i++ + } + + out.Write(text[:i+1]) + return i +} + +type smartCallback func(out *bytes.Buffer, previousChar byte, text []byte) int + +// NewSmartypantsRenderer constructs a Smartypants renderer object. +func NewSmartypantsRenderer(flags HTMLFlags) *SPRenderer { + var ( + r SPRenderer + + smartAmpAngled = r.smartAmp(true, false) + smartAmpAngledNBSP = r.smartAmp(true, true) + smartAmpRegular = r.smartAmp(false, false) + smartAmpRegularNBSP = r.smartAmp(false, true) + + addNBSP = flags&SmartypantsQuotesNBSP != 0 + ) + + if flags&SmartypantsAngledQuotes == 0 { + r.callbacks['"'] = r.smartDoubleQuote + if !addNBSP { + r.callbacks['&'] = smartAmpRegular + } else { + r.callbacks['&'] = smartAmpRegularNBSP + } + } else { + r.callbacks['"'] = r.smartAngledDoubleQuote + if !addNBSP { + r.callbacks['&'] = smartAmpAngled + } else { + r.callbacks['&'] = smartAmpAngledNBSP + } + } + r.callbacks['\''] = r.smartSingleQuote + r.callbacks['('] = r.smartParens + if flags&SmartypantsDashes != 0 { + if flags&SmartypantsLatexDashes == 0 { + r.callbacks['-'] = r.smartDash + } else { + r.callbacks['-'] = r.smartDashLatex + } + } + r.callbacks['.'] = r.smartPeriod + if flags&SmartypantsFractions == 0 { + r.callbacks['1'] = r.smartNumber + r.callbacks['3'] = r.smartNumber + } else { + for ch := '1'; ch <= '9'; ch++ { + r.callbacks[ch] = r.smartNumberGeneric + } + } + r.callbacks['<'] = r.smartLeftAngle + r.callbacks['`'] = r.smartBacktick + return &r +} + +// Process is the entry point of the Smartypants renderer. +func (r *SPRenderer) Process(w io.Writer, text []byte) { + mark := 0 + for i := 0; i < len(text); i++ { + if action := r.callbacks[text[i]]; action != nil { + if i > mark { + w.Write(text[mark:i]) + } + previousChar := byte(0) + if i > 0 { + previousChar = text[i-1] + } + var tmp bytes.Buffer + i += action(&tmp, previousChar, text[i:]) + w.Write(tmp.Bytes()) + mark = i + 1 + } + } + if mark < len(text) { + w.Write(text[mark:]) + } +} diff --git a/vendor/github.com/shurcooL/sanitized_anchor_name/.travis.yml b/vendor/github.com/shurcooL/sanitized_anchor_name/.travis.yml new file mode 100644 index 000000000..93b1fcdb3 --- /dev/null +++ b/vendor/github.com/shurcooL/sanitized_anchor_name/.travis.yml @@ -0,0 +1,16 @@ +sudo: false +language: go +go: + - 1.x + - master +matrix: + allow_failures: + - go: master + fast_finish: true +install: + - # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step). +script: + - go get -t -v ./... + - diff -u <(echo -n) <(gofmt -d -s .) + - go tool vet . + - go test -v -race ./... diff --git a/vendor/github.com/shurcooL/sanitized_anchor_name/LICENSE b/vendor/github.com/shurcooL/sanitized_anchor_name/LICENSE new file mode 100644 index 000000000..c35c17af9 --- /dev/null +++ b/vendor/github.com/shurcooL/sanitized_anchor_name/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2015 Dmitri Shuralyov + +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/shurcooL/sanitized_anchor_name/README.md b/vendor/github.com/shurcooL/sanitized_anchor_name/README.md new file mode 100644 index 000000000..670bf0fe6 --- /dev/null +++ b/vendor/github.com/shurcooL/sanitized_anchor_name/README.md @@ -0,0 +1,36 @@ +sanitized_anchor_name +===================== + +[![Build Status](https://travis-ci.org/shurcooL/sanitized_anchor_name.svg?branch=master)](https://travis-ci.org/shurcooL/sanitized_anchor_name) [![GoDoc](https://godoc.org/github.com/shurcooL/sanitized_anchor_name?status.svg)](https://godoc.org/github.com/shurcooL/sanitized_anchor_name) + +Package sanitized_anchor_name provides a func to create sanitized anchor names. + +Its logic can be reused by multiple packages to create interoperable anchor names +and links to those anchors. + +At this time, it does not try to ensure that generated anchor names +are unique, that responsibility falls on the caller. + +Installation +------------ + +```bash +go get -u github.com/shurcooL/sanitized_anchor_name +``` + +Example +------- + +```Go +anchorName := sanitized_anchor_name.Create("This is a header") + +fmt.Println(anchorName) + +// Output: +// this-is-a-header +``` + +License +------- + +- [MIT License](LICENSE) diff --git a/vendor/github.com/shurcooL/sanitized_anchor_name/go.mod b/vendor/github.com/shurcooL/sanitized_anchor_name/go.mod new file mode 100644 index 000000000..1e2553475 --- /dev/null +++ b/vendor/github.com/shurcooL/sanitized_anchor_name/go.mod @@ -0,0 +1 @@ +module github.com/shurcooL/sanitized_anchor_name diff --git a/vendor/github.com/shurcooL/sanitized_anchor_name/main.go b/vendor/github.com/shurcooL/sanitized_anchor_name/main.go new file mode 100644 index 000000000..6a77d1243 --- /dev/null +++ b/vendor/github.com/shurcooL/sanitized_anchor_name/main.go @@ -0,0 +1,29 @@ +// Package sanitized_anchor_name provides a func to create sanitized anchor names. +// +// Its logic can be reused by multiple packages to create interoperable anchor names +// and links to those anchors. +// +// At this time, it does not try to ensure that generated anchor names +// are unique, that responsibility falls on the caller. +package sanitized_anchor_name // import "github.com/shurcooL/sanitized_anchor_name" + +import "unicode" + +// Create returns a sanitized anchor name for the given text. +func Create(text string) string { + var anchorName []rune + var futureDash = false + for _, r := range text { + switch { + case unicode.IsLetter(r) || unicode.IsNumber(r): + if futureDash && len(anchorName) > 0 { + anchorName = append(anchorName, '-') + } + futureDash = false + anchorName = append(anchorName, unicode.ToLower(r)) + default: + futureDash = true + } + } + return string(anchorName) +} diff --git a/vendor/github.com/urfave/cli/.travis.yml b/vendor/github.com/urfave/cli/.travis.yml deleted file mode 100644 index cf8d0980d..000000000 --- a/vendor/github.com/urfave/cli/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: go -sudo: false -dist: trusty -osx_image: xcode8.3 -go: 1.8.x - -os: -- linux -- osx - -cache: - directories: - - node_modules - -before_script: -- go get github.com/urfave/gfmrun/... || true -- go get golang.org/x/tools/cmd/goimports -- if [ ! -f node_modules/.bin/markdown-toc ] ; then - npm install markdown-toc ; - fi - -script: -- ./runtests gen -- ./runtests vet -- ./runtests test -- ./runtests gfmrun -- ./runtests toc diff --git a/vendor/github.com/urfave/cli/CHANGELOG.md b/vendor/github.com/urfave/cli/CHANGELOG.md deleted file mode 100644 index 401eae5a2..000000000 --- a/vendor/github.com/urfave/cli/CHANGELOG.md +++ /dev/null @@ -1,435 +0,0 @@ -# Change Log - -**ATTN**: This project uses [semantic versioning](http://semver.org/). - -## [Unreleased] - -## 1.20.0 - 2017-08-10 - -### Fixed - -* `HandleExitCoder` is now correctly iterates over all errors in - a `MultiError`. The exit code is the exit code of the last error or `1` if - there are no `ExitCoder`s in the `MultiError`. -* Fixed YAML file loading on Windows (previously would fail validate the file path) -* Subcommand `Usage`, `Description`, `ArgsUsage`, `OnUsageError` correctly - propogated -* `ErrWriter` is now passed downwards through command structure to avoid the - need to redefine it -* Pass `Command` context into `OnUsageError` rather than parent context so that - all fields are avaiable -* Errors occuring in `Before` funcs are no longer double printed -* Use `UsageText` in the help templates for commands and subcommands if - defined; otherwise build the usage as before (was previously ignoring this - field) -* `IsSet` and `GlobalIsSet` now correctly return whether a flag is set if - a program calls `Set` or `GlobalSet` directly after flag parsing (would - previously only return `true` if the flag was set during parsing) - -### Changed - -* No longer exit the program on command/subcommand error if the error raised is - not an `OsExiter`. This exiting behavior was introduced in 1.19.0, but was - determined to be a regression in functionality. See [the - PR](https://github.com/urfave/cli/pull/595) for discussion. - -### Added - -* `CommandsByName` type was added to make it easy to sort `Command`s by name, - alphabetically -* `altsrc` now handles loading of string and int arrays from TOML -* Support for definition of custom help templates for `App` via - `CustomAppHelpTemplate` -* Support for arbitrary key/value fields on `App` to be used with - `CustomAppHelpTemplate` via `ExtraInfo` -* `HelpFlag`, `VersionFlag`, and `BashCompletionFlag` changed to explictly be - `cli.Flag`s allowing for the use of custom flags satisfying the `cli.Flag` - interface to be used. - - -## [1.19.1] - 2016-11-21 - -### Fixed - -- Fixes regression introduced in 1.19.0 where using an `ActionFunc` as - the `Action` for a command would cause it to error rather than calling the - function. Should not have a affected declarative cases using `func(c - *cli.Context) err)`. -- Shell completion now handles the case where the user specifies - `--generate-bash-completion` immediately after a flag that takes an argument. - Previously it call the application with `--generate-bash-completion` as the - flag value. - -## [1.19.0] - 2016-11-19 -### Added -- `FlagsByName` was added to make it easy to sort flags (e.g. `sort.Sort(cli.FlagsByName(app.Flags))`) -- A `Description` field was added to `App` for a more detailed description of - the application (similar to the existing `Description` field on `Command`) -- Flag type code generation via `go generate` -- Write to stderr and exit 1 if action returns non-nil error -- Added support for TOML to the `altsrc` loader -- `SkipArgReorder` was added to allow users to skip the argument reordering. - This is useful if you want to consider all "flags" after an argument as - arguments rather than flags (the default behavior of the stdlib `flag` - library). This is backported functionality from the [removal of the flag - reordering](https://github.com/urfave/cli/pull/398) in the unreleased version - 2 -- For formatted errors (those implementing `ErrorFormatter`), the errors will - be formatted during output. Compatible with `pkg/errors`. - -### Changed -- Raise minimum tested/supported Go version to 1.2+ - -### Fixed -- Consider empty environment variables as set (previously environment variables - with the equivalent of `""` would be skipped rather than their value used). -- Return an error if the value in a given environment variable cannot be parsed - as the flag type. Previously these errors were silently swallowed. -- Print full error when an invalid flag is specified (which includes the invalid flag) -- `App.Writer` defaults to `stdout` when `nil` -- If no action is specified on a command or app, the help is now printed instead of `panic`ing -- `App.Metadata` is initialized automatically now (previously was `nil` unless initialized) -- Correctly show help message if `-h` is provided to a subcommand -- `context.(Global)IsSet` now respects environment variables. Previously it - would return `false` if a flag was specified in the environment rather than - as an argument -- Removed deprecation warnings to STDERR to avoid them leaking to the end-user -- `altsrc`s import paths were updated to use `gopkg.in/urfave/cli.v1`. This - fixes issues that occurred when `gopkg.in/urfave/cli.v1` was imported as well - as `altsrc` where Go would complain that the types didn't match - -## [1.18.1] - 2016-08-28 -### Fixed -- Removed deprecation warnings to STDERR to avoid them leaking to the end-user (backported) - -## [1.18.0] - 2016-06-27 -### Added -- `./runtests` test runner with coverage tracking by default -- testing on OS X -- testing on Windows -- `UintFlag`, `Uint64Flag`, and `Int64Flag` types and supporting code - -### Changed -- Use spaces for alignment in help/usage output instead of tabs, making the - output alignment consistent regardless of tab width - -### Fixed -- Printing of command aliases in help text -- Printing of visible flags for both struct and struct pointer flags -- Display the `help` subcommand when using `CommandCategories` -- No longer swallows `panic`s that occur within the `Action`s themselves when - detecting the signature of the `Action` field - -## [1.17.1] - 2016-08-28 -### Fixed -- Removed deprecation warnings to STDERR to avoid them leaking to the end-user - -## [1.17.0] - 2016-05-09 -### Added -- Pluggable flag-level help text rendering via `cli.DefaultFlagStringFunc` -- `context.GlobalBoolT` was added as an analogue to `context.GlobalBool` -- Support for hiding commands by setting `Hidden: true` -- this will hide the - commands in help output - -### Changed -- `Float64Flag`, `IntFlag`, and `DurationFlag` default values are no longer - quoted in help text output. -- All flag types now include `(default: {value})` strings following usage when a - default value can be (reasonably) detected. -- `IntSliceFlag` and `StringSliceFlag` usage strings are now more consistent - with non-slice flag types -- Apps now exit with a code of 3 if an unknown subcommand is specified - (previously they printed "No help topic for...", but still exited 0. This - makes it easier to script around apps built using `cli` since they can trust - that a 0 exit code indicated a successful execution. -- cleanups based on [Go Report Card - feedback](https://goreportcard.com/report/github.com/urfave/cli) - -## [1.16.1] - 2016-08-28 -### Fixed -- Removed deprecation warnings to STDERR to avoid them leaking to the end-user - -## [1.16.0] - 2016-05-02 -### Added -- `Hidden` field on all flag struct types to omit from generated help text - -### Changed -- `BashCompletionFlag` (`--enable-bash-completion`) is now omitted from -generated help text via the `Hidden` field - -### Fixed -- handling of error values in `HandleAction` and `HandleExitCoder` - -## [1.15.0] - 2016-04-30 -### Added -- This file! -- Support for placeholders in flag usage strings -- `App.Metadata` map for arbitrary data/state management -- `Set` and `GlobalSet` methods on `*cli.Context` for altering values after -parsing. -- Support for nested lookup of dot-delimited keys in structures loaded from -YAML. - -### Changed -- The `App.Action` and `Command.Action` now prefer a return signature of -`func(*cli.Context) error`, as defined by `cli.ActionFunc`. If a non-nil -`error` is returned, there may be two outcomes: - - If the error fulfills `cli.ExitCoder`, then `os.Exit` will be called - automatically - - Else the error is bubbled up and returned from `App.Run` -- Specifying an `Action` with the legacy return signature of -`func(*cli.Context)` will produce a deprecation message to stderr -- Specifying an `Action` that is not a `func` type will produce a non-zero exit -from `App.Run` -- Specifying an `Action` func that has an invalid (input) signature will -produce a non-zero exit from `App.Run` - -### Deprecated -- -`cli.App.RunAndExitOnError`, which should now be done by returning an error -that fulfills `cli.ExitCoder` to `cli.App.Run`. -- the legacy signature for -`cli.App.Action` of `func(*cli.Context)`, which should now have a return -signature of `func(*cli.Context) error`, as defined by `cli.ActionFunc`. - -### Fixed -- Added missing `*cli.Context.GlobalFloat64` method - -## [1.14.0] - 2016-04-03 (backfilled 2016-04-25) -### Added -- Codebeat badge -- Support for categorization via `CategorizedHelp` and `Categories` on app. - -### Changed -- Use `filepath.Base` instead of `path.Base` in `Name` and `HelpName`. - -### Fixed -- Ensure version is not shown in help text when `HideVersion` set. - -## [1.13.0] - 2016-03-06 (backfilled 2016-04-25) -### Added -- YAML file input support. -- `NArg` method on context. - -## [1.12.0] - 2016-02-17 (backfilled 2016-04-25) -### Added -- Custom usage error handling. -- Custom text support in `USAGE` section of help output. -- Improved help messages for empty strings. -- AppVeyor CI configuration. - -### Changed -- Removed `panic` from default help printer func. -- De-duping and optimizations. - -### Fixed -- Correctly handle `Before`/`After` at command level when no subcommands. -- Case of literal `-` argument causing flag reordering. -- Environment variable hints on Windows. -- Docs updates. - -## [1.11.1] - 2015-12-21 (backfilled 2016-04-25) -### Changed -- Use `path.Base` in `Name` and `HelpName` -- Export `GetName` on flag types. - -### Fixed -- Flag parsing when skipping is enabled. -- Test output cleanup. -- Move completion check to account for empty input case. - -## [1.11.0] - 2015-11-15 (backfilled 2016-04-25) -### Added -- Destination scan support for flags. -- Testing against `tip` in Travis CI config. - -### Changed -- Go version in Travis CI config. - -### Fixed -- Removed redundant tests. -- Use correct example naming in tests. - -## [1.10.2] - 2015-10-29 (backfilled 2016-04-25) -### Fixed -- Remove unused var in bash completion. - -## [1.10.1] - 2015-10-21 (backfilled 2016-04-25) -### Added -- Coverage and reference logos in README. - -### Fixed -- Use specified values in help and version parsing. -- Only display app version and help message once. - -## [1.10.0] - 2015-10-06 (backfilled 2016-04-25) -### Added -- More tests for existing functionality. -- `ArgsUsage` at app and command level for help text flexibility. - -### Fixed -- Honor `HideHelp` and `HideVersion` in `App.Run`. -- Remove juvenile word from README. - -## [1.9.0] - 2015-09-08 (backfilled 2016-04-25) -### Added -- `FullName` on command with accompanying help output update. -- Set default `$PROG` in bash completion. - -### Changed -- Docs formatting. - -### Fixed -- Removed self-referential imports in tests. - -## [1.8.0] - 2015-06-30 (backfilled 2016-04-25) -### Added -- Support for `Copyright` at app level. -- `Parent` func at context level to walk up context lineage. - -### Fixed -- Global flag processing at top level. - -## [1.7.1] - 2015-06-11 (backfilled 2016-04-25) -### Added -- Aggregate errors from `Before`/`After` funcs. -- Doc comments on flag structs. -- Include non-global flags when checking version and help. -- Travis CI config updates. - -### Fixed -- Ensure slice type flags have non-nil values. -- Collect global flags from the full command hierarchy. -- Docs prose. - -## [1.7.0] - 2015-05-03 (backfilled 2016-04-25) -### Changed -- `HelpPrinter` signature includes output writer. - -### Fixed -- Specify go 1.1+ in docs. -- Set `Writer` when running command as app. - -## [1.6.0] - 2015-03-23 (backfilled 2016-04-25) -### Added -- Multiple author support. -- `NumFlags` at context level. -- `Aliases` at command level. - -### Deprecated -- `ShortName` at command level. - -### Fixed -- Subcommand help output. -- Backward compatible support for deprecated `Author` and `Email` fields. -- Docs regarding `Names`/`Aliases`. - -## [1.5.0] - 2015-02-20 (backfilled 2016-04-25) -### Added -- `After` hook func support at app and command level. - -### Fixed -- Use parsed context when running command as subcommand. -- Docs prose. - -## [1.4.1] - 2015-01-09 (backfilled 2016-04-25) -### Added -- Support for hiding `-h / --help` flags, but not `help` subcommand. -- Stop flag parsing after `--`. - -### Fixed -- Help text for generic flags to specify single value. -- Use double quotes in output for defaults. -- Use `ParseInt` instead of `ParseUint` for int environment var values. -- Use `0` as base when parsing int environment var values. - -## [1.4.0] - 2014-12-12 (backfilled 2016-04-25) -### Added -- Support for environment variable lookup "cascade". -- Support for `Stdout` on app for output redirection. - -### Fixed -- Print command help instead of app help in `ShowCommandHelp`. - -## [1.3.1] - 2014-11-13 (backfilled 2016-04-25) -### Added -- Docs and example code updates. - -### Changed -- Default `-v / --version` flag made optional. - -## [1.3.0] - 2014-08-10 (backfilled 2016-04-25) -### Added -- `FlagNames` at context level. -- Exposed `VersionPrinter` var for more control over version output. -- Zsh completion hook. -- `AUTHOR` section in default app help template. -- Contribution guidelines. -- `DurationFlag` type. - -## [1.2.0] - 2014-08-02 -### Added -- Support for environment variable defaults on flags plus tests. - -## [1.1.0] - 2014-07-15 -### Added -- Bash completion. -- Optional hiding of built-in help command. -- Optional skipping of flag parsing at command level. -- `Author`, `Email`, and `Compiled` metadata on app. -- `Before` hook func support at app and command level. -- `CommandNotFound` func support at app level. -- Command reference available on context. -- `GenericFlag` type. -- `Float64Flag` type. -- `BoolTFlag` type. -- `IsSet` flag helper on context. -- More flag lookup funcs at context level. -- More tests & docs. - -### Changed -- Help template updates to account for presence/absence of flags. -- Separated subcommand help template. -- Exposed `HelpPrinter` var for more control over help output. - -## [1.0.0] - 2013-11-01 -### Added -- `help` flag in default app flag set and each command flag set. -- Custom handling of argument parsing errors. -- Command lookup by name at app level. -- `StringSliceFlag` type and supporting `StringSlice` type. -- `IntSliceFlag` type and supporting `IntSlice` type. -- Slice type flag lookups by name at context level. -- Export of app and command help functions. -- More tests & docs. - -## 0.1.0 - 2013-07-22 -### Added -- Initial implementation. - -[Unreleased]: https://github.com/urfave/cli/compare/v1.18.0...HEAD -[1.18.0]: https://github.com/urfave/cli/compare/v1.17.0...v1.18.0 -[1.17.0]: https://github.com/urfave/cli/compare/v1.16.0...v1.17.0 -[1.16.0]: https://github.com/urfave/cli/compare/v1.15.0...v1.16.0 -[1.15.0]: https://github.com/urfave/cli/compare/v1.14.0...v1.15.0 -[1.14.0]: https://github.com/urfave/cli/compare/v1.13.0...v1.14.0 -[1.13.0]: https://github.com/urfave/cli/compare/v1.12.0...v1.13.0 -[1.12.0]: https://github.com/urfave/cli/compare/v1.11.1...v1.12.0 -[1.11.1]: https://github.com/urfave/cli/compare/v1.11.0...v1.11.1 -[1.11.0]: https://github.com/urfave/cli/compare/v1.10.2...v1.11.0 -[1.10.2]: https://github.com/urfave/cli/compare/v1.10.1...v1.10.2 -[1.10.1]: https://github.com/urfave/cli/compare/v1.10.0...v1.10.1 -[1.10.0]: https://github.com/urfave/cli/compare/v1.9.0...v1.10.0 -[1.9.0]: https://github.com/urfave/cli/compare/v1.8.0...v1.9.0 -[1.8.0]: https://github.com/urfave/cli/compare/v1.7.1...v1.8.0 -[1.7.1]: https://github.com/urfave/cli/compare/v1.7.0...v1.7.1 -[1.7.0]: https://github.com/urfave/cli/compare/v1.6.0...v1.7.0 -[1.6.0]: https://github.com/urfave/cli/compare/v1.5.0...v1.6.0 -[1.5.0]: https://github.com/urfave/cli/compare/v1.4.1...v1.5.0 -[1.4.1]: https://github.com/urfave/cli/compare/v1.4.0...v1.4.1 -[1.4.0]: https://github.com/urfave/cli/compare/v1.3.1...v1.4.0 -[1.3.1]: https://github.com/urfave/cli/compare/v1.3.0...v1.3.1 -[1.3.0]: https://github.com/urfave/cli/compare/v1.2.0...v1.3.0 -[1.2.0]: https://github.com/urfave/cli/compare/v1.1.0...v1.2.0 -[1.1.0]: https://github.com/urfave/cli/compare/v1.0.0...v1.1.0 -[1.0.0]: https://github.com/urfave/cli/compare/v0.1.0...v1.0.0 diff --git a/vendor/github.com/urfave/cli/README.md b/vendor/github.com/urfave/cli/README.md deleted file mode 100644 index 2bbbd8ea9..000000000 --- a/vendor/github.com/urfave/cli/README.md +++ /dev/null @@ -1,1381 +0,0 @@ -cli -=== - -[![Build Status](https://travis-ci.org/urfave/cli.svg?branch=master)](https://travis-ci.org/urfave/cli) -[![Windows Build Status](https://ci.appveyor.com/api/projects/status/rtgk5xufi932pb2v?svg=true)](https://ci.appveyor.com/project/urfave/cli) -[![GoDoc](https://godoc.org/github.com/urfave/cli?status.svg)](https://godoc.org/github.com/urfave/cli) -[![codebeat](https://codebeat.co/badges/0a8f30aa-f975-404b-b878-5fab3ae1cc5f)](https://codebeat.co/projects/github-com-urfave-cli) -[![Go Report Card](https://goreportcard.com/badge/urfave/cli)](https://goreportcard.com/report/urfave/cli) -[![top level coverage](https://gocover.io/_badge/github.com/urfave/cli?0 "top level coverage")](http://gocover.io/github.com/urfave/cli) / -[![altsrc coverage](https://gocover.io/_badge/github.com/urfave/cli/altsrc?0 "altsrc coverage")](http://gocover.io/github.com/urfave/cli/altsrc) - -**Notice:** This is the library formerly known as -`github.com/codegangsta/cli` -- Github will automatically redirect requests -to this repository, but we recommend updating your references for clarity. - -cli is a simple, fast, and fun package for building command line apps in Go. The -goal is to enable developers to write fast and distributable command line -applications in an expressive way. - - - -- [Overview](#overview) -- [Installation](#installation) - * [Supported platforms](#supported-platforms) - * [Using the `v2` branch](#using-the-v2-branch) - * [Pinning to the `v1` releases](#pinning-to-the-v1-releases) -- [Getting Started](#getting-started) -- [Examples](#examples) - * [Arguments](#arguments) - * [Flags](#flags) - + [Placeholder Values](#placeholder-values) - + [Alternate Names](#alternate-names) - + [Ordering](#ordering) - + [Values from the Environment](#values-from-the-environment) - + [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others) - * [Subcommands](#subcommands) - * [Subcommands categories](#subcommands-categories) - * [Exit code](#exit-code) - * [Bash Completion](#bash-completion) - + [Enabling](#enabling) - + [Distribution](#distribution) - + [Customization](#customization) - * [Generated Help Text](#generated-help-text) - + [Customization](#customization-1) - * [Version Flag](#version-flag) - + [Customization](#customization-2) - + [Full API Example](#full-api-example) -- [Contribution Guidelines](#contribution-guidelines) - - - -## Overview - -Command line apps are usually so tiny that there is absolutely no reason why -your code should *not* be self-documenting. Things like generating help text and -parsing command flags/options should not hinder productivity when writing a -command line app. - -**This is where cli comes into play.** cli makes command line programming fun, -organized, and expressive! - -## Installation - -Make sure you have a working Go environment. Go version 1.2+ is supported. [See -the install instructions for Go](http://golang.org/doc/install.html). - -To install cli, simply run: -``` -$ go get github.com/urfave/cli -``` - -Make sure your `PATH` includes the `$GOPATH/bin` directory so your commands can -be easily used: -``` -export PATH=$PATH:$GOPATH/bin -``` - -### Supported platforms - -cli is tested against multiple versions of Go on Linux, and against the latest -released version of Go on OS X and Windows. For full details, see -[`./.travis.yml`](./.travis.yml) and [`./appveyor.yml`](./appveyor.yml). - -### Using the `v2` branch - -**Warning**: The `v2` branch is currently unreleased and considered unstable. - -There is currently a long-lived branch named `v2` that is intended to land as -the new `master` branch once development there has settled down. The current -`master` branch (mirrored as `v1`) is being manually merged into `v2` on -an irregular human-based schedule, but generally if one wants to "upgrade" to -`v2` *now* and accept the volatility (read: "awesomeness") that comes along with -that, please use whatever version pinning of your preference, such as via -`gopkg.in`: - -``` -$ go get gopkg.in/urfave/cli.v2 -``` - -``` go -... -import ( - "gopkg.in/urfave/cli.v2" // imports as package "cli" -) -... -``` - -### Pinning to the `v1` releases - -Similarly to the section above describing use of the `v2` branch, if one wants -to avoid any unexpected compatibility pains once `v2` becomes `master`, then -pinning to `v1` is an acceptable option, e.g.: - -``` -$ go get gopkg.in/urfave/cli.v1 -``` - -``` go -... -import ( - "gopkg.in/urfave/cli.v1" // imports as package "cli" -) -... -``` - -This will pull the latest tagged `v1` release (e.g. `v1.18.1` at the time of writing). - -## Getting Started - -One of the philosophies behind cli is that an API should be playful and full of -discovery. So a cli app can be as little as one line of code in `main()`. - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - cli.NewApp().Run(os.Args) -} -``` - -This app will run and show help text, but is not very useful. Let's give an -action to execute and some help documentation: - - -``` go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - app.Name = "boom" - app.Usage = "make an explosive entrance" - app.Action = func(c *cli.Context) error { - fmt.Println("boom! I say!") - return nil - } - - app.Run(os.Args) -} -``` - -Running this already gives you a ton of functionality, plus support for things -like subcommands and flags, which are covered below. - -## Examples - -Being a programmer can be a lonely job. Thankfully by the power of automation -that is not the case! Let's create a greeter app to fend off our demons of -loneliness! - -Start by creating a directory named `greet`, and within it, add a file, -`greet.go` with the following code in it: - - -``` go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - app.Name = "greet" - app.Usage = "fight the loneliness!" - app.Action = func(c *cli.Context) error { - fmt.Println("Hello friend!") - return nil - } - - app.Run(os.Args) -} -``` - -Install our command to the `$GOPATH/bin` directory: - -``` -$ go install -``` - -Finally run our new command: - -``` -$ greet -Hello friend! -``` - -cli also generates neat help text: - -``` -$ greet help -NAME: - greet - fight the loneliness! - -USAGE: - greet [global options] command [command options] [arguments...] - -VERSION: - 0.0.0 - -COMMANDS: - help, h Shows a list of commands or help for one command - -GLOBAL OPTIONS - --version Shows version information -``` - -### Arguments - -You can lookup arguments by calling the `Args` function on `cli.Context`, e.g.: - - -``` go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Action = func(c *cli.Context) error { - fmt.Printf("Hello %q", c.Args().Get(0)) - return nil - } - - app.Run(os.Args) -} -``` - -### Flags - -Setting and querying flags is simple. - - -``` go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang", - Value: "english", - Usage: "language for the greeting", - }, - } - - app.Action = func(c *cli.Context) error { - name := "Nefertiti" - if c.NArg() > 0 { - name = c.Args().Get(0) - } - if c.String("lang") == "spanish" { - fmt.Println("Hola", name) - } else { - fmt.Println("Hello", name) - } - return nil - } - - app.Run(os.Args) -} -``` - -You can also set a destination variable for a flag, to which the content will be -scanned. - - -``` go -package main - -import ( - "os" - "fmt" - - "github.com/urfave/cli" -) - -func main() { - var language string - - app := cli.NewApp() - - app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang", - Value: "english", - Usage: "language for the greeting", - Destination: &language, - }, - } - - app.Action = func(c *cli.Context) error { - name := "someone" - if c.NArg() > 0 { - name = c.Args()[0] - } - if language == "spanish" { - fmt.Println("Hola", name) - } else { - fmt.Println("Hello", name) - } - return nil - } - - app.Run(os.Args) -} -``` - -See full list of flags at http://godoc.org/github.com/urfave/cli - -#### Placeholder Values - -Sometimes it's useful to specify a flag's value within the usage string itself. -Such placeholders are indicated with back quotes. - -For example this: - - -```go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag{ - cli.StringFlag{ - Name: "config, c", - Usage: "Load configuration from `FILE`", - }, - } - - app.Run(os.Args) -} -``` - -Will result in help output like: - -``` ---config FILE, -c FILE Load configuration from FILE -``` - -Note that only the first placeholder is used. Subsequent back-quoted words will -be left as-is. - -#### Alternate Names - -You can set alternate (or short) names for flags by providing a comma-delimited -list for the `Name`. e.g. - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "language for the greeting", - }, - } - - app.Run(os.Args) -} -``` - -That flag can then be set with `--lang spanish` or `-l spanish`. Note that -giving two different forms of the same flag in the same command invocation is an -error. - -#### Ordering - -Flags for the application and commands are shown in the order they are defined. -However, it's possible to sort them from outside this library by using `FlagsByName` -or `CommandsByName` with `sort`. - -For example this: - - -``` go -package main - -import ( - "os" - "sort" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "Language for the greeting", - }, - cli.StringFlag{ - Name: "config, c", - Usage: "Load configuration from `FILE`", - }, - } - - app.Commands = []cli.Command{ - { - Name: "complete", - Aliases: []string{"c"}, - Usage: "complete a task on the list", - Action: func(c *cli.Context) error { - return nil - }, - }, - { - Name: "add", - Aliases: []string{"a"}, - Usage: "add a task to the list", - Action: func(c *cli.Context) error { - return nil - }, - }, - } - - sort.Sort(cli.FlagsByName(app.Flags)) - sort.Sort(cli.CommandsByName(app.Commands)) - - app.Run(os.Args) -} -``` - -Will result in help output like: - -``` ---config FILE, -c FILE Load configuration from FILE ---lang value, -l value Language for the greeting (default: "english") -``` - -#### Values from the Environment - -You can also have the default value set from the environment via `EnvVar`. e.g. - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "language for the greeting", - EnvVar: "APP_LANG", - }, - } - - app.Run(os.Args) -} -``` - -The `EnvVar` may also be given as a comma-delimited "cascade", where the first -environment variable that resolves is used as the default. - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag { - cli.StringFlag{ - Name: "lang, l", - Value: "english", - Usage: "language for the greeting", - EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG", - }, - } - - app.Run(os.Args) -} -``` - -#### Values from alternate input sources (YAML, TOML, and others) - -There is a separate package altsrc that adds support for getting flag values -from other file input sources. - -Currently supported input source formats: -* YAML -* TOML - -In order to get values for a flag from an alternate input source the following -code would be added to wrap an existing cli.Flag like below: - -``` go - altsrc.NewIntFlag(cli.IntFlag{Name: "test"}) -``` - -Initialization must also occur for these flags. Below is an example initializing -getting data from a yaml file below. - -``` go - command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load")) -``` - -The code above will use the "load" string as a flag name to get the file name of -a yaml file from the cli.Context. It will then use that file name to initialize -the yaml input source for any flags that are defined on that command. As a note -the "load" flag used would also have to be defined on the command flags in order -for this code snipped to work. - -Currently only the aboved specified formats are supported but developers can -add support for other input sources by implementing the -altsrc.InputSourceContext for their given sources. - -Here is a more complete sample of a command using YAML support: - - -``` go -package notmain - -import ( - "fmt" - "os" - - "github.com/urfave/cli" - "github.com/urfave/cli/altsrc" -) - -func main() { - app := cli.NewApp() - - flags := []cli.Flag{ - altsrc.NewIntFlag(cli.IntFlag{Name: "test"}), - cli.StringFlag{Name: "load"}, - } - - app.Action = func(c *cli.Context) error { - fmt.Println("yaml ist rad") - return nil - } - - app.Before = altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("load")) - app.Flags = flags - - app.Run(os.Args) -} -``` - -### Subcommands - -Subcommands can be defined for a more git-like command line app. - - -```go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Commands = []cli.Command{ - { - Name: "add", - Aliases: []string{"a"}, - Usage: "add a task to the list", - Action: func(c *cli.Context) error { - fmt.Println("added task: ", c.Args().First()) - return nil - }, - }, - { - Name: "complete", - Aliases: []string{"c"}, - Usage: "complete a task on the list", - Action: func(c *cli.Context) error { - fmt.Println("completed task: ", c.Args().First()) - return nil - }, - }, - { - Name: "template", - Aliases: []string{"t"}, - Usage: "options for task templates", - Subcommands: []cli.Command{ - { - Name: "add", - Usage: "add a new template", - Action: func(c *cli.Context) error { - fmt.Println("new task template: ", c.Args().First()) - return nil - }, - }, - { - Name: "remove", - Usage: "remove an existing template", - Action: func(c *cli.Context) error { - fmt.Println("removed task template: ", c.Args().First()) - return nil - }, - }, - }, - }, - } - - app.Run(os.Args) -} -``` - -### Subcommands categories - -For additional organization in apps that have many subcommands, you can -associate a category for each command to group them together in the help -output. - -E.g. - -```go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - - app.Commands = []cli.Command{ - { - Name: "noop", - }, - { - Name: "add", - Category: "template", - }, - { - Name: "remove", - Category: "template", - }, - } - - app.Run(os.Args) -} -``` - -Will include: - -``` -COMMANDS: - noop - - Template actions: - add - remove -``` - -### Exit code - -Calling `App.Run` will not automatically call `os.Exit`, which means that by -default the exit code will "fall through" to being `0`. An explicit exit code -may be set by returning a non-nil error that fulfills `cli.ExitCoder`, *or* a -`cli.MultiError` that includes an error that fulfills `cli.ExitCoder`, e.g.: - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - app := cli.NewApp() - app.Flags = []cli.Flag{ - cli.BoolTFlag{ - Name: "ginger-crouton", - Usage: "is it in the soup?", - }, - } - app.Action = func(ctx *cli.Context) error { - if !ctx.Bool("ginger-crouton") { - return cli.NewExitError("it is not in the soup", 86) - } - return nil - } - - app.Run(os.Args) -} -``` - -### Bash Completion - -You can enable completion commands by setting the `EnableBashCompletion` -flag on the `App` object. By default, this setting will only auto-complete to -show an app's subcommands, but you can write your own completion methods for -the App or its subcommands. - - -``` go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -func main() { - tasks := []string{"cook", "clean", "laundry", "eat", "sleep", "code"} - - app := cli.NewApp() - app.EnableBashCompletion = true - app.Commands = []cli.Command{ - { - Name: "complete", - Aliases: []string{"c"}, - Usage: "complete a task on the list", - Action: func(c *cli.Context) error { - fmt.Println("completed task: ", c.Args().First()) - return nil - }, - BashComplete: func(c *cli.Context) { - // This will complete if no args are passed - if c.NArg() > 0 { - return - } - for _, t := range tasks { - fmt.Println(t) - } - }, - }, - } - - app.Run(os.Args) -} -``` - -#### Enabling - -Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while -setting the `PROG` variable to the name of your program: - -`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete` - -#### Distribution - -Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename -it to the name of the program you wish to add autocomplete support for (or -automatically install it there if you are distributing a package). Don't forget -to source the file to make it active in the current shell. - -``` -sudo cp src/bash_autocomplete /etc/bash_completion.d/ -source /etc/bash_completion.d/ -``` - -Alternatively, you can just document that users should source the generic -`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set -to the name of their program (as above). - -#### Customization - -The default bash completion flag (`--generate-bash-completion`) is defined as -`cli.BashCompletionFlag`, and may be redefined if desired, e.g.: - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - cli.BashCompletionFlag = cli.BoolFlag{ - Name: "compgen", - Hidden: true, - } - - app := cli.NewApp() - app.EnableBashCompletion = true - app.Commands = []cli.Command{ - { - Name: "wat", - }, - } - app.Run(os.Args) -} -``` - -### Generated Help Text - -The default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked -by the cli internals in order to print generated help text for the app, command, -or subcommand, and break execution. - -#### Customization - -All of the help text generation may be customized, and at multiple levels. The -templates are exposed as variables `AppHelpTemplate`, `CommandHelpTemplate`, and -`SubcommandHelpTemplate` which may be reassigned or augmented, and full override -is possible by assigning a compatible func to the `cli.HelpPrinter` variable, -e.g.: - - -``` go -package main - -import ( - "fmt" - "io" - "os" - - "github.com/urfave/cli" -) - -func main() { - // EXAMPLE: Append to an existing template - cli.AppHelpTemplate = fmt.Sprintf(`%s - -WEBSITE: http://awesometown.example.com - -SUPPORT: support@awesometown.example.com - -`, cli.AppHelpTemplate) - - // EXAMPLE: Override a template - cli.AppHelpTemplate = `NAME: - {{.Name}} - {{.Usage}} -USAGE: - {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} - {{if len .Authors}} -AUTHOR: - {{range .Authors}}{{ . }}{{end}} - {{end}}{{if .Commands}} -COMMANDS: -{{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t"}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}} -GLOBAL OPTIONS: - {{range .VisibleFlags}}{{.}} - {{end}}{{end}}{{if .Copyright }} -COPYRIGHT: - {{.Copyright}} - {{end}}{{if .Version}} -VERSION: - {{.Version}} - {{end}} -` - - // EXAMPLE: Replace the `HelpPrinter` func - cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) { - fmt.Println("Ha HA. I pwnd the help!!1") - } - - cli.NewApp().Run(os.Args) -} -``` - -The default flag may be customized to something other than `-h/--help` by -setting `cli.HelpFlag`, e.g.: - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - cli.HelpFlag = cli.BoolFlag{ - Name: "halp, haaaaalp", - Usage: "HALP", - EnvVar: "SHOW_HALP,HALPPLZ", - } - - cli.NewApp().Run(os.Args) -} -``` - -### Version Flag - -The default version flag (`-v/--version`) is defined as `cli.VersionFlag`, which -is checked by the cli internals in order to print the `App.Version` via -`cli.VersionPrinter` and break execution. - -#### Customization - -The default flag may be customized to something other than `-v/--version` by -setting `cli.VersionFlag`, e.g.: - - -``` go -package main - -import ( - "os" - - "github.com/urfave/cli" -) - -func main() { - cli.VersionFlag = cli.BoolFlag{ - Name: "print-version, V", - Usage: "print only the version", - } - - app := cli.NewApp() - app.Name = "partay" - app.Version = "19.99.0" - app.Run(os.Args) -} -``` - -Alternatively, the version printer at `cli.VersionPrinter` may be overridden, e.g.: - - -``` go -package main - -import ( - "fmt" - "os" - - "github.com/urfave/cli" -) - -var ( - Revision = "fafafaf" -) - -func main() { - cli.VersionPrinter = func(c *cli.Context) { - fmt.Printf("version=%s revision=%s\n", c.App.Version, Revision) - } - - app := cli.NewApp() - app.Name = "partay" - app.Version = "19.99.0" - app.Run(os.Args) -} -``` - -#### Full API Example - -**Notice**: This is a contrived (functioning) example meant strictly for API -demonstration purposes. Use of one's imagination is encouraged. - - -``` go -package main - -import ( - "errors" - "flag" - "fmt" - "io" - "io/ioutil" - "os" - "time" - - "github.com/urfave/cli" -) - -func init() { - cli.AppHelpTemplate += "\nCUSTOMIZED: you bet ur muffins\n" - cli.CommandHelpTemplate += "\nYMMV\n" - cli.SubcommandHelpTemplate += "\nor something\n" - - cli.HelpFlag = cli.BoolFlag{Name: "halp"} - cli.BashCompletionFlag = cli.BoolFlag{Name: "compgen", Hidden: true} - cli.VersionFlag = cli.BoolFlag{Name: "print-version, V"} - - cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) { - fmt.Fprintf(w, "best of luck to you\n") - } - cli.VersionPrinter = func(c *cli.Context) { - fmt.Fprintf(c.App.Writer, "version=%s\n", c.App.Version) - } - cli.OsExiter = func(c int) { - fmt.Fprintf(cli.ErrWriter, "refusing to exit %d\n", c) - } - cli.ErrWriter = ioutil.Discard - cli.FlagStringer = func(fl cli.Flag) string { - return fmt.Sprintf("\t\t%s", fl.GetName()) - } -} - -type hexWriter struct{} - -func (w *hexWriter) Write(p []byte) (int, error) { - for _, b := range p { - fmt.Printf("%x", b) - } - fmt.Printf("\n") - - return len(p), nil -} - -type genericType struct{ - s string -} - -func (g *genericType) Set(value string) error { - g.s = value - return nil -} - -func (g *genericType) String() string { - return g.s -} - -func main() { - app := cli.NewApp() - app.Name = "kənˈtrīv" - app.Version = "19.99.0" - app.Compiled = time.Now() - app.Authors = []cli.Author{ - cli.Author{ - Name: "Example Human", - Email: "human@example.com", - }, - } - app.Copyright = "(c) 1999 Serious Enterprise" - app.HelpName = "contrive" - app.Usage = "demonstrate available API" - app.UsageText = "contrive - demonstrating the available API" - app.ArgsUsage = "[args and such]" - app.Commands = []cli.Command{ - cli.Command{ - Name: "doo", - Aliases: []string{"do"}, - Category: "motion", - Usage: "do the doo", - UsageText: "doo - does the dooing", - Description: "no really, there is a lot of dooing to be done", - ArgsUsage: "[arrgh]", - Flags: []cli.Flag{ - cli.BoolFlag{Name: "forever, forevvarr"}, - }, - Subcommands: cli.Commands{ - cli.Command{ - Name: "wop", - Action: wopAction, - }, - }, - SkipFlagParsing: false, - HideHelp: false, - Hidden: false, - HelpName: "doo!", - BashComplete: func(c *cli.Context) { - fmt.Fprintf(c.App.Writer, "--better\n") - }, - Before: func(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, "brace for impact\n") - return nil - }, - After: func(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, "did we lose anyone?\n") - return nil - }, - Action: func(c *cli.Context) error { - c.Command.FullName() - c.Command.HasName("wop") - c.Command.Names() - c.Command.VisibleFlags() - fmt.Fprintf(c.App.Writer, "dodododododoodododddooooododododooo\n") - if c.Bool("forever") { - c.Command.Run(c) - } - return nil - }, - OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error { - fmt.Fprintf(c.App.Writer, "for shame\n") - return err - }, - }, - } - app.Flags = []cli.Flag{ - cli.BoolFlag{Name: "fancy"}, - cli.BoolTFlag{Name: "fancier"}, - cli.DurationFlag{Name: "howlong, H", Value: time.Second * 3}, - cli.Float64Flag{Name: "howmuch"}, - cli.GenericFlag{Name: "wat", Value: &genericType{}}, - cli.Int64Flag{Name: "longdistance"}, - cli.Int64SliceFlag{Name: "intervals"}, - cli.IntFlag{Name: "distance"}, - cli.IntSliceFlag{Name: "times"}, - cli.StringFlag{Name: "dance-move, d"}, - cli.StringSliceFlag{Name: "names, N"}, - cli.UintFlag{Name: "age"}, - cli.Uint64Flag{Name: "bigage"}, - } - app.EnableBashCompletion = true - app.HideHelp = false - app.HideVersion = false - app.BashComplete = func(c *cli.Context) { - fmt.Fprintf(c.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n") - } - app.Before = func(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, "HEEEERE GOES\n") - return nil - } - app.After = func(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, "Phew!\n") - return nil - } - app.CommandNotFound = func(c *cli.Context, command string) { - fmt.Fprintf(c.App.Writer, "Thar be no %q here.\n", command) - } - app.OnUsageError = func(c *cli.Context, err error, isSubcommand bool) error { - if isSubcommand { - return err - } - - fmt.Fprintf(c.App.Writer, "WRONG: %#v\n", err) - return nil - } - app.Action = func(c *cli.Context) error { - cli.DefaultAppComplete(c) - cli.HandleExitCoder(errors.New("not an exit coder, though")) - cli.ShowAppHelp(c) - cli.ShowCommandCompletions(c, "nope") - cli.ShowCommandHelp(c, "also-nope") - cli.ShowCompletions(c) - cli.ShowSubcommandHelp(c) - cli.ShowVersion(c) - - categories := c.App.Categories() - categories.AddCommand("sounds", cli.Command{ - Name: "bloop", - }) - - for _, category := range c.App.Categories() { - fmt.Fprintf(c.App.Writer, "%s\n", category.Name) - fmt.Fprintf(c.App.Writer, "%#v\n", category.Commands) - fmt.Fprintf(c.App.Writer, "%#v\n", category.VisibleCommands()) - } - - fmt.Printf("%#v\n", c.App.Command("doo")) - if c.Bool("infinite") { - c.App.Run([]string{"app", "doo", "wop"}) - } - - if c.Bool("forevar") { - c.App.RunAsSubcommand(c) - } - c.App.Setup() - fmt.Printf("%#v\n", c.App.VisibleCategories()) - fmt.Printf("%#v\n", c.App.VisibleCommands()) - fmt.Printf("%#v\n", c.App.VisibleFlags()) - - fmt.Printf("%#v\n", c.Args().First()) - if len(c.Args()) > 0 { - fmt.Printf("%#v\n", c.Args()[1]) - } - fmt.Printf("%#v\n", c.Args().Present()) - fmt.Printf("%#v\n", c.Args().Tail()) - - set := flag.NewFlagSet("contrive", 0) - nc := cli.NewContext(c.App, set, c) - - fmt.Printf("%#v\n", nc.Args()) - fmt.Printf("%#v\n", nc.Bool("nope")) - fmt.Printf("%#v\n", nc.BoolT("nerp")) - fmt.Printf("%#v\n", nc.Duration("howlong")) - fmt.Printf("%#v\n", nc.Float64("hay")) - fmt.Printf("%#v\n", nc.Generic("bloop")) - fmt.Printf("%#v\n", nc.Int64("bonk")) - fmt.Printf("%#v\n", nc.Int64Slice("burnks")) - fmt.Printf("%#v\n", nc.Int("bips")) - fmt.Printf("%#v\n", nc.IntSlice("blups")) - fmt.Printf("%#v\n", nc.String("snurt")) - fmt.Printf("%#v\n", nc.StringSlice("snurkles")) - fmt.Printf("%#v\n", nc.Uint("flub")) - fmt.Printf("%#v\n", nc.Uint64("florb")) - fmt.Printf("%#v\n", nc.GlobalBool("global-nope")) - fmt.Printf("%#v\n", nc.GlobalBoolT("global-nerp")) - fmt.Printf("%#v\n", nc.GlobalDuration("global-howlong")) - fmt.Printf("%#v\n", nc.GlobalFloat64("global-hay")) - fmt.Printf("%#v\n", nc.GlobalGeneric("global-bloop")) - fmt.Printf("%#v\n", nc.GlobalInt("global-bips")) - fmt.Printf("%#v\n", nc.GlobalIntSlice("global-blups")) - fmt.Printf("%#v\n", nc.GlobalString("global-snurt")) - fmt.Printf("%#v\n", nc.GlobalStringSlice("global-snurkles")) - - fmt.Printf("%#v\n", nc.FlagNames()) - fmt.Printf("%#v\n", nc.GlobalFlagNames()) - fmt.Printf("%#v\n", nc.GlobalIsSet("wat")) - fmt.Printf("%#v\n", nc.GlobalSet("wat", "nope")) - fmt.Printf("%#v\n", nc.NArg()) - fmt.Printf("%#v\n", nc.NumFlags()) - fmt.Printf("%#v\n", nc.Parent()) - - nc.Set("wat", "also-nope") - - ec := cli.NewExitError("ohwell", 86) - fmt.Fprintf(c.App.Writer, "%d", ec.ExitCode()) - fmt.Printf("made it!\n") - return ec - } - - if os.Getenv("HEXY") != "" { - app.Writer = &hexWriter{} - app.ErrWriter = &hexWriter{} - } - - app.Metadata = map[string]interface{}{ - "layers": "many", - "explicable": false, - "whatever-values": 19.99, - } - - app.Run(os.Args) -} - -func wopAction(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, ":wave: over here, eh\n") - return nil -} -``` - -## Contribution Guidelines - -Feel free to put up a pull request to fix a bug or maybe add a feature. I will -give it a code review and make sure that it does not break backwards -compatibility. If I or any other collaborators agree that it is in line with -the vision of the project, we will work with you to get the code into -a mergeable state and merge it into the master branch. - -If you have contributed something significant to the project, we will most -likely add you as a collaborator. As a collaborator you are given the ability -to merge others pull requests. It is very important that new code does not -break existing code, so be careful about what code you do choose to merge. - -If you feel like you have contributed to the project but have not yet been -added as a collaborator, we probably forgot to add you, please open an issue. diff --git a/vendor/github.com/urfave/cli/appveyor.yml b/vendor/github.com/urfave/cli/appveyor.yml deleted file mode 100644 index 1e1489c36..000000000 --- a/vendor/github.com/urfave/cli/appveyor.yml +++ /dev/null @@ -1,26 +0,0 @@ -version: "{build}" - -os: Windows Server 2016 - -image: Visual Studio 2017 - -clone_folder: c:\gopath\src\github.com\urfave\cli - -environment: - GOPATH: C:\gopath - GOVERSION: 1.8.x - PYTHON: C:\Python36-x64 - PYTHON_VERSION: 3.6.x - PYTHON_ARCH: 64 - -install: -- set PATH=%GOPATH%\bin;C:\go\bin;%PATH% -- go version -- go env -- go get github.com/urfave/gfmrun/... -- go get -v -t ./... - -build_script: -- python runtests vet -- python runtests test -- python runtests gfmrun diff --git a/vendor/github.com/urfave/cli/category.go b/vendor/github.com/urfave/cli/category.go deleted file mode 100644 index 1a6055023..000000000 --- a/vendor/github.com/urfave/cli/category.go +++ /dev/null @@ -1,44 +0,0 @@ -package cli - -// CommandCategories is a slice of *CommandCategory. -type CommandCategories []*CommandCategory - -// CommandCategory is a category containing commands. -type CommandCategory struct { - Name string - Commands Commands -} - -func (c CommandCategories) Less(i, j int) bool { - return c[i].Name < c[j].Name -} - -func (c CommandCategories) Len() int { - return len(c) -} - -func (c CommandCategories) Swap(i, j int) { - c[i], c[j] = c[j], c[i] -} - -// AddCommand adds a command to a category. -func (c CommandCategories) AddCommand(category string, command Command) CommandCategories { - for _, commandCategory := range c { - if commandCategory.Name == category { - commandCategory.Commands = append(commandCategory.Commands, command) - return c - } - } - return append(c, &CommandCategory{Name: category, Commands: []Command{command}}) -} - -// VisibleCommands returns a slice of the Commands with Hidden=false -func (c *CommandCategory) VisibleCommands() []Command { - ret := []Command{} - for _, command := range c.Commands { - if !command.Hidden { - ret = append(ret, command) - } - } - return ret -} diff --git a/vendor/github.com/urfave/cli/context.go b/vendor/github.com/urfave/cli/context.go deleted file mode 100644 index db94191e2..000000000 --- a/vendor/github.com/urfave/cli/context.go +++ /dev/null @@ -1,278 +0,0 @@ -package cli - -import ( - "errors" - "flag" - "reflect" - "strings" - "syscall" -) - -// Context is a type that is passed through to -// each Handler action in a cli application. Context -// can be used to retrieve context-specific Args and -// parsed command-line options. -type Context struct { - App *App - Command Command - shellComplete bool - flagSet *flag.FlagSet - setFlags map[string]bool - parentContext *Context -} - -// NewContext creates a new context. For use in when invoking an App or Command action. -func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { - c := &Context{App: app, flagSet: set, parentContext: parentCtx} - - if parentCtx != nil { - c.shellComplete = parentCtx.shellComplete - } - - return c -} - -// NumFlags returns the number of flags set -func (c *Context) NumFlags() int { - return c.flagSet.NFlag() -} - -// Set sets a context flag to a value. -func (c *Context) Set(name, value string) error { - c.setFlags = nil - return c.flagSet.Set(name, value) -} - -// GlobalSet sets a context flag to a value on the global flagset -func (c *Context) GlobalSet(name, value string) error { - globalContext(c).setFlags = nil - return globalContext(c).flagSet.Set(name, value) -} - -// IsSet determines if the flag was actually set -func (c *Context) IsSet(name string) bool { - if c.setFlags == nil { - c.setFlags = make(map[string]bool) - - c.flagSet.Visit(func(f *flag.Flag) { - c.setFlags[f.Name] = true - }) - - c.flagSet.VisitAll(func(f *flag.Flag) { - if _, ok := c.setFlags[f.Name]; ok { - return - } - c.setFlags[f.Name] = false - }) - - // XXX hack to support IsSet for flags with EnvVar - // - // There isn't an easy way to do this with the current implementation since - // whether a flag was set via an environment variable is very difficult to - // determine here. Instead, we intend to introduce a backwards incompatible - // change in version 2 to add `IsSet` to the Flag interface to push the - // responsibility closer to where the information required to determine - // whether a flag is set by non-standard means such as environment - // variables is avaliable. - // - // See https://github.com/urfave/cli/issues/294 for additional discussion - flags := c.Command.Flags - if c.Command.Name == "" { // cannot == Command{} since it contains slice types - if c.App != nil { - flags = c.App.Flags - } - } - for _, f := range flags { - eachName(f.GetName(), func(name string) { - if isSet, ok := c.setFlags[name]; isSet || !ok { - return - } - - val := reflect.ValueOf(f) - if val.Kind() == reflect.Ptr { - val = val.Elem() - } - - envVarValue := val.FieldByName("EnvVar") - if !envVarValue.IsValid() { - return - } - - eachName(envVarValue.String(), func(envVar string) { - envVar = strings.TrimSpace(envVar) - if _, ok := syscall.Getenv(envVar); ok { - c.setFlags[name] = true - return - } - }) - }) - } - } - - return c.setFlags[name] -} - -// GlobalIsSet determines if the global flag was actually set -func (c *Context) GlobalIsSet(name string) bool { - ctx := c - if ctx.parentContext != nil { - ctx = ctx.parentContext - } - - for ; ctx != nil; ctx = ctx.parentContext { - if ctx.IsSet(name) { - return true - } - } - return false -} - -// FlagNames returns a slice of flag names used in this context. -func (c *Context) FlagNames() (names []string) { - for _, flag := range c.Command.Flags { - name := strings.Split(flag.GetName(), ",")[0] - if name == "help" { - continue - } - names = append(names, name) - } - return -} - -// GlobalFlagNames returns a slice of global flag names used by the app. -func (c *Context) GlobalFlagNames() (names []string) { - for _, flag := range c.App.Flags { - name := strings.Split(flag.GetName(), ",")[0] - if name == "help" || name == "version" { - continue - } - names = append(names, name) - } - return -} - -// Parent returns the parent context, if any -func (c *Context) Parent() *Context { - return c.parentContext -} - -// value returns the value of the flag coressponding to `name` -func (c *Context) value(name string) interface{} { - return c.flagSet.Lookup(name).Value.(flag.Getter).Get() -} - -// Args contains apps console arguments -type Args []string - -// Args returns the command line arguments associated with the context. -func (c *Context) Args() Args { - args := Args(c.flagSet.Args()) - return args -} - -// NArg returns the number of the command line arguments. -func (c *Context) NArg() int { - return len(c.Args()) -} - -// Get returns the nth argument, or else a blank string -func (a Args) Get(n int) string { - if len(a) > n { - return a[n] - } - return "" -} - -// First returns the first argument, or else a blank string -func (a Args) First() string { - return a.Get(0) -} - -// Tail returns the rest of the arguments (not the first one) -// or else an empty string slice -func (a Args) Tail() []string { - if len(a) >= 2 { - return []string(a)[1:] - } - return []string{} -} - -// Present checks if there are any arguments present -func (a Args) Present() bool { - return len(a) != 0 -} - -// Swap swaps arguments at the given indexes -func (a Args) Swap(from, to int) error { - if from >= len(a) || to >= len(a) { - return errors.New("index out of range") - } - a[from], a[to] = a[to], a[from] - return nil -} - -func globalContext(ctx *Context) *Context { - if ctx == nil { - return nil - } - - for { - if ctx.parentContext == nil { - return ctx - } - ctx = ctx.parentContext - } -} - -func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet { - if ctx.parentContext != nil { - ctx = ctx.parentContext - } - for ; ctx != nil; ctx = ctx.parentContext { - if f := ctx.flagSet.Lookup(name); f != nil { - return ctx.flagSet - } - } - return nil -} - -func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { - switch ff.Value.(type) { - case *StringSlice: - default: - set.Set(name, ff.Value.String()) - } -} - -func normalizeFlags(flags []Flag, set *flag.FlagSet) error { - visited := make(map[string]bool) - set.Visit(func(f *flag.Flag) { - visited[f.Name] = true - }) - for _, f := range flags { - parts := strings.Split(f.GetName(), ",") - if len(parts) == 1 { - continue - } - var ff *flag.Flag - for _, name := range parts { - name = strings.Trim(name, " ") - if visited[name] { - if ff != nil { - return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name) - } - ff = set.Lookup(name) - } - } - if ff == nil { - continue - } - for _, name := range parts { - name = strings.Trim(name, " ") - if !visited[name] { - copyFlag(name, ff, set) - } - } - } - return nil -} diff --git a/vendor/github.com/urfave/cli/flag-types.json b/vendor/github.com/urfave/cli/flag-types.json deleted file mode 100644 index 122310785..000000000 --- a/vendor/github.com/urfave/cli/flag-types.json +++ /dev/null @@ -1,93 +0,0 @@ -[ - { - "name": "Bool", - "type": "bool", - "value": false, - "context_default": "false", - "parser": "strconv.ParseBool(f.Value.String())" - }, - { - "name": "BoolT", - "type": "bool", - "value": false, - "doctail": " that is true by default", - "context_default": "false", - "parser": "strconv.ParseBool(f.Value.String())" - }, - { - "name": "Duration", - "type": "time.Duration", - "doctail": " (see https://golang.org/pkg/time/#ParseDuration)", - "context_default": "0", - "parser": "time.ParseDuration(f.Value.String())" - }, - { - "name": "Float64", - "type": "float64", - "context_default": "0", - "parser": "strconv.ParseFloat(f.Value.String(), 64)" - }, - { - "name": "Generic", - "type": "Generic", - "dest": false, - "context_default": "nil", - "context_type": "interface{}" - }, - { - "name": "Int64", - "type": "int64", - "context_default": "0", - "parser": "strconv.ParseInt(f.Value.String(), 0, 64)" - }, - { - "name": "Int", - "type": "int", - "context_default": "0", - "parser": "strconv.ParseInt(f.Value.String(), 0, 64)", - "parser_cast": "int(parsed)" - }, - { - "name": "IntSlice", - "type": "*IntSlice", - "dest": false, - "context_default": "nil", - "context_type": "[]int", - "parser": "(f.Value.(*IntSlice)).Value(), error(nil)" - }, - { - "name": "Int64Slice", - "type": "*Int64Slice", - "dest": false, - "context_default": "nil", - "context_type": "[]int64", - "parser": "(f.Value.(*Int64Slice)).Value(), error(nil)" - }, - { - "name": "String", - "type": "string", - "context_default": "\"\"", - "parser": "f.Value.String(), error(nil)" - }, - { - "name": "StringSlice", - "type": "*StringSlice", - "dest": false, - "context_default": "nil", - "context_type": "[]string", - "parser": "(f.Value.(*StringSlice)).Value(), error(nil)" - }, - { - "name": "Uint64", - "type": "uint64", - "context_default": "0", - "parser": "strconv.ParseUint(f.Value.String(), 0, 64)" - }, - { - "name": "Uint", - "type": "uint", - "context_default": "0", - "parser": "strconv.ParseUint(f.Value.String(), 0, 64)", - "parser_cast": "uint(parsed)" - } -] diff --git a/vendor/github.com/urfave/cli/flag.go b/vendor/github.com/urfave/cli/flag.go deleted file mode 100644 index 877ff3523..000000000 --- a/vendor/github.com/urfave/cli/flag.go +++ /dev/null @@ -1,799 +0,0 @@ -package cli - -import ( - "flag" - "fmt" - "reflect" - "runtime" - "strconv" - "strings" - "syscall" - "time" -) - -const defaultPlaceholder = "value" - -// BashCompletionFlag enables bash-completion for all commands and subcommands -var BashCompletionFlag Flag = BoolFlag{ - Name: "generate-bash-completion", - Hidden: true, -} - -// VersionFlag prints the version for the application -var VersionFlag Flag = BoolFlag{ - Name: "version, v", - Usage: "print the version", -} - -// HelpFlag prints the help for all commands and subcommands -// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand -// unless HideHelp is set to true) -var HelpFlag Flag = BoolFlag{ - Name: "help, h", - Usage: "show help", -} - -// FlagStringer converts a flag definition to a string. This is used by help -// to display a flag. -var FlagStringer FlagStringFunc = stringifyFlag - -// FlagsByName is a slice of Flag. -type FlagsByName []Flag - -func (f FlagsByName) Len() int { - return len(f) -} - -func (f FlagsByName) Less(i, j int) bool { - return f[i].GetName() < f[j].GetName() -} - -func (f FlagsByName) Swap(i, j int) { - f[i], f[j] = f[j], f[i] -} - -// Flag is a common interface related to parsing flags in cli. -// For more advanced flag parsing techniques, it is recommended that -// this interface be implemented. -type Flag interface { - fmt.Stringer - // Apply Flag settings to the given flag set - Apply(*flag.FlagSet) - GetName() string -} - -// errorableFlag is an interface that allows us to return errors during apply -// it allows flags defined in this library to return errors in a fashion backwards compatible -// TODO remove in v2 and modify the existing Flag interface to return errors -type errorableFlag interface { - Flag - - ApplyWithError(*flag.FlagSet) error -} - -func flagSet(name string, flags []Flag) (*flag.FlagSet, error) { - set := flag.NewFlagSet(name, flag.ContinueOnError) - - for _, f := range flags { - //TODO remove in v2 when errorableFlag is removed - if ef, ok := f.(errorableFlag); ok { - if err := ef.ApplyWithError(set); err != nil { - return nil, err - } - } else { - f.Apply(set) - } - } - return set, nil -} - -func eachName(longName string, fn func(string)) { - parts := strings.Split(longName, ",") - for _, name := range parts { - name = strings.Trim(name, " ") - fn(name) - } -} - -// Generic is a generic parseable type identified by a specific flag -type Generic interface { - Set(value string) error - String() string -} - -// Apply takes the flagset and calls Set on the generic flag with the value -// provided by the user for parsing by the flag -// Ignores parsing errors -func (f GenericFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError takes the flagset and calls Set on the generic flag with the value -// provided by the user for parsing by the flag -func (f GenericFlag) ApplyWithError(set *flag.FlagSet) error { - val := f.Value - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - if err := val.Set(envVal); err != nil { - return fmt.Errorf("could not parse %s as value for flag %s: %s", envVal, f.Name, err) - } - break - } - } - } - - eachName(f.Name, func(name string) { - set.Var(f.Value, name, f.Usage) - }) - - return nil -} - -// StringSlice is an opaque type for []string to satisfy flag.Value and flag.Getter -type StringSlice []string - -// Set appends the string value to the list of values -func (f *StringSlice) Set(value string) error { - *f = append(*f, value) - return nil -} - -// String returns a readable representation of this value (for usage defaults) -func (f *StringSlice) String() string { - return fmt.Sprintf("%s", *f) -} - -// Value returns the slice of strings set by this flag -func (f *StringSlice) Value() []string { - return *f -} - -// Get returns the slice of strings set by this flag -func (f *StringSlice) Get() interface{} { - return *f -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f StringSliceFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f StringSliceFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - newVal := &StringSlice{} - for _, s := range strings.Split(envVal, ",") { - s = strings.TrimSpace(s) - if err := newVal.Set(s); err != nil { - return fmt.Errorf("could not parse %s as string value for flag %s: %s", envVal, f.Name, err) - } - } - f.Value = newVal - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Value == nil { - f.Value = &StringSlice{} - } - set.Var(f.Value, name, f.Usage) - }) - - return nil -} - -// IntSlice is an opaque type for []int to satisfy flag.Value and flag.Getter -type IntSlice []int - -// Set parses the value into an integer and appends it to the list of values -func (f *IntSlice) Set(value string) error { - tmp, err := strconv.Atoi(value) - if err != nil { - return err - } - *f = append(*f, tmp) - return nil -} - -// String returns a readable representation of this value (for usage defaults) -func (f *IntSlice) String() string { - return fmt.Sprintf("%#v", *f) -} - -// Value returns the slice of ints set by this flag -func (f *IntSlice) Value() []int { - return *f -} - -// Get returns the slice of ints set by this flag -func (f *IntSlice) Get() interface{} { - return *f -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f IntSliceFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f IntSliceFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - newVal := &IntSlice{} - for _, s := range strings.Split(envVal, ",") { - s = strings.TrimSpace(s) - if err := newVal.Set(s); err != nil { - return fmt.Errorf("could not parse %s as int slice value for flag %s: %s", envVal, f.Name, err) - } - } - f.Value = newVal - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Value == nil { - f.Value = &IntSlice{} - } - set.Var(f.Value, name, f.Usage) - }) - - return nil -} - -// Int64Slice is an opaque type for []int to satisfy flag.Value and flag.Getter -type Int64Slice []int64 - -// Set parses the value into an integer and appends it to the list of values -func (f *Int64Slice) Set(value string) error { - tmp, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return err - } - *f = append(*f, tmp) - return nil -} - -// String returns a readable representation of this value (for usage defaults) -func (f *Int64Slice) String() string { - return fmt.Sprintf("%#v", *f) -} - -// Value returns the slice of ints set by this flag -func (f *Int64Slice) Value() []int64 { - return *f -} - -// Get returns the slice of ints set by this flag -func (f *Int64Slice) Get() interface{} { - return *f -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f Int64SliceFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f Int64SliceFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - newVal := &Int64Slice{} - for _, s := range strings.Split(envVal, ",") { - s = strings.TrimSpace(s) - if err := newVal.Set(s); err != nil { - return fmt.Errorf("could not parse %s as int64 slice value for flag %s: %s", envVal, f.Name, err) - } - } - f.Value = newVal - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Value == nil { - f.Value = &Int64Slice{} - } - set.Var(f.Value, name, f.Usage) - }) - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f BoolFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f BoolFlag) ApplyWithError(set *flag.FlagSet) error { - val := false - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - if envVal == "" { - val = false - break - } - - envValBool, err := strconv.ParseBool(envVal) - if err != nil { - return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) - } - - val = envValBool - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.BoolVar(f.Destination, name, val, f.Usage) - return - } - set.Bool(name, val, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f BoolTFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f BoolTFlag) ApplyWithError(set *flag.FlagSet) error { - val := true - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - if envVal == "" { - val = false - break - } - - envValBool, err := strconv.ParseBool(envVal) - if err != nil { - return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) - } - - val = envValBool - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.BoolVar(f.Destination, name, val, f.Usage) - return - } - set.Bool(name, val, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f StringFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f StringFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - f.Value = envVal - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.StringVar(f.Destination, name, f.Value, f.Usage) - return - } - set.String(name, f.Value, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f IntFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f IntFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - envValInt, err := strconv.ParseInt(envVal, 0, 64) - if err != nil { - return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) - } - f.Value = int(envValInt) - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.IntVar(f.Destination, name, f.Value, f.Usage) - return - } - set.Int(name, f.Value, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f Int64Flag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f Int64Flag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - envValInt, err := strconv.ParseInt(envVal, 0, 64) - if err != nil { - return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) - } - - f.Value = envValInt - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.Int64Var(f.Destination, name, f.Value, f.Usage) - return - } - set.Int64(name, f.Value, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f UintFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f UintFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - envValInt, err := strconv.ParseUint(envVal, 0, 64) - if err != nil { - return fmt.Errorf("could not parse %s as uint value for flag %s: %s", envVal, f.Name, err) - } - - f.Value = uint(envValInt) - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.UintVar(f.Destination, name, f.Value, f.Usage) - return - } - set.Uint(name, f.Value, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f Uint64Flag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f Uint64Flag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - envValInt, err := strconv.ParseUint(envVal, 0, 64) - if err != nil { - return fmt.Errorf("could not parse %s as uint64 value for flag %s: %s", envVal, f.Name, err) - } - - f.Value = uint64(envValInt) - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.Uint64Var(f.Destination, name, f.Value, f.Usage) - return - } - set.Uint64(name, f.Value, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f DurationFlag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f DurationFlag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - envValDuration, err := time.ParseDuration(envVal) - if err != nil { - return fmt.Errorf("could not parse %s as duration for flag %s: %s", envVal, f.Name, err) - } - - f.Value = envValDuration - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.DurationVar(f.Destination, name, f.Value, f.Usage) - return - } - set.Duration(name, f.Value, f.Usage) - }) - - return nil -} - -// Apply populates the flag given the flag set and environment -// Ignores errors -func (f Float64Flag) Apply(set *flag.FlagSet) { - f.ApplyWithError(set) -} - -// ApplyWithError populates the flag given the flag set and environment -func (f Float64Flag) ApplyWithError(set *flag.FlagSet) error { - if f.EnvVar != "" { - for _, envVar := range strings.Split(f.EnvVar, ",") { - envVar = strings.TrimSpace(envVar) - if envVal, ok := syscall.Getenv(envVar); ok { - envValFloat, err := strconv.ParseFloat(envVal, 10) - if err != nil { - return fmt.Errorf("could not parse %s as float64 value for flag %s: %s", envVal, f.Name, err) - } - - f.Value = float64(envValFloat) - break - } - } - } - - eachName(f.Name, func(name string) { - if f.Destination != nil { - set.Float64Var(f.Destination, name, f.Value, f.Usage) - return - } - set.Float64(name, f.Value, f.Usage) - }) - - return nil -} - -func visibleFlags(fl []Flag) []Flag { - visible := []Flag{} - for _, flag := range fl { - field := flagValue(flag).FieldByName("Hidden") - if !field.IsValid() || !field.Bool() { - visible = append(visible, flag) - } - } - return visible -} - -func prefixFor(name string) (prefix string) { - if len(name) == 1 { - prefix = "-" - } else { - prefix = "--" - } - - return -} - -// Returns the placeholder, if any, and the unquoted usage string. -func unquoteUsage(usage string) (string, string) { - for i := 0; i < len(usage); i++ { - if usage[i] == '`' { - for j := i + 1; j < len(usage); j++ { - if usage[j] == '`' { - name := usage[i+1 : j] - usage = usage[:i] + name + usage[j+1:] - return name, usage - } - } - break - } - } - return "", usage -} - -func prefixedNames(fullName, placeholder string) string { - var prefixed string - parts := strings.Split(fullName, ",") - for i, name := range parts { - name = strings.Trim(name, " ") - prefixed += prefixFor(name) + name - if placeholder != "" { - prefixed += " " + placeholder - } - if i < len(parts)-1 { - prefixed += ", " - } - } - return prefixed -} - -func withEnvHint(envVar, str string) string { - envText := "" - if envVar != "" { - prefix := "$" - suffix := "" - sep := ", $" - if runtime.GOOS == "windows" { - prefix = "%" - suffix = "%" - sep = "%, %" - } - envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix) - } - return str + envText -} - -func flagValue(f Flag) reflect.Value { - fv := reflect.ValueOf(f) - for fv.Kind() == reflect.Ptr { - fv = reflect.Indirect(fv) - } - return fv -} - -func stringifyFlag(f Flag) string { - fv := flagValue(f) - - switch f.(type) { - case IntSliceFlag: - return withEnvHint(fv.FieldByName("EnvVar").String(), - stringifyIntSliceFlag(f.(IntSliceFlag))) - case Int64SliceFlag: - return withEnvHint(fv.FieldByName("EnvVar").String(), - stringifyInt64SliceFlag(f.(Int64SliceFlag))) - case StringSliceFlag: - return withEnvHint(fv.FieldByName("EnvVar").String(), - stringifyStringSliceFlag(f.(StringSliceFlag))) - } - - placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String()) - - needsPlaceholder := false - defaultValueString := "" - - if val := fv.FieldByName("Value"); val.IsValid() { - needsPlaceholder = true - defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface()) - - if val.Kind() == reflect.String && val.String() != "" { - defaultValueString = fmt.Sprintf(" (default: %q)", val.String()) - } - } - - if defaultValueString == " (default: )" { - defaultValueString = "" - } - - if needsPlaceholder && placeholder == "" { - placeholder = defaultPlaceholder - } - - usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString)) - - return withEnvHint(fv.FieldByName("EnvVar").String(), - fmt.Sprintf("%s\t%s", prefixedNames(fv.FieldByName("Name").String(), placeholder), usageWithDefault)) -} - -func stringifyIntSliceFlag(f IntSliceFlag) string { - defaultVals := []string{} - if f.Value != nil && len(f.Value.Value()) > 0 { - for _, i := range f.Value.Value() { - defaultVals = append(defaultVals, fmt.Sprintf("%d", i)) - } - } - - return stringifySliceFlag(f.Usage, f.Name, defaultVals) -} - -func stringifyInt64SliceFlag(f Int64SliceFlag) string { - defaultVals := []string{} - if f.Value != nil && len(f.Value.Value()) > 0 { - for _, i := range f.Value.Value() { - defaultVals = append(defaultVals, fmt.Sprintf("%d", i)) - } - } - - return stringifySliceFlag(f.Usage, f.Name, defaultVals) -} - -func stringifyStringSliceFlag(f StringSliceFlag) string { - defaultVals := []string{} - if f.Value != nil && len(f.Value.Value()) > 0 { - for _, s := range f.Value.Value() { - if len(s) > 0 { - defaultVals = append(defaultVals, fmt.Sprintf("%q", s)) - } - } - } - - return stringifySliceFlag(f.Usage, f.Name, defaultVals) -} - -func stringifySliceFlag(usage, name string, defaultVals []string) string { - placeholder, usage := unquoteUsage(usage) - if placeholder == "" { - placeholder = defaultPlaceholder - } - - defaultVal := "" - if len(defaultVals) > 0 { - defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", ")) - } - - usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal)) - return fmt.Sprintf("%s\t%s", prefixedNames(name, placeholder), usageWithDefault) -} diff --git a/vendor/github.com/urfave/cli/flag_generated.go b/vendor/github.com/urfave/cli/flag_generated.go deleted file mode 100644 index 491b61956..000000000 --- a/vendor/github.com/urfave/cli/flag_generated.go +++ /dev/null @@ -1,627 +0,0 @@ -package cli - -import ( - "flag" - "strconv" - "time" -) - -// WARNING: This file is generated! - -// BoolFlag is a flag with type bool -type BoolFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Destination *bool -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f BoolFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f BoolFlag) GetName() string { - return f.Name -} - -// Bool looks up the value of a local BoolFlag, returns -// false if not found -func (c *Context) Bool(name string) bool { - return lookupBool(name, c.flagSet) -} - -// GlobalBool looks up the value of a global BoolFlag, returns -// false if not found -func (c *Context) GlobalBool(name string) bool { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupBool(name, fs) - } - return false -} - -func lookupBool(name string, set *flag.FlagSet) bool { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseBool(f.Value.String()) - if err != nil { - return false - } - return parsed - } - return false -} - -// BoolTFlag is a flag with type bool that is true by default -type BoolTFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Destination *bool -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f BoolTFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f BoolTFlag) GetName() string { - return f.Name -} - -// BoolT looks up the value of a local BoolTFlag, returns -// false if not found -func (c *Context) BoolT(name string) bool { - return lookupBoolT(name, c.flagSet) -} - -// GlobalBoolT looks up the value of a global BoolTFlag, returns -// false if not found -func (c *Context) GlobalBoolT(name string) bool { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupBoolT(name, fs) - } - return false -} - -func lookupBoolT(name string, set *flag.FlagSet) bool { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseBool(f.Value.String()) - if err != nil { - return false - } - return parsed - } - return false -} - -// DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration) -type DurationFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value time.Duration - Destination *time.Duration -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f DurationFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f DurationFlag) GetName() string { - return f.Name -} - -// Duration looks up the value of a local DurationFlag, returns -// 0 if not found -func (c *Context) Duration(name string) time.Duration { - return lookupDuration(name, c.flagSet) -} - -// GlobalDuration looks up the value of a global DurationFlag, returns -// 0 if not found -func (c *Context) GlobalDuration(name string) time.Duration { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupDuration(name, fs) - } - return 0 -} - -func lookupDuration(name string, set *flag.FlagSet) time.Duration { - f := set.Lookup(name) - if f != nil { - parsed, err := time.ParseDuration(f.Value.String()) - if err != nil { - return 0 - } - return parsed - } - return 0 -} - -// Float64Flag is a flag with type float64 -type Float64Flag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value float64 - Destination *float64 -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f Float64Flag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f Float64Flag) GetName() string { - return f.Name -} - -// Float64 looks up the value of a local Float64Flag, returns -// 0 if not found -func (c *Context) Float64(name string) float64 { - return lookupFloat64(name, c.flagSet) -} - -// GlobalFloat64 looks up the value of a global Float64Flag, returns -// 0 if not found -func (c *Context) GlobalFloat64(name string) float64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupFloat64(name, fs) - } - return 0 -} - -func lookupFloat64(name string, set *flag.FlagSet) float64 { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseFloat(f.Value.String(), 64) - if err != nil { - return 0 - } - return parsed - } - return 0 -} - -// GenericFlag is a flag with type Generic -type GenericFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value Generic -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f GenericFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f GenericFlag) GetName() string { - return f.Name -} - -// Generic looks up the value of a local GenericFlag, returns -// nil if not found -func (c *Context) Generic(name string) interface{} { - return lookupGeneric(name, c.flagSet) -} - -// GlobalGeneric looks up the value of a global GenericFlag, returns -// nil if not found -func (c *Context) GlobalGeneric(name string) interface{} { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupGeneric(name, fs) - } - return nil -} - -func lookupGeneric(name string, set *flag.FlagSet) interface{} { - f := set.Lookup(name) - if f != nil { - parsed, err := f.Value, error(nil) - if err != nil { - return nil - } - return parsed - } - return nil -} - -// Int64Flag is a flag with type int64 -type Int64Flag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value int64 - Destination *int64 -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f Int64Flag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f Int64Flag) GetName() string { - return f.Name -} - -// Int64 looks up the value of a local Int64Flag, returns -// 0 if not found -func (c *Context) Int64(name string) int64 { - return lookupInt64(name, c.flagSet) -} - -// GlobalInt64 looks up the value of a global Int64Flag, returns -// 0 if not found -func (c *Context) GlobalInt64(name string) int64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt64(name, fs) - } - return 0 -} - -func lookupInt64(name string, set *flag.FlagSet) int64 { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return parsed - } - return 0 -} - -// IntFlag is a flag with type int -type IntFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value int - Destination *int -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f IntFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f IntFlag) GetName() string { - return f.Name -} - -// Int looks up the value of a local IntFlag, returns -// 0 if not found -func (c *Context) Int(name string) int { - return lookupInt(name, c.flagSet) -} - -// GlobalInt looks up the value of a global IntFlag, returns -// 0 if not found -func (c *Context) GlobalInt(name string) int { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt(name, fs) - } - return 0 -} - -func lookupInt(name string, set *flag.FlagSet) int { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return int(parsed) - } - return 0 -} - -// IntSliceFlag is a flag with type *IntSlice -type IntSliceFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value *IntSlice -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f IntSliceFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f IntSliceFlag) GetName() string { - return f.Name -} - -// IntSlice looks up the value of a local IntSliceFlag, returns -// nil if not found -func (c *Context) IntSlice(name string) []int { - return lookupIntSlice(name, c.flagSet) -} - -// GlobalIntSlice looks up the value of a global IntSliceFlag, returns -// nil if not found -func (c *Context) GlobalIntSlice(name string) []int { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupIntSlice(name, fs) - } - return nil -} - -func lookupIntSlice(name string, set *flag.FlagSet) []int { - f := set.Lookup(name) - if f != nil { - parsed, err := (f.Value.(*IntSlice)).Value(), error(nil) - if err != nil { - return nil - } - return parsed - } - return nil -} - -// Int64SliceFlag is a flag with type *Int64Slice -type Int64SliceFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value *Int64Slice -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f Int64SliceFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f Int64SliceFlag) GetName() string { - return f.Name -} - -// Int64Slice looks up the value of a local Int64SliceFlag, returns -// nil if not found -func (c *Context) Int64Slice(name string) []int64 { - return lookupInt64Slice(name, c.flagSet) -} - -// GlobalInt64Slice looks up the value of a global Int64SliceFlag, returns -// nil if not found -func (c *Context) GlobalInt64Slice(name string) []int64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt64Slice(name, fs) - } - return nil -} - -func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { - f := set.Lookup(name) - if f != nil { - parsed, err := (f.Value.(*Int64Slice)).Value(), error(nil) - if err != nil { - return nil - } - return parsed - } - return nil -} - -// StringFlag is a flag with type string -type StringFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value string - Destination *string -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f StringFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f StringFlag) GetName() string { - return f.Name -} - -// String looks up the value of a local StringFlag, returns -// "" if not found -func (c *Context) String(name string) string { - return lookupString(name, c.flagSet) -} - -// GlobalString looks up the value of a global StringFlag, returns -// "" if not found -func (c *Context) GlobalString(name string) string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupString(name, fs) - } - return "" -} - -func lookupString(name string, set *flag.FlagSet) string { - f := set.Lookup(name) - if f != nil { - parsed, err := f.Value.String(), error(nil) - if err != nil { - return "" - } - return parsed - } - return "" -} - -// StringSliceFlag is a flag with type *StringSlice -type StringSliceFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value *StringSlice -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f StringSliceFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f StringSliceFlag) GetName() string { - return f.Name -} - -// StringSlice looks up the value of a local StringSliceFlag, returns -// nil if not found -func (c *Context) StringSlice(name string) []string { - return lookupStringSlice(name, c.flagSet) -} - -// GlobalStringSlice looks up the value of a global StringSliceFlag, returns -// nil if not found -func (c *Context) GlobalStringSlice(name string) []string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupStringSlice(name, fs) - } - return nil -} - -func lookupStringSlice(name string, set *flag.FlagSet) []string { - f := set.Lookup(name) - if f != nil { - parsed, err := (f.Value.(*StringSlice)).Value(), error(nil) - if err != nil { - return nil - } - return parsed - } - return nil -} - -// Uint64Flag is a flag with type uint64 -type Uint64Flag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value uint64 - Destination *uint64 -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f Uint64Flag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f Uint64Flag) GetName() string { - return f.Name -} - -// Uint64 looks up the value of a local Uint64Flag, returns -// 0 if not found -func (c *Context) Uint64(name string) uint64 { - return lookupUint64(name, c.flagSet) -} - -// GlobalUint64 looks up the value of a global Uint64Flag, returns -// 0 if not found -func (c *Context) GlobalUint64(name string) uint64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupUint64(name, fs) - } - return 0 -} - -func lookupUint64(name string, set *flag.FlagSet) uint64 { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return parsed - } - return 0 -} - -// UintFlag is a flag with type uint -type UintFlag struct { - Name string - Usage string - EnvVar string - Hidden bool - Value uint - Destination *uint -} - -// String returns a readable representation of this value -// (for usage defaults) -func (f UintFlag) String() string { - return FlagStringer(f) -} - -// GetName returns the name of the flag -func (f UintFlag) GetName() string { - return f.Name -} - -// Uint looks up the value of a local UintFlag, returns -// 0 if not found -func (c *Context) Uint(name string) uint { - return lookupUint(name, c.flagSet) -} - -// GlobalUint looks up the value of a global UintFlag, returns -// 0 if not found -func (c *Context) GlobalUint(name string) uint { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupUint(name, fs) - } - return 0 -} - -func lookupUint(name string, set *flag.FlagSet) uint { - f := set.Lookup(name) - if f != nil { - parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return uint(parsed) - } - return 0 -} diff --git a/vendor/github.com/urfave/cli/generate-flag-types b/vendor/github.com/urfave/cli/generate-flag-types deleted file mode 100644 index 7147381ce..000000000 --- a/vendor/github.com/urfave/cli/generate-flag-types +++ /dev/null @@ -1,255 +0,0 @@ -#!/usr/bin/env python -""" -The flag types that ship with the cli library have many things in common, and -so we can take advantage of the `go generate` command to create much of the -source code from a list of definitions. These definitions attempt to cover -the parts that vary between flag types, and should evolve as needed. - -An example of the minimum definition needed is: - - { - "name": "SomeType", - "type": "sometype", - "context_default": "nil" - } - -In this example, the code generated for the `cli` package will include a type -named `SomeTypeFlag` that is expected to wrap a value of type `sometype`. -Fetching values by name via `*cli.Context` will default to a value of `nil`. - -A more complete, albeit somewhat redundant, example showing all available -definition keys is: - - { - "name": "VeryMuchType", - "type": "*VeryMuchType", - "value": true, - "dest": false, - "doctail": " which really only wraps a []float64, oh well!", - "context_type": "[]float64", - "context_default": "nil", - "parser": "parseVeryMuchType(f.Value.String())", - "parser_cast": "[]float64(parsed)" - } - -The meaning of each field is as follows: - - name (string) - The type "name", which will be suffixed with - `Flag` when generating the type definition - for `cli` and the wrapper type for `altsrc` - type (string) - The type that the generated `Flag` type for `cli` - is expected to "contain" as its `.Value` member - value (bool) - Should the generated `cli` type have a `Value` - member? - dest (bool) - Should the generated `cli` type support a - destination pointer? - doctail (string) - Additional docs for the `cli` flag type comment - context_type (string) - The literal type used in the `*cli.Context` - reader func signature - context_default (string) - The literal value used as the default by the - `*cli.Context` reader funcs when no value is - present - parser (string) - Literal code used to parse the flag `f`, - expected to have a return signature of - (value, error) - parser_cast (string) - Literal code used to cast the `parsed` value - returned from the `parser` code -""" - -from __future__ import print_function, unicode_literals - -import argparse -import json -import os -import subprocess -import sys -import tempfile -import textwrap - - -class _FancyFormatter(argparse.ArgumentDefaultsHelpFormatter, - argparse.RawDescriptionHelpFormatter): - pass - - -def main(sysargs=sys.argv[:]): - parser = argparse.ArgumentParser( - description='Generate flag type code!', - formatter_class=_FancyFormatter) - parser.add_argument( - 'package', - type=str, default='cli', choices=_WRITEFUNCS.keys(), - help='Package for which flag types will be generated' - ) - parser.add_argument( - '-i', '--in-json', - type=argparse.FileType('r'), - default=sys.stdin, - help='Input JSON file which defines each type to be generated' - ) - parser.add_argument( - '-o', '--out-go', - type=argparse.FileType('w'), - default=sys.stdout, - help='Output file/stream to which generated source will be written' - ) - parser.epilog = __doc__ - - args = parser.parse_args(sysargs[1:]) - _generate_flag_types(_WRITEFUNCS[args.package], args.out_go, args.in_json) - return 0 - - -def _generate_flag_types(writefunc, output_go, input_json): - types = json.load(input_json) - - tmp = tempfile.NamedTemporaryFile(suffix='.go', delete=False) - writefunc(tmp, types) - tmp.close() - - new_content = subprocess.check_output( - ['goimports', tmp.name] - ).decode('utf-8') - - print(new_content, file=output_go, end='') - output_go.flush() - os.remove(tmp.name) - - -def _set_typedef_defaults(typedef): - typedef.setdefault('doctail', '') - typedef.setdefault('context_type', typedef['type']) - typedef.setdefault('dest', True) - typedef.setdefault('value', True) - typedef.setdefault('parser', 'f.Value, error(nil)') - typedef.setdefault('parser_cast', 'parsed') - - -def _write_cli_flag_types(outfile, types): - _fwrite(outfile, """\ - package cli - - // WARNING: This file is generated! - - """) - - for typedef in types: - _set_typedef_defaults(typedef) - - _fwrite(outfile, """\ - // {name}Flag is a flag with type {type}{doctail} - type {name}Flag struct {{ - Name string - Usage string - EnvVar string - Hidden bool - """.format(**typedef)) - - if typedef['value']: - _fwrite(outfile, """\ - Value {type} - """.format(**typedef)) - - if typedef['dest']: - _fwrite(outfile, """\ - Destination *{type} - """.format(**typedef)) - - _fwrite(outfile, "\n}\n\n") - - _fwrite(outfile, """\ - // String returns a readable representation of this value - // (for usage defaults) - func (f {name}Flag) String() string {{ - return FlagStringer(f) - }} - - // GetName returns the name of the flag - func (f {name}Flag) GetName() string {{ - return f.Name - }} - - // {name} looks up the value of a local {name}Flag, returns - // {context_default} if not found - func (c *Context) {name}(name string) {context_type} {{ - return lookup{name}(name, c.flagSet) - }} - - // Global{name} looks up the value of a global {name}Flag, returns - // {context_default} if not found - func (c *Context) Global{name}(name string) {context_type} {{ - if fs := lookupGlobalFlagSet(name, c); fs != nil {{ - return lookup{name}(name, fs) - }} - return {context_default} - }} - - func lookup{name}(name string, set *flag.FlagSet) {context_type} {{ - f := set.Lookup(name) - if f != nil {{ - parsed, err := {parser} - if err != nil {{ - return {context_default} - }} - return {parser_cast} - }} - return {context_default} - }} - """.format(**typedef)) - - -def _write_altsrc_flag_types(outfile, types): - _fwrite(outfile, """\ - package altsrc - - import ( - "gopkg.in/urfave/cli.v1" - ) - - // WARNING: This file is generated! - - """) - - for typedef in types: - _set_typedef_defaults(typedef) - - _fwrite(outfile, """\ - // {name}Flag is the flag type that wraps cli.{name}Flag to allow - // for other values to be specified - type {name}Flag struct {{ - cli.{name}Flag - set *flag.FlagSet - }} - - // New{name}Flag creates a new {name}Flag - func New{name}Flag(fl cli.{name}Flag) *{name}Flag {{ - return &{name}Flag{{{name}Flag: fl, set: nil}} - }} - - // Apply saves the flagSet for later usage calls, then calls the - // wrapped {name}Flag.Apply - func (f *{name}Flag) Apply(set *flag.FlagSet) {{ - f.set = set - f.{name}Flag.Apply(set) - }} - - // ApplyWithError saves the flagSet for later usage calls, then calls the - // wrapped {name}Flag.ApplyWithError - func (f *{name}Flag) ApplyWithError(set *flag.FlagSet) error {{ - f.set = set - return f.{name}Flag.ApplyWithError(set) - }} - """.format(**typedef)) - - -def _fwrite(outfile, text): - print(textwrap.dedent(text), end='', file=outfile) - - -_WRITEFUNCS = { - 'cli': _write_cli_flag_types, - 'altsrc': _write_altsrc_flag_types -} - -if __name__ == '__main__': - sys.exit(main()) diff --git a/vendor/github.com/urfave/cli/runtests b/vendor/github.com/urfave/cli/runtests deleted file mode 100644 index ee22bdeed..000000000 --- a/vendor/github.com/urfave/cli/runtests +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function - -import argparse -import os -import sys -import tempfile - -from subprocess import check_call, check_output - - -PACKAGE_NAME = os.environ.get( - 'CLI_PACKAGE_NAME', 'github.com/urfave/cli' -) - - -def main(sysargs=sys.argv[:]): - targets = { - 'vet': _vet, - 'test': _test, - 'gfmrun': _gfmrun, - 'toc': _toc, - 'gen': _gen, - } - - parser = argparse.ArgumentParser() - parser.add_argument( - 'target', nargs='?', choices=tuple(targets.keys()), default='test' - ) - args = parser.parse_args(sysargs[1:]) - - targets[args.target]() - return 0 - - -def _test(): - if check_output('go version'.split()).split()[2] < 'go1.2': - _run('go test -v .') - return - - coverprofiles = [] - for subpackage in ['', 'altsrc']: - coverprofile = 'cli.coverprofile' - if subpackage != '': - coverprofile = '{}.coverprofile'.format(subpackage) - - coverprofiles.append(coverprofile) - - _run('go test -v'.split() + [ - '-coverprofile={}'.format(coverprofile), - ('{}/{}'.format(PACKAGE_NAME, subpackage)).rstrip('/') - ]) - - combined_name = _combine_coverprofiles(coverprofiles) - _run('go tool cover -func={}'.format(combined_name)) - os.remove(combined_name) - - -def _gfmrun(): - go_version = check_output('go version'.split()).split()[2] - if go_version < 'go1.3': - print('runtests: skip on {}'.format(go_version), file=sys.stderr) - return - _run(['gfmrun', '-c', str(_gfmrun_count()), '-s', 'README.md']) - - -def _vet(): - _run('go vet ./...') - - -def _toc(): - _run('node_modules/.bin/markdown-toc -i README.md') - _run('git diff --exit-code') - - -def _gen(): - go_version = check_output('go version'.split()).split()[2] - if go_version < 'go1.5': - print('runtests: skip on {}'.format(go_version), file=sys.stderr) - return - - _run('go generate ./...') - _run('git diff --exit-code') - - -def _run(command): - if hasattr(command, 'split'): - command = command.split() - print('runtests: {}'.format(' '.join(command)), file=sys.stderr) - check_call(command) - - -def _gfmrun_count(): - with open('README.md') as infile: - lines = infile.read().splitlines() - return len(filter(_is_go_runnable, lines)) - - -def _is_go_runnable(line): - return line.startswith('package main') - - -def _combine_coverprofiles(coverprofiles): - combined = tempfile.NamedTemporaryFile( - suffix='.coverprofile', delete=False - ) - combined.write('mode: set\n') - - for coverprofile in coverprofiles: - with open(coverprofile, 'r') as infile: - for line in infile.readlines(): - if not line.startswith('mode: '): - combined.write(line) - - combined.flush() - name = combined.name - combined.close() - return name - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/vendor/github.com/urfave/cli/.flake8 b/vendor/github.com/urfave/cli/v2/.flake8 similarity index 100% rename from vendor/github.com/urfave/cli/.flake8 rename to vendor/github.com/urfave/cli/v2/.flake8 diff --git a/vendor/github.com/urfave/cli/.gitignore b/vendor/github.com/urfave/cli/v2/.gitignore similarity index 59% rename from vendor/github.com/urfave/cli/.gitignore rename to vendor/github.com/urfave/cli/v2/.gitignore index faf70c4c2..b013e4ac6 100644 --- a/vendor/github.com/urfave/cli/.gitignore +++ b/vendor/github.com/urfave/cli/v2/.gitignore @@ -1,2 +1,5 @@ *.coverprofile +*.orig node_modules/ +vendor +.idea diff --git a/vendor/github.com/urfave/cli/v2/CODE_OF_CONDUCT.md b/vendor/github.com/urfave/cli/v2/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..41ba294f6 --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting Dan Buch at dan@meatballhat.com. All complaints will be +reviewed and investigated and will result in a response that is deemed necessary +and appropriate to the circumstances. The project team is obligated to maintain +confidentiality with regard to the reporter of an incident. Further details of +specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + diff --git a/vendor/github.com/urfave/cli/LICENSE b/vendor/github.com/urfave/cli/v2/LICENSE similarity index 100% rename from vendor/github.com/urfave/cli/LICENSE rename to vendor/github.com/urfave/cli/v2/LICENSE diff --git a/vendor/github.com/urfave/cli/v2/README.md b/vendor/github.com/urfave/cli/v2/README.md new file mode 100644 index 000000000..e7fb3d755 --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/README.md @@ -0,0 +1,68 @@ +cli +=== + +[![Windows Build Status](https://ci.appveyor.com/api/projects/status/rtgk5xufi932pb2v?svg=true)](https://ci.appveyor.com/project/urfave/cli) + +[![GoDoc](https://godoc.org/github.com/urfave/cli?status.svg)](https://godoc.org/github.com/urfave/cli) +[![codebeat](https://codebeat.co/badges/0a8f30aa-f975-404b-b878-5fab3ae1cc5f)](https://codebeat.co/projects/github-com-urfave-cli) +[![Go Report Card](https://goreportcard.com/badge/urfave/cli)](https://goreportcard.com/report/urfave/cli) +[![codecov](https://codecov.io/gh/urfave/cli/branch/master/graph/badge.svg)](https://codecov.io/gh/urfave/cli) + +cli is a simple, fast, and fun package for building command line apps in Go. The +goal is to enable developers to write fast and distributable command line +applications in an expressive way. + +## Usage Documentation + +Usage documentation exists for each major version. Don't know what version you're on? You're probably using the version from the `master` branch, which is currently `v2`. + +- `v2` - [./docs/v2/manual.md](./docs/v2/manual.md) +- `v1` - [./docs/v1/manual.md](./docs/v1/manual.md) + +## Installation + +Make sure you have a working Go environment. Go version 1.11+ is supported. [See the install instructions for Go](http://golang.org/doc/install.html). + +Go Modules are strongly recommended when using this package. [See the go blog guide on using Go Modules](https://blog.golang.org/using-go-modules). + +### Using `v2` releases + +``` +$ GO111MODULE=on go get github.com/urfave/cli/v2 +``` + +```go +... +import ( + "github.com/urfave/cli/v2" // imports as package "cli" +) +... +``` + +### Using `v1` releases + +``` +$ GO111MODULE=on go get github.com/urfave/cli +``` + +```go +... +import ( + "github.com/urfave/cli" +) +... +``` + +### GOPATH + +Make sure your `PATH` includes the `$GOPATH/bin` directory so your commands can +be easily used: +``` +export PATH=$PATH:$GOPATH/bin +``` + +### Supported platforms + +cli is tested against multiple versions of Go on Linux, and against the latest +released version of Go on OS X and Windows. This project uses Github Actions for +builds. For more build info, please look at the [./.github/workflows/cli.yml](https://github.com/urfave/cli/blob/master/.github/workflows/cli.yml). diff --git a/vendor/github.com/urfave/cli/app.go b/vendor/github.com/urfave/cli/v2/app.go similarity index 65% rename from vendor/github.com/urfave/cli/app.go rename to vendor/github.com/urfave/cli/v2/app.go index 51fc45d87..c04e9afda 100644 --- a/vendor/github.com/urfave/cli/app.go +++ b/vendor/github.com/urfave/cli/v2/app.go @@ -1,23 +1,22 @@ package cli import ( + "context" + "flag" "fmt" "io" - "io/ioutil" "os" "path/filepath" + "reflect" "sort" "time" ) var ( - changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md" - appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL) - runAndExitOnErrorDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-runandexitonerror", changeLogURL) - - contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you." - - errInvalidActionType = NewExitError("ERROR invalid Action type. "+ + changeLogURL = "https://github.com/urfave/cli/blob/master/docs/CHANGELOG.md" + appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL) + contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you." + errInvalidActionType = NewExitError("ERROR invalid Action type. "+ fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+ fmt.Sprintf("See %s", appActionDeprecationURL), 2) ) @@ -40,7 +39,7 @@ type App struct { // Description of the program Description string // List of commands to execute - Commands []Command + Commands []*Command // List of flags to parse Flags []Flag // Boolean to enable bash completion commands @@ -49,9 +48,9 @@ type App struct { HideHelp bool // Boolean to hide built-in version flag and the VERSION section of help HideVersion bool - // Populate on app startup, only gettable through method Categories() + // categories contains the categorized commands and is populated on app startup categories CommandCategories - // An action to execute when the bash-completion flag is set + // An action to execute when the shell completion flag is set BashComplete BashCompleteFunc // An action to execute before any subcommands are run, but after the context is ready // If a non-nil error is returned, no subcommands are run @@ -59,12 +58,8 @@ type App struct { // An action to execute after any subcommands are run, but after the subcommand has finished // It is run even if Action() panics After AfterFunc - // The action to execute when no subcommands are specified - // Expects a `cli.ActionFunc` but will accept the *deprecated* signature of `func(*cli.Context) {}` - // *Note*: support for the deprecated `Action` signature will be removed in a future version - Action interface{} - + Action ActionFunc // Execute this function if the proper command cannot be found CommandNotFound CommandNotFoundFunc // Execute this function if an usage error occurs @@ -72,17 +67,16 @@ type App struct { // Compilation date Compiled time.Time // List of all authors who contributed - Authors []Author + Authors []*Author // Copyright of the binary if any Copyright string - // Name of Author (Note: Use App.Authors, this is deprecated) - Author string - // Email of Author (Note: Use App.Authors, this is deprecated) - Email string // Writer writer to write output to Writer io.Writer // ErrWriter writes error output ErrWriter io.Writer + // Execute this function to handle ExitErrors. If not provided, HandleExitCoder is provided to + // function as a default, so this is optional. + ExitErrHandler ExitErrHandlerFunc // Other custom info Metadata map[string]interface{} // Carries a function which returns app specific info. @@ -91,6 +85,10 @@ type App struct { // cli.go uses text/template to render templates. You can // render custom help text by setting this variable. CustomAppHelpTemplate string + // Boolean to enable short-option handling so user can combine several + // single-character bool arguments into one + // i.e. foobar -o -v -> foobar -ov + UseShortOptionHandling bool didSetup bool } @@ -113,7 +111,6 @@ func NewApp() *App { HelpName: filepath.Base(os.Args[0]), Usage: "A new cli application", UsageText: "", - Version: "0.0.0", BashComplete: DefaultAppComplete, Action: helpCommand.Action, Compiled: compileTime(), @@ -131,22 +128,52 @@ func (a *App) Setup() { a.didSetup = true - if a.Author != "" || a.Email != "" { - a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email}) + if a.Name == "" { + a.Name = filepath.Base(os.Args[0]) } - newCmds := []Command{} + if a.HelpName == "" { + a.HelpName = filepath.Base(os.Args[0]) + } + + if a.Usage == "" { + a.Usage = "A new cli application" + } + + if a.Version == "" { + a.HideVersion = true + } + + if a.BashComplete == nil { + a.BashComplete = DefaultAppComplete + } + + if a.Action == nil { + a.Action = helpCommand.Action + } + + if a.Compiled == (time.Time{}) { + a.Compiled = compileTime() + } + + if a.Writer == nil { + a.Writer = os.Stdout + } + + var newCommands []*Command + for _, c := range a.Commands { if c.HelpName == "" { c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) } - newCmds = append(newCmds, c) + newCommands = append(newCommands, c) } - a.Commands = newCmds + a.Commands = newCommands if a.Command(helpCommand.Name) == nil && !a.HideHelp { - a.Commands = append(a.Commands, helpCommand) - if (HelpFlag != BoolFlag{}) { + a.appendCommand(helpCommand) + + if HelpFlag != nil { a.appendFlag(HelpFlag) } } @@ -155,11 +182,11 @@ func (a *App) Setup() { a.appendFlag(VersionFlag) } - a.categories = CommandCategories{} + a.categories = newCommandCategories() for _, command := range a.Commands { - a.categories = a.categories.AddCommand(command.Category, command) + a.categories.AddCommand(command.Category, command) } - sort.Sort(a.categories) + sort.Sort(a.categories.(*commandCategories)) if a.Metadata == nil { a.Metadata = make(map[string]interface{}) @@ -170,9 +197,24 @@ func (a *App) Setup() { } } +func (a *App) newFlagSet() (*flag.FlagSet, error) { + return flagSet(a.Name, a.Flags) +} + +func (a *App) useShortOptionHandling() bool { + return a.UseShortOptionHandling +} + // Run is the entry point to the cli app. Parses the arguments slice and routes // to the proper flag/args combination func (a *App) Run(arguments []string) (err error) { + return a.RunContext(context.Background(), arguments) +} + +// RunContext is like Run except it takes a Context that will be +// passed to its commands and sub-commands. Through this, you can +// propagate timeouts and cancellation requests +func (a *App) RunContext(ctx context.Context, arguments []string) (err error) { a.Setup() // handle the completion flag separately from the flagset since @@ -183,19 +225,17 @@ func (a *App) Run(arguments []string) (err error) { // always appends the completion flag at the end of the command shellComplete, arguments := checkShellCompleteFlag(a, arguments) - // parse flags - set, err := flagSet(a.Name, a.Flags) + set, err := a.newFlagSet() if err != nil { return err } - set.SetOutput(ioutil.Discard) - err = set.Parse(arguments[1:]) + err = parseIter(set, a, arguments[1:], shellComplete) nerr := normalizeFlags(a.Flags, set) - context := NewContext(a, set, nil) + context := NewContext(a, set, &Context{Context: ctx}) if nerr != nil { - fmt.Fprintln(a.Writer, nerr) - ShowAppHelp(context) + _, _ = fmt.Fprintln(a.Writer, nerr) + _ = ShowAppHelp(context) return nerr } context.shellComplete = shellComplete @@ -207,16 +247,16 @@ func (a *App) Run(arguments []string) (err error) { if err != nil { if a.OnUsageError != nil { err := a.OnUsageError(context, err, false) - HandleExitCoder(err) + a.handleExitCoder(context, err) return err } - fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) - ShowAppHelp(context) + _, _ = fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) + _ = ShowAppHelp(context) return err } if !a.HideHelp && checkHelp(context) { - ShowAppHelp(context) + _ = ShowAppHelp(context) return nil } @@ -225,11 +265,17 @@ func (a *App) Run(arguments []string) (err error) { return nil } + cerr := checkRequiredFlags(a.Flags, context) + if cerr != nil { + _ = ShowAppHelp(context) + return cerr + } + if a.After != nil { defer func() { if afterErr := a.After(context); afterErr != nil { if err != nil { - err = NewMultiError(err, afterErr) + err = newMultiError(err, afterErr) } else { err = afterErr } @@ -240,8 +286,9 @@ func (a *App) Run(arguments []string) (err error) { if a.Before != nil { beforeErr := a.Before(context) if beforeErr != nil { - ShowAppHelp(context) - HandleExitCoder(beforeErr) + _, _ = fmt.Fprintf(a.Writer, "%v\n\n", beforeErr) + _ = ShowAppHelp(context) + a.handleExitCoder(context, beforeErr) err = beforeErr return err } @@ -261,9 +308,9 @@ func (a *App) Run(arguments []string) (err error) { } // Run default Action - err = HandleAction(a.Action, context) + err = a.Action(context) - HandleExitCoder(err) + a.handleExitCoder(context, err) return err } @@ -274,7 +321,7 @@ func (a *App) Run(arguments []string) (err error) { // code in the cli.ExitCoder func (a *App) RunAndExitOnError() { if err := a.Run(os.Args); err != nil { - fmt.Fprintln(a.errWriter(), err) + _, _ = fmt.Fprintln(a.errWriter(), err) OsExiter(1) } } @@ -282,17 +329,20 @@ func (a *App) RunAndExitOnError() { // RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to // generate command-specific flags func (a *App) RunAsSubcommand(ctx *Context) (err error) { + a.Setup() + // append help to commands if len(a.Commands) > 0 { if a.Command(helpCommand.Name) == nil && !a.HideHelp { - a.Commands = append(a.Commands, helpCommand) - if (HelpFlag != BoolFlag{}) { + a.appendCommand(helpCommand) + + if HelpFlag != nil { a.appendFlag(HelpFlag) } } } - newCmds := []Command{} + var newCmds []*Command for _, c := range a.Commands { if c.HelpName == "" { c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name) @@ -301,24 +351,22 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { } a.Commands = newCmds - // parse flags - set, err := flagSet(a.Name, a.Flags) + set, err := a.newFlagSet() if err != nil { return err } - set.SetOutput(ioutil.Discard) - err = set.Parse(ctx.Args().Tail()) + err = parseIter(set, a, ctx.Args().Tail(), ctx.shellComplete) nerr := normalizeFlags(a.Flags, set) context := NewContext(a, set, ctx) if nerr != nil { - fmt.Fprintln(a.Writer, nerr) - fmt.Fprintln(a.Writer) + _, _ = fmt.Fprintln(a.Writer, nerr) + _, _ = fmt.Fprintln(a.Writer) if len(a.Commands) > 0 { - ShowSubcommandHelp(context) + _ = ShowSubcommandHelp(context) } else { - ShowCommandHelp(ctx, context.Args().First()) + _ = ShowCommandHelp(ctx, context.Args().First()) } return nerr } @@ -330,11 +378,11 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { if err != nil { if a.OnUsageError != nil { err = a.OnUsageError(context, err, true) - HandleExitCoder(err) + a.handleExitCoder(context, err) return err } - fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) - ShowSubcommandHelp(context) + _, _ = fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error()) + _ = ShowSubcommandHelp(context) return err } @@ -348,13 +396,19 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { } } + cerr := checkRequiredFlags(a.Flags, context) + if cerr != nil { + _ = ShowSubcommandHelp(context) + return cerr + } + if a.After != nil { defer func() { afterErr := a.After(context) if afterErr != nil { - HandleExitCoder(err) + a.handleExitCoder(context, err) if err != nil { - err = NewMultiError(err, afterErr) + err = newMultiError(err, afterErr) } else { err = afterErr } @@ -365,7 +419,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { if a.Before != nil { beforeErr := a.Before(context) if beforeErr != nil { - HandleExitCoder(beforeErr) + a.handleExitCoder(context, beforeErr) err = beforeErr return err } @@ -381,9 +435,9 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { } // Run default Action - err = HandleAction(a.Action, context) + err = a.Action(context) - HandleExitCoder(err) + a.handleExitCoder(context, err) return err } @@ -391,28 +445,21 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { func (a *App) Command(name string) *Command { for _, c := range a.Commands { if c.HasName(name) { - return &c + return c } } return nil } -// Categories returns a slice containing all the categories with the commands they contain -func (a *App) Categories() CommandCategories { - return a.categories -} - // VisibleCategories returns a slice of categories and commands that are // Hidden=false -func (a *App) VisibleCategories() []*CommandCategory { - ret := []*CommandCategory{} - for _, category := range a.categories { - if visible := func() *CommandCategory { - for _, command := range category.Commands { - if !command.Hidden { - return category - } +func (a *App) VisibleCategories() []CommandCategory { + ret := []CommandCategory{} + for _, category := range a.categories.Categories() { + if visible := func() CommandCategory { + if len(category.VisibleCommands()) > 0 { + return category } return nil }(); visible != nil { @@ -423,8 +470,8 @@ func (a *App) VisibleCategories() []*CommandCategory { } // VisibleCommands returns a slice of the Commands with Hidden=false -func (a *App) VisibleCommands() []Command { - ret := []Command{} +func (a *App) VisibleCommands() []*Command { + var ret []*Command for _, command := range a.Commands { if !command.Hidden { ret = append(ret, command) @@ -440,7 +487,7 @@ func (a *App) VisibleFlags() []Flag { func (a *App) hasFlag(flag Flag) bool { for _, f := range a.Flags { - if flag == f { + if reflect.DeepEqual(flag, f) { return true } } @@ -449,7 +496,6 @@ func (a *App) hasFlag(flag Flag) bool { } func (a *App) errWriter() io.Writer { - // When the app ErrWriter is nil use the package level one. if a.ErrWriter == nil { return ErrWriter @@ -458,9 +504,23 @@ func (a *App) errWriter() io.Writer { return a.ErrWriter } -func (a *App) appendFlag(flag Flag) { - if !a.hasFlag(flag) { - a.Flags = append(a.Flags, flag) +func (a *App) appendFlag(fl Flag) { + if !hasFlag(a.Flags, fl) { + a.Flags = append(a.Flags, fl) + } +} + +func (a *App) appendCommand(c *Command) { + if !hasCommand(a.Commands, c) { + a.Commands = append(a.Commands, c) + } +} + +func (a *App) handleExitCoder(context *Context, err error) { + if a.ExitErrHandler != nil { + a.ExitErrHandler(context, err) + } else { + HandleExitCoder(err) } } @@ -471,7 +531,7 @@ type Author struct { } // String makes Author comply to the Stringer interface, to allow an easy print in the templating process -func (a Author) String() string { +func (a *Author) String() string { e := "" if a.Email != "" { e = " <" + a.Email + ">" @@ -484,14 +544,15 @@ func (a Author) String() string { // it's an ActionFunc or a func with the legacy signature for Action, the func // is run! func HandleAction(action interface{}, context *Context) (err error) { - if a, ok := action.(ActionFunc); ok { + switch a := action.(type) { + case ActionFunc: return a(context) - } else if a, ok := action.(func(*Context) error); ok { + case func(*Context) error: return a(context) - } else if a, ok := action.(func(*Context)); ok { // deprecated function signature + case func(*Context): // deprecated function signature a(context) return nil - } else { - return errInvalidActionType } + + return errInvalidActionType } diff --git a/vendor/github.com/urfave/cli/v2/appveyor.yml b/vendor/github.com/urfave/cli/v2/appveyor.yml new file mode 100644 index 000000000..f1cae90b5 --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/appveyor.yml @@ -0,0 +1,28 @@ +version: "{build}" + +os: Windows Server 2016 + +image: Visual Studio 2017 + +clone_folder: c:\gopath\src\github.com\urfave\cli + +cache: + - node_modules + +environment: + GOPATH: C:\gopath + GOVERSION: 1.11.x + GO111MODULE: on + GOPROXY: https://proxy.golang.org + +install: + - set PATH=%GOPATH%\bin;C:\go\bin;%PATH% + - go version + - go env + - go get github.com/urfave/gfmrun/cmd/gfmrun + - go mod tidy + +build_script: + - go run build.go vet + - go run build.go test + - go run build.go gfmrun docs/v1/manual.md diff --git a/vendor/github.com/urfave/cli/v2/args.go b/vendor/github.com/urfave/cli/v2/args.go new file mode 100644 index 000000000..bd65c17bd --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/args.go @@ -0,0 +1,54 @@ +package cli + +type Args interface { + // Get returns the nth argument, or else a blank string + Get(n int) string + // First returns the first argument, or else a blank string + First() string + // Tail returns the rest of the arguments (not the first one) + // or else an empty string slice + Tail() []string + // Len returns the length of the wrapped slice + Len() int + // Present checks if there are any arguments present + Present() bool + // Slice returns a copy of the internal slice + Slice() []string +} + +type args []string + +func (a *args) Get(n int) string { + if len(*a) > n { + return (*a)[n] + } + return "" +} + +func (a *args) First() string { + return a.Get(0) +} + +func (a *args) Tail() []string { + if a.Len() >= 2 { + tail := []string((*a)[1:]) + ret := make([]string, len(tail)) + copy(ret, tail) + return ret + } + return []string{} +} + +func (a *args) Len() int { + return len(*a) +} + +func (a *args) Present() bool { + return a.Len() != 0 +} + +func (a *args) Slice() []string { + ret := make([]string, len(*a)) + copy(ret, *a) + return ret +} diff --git a/vendor/github.com/urfave/cli/v2/category.go b/vendor/github.com/urfave/cli/v2/category.go new file mode 100644 index 000000000..867e3908c --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/category.go @@ -0,0 +1,79 @@ +package cli + +// CommandCategories interface allows for category manipulation +type CommandCategories interface { + // AddCommand adds a command to a category, creating a new category if necessary. + AddCommand(category string, command *Command) + // categories returns a copy of the category slice + Categories() []CommandCategory +} + +type commandCategories []*commandCategory + +func newCommandCategories() CommandCategories { + ret := commandCategories([]*commandCategory{}) + return &ret +} + +func (c *commandCategories) Less(i, j int) bool { + return lexicographicLess((*c)[i].Name(), (*c)[j].Name()) +} + +func (c *commandCategories) Len() int { + return len(*c) +} + +func (c *commandCategories) Swap(i, j int) { + (*c)[i], (*c)[j] = (*c)[j], (*c)[i] +} + +func (c *commandCategories) AddCommand(category string, command *Command) { + for _, commandCategory := range []*commandCategory(*c) { + if commandCategory.name == category { + commandCategory.commands = append(commandCategory.commands, command) + return + } + } + newVal := append(*c, + &commandCategory{name: category, commands: []*Command{command}}) + *c = newVal +} + +func (c *commandCategories) Categories() []CommandCategory { + ret := make([]CommandCategory, len(*c)) + for i, cat := range *c { + ret[i] = cat + } + return ret +} + +// CommandCategory is a category containing commands. +type CommandCategory interface { + // Name returns the category name string + Name() string + // VisibleCommands returns a slice of the Commands with Hidden=false + VisibleCommands() []*Command +} + +type commandCategory struct { + name string + commands []*Command +} + +func (c *commandCategory) Name() string { + return c.name +} + +func (c *commandCategory) VisibleCommands() []*Command { + if c.commands == nil { + c.commands = []*Command{} + } + + var ret []*Command + for _, command := range c.commands { + if !command.Hidden { + ret = append(ret, command) + } + } + return ret +} diff --git a/vendor/github.com/urfave/cli/cli.go b/vendor/github.com/urfave/cli/v2/cli.go similarity index 56% rename from vendor/github.com/urfave/cli/cli.go rename to vendor/github.com/urfave/cli/v2/cli.go index 90c07eb8e..62a5bc22d 100644 --- a/vendor/github.com/urfave/cli/cli.go +++ b/vendor/github.com/urfave/cli/v2/cli.go @@ -2,21 +2,22 @@ // Go applications. cli is designed to be easy to understand and write, the most simple // cli application can be written as follows: // func main() { -// cli.NewApp().Run(os.Args) +// (&cli.App{}).Run(os.Args) // } // // Of course this application does not do much, so let's make this an actual application: // func main() { -// app := cli.NewApp() -// app.Name = "greet" -// app.Usage = "say a greeting" -// app.Action = func(c *cli.Context) error { -// println("Greetings") -// return nil -// } +// app := &cli.App{ +// Name: "greet", +// Usage: "say a greeting", +// Action: func(c *cli.Context) error { +// fmt.Println("Greetings") +// return nil +// }, +// } // // app.Run(os.Args) // } package cli -//go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go +//go:generate go run flag-gen/main.go flag-gen/assets_vfsdata.go diff --git a/vendor/github.com/urfave/cli/command.go b/vendor/github.com/urfave/cli/v2/command.go similarity index 57% rename from vendor/github.com/urfave/cli/command.go rename to vendor/github.com/urfave/cli/v2/command.go index 23de2944b..db6c8024b 100644 --- a/vendor/github.com/urfave/cli/command.go +++ b/vendor/github.com/urfave/cli/v2/command.go @@ -1,8 +1,8 @@ package cli import ( + "flag" "fmt" - "io/ioutil" "sort" "strings" ) @@ -11,8 +11,6 @@ import ( type Command struct { // The name of the command Name string - // short name of the command. Typically one character (deprecated, use `Aliases`) - ShortName string // A list of aliases for the command Aliases []string // A short description of the usage of this command @@ -34,27 +32,23 @@ type Command struct { // It is run even if Action() panics After AfterFunc // The function to call when this command is invoked - Action interface{} - // TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind - // of deprecation period has passed, maybe? - + Action ActionFunc // Execute this function if a usage error occurs. OnUsageError OnUsageErrorFunc // List of child commands - Subcommands Commands + Subcommands []*Command // List of flags to parse Flags []Flag // Treat all flags as normal arguments if true SkipFlagParsing bool - // Skip argument reordering which attempts to move flags before arguments, - // but only works if all flags appear after all arguments. This behavior was - // removed n version 2 since it only works under specific conditions so we - // backport here by exposing it as an option for compatibility. - SkipArgReorder bool // Boolean to hide built-in help command HideHelp bool // Boolean to hide this command from help or completion Hidden bool + // Boolean to enable short-option handling so user can combine several + // single-character bool arguments into one + // i.e. foobar -o -v -> foobar -ov + UseShortOptionHandling bool // Full name of command for help, defaults to full command name, including parent commands. HelpName string @@ -66,14 +60,16 @@ type Command struct { CustomHelpTemplate string } -type CommandsByName []Command +type Commands []*Command + +type CommandsByName []*Command func (c CommandsByName) Len() int { return len(c) } func (c CommandsByName) Less(i, j int) bool { - return c[i].Name < c[j].Name + return lexicographicLess(c[i].Name, c[j].Name) } func (c CommandsByName) Swap(i, j int) { @@ -82,81 +78,29 @@ func (c CommandsByName) Swap(i, j int) { // FullName returns the full name of the command. // For subcommands this ensures that parent commands are part of the command path -func (c Command) FullName() string { +func (c *Command) FullName() string { if c.commandNamePath == nil { return c.Name } return strings.Join(c.commandNamePath, " ") } -// Commands is a slice of Command -type Commands []Command - // Run invokes the command given the context, parses ctx.Args() to generate command-specific flags -func (c Command) Run(ctx *Context) (err error) { +func (c *Command) Run(ctx *Context) (err error) { if len(c.Subcommands) > 0 { return c.startApp(ctx) } - if !c.HideHelp && (HelpFlag != BoolFlag{}) { + if !c.HideHelp && HelpFlag != nil { // append help to flags - c.Flags = append( - c.Flags, - HelpFlag, - ) + c.appendFlag(HelpFlag) } - set, err := flagSet(c.Name, c.Flags) - if err != nil { - return err - } - set.SetOutput(ioutil.Discard) - - if c.SkipFlagParsing { - err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...)) - } else if !c.SkipArgReorder { - firstFlagIndex := -1 - terminatorIndex := -1 - for index, arg := range ctx.Args() { - if arg == "--" { - terminatorIndex = index - break - } else if arg == "-" { - // Do nothing. A dash alone is not really a flag. - continue - } else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 { - firstFlagIndex = index - } - } - - if firstFlagIndex > -1 { - args := ctx.Args() - regularArgs := make([]string, len(args[1:firstFlagIndex])) - copy(regularArgs, args[1:firstFlagIndex]) - - var flagArgs []string - if terminatorIndex > -1 { - flagArgs = args[firstFlagIndex:terminatorIndex] - regularArgs = append(regularArgs, args[terminatorIndex:]...) - } else { - flagArgs = args[firstFlagIndex:] - } - - err = set.Parse(append(flagArgs, regularArgs...)) - } else { - err = set.Parse(ctx.Args().Tail()) - } - } else { - err = set.Parse(ctx.Args().Tail()) + if ctx.App.UseShortOptionHandling { + c.UseShortOptionHandling = true } - nerr := normalizeFlags(c.Flags, set) - if nerr != nil { - fmt.Fprintln(ctx.App.Writer, nerr) - fmt.Fprintln(ctx.App.Writer) - ShowCommandHelp(ctx, c.Name) - return nerr - } + set, err := c.parseFlags(ctx.Args(), ctx.shellComplete) context := NewContext(ctx.App, set, ctx) context.Command = c @@ -166,13 +110,13 @@ func (c Command) Run(ctx *Context) (err error) { if err != nil { if c.OnUsageError != nil { - err := c.OnUsageError(context, err, false) - HandleExitCoder(err) + err = c.OnUsageError(context, err, false) + context.App.handleExitCoder(context, err) return err } - fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error()) - fmt.Fprintln(context.App.Writer) - ShowCommandHelp(context, c.Name) + _, _ = fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error()) + _, _ = fmt.Fprintln(context.App.Writer) + _ = ShowCommandHelp(context, c.Name) return err } @@ -180,13 +124,19 @@ func (c Command) Run(ctx *Context) (err error) { return nil } + cerr := checkRequiredFlags(c.Flags, context) + if cerr != nil { + _ = ShowCommandHelp(context, c.Name) + return cerr + } + if c.After != nil { defer func() { afterErr := c.After(context) if afterErr != nil { - HandleExitCoder(err) + context.App.handleExitCoder(context, err) if err != nil { - err = NewMultiError(err, afterErr) + err = newMultiError(err, afterErr) } else { err = afterErr } @@ -197,8 +147,8 @@ func (c Command) Run(ctx *Context) (err error) { if c.Before != nil { err = c.Before(context) if err != nil { - ShowCommandHelp(context, c.Name) - HandleExitCoder(err) + _ = ShowCommandHelp(context, c.Name) + context.App.handleExitCoder(context, err) return err } } @@ -207,27 +157,53 @@ func (c Command) Run(ctx *Context) (err error) { c.Action = helpSubcommand.Action } - err = HandleAction(c.Action, context) + context.Command = c + err = c.Action(context) if err != nil { - HandleExitCoder(err) + context.App.handleExitCoder(context, err) } return err } -// Names returns the names including short names and aliases. -func (c Command) Names() []string { - names := []string{c.Name} - - if c.ShortName != "" { - names = append(names, c.ShortName) - } - - return append(names, c.Aliases...) +func (c *Command) newFlagSet() (*flag.FlagSet, error) { + return flagSet(c.Name, c.Flags) } -// HasName returns true if Command.Name or Command.ShortName matches given name -func (c Command) HasName(name string) bool { +func (c *Command) useShortOptionHandling() bool { + return c.UseShortOptionHandling +} + +func (c *Command) parseFlags(args Args, shellComplete bool) (*flag.FlagSet, error) { + set, err := c.newFlagSet() + if err != nil { + return nil, err + } + + if c.SkipFlagParsing { + return set, set.Parse(append([]string{"--"}, args.Tail()...)) + } + + err = parseIter(set, c, args.Tail(), shellComplete) + if err != nil { + return nil, err + } + + err = normalizeFlags(c.Flags, set) + if err != nil { + return nil, err + } + + return set, nil +} + +// Names returns the names including short names and aliases. +func (c *Command) Names() []string { + return append([]string{c.Name}, c.Aliases...) +} + +// HasName returns true if Command.Name matches given name +func (c *Command) HasName(name string) bool { for _, n := range c.Names() { if n == name { return true @@ -236,11 +212,12 @@ func (c Command) HasName(name string) bool { return false } -func (c Command) startApp(ctx *Context) error { - app := NewApp() - app.Metadata = ctx.App.Metadata - // set the name and usage - app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) +func (c *Command) startApp(ctx *Context) error { + app := &App{ + Metadata: ctx.App.Metadata, + Name: fmt.Sprintf("%s %s", ctx.App.Name, c.Name), + } + if c.HelpName == "" { app.HelpName = c.HelpName } else { @@ -263,17 +240,17 @@ func (c Command) startApp(ctx *Context) error { app.Version = ctx.App.Version app.HideVersion = ctx.App.HideVersion app.Compiled = ctx.App.Compiled - app.Author = ctx.App.Author - app.Email = ctx.App.Email app.Writer = ctx.App.Writer app.ErrWriter = ctx.App.ErrWriter + app.ExitErrHandler = ctx.App.ExitErrHandler + app.UseShortOptionHandling = ctx.App.UseShortOptionHandling - app.categories = CommandCategories{} + app.categories = newCommandCategories() for _, command := range c.Subcommands { - app.categories = app.categories.AddCommand(command.Category, command) + app.categories.AddCommand(command.Category, command) } - sort.Sort(app.categories) + sort.Sort(app.categories.(*commandCategories)) // bash completion app.EnableBashCompletion = ctx.App.EnableBashCompletion @@ -299,6 +276,22 @@ func (c Command) startApp(ctx *Context) error { } // VisibleFlags returns a slice of the Flags with Hidden=false -func (c Command) VisibleFlags() []Flag { +func (c *Command) VisibleFlags() []Flag { return visibleFlags(c.Flags) } + +func (c *Command) appendFlag(fl Flag) { + if !hasFlag(c.Flags, fl) { + c.Flags = append(c.Flags, fl) + } +} + +func hasCommand(commands []*Command, command *Command) bool { + for _, existing := range commands { + if command == existing { + return true + } + } + + return false +} diff --git a/vendor/github.com/urfave/cli/v2/context.go b/vendor/github.com/urfave/cli/v2/context.go new file mode 100644 index 000000000..c0c526f41 --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/context.go @@ -0,0 +1,274 @@ +package cli + +import ( + "context" + "errors" + "flag" + "fmt" + "strings" +) + +// Context is a type that is passed through to +// each Handler action in a cli application. Context +// can be used to retrieve context-specific args and +// parsed command-line options. +type Context struct { + context.Context + App *App + Command *Command + shellComplete bool + setFlags map[string]bool + flagSet *flag.FlagSet + parentContext *Context +} + +// NewContext creates a new context. For use in when invoking an App or Command action. +func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { + c := &Context{App: app, flagSet: set, parentContext: parentCtx} + if parentCtx != nil { + c.Context = parentCtx.Context + c.shellComplete = parentCtx.shellComplete + if parentCtx.flagSet == nil { + parentCtx.flagSet = &flag.FlagSet{} + } + } + + c.Command = &Command{} + + if c.Context == nil { + c.Context = context.Background() + } + + return c +} + +// NumFlags returns the number of flags set +func (c *Context) NumFlags() int { + return c.flagSet.NFlag() +} + +// Set sets a context flag to a value. +func (c *Context) Set(name, value string) error { + return c.flagSet.Set(name, value) +} + +// IsSet determines if the flag was actually set +func (c *Context) IsSet(name string) bool { + if fs := lookupFlagSet(name, c); fs != nil { + if fs := lookupFlagSet(name, c); fs != nil { + isSet := false + fs.Visit(func(f *flag.Flag) { + if f.Name == name { + isSet = true + } + }) + if isSet { + return true + } + } + + f := lookupFlag(name, c) + if f == nil { + return false + } + + return f.IsSet() + } + + return false +} + +// LocalFlagNames returns a slice of flag names used in this context. +func (c *Context) LocalFlagNames() []string { + var names []string + c.flagSet.Visit(makeFlagNameVisitor(&names)) + return names +} + +// FlagNames returns a slice of flag names used by the this context and all of +// its parent contexts. +func (c *Context) FlagNames() []string { + var names []string + for _, ctx := range c.Lineage() { + ctx.flagSet.Visit(makeFlagNameVisitor(&names)) + } + return names +} + +// Lineage returns *this* context and all of its ancestor contexts in order from +// child to parent +func (c *Context) Lineage() []*Context { + var lineage []*Context + + for cur := c; cur != nil; cur = cur.parentContext { + lineage = append(lineage, cur) + } + + return lineage +} + +// Value returns the value of the flag corresponding to `name` +func (c *Context) Value(name string) interface{} { + return c.flagSet.Lookup(name).Value.(flag.Getter).Get() +} + +// Args returns the command line arguments associated with the context. +func (c *Context) Args() Args { + ret := args(c.flagSet.Args()) + return &ret +} + +// NArg returns the number of the command line arguments. +func (c *Context) NArg() int { + return c.Args().Len() +} + +func lookupFlag(name string, ctx *Context) Flag { + for _, c := range ctx.Lineage() { + if c.Command == nil { + continue + } + + for _, f := range c.Command.Flags { + for _, n := range f.Names() { + if n == name { + return f + } + } + } + } + + if ctx.App != nil { + for _, f := range ctx.App.Flags { + for _, n := range f.Names() { + if n == name { + return f + } + } + } + } + + return nil +} + +func lookupFlagSet(name string, ctx *Context) *flag.FlagSet { + for _, c := range ctx.Lineage() { + if f := c.flagSet.Lookup(name); f != nil { + return c.flagSet + } + } + + return nil +} + +func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { + switch ff.Value.(type) { + case Serializer: + _ = set.Set(name, ff.Value.(Serializer).Serialize()) + default: + _ = set.Set(name, ff.Value.String()) + } +} + +func normalizeFlags(flags []Flag, set *flag.FlagSet) error { + visited := make(map[string]bool) + set.Visit(func(f *flag.Flag) { + visited[f.Name] = true + }) + for _, f := range flags { + parts := f.Names() + if len(parts) == 1 { + continue + } + var ff *flag.Flag + for _, name := range parts { + name = strings.Trim(name, " ") + if visited[name] { + if ff != nil { + return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name) + } + ff = set.Lookup(name) + } + } + if ff == nil { + continue + } + for _, name := range parts { + name = strings.Trim(name, " ") + if !visited[name] { + copyFlag(name, ff, set) + } + } + } + return nil +} + +func makeFlagNameVisitor(names *[]string) func(*flag.Flag) { + return func(f *flag.Flag) { + nameParts := strings.Split(f.Name, ",") + name := strings.TrimSpace(nameParts[0]) + + for _, part := range nameParts { + part = strings.TrimSpace(part) + if len(part) > len(name) { + name = part + } + } + + if name != "" { + *names = append(*names, name) + } + } +} + +type requiredFlagsErr interface { + error + getMissingFlags() []string +} + +type errRequiredFlags struct { + missingFlags []string +} + +func (e *errRequiredFlags) Error() string { + numberOfMissingFlags := len(e.missingFlags) + if numberOfMissingFlags == 1 { + return fmt.Sprintf("Required flag %q not set", e.missingFlags[0]) + } + joinedMissingFlags := strings.Join(e.missingFlags, ", ") + return fmt.Sprintf("Required flags %q not set", joinedMissingFlags) +} + +func (e *errRequiredFlags) getMissingFlags() []string { + return e.missingFlags +} + +func checkRequiredFlags(flags []Flag, context *Context) requiredFlagsErr { + var missingFlags []string + for _, f := range flags { + if rf, ok := f.(RequiredFlag); ok && rf.IsRequired() { + var flagPresent bool + var flagName string + + for _, key := range f.Names() { + if len(key) > 1 { + flagName = key + } + + if context.IsSet(strings.TrimSpace(key)) { + flagPresent = true + } + } + + if !flagPresent && flagName != "" { + missingFlags = append(missingFlags, flagName) + } + } + } + + if len(missingFlags) != 0 { + return &errRequiredFlags{missingFlags: missingFlags} + } + + return nil +} diff --git a/vendor/github.com/urfave/cli/v2/docs.go b/vendor/github.com/urfave/cli/v2/docs.go new file mode 100644 index 000000000..dc16fc82d --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/docs.go @@ -0,0 +1,148 @@ +package cli + +import ( + "bytes" + "fmt" + "io" + "sort" + "strings" + "text/template" + + "github.com/cpuguy83/go-md2man/v2/md2man" +) + +// ToMarkdown creates a markdown string for the `*App` +// The function errors if either parsing or writing of the string fails. +func (a *App) ToMarkdown() (string, error) { + var w bytes.Buffer + if err := a.writeDocTemplate(&w); err != nil { + return "", err + } + return w.String(), nil +} + +// ToMan creates a man page string for the `*App` +// The function errors if either parsing or writing of the string fails. +func (a *App) ToMan() (string, error) { + var w bytes.Buffer + if err := a.writeDocTemplate(&w); err != nil { + return "", err + } + man := md2man.Render(w.Bytes()) + return string(man), nil +} + +type cliTemplate struct { + App *App + Commands []string + GlobalArgs []string + SynopsisArgs []string +} + +func (a *App) writeDocTemplate(w io.Writer) error { + const name = "cli" + t, err := template.New(name).Parse(MarkdownDocTemplate) + if err != nil { + return err + } + return t.ExecuteTemplate(w, name, &cliTemplate{ + App: a, + Commands: prepareCommands(a.Commands, 0), + GlobalArgs: prepareArgsWithValues(a.VisibleFlags()), + SynopsisArgs: prepareArgsSynopsis(a.VisibleFlags()), + }) +} + +func prepareCommands(commands []*Command, level int) []string { + var coms []string + for _, command := range commands { + if command.Hidden { + continue + } + usage := "" + if command.Usage != "" { + usage = command.Usage + } + + prepared := fmt.Sprintf("%s %s\n\n%s\n", + strings.Repeat("#", level+2), + strings.Join(command.Names(), ", "), + usage, + ) + + flags := prepareArgsWithValues(command.Flags) + if len(flags) > 0 { + prepared += fmt.Sprintf("\n%s", strings.Join(flags, "\n")) + } + + coms = append(coms, prepared) + + // recursevly iterate subcommands + if len(command.Subcommands) > 0 { + coms = append( + coms, + prepareCommands(command.Subcommands, level+1)..., + ) + } + } + + return coms +} + +func prepareArgsWithValues(flags []Flag) []string { + return prepareFlags(flags, ", ", "**", "**", `""`, true) +} + +func prepareArgsSynopsis(flags []Flag) []string { + return prepareFlags(flags, "|", "[", "]", "[value]", false) +} + +func prepareFlags( + flags []Flag, + sep, opener, closer, value string, + addDetails bool, +) []string { + args := []string{} + for _, f := range flags { + flag, ok := f.(DocGenerationFlag) + if !ok { + continue + } + modifiedArg := opener + + for _, s := range flag.Names() { + trimmed := strings.TrimSpace(s) + if len(modifiedArg) > len(opener) { + modifiedArg += sep + } + if len(trimmed) > 1 { + modifiedArg += fmt.Sprintf("--%s", trimmed) + } else { + modifiedArg += fmt.Sprintf("-%s", trimmed) + } + } + modifiedArg += closer + if flag.TakesValue() { + modifiedArg += fmt.Sprintf("=%s", value) + } + + if addDetails { + modifiedArg += flagDetails(flag) + } + + args = append(args, modifiedArg+"\n") + + } + sort.Strings(args) + return args +} + +// flagDetails returns a string containing the flags metadata +func flagDetails(flag DocGenerationFlag) string { + description := flag.GetUsage() + value := flag.GetValue() + if value != "" { + description += " (default: " + value + ")" + } + return ": " + description +} diff --git a/vendor/github.com/urfave/cli/errors.go b/vendor/github.com/urfave/cli/v2/errors.go similarity index 62% rename from vendor/github.com/urfave/cli/errors.go rename to vendor/github.com/urfave/cli/v2/errors.go index 562b2953c..344b4361e 100644 --- a/vendor/github.com/urfave/cli/errors.go +++ b/vendor/github.com/urfave/cli/v2/errors.go @@ -15,25 +15,40 @@ var OsExiter = os.Exit var ErrWriter io.Writer = os.Stderr // MultiError is an error that wraps multiple errors. -type MultiError struct { - Errors []error +type MultiError interface { + error + // Errors returns a copy of the errors slice + Errors() []error } // NewMultiError creates a new MultiError. Pass in one or more errors. -func NewMultiError(err ...error) MultiError { - return MultiError{Errors: err} +func newMultiError(err ...error) MultiError { + ret := multiError(err) + return &ret } +type multiError []error + // Error implements the error interface. -func (m MultiError) Error() string { - errs := make([]string, len(m.Errors)) - for i, err := range m.Errors { +func (m *multiError) Error() string { + errs := make([]string, len(*m)) + for i, err := range *m { errs[i] = err.Error() } return strings.Join(errs, "\n") } +// Errors returns a copy of the errors slice +func (m *multiError) Errors() []error { + errs := make([]error, len(*m)) + for _, err := range *m { + errs = append(errs, err) + } + return errs +} + +// ErrorFormatter is the interface that will suitably format the error output type ErrorFormatter interface { Format(s fmt.State, verb rune) } @@ -45,29 +60,30 @@ type ExitCoder interface { ExitCode() int } -// ExitError fulfills both the builtin `error` interface and `ExitCoder` -type ExitError struct { +type exitError struct { exitCode int message interface{} } -// NewExitError makes a new *ExitError -func NewExitError(message interface{}, exitCode int) *ExitError { - return &ExitError{ - exitCode: exitCode, +// NewExitError makes a new *exitError +func NewExitError(message interface{}, exitCode int) ExitCoder { + return Exit(message, exitCode) +} + +// Exit wraps a message and exit code into an ExitCoder suitable for handling by +// HandleExitCoder +func Exit(message interface{}, exitCode int) ExitCoder { + return &exitError{ message: message, + exitCode: exitCode, } } -// Error returns the string message, fulfilling the interface required by -// `error` -func (ee *ExitError) Error() string { +func (ee *exitError) Error() string { return fmt.Sprintf("%v", ee.message) } -// ExitCode returns the exit code, fulfilling the interface required by -// `ExitCoder` -func (ee *ExitError) ExitCode() int { +func (ee *exitError) ExitCode() int { return ee.exitCode } @@ -83,9 +99,9 @@ func HandleExitCoder(err error) { if exitErr, ok := err.(ExitCoder); ok { if err.Error() != "" { if _, ok := exitErr.(ErrorFormatter); ok { - fmt.Fprintf(ErrWriter, "%+v\n", err) + _, _ = fmt.Fprintf(ErrWriter, "%+v\n", err) } else { - fmt.Fprintln(ErrWriter, err) + _, _ = fmt.Fprintln(ErrWriter, err) } } OsExiter(exitErr.ExitCode()) @@ -101,10 +117,10 @@ func HandleExitCoder(err error) { func handleMultiError(multiErr MultiError) int { code := 1 - for _, merr := range multiErr.Errors { + for _, merr := range multiErr.Errors() { if multiErr2, ok := merr.(MultiError); ok { code = handleMultiError(multiErr2) - } else { + } else if merr != nil { fmt.Fprintln(ErrWriter, merr) if exitErr, ok := merr.(ExitCoder); ok { code = exitErr.ExitCode() diff --git a/vendor/github.com/urfave/cli/v2/fish.go b/vendor/github.com/urfave/cli/v2/fish.go new file mode 100644 index 000000000..67122c9fe --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/fish.go @@ -0,0 +1,192 @@ +package cli + +import ( + "bytes" + "fmt" + "io" + "strings" + "text/template" +) + +// ToFishCompletion creates a fish completion string for the `*App` +// The function errors if either parsing or writing of the string fails. +func (a *App) ToFishCompletion() (string, error) { + var w bytes.Buffer + if err := a.writeFishCompletionTemplate(&w); err != nil { + return "", err + } + return w.String(), nil +} + +type fishCompletionTemplate struct { + App *App + Completions []string + AllCommands []string +} + +func (a *App) writeFishCompletionTemplate(w io.Writer) error { + const name = "cli" + t, err := template.New(name).Parse(FishCompletionTemplate) + if err != nil { + return err + } + allCommands := []string{} + + // Add global flags + completions := a.prepareFishFlags(a.VisibleFlags(), allCommands) + + // Add help flag + if !a.HideHelp { + completions = append( + completions, + a.prepareFishFlags([]Flag{HelpFlag}, allCommands)..., + ) + } + + // Add version flag + if !a.HideVersion { + completions = append( + completions, + a.prepareFishFlags([]Flag{VersionFlag}, allCommands)..., + ) + } + + // Add commands and their flags + completions = append( + completions, + a.prepareFishCommands(a.VisibleCommands(), &allCommands, []string{})..., + ) + + return t.ExecuteTemplate(w, name, &fishCompletionTemplate{ + App: a, + Completions: completions, + AllCommands: allCommands, + }) +} + +func (a *App) prepareFishCommands(commands []*Command, allCommands *[]string, previousCommands []string) []string { + completions := []string{} + for _, command := range commands { + if command.Hidden { + continue + } + + var completion strings.Builder + completion.WriteString(fmt.Sprintf( + "complete -r -c %s -n '%s' -a '%s'", + a.Name, + a.fishSubcommandHelper(previousCommands), + strings.Join(command.Names(), " "), + )) + + if command.Usage != "" { + completion.WriteString(fmt.Sprintf(" -d '%s'", + escapeSingleQuotes(command.Usage))) + } + + if !command.HideHelp { + completions = append( + completions, + a.prepareFishFlags([]Flag{HelpFlag}, command.Names())..., + ) + } + + *allCommands = append(*allCommands, command.Names()...) + completions = append(completions, completion.String()) + completions = append( + completions, + a.prepareFishFlags(command.Flags, command.Names())..., + ) + + // recursevly iterate subcommands + if len(command.Subcommands) > 0 { + completions = append( + completions, + a.prepareFishCommands( + command.Subcommands, allCommands, command.Names(), + )..., + ) + } + } + + return completions +} + +func (a *App) prepareFishFlags(flags []Flag, previousCommands []string) []string { + completions := []string{} + for _, f := range flags { + flag, ok := f.(DocGenerationFlag) + if !ok { + continue + } + + completion := &strings.Builder{} + completion.WriteString(fmt.Sprintf( + "complete -c %s -n '%s'", + a.Name, + a.fishSubcommandHelper(previousCommands), + )) + + fishAddFileFlag(f, completion) + + for idx, opt := range flag.Names() { + if idx == 0 { + completion.WriteString(fmt.Sprintf( + " -l %s", strings.TrimSpace(opt), + )) + } else { + completion.WriteString(fmt.Sprintf( + " -s %s", strings.TrimSpace(opt), + )) + + } + } + + if flag.TakesValue() { + completion.WriteString(" -r") + } + + if flag.GetUsage() != "" { + completion.WriteString(fmt.Sprintf(" -d '%s'", + escapeSingleQuotes(flag.GetUsage()))) + } + + completions = append(completions, completion.String()) + } + + return completions +} + +func fishAddFileFlag(flag Flag, completion *strings.Builder) { + switch f := flag.(type) { + case *GenericFlag: + if f.TakesFile { + return + } + case *StringFlag: + if f.TakesFile { + return + } + case *StringSliceFlag: + if f.TakesFile { + return + } + } + completion.WriteString(" -f") +} + +func (a *App) fishSubcommandHelper(allCommands []string) string { + fishHelper := fmt.Sprintf("__fish_%s_no_subcommand", a.Name) + if len(allCommands) > 0 { + fishHelper = fmt.Sprintf( + "__fish_seen_subcommand_from %s", + strings.Join(allCommands, " "), + ) + } + return fishHelper + +} + +func escapeSingleQuotes(input string) string { + return strings.Replace(input, `'`, `\'`, -1) +} diff --git a/vendor/github.com/urfave/cli/v2/flag.go b/vendor/github.com/urfave/cli/v2/flag.go new file mode 100644 index 000000000..ec128fd44 --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag.go @@ -0,0 +1,398 @@ +package cli + +import ( + "flag" + "fmt" + "io/ioutil" + "reflect" + "regexp" + "runtime" + "strconv" + "strings" + "syscall" + "time" +) + +const defaultPlaceholder = "value" + +var ( + slPfx = fmt.Sprintf("sl:::%d:::", time.Now().UTC().UnixNano()) + + commaWhitespace = regexp.MustCompile("[, ]+.*") +) + +// BashCompletionFlag enables bash-completion for all commands and subcommands +var BashCompletionFlag Flag = &BoolFlag{ + Name: "generate-bash-completion", + Hidden: true, +} + +// VersionFlag prints the version for the application +var VersionFlag Flag = &BoolFlag{ + Name: "version", + Aliases: []string{"v"}, + Usage: "print the version", +} + +// HelpFlag prints the help for all commands and subcommands. +// Set to nil to disable the flag. The subcommand +// will still be added unless HideHelp is set to true. +var HelpFlag Flag = &BoolFlag{ + Name: "help", + Aliases: []string{"h"}, + Usage: "show help", +} + +// FlagStringer converts a flag definition to a string. This is used by help +// to display a flag. +var FlagStringer FlagStringFunc = stringifyFlag + +// Serializer is used to circumvent the limitations of flag.FlagSet.Set +type Serializer interface { + Serialize() string +} + +// FlagNamePrefixer converts a full flag name and its placeholder into the help +// message flag prefix. This is used by the default FlagStringer. +var FlagNamePrefixer FlagNamePrefixFunc = prefixedNames + +// FlagEnvHinter annotates flag help message with the environment variable +// details. This is used by the default FlagStringer. +var FlagEnvHinter FlagEnvHintFunc = withEnvHint + +// FlagFileHinter annotates flag help message with the environment variable +// details. This is used by the default FlagStringer. +var FlagFileHinter FlagFileHintFunc = withFileHint + +// FlagsByName is a slice of Flag. +type FlagsByName []Flag + +func (f FlagsByName) Len() int { + return len(f) +} + +func (f FlagsByName) Less(i, j int) bool { + if len(f[j].Names()) == 0 { + return false + } else if len(f[i].Names()) == 0 { + return true + } + return lexicographicLess(f[i].Names()[0], f[j].Names()[0]) +} + +func (f FlagsByName) Swap(i, j int) { + f[i], f[j] = f[j], f[i] +} + +// Flag is a common interface related to parsing flags in cli. +// For more advanced flag parsing techniques, it is recommended that +// this interface be implemented. +type Flag interface { + fmt.Stringer + // Apply Flag settings to the given flag set + Apply(*flag.FlagSet) error + Names() []string + IsSet() bool +} + +// RequiredFlag is an interface that allows us to mark flags as required +// it allows flags required flags to be backwards compatible with the Flag interface +type RequiredFlag interface { + Flag + + IsRequired() bool +} + +// DocGenerationFlag is an interface that allows documentation generation for the flag +type DocGenerationFlag interface { + Flag + + // TakesValue returns true if the flag takes a value, otherwise false + TakesValue() bool + + // GetUsage returns the usage string for the flag + GetUsage() string + + // GetValue returns the flags value as string representation and an empty + // string if the flag takes no value at all. + GetValue() string +} + +func flagSet(name string, flags []Flag) (*flag.FlagSet, error) { + set := flag.NewFlagSet(name, flag.ContinueOnError) + + for _, f := range flags { + if err := f.Apply(set); err != nil { + return nil, err + } + } + set.SetOutput(ioutil.Discard) + return set, nil +} + +func visibleFlags(fl []Flag) []Flag { + var visible []Flag + for _, f := range fl { + field := flagValue(f).FieldByName("Hidden") + if !field.IsValid() || !field.Bool() { + visible = append(visible, f) + } + } + return visible +} + +func prefixFor(name string) (prefix string) { + if len(name) == 1 { + prefix = "-" + } else { + prefix = "--" + } + + return +} + +// Returns the placeholder, if any, and the unquoted usage string. +func unquoteUsage(usage string) (string, string) { + for i := 0; i < len(usage); i++ { + if usage[i] == '`' { + for j := i + 1; j < len(usage); j++ { + if usage[j] == '`' { + name := usage[i+1 : j] + usage = usage[:i] + name + usage[j+1:] + return name, usage + } + } + break + } + } + return "", usage +} + +func prefixedNames(names []string, placeholder string) string { + var prefixed string + for i, name := range names { + if name == "" { + continue + } + + prefixed += prefixFor(name) + name + if placeholder != "" { + prefixed += " " + placeholder + } + if i < len(names)-1 { + prefixed += ", " + } + } + return prefixed +} + +func withEnvHint(envVars []string, str string) string { + envText := "" + if envVars != nil && len(envVars) > 0 { + prefix := "$" + suffix := "" + sep := ", $" + if runtime.GOOS == "windows" { + prefix = "%" + suffix = "%" + sep = "%, %" + } + + envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(envVars, sep), suffix) + } + return str + envText +} + +func flagNames(f Flag) []string { + var ret []string + + name := flagStringField(f, "Name") + aliases := flagStringSliceField(f, "Aliases") + + for _, part := range append([]string{name}, aliases...) { + // v1 -> v2 migration warning zone: + // Strip off anything after the first found comma or space, which + // *hopefully* makes it a tiny bit more obvious that unexpected behavior is + // caused by using the v1 form of stringly typed "Name". + ret = append(ret, commaWhitespace.ReplaceAllString(part, "")) + } + + return ret +} + +func flagStringSliceField(f Flag, name string) []string { + fv := flagValue(f) + field := fv.FieldByName(name) + + if field.IsValid() { + return field.Interface().([]string) + } + + return []string{} +} + +func flagStringField(f Flag, name string) string { + fv := flagValue(f) + field := fv.FieldByName(name) + + if field.IsValid() { + return field.String() + } + + return "" +} + +func withFileHint(filePath, str string) string { + fileText := "" + if filePath != "" { + fileText = fmt.Sprintf(" [%s]", filePath) + } + return str + fileText +} + +func flagValue(f Flag) reflect.Value { + fv := reflect.ValueOf(f) + for fv.Kind() == reflect.Ptr { + fv = reflect.Indirect(fv) + } + return fv +} + +func stringifyFlag(f Flag) string { + fv := flagValue(f) + + switch f.(type) { + case *IntSliceFlag: + return withEnvHint(flagStringSliceField(f, "EnvVars"), + stringifyIntSliceFlag(f.(*IntSliceFlag))) + case *Int64SliceFlag: + return withEnvHint(flagStringSliceField(f, "EnvVars"), + stringifyInt64SliceFlag(f.(*Int64SliceFlag))) + case *Float64SliceFlag: + return withEnvHint(flagStringSliceField(f, "EnvVars"), + stringifyFloat64SliceFlag(f.(*Float64SliceFlag))) + case *StringSliceFlag: + return withEnvHint(flagStringSliceField(f, "EnvVars"), + stringifyStringSliceFlag(f.(*StringSliceFlag))) + } + + placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String()) + + needsPlaceholder := false + defaultValueString := "" + val := fv.FieldByName("Value") + if val.IsValid() { + needsPlaceholder = val.Kind() != reflect.Bool + defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface()) + + if val.Kind() == reflect.String && val.String() != "" { + defaultValueString = fmt.Sprintf(" (default: %q)", val.String()) + } + } + + helpText := fv.FieldByName("DefaultText") + if helpText.IsValid() && helpText.String() != "" { + needsPlaceholder = val.Kind() != reflect.Bool + defaultValueString = fmt.Sprintf(" (default: %s)", helpText.String()) + } + + if defaultValueString == " (default: )" { + defaultValueString = "" + } + + if needsPlaceholder && placeholder == "" { + placeholder = defaultPlaceholder + } + + usageWithDefault := strings.TrimSpace(usage + defaultValueString) + + return withEnvHint(flagStringSliceField(f, "EnvVars"), + fmt.Sprintf("%s\t%s", prefixedNames(f.Names(), placeholder), usageWithDefault)) +} + +func stringifyIntSliceFlag(f *IntSliceFlag) string { + var defaultVals []string + if f.Value != nil && len(f.Value.Value()) > 0 { + for _, i := range f.Value.Value() { + defaultVals = append(defaultVals, strconv.Itoa(i)) + } + } + + return stringifySliceFlag(f.Usage, f.Names(), defaultVals) +} + +func stringifyInt64SliceFlag(f *Int64SliceFlag) string { + var defaultVals []string + if f.Value != nil && len(f.Value.Value()) > 0 { + for _, i := range f.Value.Value() { + defaultVals = append(defaultVals, strconv.FormatInt(i, 10)) + } + } + + return stringifySliceFlag(f.Usage, f.Names(), defaultVals) +} + +func stringifyFloat64SliceFlag(f *Float64SliceFlag) string { + var defaultVals []string + + if f.Value != nil && len(f.Value.Value()) > 0 { + for _, i := range f.Value.Value() { + defaultVals = append(defaultVals, strings.TrimRight(strings.TrimRight(fmt.Sprintf("%f", i), "0"), ".")) + } + } + + return stringifySliceFlag(f.Usage, f.Names(), defaultVals) +} + +func stringifyStringSliceFlag(f *StringSliceFlag) string { + var defaultVals []string + if f.Value != nil && len(f.Value.Value()) > 0 { + for _, s := range f.Value.Value() { + if len(s) > 0 { + defaultVals = append(defaultVals, strconv.Quote(s)) + } + } + } + + return stringifySliceFlag(f.Usage, f.Names(), defaultVals) +} + +func stringifySliceFlag(usage string, names, defaultVals []string) string { + placeholder, usage := unquoteUsage(usage) + if placeholder == "" { + placeholder = defaultPlaceholder + } + + defaultVal := "" + if len(defaultVals) > 0 { + defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", ")) + } + + usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal)) + return fmt.Sprintf("%s\t%s", prefixedNames(names, placeholder), usageWithDefault) +} + +func hasFlag(flags []Flag, fl Flag) bool { + for _, existing := range flags { + if fl == existing { + return true + } + } + + return false +} + +func flagFromEnvOrFile(envVars []string, filePath string) (val string, ok bool) { + for _, envVar := range envVars { + envVar = strings.TrimSpace(envVar) + if val, ok := syscall.Getenv(envVar); ok { + return val, true + } + } + for _, fileVar := range strings.Split(filePath, ",") { + if data, err := ioutil.ReadFile(fileVar); err == nil { + return string(data), true + } + } + return "", false +} diff --git a/vendor/github.com/urfave/cli/v2/flag_bool.go b/vendor/github.com/urfave/cli/v2/flag_bool.go new file mode 100644 index 000000000..6a1da61ef --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_bool.go @@ -0,0 +1,106 @@ +package cli + +import ( + "flag" + "fmt" + "strconv" +) + +// BoolFlag is a flag with type bool +type BoolFlag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + Value bool + DefaultText string + Destination *bool + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *BoolFlag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *BoolFlag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *BoolFlag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *BoolFlag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *BoolFlag) TakesValue() bool { + return false +} + +// GetUsage returns the usage string for the flag +func (f *BoolFlag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *BoolFlag) GetValue() string { + return "" +} + +// Apply populates the flag given the flag set and environment +func (f *BoolFlag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + if val != "" { + valBool, err := strconv.ParseBool(val) + + if err != nil { + return fmt.Errorf("could not parse %q as bool value for flag %s: %s", val, f.Name, err) + } + + f.Value = valBool + f.HasBeenSet = true + } + } + + for _, name := range f.Names() { + if f.Destination != nil { + set.BoolVar(f.Destination, name, f.Value, f.Usage) + continue + } + set.Bool(name, f.Value, f.Usage) + } + + return nil +} + +// Bool looks up the value of a local BoolFlag, returns +// false if not found +func (c *Context) Bool(name string) bool { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupBool(name, fs) + } + return false +} + +func lookupBool(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return false + } + return parsed + } + return false +} diff --git a/vendor/github.com/urfave/cli/v2/flag_duration.go b/vendor/github.com/urfave/cli/v2/flag_duration.go new file mode 100644 index 000000000..2c34944a4 --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_duration.go @@ -0,0 +1,105 @@ +package cli + +import ( + "flag" + "fmt" + "time" +) + +// DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration) +type DurationFlag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + Value time.Duration + DefaultText string + Destination *time.Duration + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *DurationFlag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *DurationFlag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *DurationFlag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *DurationFlag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *DurationFlag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f *DurationFlag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *DurationFlag) GetValue() string { + return f.Value.String() +} + +// Apply populates the flag given the flag set and environment +func (f *DurationFlag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + if val != "" { + valDuration, err := time.ParseDuration(val) + + if err != nil { + return fmt.Errorf("could not parse %q as duration value for flag %s: %s", val, f.Name, err) + } + + f.Value = valDuration + f.HasBeenSet = true + } + } + + for _, name := range f.Names() { + if f.Destination != nil { + set.DurationVar(f.Destination, name, f.Value, f.Usage) + continue + } + set.Duration(name, f.Value, f.Usage) + } + return nil +} + +// Duration looks up the value of a local DurationFlag, returns +// 0 if not found +func (c *Context) Duration(name string) time.Duration { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupDuration(name, fs) + } + return 0 +} + +func lookupDuration(name string, set *flag.FlagSet) time.Duration { + f := set.Lookup(name) + if f != nil { + parsed, err := time.ParseDuration(f.Value.String()) + if err != nil { + return 0 + } + return parsed + } + return 0 +} diff --git a/vendor/github.com/urfave/cli/v2/flag_float64.go b/vendor/github.com/urfave/cli/v2/flag_float64.go new file mode 100644 index 000000000..31f06f35e --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_float64.go @@ -0,0 +1,106 @@ +package cli + +import ( + "flag" + "fmt" + "strconv" +) + +// Float64Flag is a flag with type float64 +type Float64Flag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + Value float64 + DefaultText string + Destination *float64 + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *Float64Flag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *Float64Flag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *Float64Flag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *Float64Flag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *Float64Flag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f *Float64Flag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *Float64Flag) GetValue() string { + return fmt.Sprintf("%f", f.Value) +} + +// Apply populates the flag given the flag set and environment +func (f *Float64Flag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + if val != "" { + valFloat, err := strconv.ParseFloat(val, 10) + + if err != nil { + return fmt.Errorf("could not parse %q as float64 value for flag %s: %s", val, f.Name, err) + } + + f.Value = valFloat + f.HasBeenSet = true + } + } + + for _, name := range f.Names() { + if f.Destination != nil { + set.Float64Var(f.Destination, name, f.Value, f.Usage) + continue + } + set.Float64(name, f.Value, f.Usage) + } + + return nil +} + +// Float64 looks up the value of a local Float64Flag, returns +// 0 if not found +func (c *Context) Float64(name string) float64 { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupFloat64(name, fs) + } + return 0 +} + +func lookupFloat64(name string, set *flag.FlagSet) float64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseFloat(f.Value.String(), 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} diff --git a/vendor/github.com/urfave/cli/v2/flag_float64_slice.go b/vendor/github.com/urfave/cli/v2/flag_float64_slice.go new file mode 100644 index 000000000..91d2e9d10 --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_float64_slice.go @@ -0,0 +1,165 @@ +package cli + +import ( + "encoding/json" + "flag" + "fmt" + "strconv" + "strings" +) + +// Float64Slice wraps []float64 to satisfy flag.Value +type Float64Slice struct { + slice []float64 + hasBeenSet bool +} + +// NewFloat64Slice makes a *Float64Slice with default values +func NewFloat64Slice(defaults ...float64) *Float64Slice { + return &Float64Slice{slice: append([]float64{}, defaults...)} +} + +// Set parses the value into a float64 and appends it to the list of values +func (f *Float64Slice) Set(value string) error { + if !f.hasBeenSet { + f.slice = []float64{} + f.hasBeenSet = true + } + + if strings.HasPrefix(value, slPfx) { + // Deserializing assumes overwrite + _ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &f.slice) + f.hasBeenSet = true + return nil + } + + tmp, err := strconv.ParseFloat(value, 64) + if err != nil { + return err + } + + f.slice = append(f.slice, tmp) + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (f *Float64Slice) String() string { + return fmt.Sprintf("%#v", f.slice) +} + +// Serialize allows Float64Slice to fulfill Serializer +func (f *Float64Slice) Serialize() string { + jsonBytes, _ := json.Marshal(f.slice) + return fmt.Sprintf("%s%s", slPfx, string(jsonBytes)) +} + +// Value returns the slice of float64s set by this flag +func (f *Float64Slice) Value() []float64 { + return f.slice +} + +// Get returns the slice of float64s set by this flag +func (f *Float64Slice) Get() interface{} { + return *f +} + +// Float64SliceFlag is a flag with type *Float64Slice +type Float64SliceFlag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + Value *Float64Slice + DefaultText string + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *Float64SliceFlag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *Float64SliceFlag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *Float64SliceFlag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *Float64SliceFlag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true if the flag takes a value, otherwise false +func (f *Float64SliceFlag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f *Float64SliceFlag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *Float64SliceFlag) GetValue() string { + if f.Value != nil { + return f.Value.String() + } + return "" +} + +// Apply populates the flag given the flag set and environment +func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + if val != "" { + f.Value = &Float64Slice{} + + for _, s := range strings.Split(val, ",") { + if err := f.Value.Set(strings.TrimSpace(s)); err != nil { + return fmt.Errorf("could not parse %q as float64 slice value for flag %s: %s", f.Value, f.Name, err) + } + } + + f.HasBeenSet = true + } + } + + for _, name := range f.Names() { + if f.Value == nil { + f.Value = &Float64Slice{} + } + set.Var(f.Value, name, f.Usage) + } + + return nil +} + +// Float64Slice looks up the value of a local Float64SliceFlag, returns +// nil if not found +func (c *Context) Float64Slice(name string) []float64 { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupFloat64Slice(name, fs) + } + return nil +} + +func lookupFloat64Slice(name string, set *flag.FlagSet) []float64 { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*Float64Slice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} diff --git a/vendor/github.com/urfave/cli/v2/flag_generic.go b/vendor/github.com/urfave/cli/v2/flag_generic.go new file mode 100644 index 000000000..2d9baa78d --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_generic.go @@ -0,0 +1,108 @@ +package cli + +import ( + "flag" + "fmt" +) + +// Generic is a generic parseable type identified by a specific flag +type Generic interface { + Set(value string) error + String() string +} + +// GenericFlag is a flag with type Generic +type GenericFlag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + TakesFile bool + Value Generic + DefaultText string + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *GenericFlag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *GenericFlag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *GenericFlag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *GenericFlag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *GenericFlag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f *GenericFlag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *GenericFlag) GetValue() string { + if f.Value != nil { + return f.Value.String() + } + return "" +} + +// Apply takes the flagset and calls Set on the generic flag with the value +// provided by the user for parsing by the flag +func (f GenericFlag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + if val != "" { + if err := f.Value.Set(val); err != nil { + return fmt.Errorf("could not parse %q as value for flag %s: %s", val, f.Name, err) + } + + f.HasBeenSet = true + } + } + + for _, name := range f.Names() { + set.Var(f.Value, name, f.Usage) + } + + return nil +} + +// Generic looks up the value of a local GenericFlag, returns +// nil if not found +func (c *Context) Generic(name string) interface{} { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupGeneric(name, fs) + } + return nil +} + +func lookupGeneric(name string, set *flag.FlagSet) interface{} { + f := set.Lookup(name) + if f != nil { + parsed, err := f.Value, error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} diff --git a/vendor/github.com/urfave/cli/v2/flag_int.go b/vendor/github.com/urfave/cli/v2/flag_int.go new file mode 100644 index 000000000..be961bf5f --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_int.go @@ -0,0 +1,106 @@ +package cli + +import ( + "flag" + "fmt" + "strconv" +) + +// IntFlag is a flag with type int +type IntFlag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + Value int + DefaultText string + Destination *int + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *IntFlag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *IntFlag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *IntFlag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *IntFlag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *IntFlag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f *IntFlag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *IntFlag) GetValue() string { + return fmt.Sprintf("%d", f.Value) +} + +// Apply populates the flag given the flag set and environment +func (f *IntFlag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + if val != "" { + valInt, err := strconv.ParseInt(val, 0, 64) + + if err != nil { + return fmt.Errorf("could not parse %q as int value for flag %s: %s", val, f.Name, err) + } + + f.Value = int(valInt) + f.HasBeenSet = true + } + } + + for _, name := range f.Names() { + if f.Destination != nil { + set.IntVar(f.Destination, name, f.Value, f.Usage) + continue + } + set.Int(name, f.Value, f.Usage) + } + + return nil +} + +// Int looks up the value of a local IntFlag, returns +// 0 if not found +func (c *Context) Int(name string) int { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupInt(name, fs) + } + return 0 +} + +func lookupInt(name string, set *flag.FlagSet) int { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return int(parsed) + } + return 0 +} diff --git a/vendor/github.com/urfave/cli/v2/flag_int64.go b/vendor/github.com/urfave/cli/v2/flag_int64.go new file mode 100644 index 000000000..c979119f8 --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_int64.go @@ -0,0 +1,105 @@ +package cli + +import ( + "flag" + "fmt" + "strconv" +) + +// Int64Flag is a flag with type int64 +type Int64Flag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + Value int64 + DefaultText string + Destination *int64 + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *Int64Flag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *Int64Flag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *Int64Flag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *Int64Flag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *Int64Flag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f *Int64Flag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *Int64Flag) GetValue() string { + return fmt.Sprintf("%d", f.Value) +} + +// Apply populates the flag given the flag set and environment +func (f *Int64Flag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + if val != "" { + valInt, err := strconv.ParseInt(val, 0, 64) + + if err != nil { + return fmt.Errorf("could not parse %q as int value for flag %s: %s", val, f.Name, err) + } + + f.Value = valInt + f.HasBeenSet = true + } + } + + for _, name := range f.Names() { + if f.Destination != nil { + set.Int64Var(f.Destination, name, f.Value, f.Usage) + continue + } + set.Int64(name, f.Value, f.Usage) + } + return nil +} + +// Int64 looks up the value of a local Int64Flag, returns +// 0 if not found +func (c *Context) Int64(name string) int64 { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupInt64(name, fs) + } + return 0 +} + +func lookupInt64(name string, set *flag.FlagSet) int64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} diff --git a/vendor/github.com/urfave/cli/v2/flag_int64_slice.go b/vendor/github.com/urfave/cli/v2/flag_int64_slice.go new file mode 100644 index 000000000..41aa0667e --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_int64_slice.go @@ -0,0 +1,161 @@ +package cli + +import ( + "encoding/json" + "flag" + "fmt" + "strconv" + "strings" +) + +// Int64Slice wraps []int64 to satisfy flag.Value +type Int64Slice struct { + slice []int64 + hasBeenSet bool +} + +// NewInt64Slice makes an *Int64Slice with default values +func NewInt64Slice(defaults ...int64) *Int64Slice { + return &Int64Slice{slice: append([]int64{}, defaults...)} +} + +// Set parses the value into an integer and appends it to the list of values +func (i *Int64Slice) Set(value string) error { + if !i.hasBeenSet { + i.slice = []int64{} + i.hasBeenSet = true + } + + if strings.HasPrefix(value, slPfx) { + // Deserializing assumes overwrite + _ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &i.slice) + i.hasBeenSet = true + return nil + } + + tmp, err := strconv.ParseInt(value, 0, 64) + if err != nil { + return err + } + + i.slice = append(i.slice, tmp) + + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (i *Int64Slice) String() string { + return fmt.Sprintf("%#v", i.slice) +} + +// Serialize allows Int64Slice to fulfill Serializer +func (i *Int64Slice) Serialize() string { + jsonBytes, _ := json.Marshal(i.slice) + return fmt.Sprintf("%s%s", slPfx, string(jsonBytes)) +} + +// Value returns the slice of ints set by this flag +func (i *Int64Slice) Value() []int64 { + return i.slice +} + +// Get returns the slice of ints set by this flag +func (i *Int64Slice) Get() interface{} { + return *i +} + +// Int64SliceFlag is a flag with type *Int64Slice +type Int64SliceFlag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + Value *Int64Slice + DefaultText string + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *Int64SliceFlag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *Int64SliceFlag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *Int64SliceFlag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *Int64SliceFlag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *Int64SliceFlag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f Int64SliceFlag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *Int64SliceFlag) GetValue() string { + if f.Value != nil { + return f.Value.String() + } + return "" +} + +// Apply populates the flag given the flag set and environment +func (f *Int64SliceFlag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + f.Value = &Int64Slice{} + + for _, s := range strings.Split(val, ",") { + if err := f.Value.Set(strings.TrimSpace(s)); err != nil { + return fmt.Errorf("could not parse %q as int64 slice value for flag %s: %s", val, f.Name, err) + } + } + + f.HasBeenSet = true + } + + for _, name := range f.Names() { + if f.Value == nil { + f.Value = &Int64Slice{} + } + set.Var(f.Value, name, f.Usage) + } + + return nil +} + +// Int64Slice looks up the value of a local Int64SliceFlag, returns +// nil if not found +func (c *Context) Int64Slice(name string) []int64 { + return lookupInt64Slice(name, c.flagSet) +} + +func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*Int64Slice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} diff --git a/vendor/github.com/urfave/cli/v2/flag_int_slice.go b/vendor/github.com/urfave/cli/v2/flag_int_slice.go new file mode 100644 index 000000000..938897842 --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_int_slice.go @@ -0,0 +1,175 @@ +package cli + +import ( + "encoding/json" + "flag" + "fmt" + "strconv" + "strings" +) + +// IntSlice wraps []int to satisfy flag.Value +type IntSlice struct { + slice []int + hasBeenSet bool +} + +// NewIntSlice makes an *IntSlice with default values +func NewIntSlice(defaults ...int) *IntSlice { + return &IntSlice{slice: append([]int{}, defaults...)} +} + +// TODO: Consistently have specific Set function for Int64 and Float64 ? +// SetInt directly adds an integer to the list of values +func (i *IntSlice) SetInt(value int) { + if !i.hasBeenSet { + i.slice = []int{} + i.hasBeenSet = true + } + + i.slice = append(i.slice, value) +} + +// Set parses the value into an integer and appends it to the list of values +func (i *IntSlice) Set(value string) error { + if !i.hasBeenSet { + i.slice = []int{} + i.hasBeenSet = true + } + + if strings.HasPrefix(value, slPfx) { + // Deserializing assumes overwrite + _ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &i.slice) + i.hasBeenSet = true + return nil + } + + tmp, err := strconv.ParseInt(value, 0, 64) + if err != nil { + return err + } + + i.slice = append(i.slice, int(tmp)) + + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (i *IntSlice) String() string { + return fmt.Sprintf("%#v", i.slice) +} + +// Serialize allows IntSlice to fulfill Serializer +func (i *IntSlice) Serialize() string { + jsonBytes, _ := json.Marshal(i.slice) + return fmt.Sprintf("%s%s", slPfx, string(jsonBytes)) +} + +// Value returns the slice of ints set by this flag +func (i *IntSlice) Value() []int { + return i.slice +} + +// Get returns the slice of ints set by this flag +func (i *IntSlice) Get() interface{} { + return *i +} + +// IntSliceFlag is a flag with type *IntSlice +type IntSliceFlag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + Value *IntSlice + DefaultText string + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *IntSliceFlag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *IntSliceFlag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *IntSliceFlag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *IntSliceFlag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *IntSliceFlag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f IntSliceFlag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *IntSliceFlag) GetValue() string { + if f.Value != nil { + return f.Value.String() + } + return "" +} + +// Apply populates the flag given the flag set and environment +func (f *IntSliceFlag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + f.Value = &IntSlice{} + + for _, s := range strings.Split(val, ",") { + if err := f.Value.Set(strings.TrimSpace(s)); err != nil { + return fmt.Errorf("could not parse %q as int slice value for flag %s: %s", val, f.Name, err) + } + } + + f.HasBeenSet = true + } + + for _, name := range f.Names() { + if f.Value == nil { + f.Value = &IntSlice{} + } + set.Var(f.Value, name, f.Usage) + } + + return nil +} + +// IntSlice looks up the value of a local IntSliceFlag, returns +// nil if not found +func (c *Context) IntSlice(name string) []int { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupIntSlice(name, c.flagSet) + } + return nil +} + +func lookupIntSlice(name string, set *flag.FlagSet) []int { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*IntSlice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} diff --git a/vendor/github.com/urfave/cli/v2/flag_path.go b/vendor/github.com/urfave/cli/v2/flag_path.go new file mode 100644 index 000000000..a32285739 --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_path.go @@ -0,0 +1,95 @@ +package cli + +import "flag" + +type PathFlag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + TakesFile bool + Value string + DefaultText string + Destination *string + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *PathFlag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *PathFlag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *PathFlag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *PathFlag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *PathFlag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f *PathFlag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *PathFlag) GetValue() string { + return f.Value +} + +// Apply populates the flag given the flag set and environment +func (f *PathFlag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + f.Value = val + f.HasBeenSet = true + } + + for _, name := range f.Names() { + if f.Destination != nil { + set.StringVar(f.Destination, name, f.Value, f.Usage) + continue + } + set.String(name, f.Value, f.Usage) + } + + return nil +} + +// Path looks up the value of a local PathFlag, returns +// "" if not found +func (c *Context) Path(name string) string { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupPath(name, fs) + } + + return "" +} + +func lookupPath(name string, set *flag.FlagSet) string { + f := set.Lookup(name) + if f != nil { + parsed, err := f.Value.String(), error(nil) + if err != nil { + return "" + } + return parsed + } + return "" +} diff --git a/vendor/github.com/urfave/cli/v2/flag_string.go b/vendor/github.com/urfave/cli/v2/flag_string.go new file mode 100644 index 000000000..bcd82530c --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_string.go @@ -0,0 +1,95 @@ +package cli + +import "flag" + +// StringFlag is a flag with type string +type StringFlag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + TakesFile bool + Value string + DefaultText string + Destination *string + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *StringFlag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *StringFlag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *StringFlag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *StringFlag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *StringFlag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f *StringFlag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *StringFlag) GetValue() string { + return f.Value +} + +// Apply populates the flag given the flag set and environment +func (f *StringFlag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + f.Value = val + f.HasBeenSet = true + } + + for _, name := range f.Names() { + if f.Destination != nil { + set.StringVar(f.Destination, name, f.Value, f.Usage) + continue + } + set.String(name, f.Value, f.Usage) + } + + return nil +} + +// String looks up the value of a local StringFlag, returns +// "" if not found +func (c *Context) String(name string) string { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupString(name, fs) + } + return "" +} + +func lookupString(name string, set *flag.FlagSet) string { + f := set.Lookup(name) + if f != nil { + parsed, err := f.Value.String(), error(nil) + if err != nil { + return "" + } + return parsed + } + return "" +} diff --git a/vendor/github.com/urfave/cli/v2/flag_string_slice.go b/vendor/github.com/urfave/cli/v2/flag_string_slice.go new file mode 100644 index 000000000..a114a495e --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_string_slice.go @@ -0,0 +1,159 @@ +package cli + +import ( + "encoding/json" + "flag" + "fmt" + "strings" +) + +// StringSlice wraps a []string to satisfy flag.Value +type StringSlice struct { + slice []string + hasBeenSet bool +} + +// NewStringSlice creates a *StringSlice with default values +func NewStringSlice(defaults ...string) *StringSlice { + return &StringSlice{slice: append([]string{}, defaults...)} +} + +// Set appends the string value to the list of values +func (s *StringSlice) Set(value string) error { + if !s.hasBeenSet { + s.slice = []string{} + s.hasBeenSet = true + } + + if strings.HasPrefix(value, slPfx) { + // Deserializing assumes overwrite + _ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &s.slice) + s.hasBeenSet = true + return nil + } + + s.slice = append(s.slice, value) + + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (s *StringSlice) String() string { + return fmt.Sprintf("%s", s.slice) +} + +// Serialize allows StringSlice to fulfill Serializer +func (s *StringSlice) Serialize() string { + jsonBytes, _ := json.Marshal(s.slice) + return fmt.Sprintf("%s%s", slPfx, string(jsonBytes)) +} + +// Value returns the slice of strings set by this flag +func (s *StringSlice) Value() []string { + return s.slice +} + +// Get returns the slice of strings set by this flag +func (s *StringSlice) Get() interface{} { + return *s +} + +// StringSliceFlag is a flag with type *StringSlice +type StringSliceFlag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + TakesFile bool + Value *StringSlice + DefaultText string + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *StringSliceFlag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *StringSliceFlag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *StringSliceFlag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *StringSliceFlag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *StringSliceFlag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f *StringSliceFlag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *StringSliceFlag) GetValue() string { + if f.Value != nil { + return f.Value.String() + } + return "" +} + +// Apply populates the flag given the flag set and environment +func (f *StringSliceFlag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + f.Value = &StringSlice{} + + for _, s := range strings.Split(val, ",") { + if err := f.Value.Set(strings.TrimSpace(s)); err != nil { + return fmt.Errorf("could not parse %q as string value for flag %s: %s", val, f.Name, err) + } + } + + f.HasBeenSet = true + } + + for _, name := range f.Names() { + if f.Value == nil { + f.Value = &StringSlice{} + } + set.Var(f.Value, name, f.Usage) + } + + return nil +} + +// StringSlice looks up the value of a local StringSliceFlag, returns +// nil if not found +func (c *Context) StringSlice(name string) []string { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupStringSlice(name, fs) + } + return nil +} + +func lookupStringSlice(name string, set *flag.FlagSet) []string { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*StringSlice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} diff --git a/vendor/github.com/urfave/cli/v2/flag_timestamp.go b/vendor/github.com/urfave/cli/v2/flag_timestamp.go new file mode 100644 index 000000000..d24edcd7f --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_timestamp.go @@ -0,0 +1,152 @@ +package cli + +import ( + "flag" + "fmt" + "time" +) + +// Timestamp wrap to satisfy golang's flag interface. +type Timestamp struct { + timestamp *time.Time + hasBeenSet bool + layout string +} + +// Timestamp constructor +func NewTimestamp(timestamp time.Time) *Timestamp { + return &Timestamp{timestamp: ×tamp} +} + +// Set the timestamp value directly +func (t *Timestamp) SetTimestamp(value time.Time) { + if !t.hasBeenSet { + t.timestamp = &value + t.hasBeenSet = true + } +} + +// Set the timestamp string layout for future parsing +func (t *Timestamp) SetLayout(layout string) { + t.layout = layout +} + +// Parses the string value to timestamp +func (t *Timestamp) Set(value string) error { + timestamp, err := time.Parse(t.layout, value) + if err != nil { + return err + } + + t.timestamp = ×tamp + t.hasBeenSet = true + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (t *Timestamp) String() string { + return fmt.Sprintf("%#v", t.timestamp) +} + +// Value returns the timestamp value stored in the flag +func (t *Timestamp) Value() *time.Time { + return t.timestamp +} + +// Get returns the flag structure +func (t *Timestamp) Get() interface{} { + return *t +} + +// TimestampFlag is a flag with type time +type TimestampFlag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + Layout string + Value *Timestamp + DefaultText string + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *TimestampFlag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *TimestampFlag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *TimestampFlag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *TimestampFlag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *TimestampFlag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f *TimestampFlag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *TimestampFlag) GetValue() string { + if f.Value != nil { + return f.Value.timestamp.String() + } + return "" +} + +// Apply populates the flag given the flag set and environment +func (f *TimestampFlag) Apply(set *flag.FlagSet) error { + if f.Layout == "" { + return fmt.Errorf("timestamp Layout is required") + } + f.Value = &Timestamp{} + f.Value.SetLayout(f.Layout) + + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + if err := f.Value.Set(val); err != nil { + return fmt.Errorf("could not parse %q as timestamp value for flag %s: %s", val, f.Name, err) + } + f.HasBeenSet = true + } + + for _, name := range f.Names() { + set.Var(f.Value, name, f.Usage) + } + return nil +} + +// Timestamp gets the timestamp from a flag name +func (c *Context) Timestamp(name string) *time.Time { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupTimestamp(name, fs) + } + return nil +} + +// Fetches the timestamp value from the local timestampWrap +func lookupTimestamp(name string, set *flag.FlagSet) *time.Time { + f := set.Lookup(name) + if f != nil { + return (f.Value.(*Timestamp)).Value() + } + return nil +} diff --git a/vendor/github.com/urfave/cli/v2/flag_uint.go b/vendor/github.com/urfave/cli/v2/flag_uint.go new file mode 100644 index 000000000..9f592388f --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_uint.go @@ -0,0 +1,105 @@ +package cli + +import ( + "flag" + "fmt" + "strconv" +) + +// UintFlag is a flag with type uint +type UintFlag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + Value uint + DefaultText string + Destination *uint + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *UintFlag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *UintFlag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *UintFlag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *UintFlag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *UintFlag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f *UintFlag) GetUsage() string { + return f.Usage +} + +// Apply populates the flag given the flag set and environment +func (f *UintFlag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + if val != "" { + valInt, err := strconv.ParseUint(val, 0, 64) + if err != nil { + return fmt.Errorf("could not parse %q as uint value for flag %s: %s", val, f.Name, err) + } + + f.Value = uint(valInt) + f.HasBeenSet = true + } + } + + for _, name := range f.Names() { + if f.Destination != nil { + set.UintVar(f.Destination, name, f.Value, f.Usage) + continue + } + set.Uint(name, f.Value, f.Usage) + } + + return nil +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *UintFlag) GetValue() string { + return fmt.Sprintf("%d", f.Value) +} + +// Uint looks up the value of a local UintFlag, returns +// 0 if not found +func (c *Context) Uint(name string) uint { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupUint(name, fs) + } + return 0 +} + +func lookupUint(name string, set *flag.FlagSet) uint { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return uint(parsed) + } + return 0 +} diff --git a/vendor/github.com/urfave/cli/v2/flag_uint64.go b/vendor/github.com/urfave/cli/v2/flag_uint64.go new file mode 100644 index 000000000..5bbd1fa4b --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/flag_uint64.go @@ -0,0 +1,105 @@ +package cli + +import ( + "flag" + "fmt" + "strconv" +) + +// Uint64Flag is a flag with type uint64 +type Uint64Flag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + Value uint64 + DefaultText string + Destination *uint64 + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *Uint64Flag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *Uint64Flag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *Uint64Flag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *Uint64Flag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *Uint64Flag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f *Uint64Flag) GetUsage() string { + return f.Usage +} + +// Apply populates the flag given the flag set and environment +func (f *Uint64Flag) Apply(set *flag.FlagSet) error { + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + if val != "" { + valInt, err := strconv.ParseUint(val, 0, 64) + if err != nil { + return fmt.Errorf("could not parse %q as uint64 value for flag %s: %s", val, f.Name, err) + } + + f.Value = valInt + f.HasBeenSet = true + } + } + + for _, name := range f.Names() { + if f.Destination != nil { + set.Uint64Var(f.Destination, name, f.Value, f.Usage) + continue + } + set.Uint64(name, f.Value, f.Usage) + } + + return nil +} + +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *Uint64Flag) GetValue() string { + return fmt.Sprintf("%d", f.Value) +} + +// Uint64 looks up the value of a local Uint64Flag, returns +// 0 if not found +func (c *Context) Uint64(name string) uint64 { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupUint64(name, fs) + } + return 0 +} + +func lookupUint64(name string, set *flag.FlagSet) uint64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} diff --git a/vendor/github.com/urfave/cli/funcs.go b/vendor/github.com/urfave/cli/v2/funcs.go similarity index 59% rename from vendor/github.com/urfave/cli/funcs.go rename to vendor/github.com/urfave/cli/v2/funcs.go index cba5e6cb0..474c48faf 100644 --- a/vendor/github.com/urfave/cli/funcs.go +++ b/vendor/github.com/urfave/cli/v2/funcs.go @@ -1,6 +1,6 @@ package cli -// BashCompleteFunc is an action to execute when the bash-completion flag is set +// BashCompleteFunc is an action to execute when the shell completion flag is set type BashCompleteFunc func(*Context) // BeforeFunc is an action to execute before any subcommands are run, but after @@ -23,6 +23,22 @@ type CommandNotFoundFunc func(*Context, string) // is displayed and the execution is interrupted. type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error +// ExitErrHandlerFunc is executed if provided in order to handle exitError values +// returned by Actions and Before/After functions. +type ExitErrHandlerFunc func(context *Context, err error) + // FlagStringFunc is used by the help generation to display a flag, which is // expected to be a single line. type FlagStringFunc func(Flag) string + +// FlagNamePrefixFunc is used by the default FlagStringFunc to create prefix +// text for a flag's full name. +type FlagNamePrefixFunc func(fullName []string, placeholder string) string + +// FlagEnvHintFunc is used by the default FlagStringFunc to annotate flag help +// with the environment variable details. +type FlagEnvHintFunc func(envVars []string, str string) string + +// FlagFileHintFunc is used by the default FlagStringFunc to annotate flag help +// with the file path details. +type FlagFileHintFunc func(filePath, str string) string diff --git a/vendor/github.com/urfave/cli/v2/go.mod b/vendor/github.com/urfave/cli/v2/go.mod new file mode 100644 index 000000000..c38d41c14 --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/go.mod @@ -0,0 +1,9 @@ +module github.com/urfave/cli/v2 + +go 1.11 + +require ( + github.com/BurntSushi/toml v0.3.1 + github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d + gopkg.in/yaml.v2 v2.2.2 +) diff --git a/vendor/github.com/urfave/cli/v2/go.sum b/vendor/github.com/urfave/cli/v2/go.sum new file mode 100644 index 000000000..ef121ff5d --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/go.sum @@ -0,0 +1,14 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +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/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +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.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/urfave/cli/help.go b/vendor/github.com/urfave/cli/v2/help.go similarity index 50% rename from vendor/github.com/urfave/cli/help.go rename to vendor/github.com/urfave/cli/v2/help.go index 57ec98d58..c1e974a48 100644 --- a/vendor/github.com/urfave/cli/help.go +++ b/vendor/github.com/urfave/cli/v2/help.go @@ -7,78 +7,10 @@ import ( "strings" "text/tabwriter" "text/template" + "unicode/utf8" ) -// AppHelpTemplate is the text template for the Default help topic. -// cli.go uses text/template to render templates. You can -// render custom help text by setting this variable. -var AppHelpTemplate = `NAME: - {{.Name}}{{if .Usage}} - {{.Usage}}{{end}} - -USAGE: - {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} - -VERSION: - {{.Version}}{{end}}{{end}}{{if .Description}} - -DESCRIPTION: - {{.Description}}{{end}}{{if len .Authors}} - -AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: - {{range $index, $author := .Authors}}{{if $index}} - {{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}} - -COMMANDS:{{range .VisibleCategories}}{{if .Name}} - {{.Name}}:{{end}}{{range .VisibleCommands}} - {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}} - -GLOBAL OPTIONS: - {{range $index, $option := .VisibleFlags}}{{if $index}} - {{end}}{{$option}}{{end}}{{end}}{{if .Copyright}} - -COPYRIGHT: - {{.Copyright}}{{end}} -` - -// CommandHelpTemplate is the text template for the command help topic. -// cli.go uses text/template to render templates. You can -// render custom help text by setting this variable. -var CommandHelpTemplate = `NAME: - {{.HelpName}} - {{.Usage}} - -USAGE: - {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}} - -CATEGORY: - {{.Category}}{{end}}{{if .Description}} - -DESCRIPTION: - {{.Description}}{{end}}{{if .VisibleFlags}} - -OPTIONS: - {{range .VisibleFlags}}{{.}} - {{end}}{{end}} -` - -// SubcommandHelpTemplate is the text template for the subcommand help topic. -// cli.go uses text/template to render templates. You can -// render custom help text by setting this variable. -var SubcommandHelpTemplate = `NAME: - {{.HelpName}} - {{if .Description}}{{.Description}}{{else}}{{.Usage}}{{end}} - -USAGE: - {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}} - -COMMANDS:{{range .VisibleCategories}}{{if .Name}} - {{.Name}}:{{end}}{{range .VisibleCommands}} - {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}} -{{end}}{{if .VisibleFlags}} -OPTIONS: - {{range .VisibleFlags}}{{.}} - {{end}}{{end}} -` - -var helpCommand = Command{ +var helpCommand = &Command{ Name: "help", Aliases: []string{"h"}, Usage: "Shows a list of commands or help for one command", @@ -89,12 +21,12 @@ var helpCommand = Command{ return ShowCommandHelp(c, args.First()) } - ShowAppHelp(c) + _ = ShowAppHelp(c) return nil }, } -var helpSubcommand = Command{ +var helpSubcommand = &Command{ Name: "help", Aliases: []string{"h"}, Usage: "Shows a list of commands or help for one command", @@ -115,13 +47,18 @@ type helpPrinter func(w io.Writer, templ string, data interface{}) // Prints help for the App or Command with custom template function. type helpPrinterCustom func(w io.Writer, templ string, data interface{}, customFunc map[string]interface{}) -// HelpPrinter is a function that writes the help output. If not set a default -// is used. The function signature is: -// func(w io.Writer, templ string, data interface{}) +// HelpPrinter is a function that writes the help output. If not set explicitly, +// this calls HelpPrinterCustom using only the default template functions. +// +// If custom logic for printing help is required, this function can be +// overridden. If the ExtraInfo field is defined on an App, this function +// should not be modified, as HelpPrinterCustom will be used directly in order +// to capture the extra information. var HelpPrinter helpPrinter = printHelp -// HelpPrinterCustom is same as HelpPrinter but -// takes a custom function for template function map. +// HelpPrinterCustom is a function that writes the help output. It is used as +// the default implementation of HelpPrinter, and may be called directly if +// the ExtraInfo field is set on an App. var HelpPrinterCustom helpPrinterCustom = printHelpCustom // VersionPrinter prints the version for the App @@ -129,43 +66,122 @@ var VersionPrinter = printVersion // ShowAppHelpAndExit - Prints the list of subcommands for the app and exits with exit code. func ShowAppHelpAndExit(c *Context, exitCode int) { - ShowAppHelp(c) + _ = ShowAppHelp(c) os.Exit(exitCode) } // ShowAppHelp is an action that displays the help. -func ShowAppHelp(c *Context) (err error) { - if c.App.CustomAppHelpTemplate == "" { - HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) - return +func ShowAppHelp(c *Context) error { + template := c.App.CustomAppHelpTemplate + if template == "" { + template = AppHelpTemplate } + + if c.App.ExtraInfo == nil { + HelpPrinter(c.App.Writer, template, c.App) + return nil + } + customAppData := func() map[string]interface{} { - if c.App.ExtraInfo == nil { - return nil - } return map[string]interface{}{ "ExtraInfo": c.App.ExtraInfo, } } - HelpPrinterCustom(c.App.Writer, c.App.CustomAppHelpTemplate, c.App, customAppData()) + HelpPrinterCustom(c.App.Writer, template, c.App, customAppData()) + return nil } // DefaultAppComplete prints the list of subcommands as the default app completion method func DefaultAppComplete(c *Context) { - for _, command := range c.App.Commands { + DefaultCompleteWithFlags(nil)(c) +} + +func printCommandSuggestions(commands []*Command, writer io.Writer) { + for _, command := range commands { if command.Hidden { continue } - for _, name := range command.Names() { - fmt.Fprintln(c.App.Writer, name) + if os.Getenv("_CLI_ZSH_AUTOCOMPLETE_HACK") == "1" { + for _, name := range command.Names() { + _, _ = fmt.Fprintf(writer, "%s:%s\n", name, command.Usage) + } + } else { + for _, name := range command.Names() { + _, _ = fmt.Fprintf(writer, "%s\n", name) + } + } + } +} + +func cliArgContains(flagName string) bool { + for _, name := range strings.Split(flagName, ",") { + name = strings.TrimSpace(name) + count := utf8.RuneCountInString(name) + if count > 2 { + count = 2 + } + flag := fmt.Sprintf("%s%s", strings.Repeat("-", count), name) + for _, a := range os.Args { + if a == flag { + return true + } + } + } + return false +} + +func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) { + cur := strings.TrimPrefix(lastArg, "-") + cur = strings.TrimPrefix(cur, "-") + for _, flag := range flags { + if bflag, ok := flag.(*BoolFlag); ok && bflag.Hidden { + continue + } + for _, name := range flag.Names() { + name = strings.TrimSpace(name) + // this will get total count utf8 letters in flag name + count := utf8.RuneCountInString(name) + if count > 2 { + count = 2 // resuse this count to generate single - or -- in flag completion + } + // if flag name has more than one utf8 letter and last argument in cli has -- prefix then + // skip flag completion for short flags example -v or -x + if strings.HasPrefix(lastArg, "--") && count == 1 { + continue + } + // match if last argument matches this flag and it is not repeated + if strings.HasPrefix(name, cur) && cur != name && !cliArgContains(name) { + flagCompletion := fmt.Sprintf("%s%s", strings.Repeat("-", count), name) + _, _ = fmt.Fprintln(writer, flagCompletion) + } + } + } +} + +func DefaultCompleteWithFlags(cmd *Command) func(c *Context) { + return func(c *Context) { + if len(os.Args) > 2 { + lastArg := os.Args[len(os.Args)-2] + if strings.HasPrefix(lastArg, "-") { + printFlagSuggestions(lastArg, c.App.Flags, c.App.Writer) + if cmd != nil { + printFlagSuggestions(lastArg, cmd.Flags, c.App.Writer) + } + return + } + } + if cmd != nil { + printCommandSuggestions(cmd.Subcommands, c.App.Writer) + } else { + printCommandSuggestions(c.App.Commands, c.App.Writer) } } } // ShowCommandHelpAndExit - exits with code after showing help func ShowCommandHelpAndExit(c *Context, command string, code int) { - ShowCommandHelp(c, command) + _ = ShowCommandHelp(c, command) os.Exit(code) } @@ -179,17 +195,19 @@ func ShowCommandHelp(ctx *Context, command string) error { for _, c := range ctx.App.Commands { if c.HasName(command) { - if c.CustomHelpTemplate != "" { - HelpPrinterCustom(ctx.App.Writer, c.CustomHelpTemplate, c, nil) - } else { - HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) + templ := c.CustomHelpTemplate + if templ == "" { + templ = CommandHelpTemplate } + + HelpPrinter(ctx.App.Writer, templ, c) + return nil } } if ctx.App.CommandNotFound == nil { - return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3) + return Exit(fmt.Sprintf("No help topic for '%v'", command), 3) } ctx.App.CommandNotFound(ctx, command) @@ -198,7 +216,15 @@ func ShowCommandHelp(ctx *Context, command string) error { // ShowSubcommandHelp prints help for the given subcommand func ShowSubcommandHelp(c *Context) error { - return ShowCommandHelp(c, c.Command.Name) + if c == nil { + return nil + } + + if c.Command != nil { + return ShowCommandHelp(c, c.Command.Name) + } + + return ShowCommandHelp(c, "") } // ShowVersion prints the version number of the App @@ -207,7 +233,7 @@ func ShowVersion(c *Context) { } func printVersion(c *Context) { - fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version) + _, _ = fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version) } // ShowCompletions prints the lists of commands within a given context @@ -221,66 +247,70 @@ func ShowCompletions(c *Context) { // ShowCommandCompletions prints the custom completions for a given command func ShowCommandCompletions(ctx *Context, command string) { c := ctx.App.Command(command) - if c != nil && c.BashComplete != nil { - c.BashComplete(ctx) + if c != nil { + if c.BashComplete != nil { + c.BashComplete(ctx) + } else { + DefaultCompleteWithFlags(c)(ctx) + } } + } -func printHelpCustom(out io.Writer, templ string, data interface{}, customFunc map[string]interface{}) { +// printHelpCustom is the default implementation of HelpPrinterCustom. +// +// The customFuncs map will be combined with a default template.FuncMap to +// allow using arbitrary functions in template rendering. +func printHelpCustom(out io.Writer, templ string, data interface{}, customFuncs map[string]interface{}) { funcMap := template.FuncMap{ "join": strings.Join, } - if customFunc != nil { - for key, value := range customFunc { - funcMap[key] = value - } + for key, value := range customFuncs { + funcMap[key] = value } w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) + err := t.Execute(w, data) if err != nil { // If the writer is closed, t.Execute will fail, and there's nothing // we can do to recover. if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" { - fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err) + _, _ = fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err) } return } - w.Flush() + _ = w.Flush() } func printHelp(out io.Writer, templ string, data interface{}) { - printHelpCustom(out, templ, data, nil) + HelpPrinterCustom(out, templ, data, nil) } func checkVersion(c *Context) bool { found := false - if VersionFlag.GetName() != "" { - eachName(VersionFlag.GetName(), func(name string) { - if c.GlobalBool(name) || c.Bool(name) { - found = true - } - }) + for _, name := range VersionFlag.Names() { + if c.Bool(name) { + found = true + } } return found } func checkHelp(c *Context) bool { found := false - if HelpFlag.GetName() != "" { - eachName(HelpFlag.GetName(), func(name string) { - if c.GlobalBool(name) || c.Bool(name) { - found = true - } - }) + for _, name := range HelpFlag.Names() { + if c.Bool(name) { + found = true + } } return found } func checkCommandHelp(c *Context, name string) bool { if c.Bool("h") || c.Bool("help") { - ShowCommandHelp(c, name) + _ = ShowCommandHelp(c, name) return true } @@ -289,7 +319,7 @@ func checkCommandHelp(c *Context, name string) bool { func checkSubcommandHelp(c *Context) bool { if c.Bool("h") || c.Bool("help") { - ShowSubcommandHelp(c) + _ = ShowSubcommandHelp(c) return true } @@ -304,7 +334,7 @@ func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) { pos := len(arguments) - 1 lastArg := arguments[pos] - if lastArg != "--"+BashCompletionFlag.GetName() { + if lastArg != "--generate-bash-completion" { return false, arguments } diff --git a/vendor/github.com/urfave/cli/v2/parse.go b/vendor/github.com/urfave/cli/v2/parse.go new file mode 100644 index 000000000..7df17296a --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/parse.go @@ -0,0 +1,94 @@ +package cli + +import ( + "flag" + "strings" +) + +type iterativeParser interface { + newFlagSet() (*flag.FlagSet, error) + useShortOptionHandling() bool +} + +// To enable short-option handling (e.g., "-it" vs "-i -t") we have to +// iteratively catch parsing errors. This way we achieve LR parsing without +// transforming any arguments. Otherwise, there is no way we can discriminate +// combined short options from common arguments that should be left untouched. +// Pass `shellComplete` to continue parsing options on failure during shell +// completion when, the user-supplied options may be incomplete. +func parseIter(set *flag.FlagSet, ip iterativeParser, args []string, shellComplete bool) error { + for { + err := set.Parse(args) + if !ip.useShortOptionHandling() || err == nil { + if shellComplete { + return nil + } + return err + } + + errStr := err.Error() + trimmed := strings.TrimPrefix(errStr, "flag provided but not defined: -") + if errStr == trimmed { + return err + } + + // regenerate the initial args with the split short opts + argsWereSplit := false + for i, arg := range args { + // skip args that are not part of the error message + if name := strings.TrimLeft(arg, "-"); name != trimmed { + continue + } + + // if we can't split, the error was accurate + shortOpts := splitShortOptions(set, arg) + if len(shortOpts) == 1 { + return err + } + + // swap current argument with the split version + args = append(args[:i], append(shortOpts, args[i+1:]...)...) + argsWereSplit = true + break + } + + // This should be an impossible to reach code path, but in case the arg + // splitting failed to happen, this will prevent infinite loops + if !argsWereSplit { + return err + } + + // Since custom parsing failed, replace the flag set before retrying + newSet, err := ip.newFlagSet() + if err != nil { + return err + } + *set = *newSet + } +} + +func splitShortOptions(set *flag.FlagSet, arg string) []string { + shortFlagsExist := func(s string) bool { + for _, c := range s[1:] { + if f := set.Lookup(string(c)); f == nil { + return false + } + } + return true + } + + if !isSplittable(arg) || !shortFlagsExist(arg) { + return []string{arg} + } + + separated := make([]string, 0, len(arg)-1) + for _, flagChar := range arg[1:] { + separated = append(separated, "-"+string(flagChar)) + } + + return separated +} + +func isSplittable(flagArg string) bool { + return strings.HasPrefix(flagArg, "-") && !strings.HasPrefix(flagArg, "--") && len(flagArg) > 2 +} diff --git a/vendor/github.com/urfave/cli/v2/sort.go b/vendor/github.com/urfave/cli/v2/sort.go new file mode 100644 index 000000000..23d1c2f77 --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/sort.go @@ -0,0 +1,29 @@ +package cli + +import "unicode" + +// lexicographicLess compares strings alphabetically considering case. +func lexicographicLess(i, j string) bool { + iRunes := []rune(i) + jRunes := []rune(j) + + lenShared := len(iRunes) + if lenShared > len(jRunes) { + lenShared = len(jRunes) + } + + for index := 0; index < lenShared; index++ { + ir := iRunes[index] + jr := jRunes[index] + + if lir, ljr := unicode.ToLower(ir), unicode.ToLower(jr); lir != ljr { + return lir < ljr + } + + if ir != jr { + return ir < jr + } + } + + return i < j +} diff --git a/vendor/github.com/urfave/cli/v2/template.go b/vendor/github.com/urfave/cli/v2/template.go new file mode 100644 index 000000000..1cc4bd624 --- /dev/null +++ b/vendor/github.com/urfave/cli/v2/template.go @@ -0,0 +1,119 @@ +package cli + +// AppHelpTemplate is the text template for the Default help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var AppHelpTemplate = `NAME: + {{.Name}}{{if .Usage}} - {{.Usage}}{{end}} + +USAGE: + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} + +VERSION: + {{.Version}}{{end}}{{end}}{{if .Description}} + +DESCRIPTION: + {{.Description}}{{end}}{{if len .Authors}} + +AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: + {{range $index, $author := .Authors}}{{if $index}} + {{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}} + +COMMANDS:{{range .VisibleCategories}}{{if .Name}} + {{.Name}}:{{range .VisibleCommands}} + {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}} + {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlags}} + +GLOBAL OPTIONS: + {{range $index, $option := .VisibleFlags}}{{if $index}} + {{end}}{{$option}}{{end}}{{end}}{{if .Copyright}} + +COPYRIGHT: + {{.Copyright}}{{end}} +` + +// CommandHelpTemplate is the text template for the command help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var CommandHelpTemplate = `NAME: + {{.HelpName}} - {{.Usage}} + +USAGE: + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}} + +CATEGORY: + {{.Category}}{{end}}{{if .Description}} + +DESCRIPTION: + {{.Description}}{{end}}{{if .VisibleFlags}} + +OPTIONS: + {{range .VisibleFlags}}{{.}} + {{end}}{{end}} +` + +// SubcommandHelpTemplate is the text template for the subcommand help topic. +// cli.go uses text/template to render templates. You can +// render custom help text by setting this variable. +var SubcommandHelpTemplate = `NAME: + {{.HelpName}} - {{if .Description}}{{.Description}}{{else}}{{.Usage}}{{end}} + +USAGE: + {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}} + +COMMANDS:{{range .VisibleCategories}}{{if .Name}} + {{.Name}}:{{range .VisibleCommands}} + {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}} + {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}} + +OPTIONS: + {{range .VisibleFlags}}{{.}} + {{end}}{{end}} +` + +var MarkdownDocTemplate = `% {{ .App.Name }}(8){{ if .App.Description }} {{ .App.Description }}{{ end }} +{{ range $a := .App.Authors }} +% {{ $a }}{{ end }} + +# NAME + +{{ .App.Name }}{{ if .App.Usage }} - {{ .App.Usage }}{{ end }} + +# SYNOPSIS + +{{ .App.Name }} +{{ if .SynopsisArgs }} +` + "```" + ` +{{ range $v := .SynopsisArgs }}{{ $v }}{{ end }}` + "```" + ` +{{ end }}{{ if .App.UsageText }} +# DESCRIPTION + +{{ .App.UsageText }} +{{ end }} +**Usage**: + +` + "```" + ` +{{ .App.Name }} [GLOBAL OPTIONS] command [COMMAND OPTIONS] [ARGUMENTS...] +` + "```" + ` +{{ if .GlobalArgs }} +# GLOBAL OPTIONS +{{ range $v := .GlobalArgs }} +{{ $v }}{{ end }} +{{ end }}{{ if .Commands }} +# COMMANDS +{{ range $v := .Commands }} +{{ $v }}{{ end }}{{ end }}` + +var FishCompletionTemplate = `# {{ .App.Name }} fish shell completion + +function __fish_{{ .App.Name }}_no_subcommand --description 'Test if there has been any subcommand yet' + for i in (commandline -opc) + if contains -- $i{{ range $v := .AllCommands }} {{ $v }}{{ end }} + return 1 + end + end + return 0 +end + +{{ range $v := .Completions }}{{ $v }} +{{ end }}` diff --git a/vendor/github.com/vektah/gqlparser/.gitignore b/vendor/github.com/vektah/gqlparser/v2/.gitignore similarity index 100% rename from vendor/github.com/vektah/gqlparser/.gitignore rename to vendor/github.com/vektah/gqlparser/v2/.gitignore diff --git a/vendor/github.com/vektah/gqlparser/LICENSE b/vendor/github.com/vektah/gqlparser/v2/LICENSE similarity index 100% rename from vendor/github.com/vektah/gqlparser/LICENSE rename to vendor/github.com/vektah/gqlparser/v2/LICENSE diff --git a/vendor/github.com/vektah/gqlparser/ast/argmap.go b/vendor/github.com/vektah/gqlparser/v2/ast/argmap.go similarity index 100% rename from vendor/github.com/vektah/gqlparser/ast/argmap.go rename to vendor/github.com/vektah/gqlparser/v2/ast/argmap.go diff --git a/vendor/github.com/vektah/gqlparser/ast/collections.go b/vendor/github.com/vektah/gqlparser/v2/ast/collections.go similarity index 93% rename from vendor/github.com/vektah/gqlparser/ast/collections.go rename to vendor/github.com/vektah/gqlparser/v2/ast/collections.go index 6bf672976..94b800ee2 100644 --- a/vendor/github.com/vektah/gqlparser/ast/collections.go +++ b/vendor/github.com/vektah/gqlparser/v2/ast/collections.go @@ -33,6 +33,16 @@ func (l DirectiveList) ForName(name string) *Directive { return nil } +func (l DirectiveList) ForNames(name string) []*Directive { + resp := []*Directive{} + for _, it := range l { + if it.Name == name { + resp = append(resp, it) + } + } + return resp +} + type OperationList []*OperationDefinition func (l OperationList) ForName(name string) *OperationDefinition { diff --git a/vendor/github.com/vektah/gqlparser/ast/definition.go b/vendor/github.com/vektah/gqlparser/v2/ast/definition.go similarity index 100% rename from vendor/github.com/vektah/gqlparser/ast/definition.go rename to vendor/github.com/vektah/gqlparser/v2/ast/definition.go diff --git a/vendor/github.com/vektah/gqlparser/ast/directive.go b/vendor/github.com/vektah/gqlparser/v2/ast/directive.go similarity index 100% rename from vendor/github.com/vektah/gqlparser/ast/directive.go rename to vendor/github.com/vektah/gqlparser/v2/ast/directive.go diff --git a/vendor/github.com/vektah/gqlparser/ast/document.go b/vendor/github.com/vektah/gqlparser/v2/ast/document.go similarity index 100% rename from vendor/github.com/vektah/gqlparser/ast/document.go rename to vendor/github.com/vektah/gqlparser/v2/ast/document.go diff --git a/vendor/github.com/vektah/gqlparser/ast/dumper.go b/vendor/github.com/vektah/gqlparser/v2/ast/dumper.go similarity index 100% rename from vendor/github.com/vektah/gqlparser/ast/dumper.go rename to vendor/github.com/vektah/gqlparser/v2/ast/dumper.go diff --git a/vendor/github.com/vektah/gqlparser/ast/fragment.go b/vendor/github.com/vektah/gqlparser/v2/ast/fragment.go similarity index 100% rename from vendor/github.com/vektah/gqlparser/ast/fragment.go rename to vendor/github.com/vektah/gqlparser/v2/ast/fragment.go diff --git a/vendor/github.com/vektah/gqlparser/ast/operation.go b/vendor/github.com/vektah/gqlparser/v2/ast/operation.go similarity index 100% rename from vendor/github.com/vektah/gqlparser/ast/operation.go rename to vendor/github.com/vektah/gqlparser/v2/ast/operation.go diff --git a/vendor/github.com/vektah/gqlparser/v2/ast/path.go b/vendor/github.com/vektah/gqlparser/v2/ast/path.go new file mode 100644 index 000000000..9af168438 --- /dev/null +++ b/vendor/github.com/vektah/gqlparser/v2/ast/path.go @@ -0,0 +1,67 @@ +package ast + +import ( + "bytes" + "encoding/json" + "fmt" +) + +var _ json.Unmarshaler = (*Path)(nil) + +type Path []PathElement + +type PathElement interface { + isPathElement() +} + +var _ PathElement = PathIndex(0) +var _ PathElement = PathName("") + +func (path Path) String() string { + var str bytes.Buffer + for i, v := range path { + switch v := v.(type) { + case PathIndex: + str.WriteString(fmt.Sprintf("[%d]", v)) + case PathName: + if i != 0 { + str.WriteByte('.') + } + str.WriteString(string(v)) + default: + panic(fmt.Sprintf("unknown type: %T", v)) + } + } + return str.String() +} + +func (path *Path) UnmarshalJSON(b []byte) error { + var vs []interface{} + err := json.Unmarshal(b, &vs) + if err != nil { + return err + } + + *path = make([]PathElement, 0, len(vs)) + for _, v := range vs { + switch v := v.(type) { + case string: + *path = append(*path, PathName(v)) + case int: + *path = append(*path, PathIndex(v)) + case float64: + *path = append(*path, PathIndex(int(v))) + default: + return fmt.Errorf("unknown path element type: %T", v) + } + } + return nil +} + +type PathIndex int + +func (_ PathIndex) isPathElement() {} + +type PathName string + +func (_ PathName) isPathElement() {} diff --git a/vendor/github.com/vektah/gqlparser/ast/selection.go b/vendor/github.com/vektah/gqlparser/v2/ast/selection.go similarity index 100% rename from vendor/github.com/vektah/gqlparser/ast/selection.go rename to vendor/github.com/vektah/gqlparser/v2/ast/selection.go diff --git a/vendor/github.com/vektah/gqlparser/ast/source.go b/vendor/github.com/vektah/gqlparser/v2/ast/source.go similarity index 94% rename from vendor/github.com/vektah/gqlparser/ast/source.go rename to vendor/github.com/vektah/gqlparser/v2/ast/source.go index 08c66689a..2949f83f7 100644 --- a/vendor/github.com/vektah/gqlparser/ast/source.go +++ b/vendor/github.com/vektah/gqlparser/v2/ast/source.go @@ -3,13 +3,13 @@ package ast // Source covers a single *.graphql file type Source struct { // Name is the filename of the source - Name string + Name string // Input is the actual contents of the source file - Input string + Input string // BuiltIn indicate whether the source is a part of the specification BuiltIn bool } - + type Position struct { Start int // The starting position, in runes, of this token in the input. End int // The end position, in runes, of this token in the input. diff --git a/vendor/github.com/vektah/gqlparser/ast/type.go b/vendor/github.com/vektah/gqlparser/v2/ast/type.go similarity index 100% rename from vendor/github.com/vektah/gqlparser/ast/type.go rename to vendor/github.com/vektah/gqlparser/v2/ast/type.go diff --git a/vendor/github.com/vektah/gqlparser/ast/value.go b/vendor/github.com/vektah/gqlparser/v2/ast/value.go similarity index 100% rename from vendor/github.com/vektah/gqlparser/ast/value.go rename to vendor/github.com/vektah/gqlparser/v2/ast/value.go diff --git a/vendor/github.com/vektah/gqlparser/v2/formatter/formatter.go b/vendor/github.com/vektah/gqlparser/v2/formatter/formatter.go new file mode 100644 index 000000000..194911a1e --- /dev/null +++ b/vendor/github.com/vektah/gqlparser/v2/formatter/formatter.go @@ -0,0 +1,605 @@ +package formatter + +import ( + "fmt" + "io" + "sort" + "strings" + + "github.com/vektah/gqlparser/v2/ast" +) + +type Formatter interface { + FormatSchema(schema *ast.Schema) + FormatSchemaDocument(doc *ast.SchemaDocument) + FormatQueryDocument(doc *ast.QueryDocument) +} + +func NewFormatter(w io.Writer) Formatter { + return &formatter{writer: w} +} + +type formatter struct { + writer io.Writer + + indent int + emitBuiltin bool + + padNext bool + lineHead bool +} + +func (f *formatter) writeString(s string) { + _, _ = f.writer.Write([]byte(s)) +} + +func (f *formatter) writeIndent() *formatter { + if f.lineHead { + f.writeString(strings.Repeat("\t", f.indent)) + } + f.lineHead = false + f.padNext = false + + return f +} + +func (f *formatter) WriteNewline() *formatter { + f.writeString("\n") + f.lineHead = true + f.padNext = false + + return f +} + +func (f *formatter) WriteWord(word string) *formatter { + if f.lineHead { + f.writeIndent() + } + if f.padNext { + f.writeString(" ") + } + f.writeString(strings.TrimSpace(word)) + f.padNext = true + + return f +} + +func (f *formatter) WriteString(s string) *formatter { + if f.lineHead { + f.writeIndent() + } + if f.padNext { + f.writeString(" ") + } + f.writeString(s) + f.padNext = false + + return f +} + +func (f *formatter) WriteDescription(s string) *formatter { + if s == "" { + return f + } + + f.WriteString(`"""`).WriteNewline() + + ss := strings.Split(s, "\n") + for _, s := range ss { + f.WriteString(s).WriteNewline() + } + + f.WriteString(`"""`).WriteNewline() + + return f +} + +func (f *formatter) IncrementIndent() { + f.indent++ +} + +func (f *formatter) DecrementIndent() { + f.indent-- +} + +func (f *formatter) NoPadding() *formatter { + f.padNext = false + + return f +} + +func (f *formatter) NeedPadding() *formatter { + f.padNext = true + + return f +} + +func (f *formatter) FormatSchema(schema *ast.Schema) { + if schema == nil { + return + } + + var inSchema bool + startSchema := func() { + if !inSchema { + inSchema = true + + f.WriteWord("schema").WriteString("{").WriteNewline() + f.IncrementIndent() + } + } + if schema.Query != nil && schema.Query.Name != "Query" { + startSchema() + f.WriteWord("query").NoPadding().WriteString(":").NeedPadding() + f.WriteWord(schema.Query.Name).WriteNewline() + } + if schema.Mutation != nil && schema.Mutation.Name != "Mutation" { + startSchema() + f.WriteWord("mutation").NoPadding().WriteString(":").NeedPadding() + f.WriteWord(schema.Mutation.Name).WriteNewline() + } + if schema.Subscription != nil && schema.Subscription.Name != "Subscription" { + startSchema() + f.WriteWord("subscription").NoPadding().WriteString(":").NeedPadding() + f.WriteWord(schema.Subscription.Name).WriteNewline() + } + if inSchema { + f.DecrementIndent() + f.WriteString("}").WriteNewline() + } + + directiveNames := make([]string, 0, len(schema.Directives)) + for name := range schema.Directives { + directiveNames = append(directiveNames, name) + } + sort.Strings(directiveNames) + for _, name := range directiveNames { + f.FormatDirectiveDefinition(schema.Directives[name]) + } + + typeNames := make([]string, 0, len(schema.Types)) + for name := range schema.Types { + typeNames = append(typeNames, name) + } + sort.Strings(typeNames) + for _, name := range typeNames { + f.FormatDefinition(schema.Types[name], false) + } +} + +func (f *formatter) FormatSchemaDocument(doc *ast.SchemaDocument) { + // TODO emit by position based order + + if doc == nil { + return + } + + f.FormatSchemaDefinitionList(doc.Schema, false) + f.FormatSchemaDefinitionList(doc.SchemaExtension, true) + + f.FormatDirectiveDefinitionList(doc.Directives) + + f.FormatDefinitionList(doc.Definitions, false) + f.FormatDefinitionList(doc.Extensions, true) +} + +func (f *formatter) FormatQueryDocument(doc *ast.QueryDocument) { + // TODO emit by position based order + + if doc == nil { + return + } + + f.FormatOperationList(doc.Operations) + f.FormatFragmentDefinitionList(doc.Fragments) +} + +func (f *formatter) FormatSchemaDefinitionList(lists ast.SchemaDefinitionList, extension bool) { + if len(lists) == 0 { + return + } + + if extension { + f.WriteWord("extend") + } + f.WriteWord("schema").WriteString("{").WriteNewline() + f.IncrementIndent() + + for _, def := range lists { + f.FormatSchemaDefinition(def) + } + + f.DecrementIndent() + f.WriteString("}").WriteNewline() +} + +func (f *formatter) FormatSchemaDefinition(def *ast.SchemaDefinition) { + f.WriteDescription(def.Description) + + f.FormatDirectiveList(def.Directives) + + f.FormatOperationTypeDefinitionList(def.OperationTypes) +} + +func (f *formatter) FormatOperationTypeDefinitionList(lists ast.OperationTypeDefinitionList) { + for _, def := range lists { + f.FormatOperationTypeDefinition(def) + } +} + +func (f *formatter) FormatOperationTypeDefinition(def *ast.OperationTypeDefinition) { + f.WriteWord(string(def.Operation)).NoPadding().WriteString(":").NeedPadding() + f.WriteWord(def.Type) + f.WriteNewline() +} + +func (f *formatter) FormatFieldList(fieldList ast.FieldList) { + if len(fieldList) == 0 { + return + } + + f.WriteString("{").WriteNewline() + f.IncrementIndent() + + for _, field := range fieldList { + f.FormatFieldDefinition(field) + } + + f.DecrementIndent() + f.WriteString("}") +} + +func (f *formatter) FormatFieldDefinition(field *ast.FieldDefinition) { + if !f.emitBuiltin && strings.HasPrefix(field.Name, "__") { + return + } + + f.WriteDescription(field.Description) + + f.WriteWord(field.Name).NoPadding() + f.FormatArgumentDefinitionList(field.Arguments) + f.NoPadding().WriteString(":").NeedPadding() + f.FormatType(field.Type) + + if field.DefaultValue != nil { + f.WriteWord("=") + f.FormatValue(field.DefaultValue) + } + + f.FormatDirectiveList(field.Directives) + + f.WriteNewline() +} + +func (f *formatter) FormatArgumentDefinitionList(lists ast.ArgumentDefinitionList) { + if len(lists) == 0 { + return + } + + f.WriteString("(") + for idx, arg := range lists { + f.FormatArgumentDefinition(arg) + + if idx != len(lists)-1 { + f.NoPadding().WriteWord(",") + } + } + f.NoPadding().WriteString(")").NeedPadding() +} + +func (f *formatter) FormatArgumentDefinition(def *ast.ArgumentDefinition) { + f.WriteDescription(def.Description) + + f.WriteWord(def.Name).NoPadding().WriteString(":").NeedPadding() + f.FormatType(def.Type) + + if def.DefaultValue != nil { + f.WriteWord("=") + f.FormatValue(def.DefaultValue) + } +} + +func (f *formatter) FormatDirectiveLocation(location ast.DirectiveLocation) { + f.WriteWord(string(location)) +} + +func (f *formatter) FormatDirectiveDefinitionList(lists ast.DirectiveDefinitionList) { + if len(lists) == 0 { + return + } + + for _, dec := range lists { + f.FormatDirectiveDefinition(dec) + } +} + +func (f *formatter) FormatDirectiveDefinition(def *ast.DirectiveDefinition) { + if !f.emitBuiltin { + if def.Position.Src.BuiltIn { + return + } + } + + f.WriteDescription(def.Description) + f.WriteWord("directive").WriteString("@").WriteWord(def.Name) + + if len(def.Arguments) != 0 { + f.NoPadding() + f.FormatArgumentDefinitionList(def.Arguments) + } + + if len(def.Locations) != 0 { + f.WriteWord("on") + + for idx, dirLoc := range def.Locations { + f.FormatDirectiveLocation(dirLoc) + + if idx != len(def.Locations)-1 { + f.WriteWord("|") + } + } + } + + f.WriteNewline() +} + +func (f *formatter) FormatDefinitionList(lists ast.DefinitionList, extend bool) { + if len(lists) == 0 { + return + } + + for _, dec := range lists { + f.FormatDefinition(dec, extend) + } +} + +func (f *formatter) FormatDefinition(def *ast.Definition, extend bool) { + if !f.emitBuiltin && def.BuiltIn { + return + } + + f.WriteDescription(def.Description) + + if extend { + f.WriteWord("extend") + } + + switch def.Kind { + case ast.Scalar: + f.WriteWord("scalar").WriteWord(def.Name) + + case ast.Object: + f.WriteWord("type").WriteWord(def.Name) + + case ast.Interface: + f.WriteWord("interface").WriteWord(def.Name) + + case ast.Union: + f.WriteWord("union").WriteWord(def.Name) + + case ast.Enum: + f.WriteWord("enum").WriteWord(def.Name) + + case ast.InputObject: + f.WriteWord("input").WriteWord(def.Name) + } + + if len(def.Interfaces) != 0 { + f.WriteWord("implements").WriteWord(strings.Join(def.Interfaces, " & ")) + } + + f.FormatDirectiveList(def.Directives) + + if len(def.Types) != 0 { + f.WriteWord("=").WriteWord(strings.Join(def.Types, " | ")) + } + + f.FormatFieldList(def.Fields) + + f.FormatEnumValueList(def.EnumValues) + + f.WriteNewline() +} + +func (f *formatter) FormatEnumValueList(lists ast.EnumValueList) { + if len(lists) == 0 { + return + } + + f.WriteString("{").WriteNewline() + f.IncrementIndent() + + for _, v := range lists { + f.FormatEnumValueDefinition(v) + } + + f.DecrementIndent() + f.WriteString("}") +} + +func (f *formatter) FormatEnumValueDefinition(def *ast.EnumValueDefinition) { + f.WriteDescription(def.Description) + + f.WriteWord(def.Name) + f.FormatDirectiveList(def.Directives) + + f.WriteNewline() +} + +func (f *formatter) FormatOperationList(lists ast.OperationList) { + for _, def := range lists { + f.FormatOperationDefinition(def) + } +} + +func (f *formatter) FormatOperationDefinition(def *ast.OperationDefinition) { + f.WriteWord(string(def.Operation)) + if def.Name != "" { + f.WriteWord(def.Name) + } + f.FormatVariableDefinitionList(def.VariableDefinitions) + f.FormatDirectiveList(def.Directives) + + if len(def.SelectionSet) != 0 { + f.FormatSelectionSet(def.SelectionSet) + f.WriteNewline() + } +} + +func (f *formatter) FormatDirectiveList(lists ast.DirectiveList) { + if len(lists) == 0 { + return + } + + for _, dir := range lists { + f.FormatDirective(dir) + } +} + +func (f *formatter) FormatDirective(dir *ast.Directive) { + f.WriteString("@").WriteWord(dir.Name) + f.FormatArgumentList(dir.Arguments) +} + +func (f *formatter) FormatArgumentList(lists ast.ArgumentList) { + if len(lists) == 0 { + return + } + f.NoPadding().WriteString("(") + for idx, arg := range lists { + f.FormatArgument(arg) + + if idx != len(lists)-1 { + f.NoPadding().WriteWord(",") + } + } + f.WriteString(")").NeedPadding() +} + +func (f *formatter) FormatArgument(arg *ast.Argument) { + f.WriteWord(arg.Name).NoPadding().WriteString(":").NeedPadding() + f.WriteString(arg.Value.String()) +} + +func (f *formatter) FormatFragmentDefinitionList(lists ast.FragmentDefinitionList) { + for _, def := range lists { + f.FormatFragmentDefinition(def) + } +} + +func (f *formatter) FormatFragmentDefinition(def *ast.FragmentDefinition) { + f.WriteWord("fragment").WriteWord(def.Name) + f.FormatVariableDefinitionList(def.VariableDefinition) + f.WriteWord("on").WriteWord(def.TypeCondition) + f.FormatDirectiveList(def.Directives) + + if len(def.SelectionSet) != 0 { + f.FormatSelectionSet(def.SelectionSet) + f.WriteNewline() + } +} + +func (f *formatter) FormatVariableDefinitionList(lists ast.VariableDefinitionList) { + if len(lists) == 0 { + return + } + + f.WriteString("(") + for idx, def := range lists { + f.FormatVariableDefinition(def) + + if idx != len(lists)-1 { + f.NoPadding().WriteWord(",") + } + } + f.NoPadding().WriteString(")").NeedPadding() +} + +func (f *formatter) FormatVariableDefinition(def *ast.VariableDefinition) { + f.WriteString("$").WriteWord(def.Variable).NoPadding().WriteString(":").NeedPadding() + f.FormatType(def.Type) + + if def.DefaultValue != nil { + f.WriteWord("=") + f.FormatValue(def.DefaultValue) + } + + // TODO https://github.com/vektah/gqlparser/v2/issues/102 + // VariableDefinition : Variable : Type DefaultValue? Directives[Const]? +} + +func (f *formatter) FormatSelectionSet(sets ast.SelectionSet) { + if len(sets) == 0 { + return + } + + f.WriteString("{").WriteNewline() + f.IncrementIndent() + + for _, sel := range sets { + f.FormatSelection(sel) + } + + f.DecrementIndent() + f.WriteString("}") +} + +func (f *formatter) FormatSelection(selection ast.Selection) { + switch v := selection.(type) { + case *ast.Field: + f.FormatField(v) + + case *ast.FragmentSpread: + f.FormatFragmentSpread(v) + + case *ast.InlineFragment: + f.FormatInlineFragment(v) + + default: + panic(fmt.Errorf("unknown Selection type: %T", selection)) + } + + f.WriteNewline() +} + +func (f *formatter) FormatField(field *ast.Field) { + if field.Alias != "" && field.Alias != field.Name { + f.WriteWord(field.Alias).NoPadding().WriteString(":").NeedPadding() + } + f.WriteWord(field.Name) + + if len(field.Arguments) != 0 { + f.NoPadding() + f.FormatArgumentList(field.Arguments) + f.NeedPadding() + } + + f.FormatDirectiveList(field.Directives) + + f.FormatSelectionSet(field.SelectionSet) +} + +func (f *formatter) FormatFragmentSpread(spread *ast.FragmentSpread) { + f.WriteWord("...").WriteWord(spread.Name) + + f.FormatDirectiveList(spread.Directives) +} + +func (f *formatter) FormatInlineFragment(inline *ast.InlineFragment) { + f.WriteWord("...") + if inline.TypeCondition != "" { + f.WriteWord("on").WriteWord(inline.TypeCondition) + } + + f.FormatDirectiveList(inline.Directives) + + f.FormatSelectionSet(inline.SelectionSet) +} + +func (f *formatter) FormatType(t *ast.Type) { + f.WriteWord(t.String()) +} + +func (f *formatter) FormatValue(value *ast.Value) { + f.WriteString(value.String()) +} diff --git a/vendor/github.com/vektah/gqlparser/go.mod b/vendor/github.com/vektah/gqlparser/v2/go.mod similarity index 52% rename from vendor/github.com/vektah/gqlparser/go.mod rename to vendor/github.com/vektah/gqlparser/v2/go.mod index dff172f6f..afdb99d8c 100644 --- a/vendor/github.com/vektah/gqlparser/go.mod +++ b/vendor/github.com/vektah/gqlparser/v2/go.mod @@ -1,10 +1,12 @@ -module github.com/vektah/gqlparser +module github.com/vektah/gqlparser/v2 + +go 1.12 require ( github.com/agnivade/levenshtein v1.0.1 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 - github.com/sergi/go-diff v1.0.0 // indirect - github.com/stretchr/testify v1.3.0 + github.com/sergi/go-diff v1.1.0 // indirect + github.com/stretchr/testify v1.4.0 golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6 - gopkg.in/yaml.v2 v2.2.2 + gopkg.in/yaml.v2 v2.2.4 ) diff --git a/vendor/github.com/vektah/gqlparser/go.sum b/vendor/github.com/vektah/gqlparser/v2/go.sum similarity index 52% rename from vendor/github.com/vektah/gqlparser/go.sum rename to vendor/github.com/vektah/gqlparser/v2/go.sum index 794906fa2..38f4ee3d6 100644 --- a/vendor/github.com/vektah/gqlparser/go.sum +++ b/vendor/github.com/vektah/gqlparser/v2/go.sum @@ -4,16 +4,27 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNg 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +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.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 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= golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6 h1:iZgcI2DDp6zW5v9Z/5+f0NuqoxNdmzg4hivjk2WLXpY= golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +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 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/vektah/gqlparser/gqlerror/error.go b/vendor/github.com/vektah/gqlparser/v2/gqlerror/error.go similarity index 81% rename from vendor/github.com/vektah/gqlparser/gqlerror/error.go rename to vendor/github.com/vektah/gqlparser/v2/gqlerror/error.go index c4c0847ad..390a7ab3f 100644 --- a/vendor/github.com/vektah/gqlparser/gqlerror/error.go +++ b/vendor/github.com/vektah/gqlparser/v2/gqlerror/error.go @@ -5,13 +5,13 @@ import ( "fmt" "strconv" - "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/v2/ast" ) // Error is the standard graphql error type described in https://facebook.github.io/graphql/draft/#sec-Errors type Error struct { Message string `json:"message"` - Path []interface{} `json:"path,omitempty"` + Path ast.Path `json:"path,omitempty"` Locations []Location `json:"locations,omitempty"` Extensions map[string]interface{} `json:"extensions,omitempty"` Rule string `json:"-"` @@ -63,20 +63,7 @@ func (err *Error) Error() string { } func (err Error) pathString() string { - var str bytes.Buffer - for i, v := range err.Path { - - switch v := v.(type) { - case int, int64: - str.WriteString(fmt.Sprintf("[%d]", v)) - default: - if i != 0 { - str.WriteByte('.') - } - str.WriteString(fmt.Sprint(v)) - } - } - return str.String() + return err.Path.String() } func (errs List) Error() string { @@ -88,7 +75,7 @@ func (errs List) Error() string { return buf.String() } -func WrapPath(path []interface{}, err error) *Error { +func WrapPath(path ast.Path, err error) *Error { return &Error{ Message: err.Error(), Path: path, @@ -101,7 +88,7 @@ func Errorf(message string, args ...interface{}) *Error { } } -func ErrorPathf(path []interface{}, message string, args ...interface{}) *Error { +func ErrorPathf(path ast.Path, message string, args ...interface{}) *Error { return &Error{ Message: fmt.Sprintf(message, args...), Path: path, diff --git a/vendor/github.com/vektah/gqlparser/gqlparser.go b/vendor/github.com/vektah/gqlparser/v2/gqlparser.go similarity index 79% rename from vendor/github.com/vektah/gqlparser/gqlparser.go rename to vendor/github.com/vektah/gqlparser/v2/gqlparser.go index 71e464072..ace63e14a 100644 --- a/vendor/github.com/vektah/gqlparser/gqlparser.go +++ b/vendor/github.com/vektah/gqlparser/v2/gqlparser.go @@ -1,11 +1,11 @@ package gqlparser import ( - "github.com/vektah/gqlparser/ast" - "github.com/vektah/gqlparser/gqlerror" - "github.com/vektah/gqlparser/parser" - "github.com/vektah/gqlparser/validator" - _ "github.com/vektah/gqlparser/validator/rules" + "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" + "github.com/vektah/gqlparser/v2/parser" + "github.com/vektah/gqlparser/v2/validator" + _ "github.com/vektah/gqlparser/v2/validator/rules" ) func LoadSchema(str ...*ast.Source) (*ast.Schema, *gqlerror.Error) { diff --git a/vendor/github.com/vektah/gqlparser/lexer/blockstring.go b/vendor/github.com/vektah/gqlparser/v2/lexer/blockstring.go similarity index 100% rename from vendor/github.com/vektah/gqlparser/lexer/blockstring.go rename to vendor/github.com/vektah/gqlparser/v2/lexer/blockstring.go diff --git a/vendor/github.com/vektah/gqlparser/lexer/lexer.go b/vendor/github.com/vektah/gqlparser/v2/lexer/lexer.go similarity index 99% rename from vendor/github.com/vektah/gqlparser/lexer/lexer.go rename to vendor/github.com/vektah/gqlparser/v2/lexer/lexer.go index 89687857b..720dd5b48 100644 --- a/vendor/github.com/vektah/gqlparser/lexer/lexer.go +++ b/vendor/github.com/vektah/gqlparser/v2/lexer/lexer.go @@ -4,8 +4,8 @@ import ( "bytes" "unicode/utf8" - "github.com/vektah/gqlparser/ast" - "github.com/vektah/gqlparser/gqlerror" + "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" ) // Lexer turns graphql request and schema strings into tokens diff --git a/vendor/github.com/vektah/gqlparser/lexer/lexer_test.yml b/vendor/github.com/vektah/gqlparser/v2/lexer/lexer_test.yml similarity index 100% rename from vendor/github.com/vektah/gqlparser/lexer/lexer_test.yml rename to vendor/github.com/vektah/gqlparser/v2/lexer/lexer_test.yml diff --git a/vendor/github.com/vektah/gqlparser/lexer/token.go b/vendor/github.com/vektah/gqlparser/v2/lexer/token.go similarity index 98% rename from vendor/github.com/vektah/gqlparser/lexer/token.go rename to vendor/github.com/vektah/gqlparser/v2/lexer/token.go index aef8b7298..8985a7efb 100644 --- a/vendor/github.com/vektah/gqlparser/lexer/token.go +++ b/vendor/github.com/vektah/gqlparser/v2/lexer/token.go @@ -3,7 +3,7 @@ package lexer import ( "strconv" - "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/v2/ast" ) const ( diff --git a/vendor/github.com/vektah/gqlparser/parser/parser.go b/vendor/github.com/vektah/gqlparser/v2/parser/parser.go similarity index 94% rename from vendor/github.com/vektah/gqlparser/parser/parser.go rename to vendor/github.com/vektah/gqlparser/v2/parser/parser.go index 96e984022..52b8e6840 100644 --- a/vendor/github.com/vektah/gqlparser/parser/parser.go +++ b/vendor/github.com/vektah/gqlparser/v2/parser/parser.go @@ -3,9 +3,9 @@ package parser import ( "strconv" - "github.com/vektah/gqlparser/ast" - "github.com/vektah/gqlparser/gqlerror" - "github.com/vektah/gqlparser/lexer" + "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" + "github.com/vektah/gqlparser/v2/lexer" ) type parser struct { diff --git a/vendor/github.com/vektah/gqlparser/parser/query.go b/vendor/github.com/vektah/gqlparser/v2/parser/query.go similarity index 98% rename from vendor/github.com/vektah/gqlparser/parser/query.go rename to vendor/github.com/vektah/gqlparser/v2/parser/query.go index 89e1e2e33..87deeeeb3 100644 --- a/vendor/github.com/vektah/gqlparser/parser/query.go +++ b/vendor/github.com/vektah/gqlparser/v2/parser/query.go @@ -1,10 +1,10 @@ package parser import ( - "github.com/vektah/gqlparser/gqlerror" - "github.com/vektah/gqlparser/lexer" + "github.com/vektah/gqlparser/v2/gqlerror" + "github.com/vektah/gqlparser/v2/lexer" - . "github.com/vektah/gqlparser/ast" + . "github.com/vektah/gqlparser/v2/ast" ) func ParseQuery(source *Source) (*QueryDocument, *gqlerror.Error) { diff --git a/vendor/github.com/vektah/gqlparser/parser/query_test.yml b/vendor/github.com/vektah/gqlparser/v2/parser/query_test.yml similarity index 100% rename from vendor/github.com/vektah/gqlparser/parser/query_test.yml rename to vendor/github.com/vektah/gqlparser/v2/parser/query_test.yml diff --git a/vendor/github.com/vektah/gqlparser/parser/schema.go b/vendor/github.com/vektah/gqlparser/v2/parser/schema.go similarity index 99% rename from vendor/github.com/vektah/gqlparser/parser/schema.go rename to vendor/github.com/vektah/gqlparser/v2/parser/schema.go index 5689e4334..7cfdd147e 100644 --- a/vendor/github.com/vektah/gqlparser/parser/schema.go +++ b/vendor/github.com/vektah/gqlparser/v2/parser/schema.go @@ -1,9 +1,9 @@ package parser import ( - . "github.com/vektah/gqlparser/ast" - "github.com/vektah/gqlparser/gqlerror" - "github.com/vektah/gqlparser/lexer" + . "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" + "github.com/vektah/gqlparser/v2/lexer" ) func ParseSchema(source *Source) (*SchemaDocument, *gqlerror.Error) { diff --git a/vendor/github.com/vektah/gqlparser/parser/schema_test.yml b/vendor/github.com/vektah/gqlparser/v2/parser/schema_test.yml similarity index 100% rename from vendor/github.com/vektah/gqlparser/parser/schema_test.yml rename to vendor/github.com/vektah/gqlparser/v2/parser/schema_test.yml diff --git a/vendor/github.com/vektah/gqlparser/readme.md b/vendor/github.com/vektah/gqlparser/v2/readme.md similarity index 85% rename from vendor/github.com/vektah/gqlparser/readme.md rename to vendor/github.com/vektah/gqlparser/v2/readme.md index 8d1362bbb..a7cb346b6 100644 --- a/vendor/github.com/vektah/gqlparser/readme.md +++ b/vendor/github.com/vektah/gqlparser/v2/readme.md @@ -1,4 +1,4 @@ -gqlparser [![CircleCI](https://badgen.net/circleci/github/vektah/gqlparser/master)](https://circleci.com/gh/vektah/gqlparser) [![Go Report Card](https://goreportcard.com/badge/github.com/vektah/gqlparser)](https://goreportcard.com/report/github.com/vektah/gqlparser) [![Coverage Status](https://badgen.net/coveralls/c/github/vektah/gqlparser)](https://coveralls.io/github/vektah/gqlparser?branch=master) +gqlparser [![CircleCI](https://badgen.net/circleci/github/vektah/gqlparser/master)](https://circleci.com/gh/vektah/gqlparser) [![Go Report Card](https://goreportcard.com/badge/github.com/vektah/gqlparser/v2)](https://goreportcard.com/report/github.com/vektah/gqlparser/v2) [![Coverage Status](https://badgen.net/coveralls/c/github/vektah/gqlparser)](https://coveralls.io/github/vektah/gqlparser?branch=master) === This is a parser for graphql, written to mirror the graphql-js reference implementation as closely while remaining idiomatic and easy to use. diff --git a/vendor/github.com/vektah/gqlparser/validator/error.go b/vendor/github.com/vektah/gqlparser/v2/validator/error.go similarity index 94% rename from vendor/github.com/vektah/gqlparser/validator/error.go rename to vendor/github.com/vektah/gqlparser/v2/validator/error.go index f354dee59..f8f76055a 100644 --- a/vendor/github.com/vektah/gqlparser/validator/error.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/error.go @@ -3,8 +3,8 @@ package validator import ( "fmt" - "github.com/vektah/gqlparser/ast" - "github.com/vektah/gqlparser/gqlerror" + "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" ) type ErrorOption func(err *gqlerror.Error) diff --git a/vendor/github.com/vektah/gqlparser/validator/messaging.go b/vendor/github.com/vektah/gqlparser/v2/validator/messaging.go similarity index 100% rename from vendor/github.com/vektah/gqlparser/validator/messaging.go rename to vendor/github.com/vektah/gqlparser/v2/validator/messaging.go diff --git a/vendor/github.com/vektah/gqlparser/validator/prelude.go b/vendor/github.com/vektah/gqlparser/v2/validator/prelude.go similarity index 98% rename from vendor/github.com/vektah/gqlparser/validator/prelude.go rename to vendor/github.com/vektah/gqlparser/v2/validator/prelude.go index 00ae78f74..0c7e9b2d5 100644 --- a/vendor/github.com/vektah/gqlparser/validator/prelude.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/prelude.go @@ -1,6 +1,6 @@ package validator -import "github.com/vektah/gqlparser/ast" +import "github.com/vektah/gqlparser/v2/ast" var Prelude = &ast.Source{ Name: "prelude.graphql", diff --git a/vendor/github.com/vektah/gqlparser/validator/prelude.graphql b/vendor/github.com/vektah/gqlparser/v2/validator/prelude.graphql similarity index 100% rename from vendor/github.com/vektah/gqlparser/validator/prelude.graphql rename to vendor/github.com/vektah/gqlparser/v2/validator/prelude.graphql diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/fields_on_correct_type.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/fields_on_correct_type.go similarity index 97% rename from vendor/github.com/vektah/gqlparser/validator/rules/fields_on_correct_type.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/fields_on_correct_type.go index 69148d526..8bfb8cc3d 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/fields_on_correct_type.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/fields_on_correct_type.go @@ -4,8 +4,8 @@ import ( "fmt" "sort" - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/fragments_on_composite_types.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/fragments_on_composite_types.go similarity index 92% rename from vendor/github.com/vektah/gqlparser/validator/rules/fragments_on_composite_types.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/fragments_on_composite_types.go index a4a482469..5215f697e 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/fragments_on_composite_types.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/fragments_on_composite_types.go @@ -3,8 +3,8 @@ package validator import ( "fmt" - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/known_argument_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_argument_names.go similarity index 94% rename from vendor/github.com/vektah/gqlparser/validator/rules/known_argument_names.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/known_argument_names.go index 1a46431d8..9a53df172 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/known_argument_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_argument_names.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/known_directives.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_directives.go similarity index 87% rename from vendor/github.com/vektah/gqlparser/validator/rules/known_directives.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/known_directives.go index dc4353efc..f3c0f80e4 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/known_directives.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_directives.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/known_fragment_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_fragment_names.go similarity index 82% rename from vendor/github.com/vektah/gqlparser/validator/rules/known_fragment_names.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/known_fragment_names.go index ec91588c3..b7427d0d0 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/known_fragment_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_fragment_names.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/known_type_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_type_names.go similarity index 94% rename from vendor/github.com/vektah/gqlparser/validator/rules/known_type_names.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/known_type_names.go index 223086b38..c228af704 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/known_type_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/known_type_names.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/lone_anonymous_operation.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/lone_anonymous_operation.go similarity index 83% rename from vendor/github.com/vektah/gqlparser/validator/rules/lone_anonymous_operation.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/lone_anonymous_operation.go index dd232142b..d27528542 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/lone_anonymous_operation.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/lone_anonymous_operation.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/no_fragment_cycles.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_fragment_cycles.go similarity index 96% rename from vendor/github.com/vektah/gqlparser/validator/rules/no_fragment_cycles.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/no_fragment_cycles.go index 7511529b7..81fffa578 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/no_fragment_cycles.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_fragment_cycles.go @@ -4,8 +4,8 @@ import ( "fmt" "strings" - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/no_undefined_variables.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_undefined_variables.go similarity index 88% rename from vendor/github.com/vektah/gqlparser/validator/rules/no_undefined_variables.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/no_undefined_variables.go index 505206bed..4f05f00a2 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/no_undefined_variables.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_undefined_variables.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/no_unused_fragments.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_fragments.go similarity index 88% rename from vendor/github.com/vektah/gqlparser/validator/rules/no_unused_fragments.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_fragments.go index 4aa835f5c..dfc896725 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/no_unused_fragments.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_fragments.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/no_unused_variables.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_variables.go similarity index 88% rename from vendor/github.com/vektah/gqlparser/validator/rules/no_unused_variables.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_variables.go index 28cf77365..df2e5f4b7 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/no_unused_variables.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/no_unused_variables.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/overlapping_fields_can_be_merged.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/overlapping_fields_can_be_merged.go similarity index 99% rename from vendor/github.com/vektah/gqlparser/validator/rules/overlapping_fields_can_be_merged.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/overlapping_fields_can_be_merged.go index bb2f18319..5cd028df8 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/overlapping_fields_can_be_merged.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/overlapping_fields_can_be_merged.go @@ -5,8 +5,8 @@ import ( "fmt" "reflect" - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/possible_fragment_spreads.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/possible_fragment_spreads.go similarity index 95% rename from vendor/github.com/vektah/gqlparser/validator/rules/possible_fragment_spreads.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/possible_fragment_spreads.go index 046118348..a3f795c97 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/possible_fragment_spreads.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/possible_fragment_spreads.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/provided_required_arguments.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/provided_required_arguments.go similarity index 94% rename from vendor/github.com/vektah/gqlparser/validator/rules/provided_required_arguments.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/provided_required_arguments.go index 55791a6bf..4410288a8 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/provided_required_arguments.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/provided_required_arguments.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/scalar_leafs.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/scalar_leafs.go similarity index 91% rename from vendor/github.com/vektah/gqlparser/validator/rules/scalar_leafs.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/scalar_leafs.go index bb961f448..718bc6834 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/scalar_leafs.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/scalar_leafs.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/single_field_subscriptions.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/single_field_subscriptions.go similarity index 87% rename from vendor/github.com/vektah/gqlparser/validator/rules/single_field_subscriptions.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/single_field_subscriptions.go index 53003c112..206e3a6e2 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/single_field_subscriptions.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/single_field_subscriptions.go @@ -3,8 +3,8 @@ package validator import ( "strconv" - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/unique_argument_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_argument_names.go similarity index 89% rename from vendor/github.com/vektah/gqlparser/validator/rules/unique_argument_names.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_argument_names.go index 0ddcde724..fc2b639df 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/unique_argument_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_argument_names.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/unique_directives_per_location.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_directives_per_location.go similarity index 85% rename from vendor/github.com/vektah/gqlparser/validator/rules/unique_directives_per_location.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_directives_per_location.go index 077c4687e..2ea4f13d1 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/unique_directives_per_location.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_directives_per_location.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/unique_fragment_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_fragment_names.go similarity index 84% rename from vendor/github.com/vektah/gqlparser/validator/rules/unique_fragment_names.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_fragment_names.go index 46a8b7c7b..8c348aea0 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/unique_fragment_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_fragment_names.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/unique_input_field_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_input_field_names.go similarity index 85% rename from vendor/github.com/vektah/gqlparser/validator/rules/unique_input_field_names.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_input_field_names.go index f254d5888..092be671c 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/unique_input_field_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_input_field_names.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/unique_operation_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_operation_names.go similarity index 83% rename from vendor/github.com/vektah/gqlparser/validator/rules/unique_operation_names.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_operation_names.go index c1ab56be0..4d41b60ae 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/unique_operation_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_operation_names.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/unique_variable_names.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_variable_names.go similarity index 85% rename from vendor/github.com/vektah/gqlparser/validator/rules/unique_variable_names.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_variable_names.go index 70590a886..64ac5072d 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/unique_variable_names.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/unique_variable_names.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/values_of_correct_type.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/values_of_correct_type.go similarity index 97% rename from vendor/github.com/vektah/gqlparser/validator/rules/values_of_correct_type.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/values_of_correct_type.go index d64cc666d..40dc2194a 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/values_of_correct_type.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/values_of_correct_type.go @@ -3,8 +3,8 @@ package validator import ( "fmt" - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/variables_are_input_types.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_are_input_types.go similarity index 86% rename from vendor/github.com/vektah/gqlparser/validator/rules/variables_are_input_types.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_are_input_types.go index 9d58ae1c2..4ea94e5a8 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/variables_are_input_types.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_are_input_types.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/rules/variables_in_allowed_position.go b/vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_in_allowed_position.go similarity index 91% rename from vendor/github.com/vektah/gqlparser/validator/rules/variables_in_allowed_position.go rename to vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_in_allowed_position.go index e6d97c9f6..aba6eb621 100644 --- a/vendor/github.com/vektah/gqlparser/validator/rules/variables_in_allowed_position.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/rules/variables_in_allowed_position.go @@ -1,8 +1,8 @@ package validator import ( - "github.com/vektah/gqlparser/ast" - . "github.com/vektah/gqlparser/validator" + "github.com/vektah/gqlparser/v2/ast" + . "github.com/vektah/gqlparser/v2/validator" ) func init() { diff --git a/vendor/github.com/vektah/gqlparser/validator/schema.go b/vendor/github.com/vektah/gqlparser/v2/validator/schema.go similarity index 95% rename from vendor/github.com/vektah/gqlparser/validator/schema.go rename to vendor/github.com/vektah/gqlparser/v2/validator/schema.go index 3242822fa..4c96c31a7 100644 --- a/vendor/github.com/vektah/gqlparser/validator/schema.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/schema.go @@ -6,9 +6,9 @@ import ( "strconv" "strings" - . "github.com/vektah/gqlparser/ast" - "github.com/vektah/gqlparser/gqlerror" - "github.com/vektah/gqlparser/parser" + . "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" + "github.com/vektah/gqlparser/v2/parser" ) func LoadSchema(inputs ...*Source) (*Schema, *gqlerror.Error) { @@ -34,10 +34,18 @@ func ValidateSchemaDocument(ast *SchemaDocument) (*Schema, *gqlerror.Error) { schema.Types[def.Name] = ast.Definitions[i] } + defs := append(DefinitionList{}, ast.Definitions...) + for _, ext := range ast.Extensions { def := schema.Types[ext.Name] if def == nil { - return nil, gqlerror.ErrorPosf(ext.Position, "Cannot extend type %s because it does not exist.", ext.Name) + schema.Types[ext.Name] = &Definition{ + Kind: ext.Kind, + Name: ext.Name, + Position: ext.Position, + } + def = schema.Types[ext.Name] + defs = append(defs, def) } if def.Kind != ext.Kind { @@ -51,7 +59,7 @@ func ValidateSchemaDocument(ast *SchemaDocument) (*Schema, *gqlerror.Error) { def.EnumValues = append(def.EnumValues, ext.EnumValues...) } - for _, def := range ast.Definitions { + for _, def := range defs { switch def.Kind { case Union: for _, t := range def.Types { @@ -147,9 +155,9 @@ func ValidateSchemaDocument(ast *SchemaDocument) (*Schema, *gqlerror.Error) { }, &FieldDefinition{ Name: "__type", - Type: NonNullNamedType("__Type", nil), + Type: NamedType("__Type", nil), Arguments: ArgumentDefinitionList{ - {Name: "name", Type: NamedType("String", nil)}, + {Name: "name", Type: NonNullNamedType("String", nil)}, }, }, ) diff --git a/vendor/github.com/vektah/gqlparser/validator/schema_test.yml b/vendor/github.com/vektah/gqlparser/v2/validator/schema_test.yml similarity index 94% rename from vendor/github.com/vektah/gqlparser/validator/schema_test.yml rename to vendor/github.com/vektah/gqlparser/v2/validator/schema_test.yml index b1d85c448..a5d8bb491 100644 --- a/vendor/github.com/vektah/gqlparser/validator/schema_test.yml +++ b/vendor/github.com/vektah/gqlparser/v2/validator/schema_test.yml @@ -418,15 +418,43 @@ unions: message: "UNION type \"Baz\" must be OBJECT." locations: [{line: 1, column: 7}] + - name: unions of pure type extensions are valid + input: | + + type Review { + body: String! + author: User! @provides(fields: "username") + product: Product! + } + + extend type User @key(fields: "id") { + id: ID! @external + reviews: [Review] + } + + extend type Product @key(fields: "upc") { + upc: String! @external + reviews: [Review] + } + + union Foo = User | Product + scalar _Any + scalar _FieldSet + directive @external on FIELD_DEFINITION + directive @requires(fields: _FieldSet!) on FIELD_DEFINITION + directive @provides(fields: _FieldSet!) on FIELD_DEFINITION + directive @key(fields: _FieldSet!) on OBJECT | INTERFACE + directive @extends on OBJECT + + + type extensions: - - name: cannot extend non existant types + - name: can extend non existant types input: | extend type A { name: String } - error: - message: "Cannot extend type A because it does not exist." - locations: [{line: 1, column: 13}] + - name: cannot extend incorret type existant types input: | diff --git a/vendor/github.com/vektah/gqlparser/validator/suggestionList.go b/vendor/github.com/vektah/gqlparser/v2/validator/suggestionList.go similarity index 100% rename from vendor/github.com/vektah/gqlparser/validator/suggestionList.go rename to vendor/github.com/vektah/gqlparser/v2/validator/suggestionList.go diff --git a/vendor/github.com/vektah/gqlparser/validator/validator.go b/vendor/github.com/vektah/gqlparser/v2/validator/validator.go similarity index 90% rename from vendor/github.com/vektah/gqlparser/validator/validator.go rename to vendor/github.com/vektah/gqlparser/v2/validator/validator.go index bbacec6f2..34bf93db3 100644 --- a/vendor/github.com/vektah/gqlparser/validator/validator.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/validator.go @@ -1,8 +1,8 @@ package validator import ( - . "github.com/vektah/gqlparser/ast" - "github.com/vektah/gqlparser/gqlerror" + . "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" ) type AddErrFunc func(options ...ErrorOption) diff --git a/vendor/github.com/vektah/gqlparser/validator/vars.go b/vendor/github.com/vektah/gqlparser/v2/validator/vars.go similarity index 81% rename from vendor/github.com/vektah/gqlparser/validator/vars.go rename to vendor/github.com/vektah/gqlparser/v2/validator/vars.go index aaf3a0d1a..9151fa8e9 100644 --- a/vendor/github.com/vektah/gqlparser/validator/vars.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/vars.go @@ -2,11 +2,12 @@ package validator import ( "reflect" + "strings" "fmt" - "github.com/vektah/gqlparser/ast" - "github.com/vektah/gqlparser/gqlerror" + "github.com/vektah/gqlparser/v2/ast" + "github.com/vektah/gqlparser/v2/gqlerror" ) var UnexpectedType = fmt.Errorf("Unexpected Type") @@ -16,12 +17,12 @@ func VariableValues(schema *ast.Schema, op *ast.OperationDefinition, variables m coercedVars := map[string]interface{}{} validator := varValidator{ - path: []interface{}{"variable"}, + path: ast.Path{ast.PathName("variable")}, schema: schema, } for _, v := range op.VariableDefinitions { - validator.path = append(validator.path, v.Variable) + validator.path = append(validator.path, ast.PathName(v.Variable)) if !v.Definition.IsInputType() { return nil, gqlerror.ErrorPathf(validator.path, "must an input type") @@ -68,7 +69,7 @@ func VariableValues(schema *ast.Schema, op *ast.OperationDefinition, variables m } type varValidator struct { - path []interface{} + path ast.Path schema *ast.Schema } @@ -86,7 +87,7 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) *gqlerr for i := 0; i < val.Len(); i++ { resetPath() - v.path = append(v.path, i) + v.path = append(v.path, ast.PathIndex(i)) field := val.Index(i) if field.Kind() == reflect.Ptr || field.Kind() == reflect.Interface { @@ -109,13 +110,27 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) *gqlerr panic(fmt.Errorf("missing def for %s", typ.NamedType)) } + if !typ.NonNull && !val.IsValid() { + // If the type is not null and we got a invalid value namely null/nil, then it's valid + return nil + } + switch def.Kind { case ast.Enum: kind := val.Type().Kind() - if kind == reflect.Int || kind == reflect.Int32 || kind == reflect.Int64 || kind == reflect.String { - return nil + if kind != reflect.Int && kind != reflect.Int32 && kind != reflect.Int64 && kind != reflect.String { + return gqlerror.ErrorPathf(v.path, "enums must be ints or strings") } - return gqlerror.ErrorPathf(v.path, "enums must be ints or strings") + isValidEnum := false + for _, enumVal := range def.EnumValues { + if strings.EqualFold(val.String(), enumVal.Name) { + isValidEnum = true + } + } + if !isValidEnum { + return gqlerror.ErrorPathf(v.path, "%s is not a valid %s", val.String(), def.Name) + } + return nil case ast.Scalar: kind := val.Type().Kind() switch typ.NamedType { @@ -156,7 +171,7 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) *gqlerr val.MapIndex(name) fieldDef := def.Fields.ForName(name.String()) resetPath() - v.path = append(v.path, name.String()) + v.path = append(v.path, ast.PathName(name.String())) if fieldDef == nil { return gqlerror.ErrorPathf(v.path, "unknown field") @@ -165,7 +180,7 @@ func (v *varValidator) validateVarType(typ *ast.Type, val reflect.Value) *gqlerr for _, fieldDef := range def.Fields { resetPath() - v.path = append(v.path, fieldDef.Name) + v.path = append(v.path, ast.PathName(fieldDef.Name)) field := val.MapIndex(reflect.ValueOf(fieldDef.Name)) if !field.IsValid() { diff --git a/vendor/github.com/vektah/gqlparser/validator/walk.go b/vendor/github.com/vektah/gqlparser/v2/validator/walk.go similarity index 99% rename from vendor/github.com/vektah/gqlparser/validator/walk.go rename to vendor/github.com/vektah/gqlparser/v2/validator/walk.go index 751ba1f11..8f8abf108 100644 --- a/vendor/github.com/vektah/gqlparser/validator/walk.go +++ b/vendor/github.com/vektah/gqlparser/v2/validator/walk.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/vektah/gqlparser/ast" + "github.com/vektah/gqlparser/v2/ast" ) type Events struct { diff --git a/vendor/golang.org/x/crypto/ssh/terminal/terminal.go b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go index 2f04ee5b5..2ffb97bfb 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/terminal.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go @@ -7,6 +7,7 @@ package terminal import ( "bytes" "io" + "runtime" "strconv" "sync" "unicode/utf8" @@ -112,6 +113,7 @@ func NewTerminal(c io.ReadWriter, prompt string) *Terminal { } const ( + keyCtrlC = 3 keyCtrlD = 4 keyCtrlU = 21 keyEnter = '\r' @@ -150,8 +152,12 @@ func bytesToKey(b []byte, pasteActive bool) (rune, []byte) { switch b[0] { case 1: // ^A return keyHome, b[1:] + case 2: // ^B + return keyLeft, b[1:] case 5: // ^E return keyEnd, b[1:] + case 6: // ^F + return keyRight, b[1:] case 8: // ^H return keyBackspace, b[1:] case 11: // ^K @@ -737,6 +743,9 @@ func (t *Terminal) readLine() (line string, err error) { return "", io.EOF } } + if key == keyCtrlC { + return "", io.EOF + } if key == keyPasteStart { t.pasteActive = true if len(t.line) == 0 { @@ -939,6 +948,8 @@ func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) { // readPasswordLine reads from reader until it finds \n or io.EOF. // The slice returned does not include the \n. // readPasswordLine also ignores any \r it finds. +// Windows uses \r as end of line. So, on Windows, readPasswordLine +// reads until it finds \r and ignores any \n it finds during processing. func readPasswordLine(reader io.Reader) ([]byte, error) { var buf [1]byte var ret []byte @@ -947,10 +958,20 @@ func readPasswordLine(reader io.Reader) ([]byte, error) { n, err := reader.Read(buf[:]) if n > 0 { switch buf[0] { + case '\b': + if len(ret) > 0 { + ret = ret[:len(ret)-1] + } case '\n': - return ret, nil + if runtime.GOOS != "windows" { + return ret, nil + } + // otherwise ignore \n case '\r': - // remove \r from passwords on Windows + if runtime.GOOS == "windows" { + return ret, nil + } + // otherwise ignore \r default: ret = append(ret, buf[0]) } diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go index 5cfdf8f3f..f614e9cb6 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go @@ -85,8 +85,8 @@ func ReadPassword(fd int) ([]byte, error) { } old := st - st &^= (windows.ENABLE_ECHO_INPUT) - st |= (windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT | windows.ENABLE_PROCESSED_OUTPUT) + st &^= (windows.ENABLE_ECHO_INPUT | windows.ENABLE_LINE_INPUT) + st |= (windows.ENABLE_PROCESSED_OUTPUT | windows.ENABLE_PROCESSED_INPUT) if err := windows.SetConsoleMode(windows.Handle(fd), st); err != nil { return nil, err } diff --git a/vendor/golang.org/x/net/publicsuffix/table.go b/vendor/golang.org/x/net/publicsuffix/table.go index 8e1c9d3dd..ec2bde8cb 100644 --- a/vendor/golang.org/x/net/publicsuffix/table.go +++ b/vendor/golang.org/x/net/publicsuffix/table.go @@ -2,7 +2,7 @@ package publicsuffix -const version = "publicsuffix.org's public_suffix_list.dat, git revision dbe9da0a8abeab1b6257c57668d1ecb584189951 (2020-05-27T00:50:31Z)" +const version = "publicsuffix.org's public_suffix_list.dat, git revision bdbe9dfd268d040fc826766b1d4e27dc4416fe73 (2020-08-10T09:26:55Z)" const ( nodesBitsChildren = 10 @@ -23,490 +23,492 @@ const ( ) // numTLD is the number of top level domains. -const numTLD = 1525 +const numTLD = 1518 // Text is the combined text of all labels. -const text = "9guacuiababia-goracleaningroks-theatree12hpalermomahachijoinvill" + - "eksvikaracoldwarszawabogadobeaemcloud66bjarkoyusuharabjerkreimdb" + - "altimore-og-romsdalipayokozebizenakanotoddenavuotnarashinobninsk" + - "aragandaustevoll-o-g-i-naval-d-aosta-valleyboltateshinanomachimk" + - "entateyamagrocerybnikeisenbahn4tatarantours3-ap-northeast-2ix443" + - "2-balsan-suedtirolkuszczytnoipirangamvik12bjugnieznord-frontierb" + - "lackfridayusuisservehumourbloombergbauernishiazaindielddanuorrin" + - "digenamsosnowiechernihivgubs3-website-sa-east-1bloxcms3-website-" + - "us-east-1bluedaemoneyuu2-localhostoregontrailroadrayddnsfreebox-" + - "osascoli-picenordre-landraydns3-website-us-west-1bmoattachments3" + - "-website-us-west-2bms5yuzawabmwedeploybnrwegroweibolognagasakind" + - "eroybomloabathsbchernivtsiciliabondrivefsnillfjordrobaknoluoktac" + - "hikawakuyabukievennodesadoes-itvedestrandrudupontariobranconakan" + - "iikawatanagurabonnishigoddabookinghostfoldnavyboomlair-traffic-c" + - "ontrolleyboschaefflerdalivornohtawaramotoineppueblockbustermezja" + - "mpagefrontapparachutinglobalashovhachinohedmarkarpaczeladzlglobo" + - "avistanbulsan-sudtirolombardynaliaskimitsubatamibugattiffanycher" + - "novtsymantechnologybostikaruizawabostonakijinsekikogentappsselfi" + - "paraglidinglogoweirbotanicalgardenishiharabotanicgardenishiizuna" + - "zukindustriabotanynysagaeroclubmedecincinnationwidealerbouncemer" + - "ckmsdnipropetrovskjervoyageometre-experts-comptablesakyotanabell" + - "unord-aurdalpha-myqnapcloudaccesscambridgeiseiyoichippubetsubets" + - "ugarugbydgoszczecinemagentositecnologiabounty-fullensakerryprope" + - "rtiesalangenishikatakinoueboutiquebechirurgiens-dentistes-en-fra" + - "ncebozen-sudtirolomzaporizhzhegurindustriesteamfamberkeleybozen-" + - "suedtirolondrinapleskarumaifarmsteadurbanamexhibitionishikatsura" + - "git-reposalondonetskasaokamiminersaltdalorenskogloppenzaolbia-te" + - "mpio-olbiatempioolbialystokkepnogatagajobojinfinitintelligencebp" + - "lacedogawarabikomaezakirunorddalotenkawabrandywinevalleybrasilia" + - "brindisibenikindlebtimnetzparisor-fronishikawazukamisunagawabris" + - "toloseyouriparliamentjomeloyalistoragebritishcolumbialowiezagani" + - "shimerabroadcastleclerchiryukyuragifuchungbukharavennagatorodoyb" + - "roadwaybroke-itjxfinitybrokerbronnoysundurhamburglugmbhartipscbg" + - "minakamichiharabrothermesaverdealstahaugesunderseaportsinfolldal" + - "ottebrowsersafetymarketsaludweberbrumunddalottokonamegatakazakin" + - "ternationalfirearmsalvadordalibabalena-devicesalzburgmodellingmx" + - "javald-aostarnbergretakanabeautysvardoesntexisteingeekashibataka" + - "tsukiyosatokamachintaifun-dnsdojolsterbrunelastxn--0trq7p7nnishi" + - "nomiyashironomutashinaintuitkmaxxn--11b4c3dynathomebuiltwithdark" + - "ashiharabrusselsamegawabruxellesamnangerbryansklepparmattelekomm" + - "unikationishinoomotegobrynewhollandyndns-at-homedepotenzamamidsu" + - "ndyndns-at-workisboringrimstadyndns-blogdnsampalacebuskerudinewj" + - "erseybuzentsujiiebuzzwellbeingzonebwfarsundyndns-freeboxosloftra" + - "nakanojoetsuwanouchikujogaszkolancashirecreationishinoshimatsuur" + - "abzhitomirumalatvuopmicrolightingripebzzcommunexus-2community-pr" + - "ochowicecomoarekecomparemarkerryhotelsantacruzsantafedjejuifmetl" + - "ifeinsurancecompute-1computerhistoryofscience-fictioncomsecurity" + - "tacticsantamariakecondoshichinohealth-carereformitakeharaconfere" + - "nceconstructionconsuladonnaharimalopolskanlandyndns-remotewdyndn" + - "s-serverisignconsultanthropologyconsultingrpartycontactozsdeltaj" + - "irittogliattis-a-caterercontagematsubaracontemporaryarteducation" + - "alchikugodontexistmein-iservebeercontractorskenconventureshinode" + - "arthruherecipescaravantaacookingchannelsdvrdnsfor-better-thanawa" + - "tchandclockasukabedzin-berlindasdaburcooluroycooperativano-frank" + - "ivskolefrakkestadyndns-webhopencraftrani-andria-barletta-trani-a" + - "ndriacopenhagencyclopedichofunatoriginstitutemasekashiwaracoprod" + - "uctionsantoandreamhostersanukis-a-celticsfancorsicagliaricoharuo" + - "vatraniandriabarlettatraniandriacorvettemp-dnsaobernardocosenzak" + - "opanecosidnshome-webserverdalutskasumigaurawa-mazowszexnetnedalu" + - "xurycostumedicinakaiwamizawatchesaogoncartoonartdecologiacouchpo" + - "tatofriesaotomeldaluzerncouklugsmilegallocus-3councilvivanovolda" + - "couponsapporocq-acranbrookuwanalyticsardegnarusawacrdyndns-wikir" + - "kenesardiniacreditcardyndns-workshopitsitexaskoyabearalvahkikuch" + - "ikuseikarugalsacecreditunioncremonashgabadaddjaguarqcxn--12cfi8i" + - "xb8lcrewildlifedorainfracloudfrontdoorcricketrzyncrimeast-kazakh" + - "stanangercrotonecrownipasadenaritakurashikis-a-chefashioncrsvpas" + - "sagensarlcruisesarpsborgruecryptonomichigangwoncuisinellajollame" + - "ricanexpressexyculturalcentertainmentranoycuneocupcakecuritiback" + - "yardsarufutsunomiyawakasaikaitakofuefukihaboromskoguidegreecurva" + - "lled-aostaverncymrussiacyonabaruminamidaitomanchestercyouthachio" + - "jiyahooguyfetsundynnsasayamafgujohanamakinoharafhvalerfidoomdnst" + - "racefieldynservebbsasebofagemologicallyngenfigueresinstagingulen" + - "filateliafilegear-audnedalnfilegear-deatnulvikatowicefilegear-gb" + - "izfilegear-iefilegear-jpmorganfilegear-sgunmanxn--1ck2e1bananare" + - "publicasertairaumalborkarasjohkamikoaniikappuboliviajessheimemor" + - "ialaziobserverevistaples3-external-1filminamifuranofinalfinancef" + - "ineartsavonarutomobellevuelosangelesjabbottransurlfinlandynufcfa" + - "nfinnoyfirebaseappatriafirenzefirestonefirmdalegoldpoint2thisami" + - "tsukefishingolffansaxofitjarvodkafjordynv6fitnessettlementrapani" + - "izafjalerflesberguovdageaidnunusualpersonflickragerogerschoenbru" + - "nnflightschokokekschokoladenflirfloginlinefloraflorencefloridats" + - "unanjoburgushikamifuranorth-kazakhstanfloripaderbornfloristanoha" + - "takaharunzenflorokunohealthcareerscholarshipschoolschulezajskats" + - "ushikabeeldengeluidynvpnplus-4flowerschulserverfltravelchannelfl" + - "ynnhosting-clusterfndyroyrvikinguitarsaskatchewanfor-ourfor-some" + - "dizinhistorischeschwarzgwangjuniperfor-theaterforexrothachirogat" + - "akanezawaforgotdnschweizforli-cesena-forlicesenaforlillehammerfe" + - "ste-ipaviancarrdforsaleikangerforsandasuologoipfizerfortalfortmi" + - "ssoulancasterfortworthadanorthwesternmutualfosnesciencecentersci" + - "encehistoryfotaruis-a-cubicle-slavellinodeobjectscientistordalfo" + - "xfordebianfozorafredrikstadtvscjohnsonfreeddnsgeekgalaxyfreedesk" + - "topocznore-og-uvdalfreemasonryfreesitextileirfjordfreetlscotland" + - "freiburgwiddleitungsenfreseniuscountryestateofdelawareggio-calab" + - "riafribourgxn--1ctwolominamatarnobrzegyptianfriuli-v-giuliafriul" + - "i-ve-giuliafriuli-vegiuliafriuli-venezia-giuliafriuli-veneziagiu" + - "liafriuli-vgiuliafriuliv-giuliafriulive-giuliafriulivegiuliafriu" + - "livenezia-giuliafriuliveneziagiuliafriulivgiuliafrlfroganscrappe" + - "r-sitefrognfrolandfrom-akrehamnfrom-alfrom-arfrom-azfrom-capetow" + - "nnews-stagingfrom-coffeedbackplaneapplinzis-a-democratravelersin" + - "surancefrom-ctrdfrom-dchonanbulsan-suedtirolowiczest-le-patronis" + - "hitosashimizunaminamibosogndalpusercontentoyotapartsandnessjoeni" + - "shiwakinvestmentsandoyfrom-dedyn-berlincolnfrom-flanderscrapping" + - "from-gaulardalfrom-hichisochildrensgardenfrom-iafrom-idfrom-ilfr" + - "om-in-brbanzaicloudcontrolledekagaminombresciaustraliamusementdl" + - "lpages3-ap-south-1kappchizip6116-b-dataiji234lima-cityeatselinog" + - "radult3l3p0rtatamotors3-ap-northeast-1337from-kscrysechoseiroumu" + - "enchenissandiegofrom-kyowariasahikawafrom-lanciafrom-mamurogawaf" + - "rom-mdfrom-meeresistancefrom-mifunefrom-mnfrom-modalenfrom-mserv" + - "eirchoshibuyachiyodapliernewspaperfrom-mtnfrom-nctulangevagrigen" + - "tomologyeonggiehtavuoatnagahamaroyerfrom-ndfrom-nefrom-nh-serveb" + - "logsiteleafamilycompanyanagawafflecellclaimserveminecraftrentin-" + - "sud-tirolfrom-njaworznoticiasnesoddenmarkhangelskjakdnepropetrov" + - "skiervaapsteiermarkatsuyamarugame-hostrowiechoyodobashichikashuk" + - "ujitawarafrom-nminamiiserniafrom-nvalledaostargetmyiphostrodawar" + - "afrom-nyfrom-ohkurafrom-oketogurafrom-orfrom-padovaksdalfrom-pra" + - "tohmandalfrom-ris-a-designerfrom-schmidtre-gauldalfrom-sdfrom-tn" + - "from-txn--1lqs03nfrom-utsiracusaikisarazurecontainerdpolicefrom-" + - "val-daostavalleyfrom-vtrentin-sudtirolfrom-wafrom-wielunnerfrom-" + - "wvallee-aosteroyfrom-wyfrosinonefrostalowa-wolawafroyahikobierzy" + - "cefstcgroupgfoggiafujiiderafujikawaguchikonefujiminokamoenairlin" + - "edre-eikerfujinomiyadattowebcampinashikiminohostre-totendofinter" + - "net-dnsaliasiafujiokayamangonohejis-a-doctorayfujisatoshonairpor" + - "tland-4-salernoboribetsuckservemp3fujisawafujishiroishidakabirat" + - "oridefenseljordfujitsurugashimangyshlakasamatsudovre-eikerfujixe" + - "roxn--1lqs71dfujiyoshidavvenjargap-northeast-3fukayabeatservep2p" + - "harmacienservepicservequakefukuchiyamadavvesiidappnodebalancerti" + - "ficationfukudominichristiansburgrondarfukuis-a-financialadvisor-" + - "aurdalfukumitsubishigakishiwadazaifudaigojomedio-campidano-medio" + - "campidanomediofukuokazakisofukushimaniwakuratefukuroishikarikatu" + - "rindalfukusakisosakitagawafukuyamagatakahatakaishimoichinosekiga" + - "harafunabashiriuchinadafunagatakamatsukawafunahashikamiamakusats" + - "umasendaisennangooglecodespotrentin-sued-tirolfundaciofuoiskujuk" + - "uriyamannorfolkebibleirvikaufenfuosskoczowilliamhillfurnitureggi" + - "o-emilia-romagnakatombetsumitakagiizefurubirafurudonostiaafuruka" + - "wairtelebitbridgestonekobayashikshacknetcimbarcelonagawalmartatt" + - "oolforgehimejiitatebayashijonawatempresashibetsukuiiyamanouchiku" + - "hokuryugasakitaurayasudaustrheimatunduhrennesoyokosukanumazuryok" + - "oteastcoastaldefenceatonsbergjerdrumemergencyachts3-ca-central-1" + - "fusodegaurafussaintlouis-a-anarchistoireggiocalabriafutabayamagu" + - "chinomigawafutboldlygoingnowhere-for-morenakatsugawafuttsurugimp" + - "eriafuturecmservesarcasmatartanddesignfuturehostingfuturemailing" + - "fvgfylkesbiblackbaudcdn77-securebungoonord-odalfyresdalhangoutsy" + - "stemscloudhannanmokuizumodenaklodzkochikushinonsenergyhannosegaw" + - "ahanyuzenhapmircloudharstadharvestcelebrationhasamarburghasamina" + - "mi-alpsharis-a-hunterhashbanghasudahasura-appharmacysharphdfcban" + - "kazoologyhasvikazunow-dnshawaiijimaritimoduminamimakis-a-knightp" + - "ointtohobby-sitehatogayaitakaokalmykiahatoyamazakitakamiizumisan" + - "ofidelityhatsukaichikaiseiheijis-a-landscaperugiahattfjelldalhay" + - "ashimamotobungotakadagestangeorgeorgiahazuminobusells-for-usrcfa" + - "stlylbamblebesbyglandroverhalla-speziaustinnavigationavoizumizak" + - "ibigawajudaicable-modemocraciabruzzoologicalvinklein-addrammenuo" + - "rochesterimo-i-ranaamesjevuemielno-ipifonyaaarborteaches-yogasaw" + - "aracingdyniaetnabudapest-a-la-masion-riopretobamaceratabuseating" + - "-organic66helsinkitakatakarazukaluganskygearapphiladelphiaareadm" + - "yblogspotrentino-a-adigehembygdsforbundhemneshellaspeziahemsedal" + - "hepforgeherokussldheroyhgtvallee-d-aosteigenhidorahigashiagatsum" + - "agoianiahigashichichibunkyonanaoshimageandsoundandvisionthewifia" + - "tmallorcadaqueshimokawahigashihiroshimanehigashiizumozakitakyush" + - "uaiahigashikagawahigashikagurasoedahigashikawakitaaikitamihamada" + - "higashikurumeetrentino-aadigehigashimatsushimarcheapigeelvinckdd" + - "iethnologyhigashimatsuyamakitaakitadaitoigawahigashimurayamamoto" + - "rcycleshimokitayamahigashinarusells-itrentino-alto-adigehigashin" + - "ehigashiomihachimanagementrentino-altoadigehigashiosakasayamanak" + - "akogawahigashishirakawamatakasagoppdalhigashisumiyoshikawaminami" + - "aikitamotosumy-gatewayhigashitsunoshiroomurahigashiurausukitanak" + - "agusukumodernhigashiyamatokoriyamanashiibahccavuotnagareyamainte" + - "nancehigashiyodogawahigashiyoshinogaris-a-lawyerhiraizumisatohno" + - "shoooshikamaishimofusartshimonitayanagithubusercontentrentino-s-" + - "tirolhirakatashinagawahiranairtrafficplexus-1hirarahiratsukagawa" + - "hirayaizuwakamatsubushikusakadogawahistorichouseshimonosekikawah" + - "itachiomiyagildeskaliszhitachiotagotembaixadahitraeumtgeradelmen" + - "horstalbanshimosuwalkis-a-liberalhjartdalhjelmelandholeckodairah" + - "olidayhomeiphilatelyhomelinkitoolsztynsettlershimotsukehomelinux" + - "n--1qqw23ahomeofficehomesecuritymacaparecidahomesecuritypchristm" + - "aseratiresandvikcoromantovalle-d-aostatic-accessanfranciscofreak" + - "unemurorangehirnrtoyotomiyazakinzais-a-candidatehomesenseeringho" + - "meunixn--2m4a15ehondahongotpantheonsitehonjyoitakasakitashiobara" + - "hornindalhorsellsyourhomegoodshimotsumahorteneis-a-libertarianho" + - "spitalhoteleshinichinanhotmailhoyangerhoylandetroitskypehumaniti" + - "eshinjournalismailillesandefjordhurdalhurumajis-a-linux-useranis" + - "hiaritabashikaoirminamiminowahyllestadhyogoris-a-llamarriottrent" + - "ino-stirolhyugawarahyundaiwafuneis-very-badajozis-very-evillagei" + - "s-very-goodyearis-very-niceis-very-sweetpepperis-with-thebandois" + - "leofmanaustdaljevnakershuscultureggioemiliaromagnamsskoganeis-a-" + - "nascarfanjewelryjewishartgalleryjfkharkivalleedaostejgorajlljls-" + - "sto1jmphotographysiojnjcphonefosshintomikasaharajoyentrentino-su" + - "edtiroljoyokaichibajddarchitecturealtorlandjpnjprshiojirishirifu" + - "jiedajurkosherbrookegawakoshimizumakizunokunimimatakayamarylandk" + - "oshunantankhersonkosugekotohiradomainsurehabmerkotourakouhokutam" + - "akis-a-patsfankounosupplieshirakokaminokawanishiaizubangekouyama" + - "shikekouzushimashikis-a-personaltrainerkozagawakozakis-a-photogr" + - "apherokuapphilipsyno-dshinjukumanowtvalleeaosteinkjerusalembroid" + - "erykozowindmillkpnkppspdnshiranukamitsuekrasnikahokutokashikis-a" + - "-playershifteditchyouriphoenixn--2scrj9chromedicaltanissettaishi" + - "nomakinkobeardubaiduckdnsangokrasnodarkredstonekristiansandcatsh" + - "iraois-a-republicancerresearchaeologicaliforniakristiansundkrods" + - "heradkrokstadelvaldaostarostwodzislawindowskrakowinnershiraokamo" + - "gawakryminamioguni5kumatorinokumejimasoykumenantokigawakunisakis" + - "-a-rockstarachowicekunitachiarailwaykunitomigusukumamotoyamashik" + - "okuchuokunneppubtlshiratakahagitlaborkunstsammlungkunstunddesign" + - "kuokgroupilotshishikuis-a-socialistdlibestadkureisenkurgankurobe" + - "laudibleasingleshisognekurogiminamiashigarakuroisoftwarezzokurom" + - "atsunais-a-soxfankurotakikawasakis-a-studentalkushirogawakustana" + - "is-a-teacherkassyncloudkusupplykutchanelkutnokuzumakis-a-techiet" + - "is-a-musiciankvafjordkvalsundkvamlidlugolekadenagaivuotnagaokaky" + - "otambabyenebakkeshibechambagriculturennebudejjuedischesapeakebay" + - "ernukvanangenkvinesdalkvinnheradkviteseidatingkvitsoykwpspectrum" + - "inamisanrikubetsurfastvps-serveronakasatsunairguardiannakadomari" + - "nebraskauniversitychyattorneyagawakembuchikumagayagawakkanaibets" + - "ubamericanfamilydsclouderackmazerbaijan-mayen-rootaribeiraogashi" + - "madachicagoboatsassaris-a-conservativegarsheis-a-cpadualstackher" + - "o-networkinggroupassenger-associationkzmissileluxembourgmisugito" + - "kuyamatsumotofukemitourismolanxesshitaramamitoyoakemiuramiyazure" + - "websiteshikagamiishibukawamiyotamanomjondalenmlbfanmontrealestat" + - "efarmequipmentrentinoa-adigemonza-brianzapposhizukuishimogosenmo" + - "nza-e-della-brianzaptokyotangotsukitahatakamoriokakegawamonzabri" + - "anzaramonzaebrianzamonzaedellabrianzamoonscaleforcemordoviamoriy" + - "amatsunomoriyoshiminamiawajikis-an-actormormonstermoroyamatsusak" + - "ahoginankokubunjis-an-actresshinshinotsurgerymortgagemoscowioshi" + - "zuokanagawamoseushistorymosjoenmoskeneshoppingmosshopwarendalenu" + - "gmosvikhmelnytskyivaomoteginowaniihamatamakawajimansionshoujis-a" + - "n-anarchistoricalsocietymoviemovimientolgamozilla-iotrentinoaadi" + - "gemtranbymuenstermuginozawaonsenmuikamisatokaizukamikitayamatsur" + - "is-an-artistgorymukoebenhavnmulhouseoullensvanguardmunakatanemun" + - "cienciamuosattemupimientakkoelnmurmanskhplaystation-cloudmurotor" + - "craftrentinoalto-adigemusashimurayamatsushigemusashinoharamuseet" + - "rentinoaltoadigemuseumverenigingmusicargodaddyn-vpndnshowamutsuz" + - "awamy-vigorgemy-wanggouvichungnamdalseidfjordyndns-mailubindalub" + - "lindesnesanjotoyotsukaidomyactivedirectorymyasustor-elvdalmycdn7" + - "7-sslattuminamitanemydattolocalhistorymyddnskingmydissentrentino" + - "s-tirolmydobisshikis-an-engineeringmydroboehringerikemydshowtime" + - "lhusdecorativeartshriramsterdamnserverbaniamyeffectrentinostirol" + - "myfastly-terrariuminamiuonumasudamyfirewallonieruchomoscienceand" + - "industrynmyforuminamiyamashirokawanabelembetsukubankhmelnitskiya" + - "marumorimachidamyfritzmyftpaccesshwitdklabudhabikinokawabarthads" + - "electrentin-suedtirolmyhome-servermyjinomykolaivaporcloudmymaile" + - "rmymediapchurcharternidyndns-office-on-the-webhareidsbergentingr" + - "ongausdalucaniamyokohamamatsudamypepinkmpspbarclays3-sa-east-1my" + - "petsienarviikamishihoronobeauxartsandcraftsigdalmyphotoshibalati" + - "nogiftsilknx-serversailleshioyandexcloudmypictetrentinosud-tirol" + - "mypsxn--32vp30haebaruericssongdalenviknakayamaoris-a-geekautokei" + - "notteroymysecuritycamerakermyshopblocksimple-urlmytis-a-bookkeep" + - "erspectakasugais-an-entertainermytuleaprendemasakikonaikawachina" + - "ganoharamcoachampionshiphoptobishimadridvagsoygardendoftheintern" + - "etlifyis-bytomaritimekeepingmyvncircustomer-ociprianiigataitogit" + - "suldaluccarbonia-iglesias-carboniaiglesiascarboniamywirepbodynam" + - "ic-dnsirdalplatformshangrilapyplatter-appioneerplatterpippugliap" + - "lazaplcube-serversicherungplumbingoplurinacionalpodhalevangerpod" + - "lasiellaktyubinskiptveterinaireadthedocscappgafannefrankfurtrent" + - "inosudtirolpodzonepohlpoivronpokerpokrovskomakiyosunndalpolitica" + - "rrierpolitiendapolkowicepoltavalle-aostathellewismillerpomorzesz" + - "owithgoogleapiszponpesaro-urbino-pesarourbinopesaromasvuotnaroyp" + - "onypordenonepornporsangerporsangugeporsgrunnanyokoshibahikariwan" + - "umatamayufuelveruminanopoznanpraxis-a-bruinsfanprdpreservationpr" + - "esidioprgmrprimelbourneprincipeprivatizehealthinsuranceprofesion" + - "alprogressivenneslaskerrylogisticslupskomatsushimarylhurstjordal" + - "shalsenpromombetsurgeonshalloffameiwamassa-carrara-massacarraram" + - "assabusinessebyklecznagasukepropertyprotectionprotonetrentinosue" + - "d-tirolprudentialpruszkowithyoutuberspacekitagatargivestbytemark" + - "omforbarefootballooningjerstadotsuruokakamigaharauthordalandds3-" + - "eu-central-1prvcyberlevagangaviikanonjis-certifieducatorahimeshi" + - "mamateramobaraprzeworskogptplusgardenpulawypupittsburghofficialp" + - "vhagakhanamigawapvtrentinosuedtirolpwcistrondheimmobilienissayok" + - "kaichiropractichitachinakagawassamukawatarightathomeftparocherni" + - "governmentksatxn--12c1fe0bradescorporationrenderpzqhagebostadqld" + - "qponiatowadaqslingqualifioappiwatequickconnectrentinsud-tirolqui" + - "cksytestingquipelementslzqvcitadeliveryggeesusonosuzakanazawasuz" + - "ukaneyamazoesuzukis-into-animegurownprovidersvalbardunloppacific" + - "ivilaviationissedalucernesveiosvelvikomorotsukaminoyamaxunjargas" + - "vizzerasvn-reposologneswidnicasacamdvrcampinagrandebuilderschles" + - "ischesolundbeckommunalforbundswidnikkokonoeswiebodzin-butterswif" + - "tcoverswinoujscienceandhistoryswissmarterthanyousynology-disksta" + - "tionsynology-dsolutionsnoasakakinokiaturystykanmakiwientuscanytu" + - "shuissier-justicetuvalle-daostaticsootuxfamilytwmailvestnesopotr" + - "entinsudtirolvestre-slidreviewsaitoshimayfirstockholmestrandvest" + +const text = "9guacuiababia-goracleaningroks-theatree12hpalermomahachijolstere" + + "trosnubalsfjorddnslivelanddnss3-ap-south-1kappchizip6116-b-datai" + + "ji234lima-cityeatselinogradult3l3p0rtatamotors3-ap-northeast-133" + + "7birkenesoddtangenovaranzaninohekinannestadivttasvuotnakamuratak" + + "ahamalselvendrellimitediyukuhashimojindianapolis-a-bloggerbirthp" + + "lacebjarkoyurihonjournalistjohninomiyakonojorpelandnpanamatta-va" + + "rjjatjeldsundrangedalimoliseminebjerkreimdbamblebesbyglandroverh" + + "alla-speziaustevollaziobihirosakikamijimatsuzakibigawagrocerybni" + + "keisenbahnatuurwetenschappenaumburgdyniabogadobeaemcloud66bjugni" + + "eznord-frontierblackfridayusuharabloombergbauernirasakindianmark" + + "etingjesdalinkyard-cloudyclusterbloxcms3-website-us-west-2blueda" + + "gestangeologyusuisservehumourbmoattachments5yuulmemorialivornoce" + + "anographiquebmsakyotanabellunord-aurdalpha-myqnapcloudaccesscamb" + + "ridgeiseiyoichippubetsubetsugarugbydgoszczecinemagentositechnolo" + + "gyuzawabmweddingjovikariyameinforumzjampagexlombardynaliaskimits" + + "ubatamibugattiffanycateringebuildingladefinimakanegasakirabnrwed" + + "eploybomloabathsbcatholicaxiashorokanaiebondray-dnstracebonnishi" + + "azaindielddanuorrindigenaklodzkodairabookinghostedpictethnologyb" + + "oomlair-traffic-controlleyboschaefflerdalomzaporizhzhegurindustr" + + "iabostikarlsoybostonakijinsekikogentappsselfipanasonichernihivgu" + + "bsalangenishigocelotenkawabotanicalgardenishiharabotanicgardenis" + + "hiizunazukindustriesteamsterdamnserverbaniabotanynysagaeroclubme" + + "decincinnationwidealerbouncemerckmsdnipropetrovskjervoyagets-itj" + + "maxxxboxenapponazure-mobilebounty-fullensakerrypropertiesalondon" + + "etskarmoyboutiquebechernivtsiciliabozen-sudtirolondrinamsskogane" + + "infinitintelligencebozen-suedtirolorenskoglassassinationalherita" + + "gebplacedogawarabikomaezakirunorddalottebrandywinevalleybrasilia" + + "brindisibenikinderoybristoloseyouriparachutingleezebritishcolumb" + + "ialowiezaganishikatakinouebroadcastlebtimnetzlglitchattanooganor" + + "dlandrayddnsfreebox-osascoli-picenordre-landraydnsupdaternopilaw" + + "atchesaltdalottokonamegatakazakinternationalfirearmsaludrivefsni" + + "llfjordrobaknoluoktachikawakuyabukievennodesadoes-itvedestrandru" + + "dupontariobranconakaniikawatanagurabroadwaybroke-itjomeloyalisto" + + "ragebrokerbronnoysundurbanamexhibitionishikatsuragit-reposalvado" + + "rdalibabalena-devicesalzburgliwicebrothermesaverdealstahaugesund" + + "erseaportsinfolldalouvreisenishikawazukamisunagawabrowsersafetym" + + "arketsamegawabrumunddalowiczest-le-patronishimerabrunelastxfinit" + + "ybrusselsamnangerbruxellesampalacebryansklepparaglidinglobalasho" + + "vhachinohedmarkarpaczeladzparisor-fronishinomiyashironocparliame" + + "ntjxjavald-aostarnbergloboavistanbulsan-sudtirolpusercontentkmax" + + "xn--0trq7p7nnishinoomotegoddabrynewhollandurhamburglogowegroweib" + + "olognagareyamakeupowiathletajimabaridagawalbrzycharitydalaskanit" + + "tedallasalleangaviikaascolipicenodumemsettsupportksatxn--11b4c3d" + + "ynathomebuiltwithdarkaruizawabuskerudinewjerseybuzentsujiiebuzzw" + + "eirbwellbeingzonebzhitomirumalatvuopmicrolightingloppenzaolbia-t" + + "empio-olbiatempioolbialystokkepnogatagajobojintuitmparmattelekom" + + "munikationishinoshimatsuurabzzcolumbusheycommunexus-2community-p" + + "rochowicecomoarekecomparemarkerryhotelsaobernardocompute-1comput" + + "erhistoryofscience-fictioncomsecuritytacticsxn--12cfi8ixb8luxury" + + "condoshichinohealth-carereformitakeharaconferenceconstructioncon" + + "suladonnagatorodoyconsultanthropologyconsultingrondarcontactozsd" + + "eltajirittogliattis-a-chefashioncontagematsubaracontemporaryarte" + + "ducationalchikugodontexistmein-iservebeercontractorskenconventur" + + "eshinodearthruherecipescaravantaacookingchannelsdvrdnsdojoburgro" + + "ngausdaluzerncoolvivanovoldacooperativano-frankivskolefrakkestad" + + "yndns1copenhagencyclopedichitosetogakushimotoganewspapercoproduc" + + "tionsaogoncartoonartdecologiacorporationcorsicagliaricoharuovatm" + + "allorcadaquesaotomeldalcorvettemasekashiwazakiyosemitecosenzakop" + + "anelblagrarchaeologyeongbuk0cosidnsfor-better-thanawassamukawata" + + "rikuzentakatajimidorissagamiharacostumedicinaharimalopolskanland" + + "ynnsapporocouchpotatofriesardegnaroycouklugsmilegallocus-3counci" + + "lcouponsardiniacozoracq-acranbrookuwanalyticsarlcrdynservebbsarp" + + "sborgrossetouchihayaakasakawaharacreditcardynulvikasserversaille" + + "sarufutsunomiyawakasaikaitakofuefukihaboromskogroundhandlingrozn" + + "ycreditunioncremonashgabadaddjaguarqcxn--12co0c3b4evalleaostavan" + + "gercrewiencricketrzyncrimeast-kazakhstanangercrotonecrownipartsa" + + "sayamacrsvpartycruisesasebofageometre-experts-comptablesaskatche" + + "wancryptonomichigangwoncuisinellajollamericanexpressexyculturalc" + + "entertainmentrani-andria-barletta-trani-andriacuneocupcakecuriti" + + "backyardsassaris-a-conservativegarsheis-a-cpadualstackhero-netwo" + + "rkinggroupasadenarashinocurvalled-aostaverncymrussiacyonabarumet" + + "lifeinsurancecyouthachiojiyaitakanezawafetsundyroyrvikingrpassag" + + "ensaudafguidegreefhvalerfidoomdnsiskinkyotobetsulikes-piedmontic" + + "ellodingenfieldfigueresinstaginguitarsavonarusawafilateliafilege" + + "ar-audnedalnfilegear-deatnunusualpersonfilegear-gbizfilegear-ief" + + "ilegear-jpmorganfilegear-sgujoinvilleitungsenfilminamiechizenfin" + + "alfinancefineartsaxofinlandfinnoyfirebaseappassenger-association" + + "firenetranoyfirenzefirestonefirmdalegoldpoint2thisamitsukefishin" + + "golffanschoenbrunnfitjarvodkafjordvalledaostargetmyiphostre-tote" + + "ndofinternet-dnschokokekschokoladenfitnessettlementransportefjal" + + "erflesbergulenflickragerogerscholarshipschoolschulezajskasuyanai" + + "zunzenflightschulserverflirfloginlinefloraflorencefloridatsunanj" + + "oetsuwanouchikujogaszkolancashirecreationfloripaderbornfloristan" + + "ohatakaharuslivinghistoryflorokunohealthcareerschwarzgwangjunipe" + + "rflowerschweizfltransurlflynnhosting-clusterfndfor-ourfor-somedi" + + "zinhistorischesciencecentersciencehistoryfor-theaterforexrothach" + + "irogatakaokalmykiaforgotdnscientistordalforli-cesena-forlicesena" + + "forlillehammerfeste-ipatriaforsaleikangerforsandasuologoipavianc" + + "arrdfortalfortmissoulancasterfortworthadanorthwesternmutualfosne" + + "scjohnsonfotaruis-a-democratrapaniizafoxfordebianfozfredrikstadt" + + "vscrapper-sitefreeddnsgeekgalaxyfreedesktopensocialfreemasonryfr" + + "eesitexaskoyabearalvahkikuchikuseikarugalsaceofreetlscrappingunm" + + "anxn--1ctwolominamatarnobrzegyptianfreiburguovdageaidnusrcfastly" + + "lbananarepublicaseihicampobassociatest-iservecounterstrikehimeji" + + "itatebayashijonawatempresashibetsukuiiyamanouchikuhokuryugasakit" + + "auraustinnaval-d-aosta-valleyokosukanumazuryokoteastcoastaldefen" + + "ceatonsbergivingjemnes3-eu-central-1freseniuscountryestateofdela" + + "wareggio-calabriafribourgushikamifuranorth-kazakhstanfriuli-v-gi" + + "uliafriuli-ve-giuliafriuli-vegiuliafriuli-venezia-giuliafriuli-v" + + "eneziagiuliafriuli-vgiuliafriuliv-giuliafriulive-giuliafriuliveg" + + "iuliafriulivenezia-giuliafriuliveneziagiuliafriulivgiuliafrlfrog" + + "anscrysechocolatelemarkarumaifarsundyndns-homednsamsungmodelling" + + "mxn--12c1fe0bradescotlandyndns-iparochernigovernmentoyotaparsand" + + "nessjoenishiokoppegardyndns-mailubindalublindesnesandoyfrognfrol" + + "andfrom-akrehamnfrom-alfrom-arfrom-azfrom-capetownnews-stagingwi" + + "ddleksvikaszubyfrom-coffeedbackplaneapplinzis-a-designerfrom-ctr" + + "avelchannelfrom-dchofunatoriginstitutelevisionthewifiatoyotomiya" + + "zakinuyamashinatsukigatakashimarnardalucaniafrom-dedyn-berlincol" + + "nfrom-flanderserveirchonanbulsan-suedtiroluccarbonia-iglesias-ca" + + "rboniaiglesiascarboniafrom-gaulardalfrom-hichisochildrensgardenf" + + "rom-iafrom-idfrom-ilfrom-in-brbar0emmafann-arboretumbriamallamac" + + "eiobbcg12038from-kserveminecraftravelersinsurancefrom-kyowariasa" + + "hikawawiiheyakumoduminamifuranofrom-lanciafrom-mamurogawafrom-md" + + "from-meeresistancefrom-mifunefrom-mnfrom-modalenfrom-mservemp3fr" + + "om-mtnfrom-nctulangevagrigentomologyeonggiehtavuoatnabudapest-a-" + + "la-masion-riopretobamaceratabuseating-organichoseiroumuenchenish" + + "itosashimizunaminamibosogndalucernefrom-ndfrom-nefrom-nh-servebl" + + "ogsiteleafamilycompanyanagawafflecellclaimservep2pfizerfrom-njaw" + + "orznoticiasnesoddenmarkhangelskjakdnepropetrovskiervaapsteiermar" + + "katowicefrom-nminamiiserniafrom-nvallee-aosteroyfrom-nyfrom-ohku" + + "rafrom-oketogurafrom-orfrom-padovaksdalfrom-pratohmandalfrom-ris" + + "-a-doctorayfrom-schmidtre-gauldalfrom-sdfrom-tnfrom-txn--1lqs03n" + + "from-utsiracusaikisarazurecontainerdpolicefrom-val-daostavalleyf" + + "rom-vtrdfrom-wafrom-wiardwebhostingxn--1lqs71dfrom-wvallee-d-aos" + + "teigenfrom-wyfrosinonefrostalowa-wolawafroyahooguyfstcgroupgfogg" + + "iafujiiderafujikawaguchikonefujiminokamoenairguardiannakadomarin" + + "ebraskauniversitychyattorneyagawakembuchikumagayagawakkanaibetsu" + + "bamericanfamilydsclouderackmazerbaijan-mayen-rootaribeiraogashim" + + "adachicagoboatservepicservequakefujinomiyadattowebcampinashikimi" + + "nohostfoldnavyfujiokayamangonohejis-a-financialadvisor-aurdalfuj" + + "isatoshonairlinedre-eikerfujisawafujishiroishidakabiratoridefens" + + "eljordfujitsurugashimangyshlakasamatsudopaasiafujixeroxn--1qqw23" + + "afujiyoshidavvenjargap-northeast-3fukayabeatservesarcasmatartand" + + "designfukuchiyamadavvesiidappnodebalancertificationfukudomigawaf" + + "ukuis-a-geekatsushikabeeldengeluidfukumitsubishigakishiwadazaifu" + + "daigojomedio-campidano-mediocampidanomediofukuokazakisofukushima" + + "niwakuratextileirfjordfukuroishikarikaturindalfukusakisosakitaga" + + "wafukuyamagatakahatakaishimoichinosekigaharafunabashiriuchinadaf" + + "unagatakamatsukawafunahashikamiamakusatsumasendaisennangooglecod" + + "espotrentin-sud-tirolfundaciofunkfeuerfuoiskujukuriyamannore-og-" + + "uvdalfuosskoczowildlifedorainfracloudfrontdoorfurnitureggio-emil" + + "ia-romagnakasatsunairportland-4-salernoboribetsuckservicesevasto" + + "polefurubirafurudonostiaafurukawairtelebitbridgestonekobayashiks" + + "hacknetcimbar1fusodegaurafussaintlouis-a-anarchistoireggiocalabr" + + "iafutabayamaguchinomihachimanagementrentin-sudtirolfutboldlygoin" + + "gnowhere-for-morenakatombetsumitakagiizefuttsurugimperiafuturecm" + + "sevenassisicilyfuturehostingfuturemailingfvgfyresdalhangoutsyste" + + "mscloudhannanmokuizumodenakayamapartmentsharpharmacienshawaiijim" + + "aritimoldeloittemp-dnshellaspeziahannosegawahanyuzenhapmircloudh" + + "arstadharvestcelebrationhasamarburghasaminami-alpshimokawahashba" + + "nghasudahasura-appharmacyshimokitayamahasvikatsuyamarugame-hosty" + + "hostinghatogayaizuwakamatsubushikusakadogawahatoyamazakitakamiiz" + + "umisanofidelityhatsukaichikaiseiheijis-a-landscaperugiahattfjell" + + "dalhayashimamotobungotakadancehazuminobusells-for-utwentehelsink" + + "itakatakarazukaluganskygearapphdfcbankaufenhembygdsforbundhemnes" + + "himonitayanagithubusercontentrentin-suedtirolhemsedalhepforgeher" + + "okusslattuminamiizukaminoyamaxunjargaheroyhgtvalleeaosteinkjerus" + + "alembroideryhidorahigashiagatsumagoianiahigashichichibunkyonanao" + + "shimageandsoundandvisionrenderhigashihiroshimanehigashiizumozaki" + + "takyushuaiahigashikagawahigashikagurasoedahigashikawakitaaikitam" + + "ihamadahigashikurumeetrentino-a-adigehigashimatsushimarcheapigee" + + "lvinckautokeinotteroyhigashimatsuyamakitaakitadaitoigawahigashim" + + "urayamamotorcycleshimonosekikawahigashinarusells-itrentino-aadig" + + "ehigashinehigashiomitamamurausukitamotosumy-gatewayhigashiosakas" + + "ayamanakakogawahigashishirakawamatakasagopocznorfolkebibleirvika" + + "zoologyhigashisumiyoshikawaminamiaikitanakagusukumodernhigashits" + + "unoshiroomurahigashiurawa-mazowszexnetrentino-alto-adigehigashiy" + + "amatokoriyamanashiibahccavuotnagaraholtaleniwaizumiotsukumiyamaz" + + "onawsmpplanetariuminamimakis-a-lawyerhigashiyodogawahigashiyoshi" + + "nogaris-a-liberalhiraizumisatohnoshoooshikamaishimofusartshimosu" + + "walkis-a-libertarianhirakatashinagawahiranairtrafficplexus-1hira" + + "rahiratsukagawahirayakagehistorichouseshimotsukehitachiomiyagild" + + "eskaliszhitachiotagotembaixadahitraeumtgeradelmenhorstalbanshimo" + + "tsumahjartdalhjelmelandholeckochikushinonsenergyholidayhomegoods" + + "hinichinanhomeiphiladelphiaareadmyblogspotrentino-altoadigehomel" + + "inkitoolsztynsettlershinjournalismailillesandefjordhomelinuxn--2" + + "m4a15ehomeofficehomesecuritymacaparecidahomesecuritypchoshibuyac" + + "htsandvikcoromantovalle-d-aostatic-accessanfranciscofreakunemuro" + + "rangehirnrtoyotsukaidohtawaramotoineppueblockbustermezhomesensee" + + "ringhomeunixn--2scrj9choyodobashichikashukujitawarahondahongotpa" + + "ntheonsitehonjyoitakasakitashiobarahornindalhorsellsyourhomeftph" + + "ilatelyhorteneis-a-linux-useranishiaritabashikaoirminamiminowaho" + + "spitalhoteleshinjukumanowtvalleedaostehotmailhoyangerhoylandetro" + + "itskypehumanitieshinkamigotoyohashimototalhurdalhurumajis-a-llam" + + "arriottrentino-s-tirolhyllestadhyogoris-a-musicianhyugawarahyund" + + "aiwafuneis-very-evillageis-very-goodyearis-very-niceis-very-swee" + + "tpepperis-with-thebandownloadisleofmanaustdaljetztrentino-sudtir" + + "oljevnakershuscultureggioemiliaromagnamsosnowiechristiansburgret" + + "akanabeautysvardoesntexisteingeekasaokamikoaniikappuboliviajessh" + + "eimpertrixcdn77-ssldyndns-office-on-the-weberjewelryjewishartgal" + + "leryjfkfhappoujgorajlljls-sto1jmphotographysiojnjcloudjiffylkesb" + + "iblackbaudcdn77-securebungoonord-odaljoyentrentino-sued-tiroljoy" + + "okaichibajddarchitecturealtorlandjpnjprshirakokamiminershiranuka" + + "mitsuejurkosakaerodromegallupinbarclaycards3-sa-east-1koseis-a-p" + + "ainteractivegaskvollkosherbrookegawakoshimizumakizunokunimimatak" + + "ayamarylandkoshunantankharkivanylvenicekosugekotohiradomainsureg" + + "ruhostingkotourakouhokutamakis-a-patsfankounosupplieshiraois-a-p" + + "ersonaltrainerkouyamashikekouzushimashikis-a-photographerokuapph" + + "ilipsynology-diskstationkozagawakozakis-a-playershifteditchyouri" + + "phoenixn--30rr7ykozowinbarclays3-us-east-2kpnkppspdnshiraokamoga" + + "wakrasnikahokutokashikis-a-republicancerresearchaeologicaliforni" + + "akrasnodarkredstonekristiansandcatshiratakahagitlaborkristiansun" + + "dkrodsheradkrokstadelvaldaostarostwodzislawindmillkryminamioguni" + + "5kumatorinokumejimasoykumenantokigawakunisakis-a-rockstarachowic" + + "ekunitachiarailwaykunitomigusukumamotoyamashikokuchuokunneppubtl" + + "shishikuis-a-socialistdlibestadkunstsammlungkunstunddesignkuokgr" + + "oupilotshisognekurehabmerkurgankurobelaudibleasingleshisuifuette" + + "rtdasnetzkurogiminamiashigarakuroisoftwarezzokuromatsunais-a-sox" + + "fankurotakikawasakis-a-studentalkushirogawakustanais-a-teacherka" + + "ssyno-dshinshinotsurgerykusupplynxn--3bst00minamisanrikubetsurfa" + + "uskedsmokorsetagayaseralingenoamishirasatogokasells-for-lessauhe" + + "radynv6kutchanelkutnokuzumakis-a-techietis-a-nascarfankvafjordkv" + + "alsundkvamfamberkeleykvanangenkvinesdalkvinnheradkviteseidatingk" + + "vitsoykwpspectruminamitanekzmishimatsumaebashimodatemissileluxem" + + "bourgmisugitokuyamatsumotofukemitourismolanxesshitaramamitoyoake" + + "miuramiyazurewebsiteshikagamiishibukawamiyotamanomjondalenmlbfan" + + "montrealestatefarmequipmentrentinoa-adigemonza-brianzapposhizuku" + + "ishimogosenmonza-e-della-brianzaptokyotangotsukitahatakamoriokak" + + "egawamonzabrianzaramonzaebrianzamonzaedellabrianzamoonscaleforce" + + "mordoviamoriyamatsunomoriyoshiminamiawajikis-an-actormormonsterm" + + "oroyamatsusakahoginankokubunjis-an-actresshintokushimamortgagemo" + + "scowindowskrakowinnershizuokanagawamoseushistorymosjoenmoskenesh" + + "oppingmosshopwarendalenugmosvikhersonmoteginowaniihamatamakawaji" + + "mansionshoujis-an-anarchistoricalsocietymoviemovimientolgamozill" + + "a-iotrentinoaadigemtranbymuenstermuginozawaonsenmuikamiokameokam" + + "akurazakiwakunigamiharumukoebenhavnmulhouseoullensvanguardmunaka" + + "tanemuncienciamuosattemupimientakkoelnmurmanskhmelnitskiyamarumo" + + "rimachidamurotorcraftrentinoalto-adigemusashimurayamatsushigemus" + + "ashinoharamuseetrentinoaltoadigemuseumverenigingmusicargodaddyn-" + + "vpndnshowamutsuzawamy-vigorgemy-wanggouvichristmaseratiresangomu" + + "tashinainvestmentsanjotoyouramyactivedirectorymyasustor-elvdalmy" + + "cdmydattolocalhistorymyddnskingmydissentrentinos-tirolmydobisshi" + + "kis-an-artistgorymydroboehringerikemydshowtimelhusdecorativearts" + + "hriramlidlugolekadenagahamaroygardendoftheinternetlifyis-an-engi" + + "neeringmyeffectrentinostirolmyfastly-terrariuminamiuonumasudamyf" + + "irewallonieruchomoscienceandindustrynmyforuminamiyamashirokawana" + + "belembetsukubankharkovaomyfritzmyftpaccesshwiosienarutomobellevu" + + "elosangelesjabbottrentinosud-tirolmyhome-servermyjinomykolaivare" + + "servehalflifestylemymailermymediapchromedicaltanissettaishinomak" + + "inkobeardubaiduckdnsannanishiwakinzais-a-candidatemyokohamamatsu" + + "damypepinkhmelnytskyivaporcloudmypetsigdalmyphotoshibalatinogift" + + "silkhplaystation-cloudmypicturesimple-urlmypsxn--3ds443gmysecuri" + + "tycamerakermyshopblocksirdalmythic-beastsjcbnpparibaselburgmytis" + + "-a-bookkeeperspectakasugais-an-entertainermytuleaprendemasakikon" + + "aikawachinaganoharamcoachampionshiphoptobishimadridvagsoyermyvnc" + + "hungnamdalseidfjordyndns-picsannohelplfinancialukowhalingrimstad" + + "yndns-remotewdyndns-serverisignissandiegomywirepaircraftingvollo" + + "mbardiamondslupsklabudhabikinokawabarthadselectrentin-sued-tirol" + + "platformshangrilapyplatter-appioneerplatterpippugliaplazaplcube-" + + "serverplumbingoplurinacionalpodhalevangerpodlasiellaktyubinskipt" + + "veterinaireadthedocscappgafannefrankfurtrentinosudtirolpodzonepo" + + "hlpoivronpokerpokrovsknx-serversicherungpoliticarrierpolitiendap" + + "olkowicepoltavalle-aostathellewismillerpomorzeszowitdkomaganepon" + + "pesaro-urbino-pesarourbinopesaromasvuotnaritakurashikis-bytomari" + + "timekeepingponypordenonepornporsangerporsangugeporsgrunnanyokosh" + + "ibahikariwanumatamayufuelveruminanopoznanpraxis-a-bruinsfanprdpr" + + "eservationpresidioprgmrprimelbourneprincipeprivatizehealthinsura" + + "nceprofesionalprogressivenneslaskerrylogisticsnoasakakinokiaprom" + + "ombetsurgeonshalloffameiwamassa-carrara-massacarraramassabusines" + + "sebykleclerchurcharternidyndns-webhareidsbergentingripepropertyp" + + "rotectionprotonetrentinosued-tirolprudentialpruszkowithgoogleapi" + + "szprvcyberlevagangaviikanonjis-certifieducatorahimeshimamateramo" + + "baraprzeworskogptplusgardenpulawypupittsburghofficialpvhagakhana" + + "migawapvtrentinosuedtirolpwcircustomer-ociprianiigataitogitsulda" + + "luroypzqhagebostadqldqponiatowadaqslingqualifioappiwatequickconn" + + "ectrentinsud-tirolquicksytestingquipelementsokananiimihoboleslaw" + + "iecistrondheimmobilienissayokkaichiropractichernovtsyncloudyndns" + + "-at-homedepotenzamamidsundyndns-at-workisboringlugmbhartipscbgmi" + + "nakamichiharaqvcitadeliveryggeesusonosuzakanazawasuzukaneyamazoe" + + "suzukis-into-animegurownprovidersvalbardunloppacificitichirurgie" + + "ns-dentistes-en-francesvcivilaviationissedalutskashibatakatsukiy" + + "osatokamachintaifun-dnsaliasanokashiharasveiosvelvikommunalforbu" + + "ndsvizzerasvn-reposolutionsokndalswidnicasacamdvrcampinagrandebu" + + "ilderschlesischesomaswidnikkokonoeswiebodzin-butterswiftcoverswi" + + "noujscienceandhistoryswissmarterthanyousynology-dsomnarviikamisa" + + "tokaizukameyamatotakadatuscanytushuissier-justicetuvalle-daostat" + + "icsor-varangertuxfamilytwmailvestre-slidreportrevisohughesoovest" + "re-totennishiawakuravestvagoyvevelstadvibo-valentiavibovalentiav" + - "ideovillasor-odalvinnicasadelamonedancevinnytsiavipsinaappixolin" + - "ovirginiavirtual-userveftpizzavirtualservervirtualuservegame-ser" + - "vervirtueeldomein-vigorlicevirtuelvisakegawaviterboknowsitallviv" + - "olkenkundenvixn--3bst00miniservervlaanderenvladikavkazimierz-dol" + - "nyvladimirvlogintoyonezawavminnesotaketaketomisatokorozawavologd" + - "anskongsbergvolvolkswagentsor-varangervolyngdalvoorloperaunitero" + - "is-into-carshinshirovossevangenvotevotingvotoyonowmflabsorfoldwn" + - "extdirectroandinosaureplantationworldworse-thandawowiwatsukiyono" + - "tairestaurantritonwpdevcloudwritesthisblogsytewroclawloclawekong" + - "svingerwtcminterepaircraftingvollombardiamondshisuifuettertdasne" + - "tzwtfauskedsmokorsetagayaseralingenoamishirasatogokasells-for-le" + - "ssaudawuozuwzmiuwajimaxn--42c2d9axn--45br5cylxn--45brj9civilizat" + - "ionxn--45q11civilwarmiastagets-itoyouraxn--4gbriminingxn--4it168" + - "dxn--4it797konskowolayangroupictureshirahamatonbetsurnadalxn--4p" + - "vxs4allxn--54b7fta0cclanbibaidarmeniaxn--55qw42gxn--55qx5dxn--5j" + - "s045dxn--5rtp49cldmailovecollegefantasyleaguernseyxn--5rtq34kons" + - "ulatrobeepilepsykkylvenetodayxn--5su34j936bgsgxn--5tzm5gxn--6btw" + - "5axn--6frz82gxn--6orx2rxn--6qq986b3xlxn--7t0a264clic20001wwwhosw" + - "hokksundyndns-picsannohelplfinancialukowiiheyakagexn--80adxhksor" + - "ocabalestrandabergamo-siemensncfdxn--80ao21axn--80aqecdr1axn--80" + - "asehdbarreauction-webhostingjesdalillyolasitemrxn--80aswgxn--80a" + - "ugustowmcloudxn--8ltr62konyvelolipopiemontexn--8pvr4uxn--8y0a063" + - "axn--90a3academiamicaarpkomaganexn--90aeroportalabamagasakishima" + - "baraogakibichuoxn--90aishobarakawagoexn--90azhytomyravendbarrel-" + - "of-knowledgeapplicationcloudappspotagerxn--9dbhblg6digitalxn--9d" + - "bq2axn--9et52uxn--9krt00axn--andy-iraxn--aroport-byaotsurreyxn--" + - "asky-iraxn--aurskog-hland-jnbarrell-of-knowledgestackarasjokaras" + - "uyamarshallstatebankarateu-1xn--avery-yuasakuhokkaidownloadxn--b" + - "-5gaxn--b4w605ferdxn--balsan-sdtirol-nsbsorreisahayakawakamiichi" + - "kawamisatottoris-foundationxn--bck1b9a5dre4clickashiwazakiyosemi" + - "texn--bdddj-mrabdxn--bearalvhki-y4axn--berlevg-jxaxn--bhcavuotna" + - "-s4axn--bhccavuotna-k7axn--bidr-5nachikatsuuraxn--bievt-0qa2xn--" + - "bjarky-fyasakaiminatoyookaniepcexn--bjddar-ptarumizusawaxn--blt-" + - "elabourxn--bmlo-graingerxn--bod-2nativeamericanantiquesortlandxn" + - "--bozen-sdtirol-2obanazawaxn--brnny-wuacademy-firewall-gatewayxn" + - "--brnnysund-m8accident-investigation-aptibleadpagest-mon-blogueu" + - "rovision-k3sorumincomcastresindevicenzaporizhzhiaxn--brum-voagat" + - "rogstadxn--btsfjord-9zaxn--bulsan-sdtirol-nsbarsycenterprisesaki" + - "kugawaltervistaikimobetsuitainaioirasebastopologyeongnamegawakay" + - "amagazineat-urlimanowarudautomotiveconomiasakuchinotsuchiurakawa" + - "lesundeportevadsobetsumidatlanticaseihicampobassociatest-iservec" + - "ounterstrikebinagisoccertmgrazimutheworkpccwebredirectmembers3-e" + - "u-west-1xn--c1avgxn--c2br7gxn--c3s14misakis-a-therapistoiaxn--cc" + - "k2b3barsyonlinewhampshirealtysnes3-us-gov-west-1xn--cckwcxetdxn-" + - "-cesena-forl-mcbremangerxn--cesenaforl-i8axn--cg4bkis-into-carto" + - "onshintokushimaxn--ciqpnxn--clchc0ea0b2g2a9gcdxn--comunicaes-v6a" + - "2oxn--correios-e-telecomunicaes-ghc29axn--czr694bashkiriautoscan" + - "adaeguambulanceobihirosakikamijimatsuzakibmdevelopmentatsunobira" + - "ukraanghkeymachineustargardd-dnsiskinkyotobetsulikes-piedmontice" + - "llodingenatuurwetenschappenaumburggfarmerseine164-balsfjorddnsli" + - "velanddnss3-ap-southeast-1xn--czrs0tromsakataobaomoriguchiharahk" + - "keravjuegoshikijobservableusercontentrentinsuedtirolxn--czru2dxn" + - "--czrw28basicservercelliguriaveroykenglandgcahcesuoloans3-eu-wes" + - "t-2xn--d1acj3basilicataniavocatanzarowebspacebinordreisa-hockeyn" + - "utazuerichardlikescandyn53utilitiesquare7xn--d1alfaromeoxn--d1at" + - "romsojamisonxn--d5qv7z876clinichocolatelevisionishiokoppegardynd" + - "ns-ipartinuyamashinatsukigatakashimarnardalouvreitoyosatoyokawax" + - "n--davvenjrga-y4axn--djrs72d6uyxn--djty4kooris-a-nursembokukitch" + - "enxn--dnna-grajewolterskluwerxn--drbak-wuaxn--dyry-iraxn--e1a4cl" + - "iniquenoharaxn--eckvdtc9dxn--efvn9soundcastronomy-routerxn--efvy" + - "88haibarakitahiroshimapartmentservicesevastopolexn--ehqz56nxn--e" + - "lqq16hair-surveillancexn--eveni-0qa01gaxn--f6qx53axn--fct429kope" + - "rvikharkovanylvenicexn--fhbeiarnxn--finny-yuaxn--fiq228c5hsouthc" + - "arolinatalxn--fiq64basketballfinanzgoravoues3-eu-west-3xn--fiqs8" + - "southwestfalenxn--fiqz9sowaxn--fjord-lraxn--fjq720axn--fl-ziaxn-" + - "-flor-jraxn--flw351exn--forl-cesena-fcbsspeedpartnersokananiimih" + - "oboleslawiecitichitosetogakushimotoganewportlligatmparsamsclubar" + - "towhalingriwataraidyndns-homednsamsungroks-thisayamanobeokakudam" + - "atsuexn--forlcesena-c8axn--fpcrj9c3dxn--frde-grandrapidspjelkavi" + - "komonowruzhgorodeoxn--frna-woaraisaijosoyrorospreadbettingxn--fr" + - "ya-hraxn--fzc2c9e2clintonoshoesanokasserverrankoshigayameinforum" + - "zxn--fzys8d69uvgmailxn--g2xx48clothingdustdataiwanairforcebetsui" + - "kidsmynasushiobaragusabaejrietisalatinabenonicbcn-north-1xn--gck" + - "r3f0fbsbxn--12co0c3b4evalleaostavangerxn--gecrj9cn-northwest-1xn" + - "--ggaviika-8ya47hakatanortonxn--gildeskl-g0axn--givuotna-8yasugi" + - "vingxn--gjvik-wuaxn--gk3at1exn--gls-elacaixaxn--gmq050is-into-ga" + - "messinazawaxn--gmqw5axn--h-2failxn--h1aeghakodatexn--h2breg3even" + - "espydebergxn--h2brj9c8cngrossetouchihayaakasakawaharaxn--h3cuzk1" + - "discountyxn--hbmer-xqaxn--hcesuolo-7ya35batochiokinoshimakeupowi" + - "at-band-campaniaxaurskog-holandingjemnes3-ap-southeast-2xn--hery" + - "-iraxn--hgebostad-g3axn--hkkinen-5waxn--hmmrfeasta-s4accident-pr" + - "evention-rancherkasydneyxn--hnefoss-q1axn--hobl-iraxn--holtlen-h" + - "xaxn--hpmir-xqaxn--hxt814exn--hyanger-q1axn--hylandet-54axn--i1b" + - "6b1a6a2exn--imr513nxn--indery-fyasuokanoyakumoldeloittenrikuzent" + - "akatajimidorissagamiharaxn--io0a7is-leetrentino-sud-tirolxn--j1a" + - "efbx-osauheradyndns1xn--j1amhakonexn--j6w193gxn--jlq480n2rgxn--j" + - "lq61u9w7batsfjordiscoveryombolzano-altoadigeologyomitanoceanogra" + - "phics3-us-west-1xn--jlster-byatomitamamuraxn--jrpeland-54axn--jv" + - "r189misasaguris-an-accountantshinkamigotoyohashimototalxn--k7yn9" + - "5exn--karmy-yuaxn--kbrq7oxn--kcrx77d1x4axn--kfjord-iuaxn--klbu-w" + - "oaxn--klt787dxn--kltp7dxn--kltx9axn--klty5xn--3ds443gxn--koluokt" + - "a-7ya57hakubahcavuotnagaraholtaleniwaizumiotsukumiyamazonawsmppl" + - "anetariuminamiizukamiokameokameyamatotakadaxn--kprw13dxn--kpry57" + - "dxn--kpu716fbxosavannahgaxn--kput3is-lostrolekamakurazakiwakunig" + - "amiharustkannamilanotogawaxn--krager-gyatsukanraxn--kranghke-b0a" + - "xn--krdsherad-m8axn--krehamn-dxaxn--krjohka-hwab49jdfastpanelbla" + - "grarchaeologyeongbuk0emmafann-arboretumbriamallamaceiobbcg12038x" + - "n--ksnes-uuaxn--kvfjord-nxaxn--kvitsy-fyatsushiroxn--kvnangen-k0" + - "axn--l-1fairwindsrlxn--l1accentureklamborghinikolaeventsrvareser" + - "vehalflifestylexn--laheadju-7yawaraxn--langevg-jxaxn--lcvr32dxn-" + - "-ldingen-q1axn--leagaviika-52bauhausposts-and-telecommunications" + - "3-us-west-2xn--lesund-huaxn--lgbbat1ad8jelasticbeanstalkhakassia" + - "xn--lgrd-poacctrusteexn--lhppi-xqaxn--linds-pramericanartrvargga" + - "trentoyonakagyokutoyakolobrzegersundxn--lns-qlaquilanstorfjordxn" + - "--loabt-0qaxn--lrdal-sraxn--lrenskog-54axn--lt-liacnpyatigorskod" + - "jeffersonxn--lten-granexn--lury-iraxn--m3ch0j3axn--mely-iraxn--m" + - "erker-kuaxn--mgb2ddestorjdevcloudnshinyoshitomiokamitondabayashi" + - "ogamagoriziaxn--mgb9awbfedorapeoplegnicapebretonamicrosoftbankas" + - "uyanaizulminamiechizenxn--mgba3a3ejtrycloudflareportrevisohughes" + - "omaxn--mgba3a4f16axn--mgba3a4franamizuholdingstpetersburgxn--mgb" + - "a7c0bbn0axn--mgbaakc7dvfedoraprojectransportexn--mgbaam7a8hakuis" + - "-a-greenxn--mgbab2bdxn--mgbah1a3hjkrdxn--mgbai9a5eva00beneventoe" + - "idskoguchikuzenayorovigovtaxihuanflfanfshostrowwlkpmgjovikaratsu" + - "ginamikatagamilitaryonagoyaxn--mgbai9azgqp6jelenia-goraxn--mgbay" + - "h7gpaleoxn--mgbbh1a71exn--mgbc0a9azcgxn--mgbca7dzdoxn--mgberp4a5" + - "d4a87gxn--mgberp4a5d4arxn--mgbgu82axn--mgbi4ecexposedxn--mgbpl2f" + - "hskydivingxn--mgbqly7c0a67fbcnsantabarbaraxn--mgbqly7cvafranzisk" + - "anerimaringatlantakahashimamakiryuohdattorelayxn--mgbt3dhdxn--mg" + - "btf8flatangerxn--mgbtx2bentleyonagunicommbankarelianceu-2xn--mgb" + - "x4cd0abbvieeexn--mix082feiraquarelleaseeklogesaves-the-whalessan" + - "dria-trani-barletta-andriatranibarlettaandriaxn--mix891fermochiz" + - "ukirovogradoyxn--mjndalen-64axn--mk0axin-dslgbtrysiljanxn--mk1bu" + - "44cntoystre-slidrettozawaxn--mkru45is-not-certifiedugit-pagespee" + - "dmobilizeroticanonoichinomiyakexn--mlatvuopmi-s4axn--mli-tlarvik" + - "oryokamikawanehonbetsurutaharaxn--mlselv-iuaxn--moreke-juaxn--mo" + - "ri-qsakuragawaxn--mosjen-eyawatahamaxn--mot-tlavagiskexn--mre-og" + - "-romsdal-qqbuserveexchangexn--msy-ula0hakusanagochijiwadell-ogli" + - "astraderxn--mtta-vrjjat-k7aflakstadaokagakicks-assnasaarlandxn--" + - "muost-0qaxn--mxtq1misawaxn--ngbc5azdxn--ngbe9e0axn--ngbrxn--3e0b" + - "707exn--nit225kosaigawaxn--nmesjevuemie-tcbalsan-sudtirollagdene" + - "snaaseinet-freakstreamswatch-and-clockerxn--nnx388axn--nodessaku" + - "rais-savedunetflixilxn--nqv7fs00emaxn--nry-yla5gxn--ntso0iqx3axn" + - "--ntsq17gxn--nttery-byaeservehttplantsjcbnpparibaselburgxn--nvuo" + - "tna-hwaxn--nyqy26axn--o1acheltenham-radio-openairbusantiquest-a-" + - "la-maisondre-landroidxn--o3cw4haldenxn--o3cyx2axn--od0algxn--od0" + - "aq3beppublishproxyzgorzeleccogladefinimakanegasakiraxn--ogbpf8fl" + - "ekkefjordxn--oppegrd-ixaxn--ostery-fyaxn--osyro-wuaxn--otu796dxn" + - "--p1acferraraxn--p1ais-slickfhappoutwentexn--pbt977collectionxn-" + - "-pgbs0dhlxn--porsgu-sta26ferrarivnexn--pssu33lxn--pssy2uxn--q9jy" + - "b4colognewyorkshirecifedexeterxn--qcka1pmckinseyxn--qqqt11miscon" + - "fusedxn--qxa6axn--qxamuneuestudioxn--rady-iraxn--rdal-poaxn--rde" + - "-ulavangenxn--rdy-0nabaris-uberleetrentino-sudtirolxn--rennesy-v" + - "1axn--rhkkervju-01aferrerotikagoshimalvikaszubyxn--rholt-mragowo" + - "odsidemonmouthalsaitamatsukuris-a-guruslivinghistoryxn--rhqv96gx" + - "n--rht27zxn--rht3dxn--rht61exn--risa-5naturalhistorymuseumcenter" + - "xn--risr-iraxn--rland-uuaxn--rlingen-mxaxn--rmskog-byaxn--rny31h" + - "ammarfeastafricapitalonewmexicodyn-o-saurlandesevenassisicilyxn-" + - "-rovu88beskidyn-ip24xn--rros-granvindafjordxn--rskog-uuaxn--rst-" + - "0naturalsciencesnaturellestudynamisches-dnsokndalxn--rsta-franca" + - "iseharaxn--rvc1e0am3exn--ryken-vuaxn--ryrvik-byaxn--s-1faithamur" + - "akamigoris-a-hard-workersewinbarclaycards3-fips-us-gov-west-1xn-" + - "-s9brj9colonialwilliamsburgroundhandlingroznyxn--sandnessjen-ogb" + - "estbuyshouses3-website-ap-northeast-1xn--sandy-yuaxn--sdtirol-n2" + - "axn--seral-lraxn--ses554gxn--sgne-graphoxn--3hcrj9civilisationis" + - "shinguccircleverappsannaniyodogawaxn--skierv-utazastuff-4-salexn" + - "--skjervy-v1axn--skjk-soaxn--sknit-yqaxn--sknland-fxaxn--slat-5n" + - "aturbruksgymnxn--slt-elabcieszynxn--smla-hraxn--smna-gratangentl" + - "entapisa-geekosakaerodromegallupinbargainstantcloudfunctionswede" + - "nvironmentalconservationfabricafederationionjukudoyamaizuruhrhcl" + - "oudiscourses3-us-east-2xn--snase-nraxn--sndre-land-0cbetainaboxf" + - "usejnymemsettsupportcp4xn--snes-poaxn--snsa-roaxn--sr-aurdal-l8a" + - "xn--sr-fron-q1axn--sr-odal-q1axn--sr-varanger-ggbhzcasinordkappa" + - "lmasfjordenhktjeldsundishakotanhlfanhs3-website-ap-southeast-1xn" + - "--srfold-byaxn--srreisa-q1axn--srum-gratis-a-bulls-fanxn--stfold" + - "-9xaxn--stjrdal-s1axn--stjrdalshalsen-sqbieidsvollimitediskussio" + - "nsbereichaseljeepsondriodejaneirockartuzyoriikariyaltakatorin-th" + - "e-bandain-vpncateringebuildinglassassinationalheritageu-3xn--str" + - "e-toten-zcbielawashingtondclkarlsoyoshiokanzakiyokawaraxn--t60b5" + - "6axn--tckweatherchannelxn--tiq49xqyjeonnamerikawauexn--tjme-hrax" + - "n--tn0agrinetbankoseis-a-painteractivegaskvollxn--tnsberg-q1axn-" + - "-tor131oxn--trany-yuaxn--trentin-sd-tirol-rzbiellaakesvuemielecc" + - "eu-4xn--trentin-sdtirol-7vbrplsbxn--3oq18vl8pn36axn--trentino-sd" + - "-tirol-c3bieszczadygeyachimataipeigersundisrechtrainingleezevje-" + - "og-hornnes3-website-ap-southeast-2xn--trentino-sdtirol-szbievath" + - "letajimabaridagawalbrzycharitydalcesurancechirealmpmnikonanporov" + - "noceanographiquextraspace-to-rentalstomakomaibaraxn--trentinosd-" + - "tirol-rzbifukagawashtenawdev-myqnapcloudeitysfjordivtasvuodnakam" + - "agayahabaghdadivttasvuotnakamuratakahamalselvendrellimoliseminex" + - "n--trentinosdtirol-7vbigv-infoodnetworkangerxn--trentinsd-tirol-" + - "6vbihorologyukincheoninohekinannestadiyukuhashimojindianapolis-a" + - "-bloggerxn--trentinsdtirol-nsbikedaejeonbukcoalvdalaheadjudygarl" + - "andnpalmspringsakerxn--trgstad-r1axn--trna-woaxn--troms-zuaxn--t" + - "ysvr-vraxn--uc0atvaroyxn--uc0ay4axn--uist22handsonyoursidellogli" + - "astradingxn--uisz3gxn--unjrga-rtashkentunesomnarvikommunexn--unu" + - "p4yxn--uuwu58axn--vads-jraxn--valle-aoste-ebbtunkomvuxn--30rr7yx" + - "n--valle-d-aoste-ehbodollstufftoread-booksnesolarssonxn--valleao" + - "ste-e7axn--valledaoste-ebbvacationstuttgartrentinsued-tirolxn--v" + - "ard-jraxn--vegrshei-c0axn--vermgensberater-ctbilbaokinawashirosa" + - "tochigiessensiositelemarkarmoyurihonjournalistjohninomiyakonojor" + - "pelandrangedalinkyard-cloudyclusterxn--vermgensberatung-pwbillus" + - "trationredumbrellahppiacenzachpomorskienirasakindianmarketinglit" + - "chattanooganordlandray-dnsupdaternopilawaweddingliwicexn--vestvg" + - "y-ixa6oxn--vg-yiabkhaziaxn--vgan-qoaxn--vgsy-qoa0jetztrentino-su" + - "ed-tirolxn--vgu402coloradoplateaudioxn--vhquvestfoldxn--vler-qoa" + - "xn--vre-eiker-k8axn--vrggt-xqadxn--vry-yla5gxn--vuq861biocpanama" + - "tta-varjjatjmaxxxboxenapponazure-mobilexn--w4r85el8fhu5dnraxn--w" + - "4rs40lxn--wcvs22dxn--wgbh1columbusheyxn--wgbl6axn--xhq521birdart" + - "centerprisecloudcontrolappleborkdalwaysdatabaseballangenkainanae" + - "robatickets3-website-eu-west-1xn--xkc2al3hye2axn--xkc2dl3a5ee0ha" + - "ngglidingxn--y9a3aquariumishimatsumaebashimodatexn--yer-znaturhi" + - "storischesusakis-gonexn--yfro4i67oxn--ygarden-p1axn--ygbi2ammxn-" + - "-3pxu8koninjambylxn--ystre-slidre-ujbirkenesoddtangenovaranzanqu" + - "anpachigasakihokumakogengerdalaskanittedallasalleangaviikaascoli" + - "picenodumetacentrumeteorappanasonicatholicaxiashorokanaiexn--zbx" + - "025dxn--zf0ao64axn--zf0avxlxn--zfr164birthplacexnbayxz" + "ideovillasorocabalestrandabergamo-siemensncfdvinnicasadelamoneda" + + "pliernewportlligatritonvinnytsiavipsinaappixolinovirginiavirtual" + + "-userveftpizzavirtualservervirtualuservegame-servervirtueeldomei" + + "n-vigorlicevirtuelvisakegawaviterboknowsitallvivolkenkundenvixn-" + + "-3hcrj9civilisationisshinguccircleverappsantabarbaravlaanderenvl" + + "adikavkazimierz-dolnyvladimirvlogintoyonezawavminiservervologdan" + + "skomonowruzhgorodeovolvolkswagentsorreisahayakawakamiichikawamis" + + "atottoris-foundationvolyngdalvoorloperauniterois-into-carshintom" + + "ikasaharavossevangenvotevotingvotoyonowmcloudwmflabsortlandwnext" + + "directrogstadworldworse-thandawowithyoutuberspacekitagatargitpag" + + "efrontappkmpspbar2wpdevcloudwpenginepoweredwritesthisblogsytewro" + + "clawiwatsukiyonotairestaurantroandinosaurepbodynamic-dnsopotrent" + + "insudtirolwtcminnesotaketaketomisatokorozawawtfbsbxn--1ck2e1banz" + + "aicloudcontrolledekagaminombresciaustraliajudaicable-modemocraci" + + "abruzzoologicalvinklein-addrammenuorochesterimo-i-rana4u2-localh" + + "ostrowiec66wuozuwzmiuwajimaxn--45q11civilwarmiaxn--4gbriminingxn" + + "--4it168dxn--4it797kongsbergxn--4pvxs4allxn--54b7fta0cclanbibaid" + + "armeniaxn--55qw42gxn--55qx5dxn--5js045dxn--5rtp49cldmailovecolle" + + "gefantasyleaguernseyxn--5rtq34kongsvingerxn--5su34j936bgsgxn--5t" + + "zm5gxn--6btw5axn--6frz82gxn--6orx2rxn--6qq986b3xlxn--7t0a264clic" + + "20001wwwhoswhokksundyndns-wikirkenesantacruzsantafedjejuifmetace" + + "ntrumeteorappartis-a-catererxn--80adxhksorumincomcastresindevice" + + "nzaporizhzhiaxn--80ao21axn--80aqecdr1axn--80asehdbarefootballoon" + + "ingjerdrumckinseyolasiteu-1xn--80aswgxn--80augustowloclawekomoro" + + "tsukaminokawanishiaizubangexn--8ltr62koninjambylxn--8pvr4uxn--8y" + + "0a063axn--90a3academiamicaaarborteaches-yogasawaracingxn--90aero" + + "portalabamagasakishimabaraogakibichuoxn--90aishobarakawagoexn--9" + + "0azhytomyravendbargainstantcloudfunctionswedenvironmentalconserv" + + "ationfabricafederationionjukudoyamaintenanceu-2xn--9dbhblg6digit" + + "alxn--9dbq2axn--9et52uxn--9krt00axn--andy-iraxn--aroport-byaotsu" + + "rreyxn--asky-iraxn--aurskog-hland-jnbarreauction-webhopenairbusa" + + "ntiquest-a-la-maisondre-landroidiscourses3-us-gov-west-1xn--aver" + + "y-yuasakuhokkaidovre-eikerxn--b-5gaxn--b4w605ferdxn--balsan-sdti" + + "rol-nsbsoundcastronomy-routerxn--bck1b9a5dre4clickashiwaraxn--bd" + + "ddj-mrabdxn--bearalvhki-y4axn--berlevg-jxaxn--bhcavuotna-s4axn--" + + "bhccavuotna-k7axn--bidr-5nachikatsuuraxn--bievt-0qa2xn--bjarky-f" + + "yasakaiminatoyookaniepcexn--bjddar-ptarumizusawaxn--blt-elabourx" + + "n--bmlo-graingerxn--bod-2natalxn--bozen-sdtirol-2obanazawaxn--br" + + "nny-wuacademy-firewall-gatewayxn--brnnysund-m8accident-investiga" + + "tion-aptibleadpagest-mon-blogueurovision-k3southcarolinarvikomat" + + "sushimarylhurstjordalshalsenxn--brum-voagatromsakataobaomoriguch" + + "iharahkkeravjuegoshikijobservableusercontentrentoyonakagyokutoya" + + "kolobrzegersundxn--btsfjord-9zaxn--bulsan-sdtirol-nsbarrel-of-kn" + + "owledgeapplicationcloudappspotagerevistaples3-us-west-1xn--c1avg" + + "xn--c2br7gxn--c3s14mintereitrentino-suedtirolxn--cck2b3barrell-o" + + "f-knowledgestack12xn--cckwcxetdxn--cesena-forl-mcbremangerxn--ce" + + "senaforl-i8axn--cg4bkis-into-cartoonshinyoshitomiokamitondabayas" + + "hiogamagoriziaxn--ciqpnxn--clchc0ea0b2g2a9gcdxn--comunicaes-v6a2" + + "oxn--correios-e-telecomunicaes-ghc29axn--czr694barsycenterprises" + + "akimobetsuitainaioirasebastopologyeongnamegawakayamagazineat-url" + + "illyombolzano-altoadigeorgeorgiaustrheimatunduhrennesoyokozebina" + + "gisoccertmgrazimutheworkpccwebredirectmembers3-eu-west-1xn--czrs" + + "0tromsojamisonxn--czru2dxn--czrw28barsyonlinewhampshirealtysnes3" + + "-us-west-2xn--d1acj3bashkiriauthordalandeportenrivnebinordreisa-" + + "hockeynutazuerichardlikescandyn53utilitiesquare7xn--d1alfaromeox" + + "n--d1atrusteexn--d5qv7z876clinichiryukyuragifuchungbukharavennag" + + "asakindlecznagasukexn--davvenjrga-y4axn--djrs72d6uyxn--djty4kons" + + "kowolayangroupiemontexn--dnna-grajewolterskluwerxn--drbak-wuaxn-" + + "-dyry-iraxn--e1a4cliniquenoharaxn--eckvdtc9dxn--efvn9southwestfa" + + "lenxn--efvy88haibarakitahiroshimaoris-a-greenxn--ehqz56nxn--elqq" + + "16hair-surveillancexn--eveni-0qa01gaxn--f6qx53axn--fct429konsula" + + "trobeepilepsykkylvenetodayxn--fhbeiarnxn--finny-yuaxn--fiq228c5h" + + "sowaxn--fiq64basicservercelliguriautomotiveconomiastagemological" + + "lyngenflfanquanpachigasakihokumakogenebakkeshibechambagriculture" + + "nnebudejjuedischesapeakebayernufcfanavigationavoizumizakibmdevel" + + "opmentatsunobiramusementdllpages3-ap-southeast-2ix4432-balsan-su" + + "edtirolkuszczytnoipirangamvik-serverrankoshigayachimataikikugawa" + + "lesundd-dnshome-webserverdal-o-g-i-n4tatarantours3-ap-northeast-" + + "2xn--fiqs8speedpartnersolarssonxn--fiqz9sphinxn--3e0b707exn--fjo" + + "rd-lraxn--fjq720axn--fl-ziaxn--flor-jraxn--flw351exn--forl-cesen" + + "a-fcbsspjelkavikomforbarcelonagawalmartattoolforgemreviewsaitosh" + + "imayfirstockholmestrandgcahcesuoloans3-fips-us-gov-west-1xn--for" + + "lcesena-c8axn--fpcrj9c3dxn--frde-grandrapidspreadbettingxn--frna" + + "-woaraisaijosoyrorospydebergxn--frya-hraxn--fzc2c9e2clintonoshoe" + + "santamariakexn--fzys8d69uvgmailxn--g2xx48clothingdustdataiwanair" + + "forcebetsuikidsmynasushiobaragusabaejrietisalatinabenonicbcn-nor" + + "th-1xn--gckr3f0fbx-ostrowwlkpmgruexn--gecrj9cn-northwest-1xn--gg" + + "aviika-8ya47hakatanortonxn--gildeskl-g0axn--givuotna-8yasugivest" + + "bytemarkonyvelolipoppdalxn--gjvik-wuaxn--gk3at1exn--gls-elacaixa" + + "xn--gmq050is-into-gamessinazawaxn--gmqw5axn--h-2failxn--h1aeghak" + + "odatexn--h2breg3evenesrlxn--h2brj9c8cngriwataraidyndns-workshopi" + + "tsitevadsobetsumidatlantichitachinakagawashtenawdev-myqnapcloude" + + "itysfjordyndns-blogdnsamsclubartowfarmsteadyndns-freeboxosloftoy" + + "osatoyokawaxn--h3cuzk1discountyxn--hbmer-xqaxn--hcesuolo-7ya35ba" + + "silicataniautoscanadaeguambulancechirealmpmnavuotnapleskns3-eu-w" + + "est-2xn--hery-iraxn--hgebostad-g3axn--hkkinen-5waxn--hmmrfeasta-" + + "s4accident-prevention-rancherkasydneyxn--hnefoss-q1axn--hobl-ira" + + "xn--holtlen-hxaxn--hpmir-xqaxn--hxt814exn--hyanger-q1axn--hyland" + + "et-54axn--i1b6b1a6a2exn--imr513nxn--indery-fyasuokanoyaltakatori" + + "s-leetrentino-stirolxn--io0a7is-lostrodawaraxn--j1aefbxosavannah" + + "gaxn--j1amhakonexn--j6w193gxn--jlq480n2rgxn--jlq61u9w7basketball" + + "finanzgoraveroykengerdalces3-eu-west-3xn--jlster-byatominamidait" + + "omanchesterxn--jrpeland-54axn--jvr189misakis-a-therapistoiaxn--k" + + "7yn95exn--karmy-yuaxn--kbrq7oxn--kcrx77d1x4axn--kfjord-iuaxn--kl" + + "bu-woaxn--klt787dxn--kltp7dxn--kltx9axn--klty5xn--3oq18vl8pn36ax" + + "n--koluokta-7ya57hakubahcavuotnagaivuotnagaokakyotambabyenglandx" + + "n--kprw13dxn--kpry57dxn--kput3is-not-certifiedugit-pagespeedmobi" + + "lizeroticanonoichinomiyakexn--krager-gyatsukanraxn--kranghke-b0a" + + "xn--krdsherad-m8axn--krehamn-dxaxn--krjohka-hwab49jdevcloudnshir" + + "ahamatonbetsurnadalxn--ksnes-uuaxn--kvfjord-nxaxn--kvitsy-fyatsu" + + "shiroxn--kvnangen-k0axn--l-1fairwindsrvarggatrentinsued-tirolxn-" + + "-l1accentureklamborghinikolaeventstoregontrailroadxn--laheadju-7" + + "yawaraxn--langevg-jxaxn--lcvr32dxn--ldingen-q1axn--leagaviika-52" + + "batochiokinoshimaizuruhrhcloudiscoveryomitanobninskaracoldwarsza" + + "wavocatanzarowebspacebizenakanojohanamakinoharaukraanghkeymachin" + + "eustargardds3-ca-central-1xn--lesund-huaxn--lgbbat1ad8jdfastvps-" + + "serveronakanotoddenxn--lgrd-poacctrvaroyxn--lhppi-xqaxn--linds-p" + + "ramericanartrycloudflareplantationxn--lns-qlaquilanstorfjordxn--" + + "loabt-0qaxn--lrdal-sraxn--lrenskog-54axn--lt-liacnpyatigorskodje" + + "ffersonxn--lten-granexn--lury-iraxn--m3ch0j3axn--mely-iraxn--mer" + + "ker-kuaxn--mgb2ddestorjcphonefosshioyandexcloudxn--mgb9awbfedora" + + "peoplegnicapebretonamicrosoftbankasukabedzin-berlindasdaburxn--m" + + "gba3a3ejtrysiljanxn--mgba3a4f16axn--mgba3a4franamizuholdingstpet" + + "ersburgxn--mgba7c0bbn0axn--mgbaakc7dvfedoraprojectraniandriabarl" + + "ettatraniandriaxn--mgbaam7a8hakuis-a-gurustkannamilanotogawaxn--" + + "mgbab2bdxn--mgbah1a3hjkrdxn--mgbai9a5eva00batsfjordishakotanayor" + + "ovigovtaxihuanfshostrolekamishihoronobeauxartsandcrafts3-website" + + "-ap-northeast-1xn--mgbai9azgqp6jelasticbeanstalkddietnedalxn--mg" + + "bayh7gpaleoxn--mgbbh1a71exn--mgbc0a9azcgxn--mgbca7dzdoxn--mgberp" + + "4a5d4a87gxn--mgberp4a5d4arxn--mgbgu82axn--mgbi4ecexposedxn--mgbp" + + "l2fhskydivingxn--mgbqly7c0a67fbcnsantoandreamhostersanukis-a-cel" + + "ticsfanxn--mgbqly7cvafranziskanerimaringatlantakahashimamakiryuo" + + "hdattorelayxn--mgbt3dhdxn--mgbtf8flatangerxn--mgbtx2bauhausposts" + + "-and-telecommunications3-website-ap-southeast-1xn--mgbx4cd0abbvi" + + "eeexn--mix082feiraquarelleaseeklogesaveincloudynvpnplus-4xn--mix" + + "891fermochizukirovogradoyxn--mjndalen-64axn--mk0axin-dslgbtuneso" + + "r-odalxn--mk1bu44cntoystre-slidrettozawaxn--mkru45is-savedunetfl" + + "ixilxn--mlatvuopmi-s4axn--mli-tlarvikooris-a-nursembokukitchenxn" + + "--mlselv-iuaxn--moreke-juaxn--mori-qsakuragawaxn--mosjen-eyawata" + + "hamaxn--mot-tlavagiskexn--mre-og-romsdal-qqbuserveexchangexn--ms" + + "y-ula0hakusanagochijiwadell-ogliastraderxn--mtta-vrjjat-k7aflaks" + + "tadaokagakicks-assnasaarlandxn--muost-0qaxn--mxtq1misasaguris-an" + + "-accountantshinshiroxn--ngbc5azdxn--ngbe9e0axn--ngbrxn--3pxu8kom" + + "vuxn--32vp30haebaruericssongdalenviknakatsugawaxn--nit225kopervi" + + "khakassiaxn--nmesjevuemie-tcbalsan-sudtirollagdenesnaaseinet-fre" + + "akstreamswatch-and-clockerxn--nnx388axn--nodessakurais-slickazun" + + "ow-dnshiojirishirifujiedaxn--nqv7fs00emaxn--nry-yla5gxn--ntso0iq" + + "x3axn--ntsq17gxn--nttery-byaeservehttplantslzxn--nvuotna-hwaxn--" + + "nyqy26axn--o1acheltenham-radio-opencraftrainingxn--o3cw4haldenxn" + + "--o3cyx2axn--od0algorithmiasakuchinotsuchiurakawaxn--od0aq3benev" + + "entoeidskoguchikuzenhktcp4xn--ogbpf8flekkefjordxn--oppegrd-ixaxn" + + "--ostery-fyaxn--osyro-wuaxn--otu796dxn--p1acferraraxn--p1ais-ube" + + "rleetrentino-sud-tirolxn--pgbs0dhlxn--porsgu-sta26ferraris-a-cub" + + "icle-slavellinodeobjectsaves-the-whalessandria-trani-barletta-an" + + "driatranibarlettaandriaxn--pssu33lxn--pssy2uxn--q9jyb4collection" + + "xn--qcka1pmcdirxn--qqqt11misawaxn--qxa6axn--qxamuneuestudioxn--r" + + "ady-iraxn--rdal-poaxn--rde-ulavangenxn--rdy-0nabaris-very-badajo" + + "zxn--rennesy-v1axn--rhkkervju-01aferrerotikagoshimalvikasumigaur" + + "ayasudaxn--rholt-mragowoodsidemonmouthalsaitamatsukuris-a-hard-w" + + "orkersewilliamhillxn--rhqv96gxn--rht27zxn--rht3dxn--rht61exn--ri" + + "sa-5nativeamericanantiquestudynamisches-dnsolognexn--risr-iraxn-" + + "-rland-uuaxn--rlingen-mxaxn--rmskog-byaxn--rny31hammarfeastafric" + + "apitalonewmexicodyn-o-saurlandesharis-a-hunterxn--rovu88bentleyo" + + "nagoyavoues3-external-1xn--rros-granvindafjordxn--rskog-uuaxn--r" + + "st-0naturalhistorymuseumcenterxn--rsta-francaiseharaxn--rvc1e0am" + + "3exn--ryken-vuaxn--ryrvik-byaxn--s-1faithamurakamigoris-a-knight" + + "pointtohobby-sitexn--s9brj9colognewyorkshirecifedexeterxn--sandn" + + "essjen-ogbeppublishproxyzgorzeleccogjerstadotsuruokakamigaharaxa" + + "urskog-holandinggfarmerseine164-baltimore-og-romsdalipayboltates" + + "hinanomachimkentateyamaetnaamesjevuemielno-ipifonyaarpalmasfjord" + + "enaturhistorisches3-ap-southeast-1xn--sandy-yuaxn--sdtirol-n2axn" + + "--seral-lraxn--ses554gxn--sgne-graphoxn--42c2d9axn--skierv-utaza" + + "stuff-4-salexn--skjervy-v1axn--skjk-soaxn--sknit-yqaxn--sknland-" + + "fxaxn--slat-5naturalsciencesnaturellestufftoread-booksnesolundbe" + + "ckomakiyosunndalxn--slt-elabcieszynxn--smla-hraxn--smna-gratange" + + "ntlentapisa-geekoryokamikawanehonbetsurutaharaxn--snase-nraxn--s" + + "ndre-land-0cbeskidyn-ip24xn--snes-poaxn--snsa-roaxn--sr-aurdal-l" + + "8axn--sr-fron-q1axn--sr-odal-q1axn--sr-varanger-ggbestbuyshouses" + + "3-website-ap-southeast-2xn--srfold-byaxn--srreisa-q1axn--srum-gr" + + "atis-a-bulls-fanxn--stfold-9xaxn--stjrdal-s1axn--stjrdalshalsen-" + + "sqbetainaboxfusejnymemergencyahabaghdadiskussionsbereichaseljeep" + + "sondriodejaneirockartuzyonagunicommbankaragandaxn--stre-toten-zc" + + "bhzcasertairaumalborkarasjohkamikitayamatsurin-the-bandain-vpnca" + + "sinordkappalmspringsakerxn--t60b56axn--tckweatherchannelxn--tiq4" + + "9xqyjelenia-goraxn--tjme-hraxn--tn0agrinetbankosaigawaxn--tnsber" + + "g-q1axn--tor131oxn--trany-yuaxn--trentin-sd-tirol-rzbieidsvollim" + + "anowarudaxn--trentin-sdtirol-7vbrplsbxn--45br5cylxn--trentino-sd" + + "-tirol-c3bielawaltervistaipeigersundisrechtranakaiwamizawatchand" + + "clockarasjokarasuyamarshallstatebankarateu-3xn--trentino-sdtirol" + + "-szbiellaakesvuemielecceu-4xn--trentinosd-tirol-rzbieszczadygeya" + + "chiyodaejeonbukcoalvdalaheadjudygarlandivtasvuodnakamagayahikobi" + + "erzycevje-og-hornnes3-website-eu-west-1xn--trentinosdtirol-7vbie" + + "vat-band-campaniaxn--trentinsd-tirol-6vbifukagawashingtondclkara" + + "tsuginamikatagamilitaryoriikareliancextraspace-to-rentalstomakom" + + "aibaraxn--trentinsdtirol-nsbigv-infoodnetworkangerxn--trgstad-r1" + + "axn--trna-woaxn--troms-zuaxn--tysvr-vraxn--uc0atvestfoldxn--uc0a" + + "y4axn--uist22handsonyoursidellogliastradingxn--uisz3gxn--unjrga-" + + "rtashkentunkommunexn--unup4yxn--uuwu58axn--vads-jraxn--valle-aos" + + "te-ebbturystykanmakiwielunnerxn--valle-d-aoste-ehbodollstuttgart" + + "rentinsuedtirolxn--valleaoste-e7axn--valledaoste-ebbvacationsusa" + + "kis-gonexn--vard-jraxn--vegrshei-c0axn--vermgensberater-ctbihoro" + + "logyoshiokanzakiyokawaraxn--vermgensberatung-pwbikedaemoneyukinc" + + "heonhlfanhs3-website-sa-east-1xn--vestvgy-ixa6oxn--vg-yiabkhazia" + + "xn--vgan-qoaxn--vgsy-qoa0jeonnamerikawauexn--vgu402colonialwilli" + + "amsburgroks-thisayamanobeokakudamatsuexn--vhquvestnesorfoldxn--v" + + "ler-qoaxn--vre-eiker-k8axn--vrggt-xqadxn--vry-yla5gxn--vuq861bil" + + "baokinawashirosatochigiessensiositecnologiaxn--w4r85el8fhu5dnrax" + + "n--w4rs40lxn--wcvs22dxn--wgbh1coloradoplateaudioxn--wgbl6axn--xh" + + "q521billustrationredumbrellahppiacenzachpomorskienikonanporovnob" + + "serverxn--xkc2al3hye2axn--xkc2dl3a5ee0hangglidingxn--y9a3aquariu" + + "misconfusedxn--yer-znaturbruksgymnxn--yfro4i67oxn--ygarden-p1axn" + + "--ygbi2ammxn--45brj9civilizationiyodogawaxn--ystre-slidre-ujbioc" + + "eanographics3-website-us-east-1xn--zbx025dxn--zf0ao64axn--zf0avx" + + "lxn--zfr164birdartcenterprisecloudcontrolappleborkdalwaysdatabas" + + "eballangenkainanaerobatickets3-website-us-west-1xnbayxz" // nodes is the list of nodes. Each node is represented as a uint32, which // encodes the node's children, wildcard bit and node type (as an index into @@ -526,1818 +528,1812 @@ const text = "9guacuiababia-goracleaningroks-theatree12hpalermomahachijoinvill" // [15 bits] text index // [ 6 bits] text length var nodes = [...]uint32{ - 0x297a83, - 0x32a504, - 0x2eadc6, - 0x24c943, - 0x24c946, - 0x38b146, - 0x3b05c3, - 0x214bc4, - 0x201507, - 0x2eaa08, + 0x32f643, + 0x3b5c84, + 0x2f7846, + 0x2ed303, + 0x2ed306, + 0x391ec6, + 0x3ba683, + 0x242cc4, + 0x2089c7, + 0x2f7488, 0x1a000c2, - 0x1f36987, - 0x376649, - 0x36c4ca, - 0x36c4cb, - 0x201203, - 0x233985, - 0x2201602, - 0x2d2044, - 0x2eaf43, - 0x269045, - 0x2601742, - 0x343083, - 0x2a135c4, - 0x2982c5, - 0x2e0de42, - 0x26e24e, - 0x250b83, - 0x3a6286, - 0x3203082, - 0x306087, - 0x2372c6, - 0x3606bc2, - 0x27f943, - 0x27f944, - 0x399b86, - 0x35bc88, - 0x286046, - 0x26fc84, + 0x1f3c187, + 0x37b0c9, + 0x39a04a, + 0x39a04b, + 0x231983, + 0x234b85, + 0x2202642, + 0x280004, + 0x2f79c3, + 0x202645, + 0x2608c02, + 0x365e83, + 0x2a15d84, + 0x3b5585, + 0x2e12282, + 0x27520e, + 0x251a43, + 0x3adec6, + 0x3207d42, + 0x306e07, + 0x237306, + 0x3601f82, + 0x26d143, + 0x334e46, + 0x360f48, + 0x28e806, + 0x276804, 0x3a00ac2, - 0x34abc9, - 0x2236c7, - 0x202446, - 0x353689, - 0x32f208, - 0x2478c4, - 0x23f2c6, - 0x3c3846, - 0x3e041c2, - 0x36fcc6, - 0x242f4f, - 0x2d108e, - 0x219a44, - 0x218b45, - 0x32a405, - 0x2e7589, - 0x23d709, - 0x39a387, - 0x3ddf06, - 0x267243, - 0x42037c2, - 0x21adc3, - 0x35054a, - 0x460f283, - 0x3d95c5, - 0x29d282, - 0x38b6c9, - 0x4e01182, - 0x201c84, - 0x2f3146, - 0x28a745, - 0x36d1c4, - 0x560fbc4, - 0x220dc3, - 0x232d04, - 0x5a02d02, - 0x235784, - 0x5e79284, - 0x33cb4a, + 0x34cd89, + 0x222087, + 0x3b4c86, + 0x370f49, + 0x3c8608, + 0x354f84, + 0x25b9c6, + 0x3cdd86, + 0x3e029c2, + 0x2a7f06, + 0x24394f, + 0x27f04e, + 0x221684, + 0x2d4205, + 0x32f545, + 0x215589, + 0x23d909, + 0x335647, + 0x355246, + 0x203583, + 0x42272c2, + 0x22ce03, + 0x2937ca, + 0x4601ac3, + 0x3e1a45, + 0x239202, + 0x392449, + 0x4e03502, + 0x209784, + 0x2f4406, + 0x28fac5, + 0x3732c4, + 0x56263c4, + 0x233f03, + 0x233f04, + 0x5a02e42, + 0x385d04, + 0x5e83a84, + 0x25d6ca, 0x6200882, - 0x3c1f47, - 0x2d0548, - 0x76031c2, - 0x328287, - 0x2c9044, - 0x2c9047, - 0x3d57c5, - 0x378847, - 0x303c06, - 0x2f0e44, - 0x342e05, - 0x257187, - 0x8e01482, - 0x36fe43, - 0x9226782, - 0x3633c3, - 0x9606b42, - 0x274985, + 0x229547, + 0x27e508, + 0x7a07282, + 0x334a47, + 0x2ce984, + 0x2ce987, + 0x3dbac5, + 0x390e07, + 0x34b706, + 0x2a1184, + 0x36a285, + 0x257e87, + 0x8e07cc2, + 0x2a8083, + 0x9210642, + 0x3b3f43, + 0x96074c2, + 0x2173c5, 0x9a00202, - 0x2cd104, - 0x2c23c5, - 0x219987, - 0x249e0e, - 0x2b6e44, - 0x290f44, - 0x210603, - 0x286ac9, - 0x3aa74b, - 0x2edac8, - 0x303148, - 0x3b1888, - 0x3d9ac8, - 0x3534ca, - 0x378747, - 0x2cdf46, - 0x9e47402, - 0x374d83, - 0x3ccac3, - 0x3ce604, - 0x374dc3, - 0x35cb83, - 0x1732182, - 0xa2016c2, - 0x27cd05, - 0x224686, - 0x233744, - 0x38a5c7, - 0x2355c6, - 0x2c8984, - 0x3abfc7, - 0x215dc3, - 0xa6d5bc2, - 0xaa20f82, - 0xae20d42, - 0x220d46, - 0xb200282, - 0x284405, - 0x3336c3, - 0x3c8744, - 0x2f7784, - 0x2f7785, - 0x3d6d83, - 0xb602703, - 0xba019c2, - 0x205fc5, - 0x205fcb, - 0x20ec0b, - 0x229904, - 0x206689, - 0x208244, - 0xbe09c42, - 0x20a483, - 0x20a703, - 0xc202e82, - 0x398a0a, - 0xc601542, - 0x2d22c5, - 0x2e6a0a, - 0x247584, - 0x20b103, - 0x20b7c4, - 0x20d6c3, - 0x20d6c4, - 0x20d6c7, - 0x20e245, - 0x2114c6, - 0x211846, - 0x2124c3, - 0x217688, - 0x208f03, - 0xca0cd42, - 0x308648, - 0x2862cb, - 0x21ffc8, - 0x2205c6, - 0x2213c7, - 0x227208, - 0xda07682, - 0xde1d482, - 0x298408, - 0x210c07, - 0x30dcc5, - 0x30dcc8, - 0xe301108, - 0x26c243, - 0x22a444, - 0x38b1c2, - 0xe62a882, - 0xea16182, - 0xf22c042, - 0x22c043, - 0xf6086c2, - 0x296303, - 0x3b2744, - 0x2086c3, - 0x247884, - 0x296a4b, - 0x215843, - 0x2f1486, - 0x278704, - 0x2c340e, - 0x38f345, - 0x261e48, - 0x3a6387, - 0x3a638a, - 0x22f983, - 0x2343c7, - 0x3aa905, - 0x22f984, - 0x2526c6, - 0x2526c7, - 0x31a204, - 0xfb0d704, - 0x24a144, - 0x33c806, - 0x22b844, - 0x3b5cc6, - 0x232443, - 0x3ba348, - 0x3df888, - 0x290f03, - 0x3989c3, - 0x340384, - 0x355943, - 0x10215702, - 0x1068d502, - 0x218043, - 0x2435c6, - 0x343343, - 0x30c504, - 0x10a3fec2, - 0x24cf43, - 0x327783, - 0x212c02, - 0x10e00d42, - 0x2cb886, - 0x234807, - 0x3c25c7, - 0x3b91c5, - 0x3d3004, - 0x29fbc5, - 0x2253c7, - 0x2ade49, - 0x2c19c6, - 0x2ec246, - 0x1120b682, - 0x2f4b48, - 0x3ae1c6, - 0x2aed85, - 0x30a6c7, - 0x3562c4, - 0x3562c5, - 0x11668c84, - 0x268c88, - 0x11a06082, - 0x11e00482, - 0x26e986, - 0x200488, - 0x331ac5, - 0x34b646, - 0x34ef88, - 0x35b788, - 0x12201805, - 0x126136c4, - 0x2136c7, - 0x12a07cc2, - 0x12e167c2, - 0x14201242, - 0x2f3245, - 0x14a83545, - 0x262486, - 0x323647, - 0x39f087, - 0x14e14a83, - 0x338487, - 0x38a948, - 0x2022cd09, - 0x26e407, - 0x22d447, - 0x22e548, - 0x22ed46, - 0x22f486, - 0x2300cc, - 0x23180a, - 0x231c07, - 0x23384b, - 0x234647, - 0x23464e, - 0x20635944, - 0x235b44, - 0x238b07, - 0x25c7c7, - 0x23d006, - 0x23d007, - 0x3b3147, - 0x2d2c43, - 0x20a2ba02, - 0x23e306, - 0x23e30a, - 0x23f44b, - 0x240987, - 0x241405, - 0x241e43, - 0x242246, - 0x242247, - 0x2f8983, - 0x20e00102, - 0x242bca, - 0x21377dc2, - 0x2173da82, - 0x21a3fd02, - 0x21e373c2, - 0x245385, - 0x245d44, - 0x22a05582, - 0x235805, - 0x23fa43, - 0x314885, - 0x2688c4, - 0x2afb04, - 0x2cea06, - 0x250f06, - 0x2061c3, - 0x3bb644, - 0x303ec3, - 0x23a02a42, - 0x213c44, - 0x213c46, - 0x221745, - 0x244d46, - 0x30a7c8, - 0x223dc4, - 0x367bc8, - 0x231e85, - 0x262b88, - 0x2caa06, - 0x217c07, - 0x273504, - 0x24e73506, - 0x252239c3, - 0x39e183, - 0x31d988, - 0x29ffc4, - 0x2572ccc7, - 0x25ee4846, - 0x2e4849, - 0x362008, - 0x36a408, - 0x3b6544, - 0x3c7903, - 0x22dd42, - 0x2624e782, - 0x2660fa82, - 0x3c9083, - 0x26a01642, - 0x2f8904, - 0x279986, - 0x21c103, - 0x2bc7c7, - 0x303743, - 0x32fcc8, - 0x20b885, - 0x25a683, - 0x2c2345, - 0x2c2484, + 0x375d04, + 0x2ef285, + 0x2215c7, + 0x25d04e, + 0x2ba484, + 0x29a884, + 0x20ebc3, + 0x35c549, + 0x2c17cb, + 0x2c75c8, + 0x32cc48, + 0x3313c8, + 0x3e1f48, + 0x370d8a, + 0x390d07, + 0x356606, + 0x9e3de82, + 0x26f0c3, + 0x3d2103, + 0x3d3c84, + 0x26f103, + 0x361e43, + 0x1737f82, + 0xa206c02, + 0x284a05, + 0x2bc146, + 0x234944, + 0x3aee07, + 0x26bdc6, + 0x2cd644, + 0x3bdc87, + 0x20d483, + 0xa6d7f02, + 0xab0bf02, + 0xae7b6c2, 0x30bcc6, - 0x20cac6, - 0x2198c6, - 0x2f39c4, - 0x234a03, - 0x26e0fe02, - 0x27233fc5, - 0x200843, - 0x27a07382, - 0x22d1c3, - 0x2676c5, - 0x27e32dc3, - 0x28632dc9, - 0x28a00942, - 0x29208902, - 0x28ce05, - 0x213f06, - 0x28ec06, - 0x2e6608, - 0x2e660b, - 0x339c8b, - 0x3b93c5, - 0x2d6149, - 0x1600b42, - 0x2f0548, - 0x206984, - 0x29a03c42, - 0x34a843, - 0x2a25c986, - 0x3c2888, - 0x2a6142c2, - 0x35c708, - 0x2aaaac82, - 0x337f8a, - 0x2aedb383, - 0x2b776c86, - 0x392488, - 0x214886, - 0x387b87, - 0x243147, - 0x3c33ca, - 0x247604, - 0x360704, - 0x376209, - 0x2bba9dc5, - 0x26e286, - 0x210e03, - 0x24e3c4, - 0x2be196c4, - 0x3458c7, - 0x2c241c87, - 0x294f84, - 0x39f545, - 0x262548, - 0x39e647, - 0x3a24c7, - 0x2c60dec2, - 0x29cf44, - 0x293048, - 0x246d84, - 0x24b904, - 0x24bcc5, - 0x24be07, - 0x2ca7ebc9, - 0x2232c4, - 0x24d789, - 0x24d9c8, - 0x24e144, - 0x24e147, - 0x2ce4e583, - 0x24ea87, - 0x2d20bb42, - 0x16b8842, - 0x24fa46, - 0x250087, - 0x250704, - 0x251d07, - 0x253787, - 0x253f83, - 0x22dec2, - 0x20d982, - 0x303243, - 0x3c6704, - 0x3c670b, - 0x2d703248, - 0x25a044, - 0x255b85, - 0x257407, - 0x2e92c5, - 0x33144a, + 0xb200282, + 0x2a4d45, + 0x3394c3, + 0x3d5bc4, + 0x2f9284, + 0x2f9285, + 0x3dff03, + 0xb64ac43, + 0xba05102, + 0x2093c5, + 0x2093cb, + 0x2b2a0b, + 0x204cc4, + 0x209849, + 0x20ae84, + 0xbe0b742, + 0x20c303, + 0x20e1c3, + 0xc207f42, + 0x2f2aca, + 0xc608a02, + 0x280285, + 0x2e858a, + 0x242644, + 0x210143, + 0x210a04, + 0x211943, + 0x211944, + 0x211947, + 0x212685, + 0x213086, + 0x213386, + 0x214683, + 0x218248, + 0x217143, + 0xca0cfc2, + 0x266308, + 0x28ea8b, + 0x2208c8, + 0x221106, + 0x222887, + 0x225048, + 0xda0aac2, + 0xde1c942, + 0x272d48, + 0x20f1c7, + 0x20f705, + 0x310f88, + 0xe302e48, + 0x2b0ec3, + 0x22bec4, + 0x391f42, + 0xe62c0c2, + 0xea06cc2, + 0xf22c442, + 0x22c443, + 0xf60cf02, + 0x316343, + 0x332284, + 0x214803, + 0x354f44, + 0x32430b, + 0x20cf03, + 0x2f2086, + 0x25d544, + 0x2c888e, + 0x377205, + 0x268a88, + 0x3adfc7, + 0x3adfca, + 0x231503, + 0x2355c7, + 0x2c1985, + 0x231504, + 0x253a06, + 0x253a07, + 0x31dd84, + 0xfb109c4, + 0x25d384, + 0x25d386, + 0x252684, + 0x3c2f86, + 0x20f4c3, + 0x20f4c8, + 0x210448, + 0x29a843, + 0x2f2a83, + 0x343c04, + 0x35c0c3, + 0x1020cdc2, + 0x106bd282, + 0x205083, + 0x243fc6, + 0x25bac3, + 0x274784, + 0x10a30c82, + 0x25ce43, + 0x316a83, + 0x214dc2, + 0x10e00d42, + 0x2d3286, + 0x235a07, + 0x229bc7, + 0x3c0d85, + 0x21cc84, + 0x2a0dc5, + 0x30f247, + 0x2e5a49, + 0x2ee886, + 0x3032c6, + 0x11602282, + 0x307a08, + 0x31a706, + 0x2b1bc5, + 0x30c3c7, + 0x30dcc4, + 0x30dcc5, + 0x11a02284, + 0x202288, + 0x11e09482, + 0x12200482, + 0x275946, + 0x200488, + 0x337b45, + 0x34d686, + 0x350448, + 0x360a48, + 0x12608cc5, + 0x12a15e84, + 0x215e87, + 0x12e0a902, + 0x13361e82, + 0x14612402, + 0x2f4505, + 0x14e8af45, + 0x269506, + 0x327ec7, + 0x3b26c7, + 0x1522ea43, + 0x32bb87, + 0x3c17c8, + 0x2162ed49, + 0x2753c7, + 0x22f487, + 0x22fe88, + 0x230686, + 0x231006, + 0x231c4c, + 0x23294a, + 0x232d47, + 0x234a4b, + 0x235847, + 0x23584e, + 0x21a36344, + 0x236704, + 0x238a07, + 0x260b47, + 0x23d046, + 0x23d047, + 0x335887, + 0x226dc3, + 0x21e2c982, + 0x23e846, + 0x23e84a, + 0x24004b, + 0x241287, + 0x241d05, + 0x242183, + 0x2423c6, + 0x2423c7, + 0x2fa483, + 0x22200102, + 0x2435ca, + 0x2277c682, + 0x22b49682, + 0x22e40902, + 0x23237402, + 0x246ac5, + 0x247344, + 0x23e0da02, + 0x385d85, + 0x240643, + 0x299645, + 0x201ec4, + 0x21dd04, + 0x2d4e46, + 0x251dc6, + 0x2095c3, + 0x3cce44, + 0x37f243, + 0x24e0f982, + 0x216404, + 0x216406, + 0x222c05, + 0x2482c6, + 0x30c4c8, + 0x265e44, + 0x294208, + 0x232fc5, + 0x259508, + 0x2d0686, + 0x30e0c7, + 0x269c04, + 0x26269c06, + 0x26622383, + 0x3a47c3, + 0x2f7108, + 0x38bc44, + 0x26b32ec7, + 0x2e6946, + 0x2e6949, + 0x369588, + 0x37d748, + 0x389c84, + 0x204583, + 0x240702, + 0x2724e682, + 0x27626282, + 0x205c83, + 0x27a08b02, + 0x2fa404, + 0x2790c6, + 0x21a203, + 0x2c3d47, + 0x3b3a83, + 0x2ba548, + 0x21edc5, 0x259f83, - 0x2da05dc2, - 0x208e04, - 0x25c589, - 0x260c03, - 0x260cc7, - 0x240749, - 0x205dc8, - 0x22af03, - 0x27b3c7, - 0x27be89, - 0x225583, - 0x283b84, - 0x284d09, - 0x28b2c6, - 0x2f4103, - 0x2015c2, - 0x23c903, - 0x2b8647, - 0x23c905, - 0x3b1686, - 0x270744, - 0x35ff85, - 0x27c7c3, - 0x212706, - 0x292503, - 0x206882, - 0x248f84, - 0x2de299c2, - 0x2e2299c3, - 0x2e607082, - 0x248343, - 0x211cc4, - 0x2ece07, - 0x2946c6, - 0x262302, - 0x2ea5cd82, - 0x30a9c4, - 0x2f20d842, - 0x2f616902, - 0x2ef084, - 0x2ef085, - 0x302c85, - 0x35ef86, - 0x2fa0f582, - 0x39b745, - 0x3ba745, - 0x283483, - 0x20f586, - 0x20fec5, - 0x220cc2, - 0x35b3c5, - 0x220cc4, - 0x223d03, - 0x223f43, - 0x2fe05b42, - 0x2e29c7, - 0x24dbc4, + 0x2ef205, + 0x2ef344, + 0x30d9c6, + 0x220006, + 0x221506, + 0x2f4c84, + 0x235c03, + 0x27e11702, + 0x282351c5, + 0x200843, + 0x28a0da82, + 0x22f203, + 0x3233c5, + 0x28e33fc3, + 0x29633fc9, + 0x29a00942, + 0x2a20fc42, + 0x292845, + 0x2166c6, + 0x2ada86, + 0x2e9f08, + 0x2e9f0b, + 0x346d4b, + 0x3c0f85, + 0x2d8489, + 0x1600b42, + 0x39b4c8, + 0x209b44, + 0x2aa031c2, + 0x34ca03, + 0x2b260d06, + 0x2b600fc2, + 0x3619c8, + 0x2ba293c2, + 0x33d78a, + 0x2bedd983, + 0x2c77b706, + 0x397c88, + 0x242986, + 0x38dc47, + 0x243b47, + 0x3cd90a, + 0x2426c4, + 0x365c04, + 0x37a709, + 0x2cbb1905, + 0x275246, + 0x20f3c3, + 0x24e104, + 0x2ced8384, + 0x3b4447, + 0x2d233647, + 0x25ce84, + 0x3b2b85, + 0x2695c8, + 0x3a4c87, + 0x3a9847, + 0x2d60fa02, + 0x26acc4, + 0x2981c8, + 0x248604, + 0x24bb44, + 0x24bf45, + 0x24c087, + 0x2da81989, + 0x21eb04, + 0x24d4c9, + 0x24d708, + 0x24de84, + 0x24de87, + 0x2de4e483, + 0x24f8c7, + 0x2e201282, + 0x16be142, + 0x250386, + 0x251187, + 0x2515c4, + 0x252dc7, + 0x254047, + 0x254603, + 0x2ba882, + 0x20e782, + 0x32cd43, + 0x3ce884, + 0x3ce88b, + 0x2e72cd48, + 0x259a04, + 0x255d05, + 0x2576c7, + 0x20e785, + 0x31d28a, + 0x259943, + 0x2ea091c2, + 0x21d304, + 0x260909, + 0x264e43, + 0x264f07, + 0x28c949, + 0x2091c8, + 0x26f783, + 0x283187, + 0x283b89, + 0x26a503, + 0x28b544, + 0x28cb89, + 0x290cc6, + 0x2e9d03, + 0x207c82, + 0x23cc03, + 0x2bdf47, + 0x23cc05, + 0x2c15c6, + 0x296d84, + 0x365485, + 0x2844c3, + 0x2148c6, + 0x27eb43, + 0x209a42, + 0x24ac04, + 0x2ee08882, + 0x2f368483, + 0x2f6033c2, + 0x249f83, + 0x20dc44, + 0x303b07, + 0x348546, + 0x27cec2, + 0x2fa04d82, + 0x30c6c4, + 0x30211ac2, + 0x30621c42, + 0x2f0f04, + 0x2f0f05, + 0x363e85, + 0x260286, + 0x30a06d42, + 0x20f8c5, + 0x219a45, + 0x21bb43, + 0x225d86, + 0x227545, + 0x265d82, + 0x360685, + 0x30bc44, + 0x265d83, + 0x265fc3, + 0x30e08f42, + 0x2e4dc7, + 0x24d904, + 0x24d909, + 0x24e004, + 0x28adc3, + 0x2b9808, + 0x3128adc4, + 0x28adc6, + 0x2a49c3, + 0x256543, + 0x266a83, + 0x316fb9c2, + 0x308982, + 0x31a00642, + 0x33b208, + 0x3e0108, + 0x3bef86, + 0x351a05, + 0x303c85, + 0x207d87, + 0x31e46145, + 0x23ca82, + 0x3229cac2, + 0x32600042, + 0x27db48, + 0x31a645, + 0x2feac4, + 0x248205, + 0x2497c7, + 0x388944, + 0x2434c2, + 0x32a0b2c2, + 0x352084, + 0x228b07, + 0x292d07, + 0x390dc4, + 0x3d2c03, + 0x29a784, + 0x29a788, + 0x231346, + 0x25388a, + 0x2f5844, + 0x299e48, + 0x235384, + 0x222986, + 0x29ca84, + 0x2f4806, 0x24dbc9, - 0x24e2c4, - 0x2833c3, - 0x2b61c8, - 0x302833c4, - 0x2833c6, - 0x2a37c3, - 0x256303, - 0x308003, - 0x306f7642, - 0x309442, - 0x30a00642, - 0x335408, - 0x36af48, - 0x3b7906, - 0x3830c5, - 0x22c805, - 0x204287, - 0x30e77185, - 0x23c782, - 0x3129b602, - 0x31600042, - 0x2cfb88, - 0x3ae105, - 0x2fc7c4, - 0x244c85, - 0x2547c7, - 0x3a3884, - 0x242ac2, - 0x31a11442, - 0x351144, - 0x220a87, - 0x28ddc7, - 0x378804, - 0x3cd483, - 0x290e44, - 0x290e48, - 0x22f7c6, - 0x25254a, - 0x326584, - 0x299288, - 0x234184, - 0x2214c6, - 0x29b5c4, - 0x2f3546, - 0x24de89, - 0x2a9fc7, - 0x207543, - 0x31e3ee42, - 0x3b62c3, - 0x209e42, - 0x32204702, - 0x349e46, - 0x381988, - 0x2abfc7, - 0x228b09, - 0x2b1549, - 0x2ad505, - 0x2afc09, + 0x2abc07, + 0x213ec3, + 0x32e5b542, + 0x3a2503, + 0x20b942, + 0x33205742, + 0x34c006, + 0x386d08, + 0x2adc07, + 0x30b109, + 0x2addc9, 0x2b0405, - 0x2b1245, - 0x2b1f88, - 0x32608784, - 0x32a540c7, - 0x22d803, - 0x2b2187, - 0x22d806, - 0x2b25c7, - 0x2a9ac5, - 0x22d083, - 0x32e315c2, - 0x20b344, - 0x3320e782, - 0x33606502, - 0x380e86, - 0x2d04c5, - 0x2b54c7, - 0x343a03, - 0x35cb04, - 0x209283, - 0x2cd743, - 0x33a06182, - 0x34205bc2, - 0x38b244, - 0x22de83, - 0x3047c5, - 0x34600f42, - 0x34e01f02, - 0x304fc6, - 0x201f04, - 0x306bc4, - 0x306bca, - 0x356005c2, - 0x213903, - 0x21884a, - 0x21bac8, - 0x35a21dc4, + 0x2b2d89, + 0x2b3cc5, + 0x2b4b05, + 0x2b5f88, + 0x33611b04, + 0x33a54747, + 0x22f843, + 0x2b6187, + 0x22f846, + 0x2b6987, + 0x2ab845, + 0x22f0c3, + 0x33e32702, + 0x210384, + 0x3422cb02, + 0x3460b5c2, + 0x314d06, + 0x27e485, + 0x2b8ec7, + 0x356e03, + 0x361dc4, + 0x21d783, + 0x355e03, + 0x34a09582, + 0x35208fc2, + 0x391fc4, + 0x32ae03, + 0x305545, + 0x3560f782, + 0x35e02182, + 0x305d46, + 0x2069c4, + 0x30a304, + 0x30a30a, + 0x366005c2, + 0x2160c3, + 0x21528a, + 0x219008, + 0x36a0e704, 0x2005c3, - 0x35e96b43, - 0x237909, - 0x22e0c9, - 0x2bc8c6, - 0x3621bc83, - 0x21bc85, - 0x222f8d, - 0x226586, - 0x26518b, - 0x3660ccc2, - 0x205708, - 0x3a217782, - 0x3a605382, - 0x2bad85, - 0x3aa04582, - 0x2b3307, - 0x210083, - 0x210088, - 0x3ae07882, - 0x288304, - 0x20c743, - 0x33b805, - 0x23fb46, - 0x224004, - 0x398983, - 0x2b9583, - 0x3b201d82, - 0x3b9344, - 0x3d4c45, - 0x2b8247, - 0x279403, - 0x2b8e43, - 0x16b9102, - 0x2b9103, - 0x2b9503, - 0x3b600e02, - 0x3473c4, - 0x251106, - 0x2e42c3, - 0x2b9c03, - 0x3ba49582, - 0x249588, - 0x2bab84, - 0x347146, - 0x255707, - 0x284646, - 0x29ff44, - 0x49e03fc2, - 0x22d6cb, - 0x2ff50e, - 0x216d8f, - 0x39d6c3, - 0x4a65ac42, - 0x161fb02, - 0x4aa0af02, - 0x2928c3, - 0x2108c3, - 0x20af06, - 0x21d306, - 0x34dec7, - 0x310c44, - 0x4ae14042, - 0x4b20bd82, - 0x2e0685, - 0x2ff987, - 0x2bb206, - 0x4b662702, - 0x384c44, - 0x2c03c3, - 0x4ba01e42, - 0x4bf73103, - 0x2c2984, - 0x2c8009, - 0x4c2ced42, - 0x4c614d42, - 0x344945, - 0x4cad3942, - 0x4ce06002, - 0x35f947, - 0x3768cb, - 0x242f05, - 0x258109, - 0x26aa86, - 0x4d209504, - 0x295449, - 0x2d46c7, - 0x3dea87, - 0x22c343, - 0x2eef06, - 0x324047, - 0x25cc03, - 0x2a6a86, - 0x4da1ae42, - 0x4de33042, - 0x3b6403, - 0x38b885, - 0x21f407, - 0x236146, - 0x23c885, - 0x24db44, - 0x2a8985, - 0x38dac4, - 0x4e202482, - 0x2cc844, - 0x22dfc4, - 0x22dfcd, - 0x377189, - 0x22c648, - 0x344bc4, - 0x328845, - 0x3b8c47, - 0x3c5cc4, - 0x265907, - 0x2e4005, - 0x4e6ac604, - 0x2bf345, - 0x25f8c4, - 0x3a39c6, - 0x3973c5, - 0x4ea05442, - 0x26e903, - 0x267fc3, - 0x348cc4, - 0x348cc5, - 0x396886, - 0x23c9c5, - 0x22ae84, - 0x329743, - 0x4ee1a286, - 0x221fc5, - 0x222a85, - 0x323544, - 0x2f6283, - 0x32660c, - 0x4f208b02, - 0x4f605102, - 0x4fa02042, - 0x21a8c3, - 0x21a8c4, - 0x4fe08282, - 0x30e1c8, - 0x3b1745, - 0x2d3b84, - 0x23af86, - 0x50223502, - 0x5061b542, - 0x50a00c42, - 0x290c05, - 0x2f3886, - 0x219604, - 0x39a0c6, - 0x362dc6, - 0x211183, - 0x50ea240a, - 0x2795c5, - 0x350503, - 0x222446, - 0x3d2d09, - 0x222447, - 0x2b4d08, - 0x32f0c9, - 0x2adfc8, - 0x227d46, - 0x2105c3, - 0x512017c2, - 0x39fa08, - 0x51601f42, - 0x51a09e82, - 0x2137c3, - 0x2ec0c5, - 0x29f2c4, - 0x2fe389, - 0x2898c4, - 0x24aec8, - 0x52209e83, - 0x52696ec4, - 0x213f48, - 0x22df07, - 0x52b3d642, - 0x238442, - 0x32a385, - 0x37fc49, - 0x23c803, - 0x27e384, - 0x31d284, - 0x210943, - 0x27f28a, - 0x52e03f82, - 0x5320b182, - 0x2d5b43, - 0x390883, - 0x1627f82, - 0x374583, - 0x5361d542, - 0x53a00bc2, - 0x53f06c44, - 0x3d7846, - 0x26bbc4, - 0x277d83, - 0x281c83, - 0x54200bc3, - 0x23f7c6, - 0x208405, - 0x2d9ac7, - 0x2d9a06, - 0x2dab48, - 0x2dad46, - 0x20e944, - 0x2a0f0b, - 0x2dd603, - 0x2dd605, - 0x20f002, - 0x35fc42, - 0x54645402, - 0x54a02382, - 0x202383, - 0x54e6c9c2, - 0x26c9c3, - 0x2de083, - 0x55622902, - 0x55ae2406, - 0x258946, - 0x55e05902, - 0x5620a742, - 0x56623f82, - 0x56a15402, - 0x56e18482, - 0x57202802, - 0x214e83, - 0x385546, - 0x57619a04, - 0x213a4a, - 0x3a4986, - 0x20da84, - 0x204643, - 0x5820ce02, - 0x208482, - 0x23a0c3, - 0x5861a3c3, - 0x3bd287, - 0x3972c7, - 0x5aed3087, - 0x344407, - 0x228643, - 0x22864a, - 0x262044, - 0x31afc4, - 0x31afca, - 0x22cb45, - 0x5b21bb02, - 0x24fa03, - 0x5b600602, - 0x24e283, - 0x3b6283, - 0x5be00582, - 0x38a8c4, - 0x204484, - 0x3c2d05, - 0x3dd205, - 0x26a146, - 0x306e06, - 0x5c230a42, - 0x5c602902, - 0x310805, - 0x258652, - 0x35e586, - 0x207283, - 0x359106, - 0x2bf805, - 0x16535c2, - 0x64a0a9c2, - 0x372b43, - 0x20a9c3, - 0x292083, - 0x64e06e42, - 0x210e83, - 0x6521ad42, - 0x276e43, - 0x24b188, - 0x2624c3, - 0x2ad386, - 0x3cfc87, - 0x321486, - 0x32148b, - 0x20d9c7, - 0x31d784, - 0x65a00c02, - 0x3b15c5, - 0x65e08443, - 0x26d243, - 0x3b29c5, - 0x33f243, - 0x6673f246, - 0x3cac0a, - 0x2a7083, - 0x2366c4, + 0x36e0a2c3, + 0x26a749, + 0x247109, + 0x2c3e46, + 0x372191c3, + 0x2191c5, + 0x21e7cd, + 0x22db06, + 0x2e61cb, + 0x37607542, + 0x358448, + 0x3b20c202, + 0x3b603082, + 0x39e285, + 0x3ba04b82, + 0x2af7c7, + 0x205603, + 0x227708, + 0x3be022c2, + 0x25ef84, + 0x21fc83, + 0x354a05, + 0x240746, + 0x227104, + 0x2f2a43, + 0x384583, + 0x3c206142, + 0x3c0f04, + 0x2bab45, + 0x2bdb47, + 0x281403, + 0x2be4c3, + 0x1616fc2, + 0x2be783, + 0x2beb83, + 0x3c600e02, + 0x33f584, + 0x235e06, + 0x2e6503, + 0x2bf943, + 0x3ca4b202, + 0x24b208, + 0x2c0904, + 0x33f306, + 0x253e87, + 0x29a946, + 0x38bbc4, + 0x4ae03102, + 0x22f70b, + 0x30180e, + 0x217a8f, + 0x2be183, + 0x4b65a642, + 0x1641882, + 0x4ba03802, + 0x2563c3, + 0x20ee83, + 0x21b306, + 0x34e0c6, + 0x395dc7, + 0x3d2484, + 0x4be16802, + 0x4c21f2c2, + 0x2e2845, + 0x33dec7, + 0x2c2506, + 0x4c669782, + 0x3626c4, + 0x2c7a83, + 0x4ca06902, + 0x4cf78103, + 0x2c9284, + 0x2cde89, + 0x4d2d5182, + 0x4d60a342, + 0x248985, + 0x4dad5682, + 0x4de01582, + 0x364e47, + 0x37b34b, + 0x243905, + 0x258509, + 0x270906, + 0x4e201584, + 0x206d89, + 0x2d6a07, + 0x22a147, + 0x22c743, + 0x2f0d86, + 0x352f87, + 0x21df43, + 0x2a87c6, + 0x4ea29a82, + 0x4ee34242, + 0x2061c3, + 0x392605, + 0x303147, + 0x236d06, + 0x23cb85, + 0x24d884, + 0x2aad45, + 0x393dc4, + 0x4f201482, + 0x2e9184, + 0x247004, + 0x24700d, + 0x2ee249, + 0x22ca48, + 0x248c04, + 0x347fc5, + 0x204407, + 0x206504, + 0x26be87, + 0x267a45, + 0x4f60a284, + 0x2c6045, + 0x201484, + 0x253306, + 0x394fc5, + 0x4faa4c82, + 0x2758c3, + 0x357643, + 0x35d804, + 0x35d805, + 0x39d506, + 0x23ccc5, + 0x368e84, + 0x364343, + 0x4fe17e86, + 0x21a8c5, + 0x21e2c5, + 0x327dc4, + 0x2f58c3, + 0x2f58cc, + 0x502bdc42, + 0x50600e82, + 0x50a02702, + 0x21e1c3, + 0x21e1c4, + 0x50e0a682, + 0x3b9e88, + 0x2c1685, + 0x2d5ec4, + 0x230e86, + 0x51204202, + 0x5162d582, + 0x51a00c42, + 0x296545, + 0x2f4b46, + 0x265684, + 0x335386, + 0x229306, + 0x25bfc3, + 0x51e9068a, + 0x2815c5, + 0x293783, + 0x209f06, + 0x209f09, + 0x223fc7, + 0x2b7fc8, + 0x3c84c9, + 0x2e5bc8, + 0x22dd86, + 0x20eb83, + 0x52208c82, + 0x32d248, + 0x52606a02, + 0x52a0b982, + 0x215f83, + 0x2ee705, + 0x2a0484, + 0x300689, + 0x3c04c4, + 0x20bc08, + 0x5320b983, + 0x53724784, + 0x216708, + 0x246f47, + 0x53b49242, + 0x370242, + 0x32f4c5, + 0x385509, + 0x23cb03, + 0x31bb84, + 0x3424c4, + 0x204483, + 0x28698a, + 0x53f93b42, + 0x542101c2, + 0x2d7e83, + 0x396083, + 0x162dfc2, + 0x26e8c3, + 0x54615782, + 0x54a00bc2, + 0x54e17544, + 0x217546, + 0x271a44, + 0x27d983, + 0x289683, + 0x55200bc3, + 0x2403c6, + 0x3d5d85, + 0x2dbe07, + 0x2dbd46, + 0x2dcd88, + 0x2dcf86, + 0x202a04, + 0x2a21cb, + 0x2dfa03, + 0x2dfa05, + 0x20e982, + 0x365142, + 0x55646b42, + 0x55a0a942, + 0x216843, + 0x55e720c2, + 0x2720c3, + 0x2e0483, + 0x56603e42, + 0x56ae4806, + 0x258d46, + 0x56ee4942, + 0x5720e202, + 0x57666002, + 0x57a0cac2, + 0x57e0e882, + 0x58203882, + 0x20c543, + 0x3af006, + 0x5861e484, + 0x21620a, + 0x3b0106, + 0x281284, + 0x208143, + 0x59216102, + 0x203182, + 0x241c83, + 0x59617fc3, + 0x3c49c7, + 0x394ec7, + 0x5c245ec7, + 0x37efc7, + 0x228803, + 0x22880a, + 0x237bc4, + 0x31ef04, + 0x31ef0a, + 0x22eb85, + 0x5c60e742, + 0x250343, + 0x5ca00602, + 0x24dfc3, + 0x3a24c3, + 0x5d200582, + 0x3c1744, + 0x207f84, + 0x3dcc45, + 0x32e9c5, + 0x2f6786, + 0x30a546, + 0x5d63bec2, + 0x5da02542, + 0x301dc5, + 0x258a52, + 0x363486, + 0x291043, + 0x31c146, + 0x2b6585, + 0x1605cc2, + 0x65e0fec2, + 0x377b43, + 0x20fec3, + 0x39f483, + 0x66201102, + 0x20f443, + 0x666035c2, + 0x207583, + 0x3dcf88, + 0x269543, + 0x2b0286, + 0x3da087, + 0x34f0c6, + 0x34f0cb, + 0x2811c7, + 0x2f6f04, + 0x66e00c02, + 0x2c1505, + 0x67217f83, + 0x235fc3, + 0x332505, + 0x34a9c3, + 0x67b4a9c6, + 0x3d048a, + 0x2a98c3, + 0x2371c4, 0x2003c6, - 0x2af186, - 0x66a42543, - 0x299047, - 0x237807, - 0x2a2c85, - 0x2e4406, - 0x222003, - 0x6960f7c3, - 0x69a00a82, - 0x69e0f044, - 0x3df689, - 0x21d685, - 0x356cc4, - 0x355b48, - 0x264bc5, - 0x6a231ac5, - 0x241f49, - 0x202503, - 0x33da04, - 0x6a614282, - 0x214283, - 0x6aa57b82, - 0x257b86, - 0x1677282, - 0x6ae15302, - 0x290b08, - 0x290e03, - 0x2bf287, - 0x2b9605, - 0x2b9185, - 0x2b918b, - 0x2eec86, - 0x2b9386, - 0x27d384, - 0x2efa86, - 0x6b321708, - 0x27fd03, - 0x265f03, - 0x265f04, - 0x2ed8c4, - 0x2f6a07, - 0x315645, - 0x6b72a5c2, - 0x6ba0a882, - 0x6c21bfc5, - 0x2c1044, - 0x2e0a0b, - 0x2f7688, - 0x253604, - 0x6c62c4c2, - 0x6ca1b742, - 0x3ba2c3, - 0x2f9484, - 0x2f9745, - 0x2fa147, - 0x6cefc304, - 0x378904, - 0x6d2141c2, - 0x37ab09, - 0x2fd745, - 0x2431c5, - 0x2fe2c5, - 0x6d6141c3, - 0x237f04, - 0x237f0b, - 0x2fedc4, - 0x2ff08b, - 0x3001c5, - 0x216eca, - 0x301708, - 0x30190a, - 0x3021c3, - 0x3021ca, - 0x6de11e42, - 0x6e214b42, - 0x6e615d43, - 0x6eadbd02, - 0x3068c3, - 0x6eef6702, - 0x6f333e42, - 0x309004, - 0x2177c6, - 0x399e05, - 0x30a643, - 0x298046, - 0x399905, - 0x3573c4, - 0x6f600902, - 0x299ec4, - 0x2d5dca, - 0x2ba807, - 0x33f5c6, - 0x234207, - 0x23e343, - 0x2c29c8, - 0x3d21cb, - 0x2bc9c5, - 0x2c8b85, - 0x2c8b86, - 0x34cb84, - 0x38ab88, - 0x21aa43, - 0x26ee44, - 0x3c3747, - 0x31d3c6, - 0x380b86, - 0x2c324a, - 0x24d804, - 0x31c0ca, - 0x6fb12606, - 0x312607, - 0x255c07, - 0x2a9a04, - 0x34a189, - 0x238dc5, - 0x307a4b, - 0x2f6603, - 0x20cc83, - 0x6fe1e243, - 0x22fb84, - 0x70200682, - 0x307e06, - 0x706c60c5, - 0x359345, - 0x24fc86, - 0x2a4944, - 0x70a013c2, - 0x241e84, - 0x70e0ca42, - 0x2160c5, - 0x3b2e44, - 0x71a1c5c3, - 0x71e0aa02, - 0x20aa03, - 0x21f646, - 0x72205142, - 0x393d08, - 0x2222c4, - 0x2222c6, - 0x391106, - 0x726574c4, - 0x21a205, - 0x356d88, - 0x3577c7, - 0x2ae247, - 0x2ae24f, - 0x292f46, - 0x23d183, - 0x242144, - 0x209043, - 0x221604, - 0x24e484, - 0x72a0b382, - 0x28d203, - 0x330983, - 0x72e090c2, - 0x215803, - 0x220f03, - 0x20e2ca, - 0x273847, - 0x25284c, - 0x73252b06, - 0x252c86, - 0x255407, - 0x7362e987, - 0x25a749, - 0x308784, - 0x73a5be04, - 0x73e023c2, - 0x742045c2, - 0x2c3606, - 0x298e44, - 0x28d686, - 0x22ee08, - 0x38b944, - 0x2eafc6, - 0x28ebc5, - 0x74750788, - 0x242343, - 0x3a6b85, - 0x3aa603, - 0x2432c3, - 0x2432c4, - 0x208dc3, - 0x74a499c2, - 0x74e02d42, - 0x2f64c9, - 0x290d05, - 0x291604, - 0x29ab05, - 0x206a84, - 0x286707, - 0x35a685, - 0x7523e804, - 0x2db988, - 0x2dcdc6, - 0x2e2d44, - 0x2e6e08, - 0x2e7447, - 0x75607842, - 0x2ef184, - 0x314cc4, - 0x2c9247, - 0x75a07844, - 0x24a682, - 0x75e02f82, - 0x210883, - 0x2e5ac4, - 0x299943, - 0x2b2cc5, - 0x7622ae42, - 0x309345, - 0x23c7c2, - 0x30f885, - 0x23c7c5, - 0x76607242, - 0x327704, - 0x76a071c2, - 0x33d486, - 0x2c8686, - 0x37fd88, - 0x2c9c08, - 0x380e04, - 0x3cdb05, - 0x310389, - 0x2f0684, - 0x3cabc4, - 0x288b03, - 0x26c703, - 0x76f02905, - 0x3829c5, - 0x283644, - 0x359b4d, - 0x294ec2, - 0x376403, - 0x77206382, - 0x77603242, - 0x3937c5, - 0x24b447, - 0x224244, - 0x32f2c9, - 0x2d5f09, - 0x2770c3, - 0x2770c8, - 0x312b09, - 0x21e7c7, - 0x77a08805, - 0x396406, - 0x3a06c6, - 0x3a8645, - 0x377285, - 0x77e01bc2, - 0x27a585, - 0x2bd4c8, - 0x2cb646, - 0x783b4347, - 0x2cf3c4, - 0x2da987, - 0x30b306, - 0x78601082, - 0x396586, - 0x30ef0a, - 0x30f785, - 0x78af00c2, - 0x78e11102, - 0x365486, - 0x211108, - 0x7928df87, - 0x79601402, - 0x214b83, - 0x3c0706, - 0x2caac4, - 0x346ac6, - 0x271ac6, - 0x26930a, - 0x2047c5, - 0x286f06, - 0x384643, - 0x384644, - 0x79a35002, - 0x2869c3, - 0x79e1a902, - 0x2ea903, - 0x7a218ac4, - 0x211244, - 0x7a61124a, - 0x21bd03, - 0x237ac7, - 0x313146, - 0x33c284, - 0x20d942, - 0x2aad42, - 0x7aa007c2, - 0x226e83, - 0x2559c7, + 0x2b1fc6, + 0x67e3e083, + 0x273987, + 0x26a647, + 0x2a3e85, + 0x2b2346, + 0x21a903, + 0x6aa25fc3, + 0x6ae00a82, + 0x6b20e9c4, + 0x213b49, + 0x226685, + 0x266e44, + 0x35a3c8, + 0x241e85, + 0x6b642285, + 0x247e89, + 0x3b4d43, + 0x349604, + 0x6ba05b42, + 0x216a43, + 0x6be75c42, + 0x275c46, + 0x167ce82, + 0x6c20c182, + 0x296448, + 0x29a743, + 0x2c5f87, + 0x384605, + 0x2be805, + 0x2be80b, + 0x2f0b06, + 0x2bea06, + 0x2804c4, + 0x211c86, + 0x6c6f1608, + 0x287403, + 0x25be43, + 0x25be44, + 0x2f0184, + 0x2f8747, + 0x318245, + 0x6cb20202, + 0x6ce04fc2, + 0x6d604fc5, + 0x2c6a84, + 0x2f114b, + 0x2f9188, + 0x306444, + 0x6da2c8c2, + 0x6de2d782, + 0x3c2f03, + 0x2faf84, + 0x2fb245, + 0x2fbd47, + 0x6e2fe604, + 0x390ec4, + 0x6e616982, + 0x380fc9, + 0x2ffa45, + 0x243bc5, + 0x3005c5, + 0x6ea16983, + 0x237e84, + 0x237e8b, + 0x3010c4, + 0x30138b, + 0x301f05, + 0x217bca, + 0x303dc8, + 0x303fca, + 0x304883, + 0x30488a, + 0x6f213982, + 0x6f642c42, + 0x6fa0d403, + 0x6fede302, + 0x307643, + 0x702f8442, + 0x70739c42, + 0x308544, + 0x218386, + 0x3350c5, + 0x30c343, + 0x32fc06, + 0x3a0645, + 0x366b44, + 0x70a00902, + 0x2ae704, + 0x2d810a, + 0x2c0587, + 0x34ad46, + 0x235407, + 0x23e883, + 0x2c92c8, + 0x3dc44b, + 0x2ce445, + 0x223585, + 0x223586, + 0x342604, + 0x3cd748, + 0x2198c3, + 0x28b144, + 0x3cdc87, + 0x2f6b46, + 0x314a06, + 0x2c86ca, + 0x24d544, + 0x3214ca, + 0x70f5ccc6, + 0x35ccc7, + 0x255d87, + 0x2ab784, + 0x34c349, + 0x238cc5, + 0x2f8343, + 0x2201c3, + 0x7121b843, + 0x231704, + 0x71600682, + 0x266886, + 0x71acbc45, + 0x31c385, + 0x2505c6, + 0x2a6184, + 0x71e02b02, + 0x2421c4, + 0x7220d782, + 0x20d785, + 0x37d504, + 0x7361a6c3, + 0x73a08382, + 0x208383, + 0x34d886, + 0x73e07742, + 0x399508, + 0x223e44, + 0x223e46, + 0x396906, + 0x74257784, + 0x217e05, + 0x368548, + 0x265c07, + 0x2b1087, + 0x2b108f, + 0x2980c6, + 0x23c0c3, + 0x23db04, + 0x219b43, + 0x222ac4, + 0x24c404, + 0x74606c82, + 0x2bef83, + 0x337143, + 0x74a08502, + 0x20cec3, + 0x30be83, + 0x21270a, + 0x279407, + 0x25070c, + 0x74e509c6, + 0x250b46, + 0x253b87, + 0x752302c7, + 0x259009, + 0x75666444, + 0x75a0a1c2, + 0x75e02442, + 0x2c8a86, + 0x273784, + 0x2bf406, + 0x230748, + 0x3926c4, + 0x2f7a46, + 0x2ada45, + 0x7628dc88, + 0x2424c3, + 0x292005, + 0x3ab143, + 0x243cc3, + 0x243cc4, + 0x21d2c3, + 0x7664b642, + 0x76a04782, + 0x2f8209, + 0x293a05, + 0x293d84, + 0x294545, + 0x210f44, + 0x28eec7, + 0x35ff05, + 0x772ddf84, + 0x2ddf88, + 0x2df1c6, + 0x2e5144, + 0x2e8988, + 0x2e8fc7, + 0x7760ab02, + 0x2f1004, + 0x219c04, + 0x2ceb87, + 0x77a0ab04, + 0x2670c2, + 0x77e0ee42, + 0x20ee43, + 0x248884, + 0x29a503, + 0x2b7085, + 0x78201442, + 0x308885, + 0x23cac2, + 0x312645, + 0x23cac5, + 0x786010c2, + 0x316a04, + 0x78a018c2, + 0x349086, + 0x25ab46, + 0x385648, + 0x2cf888, + 0x314c84, + 0x35a585, + 0x310489, + 0x39b604, + 0x3d0444, + 0x2132c3, + 0x237c83, + 0x78f1fb05, + 0x24fd85, + 0x28b044, + 0x35eacd, + 0x25cdc2, + 0x366543, + 0x79201702, + 0x79600ec2, + 0x398fc5, + 0x341947, + 0x227344, + 0x3c86c9, + 0x2d8249, + 0x25fc83, + 0x27ccc8, + 0x35d1c9, + 0x220f47, + 0x79b7b845, + 0x39d086, + 0x3a7d46, + 0x3ac645, + 0x2ee345, + 0x79e06242, + 0x28db85, + 0x2c4b48, + 0x2d1686, + 0x7a22aa87, + 0x2d1ec4, + 0x2d1447, + 0x30d006, + 0x7a603c02, + 0x39d206, + 0x311cca, + 0x312545, + 0x7aa30ac2, + 0x7ae92ec2, + 0x36c7c6, + 0x7b292ec7, + 0x7b60d982, + 0x242c83, + 0x3c75c6, + 0x2d0744, + 0x33ec86, + 0x24eac6, + 0x20290a, + 0x359945, + 0x35c986, + 0x38a183, + 0x38a184, + 0x7ba1cc42, + 0x28f183, + 0x7be1e202, + 0x2fccc3, + 0x7c215504, + 0x20de04, + 0x7c60de0a, + 0x219243, + 0x239747, + 0x315146, + 0x3670c4, + 0x281142, + 0x2ac982, + 0x7ca007c2, + 0x22b3c3, + 0x255b47, 0x2007c7, - 0x285d84, - 0x3da107, - 0x2fa246, - 0x210d47, - 0x220e44, - 0x2ae145, - 0x205345, - 0x7ae1e502, - 0x3d7286, - 0x220383, - 0x2266c2, - 0x2266c6, - 0x7b21f3c2, - 0x7b633442, - 0x29d005, - 0x7ba02c02, - 0x7be02982, - 0x324605, - 0x2d7505, - 0x2ac745, - 0x7c65b003, - 0x279a45, - 0x2eed47, - 0x36cc85, - 0x204985, - 0x261f44, - 0x264a46, - 0x38e104, - 0x7ca008c2, - 0x7d793085, - 0x3cb087, - 0x3c0bc8, - 0x253c46, - 0x253c4d, - 0x262d49, - 0x262d52, - 0x37a385, - 0x37ae03, - 0x7da09d42, - 0x3027c4, - 0x226603, - 0x3cb985, - 0x310f85, - 0x7de0c782, - 0x25a6c3, - 0x7e226dc2, - 0x7ea1d602, - 0x7ee00082, - 0x2e9bc5, - 0x207643, - 0x7f205b02, - 0x7f60c2c2, - 0x38a886, - 0x2d020a, - 0x215003, - 0x2579c3, - 0x2ff8c3, - 0x80e01b82, - 0x8f20c1c2, - 0x8fa0a5c2, - 0x203642, - 0x3ce689, - 0x2ce144, - 0x2dfac8, - 0x8ff04382, - 0x90606482, - 0x3bd905, - 0x233c88, - 0x231148, - 0x2f738c, - 0x2398c3, - 0x90a075c2, - 0x90e00f02, - 0x24ac46, - 0x313fc5, - 0x295b43, - 0x254686, - 0x314106, - 0x296b03, - 0x314c03, - 0x315046, - 0x316884, - 0x29cc86, - 0x23cd44, - 0x316f44, - 0x31784a, - 0x912b7402, - 0x24e705, - 0x3193ca, - 0x319305, - 0x31a7c4, - 0x31a8c6, - 0x31aa44, - 0x214546, - 0x91602b42, - 0x24c5c6, - 0x33bf85, - 0x286d87, - 0x33a106, - 0x255604, - 0x2e3407, - 0x234f85, - 0x23b687, - 0x3bc247, - 0x3bc24e, - 0x278646, - 0x222705, - 0x207787, - 0x20a783, - 0x3d3a47, - 0x20ab85, - 0x2123c4, - 0x22a8c2, - 0x325ec7, - 0x310cc4, - 0x23dec4, - 0x284a4b, - 0x21cb83, - 0x2c4907, - 0x21cb84, - 0x2c4c07, - 0x3a6603, - 0x34e40d, - 0x3a2f88, - 0x91a292c4, - 0x23e705, - 0x31b805, - 0x31bc43, - 0x91e221c2, - 0x31d1c3, - 0x31e083, - 0x3d7404, - 0x27bf85, - 0x220407, - 0x3846c6, - 0x38d943, - 0x22680b, - 0x249b8b, - 0x2acfcb, - 0x2c174b, - 0x3ccd4a, - 0x31734b, - 0x36ea8b, - 0x394e0c, - 0x3ada0b, - 0x3bf811, - 0x3dcf4a, - 0x31f58b, - 0x31f84c, - 0x31fb4b, - 0x3200ca, - 0x3209ca, - 0x3221ce, - 0x32294b, - 0x322c0a, - 0x324751, - 0x324b8a, - 0x32508b, - 0x3255ce, - 0x326c8c, - 0x32784b, - 0x327b0e, - 0x327e8c, - 0x328bca, - 0x329d4c, - 0x9232a04a, - 0x32a808, - 0x32b3c9, - 0x32ce8a, - 0x32d10a, - 0x32d38b, - 0x33010e, - 0x3316d1, - 0x33e209, - 0x33e44a, - 0x33ee8b, - 0x33fc0d, - 0x340a8a, - 0x341616, - 0x34298b, - 0x34668a, - 0x347d0a, - 0x3490cb, - 0x34aa49, - 0x34ed89, - 0x34f30d, - 0x34fe0b, - 0x351c8b, - 0x352509, - 0x352b4e, - 0x35328a, - 0x353dca, - 0x35438a, - 0x354a0b, - 0x35524b, - 0x3585cd, - 0x35a18d, - 0x35b050, - 0x35b50b, - 0x35ce4c, - 0x35d98b, - 0x35f44b, - 0x360c4e, - 0x36128b, - 0x36128d, - 0x3663cb, - 0x366e4f, - 0x36720b, - 0x36860a, - 0x368e49, - 0x369509, - 0x9276988b, - 0x369b4e, - 0x369ece, - 0x36be8b, - 0x36d64f, - 0x370acb, - 0x370d8b, - 0x37104b, - 0x37164a, - 0x3764c9, - 0x37964f, - 0x37e24c, - 0x37f30c, - 0x38058e, - 0x3810cf, - 0x38148e, - 0x381e50, - 0x38224f, - 0x382b4e, - 0x38320c, - 0x383511, - 0x383952, - 0x3856d1, - 0x385dce, - 0x38620b, - 0x38620e, - 0x38658f, - 0x38694e, - 0x386cd3, - 0x387191, - 0x3875cc, - 0x3878ce, - 0x387d4c, - 0x388293, - 0x388a90, - 0x389b8c, - 0x389e8c, - 0x38a34b, - 0x38ae4e, - 0x38b34b, - 0x38cb4b, - 0x38ddcc, - 0x39424a, - 0x39460c, - 0x39490c, - 0x394c09, - 0x396a0b, - 0x396cc8, - 0x397509, - 0x39750f, - 0x3991cb, - 0x92b9a54a, - 0x39bd0c, - 0x39cccb, - 0x39cf89, - 0x39d348, - 0x39da4b, - 0x39df4b, - 0x39eb8a, - 0x39ee0b, - 0x39f78c, - 0x3a0149, - 0x3a0388, - 0x3a3d0b, - 0x3a6f4b, - 0x3a91ce, - 0x3aaf4b, - 0x3ad38b, - 0x3bbdcb, - 0x3bc089, - 0x3bc5cd, - 0x3cbe4a, - 0x3cf5d7, - 0x3d18d8, - 0x3d5909, - 0x3d6b0b, - 0x3d79d4, - 0x3d7ecb, - 0x3d844a, - 0x3d894a, - 0x3d8bcb, - 0x3da790, - 0x3dab91, - 0x3db24a, - 0x3dc54d, - 0x3dcc4d, - 0x3e06cb, - 0x3d7383, - 0x92f9b403, - 0x289b06, - 0x246085, - 0x30ccc7, - 0x2ef746, - 0x165c942, - 0x270b89, - 0x297e44, - 0x2ed408, - 0x21e183, - 0x302707, - 0x205602, - 0x2b5503, - 0x93201442, - 0x2d69c6, - 0x2d8084, - 0x38f1c4, - 0x268643, - 0x93ad3982, - 0x93e2a784, - 0x34a0c7, - 0x9422a502, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x242543, - 0x105dc8, - 0x203dc3, + 0x28e544, + 0x3e2587, + 0x2fbe46, + 0x20f307, + 0x30bdc4, + 0x2e5d45, + 0x218ac5, + 0x7ce05682, + 0x216f86, + 0x227043, + 0x227ec2, + 0x227ec6, + 0x7d21c882, + 0x7d62dc42, + 0x238f85, + 0x7da03d02, + 0x7de02a82, + 0x353545, + 0x2d9845, + 0x2af105, + 0x7e65aa03, + 0x279185, + 0x2f0bc7, + 0x2b7945, + 0x359b05, + 0x268b84, + 0x266cc6, + 0x3944c4, + 0x7ea008c2, + 0x7f798885, + 0x3d0907, + 0x3a09c8, + 0x269f86, + 0x269f8d, + 0x26f7c9, + 0x26f7d2, + 0x34d185, + 0x380843, + 0x7fa03b42, + 0x31f9c4, + 0x22db83, + 0x393e85, + 0x313785, + 0x7fe1fcc2, + 0x259fc3, + 0x8022b302, + 0x80a1cac2, + 0x80e00082, + 0x2ec2c5, + 0x213fc3, + 0x81208f02, + 0x81604642, + 0x3c1706, + 0x27e1ca, + 0x20c6c3, + 0x257c83, + 0x2f7343, + 0x832072c2, + 0x9161f702, + 0x91e07ac2, + 0x2034c2, + 0x3d3d09, + 0x2d4584, + 0x2e1c88, + 0x92305102, + 0x92a01502, + 0x2c2285, + 0x234e88, + 0x2f65c8, + 0x2fb70c, + 0x239683, + 0x92e13f42, + 0x9320e482, + 0x2bce06, + 0x315fc5, + 0x2e5583, + 0x247cc6, + 0x316106, + 0x253383, + 0x317803, + 0x317c46, + 0x319484, + 0x26aa06, + 0x236444, + 0x319b44, + 0x31ad0a, + 0x936bb102, + 0x24e605, + 0x31c58a, + 0x31c4c5, + 0x31e504, + 0x31e606, + 0x31e784, + 0x216d06, + 0x93a03c42, + 0x2ecf86, + 0x358f85, + 0x35c807, + 0x3c7386, + 0x253d84, + 0x2e5807, + 0x21dfc5, + 0x21dfc7, + 0x3c3a87, + 0x3c3a8e, + 0x280bc6, + 0x2bda05, + 0x20aa47, + 0x20e243, + 0x20e247, + 0x228f05, + 0x22bfc4, + 0x368842, + 0x32a1c7, + 0x241184, + 0x32a684, + 0x3ab1cb, + 0x21ab83, + 0x2dd0c7, + 0x21ab84, + 0x2dd3c7, + 0x3ae243, + 0x34f8cd, + 0x3aa588, + 0x93e45f84, + 0x366dc5, + 0x31f345, + 0x31f783, + 0x94223d42, + 0x322283, + 0x322b03, + 0x217104, + 0x283c85, + 0x224e87, + 0x38a206, + 0x393c43, + 0x22ad4b, + 0x322c8b, + 0x283d8b, + 0x2b32cb, + 0x2c718a, + 0x2d184b, + 0x2f1b4b, + 0x35ab4c, + 0x319f4b, + 0x374b91, + 0x39ad0a, + 0x3b794b, + 0x3c694c, + 0x3df28b, + 0x3256ca, + 0x325bca, + 0x326a4e, + 0x3271cb, + 0x32748a, + 0x328a51, + 0x328e8a, + 0x32938b, + 0x3298ce, + 0x32b70c, + 0x32c34b, + 0x32c60e, + 0x32c98c, + 0x32d6ca, + 0x32ee8c, + 0x9472f18a, + 0x32fd88, + 0x330949, + 0x33308a, + 0x33330a, + 0x33358b, + 0x3368ce, + 0x337751, + 0x341dc9, + 0x34200a, + 0x342b4b, + 0x34348d, + 0x34430a, + 0x3455d6, + 0x34694b, + 0x349e0a, + 0x34a38a, + 0x34b28b, + 0x34cc09, + 0x350249, + 0x3507cd, + 0x3510cb, + 0x352bcb, + 0x353689, + 0x353cce, + 0x35410a, + 0x35a04a, + 0x35a7ca, + 0x35b18b, + 0x35b9cb, + 0x35e2cd, + 0x35fa0d, + 0x360310, + 0x3607cb, + 0x36210c, + 0x36288b, + 0x36494b, + 0x36614e, + 0x36660b, + 0x36660d, + 0x36d70b, + 0x36e18f, + 0x36e54b, + 0x36f50a, + 0x36fb09, + 0x370089, + 0x94b7040b, + 0x3706ce, + 0x370a4e, + 0x3726cb, + 0x37374f, + 0x375fcb, + 0x37628b, + 0x37654a, + 0x37af49, + 0x37fa0f, + 0x3841cc, + 0x384bcc, + 0x385ece, + 0x38644f, + 0x38680e, + 0x3871d0, + 0x3875cf, + 0x3883ce, + 0x388f0c, + 0x389211, + 0x389652, + 0x38b3d1, + 0x38be8e, + 0x38c2cb, + 0x38c2ce, + 0x38c64f, + 0x38ca0e, + 0x38cd93, + 0x38d251, + 0x38d68c, + 0x38d98e, + 0x38de0c, + 0x38e353, + 0x38f1d0, + 0x3902cc, + 0x3905cc, + 0x390a8b, + 0x391bce, + 0x3920cb, + 0x392e4b, + 0x39418c, + 0x399a4a, + 0x39a50c, + 0x39a80c, + 0x39ab09, + 0x39d68b, + 0x39d948, + 0x39e649, + 0x39e64f, + 0x39ff0b, + 0x94fa0bca, + 0x3a268c, + 0x3a364b, + 0x3a3909, + 0x3a3cc8, + 0x3a458b, + 0x3a688a, + 0x3a6b0b, + 0x3a700c, + 0x3a77c9, + 0x3a7a08, + 0x3ab48b, + 0x3aeb8b, + 0x3b0d0e, + 0x3b244b, + 0x3b72cb, + 0x3c360b, + 0x3c38c9, + 0x3c3e0d, + 0x3d148a, + 0x3d4917, + 0x3d5618, + 0x3d8989, + 0x3d9ccb, + 0x3daad4, + 0x3dafcb, + 0x3db54a, + 0x3dbc0a, + 0x3dbe8b, + 0x3dd190, + 0x3dd591, + 0x3ddc4a, + 0x3de88d, + 0x3def8d, + 0x3e104b, + 0x217083, + 0x953b3583, + 0x2b0f46, + 0x27ca85, + 0x29c647, + 0x384906, + 0x1602342, + 0x2b3609, + 0x32fa04, + 0x2efcc8, + 0x21b783, + 0x31f907, + 0x230902, + 0x2b8f03, + 0x95603602, + 0x2d8d06, + 0x2da3c4, + 0x377084, + 0x201c43, + 0x95ed56c2, + 0x9622c344, + 0x34c287, + 0x9662bf82, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x23e083, + 0x106b48, + 0x205803, 0x2000c2, - 0x9a048, - 0x201242, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x3dc3, - 0x242543, - 0x20e2c3, - 0x337396, - 0x364d53, - 0x3d9f89, - 0x2135c8, - 0x3b1449, - 0x319546, - 0x351190, - 0x20dcd3, - 0x31d488, - 0x277e87, - 0x279e87, - 0x2a86ca, - 0x343189, - 0x267d49, - 0x2d368b, - 0x303c06, - 0x30334a, - 0x2205c6, - 0x32a4c3, - 0x2e2905, - 0x3ba348, - 0x27decd, - 0x2f330c, - 0x2ec347, - 0x30bfcd, - 0x2136c4, - 0x22fe4a, - 0x23134a, - 0x23180a, - 0x20dfc7, - 0x23cb87, - 0x240104, - 0x273506, - 0x348a44, - 0x304c08, - 0x289909, - 0x2e6606, - 0x2e6608, - 0x24360d, - 0x2d6149, - 0x392488, - 0x243147, - 0x3b27ca, - 0x250086, - 0x2fd244, - 0x212107, - 0x30800a, - 0x3ab68e, - 0x277185, - 0x3daf8b, - 0x226bc9, - 0x22e0c9, - 0x2b3147, - 0x3d090a, - 0x2c9187, - 0x2ff649, - 0x33b048, - 0x2a5e8b, - 0x2ec0c5, - 0x22c50a, - 0x223d49, - 0x295aca, - 0x20f30b, - 0x21200b, - 0x2d3415, - 0x2c8205, - 0x2431c5, - 0x237f0a, - 0x22b98a, - 0x2f5d87, - 0x233dc3, - 0x2c3588, - 0x2e0eca, - 0x2222c6, - 0x259c09, - 0x350788, - 0x2e2d44, - 0x388049, - 0x2c9c08, - 0x2ca947, - 0x393086, - 0x3cb087, - 0x2be807, - 0x23f5c5, - 0x2d314c, - 0x23e705, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x3dc3, - 0x242543, - 0x201242, - 0x214a83, - 0x21a3c3, - 0x203dc3, - 0x242543, - 0x214a83, - 0x21a3c3, - 0x3dc3, - 0x2624c3, - 0x242543, - 0x1cc203, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x3dc3, - 0x242543, - 0x9a048, - 0x201242, - 0x214a83, - 0x22ca07, - 0x86504, - 0x21a3c3, - 0x97a04, - 0x242543, - 0x201242, - 0x2052c2, - 0x3192c2, - 0x207882, - 0x201582, - 0x2eda82, - 0x908c6, - 0x50849, - 0xf3fc7, - 0x481c5c3, - 0x86107, - 0x148406, - 0x7783, - 0x11af85, + 0xae888, + 0x212402, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x5803, + 0x23e083, + 0x208503, + 0x33cb96, + 0x36c093, + 0x3e2409, + 0x215d88, + 0x2c1389, + 0x31c706, + 0x3520d0, + 0x212113, + 0x2f6c08, + 0x282247, + 0x28d487, + 0x2aaa8a, + 0x36a609, + 0x3573c9, + 0x24cd4b, + 0x34b706, + 0x32ce4a, + 0x221106, + 0x32f603, + 0x2e4d05, + 0x20f4c8, + 0x28598d, + 0x2f45cc, + 0x3033c7, + 0x30e60d, + 0x215e84, + 0x2319ca, + 0x23248a, + 0x23294a, + 0x212407, + 0x23ce87, + 0x2410c4, + 0x269c06, + 0x35d584, + 0x305988, + 0x3c0509, + 0x2e9f06, + 0x2e9f08, + 0x24400d, + 0x2d8489, + 0x397c88, + 0x243b47, + 0x33230a, + 0x251186, + 0x2ff544, + 0x225c07, + 0x266a8a, + 0x23fb8e, + 0x246145, + 0x3dd98b, + 0x22b109, + 0x247109, + 0x205447, + 0x20544a, + 0x2ceac7, + 0x301949, + 0x347c88, + 0x33284b, + 0x2ee705, + 0x22c90a, + 0x265dc9, + 0x3568ca, + 0x21b8cb, + 0x225b0b, + 0x24cad5, + 0x2ce085, + 0x243bc5, + 0x237e8a, + 0x2527ca, + 0x321a07, + 0x234fc3, + 0x2c8a08, + 0x2e32ca, + 0x223e46, + 0x256689, + 0x28dc88, + 0x2e5144, + 0x38e109, + 0x2cf888, + 0x2d05c7, + 0x398886, + 0x3d0907, + 0x2c51c7, + 0x2401c5, + 0x245f8c, + 0x366dc5, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x5803, + 0x23e083, + 0x212402, + 0x22ea43, + 0x217fc3, + 0x205803, + 0x23e083, + 0x22ea43, + 0x217fc3, + 0x5803, + 0x269543, + 0x23e083, + 0x1d1843, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x5803, + 0x23e083, + 0xae888, + 0x212402, + 0x22ea43, + 0x22ea47, + 0x8ecc4, + 0x217fc3, + 0x1b5c04, + 0x23e083, + 0x212402, + 0x204542, + 0x2f6e82, + 0x2022c2, + 0x202582, + 0x2f2402, + 0x96206, + 0x51709, + 0xe9bc7, + 0x481a6c3, + 0x8e8c7, + 0x154546, + 0xaa43, + 0x11eec5, 0xc1, - 0x5214a83, - 0x232dc3, - 0x228503, - 0x308003, - 0x21bc83, - 0x23c803, - 0x2e2806, - 0x21a3c3, - 0x242543, - 0x233d43, - 0x9a048, - 0x345b44, - 0x296c87, - 0x268683, - 0x2bad84, - 0x2187c3, - 0x284d43, - 0x308003, - 0x17e707, + 0x522ea43, + 0x233fc3, + 0x280203, + 0x266a83, + 0x2191c3, + 0x23cb03, + 0x2e4c06, + 0x217fc3, + 0x23e083, + 0x234f43, + 0xae888, + 0x3b46c4, + 0x324547, + 0x201c83, + 0x39e284, + 0x2052c3, + 0x2054c3, + 0x266a83, + 0x178d87, 0x9c4, - 0x4e83, - 0x68b05, + 0x157bc3, + 0x2105, 0x66000c2, - 0x2703, - 0x6a01242, - 0x6c8c109, - 0x8c98d, - 0x8cccd, - 0x3192c2, - 0x21dc4, - 0x68b49, + 0x4ac43, + 0x6a12402, + 0x6e8b749, + 0x7091e09, + 0x923cd, + 0x9270d, + 0x2f6e82, + 0xe704, + 0x2149, 0x2003c2, - 0x7221cc8, - 0xfe7c4, - 0x31c843, - 0x9a048, - 0x1414882, + 0x7623188, + 0x100ac4, + 0x320c03, + 0xae888, + 0x41184, + 0x140ea82, 0x14005c2, - 0x1414882, - 0x1517146, - 0x22f043, - 0x26f6c3, - 0x7a14a83, - 0x22fe44, - 0x7e32dc3, - 0x8b08003, - 0x206182, - 0x221dc4, - 0x21a3c3, - 0x3b1e83, - 0x204042, - 0x242543, - 0x202642, - 0x308f43, - 0x205142, - 0x2263c3, - 0x223a43, - 0x201342, - 0x9a048, - 0x22f043, - 0x3df888, - 0x83b1e83, - 0x204042, - 0x308f43, - 0x205142, - 0x86263c3, - 0x223a43, - 0x201342, - 0x252b07, - 0x232dc9, - 0x308f43, - 0x205142, - 0x2263c3, - 0x223a43, - 0x201342, - 0x214a83, - 0x16c2, - 0x32443, - 0x3c42, - 0xaac82, - 0x5cd82, - 0x17c2, - 0x1b82, - 0x43342, - 0x202703, - 0x214a83, - 0x232dc3, - 0x308003, - 0x221dc4, - 0x21bc83, - 0x23c803, - 0x219a04, - 0x21a3c3, - 0x242543, - 0x20eb02, - 0x2141c3, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x242543, - 0x202703, - 0x201242, - 0x214a83, - 0x232dc3, - 0x308003, - 0x221dc4, - 0x21a3c3, - 0x242543, - 0x208805, - 0x20c782, + 0x140ea82, + 0x1519d46, + 0x230983, + 0x276243, + 0x7e2ea43, + 0x2319c4, + 0x8233fc3, + 0x8a66a83, + 0x209582, + 0x20e704, + 0x217fc3, + 0x3319c3, + 0x209282, + 0x23e083, + 0x2188c2, + 0x308483, + 0x207742, + 0x203b83, + 0x222403, + 0x207d02, + 0xae888, + 0x230983, + 0x210448, + 0x87319c3, + 0x209282, + 0x308483, + 0x207742, + 0x203b83, + 0x222403, + 0x207d02, + 0x2509c7, + 0x308483, + 0x207742, + 0x203b83, + 0x222403, + 0x207d02, + 0x22ea43, + 0x6c02, + 0xf4c3, + 0x31c2, + 0x293c2, + 0x4d82, + 0x8c82, + 0x72c2, + 0x43d42, + 0x24ac43, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x20e704, + 0x2191c3, + 0x23cb03, + 0x21e484, + 0x217fc3, + 0x23e083, + 0x201b02, + 0x216983, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x23e083, + 0x24ac43, + 0x212402, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x20e704, + 0x217fc3, + 0x23e083, + 0x37b845, + 0x21fcc2, 0x2000c2, - 0x9a048, - 0x144ca88, - 0x12848a, - 0x308003, - 0x225cc1, + 0xae888, + 0x1454408, + 0x7b64a, + 0x266a83, + 0x202881, 0x2009c1, 0x200a01, - 0x204ac1, - 0x204781, - 0x20a541, - 0x201941, - 0x225dc1, - 0x23ff81, + 0x201781, + 0x202101, + 0x20bac1, + 0x201d01, + 0x203001, + 0x230d41, 0x200001, 0x2000c1, 0x200201, - 0x139b05, - 0x9a048, + 0x146bc5, + 0xae888, 0x200101, - 0x201301, + 0x201381, 0x200501, - 0x205dc1, + 0x201281, 0x200041, 0x200801, 0x200181, @@ -2348,7193 +2344,7257 @@ var nodes = [...]uint32{ 0x200581, 0x2003c1, 0x200a81, - 0x215481, + 0x20c241, 0x200401, 0x200741, 0x2007c1, 0x200081, - 0x200f01, - 0x201341, - 0x204f01, - 0x201b41, - 0x201441, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x201242, - 0x214a83, - 0x232dc3, + 0x201501, + 0x207d01, + 0x20a8c1, + 0x202341, + 0x201c41, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x212402, + 0x22ea43, + 0x233fc3, 0x2003c2, - 0x242543, - 0x1bf83, - 0x17e707, - 0xd1407, - 0x28886, - 0x34b8a, - 0x8b848, - 0x54e08, - 0x558c7, - 0x174586, - 0xea585, - 0x97805, - 0x125483, - 0x11ec6, - 0x365c6, - 0x2d3684, - 0x328147, - 0x9a048, - 0x2e3504, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x1242, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x32a248, - 0x204244, - 0x232d04, - 0x229904, - 0x24ab47, - 0x2e0007, - 0x214a83, - 0x235b4b, - 0x29650a, - 0x33c147, - 0x23bc48, - 0x33b888, - 0x232dc3, - 0x287847, - 0x228503, - 0x206f88, - 0x2130c9, - 0x221dc4, - 0x21bc83, - 0x23b248, - 0x23c803, - 0x2dd74a, - 0x2e2806, - 0x3a4987, - 0x21a3c3, - 0x267906, - 0x26f548, - 0x242543, - 0x24d446, - 0x2f78cd, - 0x2f9e08, - 0x2fedcb, - 0x20eb46, - 0x24b347, - 0x2225c5, - 0x21674a, - 0x308245, - 0x3828ca, - 0x20c782, - 0x207783, - 0x23dec4, + 0x23e083, + 0x1a083, + 0x178d87, + 0x7f3c7, + 0x36fc6, + 0x3a8ca, + 0x91248, + 0x54d88, + 0x55a47, + 0x6e8c6, + 0xec7c5, + 0x1b5a05, + 0x129783, + 0x13a06, + 0x134c46, + 0x24cd44, + 0x334907, + 0xae888, + 0x2e5904, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x12402, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x32f388, + 0x207d44, + 0x233f04, + 0x204cc4, + 0x2bcd07, + 0x2e21c7, + 0x22ea43, + 0x23670b, + 0x323dca, + 0x34b9c7, + 0x238548, + 0x354a88, + 0x233fc3, + 0x25e4c7, + 0x280203, + 0x211448, + 0x212e49, + 0x20e704, + 0x2191c3, + 0x23b948, + 0x23cb03, + 0x2dfb4a, + 0x2e4c06, + 0x3b0107, + 0x217fc3, + 0x323606, + 0x2760c8, + 0x23e083, + 0x257546, + 0x2f93cd, + 0x2fba08, + 0x3010cb, + 0x2b2946, + 0x341847, + 0x21ecc5, + 0x3da84a, + 0x22ac05, + 0x24fc8a, + 0x21fcc2, + 0x20aa43, + 0x32a684, 0x200006, - 0x3b05c3, - 0x299f43, - 0x27ee03, - 0x204243, - 0x296183, - 0x2041c2, - 0x355dc5, - 0x2ad8c9, - 0x23fc43, - 0x220dc3, - 0x21fdc3, + 0x3ba683, + 0x2ae783, + 0x281bc3, + 0x207d43, + 0x323a43, + 0x2029c2, + 0x309b85, + 0x2b07c9, + 0x201ac3, + 0x240843, + 0x233f03, + 0x232283, 0x200201, - 0x2f0447, - 0x2e9905, - 0x3b5c03, - 0x3d6d83, - 0x229904, - 0x343a43, - 0x20ff88, - 0x35d143, - 0x30d98d, - 0x278708, - 0x3dfa46, - 0x286a03, - 0x361583, - 0x38e083, - 0xce14a83, - 0x232608, - 0x235b44, - 0x240983, + 0x39b3c7, + 0x2ec005, + 0x3c2003, + 0x2a4d43, + 0x3dff03, + 0x204cc4, + 0x356e43, + 0x227608, + 0x322bc3, + 0x310c4d, + 0x280c88, + 0x210606, + 0x28f1c3, + 0x366903, + 0x394443, + 0xce2ea43, + 0x233808, + 0x236704, + 0x23d3c3, + 0x241283, 0x200106, - 0x243d88, - 0x27b0c3, - 0x216783, - 0x22d1c3, - 0x232dc3, - 0x21afc3, - 0x2532c3, - 0x283603, - 0x286983, - 0x2cbf83, - 0x2196c3, - 0x38b5c5, - 0x250804, - 0x251987, - 0x22dec2, - 0x254483, - 0x257d06, - 0x2592c3, - 0x25a283, - 0x277083, - 0x374e43, - 0x345843, - 0x29c047, - 0xd308003, - 0x2425c3, - 0x286a43, - 0x206c03, - 0x21bac3, - 0x24c903, - 0x20ef85, - 0x373c83, - 0x200e09, - 0x20bb83, - 0x311283, - 0xd63c883, - 0x2d3b03, - 0x219208, - 0x2ad806, - 0x374c06, - 0x2b7106, - 0x389147, - 0x227d43, - 0x2137c3, - 0x23c803, - 0x28b946, - 0x20f002, - 0x267d83, - 0x353145, - 0x21a3c3, - 0x319e87, - 0x1603dc3, - 0x202903, - 0x2089c3, - 0x21fec3, - 0x26d243, - 0x242543, - 0x209006, - 0x3b5f86, - 0x37a243, - 0x2f8a83, - 0x2141c3, - 0x220ec3, - 0x314c83, - 0x305fc3, - 0x309303, - 0x399905, - 0x22b983, - 0x39f446, - 0x2d1cc8, - 0x20cc83, - 0x20cc89, - 0x298948, - 0x223488, - 0x229a85, - 0x22f18a, - 0x23818a, - 0x239b4b, - 0x23b808, - 0x398943, - 0x38da83, - 0x30a583, - 0x326f48, - 0x376dc3, - 0x384644, - 0x235002, - 0x25ca83, + 0x244e88, + 0x20f983, + 0x21fa43, + 0x2b6ec3, + 0x222383, + 0x3da883, + 0x22f203, + 0x233fc3, + 0x22d003, + 0x249203, + 0x24cbc3, + 0x28b003, + 0x28f143, + 0x20a003, + 0x265743, + 0x392345, + 0x2516c4, + 0x252a47, + 0x2ba882, + 0x254b03, + 0x258106, + 0x259243, + 0x259c43, + 0x27cc83, + 0x26f183, + 0x20b183, + 0x3b43c3, + 0x29d847, + 0xd266a83, + 0x2c3fc3, + 0x28f203, + 0x204903, + 0x20e703, + 0x2ed2c3, + 0x20e905, + 0x37fd83, + 0x24b709, + 0x2012c3, + 0x313a83, + 0xd63cb83, + 0x2d5e43, + 0x204d03, + 0x218bc8, + 0x2b0706, + 0x26ef46, + 0x2ba8c6, + 0x38f887, + 0x205e03, + 0x215f83, + 0x23cb03, + 0x291346, + 0x20e982, + 0x2b8a83, + 0x33b645, + 0x217fc3, + 0x31da07, + 0x1605803, + 0x2760c3, + 0x212483, + 0x232383, + 0x235fc3, + 0x23e083, + 0x21d506, + 0x3b5d46, + 0x380703, + 0x2fa583, + 0x216983, + 0x250983, + 0x317883, + 0x306d43, + 0x308843, + 0x3a0645, + 0x235403, + 0x3b2a86, + 0x221d43, + 0x27fc88, + 0x2201c3, + 0x2201c9, + 0x273288, + 0x221e48, + 0x225645, + 0x36000a, + 0x38e84a, + 0x22f98b, + 0x238108, + 0x294983, + 0x2f2a03, + 0x393d83, + 0x39fa83, + 0x316248, + 0x37a903, + 0x38a184, + 0x21cc42, + 0x20de03, + 0x260e03, 0x2007c3, - 0x356c43, - 0x263343, - 0x233d43, - 0x20c782, - 0x229e43, - 0x2398c3, - 0x3172c3, - 0x318284, - 0x23dec4, - 0x20fe43, - 0x9a048, + 0x22dc43, + 0x27b143, + 0x234f43, + 0x21fcc2, + 0x22b8c3, + 0x239683, + 0x319ec3, + 0x31b744, + 0x32a684, + 0x21cb03, + 0xae888, 0x2000c2, 0x200ac2, - 0x2041c2, - 0x204b42, + 0x2029c2, + 0x201802, 0x200202, - 0x204342, - 0x240702, - 0x203c42, + 0x205082, + 0x249382, + 0x2031c2, 0x200382, 0x200c42, - 0x33d642, - 0x202382, - 0x26c9c2, + 0x349242, + 0x20a942, + 0x2720c2, 0x200a82, - 0x2eda82, - 0x214282, - 0x205742, - 0x2141c2, - 0x2c1902, - 0x2069c2, + 0x2f2402, + 0x205b42, + 0x211c82, + 0x216982, + 0x206002, + 0x205502, 0x200682, - 0x206f02, - 0x2013c2, - 0x2090c2, - 0x2045c2, - 0x26c702, - 0x202982, + 0x2113c2, + 0x202b02, + 0x208502, + 0x202442, + 0x207142, + 0x202a82, 0xc2, 0xac2, - 0x41c2, - 0x4b42, + 0x29c2, + 0x1802, 0x202, - 0x4342, - 0x40702, - 0x3c42, + 0x5082, + 0x49382, + 0x31c2, 0x382, 0xc42, - 0x13d642, - 0x2382, - 0x6c9c2, + 0x149242, + 0xa942, + 0x720c2, 0xa82, - 0xeda82, - 0x14282, - 0x5742, - 0x141c2, - 0xc1902, - 0x69c2, + 0xf2402, + 0x5b42, + 0x11c82, + 0x16982, + 0x6002, + 0x5502, 0x682, - 0x6f02, - 0x13c2, - 0x90c2, - 0x45c2, - 0x6c702, - 0x2982, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x7782, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x1242, - 0x201242, - 0x242543, - 0xee14a83, - 0x308003, - 0x23c803, - 0x1b4103, - 0x22aec2, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x3dc3, - 0x1b4103, - 0x242543, - 0x1442, + 0x113c2, + 0x2b02, + 0x8502, + 0x2442, + 0x7142, + 0x2a82, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x83c2, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x12402, + 0x212402, + 0x23e083, + 0xee2ea43, + 0x266a83, + 0x23cb03, + 0x1c0443, + 0x230242, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x5803, + 0x1c0443, + 0x23e083, + 0x3602, 0x2001c2, - 0x15c45c5, - 0x139b05, - 0x20b3c2, - 0x9a048, - 0x1242, - 0x2347c2, - 0x206782, - 0x204642, - 0x21bb02, - 0x230a42, - 0x97805, - 0x202f42, - 0x204042, - 0x206e42, - 0x205e42, - 0x214282, - 0x23fcc2, - 0x202f82, - 0x292882, - 0xfe98384, + 0x1567b85, + 0x146bc5, + 0x210402, + 0xae888, + 0x12402, + 0x2359c2, + 0x206b02, + 0x208142, + 0x20e742, + 0x23bec2, + 0x1b5a05, + 0x201402, + 0x209282, + 0x201102, + 0x2053c2, + 0x205b42, + 0x2408c2, + 0x20ee42, + 0x256382, + 0xfe72cc4, 0x142, - 0x17e707, - 0x12380d, - 0xea609, - 0x115e0b, - 0xeec08, - 0x65dc9, - 0x111b86, - 0x308003, - 0x9a048, + 0x178d87, + 0x30a83, + 0x12808d, + 0xec849, + 0x118a0b, + 0xf0a88, + 0x5bd09, + 0x1145c6, + 0x266a83, + 0xae888, 0x9c4, - 0x4e83, - 0x68b05, - 0x9a048, - 0xe5a47, - 0x56306, - 0x68b49, - 0x1d134e, - 0x14a887, + 0x157bc3, + 0x2105, + 0xae888, + 0xe7607, + 0x1104d007, + 0x56546, + 0x2149, + 0xa28e, + 0x14ca47, + 0x150e583, 0x2000c2, - 0x2d3684, - 0x201242, - 0x214a83, - 0x2052c2, - 0x232dc3, - 0x1bb43, + 0x24cd44, + 0x212402, + 0x22ea43, + 0x204542, + 0x233fc3, + 0xfa03, 0x200382, - 0x2e3504, - 0x21bc83, - 0x201f42, - 0x21a3c3, - 0x30a42, + 0x2e5904, + 0x2191c3, + 0x206a02, + 0x217fc3, + 0x3bec2, 0x2003c2, - 0x242543, - 0x2431c6, - 0x32d94f, + 0x23e083, + 0x243bc6, + 0x333b4f, 0x602, - 0x725e43, - 0x2f294a, - 0x9a048, - 0x201242, - 0x228503, - 0x308003, - 0x23c803, - 0x3dc3, - 0x1467206, - 0x1d1348, - 0x141650b, - 0x156518a, - 0xf1fc9, - 0x15d024a, - 0x1511707, - 0xa878b, - 0x10b7c5, - 0xebbc5, - 0x119bc9, - 0x139b05, - 0x17e707, - 0xfbfc4, - 0x201242, - 0x214a83, - 0x308003, - 0x21a3c3, + 0x72a143, + 0x2f3c0a, + 0xae888, + 0x212402, + 0x280203, + 0x266a83, + 0x23cb03, + 0x5803, + 0x1522f06, + 0x1c4104, + 0xa288, + 0x140dbcb, + 0x156c4ca, + 0xf3289, + 0x15da64a, + 0x1513f07, + 0xaab4b, + 0x10d4c5, + 0xf0545, + 0x11d749, + 0x146bc5, + 0x178d87, + 0x1c4104, + 0xfe2c4, + 0x212402, + 0x22ea43, + 0x266a83, + 0x217fc3, 0x2000c2, 0x200c82, - 0x2019c2, - 0x13214a83, - 0x23d342, - 0x232dc3, - 0x20bb42, - 0x2299c2, - 0x308003, - 0x23c782, - 0x25d282, - 0x22a742, + 0x205102, + 0x1362ea43, + 0x23d542, + 0x233fc3, + 0x201282, + 0x208882, + 0x266a83, + 0x23ca82, + 0x27b882, + 0x22c302, 0x200cc2, - 0x290602, + 0x295f42, 0x200802, 0x200d82, - 0x23ee42, - 0x27b8c2, - 0x204702, - 0x1b19cc, - 0x2b8e42, - 0x252e82, - 0x2203c2, - 0x248642, - 0x23c803, - 0x200bc2, - 0x21a3c3, - 0x243802, - 0x249b42, - 0x242543, - 0x308c82, - 0x2090c2, - 0x2023c2, - 0x202d42, - 0x207242, - 0x2f00c2, - 0x21e502, - 0x226dc2, - 0x223fc2, - 0x322c0a, - 0x36860a, - 0x39abca, - 0x3e0d02, - 0x210702, - 0x20ef42, - 0x1376fcc9, - 0x13b5cbca, - 0x142e307, - 0x13e026c2, - 0x14fe3c3, - 0x4a82, - 0x15cbca, - 0x15dc0e, - 0x24c0c4, - 0x572c5, - 0x14614a83, - 0x3dc83, - 0x232dc3, - 0x24d9c4, - 0x308003, - 0x221dc4, - 0x21bc83, - 0x137a89, - 0x68006, - 0x23c803, - 0xefa04, - 0x4743, - 0x21a3c3, - 0x1df105, - 0x203dc3, - 0x242543, - 0x1464b04, - 0x22b983, - 0x11b504, - 0x207783, - 0x9a048, - 0x1521403, - 0x125d86, - 0x1574504, - 0x68445, - 0x14a64a, - 0x129cc2, - 0x1500160d, - 0x1a6286, - 0x15291, - 0x1576fcc9, - 0x684c8, - 0x62888, - 0x1c12c707, - 0x1182, - 0x16fe47, - 0x2380e, - 0x139b0b, - 0x13f10b, - 0x1b3d4a, - 0x29907, - 0x9a048, - 0x11c988, - 0x7bc7, - 0x1c4169cb, - 0x1bf87, - 0xcd42, - 0x26ccd, - 0x1c2a07, - 0xaed8a, - 0x1d92cf, - 0x6738f, - 0x167c2, - 0x1242, - 0x83548, - 0x1c8f48cc, - 0xe770a, - 0xe554a, - 0x18990a, - 0x78508, - 0x8d08, - 0x5aa88, - 0xe5a08, - 0x145e88, - 0x2a42, - 0x1c464f, - 0xc134b, - 0x79108, - 0x25687, - 0x14474a, - 0x2490b, - 0x33249, - 0x46e07, - 0x8c08, - 0x3834c, - 0x15c087, - 0x1a67ca, - 0x106c8, - 0x2888e, - 0x2904e, - 0x2974b, - 0x2aa8b, - 0x15748b, - 0x14bf09, - 0xe3b0b, - 0xec58d, - 0x1261cb, - 0x30b4d, - 0x30ecd, - 0x3640a, - 0x3dd0b, - 0x3e54b, - 0x46405, - 0x1cd79a10, - 0x199e8f, - 0x9854f, - 0x63c4d, - 0x137c50, - 0xaac82, - 0x1d20c388, - 0xd1288, - 0xe8090, - 0xcf48e, - 0x1d75d105, - 0x4d1cb, - 0x136b90, - 0x8e0a, - 0x2ac49, - 0x61487, - 0x617c7, - 0x61987, - 0x61d07, - 0x631c7, - 0x63407, - 0x65587, - 0x65ac7, - 0x66007, - 0x66387, - 0x66a47, - 0x66c07, - 0x66dc7, - 0x66f87, - 0x69a47, - 0x6a407, - 0x6ac07, - 0x6afc7, - 0x6b607, - 0x6b8c7, - 0x6ba87, - 0x6bd87, - 0x6c887, - 0x6ca87, - 0x6d907, - 0x6dac7, - 0x6dc87, - 0x6f247, - 0x71247, - 0x71707, - 0x72207, - 0x724c7, - 0x72847, - 0x72a07, - 0x72e07, - 0x73247, - 0x73707, - 0x73c87, - 0x73e47, - 0x74007, - 0x74447, - 0x74ec7, - 0x75407, - 0x75987, - 0x75b47, - 0x75ec7, - 0x76407, - 0x6882, - 0x5ab8a, - 0x11cc8, - 0x1b0ecc, - 0x71b87, - 0x85805, - 0xa7951, - 0x1c0d86, - 0xfb14a, - 0x833ca, - 0x56306, - 0xb060b, - 0x642, - 0x2f7d1, - 0xbf089, - 0x9b209, - 0x9bb06, - 0x3ee42, - 0x9218a, - 0xacdc9, - 0xad50f, - 0xadb0e, - 0xaff88, - 0x6502, - 0x174a49, - 0x8a58e, - 0x1c7f0c, - 0xf1ccf, - 0x1b7a0e, - 0x3230c, - 0x41a89, - 0xd2551, - 0xd2b08, - 0x59452, - 0x62a4d, - 0x733cd, - 0x7984b, - 0x7ea95, - 0xf0c09, - 0x182f8a, - 0x1a3749, - 0x1aa210, - 0x9028b, - 0x9378f, - 0xa694b, - 0xab54c, - 0xb1b90, - 0xb4b0a, - 0xcc00d, - 0xb7ece, - 0x14db0a, - 0x1bd50c, - 0xbe4d4, - 0xbed11, - 0xc0f0b, - 0xc310f, - 0xc5f8d, - 0xc854e, - 0xca80c, - 0xcb00c, - 0xcbd0b, - 0x13ea4e, - 0x16c350, - 0xd974b, - 0xda40d, - 0xdcf0f, - 0xdf00c, - 0xe648e, - 0xf2391, - 0x10498c, - 0x1dc387, - 0x10b44d, - 0x11a00c, - 0x140cd0, - 0x15fd8d, - 0x168847, - 0x18e8d0, - 0x19d508, - 0x1a160b, - 0xb6b8f, - 0x1b1148, - 0x149d4d, - 0x10f810, - 0x17e609, - 0x1db799c8, - 0x1deb9c06, - 0xbaac3, - 0x15a889, - 0xc00c5, - 0x1e42, - 0x144bc9, - 0x14a34a, - 0x1e259906, - 0x145990d, - 0x1e7c2c04, - 0x57a46, - 0x1e08a, - 0x6474d, - 0x1e9df489, - 0x19a83, - 0x1175ca, - 0xe4651, - 0xe4a89, - 0xe54c7, - 0xe61c8, - 0xe68c7, - 0x71c48, - 0x1540b, - 0x12bc49, - 0xf1210, - 0xf16cc, - 0xf27c8, - 0xf4705, - 0x13b1c8, - 0x1961ca, - 0x184947, - 0x2902, - 0x1ef47415, - 0x13788a, - 0x1b2589, - 0x108a08, - 0x9cd89, - 0x46145, - 0x119d0a, - 0x8decf, - 0x10b84b, - 0xf04c, - 0x18ee12, - 0x77285, - 0x114e48, - 0xf678b, - 0xe0a11, - 0x4dcca, - 0x1f2fe185, - 0x19b18c, - 0x133e43, - 0x192286, - 0x3fcc2, - 0x10948b, - 0x109f4a, - 0x150a2cc, - 0xd1608, - 0x30d08, - 0x1f708a86, - 0x1b2f07, - 0xca42, - 0x5142, - 0x18bb50, - 0x69bc7, - 0x2ee0f, - 0x11ec6, - 0x11ed0e, - 0x94c0b, - 0x472c8, - 0x33609, - 0x13ce92, - 0x19234d, - 0x115488, - 0x115cc9, - 0x176f4d, - 0x198609, - 0x63cb, - 0x6bf08, - 0x7a688, - 0x7ce08, - 0x7d249, - 0x7d44a, - 0x8c30c, - 0x3e80a, - 0xf198a, - 0x114cc7, - 0x9994a, - 0x1c350d, - 0xd2e11, - 0x1fac8846, - 0x1cd64b, - 0x97c4c, - 0x39988, - 0x13d849, - 0x15b84d, - 0x61f50, - 0x1808cd, - 0xc2c2, - 0x4f70d, - 0x1b82, - 0xc1c2, - 0x114c0a, - 0x6e70a, - 0xfb04a, - 0x10260b, - 0x292cc, - 0x11c48a, - 0x11c70e, - 0x1d74cd, - 0x1fde0bc5, - 0x128948, - 0x1442, - 0x14239c3, - 0x15a6960e, - 0x16204b4e, - 0x16a6820a, - 0x1734630e, - 0x17b63a8e, - 0x18289d0c, - 0x142e307, - 0x142e309, - 0x14fe3c3, - 0x18b0400c, - 0x1933dfc9, - 0x19b48e89, - 0x1a353b89, - 0x4a82, - 0x69551, - 0x4a91, - 0x6814d, - 0x146251, - 0x1639d1, - 0x89c4f, - 0x103f4f, - 0x13df0c, - 0x148dcc, - 0x153acc, - 0x4b5cd, - 0x1aaa15, - 0xedc8c, - 0x1b32cc, - 0x13f810, - 0x16b10c, - 0x178fcc, - 0x1ac319, - 0x1b6959, - 0x1c1259, - 0x1da294, - 0x76d4, - 0x7d54, - 0x9754, - 0x9f94, - 0x1aa07989, - 0x1b008009, - 0x1bbb3389, - 0x15ed2d09, - 0x4a82, - 0x166d2d09, - 0x4a82, - 0x76ca, - 0x4a82, - 0x16ed2d09, - 0x4a82, - 0x76ca, - 0x4a82, - 0x176d2d09, - 0x4a82, - 0x17ed2d09, - 0x4a82, - 0x186d2d09, - 0x4a82, - 0x76ca, - 0x4a82, - 0x18ed2d09, - 0x4a82, - 0x76ca, - 0x4a82, - 0x196d2d09, - 0x4a82, - 0x19ed2d09, - 0x4a82, - 0x76ca, - 0x4a82, - 0x1a6d2d09, - 0x4a82, - 0x76ca, - 0x4a82, - 0x1aed2d09, - 0x4a82, - 0x1b6d2d09, - 0x4a82, - 0x1bed2d09, - 0x4a82, - 0x76ca, - 0x4a82, - 0x1400401, - 0x15285, - 0x1b3d44, - 0x14c86c3, - 0x15d6e03, - 0x14f8943, - 0x6960e, - 0x4b4e, - 0x7c80e, - 0x6820a, - 0x14630e, - 0x163a8e, - 0x89d0c, - 0x10400c, - 0x13dfc9, - 0x148e89, - 0x153b89, - 0x7989, - 0x8009, - 0x1b3389, - 0x13f8cd, - 0x9a09, - 0xa249, - 0x12f604, - 0x18ad44, - 0x1bad44, - 0x1bf004, - 0xa8a44, - 0x2cc04, - 0x3ca84, - 0x53684, - 0x11dc4, - 0x62b84, - 0x1588703, - 0x13dd87, - 0x147dc8c, - 0xf283, - 0xaac82, - 0xae8c6, - 0x1d74c3, - 0xf283, - 0x9fc83, - 0x8582, - 0x8588, - 0xe9247, - 0x12bcc7, - 0x2a42, - 0x2000c2, - 0x201242, - 0x2052c2, - 0x20dec2, - 0x200382, - 0x2003c2, - 0x205142, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21bac3, - 0x21a3c3, - 0x242543, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x21a3c3, - 0x242543, - 0xb2c3, - 0x308003, - 0x21dc4, - 0x2000c2, - 0x202703, - 0x22214a83, - 0x38b9c7, - 0x308003, - 0x21a8c3, - 0x219a04, - 0x21a3c3, - 0x242543, - 0x21e2ca, - 0x2431c5, - 0x2141c3, - 0x233442, - 0x9a048, - 0x226d8a4a, - 0xe01, - 0x9a048, - 0x1242, - 0x131a42, - 0x22fdf20b, - 0x23227fc4, - 0x1c2b45, - 0x1805, - 0xf48c6, - 0x23601805, - 0x53bc3, - 0x94e83, - 0x9c4, - 0x4e83, - 0x68b05, - 0x139b05, - 0x9a048, - 0x1bf87, - 0x14a83, - 0x2cd0d, - 0x23e3a147, - 0x144686, - 0x24146145, - 0x1b8dd2, - 0x3a247, - 0x1d35ca, - 0x1d3488, - 0x95c7, - 0x6574a, - 0x1a7308, - 0xe2b07, - 0x1a870f, - 0x169347, - 0x53486, - 0x136b90, - 0x11dccf, - 0x1a009, - 0x57ac4, - 0x2443a30e, - 0x35509, - 0x670c6, - 0x10ecc9, - 0x18d986, - 0x1ba1c6, - 0x78ecc, - 0x24b0a, - 0x333c7, - 0x14420a, - 0x33c9, - 0xf714c, - 0x1d40a, - 0x5c30a, - 0x68b49, - 0x57a46, - 0x3348a, - 0x11634a, - 0xa430a, - 0x14fbc9, - 0xe30c8, - 0xe3346, - 0xeb54d, - 0x5390b, - 0xc0545, - 0x24b55a0c, - 0x14a887, - 0x10d1c9, - 0xbf407, - 0x10fc14, - 0x11010b, - 0x254ca, - 0x13cd0a, - 0xaabcd, - 0x1502809, - 0x11524c, - 0x115acb, - 0x106c3, - 0x106c3, - 0x28886, - 0x106c3, - 0xf48c8, - 0x155983, - 0x44ec4, - 0x53f83, - 0x335c5, - 0x146e943, - 0x50849, - 0xf678b, - 0x14df283, - 0x148406, - 0x14ecac7, - 0x1aa487, - 0x2592c5c9, - 0x1a286, - 0x173d09, - 0x2703, - 0x9a048, - 0x1242, - 0x4d9c4, - 0x88c3, - 0x8805, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x220dc3, - 0x214a83, - 0x232dc3, - 0x228503, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x242543, - 0x29b3c3, - 0x207783, - 0x220dc3, - 0x2d3684, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x2308c3, - 0x2752c6c5, - 0x142c943, - 0x214a83, - 0x232dc3, - 0x21bb43, - 0x228503, - 0x308003, - 0x221dc4, - 0x2059c3, - 0x2137c3, - 0x23c803, - 0x21a3c3, - 0x1b4103, - 0x242543, - 0x2141c3, - 0x2821e9c3, - 0x18ed09, - 0x1242, - 0x3c0743, - 0x28e14a83, - 0x232dc3, - 0x247103, - 0x308003, - 0x223703, - 0x2137c3, - 0x242543, - 0x2f4bc3, - 0x3b9a84, - 0x9a048, - 0x29614a83, - 0x232dc3, - 0x2b0043, - 0x308003, - 0x23c803, - 0x219a04, - 0x21a3c3, - 0x242543, - 0x22e983, - 0x9a048, - 0x29e14a83, - 0x232dc3, - 0x228503, - 0x203dc3, - 0x242543, - 0x9a048, - 0x142e307, - 0x202703, - 0x214a83, - 0x232dc3, - 0x308003, - 0x221dc4, - 0x219a04, - 0x21a3c3, - 0x242543, - 0x139b05, - 0x17e707, - 0x10fe4b, - 0xe4e84, - 0xc0545, - 0x144ca88, - 0x2a54d, - 0x2b231ac5, - 0x647c4, - 0x1242, - 0x3a83, - 0x17e505, - 0x2aec2, - 0x5e42, - 0x303dc5, - 0x9a048, - 0x106c2, - 0x1d2c3, - 0x16454f, - 0x1242, - 0x105646, - 0x2000c2, - 0x202703, - 0x214a83, - 0x308003, - 0x221dc4, - 0x23c803, - 0x219a04, - 0x21a3c3, - 0x242543, - 0x2141c3, - 0x2aec2, - 0x32a988, - 0x2d3684, - 0x349646, - 0x353986, - 0x9a048, - 0x3373c3, - 0x2cd549, - 0x217915, - 0x1791f, - 0x214a83, - 0xd1ac7, - 0x214892, - 0x169046, - 0x1712c5, - 0x8e0a, - 0x2ac49, - 0x21464f, - 0x2e3504, - 0x224445, - 0x311050, - 0x2137c7, - 0x203dc3, - 0x31bf88, - 0x1283c6, - 0x27cfca, - 0x221c84, - 0x2fdbc3, - 0x233442, - 0x2f850b, - 0x3dc3, - 0x17cc84, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x3dc3, - 0x242543, - 0x306403, - 0x201242, - 0x89ac3, - 0x1dee04, - 0x21a3c3, - 0x242543, - 0x2ed73e05, - 0x8346, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x242543, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a8c3, - 0x223d43, - 0x242543, - 0x2703, - 0x201242, - 0x214a83, - 0x232dc3, - 0x21a3c3, - 0x3dc3, - 0x242543, - 0x267c2, - 0x2000c2, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x1805, - 0xf283, - 0x2d3684, - 0x214a83, - 0x232dc3, - 0x306c44, - 0x21a3c3, - 0x242543, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x1b4103, - 0x242543, - 0x1b3089, - 0x29904, - 0x214a83, - 0x2a42, - 0x232dc3, - 0x228503, - 0x206c03, - 0x23c803, - 0x21a3c3, - 0x3dc3, - 0x242543, - 0x2982, - 0x214a83, - 0x232dc3, - 0x308003, - 0x343104, - 0x221dc4, - 0x21a3c3, - 0x242543, - 0x207783, - 0x16c2, - 0x201242, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x1b4103, - 0x242543, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x308003, - 0x2f3983, - 0x13903, - 0x1a8c3, - 0x21a3c3, - 0x1b4103, - 0x242543, - 0x322c0a, - 0x3413c9, - 0x35fb0b, - 0x3602ca, - 0x36860a, - 0x377c8b, - 0x38d74a, - 0x39424a, - 0x39abca, - 0x39ae4b, - 0x3bcfc9, - 0x3ca20a, - 0x3ca58b, - 0x3d818b, - 0x3e040a, - 0x15702, - 0x214a83, - 0x232dc3, - 0x228503, - 0x23c803, - 0x21a3c3, - 0x3dc3, - 0x242543, - 0x1558b, - 0xcf487, - 0x5b788, - 0x177084, - 0x8f308, - 0xe8006, - 0x15546, - 0x366c9, - 0x9a048, - 0x214a83, - 0x8e04, - 0x261484, - 0x202742, - 0x219a04, - 0x269045, - 0x220dc3, - 0x2d3684, - 0x214a83, - 0x235b44, - 0x232dc3, - 0x24d9c4, - 0x2e3504, - 0x221dc4, - 0x2137c3, - 0x21a3c3, - 0x242543, - 0x24f8c5, - 0x2308c3, - 0x2141c3, - 0x32bf03, - 0x23e804, - 0x325d04, - 0x373fc5, - 0x9a048, - 0x203ac4, - 0x3b5cc6, - 0x268c84, - 0x201242, - 0x38f207, - 0x3a25c7, - 0x24b904, - 0x2e92c5, - 0x35ff85, - 0x22d805, - 0x221dc4, - 0x389208, - 0x22b586, - 0x3295c8, - 0x27b905, - 0x2ec0c5, - 0x262044, - 0x242543, - 0x2fe7c4, - 0x376806, - 0x2432c3, - 0x23e804, - 0x3829c5, - 0x344b44, - 0x23acc4, - 0x233442, - 0x231d86, - 0x3aeb46, - 0x313fc5, - 0x2000c2, - 0x202703, - 0x33e01242, - 0x20c504, - 0x200382, - 0x23c803, - 0x215402, - 0x21a3c3, - 0x2003c2, - 0x2fb406, - 0x20e2c3, - 0x207783, - 0x9a048, - 0x9a048, - 0x308003, - 0x1b4103, - 0x2000c2, - 0x34a01242, - 0x308003, - 0x266d43, - 0x2059c3, - 0x227fc4, - 0x21a3c3, - 0x242543, - 0x9a048, - 0x2000c2, - 0x35201242, - 0x214a83, - 0x21a3c3, - 0x3dc3, - 0x242543, - 0x682, - 0x209d42, - 0x20c782, - 0x21a8c3, - 0x2f7103, - 0x2000c2, - 0x139b05, - 0x9a048, - 0x17e707, - 0x201242, - 0x232dc3, - 0x24d9c4, - 0x207083, - 0x308003, - 0x206c03, - 0x23c803, - 0x21a3c3, - 0x2125c3, - 0x242543, - 0x233dc3, - 0x12be53, - 0x12e714, - 0x139b05, - 0x17e707, - 0x1d35c9, - 0x10d8c6, - 0xf5ecb, - 0x28886, - 0x54c47, - 0x15aec6, - 0x649, - 0x15794a, - 0x8b70d, - 0x12350c, - 0x116cca, - 0x112988, - 0x97805, - 0x1d3608, - 0x11ec6, - 0x1c6606, - 0x365c6, - 0x602, - 0x2aac82, - 0x174ec4, - 0x9fc86, - 0x12c310, - 0x147498e, - 0x68846, - 0x6264c, - 0x36a6720b, - 0x139b05, - 0x14820b, - 0x36fc6544, - 0x1b3f07, - 0x22111, - 0x1ae28a, - 0x214a83, - 0x3727db88, - 0x656c5, - 0x19b808, - 0xca04, - 0x14a545, - 0x3755ca06, - 0xa7946, - 0xc7746, - 0x908ca, - 0x1b5c43, - 0x37a0dc84, - 0x50849, - 0x129747, - 0x1274ca, - 0x14d8949, - 0x605, - 0xec503, - 0x37e33f07, - 0x1df105, - 0x1538186, - 0x1498886, - 0xb06cc, - 0x101b88, - 0x3803fcc3, - 0xf874b, - 0x13864b, - 0x38647c0c, - 0x140a503, - 0xc2dc8, - 0xf89c5, - 0xc11c9, - 0xea803, - 0x102908, - 0x141dfc6, - 0x86107, - 0x38b5b849, - 0x19d887, - 0xebbca, - 0x39fbf648, - 0x11578d, - 0xa788, - 0xf283, - 0x1443f09, - 0x174483, - 0x28886, - 0xf48c8, - 0x11dc4, - 0x1205c5, - 0x148df83, - 0x239c7, - 0x38e239c3, - 0x393c0a06, - 0x39637f04, - 0x39b0a107, - 0xf48c4, - 0xf48c4, - 0xf48c4, - 0xf48c4, - 0x41, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x242543, - 0x2000c2, - 0x201242, - 0x308003, - 0x206182, - 0x21a3c3, - 0x242543, - 0x20e2c3, - 0x3810cf, - 0x38148e, - 0x9a048, - 0x214a83, - 0x43bc7, - 0x232dc3, - 0x308003, - 0x21bc83, - 0x21a3c3, - 0x242543, - 0x68784, - 0x4fc4, - 0x145bc4, - 0x21c9c3, - 0x296747, - 0x203082, - 0x26ce49, - 0x200ac2, - 0x38be4b, - 0x2a1b8a, - 0x2a2889, - 0x200542, - 0x20cdc6, - 0x236a55, - 0x38bf95, - 0x2391d3, - 0x38c513, - 0x2037c2, - 0x2037c5, - 0x2037cc, - 0x27514b, - 0x276205, - 0x204b42, - 0x29d282, - 0x37bb86, - 0x201182, - 0x2c9d46, - 0x20908d, - 0x3dee8c, - 0x379a84, - 0x200882, - 0x202b02, - 0x259808, - 0x200202, - 0x205086, - 0x395a8f, - 0x205090, - 0x3a1544, - 0x236c15, - 0x239353, - 0x24d2c3, - 0x34934a, - 0x214f07, - 0x383d89, - 0x327387, - 0x220f82, - 0x200282, - 0x3beb06, - 0x205fc2, - 0x9a048, - 0x202e82, - 0x201542, - 0x20ac47, - 0x36a6c7, - 0x36a6d1, - 0x2180c5, - 0x2180ce, - 0x218e8f, - 0x20cd42, - 0x2679c7, - 0x21d008, - 0x207682, - 0x21d482, - 0x2101c6, - 0x2101cf, - 0x263710, - 0x22c042, - 0x2086c2, - 0x238c48, - 0x2086c3, - 0x25cec8, - 0x2c1bcd, - 0x215843, - 0x363208, - 0x27fc4f, - 0x28000e, - 0x33c9ca, - 0x2f5211, - 0x2f5690, - 0x300acd, - 0x300e0c, - 0x24a147, - 0x3494c7, - 0x349709, - 0x220f42, - 0x204342, - 0x25678c, - 0x256a8b, - 0x200d42, - 0x2cbec6, - 0x20b682, - 0x200482, - 0x2167c2, - 0x201242, - 0x22d204, - 0x239e07, - 0x22ba02, - 0x23f707, - 0x241247, - 0x22f142, - 0x22ec02, - 0x243a85, - 0x205582, - 0x392dce, - 0x3cae0d, - 0x232dc3, - 0x28508e, - 0x2b794d, - 0x328b03, - 0x2027c2, - 0x21fc84, - 0x24cf02, - 0x222342, - 0x38cdc5, - 0x39d187, - 0x246702, - 0x20dec2, - 0x24d5c7, - 0x250bc8, - 0x22dec2, - 0x277306, - 0x25660c, - 0x25694b, - 0x205dc2, - 0x25db0f, - 0x25ded0, - 0x25e2cf, - 0x25e695, - 0x25ebd4, - 0x25f0ce, - 0x25f44e, - 0x25f7cf, - 0x25fb8e, - 0x25ff14, - 0x260413, - 0x2608cd, - 0x2765c9, - 0x28d003, - 0x207082, - 0x31e805, - 0x3ddc86, - 0x200382, - 0x37f147, - 0x308003, - 0x200642, - 0x361608, - 0x2f5451, - 0x2f5890, - 0x201f02, - 0x28bf47, - 0x204582, - 0x271547, - 0x201e42, - 0x295749, - 0x37bb47, - 0x29ac08, - 0x35c846, - 0x24b083, - 0x24b085, - 0x233042, - 0x2004c2, - 0x3bef05, - 0x39b605, - 0x202482, - 0x21bdc3, - 0x348587, - 0x20e5c7, - 0x201842, - 0x345044, - 0x210543, - 0x31d809, - 0x210548, - 0x202042, - 0x208282, - 0x2ed207, - 0x2f5145, - 0x298bc8, - 0x2ae507, - 0x20fac3, - 0x29fb06, - 0x30094d, - 0x300ccc, - 0x305086, - 0x206782, - 0x2017c2, - 0x209e82, - 0x27facf, - 0x27fece, - 0x360007, - 0x210942, - 0x372385, - 0x372386, - 0x21d542, - 0x200bc2, - 0x28e5c6, - 0x247703, - 0x3c5d46, - 0x2d6705, - 0x2d670d, - 0x2d6f95, - 0x2d7e0c, - 0x2d818d, - 0x2d84d2, - 0x202382, - 0x26c9c2, - 0x202802, - 0x219386, - 0x3c7dc6, - 0x202902, - 0x3ddd06, - 0x206e42, - 0x296f45, - 0x201582, - 0x392f09, - 0x21ae0c, - 0x21b14b, - 0x2003c2, - 0x251d88, - 0x202942, - 0x200a82, - 0x272b46, - 0x2d2c85, - 0x200a87, - 0x227c85, - 0x257145, - 0x215542, - 0x2a3882, - 0x214282, - 0x293a87, - 0x2fb4cd, - 0x2fb84c, - 0x234307, - 0x277282, + 0x25b542, + 0x2295c2, 0x205742, - 0x3d2508, - 0x344d48, - 0x3298c8, - 0x3b1104, - 0x33ecc7, - 0x3c2c83, - 0x21b742, - 0x20cb42, - 0x2fc0c9, - 0x228c87, - 0x2141c2, - 0x272f45, - 0x214b42, - 0x20eb42, - 0x2f6e43, - 0x2f6e46, - 0x305fc2, - 0x308c02, - 0x200402, - 0x35c406, - 0x21fbc7, - 0x213fc2, - 0x200902, - 0x25cd0f, - 0x284ecd, - 0x28a98e, - 0x2b77cc, - 0x206842, - 0x206142, - 0x35c685, - 0x320b86, - 0x200b82, - 0x2069c2, - 0x200682, - 0x285244, - 0x2c1a44, - 0x384486, - 0x205142, - 0x27a207, - 0x23d903, - 0x23d908, - 0x23e108, - 0x2d23c7, - 0x24c186, - 0x207842, - 0x20b603, - 0x20b607, - 0x3a6dc6, - 0x2ee0c5, - 0x274608, - 0x2071c2, - 0x3b9447, - 0x26c702, - 0x294ec2, - 0x206382, - 0x205249, - 0x201082, - 0xcb3c8, - 0x203882, - 0x234583, - 0x204847, - 0x203282, - 0x21af8c, - 0x21b28b, - 0x305106, - 0x2ec445, - 0x202c02, - 0x202982, - 0x2c55c6, - 0x216643, - 0x342e87, - 0x291f82, - 0x2008c2, - 0x2368d5, - 0x38c155, - 0x239093, - 0x38c693, - 0x24ee47, - 0x26ee11, - 0x275590, - 0x283712, - 0x2eb111, - 0x29a208, - 0x29a210, - 0x29f38f, - 0x2a1953, - 0x2a2652, - 0x2a7d50, - 0x2b4ecf, - 0x3689d2, - 0x3a1891, - 0x3d4d53, - 0x2b9d52, - 0x2d634f, - 0x2ddd0e, - 0x2e1112, - 0x2e1fd1, - 0x2e5e0f, - 0x2e7c8e, - 0x2efbd1, - 0x2f8ed0, - 0x301d52, - 0x306491, - 0x309b50, - 0x311f8f, - 0x3cea91, - 0x347910, - 0x37b006, - 0x380cc7, - 0x218987, - 0x209f42, - 0x280f85, - 0x310dc7, - 0x20c782, - 0x2018c2, - 0x229e45, - 0x21ec03, - 0x374946, - 0x2fb68d, - 0x2fb9cc, - 0x203642, - 0x20364b, - 0x27500a, - 0x22408a, - 0x2c43c9, - 0x2fa74b, - 0x2ae64d, - 0x3114cc, - 0x35d58a, - 0x244f8c, - 0x27188b, - 0x27604c, - 0x29b68e, - 0x2bf90b, - 0x2b8a0c, - 0x2dc483, - 0x376e46, - 0x3bf642, - 0x304382, - 0x24f4c3, - 0x206482, - 0x20c3c3, - 0x324506, - 0x25e847, - 0x352386, - 0x2e78c8, - 0x348408, - 0x2cf746, - 0x200f02, - 0x31398d, - 0x313ccc, - 0x338807, - 0x316b07, - 0x234a42, - 0x2143c2, - 0x20b582, - 0x27c602, - 0x330496, - 0x335f95, - 0x3395d6, - 0x33ff53, - 0x340612, - 0x355513, - 0x358152, - 0x3acc8f, - 0x3be558, - 0x3bf117, - 0x3bfc59, - 0x3c1898, - 0x3c3c58, - 0x3c5fd7, - 0x3c6b17, - 0x3c8216, - 0x3cc693, - 0x3ccfd5, - 0x3cdd52, - 0x3ce1d3, - 0x201242, - 0x21a3c3, - 0x242543, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x219a04, - 0x21a3c3, - 0x242543, - 0x20e2c3, + 0x13150c, + 0x2be4c2, + 0x250d42, + 0x227082, + 0x24a282, + 0x23cb03, + 0x200bc2, + 0x217fc3, + 0x209ec2, + 0x25c042, + 0x23e083, + 0x3081c2, + 0x208502, + 0x20a1c2, + 0x204782, + 0x2010c2, + 0x230ac2, + 0x205682, + 0x22b302, + 0x2270c2, + 0x32748a, + 0x36f50a, + 0x3a124a, + 0x3e2d42, + 0x208902, + 0x20e8c2, + 0x13aa7f09, + 0x13f61e8a, + 0x142fc47, + 0x142050c2, + 0x143a083, + 0x1742, + 0x161e8a, + 0x162b0e, + 0x241ec4, + 0x57fc5, + 0x14a2ea43, + 0x3dc03, + 0x233fc3, + 0x24d704, + 0x266a83, + 0x20e704, + 0x2191c3, + 0x13d289, + 0x157686, + 0x23cb03, + 0xf1584, + 0x1598c3, + 0x217fc3, + 0x2a7c5, + 0x205803, + 0x23e083, + 0x1466d84, + 0x235403, + 0x181584, + 0x20aa43, + 0xae888, + 0x154f043, + 0x12a086, + 0x146e844, + 0x1a45, + 0x14c80a, + 0x124d82, + 0x15408acd, + 0x1adec6, + 0x159a140b, + 0xc951, + 0x15ea7f09, + 0x1ac8, + 0x69908, + 0x1c9415c7, + 0x3502, + 0xa8087, + 0x221ce, + 0x146bcb, + 0x14a88b, + 0x1c008a, + 0x1683c7, + 0xae888, + 0x120d48, + 0xa807, + 0x1cc176cb, + 0x1a087, + 0xcfc2, + 0x2b20d, + 0x16a7c7, + 0xb1bca, + 0x1e174f, + 0x12308f, + 0x161e82, + 0x12402, + 0x8af48, + 0x1d10778c, + 0x1570a, + 0xe710a, + 0x19004a, + 0x80a88, + 0x1d208, + 0x5a488, + 0xe75c8, + 0x1388, + 0xf982, + 0x167c0f, + 0xc6d8b, + 0x10f508, + 0x35cc7, + 0x4878a, + 0xbc3cb, + 0x34449, + 0x48687, + 0x83986, + 0x1d108, + 0x18ea0c, + 0x161347, + 0x1ae40a, + 0xec88, + 0x10ae8e, + 0x10b64e, + 0x16820b, + 0x168a8b, + 0x658cb, + 0x66609, + 0x6754b, + 0xbd4cd, + 0xf548b, + 0xf5fcd, + 0xf634d, + 0x10360a, + 0x12a4cb, + 0x166c0b, + 0x3bfc5, + 0x1d58b810, + 0x13514f, + 0x72e8f, + 0x2470d, + 0x13d450, + 0x293c2, + 0x1da1f8c8, + 0x7f248, + 0xea790, + 0x17fe0e, + 0x1df22b85, + 0x4c84b, + 0x13c390, + 0x1d30a, + 0x168c49, + 0x680c7, + 0x68407, + 0x685c7, + 0x68947, + 0x69e07, + 0x6a2c7, + 0x6bb07, + 0x6c047, + 0x6d587, + 0x6d907, + 0x6dfc7, + 0x6e187, + 0x6e347, + 0x6e507, + 0x6f307, + 0x6fc47, + 0x70a87, + 0x70e47, + 0x71487, + 0x71747, + 0x71907, + 0x71c07, + 0x71f87, + 0x72187, + 0x748c7, + 0x74a87, + 0x74c47, + 0x75dc7, + 0x77207, + 0x776c7, + 0x77dc7, + 0x78087, + 0x78407, + 0x785c7, + 0x789c7, + 0x78e07, + 0x792c7, + 0x79847, + 0x79a07, + 0x79bc7, + 0x7a007, + 0x7aa87, + 0x7afc7, + 0x7b207, + 0x7b3c7, + 0x7bb87, + 0x7c187, + 0x9a42, + 0x5a58a, + 0x13808, + 0x1baf8c, + 0x4eb87, + 0x918c5, + 0x9b311, + 0x1bb46, + 0x104dca, + 0x8adca, + 0x56546, + 0xb3ecb, + 0x642, + 0x31351, + 0xc5d89, + 0x9bf49, + 0x9d306, + 0x5b542, + 0x1b21ca, + 0xafcc9, + 0xb040f, + 0xb0a0e, + 0xb3108, + 0x11b08, + 0xb5c2, + 0x6ed89, + 0x1e3586c9, + 0xbd049, + 0xbd04c, + 0x8f90e, + 0x4b8c, + 0xf2f8f, + 0x1bf08e, + 0x12b40c, + 0x33449, + 0x45391, + 0x45948, + 0x1a4e12, + 0x593cd, + 0x69acd, + 0x78f8b, + 0x81855, + 0x860c9, + 0x1518ca, + 0x188809, + 0x1aad50, + 0x1ae8cb, + 0x9890f, + 0xa868b, + 0xa914c, + 0xaa110, + 0xb7dca, + 0xb894d, + 0xd3a0e, + 0x195a0a, + 0xc1e8c, + 0xc4e94, + 0xc5a11, + 0xc694b, + 0xc858f, + 0xcbb0d, + 0xcd20e, + 0xd048c, + 0xd0c8c, + 0xd370b, + 0x172a8e, + 0x199ed0, + 0xdba8b, + 0xdc74d, + 0xdf30f, + 0xe804c, + 0xe9d8e, + 0xf3651, + 0x10570c, + 0x1d4047, + 0x10d14d, + 0x11db8c, + 0x144550, + 0x16528d, + 0x16efc7, + 0x176790, + 0x19dd08, + 0x1a3e8b, + 0xba1cf, + 0x1bb208, + 0x14bf0d, + 0x1125d0, + 0x178c89, + 0x1e78b7c8, + 0x1eabf946, + 0xc0843, + 0x3ec49, + 0xc7405, + 0x6902, + 0x48c09, + 0x14c50a, + 0x1efa52c6, + 0x15a52cd, + 0x1f36a9c4, + 0x57d06, + 0x1b68a, + 0x27bcd, + 0x1f52b109, + 0x216c3, + 0x11bb8a, + 0xe6751, + 0xe6b89, + 0xe7087, + 0xe7d88, + 0xe8447, + 0x4ec48, + 0xcacb, + 0x1311c9, + 0xf1e10, + 0xf22cc, + 0x1faf270d, + 0xf3a88, + 0xf4ec5, + 0x147e08, + 0x19ce4a, + 0x18a347, + 0x2542, + 0x1ff3f5d5, + 0x13d08a, + 0x1320c9, + 0x9e588, + 0x6ab09, + 0x7cb45, + 0x11d88a, + 0x92e0f, + 0x10d54b, + 0x11ff4c, + 0x176cd2, + 0xe9c6, + 0x7ce85, + 0x117a48, + 0xf84cb, + 0xf1151, + 0x16acc7, + 0x4da0a, + 0x20300485, + 0x1b330c, + 0x139c43, + 0x197a86, + 0x408c2, + 0x1089cb, + 0x10948a, + 0x150980c, + 0x7f5c8, + 0xf6188, + 0x2069e606, + 0x17d5c7, + 0xd782, + 0x7742, + 0x1a55d0, + 0x65087, + 0x3074f, + 0x13a06, + 0xd2b8e, + 0x99a0b, + 0x3dd48, + 0x34809, + 0x5da12, + 0x197b4d, + 0x118088, + 0x1188c9, + 0xee00d, + 0x19f749, + 0xb48b, + 0x6c348, + 0x71d88, + 0x75a88, + 0x80389, + 0x8058a, + 0x84b0c, + 0x166eca, + 0xf17ca, + 0x1178c7, + 0x9a50a, + 0x1cda4d, + 0x45c51, + 0x20acd506, + 0x1b994b, + 0x12f80c, + 0x94388, + 0x149449, + 0x160b0d, + 0x68b90, + 0x1812cd, + 0x4642, + 0x4a68d, + 0x72c2, + 0x1f702, + 0x11780a, + 0x756ca, + 0x20e7b508, + 0x104cca, + 0x11f80b, + 0x10b8cc, + 0x12048a, + 0x12070f, + 0x120ace, + 0x171cd, + 0x211e2c05, + 0x12d408, + 0x3602, + 0x1422383, + 0x415505, + 0x45d884, + 0x16202c0e, + 0x16b59cce, + 0x1720180a, + 0x17b9184e, + 0x1835788e, + 0x18b7f38c, + 0x142fc47, + 0x142fc49, + 0x143a083, + 0x1926060c, + 0x19b49bc9, + 0x1a36af09, + 0x1ab71749, + 0x1742, + 0x2b51, + 0x159c11, + 0x174d, + 0x1b6451, + 0x1577d1, + 0x17f2cf, + 0x6054f, + 0x149b0c, + 0x16ae4c, + 0x17168c, + 0x1af28d, + 0x15d915, + 0xc1a8c, + 0xc778c, + 0x135a10, + 0x141acc, + 0x14af8c, + 0x18ad99, + 0x191599, + 0x1bdfd9, + 0x1cb4d4, + 0x1d6294, + 0x1e02d4, + 0x1e2714, + 0xa994, + 0x1b2c1b49, + 0x1b9e0589, + 0x1c2c7849, + 0x16645b49, + 0x1742, + 0x16e45b49, + 0x1742, + 0xa98a, + 0x1742, + 0x17645b49, + 0x1742, + 0xa98a, + 0x1742, + 0x17e45b49, + 0x1742, + 0x18645b49, + 0x1742, + 0x18e45b49, + 0x1742, + 0xa98a, + 0x1742, + 0x19645b49, + 0x1742, + 0xa98a, + 0x1742, + 0x19e45b49, + 0x1742, + 0x1a645b49, + 0x1742, + 0xa98a, + 0x1742, + 0x1ae45b49, + 0x1742, + 0xa98a, + 0x1742, + 0x1b645b49, + 0x1742, + 0x1be45b49, + 0x1742, + 0x1c645b49, + 0x1742, + 0xa98a, + 0x1742, + 0x1400401, + 0xc945, + 0x1c0084, + 0x144ce03, + 0x1426d83, + 0x14fa443, + 0x2c0e, + 0x159cce, + 0x8450e, + 0x180a, + 0x19184e, + 0x15788e, + 0x17f38c, + 0x6060c, + 0x149bc9, + 0x16af09, + 0x171749, + 0xc1b49, + 0x1e0589, + 0xc7849, + 0x135acd, + 0x141b89, + 0xac49, + 0x12d5c4, + 0x132ac4, + 0x1c8a04, + 0x1c95c4, + 0xaae04, + 0x2ec44, + 0x3cd84, + 0x192d44, + 0x13904, + 0xbec06, + 0x59504, + 0x158e7c3, + 0x149987, + 0x148574c, + 0x1ac3, + 0x293c2, + 0x107788, + 0xd1784, + 0x14386, + 0xd8a84, + 0x15aa06, + 0x16b82, + 0xa8c1, + 0x20e44, + 0xb1706, + 0x171c3, + 0x1ac3, + 0xa0e83, + 0x13d385, + 0x124dc2, + 0x124dc8, + 0xeb947, + 0x131247, + 0xf982, 0x2000c2, - 0x201602, - 0x3be933c5, - 0x3c281445, - 0x3c746bc6, - 0x9a048, - 0x3caba385, - 0x201242, - 0x2052c2, - 0x3ce871c5, - 0x3d27e985, - 0x3d680387, - 0x3da806c9, - 0x3de1f844, + 0x212402, + 0x204542, + 0x20fa02, + 0x200382, + 0x2003c2, + 0x207742, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x20e703, + 0x217fc3, + 0x23e083, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x217fc3, + 0x23e083, + 0x10303, + 0x266a83, + 0xe704, + 0x2000c2, + 0x24ac43, + 0x2362ea43, + 0x392747, + 0x266a83, + 0x21e1c3, + 0x21e484, + 0x217fc3, + 0x23e083, + 0x226e0a, + 0x243bc5, + 0x216983, + 0x22dc42, + 0xae888, + 0x23adad8a, + 0xe01, + 0xae888, + 0x12402, + 0x137ac2, + 0x2432ae8b, + 0x2462e004, + 0x16a905, + 0x8cc5, + 0x107786, + 0x24a08cc5, + 0x54383, + 0x5cd83, + 0x9c4, + 0x157bc3, + 0x2105, + 0x146bc5, + 0xae888, + 0x1a087, + 0x2ea43, + 0x2ed4d, + 0x2523a707, + 0x159146, + 0x25401645, + 0x1c0992, + 0x159207, + 0x1dbca, + 0x10ac8, + 0x1dac7, + 0x6bcca, + 0x1bc448, + 0xe4f07, + 0x1ac70f, + 0x36fc7, + 0x192b46, + 0x13c390, + 0xcee8f, + 0x21c49, + 0x57d84, + 0x259592ce, + 0x185a89, + 0x6e646, + 0x111a89, + 0x193c86, + 0x1c2e06, + 0x4f10c, + 0xbc5ca, + 0x345c7, + 0x17edca, + 0x1596c9, + 0xf8e8c, + 0x1c8ca, + 0x4b8ca, + 0x2149, + 0x57d06, + 0x3468a, + 0x118f4a, + 0xa3a4a, + 0x137509, + 0xe54c8, + 0xe5746, + 0xed88d, + 0x5130b, + 0xc7c05, + 0x25f5a28c, + 0x14ca47, + 0x110289, + 0xd1047, + 0xc6114, + 0x1129cb, + 0x10f34a, + 0x5d88a, + 0xac80d, + 0x151fa09, + 0x117e4c, + 0x1186cb, + 0x88c3, + 0x88c3, + 0x36fc6, + 0x88c3, + 0x107788, + 0x15c103, + 0x46604, + 0x54603, + 0x347c5, + 0x1475903, + 0x51709, + 0xf84cb, + 0x14e82c3, + 0x154546, + 0x15037c7, + 0x1aafc7, + 0x26d41489, + 0x17e86, + 0x4ac43, + 0xae888, + 0x12402, + 0x4d704, + 0x61083, + 0x17b845, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x233f03, + 0x22ea43, + 0x233fc3, + 0x280203, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x23e083, + 0x2bd443, + 0x20aa43, + 0x233f03, + 0x24cd44, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x204ac3, + 0x28541585, + 0x142e6c3, + 0x22ea43, + 0x233fc3, + 0x20fa03, + 0x280203, + 0x266a83, + 0x20e704, + 0x3433c3, + 0x215f83, + 0x23cb03, + 0x217fc3, + 0x1c0443, + 0x23e083, + 0x216983, + 0x29219f03, + 0x176bc9, + 0x12402, + 0x3c7603, + 0x29e2ea43, + 0x233fc3, + 0x249283, + 0x266a83, + 0x2220c3, + 0x215f83, + 0x23e083, + 0x3005c3, + 0x3cd604, + 0xae888, + 0x2a62ea43, + 0x233fc3, + 0x2b31c3, + 0x266a83, + 0x23cb03, + 0x21e484, + 0x217fc3, + 0x23e083, + 0x2302c3, + 0xae888, + 0x2ae2ea43, + 0x233fc3, + 0x280203, + 0x205803, + 0x23e083, + 0xae888, + 0x142fc47, + 0x24ac43, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x20e704, + 0x21e484, + 0x217fc3, + 0x23e083, + 0x146bc5, + 0x178d87, + 0xc634b, + 0xe6f84, + 0xc7c05, + 0x1454408, + 0x2c10d, + 0x2c242285, + 0x27c44, + 0x12402, + 0x10103, + 0x184485, + 0x30242, + 0x53c2, + 0x34b8c5, + 0xae888, + 0x88c2, + 0x1b2c3, + 0x16b88f, + 0x12402, + 0x1063c6, + 0x2000c2, + 0x24ac43, + 0x22ea43, + 0x266a83, + 0x20e704, + 0x23cb03, + 0x21e484, + 0x217fc3, + 0x23e083, + 0x216983, + 0x30242, + 0x32ff08, + 0x24cd44, + 0x37e046, + 0x3af146, + 0xae888, + 0x31a6c3, + 0x355c09, + 0x30ddd5, + 0x10dddf, + 0x22ea43, + 0x7fa87, + 0x242992, + 0x1623c6, + 0x16fd05, + 0x1d30a, + 0x168c49, + 0x24274f, + 0x2e5904, + 0x2bbf05, + 0x313850, + 0x215f87, + 0x205803, + 0x321388, + 0x134b86, + 0x293b0a, + 0x223144, + 0x2ffec3, + 0x22dc42, + 0x2fa00b, + 0x5803, + 0x182c04, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x5803, + 0x23e083, + 0x307183, + 0x212402, + 0x1c06c3, + 0x2a4c4, + 0x217fc3, + 0x23e083, + 0x2fc39fc5, + 0x1d5cc6, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x23e083, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x21e1c3, + 0x265dc3, + 0x23e083, + 0x4ac43, + 0x212402, + 0x22ea43, + 0x233fc3, + 0x217fc3, + 0x5803, + 0x23e083, + 0x17082, + 0x2000c2, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x8cc5, + 0x1ac3, + 0x24cd44, + 0x22ea43, + 0x233fc3, + 0x217544, + 0x217fc3, + 0x23e083, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x1c0443, + 0x23e083, + 0x1357c9, + 0x4cc4, + 0x22ea43, + 0xf982, + 0x233fc3, + 0x280203, + 0x204903, + 0x23cb03, + 0x217fc3, + 0x5803, + 0x23e083, + 0x2a82, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x36a584, + 0x20e704, + 0x217fc3, + 0x23e083, + 0x20aa43, + 0x6c02, + 0x212402, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x1c0443, + 0x23e083, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x2f4c43, + 0x160c3, + 0x1e1c3, + 0x217fc3, + 0x1c0443, + 0x23e083, + 0x32748a, + 0x345389, + 0x36500b, + 0x3657ca, + 0x36f50a, + 0x37c54b, + 0x393a4a, + 0x399a4a, + 0x3a124a, + 0x3a1c4b, + 0x3c4709, + 0x3cf9ca, + 0x3cfe0b, + 0x3db28b, + 0x3e0d8a, + 0xcdc2, + 0x22ea43, + 0x233fc3, + 0x280203, + 0x23cb03, + 0x217fc3, + 0x5803, + 0x23e083, + 0xcc4b, + 0x17fe07, + 0x5af88, + 0xee144, + 0x1c4104, + 0x94dc8, + 0xea706, + 0xcc06, + 0x1a07c9, + 0xae888, + 0x22ea43, + 0x1d304, + 0x2680c4, + 0x201c02, + 0x21e484, + 0x202645, + 0x233f03, + 0x24cd44, + 0x22ea43, + 0x236704, + 0x233fc3, + 0x24d704, + 0x2e5904, + 0x20e704, + 0x215f83, + 0x217fc3, + 0x23e083, + 0x24a845, + 0x204ac3, + 0x216983, + 0x204343, + 0x2ddf84, + 0x32a004, + 0x23a185, + 0xae888, + 0x3b4e04, + 0x3c2f86, + 0x202284, + 0x212402, + 0x3770c7, + 0x3a9947, + 0x24bb44, + 0x20e785, + 0x365485, + 0x22f845, + 0x20e704, + 0x38f948, + 0x2523c6, + 0x3641c8, + 0x2836c5, + 0x2ee705, + 0x237bc4, + 0x23e083, + 0x300ac4, + 0x37b286, + 0x243cc3, + 0x2ddf84, + 0x24fd85, + 0x248b84, + 0x2a67c4, + 0x22dc42, + 0x232ec6, + 0x3b7ec6, + 0x315fc5, + 0x2000c2, + 0x24ac43, + 0x34e12402, + 0x21fa44, + 0x200382, + 0x23cb03, + 0x20cac2, + 0x217fc3, + 0x2003c2, + 0x2fcf46, + 0x208503, + 0x20aa43, + 0xae888, + 0xae888, + 0x266a83, + 0x1c0443, + 0x2000c2, + 0x35a12402, + 0x266a83, + 0x26e2c3, + 0x3433c3, + 0x22e004, + 0x217fc3, + 0x23e083, + 0xae888, + 0x2000c2, + 0x36212402, + 0x22ea43, + 0x217fc3, + 0x5803, + 0x23e083, + 0x682, + 0x203b42, + 0x21fcc2, + 0x21e1c3, + 0x2f8e43, + 0x2000c2, + 0x146bc5, + 0xae888, + 0x178d87, + 0x212402, + 0x233fc3, + 0x24d704, + 0x2033c3, + 0x266a83, + 0x204903, + 0x23cb03, + 0x217fc3, + 0x213cc3, + 0x23e083, + 0x234fc3, + 0x140d13, + 0x142dd4, + 0x146bc5, + 0x178d87, + 0x1dbc9, + 0x110b86, + 0x121b4b, + 0x36fc6, + 0x54bc7, + 0xe786, + 0x649, + 0x1d818a, + 0x9110d, + 0x127d8c, + 0x1198ca, + 0x15d048, + 0x1b5a05, + 0x1dc08, + 0x13a06, + 0x1ce786, + 0x134c46, + 0x602, + 0x2293c2, + 0x6f204, + 0xa0e86, + 0x1411d0, + 0x147a54e, + 0x1e46, + 0x696cc, + 0x37b22f0b, + 0x146bc5, + 0x15434b, + 0x37fce6c4, + 0x1c0247, + 0x23c91, + 0x11a7ca, + 0x22ea43, + 0x38285648, + 0x6bc45, + 0xf988, + 0x1ff44, + 0x14c705, + 0x38561cc6, + 0x9b306, + 0xc9b46, + 0x9620a, + 0x96ecc, + 0x1c2043, + 0x1c4104, + 0x38a120c4, + 0x51709, + 0x164347, + 0x1167ca, + 0x14dac89, + 0x605, + 0x103583, + 0x38e35107, + 0x2a7c5, + 0x153d986, + 0x14731c6, + 0xb3f8c, + 0x104248, + 0x390408c3, + 0xfa24b, + 0x12bd4b, + 0x3964950c, + 0x140ba83, + 0xc96c8, + 0xfa4c5, + 0xc6c09, + 0xeca43, + 0x11fb08, + 0x141b5c6, + 0x8e8c7, + 0x39b60b09, + 0x99c87, + 0xf054a, + 0x3afc6788, + 0x11838d, + 0xff48, + 0x1ac3, + 0x1445009, + 0x3a643, + 0x36fc6, + 0x107788, + 0x13904, + 0x154c85, + 0x1492ec3, + 0x22387, + 0x39e22383, + 0x3a3c78c6, + 0x3a637e84, + 0x3ab09647, + 0x107784, + 0x107784, + 0x107784, + 0x107784, + 0x41, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x23e083, + 0x2000c2, + 0x212402, + 0x266a83, + 0x209582, + 0x217fc3, + 0x23e083, + 0x208503, + 0x38644f, + 0x38680e, + 0xae888, + 0x22ea43, + 0x44cc7, + 0x233fc3, + 0x266a83, + 0x2191c3, + 0x217fc3, + 0x23e083, + 0x1d84, + 0x157d04, + 0x1b4744, + 0x21afc3, + 0x324007, + 0x207d42, + 0x272549, + 0x200ac2, + 0x3a58cb, + 0x2a6b8a, + 0x2aec89, + 0x200542, + 0x220306, + 0x244495, + 0x3a5a15, + 0x387d93, + 0x3a5f93, + 0x2272c2, + 0x2272c5, + 0x25f44c, + 0x27ad0b, + 0x277a05, + 0x201802, + 0x239202, + 0x381b06, + 0x203502, + 0x2cf9c6, + 0x21d58d, + 0x22a54c, + 0x38b884, + 0x200882, + 0x222b02, + 0x3a51c8, + 0x200202, + 0x336d46, + 0x39c70f, + 0x357dd0, + 0x229804, + 0x244655, + 0x387f13, + 0x24c943, + 0x369f8a, + 0x20c5c7, + 0x3a1ec9, + 0x316687, + 0x30bf02, + 0x200282, + 0x3c90c6, + 0x204cc2, + 0xae888, + 0x207f42, + 0x208a02, + 0x228fc7, + 0x348187, + 0x348191, + 0x218885, + 0x21888e, + 0x2194cf, + 0x20cfc2, + 0x3236c7, + 0x21b008, + 0x20aac2, + 0x21c942, + 0x227846, + 0x22784f, + 0x26c690, + 0x22c442, + 0x20cf02, + 0x238b48, + 0x214803, + 0x261248, + 0x2eea8d, + 0x20cf03, + 0x3cc248, + 0x28734f, + 0x28770e, + 0x25d54a, + 0x26cb11, + 0x26cf90, + 0x30280d, + 0x302b4c, + 0x3c20c7, + 0x36a107, + 0x37e109, + 0x29a842, + 0x205082, + 0x256b8c, + 0x256e8b, + 0x200d42, + 0x2d38c6, + 0x202282, + 0x200482, + 0x361e82, + 0x212402, + 0x22f244, + 0x239d87, + 0x22c982, + 0x240307, + 0x241b47, + 0x230a82, + 0x211d02, + 0x244b85, + 0x20da02, + 0x3985ce, + 0x3d068d, + 0x233fc3, + 0x28cf0e, + 0x2bb64d, + 0x35cc43, + 0x203142, + 0x28ac84, + 0x29a802, + 0x223ec2, + 0x3930c5, + 0x3a3b07, + 0x2481c2, + 0x20fa02, + 0x24d307, + 0x251a88, + 0x2ba882, + 0x27cf06, + 0x256a0c, + 0x256d4b, + 0x2091c2, + 0x261d4f, + 0x262110, + 0x26250f, + 0x2628d5, + 0x262e14, + 0x26330e, + 0x26368e, + 0x263a0f, + 0x263dce, + 0x264154, + 0x264653, + 0x264b0d, + 0x27c349, + 0x292a43, + 0x2033c2, + 0x2d2685, + 0x2033c6, + 0x200382, + 0x3451c7, + 0x266a83, + 0x200642, + 0x23e108, + 0x26cd51, + 0x26d190, + 0x202182, + 0x291c47, + 0x204b82, + 0x277507, + 0x206902, + 0x207089, + 0x381ac7, + 0x294648, + 0x361b06, + 0x207483, + 0x207485, + 0x234242, + 0x2004c2, + 0x3c94c5, + 0x3b3785, + 0x201482, + 0x219303, + 0x3546c7, + 0x20bdc7, + 0x204d02, + 0x249084, + 0x20eb03, + 0x2f6f89, + 0x20eb08, + 0x202702, + 0x20a682, + 0x26b947, + 0x26ca45, + 0x273508, + 0x2b1347, + 0x209f03, + 0x2a0d06, + 0x30268d, + 0x302a0c, + 0x305e06, + 0x206b02, + 0x208c82, + 0x20b982, + 0x2871cf, + 0x2875ce, + 0x365507, + 0x204482, + 0x388c05, + 0x388c06, + 0x215782, + 0x200bc2, + 0x293506, + 0x206583, + 0x206586, + 0x2d8a45, + 0x2d8a4d, + 0x2d92d5, + 0x2da14c, + 0x2da4cd, + 0x2da812, + 0x20a942, + 0x2720c2, + 0x203882, + 0x36ac46, + 0x204a46, + 0x202542, + 0x203446, + 0x201102, + 0x324805, + 0x202582, + 0x398709, + 0x22ce4c, + 0x22d18b, + 0x2003c2, + 0x252e48, + 0x202a42, + 0x200a82, + 0x278706, + 0x245ac5, + 0x200a87, + 0x22dcc5, + 0x257e45, + 0x201b42, + 0x21dcc2, + 0x205b42, + 0x298c07, + 0x2fd00d, + 0x2fd38c, + 0x235507, + 0x27ce82, + 0x211c82, + 0x3dc788, + 0x248d88, + 0x34f348, + 0x3bb1c4, + 0x372d07, + 0x36aa43, + 0x22d782, + 0x204ac2, + 0x2fe3c9, + 0x30b287, + 0x216982, + 0x278b05, + 0x242c42, + 0x20d402, + 0x2f8b83, + 0x2f8b86, + 0x306d42, + 0x308142, + 0x200402, + 0x3616c6, + 0x34de07, + 0x216782, + 0x200902, + 0x26108f, + 0x28cd4d, + 0x28fd0e, + 0x2bb4cc, + 0x208842, + 0x205302, + 0x361945, + 0x325d86, + 0x200b82, + 0x205502, + 0x200682, + 0x28d0c4, + 0x2c14c4, + 0x389fc6, + 0x207742, + 0x28d807, + 0x23c643, + 0x23c648, + 0x23d1c8, + 0x245207, + 0x249946, + 0x20ab02, + 0x2186c3, + 0x2186c7, + 0x292246, + 0x2ecb85, + 0x27a1c8, + 0x2018c2, + 0x3c1007, + 0x207142, + 0x25cdc2, + 0x201702, + 0x219649, + 0x203c02, + 0x10acc8, + 0x201f42, + 0x235783, + 0x3599c7, + 0x200f02, + 0x22cfcc, + 0x22d2cb, + 0x305e86, + 0x3034c5, + 0x203d02, + 0x202a82, + 0x2cb146, + 0x20dd03, + 0x36a307, + 0x2b3f42, + 0x2008c2, + 0x244315, + 0x3a5bd5, + 0x387c53, + 0x3a6113, + 0x2596c7, + 0x28b111, + 0x2908d0, + 0x2f7b92, + 0x29b711, + 0x2a0548, + 0x2a0550, + 0x2a2c8f, + 0x2a6953, + 0x2aea52, + 0x2b8190, + 0x36f14f, + 0x3a4112, + 0x2bac51, + 0x2bfa93, + 0x3426d2, + 0x2d868f, + 0x2e010e, + 0x2e3512, + 0x2e43d1, + 0x2e79cf, + 0x2ea38e, + 0x2ed451, + 0x2fa9d0, + 0x304412, + 0x307211, + 0x309090, + 0x321ecf, + 0x37ab11, + 0x3d2fd0, + 0x33fac6, + 0x314b47, + 0x2153c7, + 0x202402, + 0x288985, + 0x3135c7, + 0x21fcc2, + 0x208d82, + 0x22b8c5, + 0x208743, + 0x26ec86, + 0x2fd1cd, + 0x2fd50c, + 0x2034c2, + 0x25f2cb, + 0x27abca, + 0x22718a, + 0x2ca549, + 0x2fc34b, + 0x2b148d, + 0x313ccc, + 0x240cca, + 0x2466cc, + 0x24e88b, + 0x27784c, + 0x27bd0e, + 0x29cb4b, + 0x2b668c, + 0x2ec543, + 0x2edf06, + 0x3c6782, + 0x305102, + 0x25cb43, + 0x201502, + 0x204243, + 0x353446, + 0x262a87, + 0x2c3846, + 0x2158c8, + 0x354548, + 0x3800c6, + 0x20e482, + 0x31598d, + 0x315ccc, + 0x32bf07, + 0x319707, + 0x223542, + 0x216b82, + 0x203b02, + 0x284302, + 0x336c56, + 0x33b795, + 0x3407d6, + 0x3437d3, + 0x343e92, + 0x35bc93, + 0x35de52, + 0x3b6bcf, + 0x3c5758, + 0x3c6257, + 0x3c6c59, + 0x3c8b18, + 0x3c96d8, + 0x3cb9d7, + 0x3cc457, + 0x3ce196, + 0x3d1cd3, + 0x3d2755, + 0x3d33d2, + 0x3d3853, + 0x212402, + 0x217fc3, + 0x23e083, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x21e484, + 0x217fc3, + 0x23e083, + 0x208503, + 0x2000c2, + 0x202642, + 0x3ce98545, + 0x3d25ef05, + 0x3d73ed86, + 0xae888, + 0x3dac0105, + 0x212402, + 0x204542, + 0x3de5de45, + 0x3e285fc5, + 0x3e687a87, + 0x3ea87dc9, + 0x3ef4da84, 0x200382, 0x200642, - 0x3e249a05, - 0x3e69d789, - 0x3eb2fb48, - 0x3eeb4985, - 0x3f350107, - 0x3f61d988, - 0x3fb09745, - 0x3fe9e2c6, - 0x403a2709, - 0x406db0c8, - 0x40aca648, - 0x40e9ddca, - 0x412c21c4, - 0x4168e885, - 0x41ac6c08, - 0x41f44945, - 0x20fe82, - 0x42297703, - 0x426aa1c6, - 0x42aaf5c8, - 0x42ef2f86, - 0x4320ad88, - 0x43785546, - 0x43a02c44, - 0x43e08482, - 0x446f4cc7, - 0x44ab0b04, - 0x44e79487, - 0x453cfc87, + 0x3f25bf05, + 0x3f69e949, + 0x3fb36248, + 0x3feb87c5, + 0x403513c7, + 0x40623708, + 0x40b08c85, + 0x40e9f486, + 0x413a9a89, + 0x416dd6c8, + 0x41ad02c8, + 0x41e9ef8a, + 0x422ef084, + 0x426ad705, + 0x42acc788, + 0x42e48985, + 0x214882, + 0x4324bd03, + 0x436abe06, + 0x43a6af08, + 0x43ef4246, + 0x4434df48, + 0x447af006, + 0x44a463c4, + 0x44e03182, + 0x45707b87, + 0x45ab43c4, + 0x45e81487, + 0x463da087, 0x2003c2, - 0x456a2c85, - 0x45a13504, - 0x45fa3407, - 0x4623d187, - 0x466830c6, - 0x46a7f445, - 0x46e9d887, - 0x472daf48, - 0x477d0007, - 0x47b41189, - 0x47ed7505, - 0x48331207, - 0x48692a06, - 0x647cb, - 0x48b3aec8, - 0x225bcd, - 0x25d2c9, - 0x27418b, - 0x27c08b, - 0x2b014b, - 0x2f010b, - 0x320d8b, - 0x32104b, - 0x321e89, - 0x322e8b, - 0x32314b, - 0x323c8b, - 0x324e0a, - 0x32534a, - 0x32594c, - 0x32934b, - 0x329aca, - 0x33e6ca, - 0x34b30e, - 0x34d44e, - 0x34d7ca, - 0x34f64a, - 0x350c0b, - 0x350ecb, - 0x3519cb, - 0x36cdcb, - 0x36d3ca, - 0x36e08b, - 0x36e34a, - 0x36e5ca, - 0x36e84a, - 0x38e64b, - 0x39510b, - 0x397c0e, - 0x397f8b, - 0x39e8cb, - 0x39fc0b, - 0x3a3fca, - 0x3a4249, - 0x3a448a, - 0x3a5d8a, - 0x3bdf4b, - 0x3ca84b, - 0x3cb24a, - 0x3cc0cb, - 0x3d520b, - 0x3dfe4b, - 0x48e81788, - 0x4928ae89, - 0x496a5789, - 0x49aed408, - 0x3597c5, - 0x2041c3, - 0x251084, - 0x3015c5, - 0x21f586, - 0x307385, - 0x28a004, - 0x37f048, - 0x31bb05, - 0x294984, - 0x3c7607, - 0x2a4b0a, - 0x38f4ca, - 0x360107, - 0x34c207, - 0x2e6307, - 0x280947, - 0x334605, - 0x3b9b46, - 0x2f2207, - 0x39bc04, - 0x2f9b46, - 0x2f9a46, - 0x3c2d85, - 0x3b6684, - 0x29ee06, - 0x2a3bc7, - 0x34bb86, - 0x3adf47, - 0x251143, - 0x384106, - 0x238e85, - 0x280487, - 0x26a5ca, - 0x356504, - 0x219d88, - 0x31a2c9, - 0x2d4847, - 0x390606, - 0x3c5808, - 0x2f36c9, - 0x383f44, - 0x31eb84, - 0x2dea45, - 0x222b48, - 0x2d4b07, - 0x36c9c9, - 0x34cdc8, - 0x318406, - 0x264a46, - 0x29f988, - 0x36b706, - 0x281445, - 0x283186, - 0x279b88, - 0x27f9c6, - 0x255d8b, - 0x39d746, - 0x2a14cd, - 0x3d0845, - 0x2b09c6, - 0x20c045, - 0x24a789, - 0x370447, - 0x385188, - 0x291386, - 0x2a0689, - 0x3b1306, - 0x26a545, - 0x2a6dc6, - 0x2e5346, - 0x2d9209, - 0x2c0b06, - 0x2a4807, - 0x360b05, - 0x201583, - 0x21b7c5, - 0x34dd07, - 0x288f46, - 0x3d0749, - 0x346bc6, - 0x279686, - 0x20f849, - 0x282b89, - 0x2a8587, - 0x343488, - 0x2a7789, - 0x280c08, - 0x394486, - 0x2e2e85, - 0x2cfd8a, - 0x279706, - 0x33a806, - 0x2dc705, - 0x2523c8, - 0x326447, - 0x22f5ca, - 0x24e1c6, - 0x2e05c5, - 0x309186, - 0x215f87, - 0x3904c7, - 0x21c2c5, - 0x26a705, - 0x263586, - 0x269d46, - 0x26c0c6, - 0x2c70c4, - 0x282109, - 0x28bd06, - 0x30618a, - 0x2211c8, - 0x330f08, - 0x38f4ca, - 0x2af785, - 0x2a3b05, - 0x3c4f48, - 0x2c4f08, - 0x237c47, - 0x3b9d86, - 0x333988, - 0x2108c7, - 0x274848, - 0x2bebc6, - 0x283ec8, - 0x29c606, - 0x27ba87, - 0x3681c6, - 0x29ee06, - 0x2643ca, - 0x305206, - 0x2e2e89, - 0x36f506, - 0x2a5c8a, - 0x202c49, - 0x241706, - 0x2c2844, - 0x31e8cd, - 0x28b107, - 0x3b2a86, - 0x2ca505, - 0x3b1385, - 0x391106, - 0x2a7349, - 0x2bd687, - 0x27ab86, - 0x31db46, - 0x28a089, - 0x281384, - 0x244744, - 0x204088, - 0x356846, - 0x2a6ec8, - 0x318a88, - 0x2883c7, - 0x3c0549, - 0x26c2c7, - 0x2ba24a, - 0x2fcb8f, - 0x2e43ca, - 0x3d9e45, - 0x279dc5, - 0x2173c5, - 0x3c2147, - 0x215b43, - 0x343688, - 0x3de2c6, - 0x3de3c9, - 0x2f2b06, - 0x2d9047, - 0x2a0449, - 0x385088, - 0x2dc7c7, - 0x31f203, - 0x359845, - 0x215ac5, - 0x2c6f0b, - 0x344a04, - 0x23ba44, - 0x277906, - 0x31f3c7, - 0x39168a, - 0x3803c7, - 0x293607, - 0x27e985, - 0x3c8785, - 0x270489, - 0x29ee06, - 0x38024d, - 0x298b05, - 0x2bc683, - 0x226283, - 0x35c505, - 0x334285, - 0x3c5808, - 0x27b4c7, - 0x2444c6, - 0x2a5406, - 0x22a145, - 0x233087, - 0x287ec7, - 0x22b447, - 0x28e90a, - 0x3841c8, - 0x2c70c4, - 0x27f747, - 0x27d6c7, - 0x35e406, - 0x29bc87, - 0x2e9688, - 0x357b08, - 0x370346, - 0x34c448, - 0x2c0b84, - 0x2f2206, - 0x37ff46, - 0x3bbc46, - 0x204506, - 0x2a3044, - 0x280a06, - 0x2c95c6, - 0x29f1c6, - 0x245806, - 0x3d0d46, - 0x2e94c6, - 0x2443c8, - 0x2bb748, - 0x2dfcc8, - 0x307588, - 0x3c4ec6, - 0x206a05, - 0x21b786, - 0x2b4a05, - 0x393907, - 0x29d485, - 0x20d743, - 0x226305, - 0x2ed004, - 0x3d0e85, - 0x202943, - 0x395407, - 0x36c188, - 0x3ae006, - 0x37e88d, - 0x279d86, - 0x29e785, - 0x205243, - 0x2c65c9, - 0x281506, - 0x299486, - 0x292104, - 0x2e4347, - 0x35bf06, - 0x244945, - 0x23a8c3, - 0x206284, - 0x27d886, - 0x35ad44, - 0x26e588, - 0x3c7989, - 0x2bdc09, - 0x2a6cca, - 0x2a914d, - 0x361a87, - 0x3ba086, - 0x2afb04, - 0x2806c9, - 0x285b48, - 0x28ad06, - 0x234e86, - 0x29bc87, - 0x2c74c6, - 0x2261c6, - 0x287346, - 0x3cfd0a, - 0x21d988, - 0x265085, - 0x295e09, - 0x2d528a, - 0x30b048, - 0x2a34c8, - 0x299408, - 0x2b0d0c, - 0x34da05, - 0x2a5688, - 0x2bba46, - 0x372046, - 0x3db607, - 0x3802c5, - 0x283305, - 0x2bdac9, - 0x20d447, - 0x3de385, - 0x2283c7, - 0x226283, - 0x2d5745, - 0x2273c8, - 0x2d6d07, - 0x2a3389, - 0x2e2d45, - 0x380fc4, - 0x2a8e08, - 0x2c1e87, - 0x2dc988, - 0x20d188, - 0x2b1a85, - 0x20c206, - 0x2a5506, - 0x2dee09, - 0x380047, - 0x2b52c6, - 0x3de007, - 0x2027c3, - 0x21f844, - 0x2da0c5, - 0x2331c4, - 0x246744, - 0x389507, - 0x2664c7, - 0x27ad44, - 0x2a31d0, - 0x296007, - 0x3c8785, - 0x30394c, - 0x20cf44, - 0x2b9a08, - 0x27b989, - 0x3bcb46, - 0x302a48, - 0x267884, - 0x277c08, - 0x22fbc6, - 0x264248, - 0x2a4186, - 0x28ba4b, - 0x32b105, - 0x2d9f48, - 0x211b44, - 0x281e8a, - 0x2a3389, - 0x3680c6, - 0x2bbc48, - 0x259345, - 0x2c5bc4, - 0x2b9906, - 0x22b308, - 0x281788, - 0x32dc86, - 0x384404, - 0x2cfd06, - 0x26c347, - 0x279387, - 0x29bc8f, - 0x339e47, - 0x2417c7, - 0x372245, - 0x372ac5, - 0x2a8249, - 0x2ead06, - 0x389745, - 0x282e87, - 0x3db888, - 0x300805, - 0x3681c6, - 0x221008, - 0x2f2f8a, - 0x22b008, - 0x28e347, - 0x2fcfc6, - 0x295dc6, - 0x2003c3, - 0x212503, - 0x2d5449, - 0x2a7609, - 0x2b9806, - 0x2e2d45, - 0x2b0b88, - 0x2bbc48, - 0x36b888, - 0x2873cb, - 0x37eac7, - 0x31bdc9, - 0x29bf08, - 0x34f104, - 0x3bb888, - 0x28fe49, - 0x2b55c5, - 0x3c2047, - 0x21f8c5, - 0x281688, - 0x29324b, - 0x29d5d0, - 0x2b0545, - 0x211a8c, - 0x244685, - 0x27ea03, - 0x2bf706, - 0x2c8b04, - 0x368486, - 0x2a3bc7, - 0x202804, - 0x242808, - 0x34354d, - 0x318845, - 0x2a2cc4, - 0x2ae044, - 0x2b3e49, - 0x2b2308, - 0x32b5c7, - 0x22fc48, - 0x2821c8, - 0x27ae85, - 0x2d0e87, - 0x27ae07, - 0x2cd307, - 0x26a709, - 0x2879c9, - 0x3dfb46, - 0x301006, - 0x282f46, - 0x322605, - 0x3b8a04, - 0x3c4206, - 0x3c7086, - 0x27aec8, - 0x215c4b, - 0x3563c7, - 0x2afb04, - 0x35be46, - 0x2e99c7, - 0x36f805, - 0x2971c5, - 0x2ae204, - 0x287946, - 0x3c4288, - 0x2806c9, - 0x24bb46, - 0x285948, - 0x244a06, - 0x360a48, - 0x321a0c, - 0x27ad46, - 0x29e44d, - 0x29e8cb, - 0x2a48c5, - 0x288007, - 0x2c0c06, - 0x390388, - 0x3dfbc9, - 0x2ee4c8, - 0x3c8785, - 0x39b947, - 0x280d08, - 0x23b4c9, - 0x35bb86, - 0x25138a, - 0x390108, - 0x2ee30b, - 0x21dc0c, - 0x277d08, - 0x27cc06, - 0x2d0888, - 0x2f2c07, - 0x33a409, - 0x35024d, - 0x29ed06, - 0x2250c8, - 0x2bb609, - 0x2c71c8, - 0x283fc8, - 0x2c9ecc, - 0x2cab87, - 0x2cb7c7, - 0x26a545, - 0x2bdf87, - 0x3db748, - 0x2b9986, - 0x24b9cc, - 0x300288, - 0x2db2c8, - 0x307846, - 0x2af0c7, - 0x3dfd44, - 0x307588, - 0x2cf84c, - 0x28538c, - 0x3d9ec5, - 0x3c2e07, - 0x384386, - 0x2af046, - 0x24a948, - 0x21d284, - 0x34bb8b, - 0x27a34b, - 0x2fcfc6, - 0x3433c7, - 0x343ec5, - 0x272605, - 0x34bcc6, - 0x259305, - 0x3449c5, - 0x2d4287, - 0x20e989, - 0x269f04, - 0x25a2c5, - 0x2f6d85, - 0x35aac8, - 0x28d785, - 0x2cf209, - 0x2badc7, - 0x2badcb, - 0x2fbbc6, - 0x244109, - 0x3b65c8, - 0x290185, - 0x2cd408, - 0x287a08, - 0x253047, - 0x2b4247, - 0x389589, - 0x264187, - 0x29d389, - 0x2da70c, - 0x341088, - 0x2c0649, - 0x2c2f87, - 0x282289, - 0x33c3c7, - 0x21dd08, - 0x33a345, - 0x2f2186, - 0x2ca548, - 0x217488, - 0x2d5149, - 0x344a07, - 0x273005, - 0x3c3909, - 0x2f42c6, - 0x292a04, - 0x37b446, - 0x2af448, - 0x320807, - 0x215e48, - 0x34c509, - 0x33be47, - 0x2a4cc6, - 0x2880c4, - 0x226389, - 0x2d0d08, - 0x307707, - 0x367a06, - 0x215b86, - 0x33a784, - 0x34c706, - 0x239f83, - 0x32ac89, - 0x32b0c6, - 0x2a3705, - 0x2a5406, - 0x2d95c5, - 0x281188, - 0x347207, - 0x2306c6, - 0x287206, - 0x330f08, - 0x2a83c7, - 0x29ed45, - 0x2a2fc8, - 0x3aa048, - 0x390108, - 0x244545, - 0x2f2206, - 0x2bd9c9, - 0x2dec84, - 0x2d944b, - 0x225ecb, - 0x264f89, - 0x226283, - 0x257845, - 0x3ae4c6, - 0x246508, - 0x306ec4, - 0x3ae006, - 0x28ea49, - 0x2c93c5, - 0x2d41c6, - 0x2c1e86, - 0x222dc4, - 0x29958a, - 0x2a3648, - 0x217486, - 0x2cd045, - 0x343d47, - 0x3344c7, - 0x20c204, - 0x226107, - 0x2ba244, - 0x34ce46, - 0x210b43, - 0x26a705, - 0x2b6e45, - 0x23ef88, - 0x27f905, - 0x27aa89, - 0x2a9fc7, - 0x3073cb, - 0x2a9fcc, - 0x2aa5ca, - 0x350107, - 0x203d03, - 0x278808, - 0x244705, - 0x300885, - 0x359904, - 0x21dc06, - 0x27b986, - 0x34c747, - 0x23a80b, - 0x2a3044, - 0x355f44, - 0x2d4444, - 0x2d8ec6, - 0x202804, - 0x222c48, - 0x359705, - 0x21c145, - 0x36b7c7, - 0x288109, - 0x334285, - 0x39110a, - 0x3db9c9, - 0x2b174a, - 0x3cfe49, - 0x3545c4, - 0x31dc05, - 0x2c75c8, - 0x3a34cb, - 0x2dea45, - 0x24c386, - 0x241304, - 0x27afc6, - 0x33bcc9, - 0x2e9ac7, - 0x346d88, - 0x2a94c6, - 0x26c2c7, - 0x281788, - 0x377746, - 0x3c72c4, - 0x3817c7, - 0x382e85, - 0x392987, - 0x267784, - 0x2c0b86, - 0x30ad48, - 0x29ea88, - 0x2ff987, - 0x202808, - 0x29c6c5, - 0x226004, - 0x38f3c8, - 0x202904, - 0x217345, - 0x30af44, - 0x2109c7, - 0x28bdc7, - 0x2823c8, - 0x2dcb06, - 0x27f885, - 0x27a888, - 0x246848, - 0x2a6c09, - 0x2261c6, - 0x22f648, - 0x281d0a, - 0x36f888, - 0x309745, - 0x21b986, - 0x2a7208, - 0x39ba0a, - 0x219507, - 0x285f85, - 0x292c08, - 0x270fc4, - 0x252446, - 0x2cbb48, - 0x3d0d46, - 0x334c08, - 0x2d7ac7, - 0x3c7506, - 0x2c2844, - 0x237687, - 0x2bc004, - 0x33bc87, - 0x367e0d, - 0x237cc5, - 0x2d6b0b, - 0x285606, - 0x251e88, - 0x2427c4, - 0x3c50c6, - 0x27d886, - 0x2d0bc7, - 0x29e10d, - 0x304807, - 0x2bc5c8, - 0x284145, - 0x270648, - 0x2d4a86, - 0x29c748, - 0x238606, - 0x3036c7, - 0x282749, - 0x35a587, - 0x28afc8, - 0x34a005, - 0x22a1c8, - 0x2aef85, - 0x228e05, - 0x362b45, - 0x24dec3, - 0x204584, - 0x292e05, - 0x3a2709, - 0x367906, - 0x2e9788, - 0x2c2105, - 0x2bde47, - 0x371bca, - 0x2d4109, - 0x2e524a, - 0x2dfd48, - 0x22820c, - 0x282f0d, - 0x311883, - 0x334b08, - 0x206245, - 0x2f2d46, - 0x384f06, - 0x31e585, - 0x3de109, - 0x33d2c5, - 0x27a888, - 0x258546, - 0x369706, - 0x2a8cc9, - 0x3a9007, - 0x293506, - 0x371b48, - 0x3bbb48, - 0x2ed607, - 0x2c974e, - 0x2d4cc5, - 0x23b3c5, - 0x3d0c48, - 0x271e87, - 0x200e42, - 0x2c9b84, - 0x36838a, - 0x3077c8, - 0x287b46, - 0x2a0588, - 0x2a5506, - 0x288b88, - 0x2b52c8, - 0x228dc4, - 0x2be205, - 0x668c84, - 0x668c84, - 0x668c84, - 0x20aec3, - 0x215a06, - 0x27ad46, - 0x2a458c, - 0x202dc3, - 0x267786, - 0x21a604, - 0x281488, - 0x28e885, - 0x368486, - 0x2c6d08, - 0x2e0e46, - 0x230646, - 0x3c5608, - 0x2da147, - 0x263f49, - 0x3ae60a, - 0x266644, - 0x29d485, - 0x2e4305, - 0x2d7746, - 0x361ac6, - 0x2a50c6, - 0x3dc246, - 0x264084, - 0x26408b, - 0x264a44, - 0x244285, - 0x2b3a45, - 0x288486, - 0x201b48, - 0x282dc7, - 0x32b044, - 0x25b603, - 0x270ac5, - 0x37b307, - 0x282ccb, - 0x23ee87, - 0x2c6c08, - 0x2be347, - 0x26b746, - 0x25d588, - 0x2c51cb, - 0x301506, - 0x212849, - 0x2c5345, - 0x31f203, - 0x2d41c6, - 0x2d79c8, - 0x20c2c3, - 0x24c343, - 0x281786, - 0x2a5506, - 0x3759ca, - 0x27cc45, - 0x27d6cb, - 0x2a534b, - 0x213c03, - 0x20ea43, - 0x2ba1c4, - 0x370587, - 0x277d04, - 0x281484, - 0x2bb8c4, - 0x36fb88, - 0x2ccf88, - 0x214d49, - 0x2d7588, - 0x3b2d07, - 0x245806, - 0x2e93cf, - 0x2d4e06, - 0x2df404, - 0x2ccdca, - 0x37b207, - 0x2bc106, - 0x292a49, - 0x214cc5, - 0x23f0c5, - 0x214e06, - 0x22a303, - 0x271009, - 0x21db06, - 0x34c2c9, - 0x391686, - 0x26a705, - 0x35c905, - 0x204583, - 0x3706c8, - 0x32b787, - 0x3de2c4, - 0x281308, - 0x371dc4, - 0x359006, - 0x2bf706, - 0x23d646, - 0x2d9e09, - 0x300805, - 0x29ee06, - 0x2713c9, - 0x2d3e06, - 0x2e94c6, - 0x3a14c6, - 0x22bd85, - 0x30af46, - 0x3036c4, - 0x33a345, - 0x217484, - 0x2bcf46, - 0x298ac4, - 0x2109c3, - 0x285c05, - 0x233d88, - 0x3572c7, - 0x306f49, - 0x285e88, - 0x29f751, - 0x2c1f0a, - 0x2fcf07, - 0x357e46, - 0x21a604, - 0x2ca648, - 0x2ea008, - 0x29f90a, - 0x2cefcd, - 0x2a6dc6, - 0x3c5706, - 0x237746, - 0x21c147, - 0x2bc685, - 0x286c47, - 0x2813c5, - 0x2baf04, - 0x3c5e46, - 0x224dc7, - 0x270d0d, - 0x2a7147, - 0x37ef48, - 0x27ab89, - 0x21b886, - 0x35bb05, - 0x23c2c4, - 0x2af546, - 0x20c106, - 0x307946, - 0x2a0e08, - 0x21ad83, - 0x2465c3, - 0x349b05, - 0x31ec06, - 0x2b5285, - 0x2a96c8, - 0x2a3d8a, - 0x347344, - 0x281488, - 0x299408, - 0x2882c7, - 0x286589, - 0x2c6908, - 0x280747, - 0x2bbb46, - 0x3d0d4a, - 0x2af5c8, - 0x30c989, - 0x2b23c8, - 0x21ef89, - 0x357d07, - 0x312785, - 0x2a5906, - 0x2b9808, - 0x252008, - 0x224508, - 0x222dc8, - 0x244285, - 0x200d04, - 0x232708, - 0x241084, - 0x3cfc44, - 0x26a705, - 0x2949c7, - 0x287ec9, - 0x2d09c7, - 0x20f8c5, - 0x277b06, - 0x36f1c6, - 0x201c44, - 0x2a9006, - 0x27db04, - 0x291746, - 0x287c86, - 0x212e86, - 0x3c8785, - 0x2a9587, - 0x203d03, - 0x211609, - 0x330d08, - 0x2805c4, - 0x2805cd, - 0x29eb88, - 0x32a608, - 0x30c906, - 0x282849, - 0x2d4109, - 0x33b9c5, - 0x2a3e8a, - 0x291aca, - 0x2b444c, - 0x2b45c6, - 0x278406, - 0x2d5686, - 0x38ce89, - 0x2f2f86, - 0x21dd86, - 0x33d386, - 0x307588, - 0x202806, - 0x2de54b, - 0x294b45, - 0x21c145, - 0x279485, - 0x203e06, - 0x226043, - 0x23d5c6, - 0x2a70c7, - 0x2ca505, - 0x2d1c05, - 0x3b1385, - 0x310686, - 0x32fa44, - 0x32fa46, - 0x2ab289, - 0x203c8c, - 0x2bac48, - 0x22b284, - 0x30ac46, - 0x285706, - 0x2d79c8, - 0x2bbc48, - 0x203b89, - 0x343d47, - 0x356589, - 0x2726c6, - 0x22c144, - 0x2082c4, - 0x27f6c4, - 0x281788, - 0x287d0a, - 0x334206, - 0x3677c7, - 0x392c07, - 0x244205, - 0x36c944, - 0x28fe06, - 0x2bc6c6, - 0x21d2c3, - 0x330b47, - 0x20d088, - 0x33bb0a, - 0x22be48, - 0x20ad88, - 0x298b05, - 0x2a49c5, - 0x3564c5, - 0x2445c6, - 0x247486, - 0x33c885, - 0x32aec9, - 0x36c74c, - 0x2f4ec7, - 0x29f988, - 0x2521c5, - 0x668c84, - 0x265444, - 0x2d6e44, - 0x218706, - 0x2a650e, - 0x23f147, - 0x21c345, - 0x2dec0c, - 0x310b07, - 0x224d47, - 0x226fc9, - 0x219e49, - 0x285f85, - 0x330d08, - 0x2bd9c9, - 0x38ffc5, - 0x2ca448, - 0x2c0886, - 0x38f646, - 0x202c44, - 0x28ee48, - 0x21ba43, - 0x215604, - 0x270b45, - 0x396f07, - 0x2c2605, - 0x281bc9, - 0x2a118d, - 0x2b3046, - 0x3df784, - 0x3b9d08, - 0x20e7ca, - 0x21c847, - 0x367d45, - 0x215643, - 0x2a550e, - 0x3707cc, - 0x30b147, - 0x2a66c7, - 0x443960c7, - 0xaf286, - 0x647c4, - 0x203083, - 0x2f2fc5, - 0x2d6e45, - 0x2a0948, - 0x29dc09, - 0x22b186, - 0x277d04, - 0x2fce46, - 0x331bcb, - 0x2e844c, - 0x24df87, - 0x2de805, - 0x3a9f48, - 0x2ed3c5, - 0x2ccdc7, - 0x2f4cc7, - 0x245fc5, - 0x226043, - 0x20c584, - 0x2e4205, - 0x269e05, - 0x269e06, - 0x2a9dc8, - 0x224dc7, - 0x385206, - 0x33a686, - 0x362a86, - 0x225249, - 0x2d0f87, - 0x250f86, - 0x2e85c6, - 0x276d06, - 0x2b0ac5, - 0x20a586, - 0x39b0c5, - 0x28d808, - 0x29428b, - 0x28fb46, - 0x392c44, - 0x304e49, - 0x2a9fc4, - 0x2c0808, - 0x30e907, - 0x283ec4, - 0x2c5dc8, - 0x2cb5c4, - 0x2b0b04, - 0x274785, - 0x318886, - 0x36fac7, - 0x23db43, - 0x2a4d85, - 0x2fd1c4, - 0x23b406, - 0x33ba48, - 0x202705, - 0x293f49, - 0x350105, - 0x267788, - 0x21a4c7, - 0x32b1c8, - 0x2c5a07, - 0x241889, - 0x280886, - 0x33e906, - 0x2a78c4, - 0x355e85, - 0x31320c, - 0x279487, - 0x279c87, - 0x361708, - 0x2b3046, - 0x2a7004, - 0x34b0c4, - 0x389409, - 0x2d5786, - 0x270507, - 0x2d0804, - 0x326b06, - 0x38a805, - 0x2dc647, - 0x2de4c6, - 0x251249, - 0x2f0387, - 0x29bc87, - 0x2a8b46, - 0x326a45, - 0x27f408, - 0x21d988, - 0x245a06, - 0x202745, - 0x2cca86, - 0x20af03, - 0x2a07c9, - 0x2a4e4e, - 0x2c5748, - 0x371ec8, - 0x24580b, - 0x294186, - 0x385544, - 0x230644, - 0x2a4f4a, - 0x211987, - 0x251045, - 0x212849, - 0x2c9685, - 0x3cfc87, - 0x2305c4, - 0x3c7b07, - 0x318988, - 0x2d4906, - 0x2c0d09, - 0x2c6a0a, - 0x211906, - 0x29e6c6, - 0x2b39c5, - 0x398545, - 0x36ac07, - 0x245608, - 0x38a748, - 0x228dc6, - 0x35c985, - 0x36184e, - 0x2c70c4, - 0x245985, - 0x277489, - 0x2eab08, - 0x28e286, - 0x2a2acc, - 0x2a3990, - 0x2a614f, - 0x2a8148, - 0x350107, - 0x3c8785, - 0x292e05, - 0x36f949, - 0x292e09, - 0x2cfe06, - 0x2deac7, - 0x355d85, - 0x237c49, - 0x35e486, - 0x2f2dcd, - 0x27f589, - 0x281484, - 0x2c54c8, - 0x2327c9, - 0x3343c6, - 0x278a05, - 0x33e906, - 0x346c49, - 0x2d0688, - 0x206a05, - 0x281e04, - 0x2a2c8b, - 0x334285, - 0x246586, - 0x283246, - 0x3b4246, - 0x2875cb, - 0x294049, - 0x33a5c5, - 0x393807, - 0x2c1e86, - 0x231f46, - 0x281a88, - 0x224f09, - 0x37ed0c, - 0x37b108, - 0x31aac6, - 0x32dc83, - 0x22f306, - 0x241745, - 0x27e208, - 0x3d9d46, - 0x2dc888, - 0x380445, - 0x291805, - 0x21a608, - 0x3bba07, - 0x384e47, - 0x34c747, - 0x302a48, - 0x2d7848, - 0x2e9f06, - 0x2bcd87, - 0x21f707, - 0x2b3f4a, - 0x2168c3, - 0x203e06, - 0x22b3c5, - 0x213504, - 0x27ab89, - 0x241804, - 0x204844, - 0x2a4204, - 0x2a66cb, - 0x32b6c7, - 0x310645, - 0x29c3c8, - 0x277b06, - 0x277b08, - 0x27cb86, - 0x28ed85, - 0x28f045, - 0x290746, - 0x292408, - 0x292988, - 0x27ad46, - 0x29c20f, - 0x2a0290, - 0x3d0845, - 0x203d03, - 0x22c205, - 0x31bd08, - 0x292d09, - 0x390108, - 0x2de8c8, - 0x235288, - 0x32b787, - 0x2777c9, - 0x2dca88, - 0x291004, - 0x2a4088, - 0x35ab89, - 0x2bd387, - 0x34de44, - 0x2d0a88, - 0x2a934a, - 0x2fd446, - 0x2a6dc6, - 0x226089, - 0x2a3bc7, - 0x2d9c88, - 0x21fd08, - 0x33ad48, - 0x24ef85, - 0x3d3205, - 0x21c145, - 0x2d6e05, - 0x2bb447, - 0x226045, - 0x2ca505, - 0x3dde06, - 0x390047, - 0x3a3407, - 0x2a9646, - 0x2e0285, - 0x246586, - 0x241985, - 0x2c4d88, - 0x355d04, - 0x2d3e86, - 0x324604, - 0x2c5bc8, - 0x318c0a, - 0x27b4cc, - 0x23aa05, - 0x21c206, - 0x37eec6, - 0x202586, - 0x31ab44, - 0x3b9a05, - 0x27c447, - 0x2a3c49, - 0x2d9307, - 0x668c84, - 0x668c84, - 0x32b545, - 0x2dda04, - 0x2a204a, - 0x277986, - 0x2bd7c4, - 0x3c2d85, - 0x3bd405, - 0x2bc5c4, - 0x282e87, - 0x3c3a87, - 0x2d8ec8, - 0x26d5c8, - 0x206a09, - 0x372488, - 0x2a220b, - 0x2acc44, - 0x232045, - 0x3897c5, - 0x34c6c9, - 0x224f09, - 0x304d48, - 0x34cc48, - 0x288484, - 0x285745, - 0x2041c3, - 0x2d7705, - 0x29ee86, - 0x29da4c, - 0x20c006, - 0x278906, - 0x28e505, - 0x310708, - 0x2e86c6, - 0x357fc6, - 0x2a6dc6, - 0x22bbcc, - 0x389884, - 0x362bca, - 0x28e448, - 0x29d887, - 0x2fd0c6, - 0x22b247, - 0x2fca45, - 0x367a06, - 0x35ee86, - 0x372987, - 0x2c6704, - 0x210ac5, - 0x277484, - 0x2baf87, - 0x2776c8, - 0x27828a, - 0x280b87, - 0x2aa847, - 0x350087, - 0x2ed509, - 0x29da4a, - 0x22c103, - 0x357285, - 0x212ec3, - 0x2bb909, - 0x2d7c08, - 0x372247, - 0x390209, - 0x21da86, - 0x339f88, - 0x395385, - 0x24694a, - 0x343809, - 0x370209, - 0x3db607, - 0x2ea109, - 0x212d88, - 0x288d86, - 0x21c3c8, - 0x2d1f47, - 0x264187, - 0x3db9c7, - 0x2daf48, - 0x30aac6, - 0x2a9105, - 0x27c447, - 0x29e1c8, - 0x362a04, - 0x306044, - 0x293407, - 0x2b5647, - 0x2bd84a, - 0x288d06, - 0x32eeca, - 0x2c9ac7, - 0x2c6e87, - 0x210b84, - 0x29d444, - 0x2dc546, - 0x35c184, - 0x35c18c, - 0x30e845, - 0x2172c9, - 0x2ef004, - 0x2bc685, - 0x20e748, - 0x292a45, - 0x391106, - 0x292f44, - 0x2acb4a, - 0x2ef646, - 0x255fca, - 0x3d0007, - 0x215f85, - 0x22a305, - 0x24424a, - 0x292585, - 0x2a6cc6, - 0x241084, - 0x2ba346, - 0x36acc5, - 0x3d9e06, - 0x2ff98c, - 0x2e18ca, - 0x291bc4, - 0x245806, - 0x2a3bc7, - 0x2de444, - 0x307588, - 0x24c286, - 0x392a89, - 0x2c8349, - 0x341189, - 0x2d9606, - 0x2d2046, - 0x21c507, - 0x32ae08, - 0x2d1e49, - 0x32b6c7, - 0x29c546, - 0x26c347, - 0x237605, - 0x2c70c4, - 0x21c0c7, - 0x21f8c5, - 0x28a2c5, - 0x200cc7, - 0x245e88, - 0x3a9ec6, - 0x29f00d, - 0x2a0b4f, - 0x2a534d, - 0x202d84, - 0x233e86, - 0x2e1c88, - 0x33d345, - 0x2b4108, - 0x252f0a, - 0x281484, - 0x331e06, - 0x2abe07, - 0x2b7d47, - 0x2da209, - 0x21c385, - 0x2bc5c4, - 0x2be14a, - 0x2c64c9, - 0x2ea207, - 0x30b706, - 0x3343c6, - 0x285686, - 0x381886, - 0x2e158f, - 0x2e1b49, - 0x202806, - 0x389046, - 0x297e89, - 0x2bce87, - 0x2146c3, - 0x22bd46, - 0x212503, - 0x31e448, - 0x26c187, - 0x2a8349, - 0x2bf588, - 0x384f88, - 0x33c506, - 0x20bf49, - 0x2f4e05, - 0x22f244, - 0x312847, - 0x38cf05, - 0x202d84, - 0x361b48, - 0x211c44, - 0x2bcbc7, - 0x36c106, - 0x263645, - 0x2b23c8, - 0x33428b, - 0x331207, - 0x2444c6, - 0x2d4e84, - 0x3854c6, - 0x26a705, - 0x21f8c5, - 0x27f189, - 0x282a89, - 0x2641c4, - 0x264205, - 0x245845, - 0x2467c6, - 0x330e08, - 0x2c8e86, - 0x20cecb, - 0x3bc9ca, - 0x2c5b05, - 0x28f0c6, - 0x23eb85, - 0x24a285, - 0x292647, - 0x204088, - 0x292484, - 0x37fb46, - 0x292a06, - 0x212f47, - 0x31f1c4, - 0x27d886, - 0x3c2245, - 0x3c2249, - 0x2d2244, - 0x36cac9, - 0x27ad46, - 0x2cac48, - 0x245845, - 0x392d05, - 0x3d9e06, - 0x37ec09, - 0x219e49, - 0x278986, - 0x2eac08, - 0x2a12c8, - 0x23eb44, - 0x2be9c4, - 0x2be9c8, - 0x3b2b88, - 0x356689, - 0x29ee06, - 0x2a6dc6, - 0x33384d, - 0x3ae006, - 0x3218c9, - 0x268945, - 0x214e06, - 0x33aec8, - 0x32f985, - 0x21f744, - 0x26a705, - 0x2825c8, - 0x2a1e09, - 0x277544, - 0x2c0b86, - 0x30cb4a, - 0x30b048, - 0x2bd9c9, - 0x26ad4a, - 0x390186, - 0x2a0d08, - 0x2ccb85, - 0x2f0988, - 0x2fcac5, - 0x21d949, - 0x336449, - 0x20c642, - 0x2c5345, - 0x272346, - 0x27ac87, - 0x213505, - 0x3469c6, - 0x316908, - 0x2b3046, - 0x2c7489, - 0x279d86, - 0x281908, - 0x278d45, - 0x38e4c6, - 0x3037c8, - 0x281788, - 0x357c08, - 0x318488, - 0x20a584, - 0x20c243, - 0x2c76c4, - 0x280d86, - 0x237644, - 0x371e07, - 0x357ec9, - 0x2d4445, - 0x21fd06, - 0x22bd46, - 0x2a9c0b, - 0x2bc046, - 0x298d46, - 0x2d3f88, - 0x264a46, - 0x215d83, - 0x208503, - 0x2c70c4, - 0x22f545, - 0x244847, - 0x2776c8, - 0x2776cf, - 0x27c34b, - 0x330c08, - 0x2c0c06, - 0x330f0e, - 0x23b443, - 0x2447c4, - 0x2bbfc5, - 0x2bc446, - 0x28ff0b, - 0x294a86, - 0x221089, - 0x263645, - 0x23da88, - 0x3d29c8, - 0x219d0c, - 0x2a6706, - 0x2d7746, - 0x2e2d45, - 0x28ad88, - 0x27b4c5, - 0x34f108, - 0x2a2e4a, - 0x2a5789, - 0x668c84, - 0x2000c2, - 0x4a201242, - 0x200382, - 0x221dc4, - 0x209e82, - 0x306c44, - 0x208482, - 0x3dc3, - 0x2003c2, - 0x2090c2, - 0x9a048, - 0x29904, - 0x214a83, - 0x232dc3, - 0x308003, - 0xccc2, - 0x49582, - 0x23c803, - 0x21a3c3, - 0x242543, - 0xc782, - 0xc2c2, - 0x1b82, - 0x202703, - 0x214a83, - 0x232dc3, - 0x308003, - 0x221dc4, - 0x21a3c3, - 0x242543, - 0x241f83, - 0x2d3684, - 0x214a83, - 0x235b44, - 0x232dc3, - 0x2e3504, - 0x308003, - 0x2137c7, - 0x23c803, - 0x203dc3, - 0x31bf88, - 0x242543, - 0x27cfcb, - 0x2fdbc3, - 0x2431c6, - 0x233442, - 0x2f850b, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x214a83, - 0x232dc3, - 0x308003, - 0x242543, - 0x21a103, - 0x208a03, - 0x2000c2, - 0x9a048, - 0x399c45, - 0x21f948, - 0x2e3648, - 0x201242, - 0x343045, - 0x3c8847, - 0x203c42, - 0x242a07, - 0x200382, - 0x2555c7, - 0x3742c9, - 0x26d188, - 0x33abc9, - 0x20b342, - 0x3c7387, - 0x22dd84, - 0x3c8907, - 0x3bc8c7, - 0x25ac42, - 0x23c803, - 0x202382, - 0x208482, - 0x2003c2, - 0x214282, - 0x200902, - 0x2090c2, - 0x2df885, - 0x210205, - 0x1242, - 0x32dc3, - 0x214a83, - 0x232dc3, - 0x29a643, - 0x308003, - 0x206c03, - 0x21a3c3, - 0x242543, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x1b4103, - 0x242543, - 0xa983, - 0x101, - 0x214a83, - 0x232dc3, - 0x308003, - 0x221dc4, - 0x21bc83, - 0x21a3c3, - 0x1b4103, - 0x242543, - 0x214903, - 0x4d4ae8c6, - 0x239c3, - 0xd50c5, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x201242, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x1b4103, - 0x242543, - 0x1b02, - 0x9a048, - 0x12a4c3, - 0x3dc3, - 0x1b4103, - 0x455c4, - 0x14226c4, - 0xed7c5, - 0x2000c2, - 0x393bc4, - 0x214a83, - 0x232dc3, - 0x308003, - 0x231a43, + 0x466a3e85, + 0x46a15cc4, + 0x46faaa07, + 0x4723c0c7, + 0x4768aac6, + 0x47a86b45, + 0x47e9ea47, + 0x482dd548, + 0x487da407, + 0x48adcb49, + 0x48ed9845, + 0x4931d047, + 0x49697b86, + 0x27c4b, + 0x49b47b08, + 0x22800d, + 0x25c089, + 0x279d4b, + 0x27b8cb, + 0x2afecb, + 0x39b08b, + 0x325f8b, + 0x32624b, + 0x326709, + 0x32770b, + 0x3279cb, + 0x32850b, + 0x32910a, + 0x32964a, + 0x329c4c, + 0x32e6cb, + 0x32ec0a, + 0x34228a, + 0x34d34e, + 0x34e94e, + 0x34ecca, + 0x350b0a, + 0x351b4b, + 0x351e0b, + 0x35290b, + 0x372ecb, + 0x3734ca, + 0x37418b, + 0x37444a, + 0x3746ca, + 0x37494a, + 0x394a0b, + 0x39bbcb, + 0x39ed4e, + 0x39f0cb, + 0x3a65cb, + 0x3a73cb, + 0x3ab74a, + 0x3ab9c9, + 0x3abc0a, + 0x3ad9ca, + 0x3c514b, + 0x3d00cb, + 0x3d0aca, + 0x3d170b, + 0x3d7a4b, + 0x3e07cb, + 0x49e89188, + 0x4a290209, + 0x4a6a7249, + 0x4aaefcc8, + 0x35f145, + 0x204083, + 0x251f44, + 0x34e385, + 0x34d7c6, + 0x367645, + 0x28f384, + 0x3450c8, + 0x31f645, + 0x299784, + 0x203787, + 0x2a634a, + 0x37738a, + 0x365607, + 0x26b0c7, + 0x2e7ec7, + 0x288047, + 0x33a405, + 0x20e506, + 0x2f34c7, + 0x20fd84, + 0x3ba146, + 0x3ba046, + 0x3dccc5, + 0x389dc4, + 0x29ffc6, + 0x2a5407, + 0x2671c6, + 0x31a487, + 0x235e43, + 0x3a2246, + 0x238d85, + 0x287b87, + 0x26fe0a, + 0x237784, + 0x2219c8, + 0x39a2c9, + 0x2d6b87, + 0x3bba06, + 0x203f48, + 0x2f4989, + 0x3a2084, + 0x2d2a04, + 0x313005, + 0x21e388, + 0x2d6e47, + 0x2b7689, + 0x3690c8, + 0x31b8c6, + 0x266cc6, + 0x2a0b88, + 0x371c86, + 0x25ef05, + 0x28ab86, + 0x281f48, + 0x2870c6, + 0x255f0b, + 0x2be206, + 0x2a280d, + 0x205385, + 0x2b4286, + 0x21f585, + 0x2bc949, + 0x2e0cc7, + 0x3cd248, + 0x39dec6, + 0x2a1949, + 0x2c1246, + 0x26fd85, + 0x2a9606, + 0x2d5506, + 0x2db549, + 0x2c8186, + 0x2a6047, + 0x2d5bc5, + 0x208a43, 0x22d805, - 0x21bc83, - 0x21a8c3, - 0x21a3c3, - 0x24e283, - 0x242543, - 0x20e2c3, - 0x266603, - 0x207783, - 0x5c2, - 0x2aec2, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x2000c2, - 0x202703, - 0x201242, - 0x2a42, - 0x232dc3, - 0x308003, - 0x221dc4, - 0x21a3c3, - 0x242543, - 0x2090c2, - 0x9a048, - 0x308003, - 0x1b4103, - 0x9a048, - 0x1b4103, - 0x26f6c3, - 0x214a83, - 0x22fe44, - 0x232dc3, - 0x308003, - 0x206182, - 0x23c803, - 0x21a3c3, - 0x3dc3, - 0x242543, - 0x214a83, - 0x232dc3, - 0x308003, - 0x206182, - 0x2137c3, - 0x21a3c3, - 0x242543, - 0x2f7103, - 0x20e2c3, - 0x2000c2, - 0x201242, - 0x308003, - 0x21a3c3, - 0x242543, - 0x2431c5, - 0x14fc86, - 0x2d3684, - 0x233442, - 0x882, - 0x9a048, - 0x2a42, - 0x49582, - 0x2982, - 0x2000c2, - 0x139b05, - 0x1ce08, - 0x991c3, - 0x201242, - 0x3c604, - 0x51c6c486, - 0x8d04, - 0x10fe4b, - 0x34ac6, - 0xd1407, - 0x12eb09, - 0x232dc3, - 0x48248, - 0x4824b, - 0x486cb, - 0x48d4b, - 0x4908b, - 0x4934b, - 0x4978b, - 0x1d2f06, - 0x308003, - 0xf3605, - 0x68a44, - 0x210983, - 0x1182c7, - 0xe6d44, - 0x6cbc4, - 0x21a3c3, - 0x78a86, - 0x5684, - 0x1b4103, - 0x242543, - 0x2fe7c4, - 0x12bcc7, - 0x14f889, - 0x10fc08, - 0x1b44c4, - 0x1c8a44, - 0x365c6, - 0xa788, - 0x16a605, - 0x8649, - 0x2fb03, - 0x139b05, - 0x201242, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x203dc3, - 0x242543, - 0x2fdbc3, - 0x233442, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21bac3, - 0x219a04, - 0x21a3c3, - 0x3dc3, - 0x242543, - 0x214a83, - 0x232dc3, - 0x2e3504, - 0x308003, - 0x21a3c3, - 0x242543, - 0x2431c6, - 0x232dc3, - 0x308003, - 0x10e83, - 0x1b4103, - 0x242543, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x139b05, - 0xd1407, - 0x3103, - 0x2fb03, - 0x9a048, - 0x308003, - 0x214a83, - 0x232dc3, - 0x308003, - 0x5cf43, - 0x21a3c3, - 0x242543, - 0x55214a83, - 0x232dc3, - 0x21a3c3, - 0x242543, - 0x9a048, - 0x2000c2, - 0x201242, - 0x214a83, - 0x308003, - 0x21a3c3, - 0x2003c2, - 0x242543, - 0x336987, - 0x2cd68b, - 0x20dcc3, - 0x2cfac8, - 0x32ab87, - 0x3de706, - 0x218c05, - 0x343189, - 0x242f48, - 0x3359c9, - 0x3359d0, - 0x37ab8b, - 0x2e7589, - 0x203103, - 0x2f8bc9, - 0x231506, - 0x23150c, - 0x335bc8, - 0x3db448, - 0x374789, - 0x2c368e, - 0x37408b, - 0x2ba58c, - 0x220dc3, - 0x28c68c, - 0x3d8f49, - 0x23bb47, - 0x232d0c, - 0x2b858a, - 0x24c0c4, - 0x2ee78d, - 0x28c548, - 0x3ba7cd, - 0x3a6cc6, - 0x2d368b, - 0x34fa09, - 0x3892c7, - 0x295946, - 0x267b49, - 0x33b64a, - 0x30c108, - 0x2fd7c4, - 0x2b5a07, - 0x3c51c7, - 0x204684, - 0x223804, - 0x201fc9, - 0x286ac9, - 0x3d9ac8, - 0x398bc5, - 0x20b285, - 0x2068c6, - 0x2ee649, - 0x25318d, - 0x24c488, - 0x2067c7, - 0x218c88, - 0x2355c6, - 0x239c04, - 0x284405, - 0x3cfb46, - 0x3d1e84, - 0x3d8e47, - 0x3e094a, - 0x20d384, - 0x211846, - 0x2124c9, - 0x2124cf, - 0x212a8d, - 0x213306, - 0x21ca10, - 0x21ce06, - 0x21df07, - 0x21e987, - 0x21e98f, - 0x21f1c9, - 0x225986, - 0x227207, - 0x227208, - 0x2275c9, - 0x3ba588, - 0x305c87, - 0x20ed43, - 0x3d87c6, - 0x29d1c8, - 0x2c394a, - 0x215849, - 0x243083, - 0x342f46, - 0x37f98a, - 0x2f9f87, - 0x23b98a, - 0x31458e, - 0x21f306, - 0x338547, - 0x238886, - 0x2435c6, - 0x3d300b, - 0x39964a, - 0x2cdccd, - 0x2d2107, - 0x266688, - 0x266689, - 0x26668f, - 0x3070cc, - 0x34b789, - 0x27e48e, - 0x2138ca, - 0x216406, - 0x2f4806, - 0x3adc8c, - 0x31fdcc, - 0x320308, - 0x35a487, - 0x235185, - 0x3c8ac4, - 0x28918e, - 0x3a6744, - 0x201247, - 0x39dcca, - 0x3ab1d4, - 0x3d548f, - 0x21eb48, - 0x3d8688, - 0x378c8d, - 0x378c8e, - 0x22cd09, - 0x22e548, - 0x22e54f, - 0x232a0c, - 0x232a0f, - 0x233bc7, - 0x23714a, - 0x3087cb, - 0x239808, - 0x23b107, - 0x25c7cd, - 0x3620c6, - 0x2ee946, - 0x23d449, - 0x22ba08, - 0x2433c8, - 0x2433ce, - 0x2b7687, - 0x3043c5, - 0x245385, - 0x202404, - 0x3de9c6, - 0x3d99c8, - 0x296d83, - 0x2e710e, - 0x25cb88, - 0x2aae8b, - 0x26f887, - 0x228c05, - 0x273506, - 0x2b2b07, - 0x31b348, - 0x36a409, - 0x3cd545, - 0x285c48, - 0x2209c6, - 0x3a618a, - 0x289089, - 0x232dc9, - 0x232dcb, - 0x25d908, - 0x204549, - 0x398c86, - 0x3c5a8a, - 0x2bfe4a, - 0x23734c, - 0x3488c7, - 0x26cf8a, - 0x3b1fcb, - 0x3b1fd9, - 0x324208, - 0x243245, - 0x25c986, - 0x2a0049, - 0x39f606, - 0x219aca, - 0x26e286, - 0x2196c4, - 0x2d604d, - 0x3458c7, - 0x2196c9, - 0x247105, - 0x247ac8, - 0x248009, - 0x24b904, - 0x24bfc7, - 0x24bfc8, - 0x24cc87, - 0x265c08, - 0x250dc7, - 0x2d8b85, - 0x257e8c, - 0x258349, - 0x33144a, - 0x3a8e89, - 0x2f8cc9, - 0x388e0c, - 0x25b4cb, - 0x25c008, - 0x25d0c8, - 0x260cc4, - 0x283b88, - 0x284d09, - 0x2b8647, - 0x212706, - 0x2a43c7, - 0x29fd49, - 0x24768b, - 0x36aa87, - 0x2947c7, - 0x3d0147, - 0x3ba744, - 0x3ba745, - 0x2e3205, - 0x358b4b, - 0x33d684, - 0x323a88, - 0x30060a, - 0x220a87, - 0x3caac7, - 0x28f6d2, - 0x291646, - 0x22f7c6, - 0x28870e, - 0x29ab46, - 0x299288, - 0x29a60f, - 0x3bab88, - 0x28a808, - 0x2dd1ca, - 0x2dd1d1, - 0x2a98ce, - 0x25514a, - 0x25514c, - 0x22e747, - 0x22e750, - 0x3c7108, - 0x2a9ac5, - 0x2b2e0a, - 0x3d1ecc, - 0x29c88d, - 0x3c7c86, - 0x3c7c87, - 0x3c7c8c, - 0x3d2b8c, - 0x21bc8c, - 0x3bd6cb, - 0x38b644, - 0x226204, - 0x2b6f89, - 0x34b147, - 0x37d009, - 0x2bfc89, - 0x2b8247, - 0x2b8406, - 0x2b8409, - 0x2b8803, - 0x2b314a, - 0x2961c7, - 0x3c8e0b, - 0x2cdb4a, - 0x22de04, - 0x32f4c6, - 0x280e09, - 0x35c004, - 0x2df48a, - 0x2e0685, - 0x2c7945, - 0x2c794d, - 0x2c7c8e, - 0x2c7805, - 0x335046, - 0x242dc7, - 0x22b78a, - 0x3a6a46, - 0x37bc84, - 0x3cdb87, - 0x2fab0b, - 0x265907, - 0x262944, - 0x3a39c6, - 0x3a39cd, - 0x2e568c, - 0x21a286, - 0x24c68a, - 0x34ca86, - 0x21e648, - 0x30c487, - 0x2d3b8a, - 0x23c486, - 0x27d903, - 0x2f3886, - 0x29d048, - 0x245aca, - 0x2dcc07, - 0x2dcc08, - 0x249ac4, - 0x28fc47, - 0x2f4348, - 0x291848, - 0x2bbdc8, - 0x2ffc0a, - 0x2ec0c5, - 0x2c1ac7, - 0x254f93, - 0x26b2c6, - 0x24aec8, - 0x221589, - 0x2428c8, - 0x33c58b, - 0x385308, - 0x2c02c4, - 0x21a706, - 0x320c06, - 0x3186c9, - 0x2d39c7, - 0x257f88, - 0x2a51c6, - 0x200bc4, - 0x208405, - 0x3a3188, - 0x344e4a, - 0x2d5cc8, - 0x2dad46, - 0x2a0f0a, - 0x269f88, - 0x2de248, - 0x2df708, - 0x2dff46, - 0x2e1e86, - 0x3a4d0c, - 0x2e2410, - 0x2cc145, - 0x2230c8, - 0x2230d0, - 0x3ba990, - 0x33584e, - 0x3a498e, - 0x3a4994, - 0x3a804f, - 0x3a8406, - 0x3dbe51, - 0x345213, - 0x345688, - 0x2035c5, - 0x2d0008, - 0x3a05c5, - 0x33f34c, - 0x229f09, - 0x3a6589, - 0x356947, - 0x26c649, - 0x39f1c7, - 0x334686, - 0x284207, - 0x204c05, - 0x20a9c3, - 0x210e83, - 0x213404, - 0x36adcd, - 0x3c304f, - 0x200c05, - 0x33f246, - 0x20cb87, - 0x399a87, - 0x208886, - 0x20888b, - 0x2aa785, - 0x259fc6, - 0x30be47, - 0x251ac9, - 0x229b46, - 0x3860c5, - 0x3c910b, - 0x3d6e86, - 0x21d685, - 0x241588, - 0x290b08, - 0x299b8c, - 0x299b90, - 0x2ac2c9, - 0x2c15c7, - 0x2b918b, + 0x395c07, + 0x25fac6, + 0x205289, + 0x33ed86, + 0x281686, + 0x226049, + 0x28a589, + 0x2aa947, + 0x207648, + 0x29b149, + 0x288608, + 0x3a7646, + 0x2e5285, + 0x27dd4a, + 0x281706, + 0x347446, + 0x2deb05, + 0x253708, + 0x2f5707, + 0x23114a, + 0x24df06, + 0x2e2785, + 0x3086c6, + 0x20d647, + 0x3bb8c7, + 0x21a3c5, + 0x26ff45, + 0x26c506, + 0x273b06, + 0x2b0d46, + 0x2ccc44, + 0x289b09, + 0x291a06, + 0x306f0a, + 0x30c148, + 0x31cd48, + 0x37738a, + 0x2ef805, + 0x2a5345, + 0x3cac88, + 0x2c7e88, + 0x2398c7, + 0x36ee86, + 0x339788, + 0x20ee87, + 0x27a408, + 0x2c6806, + 0x28bac8, + 0x29de06, + 0x283847, + 0x23b3c6, + 0x29ffc6, + 0x27438a, + 0x305f86, + 0x2e5289, + 0x2a7746, + 0x22910a, + 0x2463c9, + 0x2fd9c6, + 0x2c9144, + 0x2d274d, + 0x285e07, + 0x3325c6, + 0x2d0185, + 0x2c12c5, + 0x396906, + 0x2a9b89, + 0x2c09c7, + 0x282946, + 0x2ced06, + 0x28f409, + 0x288d84, + 0x23f644, + 0x3b53c8, + 0x237ac6, + 0x2a9708, + 0x322708, + 0x3a9f87, + 0x358b89, + 0x3c9f87, + 0x2bffca, + 0x2fee8f, + 0x2b230a, + 0x3e22c5, + 0x282185, + 0x21c3c5, + 0x229747, + 0x20d203, + 0x207848, + 0x355606, + 0x355709, + 0x2f3dc6, + 0x2db387, + 0x2a1709, + 0x3cd148, + 0x2debc7, + 0x325343, + 0x35f1c5, + 0x20d185, + 0x2cca8b, + 0x248a44, + 0x238344, + 0x27d506, + 0x325507, + 0x396e8a, + 0x24bd87, + 0x298787, + 0x285fc5, + 0x3d5c05, + 0x296ac9, + 0x29ffc6, + 0x24bc0d, + 0x273445, + 0x2c3c03, + 0x2059c3, + 0x3617c5, + 0x33a085, + 0x203f48, + 0x283287, + 0x23f3c6, + 0x2a6ec6, + 0x22bbc5, + 0x234287, + 0x25eb47, + 0x252287, + 0x2ad78a, + 0x3a2308, + 0x2ccc44, + 0x286e47, + 0x285187, + 0x363306, + 0x29d487, + 0x2ebd88, + 0x3d8348, + 0x29c3c6, + 0x26b308, + 0x2c8204, + 0x2f34c6, + 0x250dc6, + 0x3d5486, + 0x208006, + 0x218e84, + 0x288106, + 0x2cf246, + 0x2a0386, + 0x24bc06, + 0x205886, + 0x2a7e46, + 0x23f2c8, + 0x2c2a48, + 0x2e1e88, + 0x367848, + 0x3cac06, + 0x210ec5, + 0x22d7c6, + 0x2b8845, + 0x399107, + 0x295d45, + 0x2119c3, + 0x2e5f45, + 0x235fc4, + 0x2059c5, + 0x202a43, + 0x3c4bc7, + 0x399d08, + 0x31a546, + 0x34490d, + 0x282146, + 0x29f945, + 0x219643, + 0x2cc149, + 0x288f06, + 0x23b1c6, + 0x3b2144, + 0x2b2287, + 0x3611c6, + 0x23f845, + 0x270483, + 0x20b344, + 0x285346, + 0x20e604, + 0x275548, + 0x204609, + 0x32e489, + 0x2a950a, + 0x29738d, + 0x23e587, + 0x3c2cc6, + 0x21dd04, + 0x287dc9, + 0x28e308, + 0x290086, + 0x23abc6, + 0x29d487, + 0x2c98c6, + 0x226c46, + 0x25dfc6, + 0x3da10a, + 0x223708, + 0x2ef705, + 0x356c09, + 0x2d75ca, + 0x30cd48, + 0x2a46c8, + 0x299fc8, + 0x2b45cc, + 0x395905, + 0x2a7148, + 0x2c2d46, + 0x2e1446, + 0x2d5707, + 0x24bc85, + 0x28ad05, + 0x32e349, + 0x214207, + 0x3556c5, + 0x2284c7, + 0x2059c3, + 0x2d7a85, + 0x224148, + 0x2d9047, + 0x2a4589, + 0x2e5145, + 0x311404, + 0x2ab1c8, + 0x2eed47, + 0x2ded88, + 0x2206c8, + 0x2b5285, + 0x21f746, + 0x2a6fc6, + 0x3c2909, + 0x250ec7, + 0x2b8cc6, + 0x355347, + 0x208683, + 0x34da84, + 0x2dc405, + 0x2343c4, + 0x24b684, + 0x38fc47, + 0x26da47, + 0x282b04, + 0x2a43d0, + 0x207bc7, + 0x3d5c05, + 0x3b3c8c, + 0x220484, + 0x31e048, + 0x283749, + 0x3d78c6, + 0x31fc48, + 0x27d804, + 0x27d808, + 0x231746, + 0x274208, + 0x2a38c6, + 0x39b90b, + 0x330685, + 0x2dc288, + 0x213684, + 0x28988a, + 0x2a4589, + 0x23b2c6, + 0x2c2f48, + 0x2592c5, + 0x2cb744, + 0x31df46, + 0x252148, + 0x289188, + 0x333e86, + 0x389f44, + 0x27dcc6, + 0x3ca007, + 0x281387, + 0x29d48f, + 0x346f07, + 0x2fda87, + 0x388ac5, + 0x377ac5, + 0x2aa609, + 0x2f7786, + 0x38fe85, + 0x28a887, + 0x2d5988, + 0x302545, + 0x23b3c6, + 0x30bf88, + 0x2f424a, + 0x37e648, + 0x293287, + 0x2ff2c6, + 0x356bc6, + 0x2003c3, + 0x20c483, + 0x2d7789, + 0x29afc9, + 0x2dca46, + 0x2e5145, + 0x2b4448, + 0x2c2f48, + 0x2a3508, + 0x25e04b, + 0x344b47, + 0x3211c9, + 0x29d708, + 0x3505c4, + 0x3d50c8, + 0x295909, + 0x2b8fc5, + 0x229647, + 0x34db05, + 0x289088, + 0x2983cb, + 0x29e790, + 0x2b3e05, + 0x2135cc, + 0x23f585, + 0x25e883, + 0x2b6486, + 0x2ce3c4, + 0x23b686, + 0x2a5407, + 0x203d44, + 0x243208, + 0x20770d, + 0x3224c5, + 0x23e5c4, + 0x2b5684, + 0x2b5689, + 0x2adfc8, + 0x330b47, + 0x2317c8, + 0x289bc8, + 0x282c45, + 0x27ee47, + 0x282bc7, + 0x3559c7, + 0x26ff49, + 0x25e649, + 0x210706, + 0x302d46, + 0x28a946, + 0x326e85, + 0x3c5d04, + 0x3cc9c6, + 0x3d4e86, + 0x282c88, + 0x20d30b, + 0x237647, + 0x21dd04, + 0x361106, + 0x2ec0c7, + 0x2a7a45, + 0x324a85, + 0x267c04, + 0x25e5c6, + 0x3cca48, + 0x287dc9, + 0x261846, + 0x28e108, + 0x23f906, + 0x365f48, + 0x37904c, + 0x282b06, + 0x29f60d, + 0x29fa8b, + 0x2a6105, + 0x25ec87, + 0x2c8286, + 0x3bb788, + 0x210789, + 0x38a7c8, + 0x3d5c05, + 0x20fac7, + 0x288708, + 0x3c7c49, + 0x360e46, + 0x26174a, + 0x3bb508, + 0x38a60b, + 0x22398c, + 0x27d908, + 0x284906, + 0x27e848, + 0x2f3ec7, + 0x347049, + 0x35150d, + 0x29fec6, + 0x30ef48, + 0x2c2909, + 0x2ccd48, + 0x28bbc8, + 0x2cfb4c, + 0x2d0807, + 0x2d31c7, + 0x26fd85, + 0x2c54c7, + 0x2d5848, + 0x31dfc6, + 0x2704cc, + 0x301fc8, + 0x2dd8c8, + 0x23ae06, + 0x2b1f07, + 0x210904, + 0x367848, + 0x28d20c, + 0x29144c, + 0x3e2345, + 0x3dcd47, + 0x389ec6, + 0x2b1e86, + 0x2bcb08, + 0x21b284, + 0x2671cb, + 0x28d94b, + 0x2ff2c6, + 0x207587, + 0x3572c5, + 0x2781c5, + 0x267306, + 0x259285, + 0x248a05, + 0x2d65c7, + 0x2b2789, + 0x273cc4, + 0x23d405, + 0x2f8ac5, + 0x358908, + 0x2bf505, + 0x2d1d09, + 0x39e2c7, + 0x39e2cb, + 0x2fd706, + 0x23f009, + 0x389d08, + 0x3ae7c5, + 0x355ac8, + 0x25e688, + 0x286407, + 0x2b5a87, + 0x38fcc9, + 0x274147, + 0x295c49, + 0x2d11cc, + 0x2dca48, + 0x2c0dc9, + 0x2c4d07, + 0x289c89, + 0x367207, + 0x223a88, + 0x358d45, + 0x2f3446, + 0x2d01c8, + 0x21c488, + 0x2d7489, + 0x248a47, + 0x278bc5, + 0x3cde49, + 0x2fde86, + 0x297b84, + 0x33ff06, + 0x26ad88, + 0x2e6587, + 0x20d508, + 0x26b3c9, + 0x3a1a87, + 0x2a3646, + 0x25ed44, + 0x2e5fc9, + 0x27ecc8, + 0x23acc7, + 0x2702c6, + 0x20d246, + 0x3473c4, + 0x26b5c6, + 0x205943, + 0x330209, + 0x330646, + 0x2a4905, + 0x2a6ec6, + 0x2db905, + 0x288b88, + 0x33f3c7, + 0x23bb46, + 0x25de86, + 0x31cd48, + 0x2aa787, + 0x29ff05, + 0x2a41c8, + 0x3b1b88, + 0x3bb508, + 0x23f445, + 0x2f34c6, + 0x32e249, + 0x3c2784, + 0x2db78b, + 0x22694b, + 0x2ef609, + 0x2059c3, + 0x257b05, + 0x2ef4c6, + 0x241f88, + 0x30a604, + 0x31a546, + 0x2ad8c9, + 0x2ce1c5, + 0x2d6506, + 0x2eed46, + 0x203f44, + 0x29a14a, + 0x2a4848, + 0x21c486, + 0x375c45, + 0x357147, + 0x33a2c7, + 0x21f744, + 0x226b87, + 0x2bffc4, + 0x369146, + 0x207883, + 0x26ff45, + 0x2ba485, + 0x25b688, + 0x287005, + 0x282849, + 0x2abc07, + 0x36768b, + 0x2abc0c, + 0x2ac20a, + 0x3513c7, + 0x203843, + 0x280d88, + 0x23f605, + 0x3025c5, + 0x35f284, + 0x223986, + 0x283746, + 0x26b607, + 0x3a9d8b, + 0x218e84, + 0x309d04, + 0x2d6784, + 0x2db206, + 0x203d44, + 0x21e488, + 0x35f085, + 0x21a245, + 0x2a3447, + 0x25ed89, + 0x33a085, + 0x39690a, + 0x2d5ac9, + 0x2aceca, + 0x3da249, + 0x354004, + 0x2cedc5, + 0x2c99c8, + 0x3aaacb, + 0x313005, + 0x2ecd46, + 0x241c04, + 0x282d86, + 0x3a1909, + 0x2ec1c7, + 0x33ef48, + 0x297706, + 0x3c9f87, + 0x289188, + 0x37c006, + 0x3d5e84, + 0x386b47, + 0x388705, + 0x398187, + 0x29f484, 0x2c8206, - 0x305b4a, - 0x36ff8b, - 0x31b58a, - 0x398806, - 0x2f6fc5, - 0x32aa86, - 0x279f48, - 0x356a0a, - 0x37891c, - 0x2fdc8c, - 0x2fdf88, - 0x2431c5, - 0x382747, - 0x24a006, - 0x24aac5, - 0x2177c6, - 0x208a48, - 0x2c6747, - 0x2c3588, - 0x26b38a, - 0x3b954c, - 0x297009, - 0x3b97c7, - 0x285244, - 0x245446, - 0x28a38a, - 0x2bfd85, - 0x22348c, - 0x223b48, - 0x26a208, - 0x2aebcc, - 0x38878c, - 0x22d949, - 0x22db87, - 0x25494c, - 0x3082c4, - 0x3713ca, - 0x30de8c, - 0x24fdcb, - 0x25044b, - 0x252b06, - 0x256447, - 0x22e987, - 0x22e98f, - 0x30f351, - 0x2e8d92, - 0x258c0d, - 0x258c0e, - 0x258f4e, - 0x3a8208, - 0x3a8212, - 0x25be08, - 0x221bc7, - 0x24ec0a, - 0x2ac988, - 0x29ab05, - 0x2bb28a, - 0x21d187, - 0x2ef184, - 0x210883, - 0x236085, - 0x2dd447, - 0x30d3c7, - 0x29ca8e, - 0x352e8d, - 0x354009, - 0x302905, - 0x361043, - 0x34a886, - 0x25a5c5, - 0x2ab0c8, - 0x224249, - 0x25c9c5, - 0x25c9cf, - 0x2e0b07, - 0x218a85, - 0x27024a, - 0x3d0b06, - 0x312b09, - 0x381b4c, - 0x3ce889, - 0x2062c6, - 0x30040c, - 0x32dd86, - 0x30cfc8, - 0x3b1ec6, - 0x365486, - 0x2bc1c4, - 0x31d203, - 0x21124a, - 0x227e11, - 0x34b94a, - 0x23ea05, - 0x25b907, - 0x2559c7, - 0x2e6f04, - 0x2f444b, - 0x33aa48, - 0x2c55c6, - 0x361785, - 0x261f44, - 0x3828c9, - 0x2008c4, - 0x20e087, - 0x37a385, - 0x37a387, - 0x288945, - 0x3801c3, - 0x221a88, - 0x2d020a, - 0x23db43, - 0x399c8a, - 0x2a74c6, - 0x25c74f, - 0x2b7609, - 0x2e7090, - 0x305748, - 0x2db3c9, - 0x29df47, - 0x3a394f, - 0x3905c4, - 0x2e3584, - 0x203946, - 0x2344c6, - 0x2ef40a, - 0x254686, - 0x2b5e07, - 0x315048, - 0x315247, - 0x3166c7, - 0x31784a, - 0x316fcb, - 0x33bf85, - 0x2e89c8, - 0x201343, - 0x3bb3cc, - 0x3965cf, - 0x234f8d, - 0x258787, - 0x354149, - 0x357087, - 0x2401c8, - 0x3ab3cc, - 0x2c01c8, - 0x23e708, - 0x32c9ce, - 0x341b94, - 0x3420a4, - 0x36080a, - 0x37b90b, - 0x39f284, - 0x39f289, - 0x331e88, - 0x245d85, - 0x29688a, - 0x291087, - 0x2135c4, - 0x202703, - 0x214a83, - 0x235b44, - 0x232dc3, - 0x308003, - 0x221dc4, - 0x21bc83, - 0x23c803, - 0x2e2406, - 0x219a04, - 0x21a3c3, - 0x242543, - 0x2141c3, + 0x30ca48, + 0x29fc48, + 0x33dec7, + 0x3801c8, + 0x29dec5, + 0x205804, + 0x377288, + 0x3802c4, + 0x21c345, + 0x30cc44, + 0x20ef87, + 0x291ac7, + 0x289dc8, + 0x2def06, + 0x286f85, + 0x282648, + 0x37e848, + 0x2a9449, + 0x226c46, + 0x2311c8, + 0x28970a, + 0x2a7ac8, + 0x308c85, + 0x22d9c6, + 0x2a9a48, + 0x20fb8a, + 0x265587, + 0x28e745, + 0x297d88, + 0x2b3a44, + 0x253786, + 0x2d3548, + 0x205886, + 0x33aa08, + 0x2d9e07, + 0x203686, + 0x2c9144, + 0x26a4c7, + 0x2c3304, + 0x3a18c7, + 0x23b00d, + 0x239945, + 0x2d8e4b, + 0x2916c6, + 0x252f48, + 0x2431c4, + 0x3c0706, + 0x285346, + 0x27eb87, + 0x29f2cd, + 0x305587, + 0x2c3b48, + 0x28bd45, + 0x296c88, + 0x2d6dc6, + 0x29df48, + 0x38ecc6, + 0x3b3a07, + 0x28a149, + 0x35fe07, + 0x290348, + 0x34c1c5, + 0x22bc48, + 0x2b1dc5, + 0x2d6d05, + 0x37d145, + 0x24dc03, + 0x208084, + 0x297f85, + 0x3a9a89, + 0x36ec46, + 0x2ebe88, + 0x2eefc5, + 0x2c5387, + 0x2e0fca, + 0x2d6449, + 0x2d540a, + 0x2e1f08, + 0x22830c, + 0x28a90d, + 0x314e43, + 0x33a908, + 0x20b305, + 0x2f4006, + 0x3ccfc6, + 0x2d2405, + 0x355449, + 0x348ec5, + 0x282648, + 0x258946, + 0x370286, + 0x2ab089, + 0x3b0b47, + 0x298686, + 0x2e0f48, + 0x3d5388, + 0x2efec7, + 0x2cf3ce, + 0x2d7005, + 0x3c7b45, + 0x205788, + 0x36f947, + 0x20d282, + 0x2cf804, + 0x23b58a, + 0x23ad88, + 0x25e7c6, + 0x2a1848, + 0x2a6fc6, + 0x25f708, + 0x2b8cc8, + 0x30b3c4, + 0x2c5745, + 0x602284, + 0x602284, + 0x602284, + 0x207783, + 0x20d0c6, + 0x282b06, + 0x2a5dcc, + 0x202503, + 0x2d75c6, + 0x207844, + 0x288e88, + 0x2ad705, + 0x23b686, + 0x2cc888, + 0x2e3246, + 0x23bac6, + 0x203d48, + 0x2dc487, + 0x273f09, + 0x3df7ca, + 0x26dbc4, + 0x295d45, + 0x2b7645, + 0x2d9a86, + 0x23e5c6, + 0x2a5b46, + 0x3d3f06, + 0x274044, + 0x27404b, + 0x266cc4, + 0x23f185, + 0x2b7cc5, + 0x3aa046, + 0x209648, + 0x28a7c7, + 0x3305c4, + 0x213c03, + 0x2b3545, + 0x33fdc7, + 0x28a6cb, + 0x25b587, + 0x2cc788, + 0x2c5887, + 0x2715c6, + 0x25c348, + 0x2cad4b, + 0x34e2c6, + 0x214a09, + 0x2caec5, + 0x325343, + 0x2d6506, + 0x2d9d08, + 0x215203, + 0x2a11c3, + 0x289186, + 0x2a6fc6, + 0x379eca, + 0x284945, + 0x28518b, + 0x2a6e0b, + 0x2163c3, + 0x206743, + 0x2bff44, + 0x2e0e07, + 0x27d904, + 0x25ef44, + 0x2c2bc4, + 0x2a7dc8, + 0x375b88, + 0x20c409, + 0x2d98c8, + 0x37d3c7, + 0x24bc06, + 0x2ebacf, + 0x2d7146, + 0x2e15c4, + 0x3759ca, + 0x33fcc7, + 0x2c3406, + 0x297bc9, + 0x20c385, + 0x25b7c5, + 0x20c4c6, + 0x22bd83, + 0x2b3a89, + 0x223886, + 0x26b189, + 0x396e86, + 0x26ff45, + 0x361bc5, + 0x206643, + 0x3131c8, + 0x330d07, + 0x355604, + 0x288d08, + 0x2e11c4, + 0x31c046, + 0x2b6486, + 0x23d846, + 0x2dc149, + 0x302545, + 0x29ffc6, + 0x277389, + 0x2d6146, + 0x2a7e46, + 0x3a8b46, + 0x22e405, + 0x30cc46, + 0x3b3a04, + 0x358d45, + 0x21c484, + 0x2c45c6, + 0x273404, + 0x207a43, + 0x28e3c5, + 0x234f88, + 0x366a47, + 0x30a689, + 0x28e648, + 0x2a0951, + 0x2eedca, + 0x2ff207, + 0x3d8686, + 0x207844, + 0x2d02c8, + 0x2e2e88, + 0x2a0b0a, + 0x2d1acd, + 0x2a9606, + 0x203e46, + 0x26a586, + 0x21a247, + 0x2c3c05, + 0x35c6c7, + 0x207705, + 0x39e404, + 0x206686, + 0x30ec47, + 0x2b378d, + 0x2a9987, + 0x344fc8, + 0x282949, + 0x22d8c6, + 0x360dc5, + 0x2393c4, + 0x26ae86, + 0x21f646, + 0x23af06, + 0x2a20c8, + 0x22cdc3, + 0x23e443, + 0x34bcc5, + 0x2d2a86, + 0x2b8c85, + 0x297908, + 0x2a55ca, + 0x33f504, + 0x288e88, + 0x299fc8, + 0x25ef47, + 0x28ed49, + 0x2cc488, + 0x287e47, + 0x2c2e46, + 0x20588a, + 0x26af08, + 0x32df09, + 0x2ae088, + 0x224a09, + 0x3d8547, + 0x35ce45, + 0x2a73c6, + 0x31de48, + 0x2530c8, + 0x2bbfc8, + 0x21e608, + 0x23f185, + 0x200d04, + 0x233908, + 0x241984, + 0x3da044, + 0x26ff45, + 0x2997c7, + 0x25eb49, + 0x27e987, + 0x2260c5, + 0x27d706, + 0x375446, + 0x209744, + 0x2ab3c6, + 0x2855c4, + 0x293ec6, + 0x25e906, + 0x215046, + 0x3d5c05, + 0x2977c7, + 0x203843, + 0x22b509, + 0x31cb48, + 0x287cc4, + 0x287ccd, + 0x29fd48, + 0x2fcd48, + 0x32de86, + 0x28a249, + 0x2d6449, + 0x3a1605, + 0x2a56ca, + 0x2a844a, + 0x2b5c8c, + 0x2b5e06, + 0x280986, + 0x2d79c6, + 0x393189, + 0x2f4246, + 0x223b06, + 0x348f86, + 0x367848, + 0x37e646, + 0x2e094b, + 0x299945, + 0x21a245, + 0x281485, + 0x3b5146, + 0x205843, + 0x23d7c6, + 0x2a9907, + 0x2d0185, + 0x27fbc5, + 0x2c12c5, + 0x301c46, + 0x336144, + 0x336146, + 0x2a9e49, + 0x3b4fcc, + 0x39e148, + 0x2520c4, + 0x30c946, + 0x2917c6, + 0x2d9d08, + 0x2c2f48, + 0x3b4ec9, + 0x357147, + 0x237809, + 0x278286, + 0x22c544, + 0x20af04, + 0x286dc4, + 0x289188, + 0x25e98a, + 0x33a006, + 0x36eb07, + 0x398407, + 0x23f105, + 0x2b7604, + 0x2958c6, + 0x2c3c46, + 0x21b2c3, + 0x31c987, + 0x2205c8, + 0x3a174a, + 0x22e4c8, + 0x34df48, + 0x273445, + 0x2a6205, + 0x237745, + 0x23f4c6, + 0x242546, + 0x25d405, + 0x330449, + 0x2b740c, + 0x307d87, + 0x2a0b88, + 0x251045, + 0x602284, + 0x267c84, + 0x2d9184, + 0x212d06, + 0x2a8d0e, + 0x25b847, + 0x21a445, + 0x3c270c, + 0x3d2347, + 0x30ebc7, + 0x30f7c9, + 0x221a89, + 0x28e745, + 0x31cb48, + 0x32e249, + 0x3bb3c5, + 0x2d00c8, + 0x2c1006, + 0x377506, + 0x2463c4, + 0x294908, + 0x204883, + 0x20ccc4, + 0x2b35c5, + 0x39db87, + 0x2e5e45, + 0x2895c9, + 0x29664d, + 0x2af506, + 0x213c44, + 0x36ee08, + 0x2b25ca, + 0x2144c7, + 0x34bb05, + 0x20cd03, + 0x2a6fce, + 0x3132cc, + 0x30ce47, + 0x2a8ec7, + 0x4539cd47, + 0xb20c6, + 0x27c44, + 0x215d03, + 0x2f4285, + 0x2d9185, + 0x2a1c08, + 0x29edc9, + 0x251fc6, + 0x27d904, + 0x2ff146, + 0x2398cb, + 0x2eab4c, + 0x24dcc7, + 0x2e0c05, + 0x3b1a88, + 0x2efc85, + 0x3759c7, + 0x307b87, + 0x2475c5, + 0x205843, + 0x21fac4, + 0x2e6445, + 0x273bc5, + 0x273bc6, + 0x2a2608, + 0x30ec47, + 0x3cd2c6, + 0x3472c6, + 0x37d086, + 0x30f0c9, + 0x27ef47, + 0x251e46, + 0x2eacc6, + 0x3cae06, + 0x2b4385, + 0x20e046, + 0x3b3245, + 0x2bf588, + 0x29940b, + 0x295606, + 0x398444, + 0x305bc9, + 0x2abc04, + 0x2c0f88, + 0x3116c7, + 0x28bac4, + 0x2cb948, + 0x2d1604, + 0x2b43c4, + 0x27a345, + 0x322506, + 0x2a7d07, + 0x249b03, + 0x2a3705, + 0x2ff4c4, + 0x3c7b86, + 0x3a1688, + 0x37e545, + 0x2990c9, + 0x3513c5, + 0x323488, + 0x2bc807, + 0x330748, + 0x2cb587, + 0x2fdb49, + 0x287f86, + 0x372946, + 0x29b284, + 0x309c45, + 0x31520c, + 0x281487, + 0x282047, + 0x23e208, + 0x2af506, + 0x2a9844, + 0x34a144, + 0x38fb49, + 0x2d7ac6, + 0x296b47, + 0x27e7c4, + 0x2ab4c6, + 0x3c1685, + 0x2dea47, + 0x2e08c6, + 0x261609, + 0x39b307, + 0x29d487, + 0x2aaf06, + 0x270205, + 0x286b08, + 0x223708, + 0x371f86, + 0x37e585, + 0x2e93c6, + 0x203803, + 0x2a1a89, + 0x2a58ce, + 0x2cb2c8, + 0x2e12c8, + 0x371d8b, + 0x299306, + 0x398304, + 0x23bac4, + 0x2a59ca, + 0x2134c7, + 0x251f05, + 0x214a09, + 0x2cf305, + 0x3da087, + 0x232144, + 0x204787, + 0x322608, + 0x2d6c46, + 0x2c8389, + 0x2cc58a, + 0x213446, + 0x29f886, + 0x2b7c45, + 0x39f685, + 0x37d947, + 0x246d48, + 0x3c15c8, + 0x30b3c6, + 0x361c45, + 0x23e34e, + 0x2ccc44, + 0x2a1b85, + 0x27d089, + 0x2f7588, + 0x2931c6, + 0x2a3ccc, + 0x2a51d0, + 0x2a894f, + 0x2aa508, + 0x3513c7, + 0x3d5c05, + 0x297f85, + 0x2a7b89, + 0x297f89, + 0x27ddc6, + 0x313087, + 0x309b45, + 0x337c49, + 0x363386, + 0x2f408d, + 0x286c89, + 0x25ef44, + 0x2cb048, + 0x2339c9, + 0x33a1c6, + 0x280f85, + 0x372946, + 0x33ee09, + 0x27e648, + 0x210ec5, + 0x289804, + 0x2a3e8b, + 0x33a085, + 0x242006, + 0x28ac46, + 0x22a986, + 0x25e24b, + 0x2991c9, + 0x347205, + 0x399007, + 0x2eed46, + 0x233086, + 0x289488, + 0x30ed89, + 0x344d8c, + 0x33fbc8, + 0x31e806, + 0x333e83, + 0x360186, + 0x2b58c5, + 0x285cc8, + 0x3e21c6, + 0x2dec88, + 0x24be05, + 0x293f85, + 0x2c0b88, + 0x3d5247, + 0x3ccf07, + 0x26b607, + 0x31fc48, + 0x2d9b88, + 0x2e2d86, + 0x2c4407, + 0x34d947, + 0x2b578a, + 0x238643, + 0x3b5146, + 0x23e2c5, + 0x215cc4, + 0x282949, + 0x2fdac4, + 0x2cbd84, + 0x2a3944, + 0x2a8ecb, + 0x330c47, + 0x23e585, + 0x29dbc8, + 0x27d706, + 0x27d708, + 0x284886, + 0x294845, + 0x294b05, + 0x296086, + 0x2971c8, + 0x297b08, + 0x282b06, + 0x29da0f, + 0x2a1550, + 0x205385, + 0x203843, + 0x22c605, + 0x321108, + 0x297e89, + 0x3bb508, + 0x312e88, + 0x385808, + 0x330d07, + 0x27d3c9, + 0x2dee88, + 0x2a4f84, + 0x2a37c8, + 0x3589c9, + 0x2c4a07, + 0x395d44, + 0x27ea48, + 0x29758a, + 0x2ff746, + 0x2a9606, + 0x226b09, + 0x2a5407, + 0x2dbfc8, + 0x2321c8, + 0x347988, + 0x259805, + 0x21ce85, + 0x21a245, + 0x2d9145, + 0x2c2747, + 0x205845, + 0x2d0185, + 0x203546, + 0x3bb447, + 0x3aaa07, + 0x297886, + 0x2e2445, + 0x242006, + 0x280e45, + 0x2c7d08, + 0x309ac4, + 0x2d61c6, + 0x353544, + 0x2cb748, + 0x32288a, + 0x28328c, + 0x2a6505, + 0x21a306, + 0x344f46, + 0x348d86, + 0x31e884, + 0x3cd585, + 0x284147, + 0x2a5489, + 0x2db647, + 0x602284, + 0x602284, + 0x330ac5, + 0x2dfe04, + 0x2a328a, + 0x27d586, + 0x2c0b04, + 0x3dccc5, + 0x2c1d85, + 0x2c3b44, + 0x28a887, + 0x3cdfc7, + 0x2db208, + 0x2e94c8, + 0x210ec9, + 0x388d08, + 0x29048b, + 0x2a7cc4, + 0x233185, + 0x38ff05, + 0x26b589, + 0x30ed89, + 0x305ac8, + 0x368f48, + 0x2e6bc4, + 0x291805, + 0x204083, + 0x2d9a45, + 0x2a0046, + 0x29ec0c, + 0x21f546, + 0x280e86, + 0x293445, + 0x301cc8, + 0x2eadc6, + 0x3d8806, + 0x2a9606, + 0x22e24c, + 0x38ffc4, + 0x37d1ca, + 0x293388, + 0x29ea47, + 0x2ff3c6, + 0x252087, + 0x2fed45, + 0x2702c6, + 0x363d86, + 0x377987, + 0x2cc284, + 0x20f085, + 0x27d084, + 0x39e487, + 0x27d2c8, + 0x28080a, + 0x288587, + 0x2ac487, + 0x351347, + 0x2efdc9, + 0x29ec0a, + 0x22c503, + 0x366a05, + 0x215083, + 0x2c2c09, + 0x2d9f48, + 0x388ac7, + 0x3bb609, + 0x223806, + 0x358e08, + 0x3c4b45, + 0x37e94a, + 0x2079c9, + 0x29c289, + 0x2d5707, + 0x2e2f89, + 0x214f48, + 0x25f906, + 0x21a4c8, + 0x27ff07, + 0x274147, + 0x2d5ac7, + 0x2dd548, + 0x30c7c6, + 0x297345, + 0x284147, + 0x29f388, + 0x37d004, + 0x306dc4, + 0x298587, + 0x2b9047, + 0x32e0ca, + 0x25f886, + 0x3c82ca, + 0x2cf747, + 0x2cca07, + 0x20f144, + 0x295d04, + 0x2de946, + 0x361444, + 0x36144c, + 0x311605, + 0x21c2c9, + 0x2f0e84, + 0x2c3c05, + 0x2b2548, + 0x297bc5, + 0x396906, + 0x2980c4, + 0x2ab98a, + 0x384806, + 0x24774a, + 0x3da407, + 0x20d645, + 0x22bd85, + 0x23f14a, + 0x247685, + 0x2a7b46, + 0x241984, + 0x2c00c6, + 0x37da05, + 0x3e2286, + 0x33decc, + 0x2e3cca, + 0x2a8544, + 0x24bc06, + 0x2a5407, + 0x2e0844, + 0x367848, + 0x2ecc46, + 0x398289, + 0x2cd009, + 0x2dcb49, + 0x2db946, + 0x280006, + 0x21a607, + 0x330388, + 0x27fe09, + 0x330c47, + 0x29dd46, + 0x3ca007, + 0x26a445, + 0x2ccc44, + 0x21a1c7, + 0x34db05, + 0x28f645, + 0x200cc7, + 0x247488, + 0x3b1a06, + 0x2a01cd, + 0x2a1e0f, + 0x2a6e0d, + 0x226104, + 0x235086, + 0x2e4088, + 0x348f45, + 0x2b5948, + 0x2862ca, + 0x25ef44, + 0x239b06, + 0x211787, + 0x218e87, + 0x2dc549, + 0x21a485, + 0x2c3b44, + 0x2c568a, + 0x2cc049, + 0x2e3087, + 0x30d406, + 0x33a1c6, + 0x291746, + 0x386c06, + 0x2e398f, + 0x2e3f49, + 0x37e646, + 0x38f786, + 0x32fa49, + 0x2c4507, + 0x220d03, + 0x22e3c6, + 0x20c483, + 0x2d22c8, + 0x2b0e07, + 0x2aa709, + 0x2b6308, + 0x3cd048, + 0x367346, + 0x21f489, + 0x307cc5, + 0x2a3504, + 0x35cf07, + 0x393205, + 0x226104, + 0x23e648, + 0x213784, + 0x2c4247, + 0x399c86, + 0x26c5c5, + 0x2ae088, + 0x33a08b, + 0x31d047, + 0x23f3c6, + 0x2d71c4, + 0x3aef86, + 0x26ff45, + 0x34db05, + 0x286889, + 0x28a489, + 0x274184, + 0x2741c5, + 0x24bc45, + 0x37e7c6, + 0x31cc48, + 0x2ce7c6, + 0x22040b, + 0x3d774a, + 0x2cb685, + 0x294b86, + 0x25b285, + 0x3c2205, + 0x256147, + 0x3b53c8, + 0x237804, + 0x385406, + 0x297b86, + 0x215107, + 0x325304, + 0x285346, + 0x229845, + 0x229849, + 0x280204, + 0x2b7789, + 0x282b06, + 0x2d08c8, + 0x24bc45, + 0x398505, + 0x3e2286, + 0x344c89, + 0x221a89, + 0x280f06, + 0x2f7688, + 0x296788, + 0x25b244, + 0x2c6604, + 0x2c6608, + 0x3326c8, + 0x237909, + 0x29ffc6, + 0x2a9606, + 0x33964d, + 0x31a546, + 0x378f09, + 0x201f45, + 0x20c4c6, + 0x347b08, + 0x336085, + 0x34d984, + 0x26ff45, + 0x289fc8, + 0x2a3049, + 0x27d144, + 0x2c8206, + 0x29c4ca, + 0x30cd48, + 0x32e249, + 0x270bca, + 0x3bb586, + 0x2a1fc8, + 0x375785, + 0x293608, + 0x2fedc5, + 0x2236c9, + 0x33bc49, + 0x21fb82, + 0x2caec5, + 0x277f06, + 0x282a47, + 0x215cc5, + 0x33eb86, + 0x319508, + 0x2af506, + 0x2c9889, + 0x282146, + 0x289308, + 0x24ef85, + 0x394886, + 0x3b3b08, + 0x289188, + 0x3d8448, + 0x31b948, + 0x20e044, + 0x21f783, + 0x2c9ac4, + 0x288786, + 0x26a484, + 0x2e1207, + 0x3d8709, + 0x2d6785, + 0x2321c6, + 0x22e3c6, + 0x2a244b, + 0x2c3346, + 0x273686, + 0x2d62c8, + 0x266cc6, + 0x20d443, + 0x20bb03, + 0x2ccc44, + 0x2310c5, + 0x23f747, + 0x27d2c8, + 0x27d2cf, + 0x28404b, + 0x31ca48, + 0x2c8286, + 0x31cd4e, + 0x23f583, + 0x23f6c4, + 0x2c32c5, + 0x2c39c6, + 0x2959cb, + 0x299886, + 0x30c009, + 0x26c5c5, + 0x249a48, + 0x209bc8, + 0x22194c, + 0x2a8f06, + 0x2d9a86, + 0x2e5145, + 0x290108, + 0x283285, + 0x3505c8, + 0x2a404a, + 0x2a7249, + 0x602284, 0x2000c2, - 0x202703, - 0x201242, - 0x214a83, - 0x235b44, - 0x232dc3, - 0x308003, - 0x21bc83, - 0x2e2406, - 0x21a3c3, - 0x242543, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x228503, - 0x21a3c3, - 0x1b4103, - 0x242543, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x219a04, - 0x21a3c3, - 0x242543, - 0x2000c2, - 0x27ee03, - 0x201242, - 0x232dc3, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x242543, - 0x2086c2, - 0x215702, - 0x201242, - 0x214a83, - 0x208c02, - 0x2005c2, - 0x221dc4, - 0x306c44, - 0x223f82, - 0x219a04, + 0x4b212402, + 0x200382, + 0x20e704, + 0x20b982, + 0x217544, + 0x203182, + 0x5803, 0x2003c2, - 0x242543, - 0x2141c3, - 0x252b06, - 0x20c782, - 0x201b82, - 0x2221c2, - 0x57a07403, - 0x57e2e743, - 0x56246, - 0x56246, - 0x2d3684, - 0x203dc3, - 0x160d, - 0x1d984a, - 0x16300c, - 0x1d76cc, - 0xd4ecd, - 0x139b05, - 0x86209, - 0x8d2cc, - 0x29907, - 0xdb86, - 0x13dc8, - 0x1bf87, - 0x201c8, - 0x1ac0ca, - 0x10d707, - 0x58a8d505, - 0xe4f09, - 0x58c3480b, - 0x125c08, - 0x1558b, - 0x12c5c8, - 0x1c48c9, - 0x4060a, - 0x1b1b8e, - 0x1d158d, - 0x2cd0d, - 0x14426cb, - 0xe554a, - 0x8d04, - 0x5a106, - 0x19b808, - 0x79108, - 0x25687, - 0x1d35c5, - 0xc607, - 0x33249, - 0x15c087, - 0x106c8, - 0x26a89, - 0x4ce04, - 0x4e945, - 0x98e8e, - 0x12c207, - 0x59225a86, - 0x78d8d, - 0xd1288, - 0x59694f86, - 0x5a094f88, - 0x56f88, - 0x136b90, - 0x53f8c, - 0x61b47, - 0x62347, - 0x6a947, - 0x72047, - 0x6882, - 0x120687, - 0x19980c, - 0x13c945, - 0x107c07, - 0xac186, - 0xacdc9, - 0xaff88, - 0x6502, + 0x208502, + 0xae888, + 0x4cc4, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x7542, + 0x4b202, + 0x23cb03, + 0x217fc3, + 0x23e083, + 0x1fcc2, + 0x4642, + 0x72c2, + 0x24ac43, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x20e704, + 0x217fc3, + 0x23e083, + 0x219ac3, + 0x24cd44, + 0x22ea43, + 0x236704, + 0x233fc3, + 0x2e5904, + 0x266a83, + 0x215f87, + 0x23cb03, + 0x205803, + 0x321388, + 0x23e083, + 0x293b0b, + 0x2ffec3, + 0x243bc6, + 0x22dc42, + 0x2fa00b, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23e083, + 0x221d43, + 0x210cc3, + 0x2000c2, + 0xae888, + 0x334f05, + 0x34db88, + 0x2f4fc8, + 0x212402, + 0x36a4c5, + 0x3ca147, + 0x2031c2, + 0x243407, + 0x200382, + 0x253d47, + 0x23a489, + 0x272888, + 0x347809, + 0x210382, + 0x3d5f47, + 0x32ad04, + 0x3ca207, + 0x3d7647, + 0x25a642, + 0x23cb03, + 0x20a942, + 0x203182, + 0x2003c2, + 0x205b42, + 0x200902, + 0x208502, + 0x2e1a45, + 0x227885, + 0x12402, + 0x33fc3, + 0x22ea43, + 0x233fc3, + 0x27e883, + 0x266a83, + 0x204903, + 0x217fc3, + 0x23e083, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x1c0443, + 0x23e083, + 0xfe83, + 0x101, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x20e704, + 0x2191c3, + 0x217fc3, + 0x1c0443, + 0x23e083, + 0x217c83, + 0x4e4b1706, + 0x22383, + 0xd7405, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x212402, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x1c0443, + 0x23e083, + 0x5242, + 0xae888, + 0x12f603, + 0x5803, + 0x1c0443, + 0x46d04, + 0x147b604, + 0xf0085, + 0x2000c2, + 0x3993c4, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x247e03, + 0x22f845, + 0x2191c3, + 0x21e1c3, + 0x217fc3, + 0x24dfc3, + 0x23e083, + 0x208503, + 0x24cdc3, + 0x20aa43, 0x5c2, - 0x18d986, - 0x1b9ecb, - 0x1ba1c6, - 0x174d04, - 0x978c7, - 0x41a89, - 0xf0c09, - 0x1b1148, - 0x49582, - 0x193a49, - 0xd788, - 0xef24a, - 0x15adc9, - 0x1b4186, - 0xd8949, - 0xe54c7, - 0xe5c09, - 0xe7ac8, - 0xea3c7, - 0xec049, - 0xf0005, - 0xf1210, - 0x1b6786, - 0x97805, - 0x91487, - 0xec74d, - 0x41485, - 0xf8ac6, - 0xf92c7, - 0xfe7d8, - 0xd1608, - 0x13db8a, - 0xca42, - 0x5020a, - 0x60e4d, - 0x45c2, - 0xce946, - 0x11ec6, - 0xa1788, - 0xafd0a, - 0x472c8, - 0x6de89, - 0x115488, - 0x6eace, - 0x6e0c8, - 0x14a887, - 0x5a694ec4, - 0xae8cd, - 0x10a085, - 0x69148, - 0x34088, - 0x111b86, - 0xc2c2, - 0xc53c4, - 0xe2c06, - 0x365c6, - 0x5a8ef74b, - 0x1442, + 0x30242, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x2000c2, + 0x24ac43, + 0x212402, + 0xf982, + 0x233fc3, + 0x266a83, + 0x20e704, + 0x217fc3, + 0x23e083, + 0x208502, + 0xae888, + 0x266a83, + 0x1c0443, + 0xae888, + 0x1c0443, + 0x276243, + 0x22ea43, + 0x2319c4, + 0x233fc3, + 0x266a83, + 0x209582, + 0x23cb03, + 0x217fc3, + 0x5803, + 0x23e083, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x209582, + 0x215f83, + 0x217fc3, + 0x23e083, + 0x2f8e43, + 0x208503, + 0x2000c2, + 0x212402, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x243bc5, + 0x1375c6, + 0x24cd44, + 0x22dc42, + 0x882, + 0xae888, + 0xf982, + 0x4b202, + 0x2a82, + 0x2000c2, + 0x146bc5, + 0x1ae08, + 0x125203, + 0x212402, + 0x3c904, + 0x52d16f86, + 0x1384, + 0xc634b, + 0x3a806, + 0x7f3c7, + 0x1431c9, + 0x233fc3, + 0x49e88, + 0x49e8b, + 0x4a30b, + 0x4a9cb, + 0x4ad0b, + 0x4afcb, + 0x4b40b, + 0x1cb86, + 0x266a83, + 0xf48c5, + 0x2044, + 0x20ef43, + 0x11b787, + 0xe88c4, + 0x722c4, + 0x217fc3, + 0x81006, + 0x1583c4, + 0x1c0443, + 0x23e083, + 0x300ac4, + 0x131247, + 0x1371c9, + 0xc6108, + 0x1a2584, + 0x1ca344, + 0x134c46, + 0xff48, + 0x1480c5, + 0x124e89, + 0xe783, + 0x146bc5, + 0x212402, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x205803, + 0x23e083, + 0x2ffec3, + 0x22dc42, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x20e703, + 0x21e484, + 0x217fc3, + 0x5803, + 0x23e083, + 0x22ea43, + 0x233fc3, + 0x2e5904, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x243bc6, + 0x233fc3, + 0x266a83, + 0xf443, + 0x1c0443, + 0x23e083, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x146bc5, + 0x7f3c7, + 0x15c3, + 0xe783, + 0xae888, + 0x266a83, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x612c3, + 0x217fc3, + 0x23e083, + 0x5622ea43, + 0x233fc3, + 0x217fc3, + 0x23e083, + 0xae888, + 0x2000c2, + 0x212402, + 0x22ea43, + 0x266a83, + 0x217fc3, + 0x2003c2, + 0x23e083, + 0x33c187, + 0x355d4b, + 0x211843, + 0x27da88, + 0x330107, + 0x229dc6, + 0x2d42c5, + 0x36a609, + 0x243948, + 0x381049, + 0x3ac290, + 0x38104b, + 0x215589, + 0x2015c3, + 0x2fa6c9, + 0x232646, + 0x23264c, + 0x334fc8, + 0x3dde48, + 0x26eac9, + 0x2c8b0e, + 0x23a24b, + 0x2c030c, + 0x233f03, + 0x284e8c, + 0x3e13c9, + 0x238447, + 0x233f0c, + 0x2bde8a, + 0x241ec4, + 0x38aa8d, + 0x284d48, + 0x219acd, + 0x292146, + 0x24cd4b, + 0x337349, + 0x38fa07, + 0x25f0c6, + 0x323849, + 0x35484a, + 0x30e748, + 0x2ffac4, + 0x3a8e87, + 0x3c0807, + 0x208184, + 0x2221c4, + 0x3b4809, + 0x35c549, + 0x3e1f48, + 0x2f2c85, + 0x2102c5, + 0x209a86, + 0x38a949, + 0x28654d, + 0x2ece48, + 0x209987, + 0x2d4348, + 0x26bdc6, + 0x22fa44, + 0x2a4d45, + 0x3d9f46, + 0x3dc104, + 0x3e12c7, + 0x204e8a, + 0x210e04, + 0x213386, + 0x214689, + 0x21468f, + 0x214c4d, + 0x215ac6, + 0x21aa10, + 0x21ae06, + 0x21b507, + 0x21bcc7, + 0x21bccf, + 0x21c689, + 0x224c46, + 0x225047, + 0x225048, + 0x225449, + 0x20f708, + 0x306a07, + 0x22b743, + 0x22e8c6, + 0x239148, + 0x2c8dca, + 0x20cf09, + 0x243a83, + 0x36a3c6, + 0x38524a, + 0x2fbb87, + 0x23828a, + 0x316c8e, + 0x21c7c6, + 0x32bc47, + 0x38ef46, + 0x243fc6, + 0x21cc8b, + 0x3a038a, + 0x35638d, + 0x2800c7, + 0x26dc08, + 0x26dc09, + 0x26dc0f, + 0x30a80c, + 0x265209, + 0x2bbbce, + 0x21608a, + 0x20dac6, + 0x3076c6, + 0x31a1cc, + 0x3df50c, + 0x325908, + 0x35fd07, + 0x39d4c5, + 0x3ca3c4, + 0x25fd0e, + 0x3ae384, + 0x37dd87, + 0x3a6d8a, + 0x3d7cd4, + 0x3db78f, + 0x21be88, + 0x22e788, + 0x39124d, + 0x39124e, + 0x22ed49, + 0x22fe88, + 0x22fe8f, + 0x233c0c, + 0x233c0f, + 0x234dc7, + 0x23718a, + 0x23874b, + 0x2395c8, + 0x23b807, + 0x260b4d, + 0x369646, + 0x38ac46, + 0x23d649, + 0x252848, + 0x243dc8, + 0x243dce, + 0x2bb387, + 0x305145, + 0x246ac5, + 0x206484, + 0x22a086, + 0x3e1e48, + 0x324643, + 0x2e8c8e, + 0x260f08, + 0x2acacb, + 0x276407, + 0x30b205, + 0x269c06, + 0x2b6ec7, + 0x321848, + 0x37d749, + 0x3d2cc5, + 0x28e408, + 0x228a46, + 0x3addca, + 0x25fc09, + 0x233fc9, + 0x233fcb, + 0x25c6c8, + 0x208049, + 0x2f2d46, + 0x2041ca, + 0x29d08a, + 0x23738c, + 0x375e07, + 0x27268a, + 0x331b0b, + 0x331b19, + 0x353148, + 0x243c45, + 0x260d06, + 0x211d89, + 0x3b2c46, + 0x22170a, + 0x275246, + 0x2d8384, + 0x2d838d, + 0x3b4447, + 0x368889, + 0x249285, + 0x2493c8, + 0x249c49, + 0x24bb44, + 0x24c247, + 0x24c248, + 0x24c507, + 0x26c188, + 0x251c87, + 0x2daec5, + 0x25828c, + 0x258749, + 0x31d28a, + 0x3b09c9, + 0x2fa7c9, + 0x38f54c, + 0x25accb, + 0x25c8c8, + 0x261448, + 0x264f04, + 0x28b548, + 0x28cb89, + 0x2bdf47, + 0x2148c6, + 0x2a3b07, + 0x2a0f49, + 0x354d4b, + 0x20b187, + 0x348647, + 0x3da547, + 0x219a44, + 0x219a45, + 0x2e5605, + 0x35e84b, + 0x349284, + 0x328308, + 0x30234a, + 0x228b07, + 0x3d0347, + 0x295192, + 0x293dc6, + 0x231346, + 0x34890e, + 0x294586, + 0x299e48, + 0x29aacf, + 0x219e88, + 0x28fb88, + 0x2df5ca, + 0x2df5d1, + 0x2ab64e, + 0x2550ca, + 0x2550cc, + 0x230087, + 0x230090, + 0x3d4f08, + 0x2ab845, + 0x2b71ca, + 0x3dc14c, + 0x29e08d, + 0x204906, + 0x204907, + 0x20490c, + 0x209d8c, + 0x2191cc, + 0x2c204b, + 0x3923c4, + 0x226c84, + 0x2ba749, + 0x34a1c7, + 0x382f89, + 0x29cec9, + 0x2bdb47, + 0x2bdd06, + 0x2bdd09, + 0x2be103, + 0x2af60a, + 0x323a87, + 0x3ca70b, + 0x35620a, + 0x32ad84, + 0x3c88c6, + 0x288809, + 0x3612c4, + 0x2e164a, + 0x2e2845, + 0x2cd7c5, + 0x2cd7cd, + 0x2cdb0e, + 0x2c9c05, + 0x33ae46, + 0x2437c7, + 0x2525ca, + 0x3ae686, + 0x381c04, + 0x35a607, + 0x2fc70b, + 0x26be87, + 0x2699c4, + 0x253306, + 0x25330d, + 0x2e724c, + 0x217e86, + 0x2ed04a, + 0x223486, + 0x220dc8, + 0x274707, + 0x2d5eca, + 0x2361c6, + 0x27ffc3, + 0x2f4b46, + 0x238fc8, + 0x37204a, + 0x2df007, + 0x2df008, + 0x25bfc4, + 0x295707, + 0x2fdf08, + 0x293fc8, + 0x2c30c8, + 0x33e14a, + 0x2ee705, + 0x2ee987, + 0x254f13, + 0x271146, + 0x20bc08, + 0x222a49, + 0x2432c8, + 0x3673cb, + 0x3cd3c8, + 0x2cab84, + 0x2c0c86, + 0x325e06, + 0x322349, + 0x2d5d07, + 0x258388, + 0x2a5c46, + 0x200bc4, + 0x3d5d85, + 0x3aa788, + 0x248e8a, + 0x2d8008, + 0x2dcf86, + 0x2a21ca, + 0x273d48, + 0x2e0648, + 0x2e18c8, + 0x2e2106, + 0x2e4286, + 0x3b048c, + 0x2e4810, + 0x2b8a85, + 0x219c88, + 0x21e910, + 0x219c90, + 0x3ac10e, + 0x3b010e, + 0x3b0114, + 0x3b934f, + 0x3b9706, + 0x3b6051, + 0x208253, + 0x2086c8, + 0x25f245, + 0x27dfc8, + 0x3a7c45, + 0x34aacc, + 0x22b989, + 0x3ae1c9, + 0x317147, + 0x237bc9, + 0x3b2807, + 0x33a486, + 0x2a4b47, + 0x202cc5, + 0x20fec3, + 0x20f443, + 0x215bc4, + 0x3dff8d, + 0x20bf4f, + 0x200c05, + 0x34a9c6, + 0x2200c7, + 0x334d47, + 0x37b8c6, + 0x37b8cb, + 0x2ac3c5, + 0x259986, + 0x30db47, + 0x252b89, + 0x225706, + 0x38c185, + 0x3c324b, + 0x205d06, + 0x226685, + 0x246248, + 0x296448, + 0x2ae3cc, + 0x2ae3d0, + 0x2b4f89, + 0x2c7007, + 0x2be80b, + 0x2ce086, + 0x3068ca, + 0x2a81cb, + 0x38160a, + 0x39f946, + 0x2f8d05, + 0x330006, + 0x28d548, + 0x31720a, + 0x390edc, + 0x2fff8c, + 0x300288, + 0x243bc5, + 0x387ac7, + 0x25d246, + 0x2bcc85, + 0x218386, + 0x37ba88, + 0x2cc2c7, + 0x2c8a08, + 0x27120a, + 0x3c110c, + 0x3248c9, + 0x3c1387, + 0x28d0c4, + 0x246b86, + 0x28f70a, + 0x29cfc5, + 0x221e4c, + 0x222508, + 0x2f6848, + 0x2b1a0c, + 0x31aa0c, + 0x32a8c9, + 0x32ab07, + 0x242dcc, + 0x22ac84, + 0x36fe0a, + 0x31114c, + 0x24e1cb, + 0x24f60b, + 0x2509c6, + 0x2541c7, + 0x2302c7, + 0x2302cf, + 0x312111, + 0x2eb492, + 0x25538d, + 0x25538e, + 0x2556ce, + 0x3b9508, + 0x3b9512, + 0x266448, + 0x223087, + 0x24fa4a, + 0x2af348, + 0x294545, + 0x2c258a, + 0x21b187, + 0x2f1004, + 0x20ee43, + 0x236c45, + 0x2df847, + 0x3aca87, + 0x29e28e, + 0x33dacd, + 0x350d49, + 0x31fb05, + 0x35f4c3, + 0x34ca46, + 0x259ec5, + 0x2acd08, + 0x227349, + 0x260d45, + 0x260d4f, + 0x2c6447, + 0x2154c5, + 0x276dca, + 0x205646, + 0x35d1c9, + 0x386ecc, + 0x3d2dc9, + 0x20b386, + 0x30214c, + 0x333f86, + 0x310088, + 0x331a06, + 0x36c7c6, + 0x2c34c4, + 0x3222c3, + 0x20de0a, + 0x22de51, + 0x26a90a, + 0x25b105, + 0x288207, + 0x255b47, + 0x2e8a84, + 0x2fe00b, + 0x347688, + 0x2cb146, + 0x23e285, + 0x268b84, + 0x24fc89, + 0x2008c4, + 0x2124c7, + 0x34d185, + 0x34d187, + 0x348b45, + 0x20bb83, + 0x222f48, + 0x27e1ca, + 0x249b03, + 0x334f4a, + 0x2a9d06, + 0x260acf, + 0x2bb309, + 0x2e8c10, + 0x3064c8, + 0x2dd9c9, + 0x29f107, + 0x25328f, + 0x3bb9c4, + 0x2e5984, + 0x21ac86, + 0x2356c6, + 0x23edca, + 0x247cc6, + 0x2b9447, + 0x317c48, + 0x317e47, + 0x3192c7, + 0x31ad0a, + 0x319bcb, + 0x358f85, + 0x2eb0c8, + 0x21a303, + 0x3ccbcc, + 0x39d24f, + 0x3c7e0d, + 0x258b87, + 0x350e89, + 0x2f5c87, + 0x28c3c8, + 0x3d7ecc, + 0x2caa88, + 0x366dc8, + 0x332bce, + 0x345b54, + 0x346064, + 0x365d0a, + 0x38188b, + 0x3b28c4, + 0x3b28c9, + 0x239b88, + 0x247385, + 0x32414a, + 0x2a5007, + 0x215d84, + 0x24ac43, + 0x22ea43, + 0x236704, + 0x233fc3, + 0x266a83, + 0x20e704, + 0x2191c3, + 0x23cb03, + 0x2e4806, + 0x21e484, + 0x217fc3, + 0x23e083, + 0x216983, + 0x2000c2, + 0x24ac43, + 0x212402, + 0x22ea43, + 0x236704, + 0x233fc3, + 0x266a83, + 0x2191c3, + 0x2e4806, + 0x217fc3, + 0x23e083, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x280203, + 0x217fc3, + 0x1c0443, + 0x23e083, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x21e484, + 0x217fc3, + 0x23e083, + 0x2000c2, + 0x281bc3, + 0x212402, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x23e083, + 0x20cf02, + 0x20cdc2, + 0x212402, + 0x22ea43, + 0x204302, + 0x2005c2, + 0x20e704, + 0x217544, + 0x266002, + 0x21e484, + 0x2003c2, + 0x23e083, + 0x216983, + 0x2509c6, + 0x21fcc2, + 0x2072c2, + 0x223d42, + 0x58a13d83, + 0x58e30083, + 0x56486, + 0x56486, + 0x24cd44, + 0x205803, + 0x8acd, + 0x1e1cca, + 0x1cc04c, + 0x173cc, + 0xd720d, + 0x6e784, + 0x8f284, + 0x120384, + 0x146bc5, + 0x8e9c9, + 0xbf04c, + 0x1683c7, + 0x11fc6, + 0x16588, + 0x1a087, + 0x20ac8, + 0x1bdd8a, + 0x1109c7, + 0x59abd285, + 0xbd289, + 0x59c35a0b, + 0x129f08, + 0xcc4b, + 0x141488, + 0x167e89, + 0x8c80a, + 0x1316ce, + 0xbec4a, + 0xa4cd, + 0x2ed4d, + 0x14430cb, + 0xe710a, + 0x1384, + 0x59ac6, + 0xf988, + 0x10f508, + 0x35cc7, + 0x1dbc5, + 0x1fb47, + 0x34449, + 0x161347, + 0xec88, + 0x2afc9, + 0x3ea84, + 0xd3085, + 0x737ce, + 0x1410c7, + 0x5a224d46, + 0x4efcd, + 0x7f248, + 0x5a65ce86, + 0x5b05ce88, + 0x57388, + 0x13c390, + 0x5460c, + 0x68787, + 0x693c7, + 0x707c7, + 0x77c07, + 0x9a42, + 0x16e07, + 0x1a054c, + 0x5d4c5, + 0xb4e07, + 0xae286, + 0xafcc9, + 0xb3108, + 0xb5c2, + 0x5c2, + 0x193c86, + 0x1c2b0b, + 0x1c2e06, + 0x6f044, + 0x1b5ac7, + 0x33449, + 0x860c9, + 0x1bb208, + 0x4b202, + 0x199249, + 0x11a08, + 0xfb54a, + 0xe689, + 0x2a8c6, + 0xdac89, + 0xe7087, + 0xe77c9, + 0xea1c8, + 0xec607, + 0xee689, + 0xf1a45, + 0xf1e10, + 0x1d60c6, + 0x1b5a05, + 0x19dfc7, + 0xbd68d, + 0x41d85, + 0xfa5c6, + 0xfadc7, + 0x100ad8, + 0x7f5c8, + 0x14978a, + 0xd782, + 0x5b7928cb, + 0x4f3ca, + 0x5a04d, + 0x2442, + 0xd4d86, + 0x13a06, + 0xa2ac8, + 0xb2e8a, + 0x3dd48, + 0x74e49, + 0x118088, + 0x6f48e, + 0x75088, + 0x14ca47, + 0x5ba5cdc4, + 0xb170d, + 0x1095c5, + 0x2748, + 0x35288, + 0x1145c6, + 0x4642, + 0xcaf44, + 0xe5006, + 0x134c46, + 0x5bd8490b, + 0x3602, 0x401, 0x81, - 0xb8f08, - 0x5bc87, - 0x150503, - 0x59a37f04, - 0x59e9b383, + 0xbe588, + 0x5bb87, + 0x93783, + 0x5aa37e84, + 0x5ae9c0c3, 0xc1, - 0xf586, + 0x25d86, 0xc1, 0x201, - 0xf586, - 0x150503, - 0x66603, - 0x647c4, - 0x1e7c7, - 0x7787, - 0x15c27c5, - 0x4e684, - 0x13d707, - 0x1242, - 0x24c0c4, - 0x214a83, - 0x24d9c4, - 0x221dc4, - 0x21a3c3, - 0x221445, - 0x214903, - 0x22b983, - 0x208805, - 0x207783, - 0x1243, - 0x5ba14a83, - 0x232dc3, - 0x4d9c4, - 0x7083, - 0x308003, + 0x25d86, + 0x93783, + 0x18b7c8, + 0x4cdc3, + 0x27c44, + 0x20f47, + 0xaa47, + 0x1571585, + 0x4e584, + 0x149307, + 0x12402, + 0x241ec4, + 0x22ea43, + 0x24d704, + 0x20e704, + 0x217fc3, + 0x222905, + 0x217c83, + 0x235403, + 0x37b845, + 0x20aa43, + 0x1be83, + 0x5ce2ea43, + 0x233fc3, + 0x4d704, + 0x33c3, + 0x266a83, 0x200181, - 0x1a8c3, - 0x23c803, - 0x306c44, - 0x219a04, - 0x21a3c3, - 0x4e283, - 0x242543, - 0x20e2c3, - 0x9a048, + 0x1e1c3, + 0x23cb03, + 0x217544, + 0x21e484, + 0x217fc3, + 0x4dfc3, + 0x23e083, + 0x208503, + 0xae888, 0x2000c2, - 0x202703, - 0x201242, - 0x214a83, - 0x232dc3, - 0x228503, + 0x24ac43, + 0x212402, + 0x22ea43, + 0x233fc3, + 0x280203, 0x2005c2, - 0x221dc4, - 0x21bc83, - 0x23c803, - 0x21a3c3, - 0x203dc3, - 0x242543, - 0x207783, - 0x196504, - 0x9a048, - 0x106947, - 0x1242, - 0x1a3105, - 0x540cf, - 0xe0986, - 0x144ca88, - 0x1160ce, - 0x5ca345c2, - 0x297ac8, - 0x35c5c6, - 0x24e806, - 0x395e87, - 0x5ce00c82, - 0x5d2b7488, - 0x20bd4a, - 0x2615c8, + 0x20e704, + 0x2191c3, + 0x23cb03, + 0x217fc3, + 0x205803, + 0x23e083, + 0x20aa43, + 0x19d184, + 0xae888, + 0x10a087, + 0x12402, + 0x1aa705, + 0x5474f, + 0xf10c6, + 0x1454408, + 0x118cce, + 0x5de2a502, + 0x32f688, + 0x361886, + 0x24e706, + 0x39cb07, + 0x5e200c82, + 0x5e6bb188, + 0x21f28a, + 0x268208, 0x200ac2, - 0x3c8c49, - 0x33bfc7, - 0x212686, - 0x2217c9, - 0x2c1c04, - 0x3c8b46, - 0x2cc7c4, - 0x20e904, - 0x257889, - 0x30dbc6, - 0x265445, - 0x266245, - 0x22d547, - 0x2dbd87, - 0x34c8c4, - 0x31e606, - 0x2ff485, - 0x210845, - 0x23eac5, - 0x3bd9c7, - 0x26f6c5, - 0x248489, - 0x343fc5, - 0x31b484, - 0x3a6987, - 0x36344e, - 0x2031c9, - 0x2885c9, - 0x348706, - 0x23f9c8, - 0x36f2cb, - 0x2a5a0c, - 0x322686, - 0x2ba447, - 0x2eee85, - 0x3270ca, - 0x3d9bc9, - 0x345c89, - 0x295146, - 0x30bc05, - 0x245705, - 0x36a209, - 0x23ec4b, - 0x2c2246, - 0x352686, - 0x2067c4, - 0x2ecd46, - 0x304448, - 0x3c1e46, - 0x2e3e06, - 0x3dd908, - 0x2019c7, - 0x201d49, - 0x205a85, - 0x9a048, - 0x3cd4c4, - 0x316c44, - 0x20b105, - 0x3403c9, - 0x220747, - 0x22074b, - 0x22284a, - 0x228585, - 0x5d60c282, - 0x2cda07, - 0x5da29cc8, - 0x295387, - 0x301345, - 0x348aca, - 0x1242, - 0x27c58b, - 0x27d98a, - 0x248906, - 0x20a803, - 0x206c8d, - 0x3c4c4c, - 0x3c534d, - 0x230585, - 0x27bbc5, - 0x296dc7, - 0x3d1149, - 0x20bc46, - 0x254505, - 0x37b708, - 0x2ce983, - 0x2e3948, - 0x2ecc48, - 0x383fc7, - 0x3b8a88, - 0x3c0809, - 0x2fd2c7, - 0x2cd207, - 0x3de588, - 0x23ae04, - 0x23ae07, - 0x3a6bc8, - 0x360f06, - 0x3c0ecf, - 0x22a907, - 0x31e106, - 0x22dcc5, - 0x222343, - 0x246287, - 0x387fc3, - 0x24d046, - 0x24e586, - 0x24f0c6, - 0x293d45, - 0x265c03, - 0x3936c8, - 0x38a109, - 0x39bf8b, - 0x24f248, - 0x250a85, - 0x252305, - 0x5de2dec2, - 0x2842c9, - 0x221e47, - 0x25a045, - 0x257787, - 0x258ac6, - 0x381745, - 0x25a40b, - 0x25c004, - 0x261185, - 0x2612c7, - 0x276806, - 0x276c45, - 0x283d87, - 0x2847c7, - 0x2a7484, - 0x28d0ca, - 0x28dbc8, - 0x2ccc09, - 0x23f285, - 0x205886, - 0x30460a, - 0x266146, - 0x2ed087, - 0x26d30d, - 0x2aa2c9, - 0x391c45, - 0x363847, - 0x289708, - 0x303588, - 0x3286c7, - 0x384d06, - 0x21abc7, - 0x24dbc3, - 0x30db44, - 0x37d485, - 0x3a7747, - 0x3b0d49, - 0x229588, - 0x2ecf85, - 0x2425c4, - 0x247ec5, - 0x24f40d, + 0x3ca549, + 0x358fc7, + 0x214846, + 0x222c89, + 0x2eeac4, + 0x3ca446, + 0x2e9104, + 0x2029c4, + 0x257b49, + 0x310e86, + 0x267c85, + 0x26b845, + 0x22f587, + 0x2de387, + 0x26b784, + 0x2d2486, + 0x301785, + 0x20ee05, + 0x25b1c5, + 0x2c2347, + 0x276245, + 0x24a0c9, + 0x37eb85, + 0x321984, + 0x3ae5c7, + 0x3b3fce, + 0x207289, + 0x3487c9, + 0x371246, + 0x2405c8, + 0x37554b, + 0x2a74cc, + 0x326f06, + 0x2c01c7, + 0x2f0d05, + 0x3163ca, + 0x3e2049, + 0x201189, + 0x206a86, + 0x30d905, + 0x246e45, + 0x389a89, + 0x25b34b, + 0x2ef106, + 0x353806, + 0x209984, + 0x303a46, + 0x3051c8, + 0x3cbf46, + 0x267846, + 0x203048, + 0x205107, + 0x206809, + 0x208e85, + 0xae888, + 0x3d2c44, + 0x319844, + 0x210145, + 0x343c49, + 0x221287, + 0x22128b, + 0x22434a, + 0x228745, + 0x5ea087c2, + 0x3560c7, + 0x5ee2b748, + 0x206cc7, + 0x303085, + 0x35d60a, + 0x12402, + 0x28428b, + 0x28544a, + 0x24a546, + 0x20ffc3, + 0x21114d, + 0x3ca98c, + 0x203a8d, + 0x232105, + 0x3363c5, + 0x324687, + 0x206309, + 0x21f186, + 0x247b45, + 0x3401c8, + 0x2d4dc3, + 0x2f52c8, + 0x303948, + 0x3a2107, + 0x3c5d88, + 0x3c76c9, + 0x2ff5c7, + 0x3558c7, + 0x371408, + 0x38bcc4, + 0x38bcc7, + 0x292048, + 0x366406, + 0x3cb14f, + 0x265747, + 0x2d1f86, + 0x32ac45, + 0x223ec3, + 0x2479c7, + 0x38e083, + 0x24c6c6, + 0x24e486, + 0x24ff06, + 0x298ec5, + 0x26c183, + 0x398ec8, + 0x390849, + 0x3a290b, + 0x250088, + 0x251945, + 0x253645, + 0x5f2ba882, + 0x2a4c09, + 0x223307, + 0x259a05, + 0x257a47, + 0x258ec6, + 0x386ac5, + 0x259d0b, + 0x25c8c4, + 0x267dc5, + 0x267f07, + 0x27c586, + 0x27c9c5, + 0x28b987, + 0x28c147, + 0x2a9cc4, + 0x2bee4a, + 0x292b08, + 0x375809, + 0x25b985, + 0x3585c6, + 0x30538a, + 0x26d6c6, + 0x236047, + 0x272a0d, + 0x2abf09, + 0x397445, + 0x2603c7, + 0x32d088, + 0x3b38c8, + 0x20a107, + 0x20e3c6, + 0x22cc07, + 0x24d903, + 0x310e04, + 0x383405, + 0x3af807, + 0x3bae09, + 0x2f5e08, + 0x235f45, + 0x362784, + 0x250245, + 0x25ca8d, 0x200cc2, - 0x2bca46, - 0x2eaf06, - 0x308cca, - 0x39a786, - 0x3a3345, - 0x26d6c5, - 0x26d6c7, - 0x3a5fcc, - 0x256e0a, - 0x28f246, - 0x2e1d85, - 0x2ecb86, - 0x28f507, - 0x291246, - 0x293c4c, - 0x221909, - 0x5e20fa07, - 0x29a9c5, - 0x29a9c6, - 0x29ae08, - 0x2c4005, - 0x2aab45, - 0x2ab848, - 0x2aba4a, - 0x5e67b8c2, - 0x5ea09e42, - 0x355fc5, - 0x237643, - 0x326008, - 0x228703, - 0x2abcc4, - 0x312c4b, - 0x36f688, - 0x2b9648, - 0x5ef03cc9, - 0x2b1009, - 0x2b19c6, - 0x2b2788, - 0x2b2989, - 0x2b3806, - 0x2b3985, - 0x246c06, - 0x2b4749, - 0x2c8947, - 0x38e386, - 0x20af47, - 0x345fc7, - 0x207584, - 0x5f2d1909, - 0x24ad08, - 0x2b7388, - 0x2257c7, - 0x2d5946, - 0x3d0f49, - 0x24e7c7, - 0x24a58a, - 0x32ed08, - 0x3bb707, - 0x3d0606, - 0x2f0e0a, - 0x23df48, - 0x2ea985, - 0x227b85, - 0x3cbc87, - 0x3190c9, - 0x31cf0b, - 0x351f08, - 0x344049, - 0x24fb47, - 0x2c2bcc, - 0x2c3bcc, - 0x2c3eca, - 0x2c414c, - 0x2cc348, - 0x2cc548, - 0x2cc744, - 0x2ce109, - 0x2ce349, - 0x2ce58a, - 0x2ce809, - 0x2ceb87, - 0x3bec0c, - 0x3d2406, - 0x26ccc8, - 0x266206, - 0x38fe86, - 0x391b47, - 0x3a1088, - 0x3debcb, - 0x295247, - 0x257549, - 0x25ba49, - 0x2844c7, - 0x2cca04, - 0x200fc7, - 0x2f0806, - 0x20e486, - 0x24c845, - 0x2f7d48, - 0x26c544, - 0x26c546, - 0x256ccb, - 0x2b3449, - 0x235686, - 0x2e4009, - 0x20b1c6, - 0x345048, - 0x210543, - 0x30bd85, - 0x21a9c9, - 0x21c7c5, - 0x30e1c4, - 0x275d46, - 0x235a05, - 0x254306, - 0x319a07, - 0x247946, - 0x22c2cb, - 0x3c5987, - 0x3a28c6, - 0x2730c6, - 0x22d606, - 0x34c889, - 0x3b604a, - 0x2c58c5, - 0x3d6f8d, - 0x2abb46, - 0x23c346, - 0x2e6f86, - 0x21e5c5, - 0x2f1507, - 0x228ec7, - 0x27390e, - 0x23c803, - 0x2d5909, - 0x297289, - 0x22d287, - 0x26bbc7, - 0x2919c5, - 0x367b05, - 0x5f60210f, - 0x2db607, - 0x2db7c8, - 0x2dbb84, - 0x2dc046, - 0x5fa45402, - 0x2e01c6, - 0x2e2406, - 0x29744e, - 0x2e378a, - 0x207106, - 0x2b7c0a, - 0x3c7709, - 0x2fbe85, - 0x2ee188, - 0x3cbb46, - 0x2b7188, - 0x202ac8, - 0x277fcb, - 0x395f85, - 0x26f748, - 0x3dda4c, - 0x301207, - 0x24eb46, - 0x30c2c8, - 0x3de888, - 0x5fe30a42, - 0x21504b, - 0x205c89, - 0x28d989, - 0x21c647, - 0x3b5dc8, - 0x603d32c8, - 0x20934b, - 0x349bc9, - 0x25b18d, - 0x202908, - 0x2f1008, - 0x60604042, - 0x20d5c4, - 0x60a2aec2, - 0x3cd9c6, - 0x60e01282, - 0x2fbc8a, - 0x2a3806, - 0x34bd48, - 0x3c6908, - 0x3d9746, - 0x2ba946, - 0x3054c6, - 0x2ab045, - 0x239e44, - 0x6122ae04, - 0x359946, - 0x276247, - 0x6160d8c7, - 0x278b4b, - 0x295589, - 0x27bc0a, - 0x26d804, - 0x2f3b08, - 0x38e14d, - 0x2fc409, - 0x2fc648, - 0x2fc8c9, - 0x2fe7c4, - 0x2aae04, - 0x38d205, - 0x346f0b, - 0x36f606, - 0x359785, - 0x236209, - 0x31e6c8, - 0x22af84, - 0x327249, - 0x24a345, - 0x2dbdc8, - 0x2cd8c7, - 0x2889c8, - 0x281006, - 0x3ba447, - 0x2e6b09, - 0x3c9289, - 0x21d705, - 0x3682c5, - 0x61a1e342, - 0x31b244, - 0x21fe85, - 0x395d86, - 0x346905, - 0x244b07, - 0x359a45, - 0x276844, - 0x3487c6, - 0x254587, - 0x238f46, - 0x30a945, - 0x217108, - 0x35c7c5, - 0x21a847, - 0x2277c9, - 0x2b358a, - 0x264cc7, - 0x264ccc, - 0x265406, - 0x2423c9, - 0x31f045, - 0x369188, - 0x211ec3, - 0x398c45, - 0x3b9285, - 0x27b207, - 0x61e08dc2, - 0x2f8087, - 0x2eea86, - 0x38dc46, - 0x2f6146, - 0x3de7c6, - 0x230988, - 0x2d0145, - 0x31e1c7, - 0x31e1cd, - 0x210883, - 0x3d28c5, - 0x270007, - 0x2f83c8, - 0x26fbc5, - 0x214408, - 0x37cf06, - 0x2e50c7, - 0x2d4605, - 0x396006, - 0x393c45, - 0x20ba0a, - 0x310586, - 0x2645c7, - 0x2c9485, - 0x3a8a87, - 0x3cdb04, - 0x30e146, - 0x3cba85, - 0x39a18b, - 0x2f0689, - 0x27ef0a, - 0x21d788, - 0x314248, - 0x31968c, - 0x31adc7, - 0x330a08, - 0x335d88, - 0x3382c5, - 0x358dca, - 0x361049, - 0x62203242, - 0x2945c6, - 0x25c9c4, - 0x2fa949, - 0x35d749, - 0x2451c7, - 0x29b947, - 0x2bfb09, - 0x2ffe08, - 0x2ffe0f, - 0x21b5c6, - 0x2e4bcb, - 0x259dc5, - 0x259dc7, - 0x37bd49, - 0x20c8c6, - 0x3271c7, - 0x2e9105, - 0x230484, - 0x2f5006, - 0x220904, - 0x2f9c47, - 0x321c88, - 0x6270bb08, + 0x2ce4c6, + 0x2f7986, + 0x30820a, + 0x3a0e06, + 0x3aa945, + 0x2e95c5, + 0x2e95c7, + 0x3adc0c, + 0x25720a, + 0x294d06, + 0x2e4185, + 0x303886, + 0x294fc7, + 0x296986, + 0x298dcc, + 0x222dc9, + 0x5f626207, + 0x29ae85, + 0x29ae86, + 0x29bb48, + 0x2ca185, + 0x2ac785, + 0x2ad148, + 0x2ad34a, + 0x5fa295c2, + 0x5fe0b942, + 0x309d85, + 0x26a483, + 0x32a308, + 0x210503, + 0x2ad5c4, + 0x35d30b, + 0x2a78c8, + 0x384648, + 0x6034b7c9, + 0x2b48c9, + 0x2b51c6, + 0x2b6b48, + 0x2b6d49, + 0x2b7a86, + 0x2b7c05, + 0x248486, + 0x2b8589, + 0x2cd607, + 0x394746, + 0x21b347, + 0x2014c7, + 0x213f04, + 0x6067f8c9, + 0x2bcec8, + 0x2bb088, + 0x200e07, + 0x2d7c86, + 0x205a89, + 0x24e6c7, + 0x3c250a, + 0x3c8108, + 0x2131c7, + 0x2180c6, + 0x2a114a, + 0x32a708, + 0x2f7405, + 0x225a05, + 0x3d12c7, + 0x3264c9, + 0x32878b, + 0x39be48, + 0x37ec09, + 0x250487, + 0x2c94cc, + 0x2c9d4c, + 0x2ca04a, + 0x2ca2cc, + 0x2d3d88, + 0x2d3f88, + 0x2d4184, + 0x2d4549, + 0x2d4789, + 0x2d49ca, + 0x2d4c49, + 0x2d4fc7, + 0x3c91cc, + 0x3dc686, + 0x2723c8, + 0x26d786, + 0x3957c6, + 0x397347, + 0x3a8708, + 0x22a28b, + 0x206b87, + 0x257809, + 0x288349, + 0x2a4e07, + 0x2e9344, + 0x269087, + 0x39b786, + 0x2128c6, + 0x2ed205, + 0x2f9848, + 0x317044, + 0x317046, + 0x2570cb, + 0x2af909, + 0x385c06, + 0x267a49, + 0x210206, + 0x249088, + 0x20eb03, + 0x30da85, + 0x219849, + 0x214445, + 0x3b9e84, + 0x3d25c6, + 0x308005, + 0x20a686, + 0x31d587, + 0x355006, + 0x22c6cb, + 0x2040c7, + 0x3a9c46, + 0x278c86, + 0x22f646, + 0x26b749, + 0x3b5e0a, + 0x2cb445, + 0x205e0d, + 0x2ad446, + 0x239446, + 0x2e8b06, + 0x220d45, + 0x2f2107, + 0x30b4c7, + 0x2794ce, + 0x23cb03, + 0x2d7c49, + 0x324b49, + 0x22f2c7, + 0x271a47, + 0x2703c5, + 0x294145, + 0x60bb494f, + 0x2ddc07, + 0x2dddc8, + 0x2de184, + 0x2de646, + 0x60e46b42, + 0x2e2386, + 0x2e4806, + 0x3b564e, + 0x2f510a, + 0x2bb906, + 0x218d4a, + 0x203889, + 0x23c7c5, + 0x312d08, + 0x33dd86, + 0x2ba948, + 0x36aac8, + 0x28238b, + 0x39cc05, + 0x2762c8, + 0x20318c, + 0x302f47, + 0x24f986, + 0x30e908, + 0x229f48, + 0x6123bec2, + 0x20c70b, + 0x209089, + 0x2bf709, + 0x21a747, + 0x3c3088, + 0x6161cf48, + 0x21d84b, + 0x34bd89, + 0x28be0d, + 0x3802c8, + 0x2a1348, + 0x61a09282, + 0x228644, + 0x61e30242, + 0x3b9cc6, + 0x62200e42, + 0x2fd7ca, + 0x364486, + 0x267388, + 0x3cea88, + 0x3e1bc6, + 0x2c06c6, + 0x306246, + 0x2acc85, + 0x239dc4, + 0x62768e04, + 0x35f2c6, + 0x277a47, + 0x62a810c7, + 0x24ed8b, + 0x206ec9, + 0x33640a, + 0x2f4dc4, + 0x2e9708, + 0x39450d, + 0x2fe709, + 0x2fe948, + 0x2febc9, + 0x300ac4, + 0x266344, + 0x393505, + 0x33f0cb, + 0x2a7846, + 0x35f105, + 0x236dc9, + 0x2d2548, + 0x2aa9c4, + 0x316549, + 0x3c22c5, + 0x2de3c8, + 0x355f87, + 0x348bc8, + 0x288a06, + 0x20f5c7, + 0x2e8689, + 0x3c33c9, + 0x226705, + 0x23b4c5, + 0x62e13242, + 0x321744, + 0x232345, + 0x39ca06, + 0x33eac5, + 0x23fa07, + 0x35f3c5, + 0x27c5c4, + 0x371306, + 0x247bc7, + 0x238e46, 0x30c645, - 0x30c787, - 0x324389, - 0x20d184, - 0x241048, - 0x62bd0448, - 0x2e6f04, - 0x31d648, - 0x295a04, - 0x3b6349, - 0x21e505, - 0x62e33442, - 0x21b605, - 0x2dd945, - 0x289548, - 0x233a07, - 0x632008c2, - 0x22af45, - 0x2de0c6, - 0x243906, - 0x31b208, - 0x338fc8, - 0x3468c6, - 0x34afc6, - 0x306a09, - 0x38db86, - 0x20c78b, - 0x3c2705, - 0x2ac8c6, - 0x3c4a88, - 0x33f6c6, - 0x224786, - 0x216bca, - 0x2df94a, - 0x248a45, - 0x30ce07, - 0x274586, - 0x63603642, - 0x270147, - 0x33c305, - 0x304584, - 0x304585, - 0x2f3a06, - 0x272c47, - 0x203945, - 0x2dfac4, - 0x352248, - 0x224845, - 0x37ae87, - 0x3ca445, - 0x20b945, - 0x2d2904, - 0x2d2909, - 0x2ff2c8, - 0x23a5c6, - 0x35aa06, - 0x302d06, - 0x63bd5b08, - 0x311d07, - 0x31234d, - 0x312f0c, - 0x313509, - 0x313749, - 0x63f75442, - 0x3d4a03, - 0x2010c3, - 0x2f08c5, - 0x3a784a, - 0x338e86, - 0x23cec5, - 0x31a504, - 0x31a50b, - 0x32d64c, - 0x32df0c, - 0x32e215, - 0x32f70d, - 0x33208f, - 0x332452, - 0x3328cf, - 0x332c92, - 0x333113, - 0x3335cd, - 0x333b8d, - 0x333f0e, - 0x33480e, - 0x334e0c, - 0x3351cc, - 0x33560b, - 0x33668e, - 0x336f92, - 0x338c4c, - 0x3391d0, - 0x34cfd2, - 0x34e08c, - 0x34e74d, - 0x34ea8c, - 0x351591, - 0x35280d, - 0x3546cd, - 0x354cca, - 0x354f4c, - 0x35890c, - 0x35948c, - 0x359e8c, - 0x35df93, - 0x35e710, - 0x35eb10, - 0x35f10d, - 0x35f70c, - 0x360549, - 0x36224d, - 0x362593, - 0x364111, - 0x364913, - 0x36560f, - 0x3659cc, - 0x365ccf, - 0x36608d, - 0x36668f, - 0x366a50, - 0x3674ce, - 0x36b40e, - 0x36ba90, - 0x36d08d, - 0x36da0e, - 0x36dd8c, - 0x36ed53, - 0x37268e, - 0x372c10, - 0x373011, - 0x37344f, - 0x373813, - 0x374fcd, - 0x37530f, - 0x3756ce, - 0x375c50, - 0x376049, - 0x3773d0, - 0x3778cf, - 0x377f4f, - 0x378312, - 0x3792ce, - 0x37a00d, - 0x37a54d, - 0x37a88d, - 0x37bf8d, - 0x37c2cd, - 0x37c610, - 0x37ca0b, - 0x37d24c, - 0x37d5cc, - 0x37dbcc, - 0x37dece, - 0x38d350, - 0x38f7d2, - 0x38fc4b, - 0x39078e, - 0x390b0e, - 0x39138e, - 0x39190b, - 0x64391d96, - 0x39268d, - 0x393214, - 0x393f0d, - 0x3955d5, - 0x3978cd, - 0x39824f, - 0x398e0f, - 0x39c24f, - 0x39c60e, - 0x39c98d, - 0x39e251, - 0x3a084c, - 0x3a0b4c, - 0x3a0e4b, - 0x3a128c, - 0x3a1ccf, - 0x3a2092, - 0x3a2bcd, - 0x3a470c, - 0x3a500c, - 0x3a530d, - 0x3a564f, - 0x3a5a0e, - 0x3a750c, - 0x3a7acd, - 0x3a7e0b, - 0x3a8c4c, - 0x3a954d, - 0x3a988e, - 0x3a9c09, - 0x3abb53, - 0x3ac94d, - 0x3ad04d, - 0x3ad64c, - 0x3ae88e, - 0x3aef8f, - 0x3af34c, - 0x3af64d, - 0x3af98f, - 0x3afd4c, - 0x3b034c, - 0x3b080c, - 0x3b0b0c, - 0x3b35cd, - 0x3b3912, - 0x3b45cc, - 0x3b48cc, - 0x3b4bd1, - 0x3b500f, - 0x3b53cf, - 0x3b5793, - 0x3b6f8e, - 0x3b730f, - 0x3b76cc, - 0x647b7d8e, - 0x3b810f, - 0x3b84d6, - 0x3bae52, - 0x3bcccc, - 0x3bdb8f, - 0x3be20d, - 0x3c94cf, - 0x3c988c, - 0x3c9b8d, - 0x3c9ecd, - 0x3cb4ce, - 0x3cc38c, - 0x3ceecc, - 0x3cf1d0, - 0x3d3d91, - 0x3d41cb, - 0x3d460c, - 0x3d490e, - 0x3d6011, - 0x3d644e, - 0x3d67cd, - 0x3dbc0b, - 0x3dc88f, - 0x3dd454, - 0x23c782, - 0x23c782, - 0x23e083, - 0x23c782, - 0x23e083, - 0x23c782, - 0x203802, - 0x246c45, - 0x3d5d0c, - 0x23c782, - 0x23c782, - 0x203802, - 0x23c782, - 0x29b485, - 0x2b3585, - 0x23c782, - 0x23c782, - 0x201542, - 0x29b485, - 0x32fec9, - 0x363e0c, - 0x23c782, - 0x23c782, - 0x23c782, - 0x23c782, - 0x246c45, - 0x23c782, - 0x23c782, - 0x23c782, - 0x23c782, - 0x201542, - 0x32fec9, - 0x23c782, - 0x23c782, - 0x23c782, - 0x2b3585, - 0x23c782, - 0x2b3585, - 0x363e0c, - 0x3d5d0c, - 0x202703, - 0x214a83, - 0x232dc3, - 0x308003, - 0x221dc4, - 0x21a3c3, - 0x242543, - 0x1d904f, - 0x145988, - 0x1a704, - 0x3dc3, - 0x86808, - 0x1cc203, - 0x2000c2, - 0x65601242, - 0x240983, - 0x224c84, - 0x207083, - 0x384584, - 0x22f7c6, - 0x310c83, - 0x310c44, - 0x2f0b05, - 0x23c803, - 0x21a3c3, - 0x1b4103, - 0x242543, - 0x21e2ca, - 0x252b06, - 0x390e8c, - 0x9a048, - 0x201242, - 0x214a83, - 0x232dc3, - 0x308003, - 0x2137c3, - 0x2e2406, - 0x21a3c3, - 0x242543, - 0x2141c3, - 0x2fb03, - 0xac508, - 0x661d2145, - 0x47d47, - 0x139b05, - 0x156c9, - 0x1742, - 0x13a14a, - 0x66fa0505, - 0x139b05, - 0x29907, - 0x6dfc8, - 0x9c4e, - 0x8b392, - 0x9630b, - 0x10d806, - 0x6728d505, - 0x6768d50c, - 0x13d547, - 0x17e707, - 0x12364a, - 0x3be50, - 0x146145, - 0x10fe4b, - 0x79108, - 0x25687, - 0x2490b, - 0x33249, - 0x46e07, - 0x15c087, - 0xc2487, - 0x34a06, - 0x106c8, - 0x67c28886, - 0x47207, - 0x18ec46, - 0x78d8d, - 0xf3c90, - 0x680aac82, - 0xd1288, - 0x40350, - 0x17f5cc, - 0x687825cd, - 0x5a988, - 0x5ae0b, - 0x6b187, - 0x70749, - 0x56306, - 0x9b008, - 0x3ee42, - 0x9218a, - 0x157647, - 0x107c07, - 0xacdc9, - 0xaff88, - 0xf3605, - 0x18d986, - 0x1ba1c6, - 0xfd84e, - 0xaf88e, - 0x3874f, - 0x41a89, - 0xf0c09, - 0x91d0b, - 0xb3b4f, - 0xbd08c, - 0xca18b, - 0x131388, - 0x171887, - 0x197088, - 0xb580b, - 0xb5bcc, - 0xb5fcc, - 0xb63cc, - 0xb66cd, - 0x1b1148, - 0x52e82, - 0x193a49, - 0x112988, - 0x19fe8b, - 0xd5b46, - 0xdda8b, - 0x136acb, - 0xe884a, - 0xea585, - 0xf1210, - 0xf5c86, - 0x184806, - 0x97805, - 0x91487, - 0xe0448, - 0xf92c7, - 0xf9587, - 0x12c807, - 0xc7346, - 0x1cd80a, - 0x99eca, - 0x11ec6, - 0xb130d, - 0x472c8, - 0x115488, - 0x115cc9, - 0xc0545, - 0x1aec8c, - 0xb68cb, - 0x86fc9, - 0x1ccb44, - 0x111949, - 0x111b86, - 0x4cec6, - 0x3c686, - 0x1b82, - 0x365c6, - 0x13dacb, - 0x129187, - 0x11ac47, - 0x1442, - 0xd7445, - 0x27e04, - 0x101, - 0x4fd83, - 0x67a37806, - 0x9b383, - 0x382, - 0x26bc4, - 0xac2, - 0xd3684, - 0x882, - 0x31c2, - 0x16c2, - 0x20f82, - 0x86c2, - 0x8d502, - 0xd42, - 0x167c2, - 0x373c2, - 0x5582, - 0x2a42, - 0x4e782, - 0x32dc3, - 0x942, - 0x3c42, - 0xdec2, - 0x5dc2, - 0x642, - 0x315c2, - 0x6502, - 0x5bc2, - 0xf42, - 0x5c2, - 0x1bc83, - 0x4582, - 0x7882, - 0x49582, - 0x1e42, - 0x2042, - 0x8282, - 0x23502, - 0x17c2, - 0x9e82, - 0x3f82, - 0x6c9c2, - 0x15402, - 0x1a3c3, - 0x602, - 0x30a42, - 0x2902, - 0x1ad42, - 0x1d685, - 0xa882, - 0x14b42, - 0x3d383, - 0x682, - 0xca42, - 0x45c2, - 0x7842, - 0x2f82, - 0x8c2, - 0xc2c2, - 0x1b82, - 0x1805, - 0x68a03802, - 0x68edf283, - 0xf283, - 0x69203802, - 0xf283, - 0x74c47, - 0x201503, - 0x2000c2, - 0x214a83, - 0x232dc3, - 0x228503, - 0x2005c3, - 0x2137c3, - 0x21a3c3, - 0x203dc3, - 0x242543, - 0x29b3c3, - 0xc0584, - 0x19405, - 0x104305, - 0x3a83, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x228503, - 0x23c803, - 0x21a3c3, - 0x203dc3, - 0x1b4103, - 0x242543, - 0x214a83, - 0x232dc3, - 0x242543, - 0x214a83, - 0x232dc3, - 0x308003, - 0x200181, - 0x23c803, - 0x21a3c3, - 0x24e283, - 0x242543, - 0x69944, - 0x202703, - 0x214a83, - 0x232dc3, - 0x218bc3, - 0x228503, - 0x2c26c3, - 0x208943, - 0x2a37c3, - 0x216243, - 0x308003, - 0x221dc4, - 0x21a3c3, - 0x242543, - 0x207783, - 0x204244, - 0x24f603, - 0x20dc3, - 0x29cfc3, - 0x328fc8, - 0x2f0e44, - 0x20020a, - 0x235406, - 0x124184, - 0x3a71c7, - 0x21ec8a, - 0x21b489, - 0x3bb287, - 0x3c024a, - 0x202703, - 0x35604b, - 0x216189, - 0x2f4245, - 0x3b0647, - 0x1242, - 0x214a83, - 0x20fcc7, - 0x263bc5, - 0x2cc8c9, - 0x232dc3, - 0x373ec6, - 0x2cb983, - 0xeeb03, - 0x118f86, - 0x98186, - 0x1d3bc7, - 0x212286, - 0x220fc5, - 0x205b47, - 0x316507, - 0x6bf08003, - 0x34e2c7, - 0x23c783, - 0x3d3905, - 0x221dc4, - 0x26f3c8, - 0x385acc, - 0x2b8d05, - 0x2aa446, - 0x20fb87, - 0x3b9887, - 0x3a2a07, - 0x248b48, - 0x317ccf, - 0x21b6c5, - 0x240a87, - 0x28e747, - 0x276e0a, - 0x37b549, - 0x3dd185, - 0x3212ca, - 0xc4ac6, - 0xc0a07, - 0x2cba05, - 0x2f6684, - 0x3d9686, - 0x101406, - 0x37f847, - 0x252d87, - 0x33b388, - 0x218405, - 0x263ac6, - 0x156ec8, - 0x2e3d85, - 0xe3f46, - 0x3268c5, - 0x28ce44, - 0x24a407, - 0x2307ca, - 0x23ab88, - 0x288e06, - 0x137c3, - 0x2ec0c5, - 0x320506, - 0x3bee46, - 0x297706, - 0x23c803, - 0x3a2e47, - 0x28e6c5, - 0x21a3c3, - 0x2e8b0d, - 0x203dc3, - 0x33b488, - 0x213484, - 0x276b05, - 0x2abd06, - 0x205406, - 0x2ac7c7, - 0x25b047, - 0x350ac5, - 0x242543, - 0x271d87, - 0x371989, - 0x2708c9, - 0x384a4a, - 0x215542, - 0x3d38c4, - 0x2fb304, - 0x2f7c07, - 0x2f7f48, - 0x2fa3c9, - 0x3d2789, - 0x2fadc7, - 0x109049, - 0x362f06, - 0xfd5c6, - 0x2fe7c4, - 0x22cf8a, - 0x302448, - 0x305389, - 0x305946, - 0x2bc745, - 0x23aa48, - 0x2d5dca, - 0x32bf03, - 0x2043c6, - 0x2faec7, - 0x35a785, - 0x3b4045, - 0x2432c3, - 0x23e804, - 0x227b45, - 0x2848c7, - 0x2ff405, - 0x2ff846, - 0x111e85, - 0x2071c3, - 0x2071c9, - 0x2768cc, - 0x2c61cc, - 0x3444c8, - 0x2ab3c7, - 0x30d588, - 0x10e747, - 0x30eaca, - 0x30f18b, - 0x2162c8, - 0x205508, - 0x22b686, - 0x302bc5, - 0x25d70a, - 0x2df2c5, - 0x233442, - 0x2d44c7, - 0x253c46, - 0x376785, - 0x310949, - 0x2d0405, - 0x372185, - 0x3c2409, - 0x320446, - 0x201348, - 0x3d39c3, - 0x20aa46, - 0x275c86, - 0x31cd05, - 0x31cd09, - 0x2c4709, - 0x25d487, - 0x11cb84, - 0x31cb87, - 0x3d2689, + 0x214048, + 0x361a85, + 0x21e147, + 0x225209, + 0x2afa4a, + 0x266f07, + 0x266f0c, + 0x267c46, + 0x23df09, + 0x248085, + 0x2d2ec8, + 0x202443, + 0x2f2d05, + 0x3c0e45, + 0x282fc7, + 0x63201242, + 0x2f9b87, + 0x2f0906, + 0x3862c6, + 0x2f2586, + 0x229e86, + 0x23be08, + 0x27e105, + 0x2d2047, + 0x2d204d, + 0x20ee43, + 0x3dcb45, + 0x276b87, + 0x2f9ec8, + 0x276745, + 0x216bc8, + 0x382e86, + 0x29c107, + 0x2d6945, + 0x39cc86, + 0x399445, + 0x21ef4a, + 0x301b46, + 0x274587, + 0x2ce285, + 0x310687, + 0x35a584, + 0x3b9e06, + 0x312c45, + 0x33544b, + 0x39b609, + 0x281cca, + 0x226788, + 0x393f88, + 0x31408c, + 0x3d8d07, + 0x31c848, + 0x31ecc8, + 0x32b9c5, + 0x35c18a, + 0x35f4c9, + 0x63600ec2, + 0x20b086, + 0x260d44, + 0x2fc549, + 0x240e89, + 0x246907, + 0x27bfc7, + 0x29cd49, + 0x33e348, + 0x33e34f, + 0x22d606, + 0x2e6ccb, + 0x256845, + 0x256847, + 0x381cc9, + 0x21fe06, + 0x3164c7, + 0x2eb805, + 0x232004, + 0x307ec6, + 0x206244, + 0x3ba247, + 0x3792c8, + 0x63b0d808, + 0x30fa05, + 0x30fb47, + 0x3532c9, + 0x20c4c4, + 0x241948, + 0x63e653c8, + 0x2e8a84, + 0x2f6dc8, + 0x25f184, + 0x206109, + 0x220c85, + 0x6422dc42, + 0x22d645, + 0x2dfd45, + 0x2600c8, + 0x234c07, + 0x646008c2, + 0x3c7a85, + 0x2e04c6, + 0x24d186, + 0x321708, + 0x31f148, + 0x33ea86, + 0x34a046, + 0x30a149, + 0x386206, + 0x21fccb, + 0x229d05, + 0x2af286, + 0x368048, + 0x34ae46, + 0x2bc246, + 0x2178ca, + 0x2e1b0a, + 0x23eb45, + 0x29c787, + 0x27a146, + 0x64a034c2, + 0x276cc7, + 0x367145, + 0x305304, + 0x305305, + 0x2f4cc6, + 0x278807, + 0x21ac85, + 0x240f44, + 0x2c3708, + 0x2bc305, + 0x37a987, + 0x3808c5, 0x21ee85, - 0x39f48, - 0x349845, - 0x353885, - 0x39b489, - 0x204b42, - 0x357204, - 0x209282, - 0x204582, - 0x2ed985, - 0x323f08, - 0x2c0485, - 0x2ced43, - 0x2ced45, - 0x2e03c3, - 0x20a742, - 0x2b4384, - 0x269f03, + 0x245744, + 0x245749, + 0x3015c8, + 0x359586, + 0x358846, + 0x363f06, + 0x64fcfc08, + 0x3d8b87, + 0x31474d, + 0x314f0c, + 0x315509, + 0x315749, + 0x65379942, + 0x3d7403, + 0x20e483, + 0x39b845, + 0x3af90a, + 0x33e946, + 0x2365c5, + 0x31e244, + 0x31e24b, + 0x33384c, + 0x33410c, + 0x334415, + 0x335e0d, + 0x337e8f, + 0x338252, + 0x3386cf, + 0x338a92, + 0x338f13, + 0x3393cd, + 0x33998d, + 0x339d0e, + 0x33a60e, + 0x33ac0c, + 0x33afcc, + 0x33b40b, + 0x33be8e, + 0x33c792, + 0x33e70c, + 0x3403d0, + 0x34e4d2, + 0x34f54c, + 0x34fc0d, + 0x34ff4c, + 0x3524d1, + 0x35398d, + 0x35ae4d, + 0x35b44a, + 0x35b6cc, + 0x35e60c, + 0x35ee0c, + 0x35f70c, + 0x362e93, + 0x363610, + 0x363a10, + 0x36460d, + 0x364c0c, + 0x365a49, + 0x3697cd, + 0x369b13, + 0x36b451, + 0x36bc53, + 0x36c94f, + 0x36cd0c, + 0x36d00f, + 0x36d3cd, + 0x36d9cf, + 0x36dd90, + 0x36e80e, + 0x37198e, + 0x3722d0, + 0x37318d, + 0x373b0e, + 0x373e8c, + 0x374fd3, + 0x37768e, + 0x377c10, + 0x378011, + 0x37844f, + 0x378813, + 0x3794cd, + 0x37980f, + 0x379bce, + 0x37a150, + 0x37a549, + 0x37bc90, + 0x37c18f, + 0x37c80f, + 0x37cbd2, + 0x37f68e, + 0x3804cd, + 0x380a0d, + 0x380d4d, + 0x381f0d, + 0x38224d, + 0x382590, + 0x38298b, + 0x3831cc, + 0x38354c, + 0x383b4c, + 0x383e4e, + 0x393650, + 0x395112, + 0x39558b, + 0x395f8e, + 0x39630e, + 0x396b8e, + 0x39710b, + 0x65797596, + 0x397e8d, + 0x398a14, + 0x39970d, + 0x39c255, + 0x39ea0d, + 0x39f38f, + 0x39fb4f, + 0x3a2bcf, + 0x3a2f8e, + 0x3a330d, + 0x3a4891, + 0x3a7ecc, + 0x3a81cc, + 0x3a84cb, + 0x3a890c, + 0x3a904f, + 0x3a9412, + 0x3aa1cd, + 0x3abe8c, + 0x3acc4c, + 0x3acf4d, + 0x3ad28f, + 0x3ad64e, + 0x3af5cc, + 0x3afb8d, + 0x3afecb, + 0x3b078c, + 0x3b108d, + 0x3b13ce, + 0x3b1749, + 0x3b2dd3, + 0x3b688d, + 0x3b6f8d, + 0x3b758c, + 0x3b7c0e, + 0x3b830f, + 0x3b86cc, + 0x3b89cd, + 0x3b8d0f, + 0x3b90cc, + 0x3ba40c, + 0x3ba8cc, + 0x3babcc, + 0x3bbb8d, + 0x3bbed2, + 0x3bc64c, + 0x3bc94c, + 0x3bcc51, + 0x3bd08f, + 0x3bd44f, + 0x3bd813, + 0x3be60e, + 0x3be98f, + 0x3bed4c, + 0x65bbf40e, + 0x3bf78f, + 0x3bfb56, + 0x3c1bd2, + 0x3c440c, + 0x3c4d8f, + 0x3c540d, + 0x3cec8f, + 0x3cf04c, + 0x3cf34d, + 0x3cf68d, + 0x3d0d4e, + 0x3d19cc, + 0x3d420c, + 0x3d4510, + 0x3d6791, + 0x3d6bcb, + 0x3d700c, + 0x3d730e, + 0x3d91d1, + 0x3d960e, + 0x3d998d, + 0x3de2cb, + 0x3debcf, + 0x3dfa54, + 0x23ca82, + 0x23ca82, + 0x203183, + 0x23ca82, + 0x203183, + 0x23ca82, + 0x201082, + 0x2484c5, + 0x3d8ecc, + 0x23ca82, + 0x23ca82, + 0x201082, + 0x23ca82, + 0x29c945, + 0x2afa45, + 0x23ca82, + 0x23ca82, + 0x208a02, + 0x29c945, + 0x336689, + 0x36b14c, + 0x23ca82, + 0x23ca82, + 0x23ca82, + 0x23ca82, + 0x2484c5, + 0x23ca82, + 0x23ca82, + 0x23ca82, + 0x23ca82, + 0x208a02, + 0x336689, + 0x23ca82, + 0x23ca82, + 0x23ca82, + 0x2afa45, + 0x23ca82, + 0x2afa45, + 0x36b14c, + 0x3d8ecc, + 0x24ac43, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x20e704, + 0x217fc3, + 0x23e083, + 0x1e14cf, + 0x1b4508, + 0x6704, + 0x5803, + 0x8efc8, + 0x1d1843, + 0x2000c2, + 0x66a12402, + 0x241283, + 0x25a584, + 0x2033c3, + 0x38a0c4, + 0x231346, + 0x222743, + 0x3d2484, + 0x3517c5, + 0x23cb03, + 0x217fc3, + 0x1c0443, + 0x23e083, + 0x226e0a, + 0x2509c6, + 0x39668c, + 0xae888, + 0x212402, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x215f83, + 0x2e4806, + 0x217fc3, + 0x23e083, + 0x216983, + 0xe783, + 0xaeec8, + 0x675dc3c5, + 0x49647, + 0x146bc5, + 0xcd89, + 0x8c02, + 0x1c73ca, + 0x683a7b85, + 0x146bc5, + 0x1683c7, + 0x74f88, + 0xb74e, + 0x90d92, + 0x123bcb, + 0x110ac6, + 0x686bd285, + 0x68abf28c, + 0x149147, + 0x178d87, + 0x127eca, + 0x3c290, + 0x1645, + 0xc634b, + 0x10f508, + 0x35cc7, + 0xbc3cb, + 0x34449, + 0x48687, + 0x161347, + 0xef347, + 0x35c06, + 0xec88, + 0x69036fc6, + 0x3dc87, + 0x176b06, + 0x4efcd, + 0xe9890, + 0x694293c2, + 0x7f248, + 0x8c550, + 0x184e8c, + 0x69b8794d, + 0x5a388, + 0x5a80b, + 0x71007, + 0x96d89, + 0x56546, + 0x9bd48, + 0x5b542, + 0x1b21ca, + 0x65a87, + 0xb4e07, + 0xafcc9, + 0xb3108, + 0xf48c5, + 0x193c86, + 0x1c2e06, + 0xffb4e, + 0xef90e, + 0x18ee0f, + 0x33449, + 0x860c9, + 0x1b1d4b, + 0xb538f, + 0xc470c, + 0xcfe0b, + 0x11d1c8, + 0x16f747, + 0x194c88, + 0x1a8c8b, + 0xb920c, + 0xb960c, + 0xb9a0c, + 0xb9d0d, + 0x1bb208, + 0x50d42, + 0x199249, + 0x15d048, + 0x1de00b, + 0xd7e86, + 0xdfe8b, + 0x13c2cb, + 0xeaf4a, + 0xec7c5, + 0xf1e10, + 0xf6a46, + 0x155146, + 0x1b5a05, + 0x19dfc7, + 0xe2608, + 0xfadc7, + 0xfb087, + 0x1416c7, + 0xccec6, + 0x1b9b0a, + 0xae70a, + 0x13a06, + 0xb4bcd, + 0x3dd48, + 0x118088, + 0x1188c9, + 0xc7c05, + 0x1b800c, + 0xb9f0b, + 0x15ca49, + 0x1d1204, + 0x114389, + 0x1145c6, + 0x156786, + 0x3c986, + 0x72c2, + 0x134c46, + 0x1496cb, + 0x11e987, + 0x11eb47, + 0x3602, + 0xd9785, + 0x2de44, + 0x101, + 0x506c3, + 0x68e6a646, + 0x9c0c3, + 0x382, + 0x2b104, + 0xac2, + 0x4cd44, + 0x882, + 0x7282, + 0x6c02, + 0x10bf02, + 0xcf02, + 0xbd282, + 0xd42, + 0x161e82, + 0x37402, + 0xda02, + 0xf982, + 0x4e682, + 0x33fc3, + 0x942, + 0x31c2, + 0xfa02, + 0x91c2, + 0x642, + 0x32702, + 0xb5c2, + 0x8fc2, + 0xf782, + 0x5c2, + 0x191c3, + 0x4b82, + 0x22c2, + 0x4b202, + 0x6902, + 0x2702, + 0xa682, + 0x4202, + 0x8c82, + 0xb982, + 0x193b42, + 0x720c2, + 0xcac2, + 0x17fc3, + 0x602, + 0x3bec2, + 0x2542, + 0x35c2, + 0x26685, + 0x4fc2, + 0x42c42, + 0x3d583, + 0x682, + 0xd782, + 0x2442, + 0xab02, + 0xee42, + 0x8c2, + 0x4642, + 0x72c2, + 0x8cc5, + 0x69e01082, + 0x6a2e82c3, + 0x1ac3, + 0x6a601082, + 0x1ac3, + 0x7a807, + 0x2089c3, + 0x2000c2, + 0x22ea43, + 0x233fc3, + 0x280203, + 0x2005c3, + 0x215f83, + 0x217fc3, + 0x205803, + 0x23e083, + 0x2bd443, + 0xc7c44, + 0x16acc5, + 0x105085, + 0x10103, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x280203, + 0x23cb03, + 0x217fc3, + 0x205803, + 0x1c0443, + 0x23e083, + 0x22ea43, + 0x233fc3, + 0x23e083, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x200181, + 0x23cb03, + 0x217fc3, + 0x24dfc3, + 0x23e083, + 0x2f44, + 0x24ac43, + 0x22ea43, + 0x233fc3, + 0x275243, + 0x280203, + 0x2d2a83, + 0x2381c3, + 0x2a49c3, + 0x20d903, + 0x266a83, + 0x20e704, + 0x217fc3, + 0x23e083, + 0x20aa43, + 0x207d44, + 0x25cc83, + 0x33f03, + 0x238f43, + 0x32dac8, + 0x2a1184, + 0x20020a, + 0x385986, + 0x1530c4, + 0x3bc307, + 0x21bfca, + 0x22d4c9, + 0x3c7247, + 0x3c9c8a, + 0x24ac43, + 0x309e0b, + 0x20d849, + 0x2fde05, + 0x3ba707, + 0x12402, + 0x22ea43, + 0x2264c7, + 0x224685, + 0x2e9209, + 0x233fc3, + 0x23a086, + 0x2d3383, + 0xf0983, + 0x11bf06, + 0x8886, + 0x226c7, + 0x228c86, + 0x30bf45, + 0x208f47, + 0x319107, + 0x6d266a83, + 0x34f787, + 0x23ca83, + 0x21df05, + 0x20e704, + 0x275f48, + 0x3c410c, + 0x2be385, + 0x2ac086, + 0x226387, + 0x3c1447, + 0x269207, + 0x277008, + 0x31b18f, + 0x22d705, + 0x241387, + 0x211647, + 0x3caf0a, + 0x340009, + 0x32e945, + 0x34ef0a, + 0xdd286, + 0xc8087, + 0x2d3405, + 0x2f83c4, + 0x3e1b06, + 0x14e1c6, + 0x385107, + 0x250c47, + 0x3c5f48, + 0x212a05, + 0x224586, + 0x168688, + 0x2677c5, + 0x67986, + 0x2f5b85, + 0x267704, + 0x3c2387, + 0x23bc4a, + 0x2a6688, + 0x25f986, + 0x15f83, + 0x2ee705, + 0x354bc6, + 0x3c9406, + 0x3b5906, + 0x23cb03, + 0x3aa447, + 0x2115c5, + 0x217fc3, + 0x2eb20d, + 0x205803, + 0x3c6048, + 0x215c44, + 0x27c885, + 0x2ad606, + 0x358146, + 0x2af187, + 0x2a4a07, + 0x28dfc5, + 0x23e083, + 0x36f847, + 0x38a449, + 0x325009, + 0x3624ca, + 0x201b42, + 0x21dec4, + 0x304f84, + 0x2f9707, + 0x2f9a48, + 0x2fbfc9, + 0x3dca09, + 0x2fc9c7, + 0x108589, + 0x229446, + 0xff8c6, + 0x300ac4, + 0x22efca, + 0x304b08, + 0x306109, + 0x3066c6, + 0x2c3cc5, + 0x2a6548, + 0x2d810a, + 0x204343, + 0x207ec6, + 0x2fcac7, + 0x30f6c5, + 0x3c0385, + 0x243cc3, + 0x2ddf84, + 0x2259c5, + 0x28c247, + 0x301705, + 0x2f72c6, + 0x121dc5, + 0x288d83, + 0x2bb9c9, + 0x27c64c, + 0x2cbd4c, + 0x37f088, + 0x2a9f87, + 0x310848, + 0x111507, + 0x31188a, + 0x311f4b, + 0x20d988, + 0x358248, + 0x2524c6, + 0x31fdc5, + 0x25c4ca, + 0x2e8305, + 0x22dc42, + 0x2d6807, + 0x269f86, + 0x37b205, + 0x3d2189, + 0x27e3c5, + 0x388a05, + 0x229a09, + 0x325a46, + 0x37de88, + 0x270103, + 0x228dc6, + 0x3d2506, + 0x32dc85, + 0x32dc89, + 0x2ca889, + 0x25c247, + 0x120f44, + 0x320f47, + 0x3dc909, + 0x21c1c5, + 0x39ec8, + 0x37e245, + 0x371145, + 0x3b3609, + 0x201802, + 0x366984, + 0x20d2c2, + 0x204b82, + 0x320245, + 0x352e48, + 0x2c7b45, + 0x2d5183, + 0x2d5185, + 0x2e2583, + 0x20e202, + 0x2b5bc4, + 0x273cc3, 0x200a82, - 0x3b17c4, - 0x309703, - 0x20cb42, - 0x2c0503, - 0x211e44, - 0x305ac3, - 0x255544, - 0x205142, - 0x2140c3, - 0x21ab03, - 0x2071c2, - 0x294ec2, - 0x2c4549, - 0x205b02, - 0x28bec4, - 0x206542, - 0x23a8c4, - 0x362ec4, - 0x3b4384, - 0x201b82, - 0x22b2c2, - 0x22db03, - 0x29cec3, - 0x3269c4, - 0x3aa684, - 0x2dae84, - 0x2ea884, - 0x31bcc3, - 0x312743, - 0x2c4a44, - 0x31f184, - 0x31f2c6, - 0x21d642, - 0x1242, - 0x41483, - 0x201242, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x6c05, + 0x2c1704, + 0x308c43, + 0x204ac2, + 0x2c7bc3, + 0x213984, + 0x306843, + 0x253cc4, + 0x207742, + 0x216883, + 0x218e43, + 0x2018c2, + 0x25cdc2, + 0x2ca6c9, + 0x208f02, + 0x291bc4, + 0x208742, + 0x3a9e44, + 0x229404, + 0x22aac4, + 0x2072c2, + 0x23d882, + 0x32aa83, + 0x26ac43, + 0x270184, + 0x2c7504, + 0x2ecac4, + 0x2fcc44, + 0x3210c3, + 0x35ce03, + 0x2dd204, + 0x3252c4, + 0x325406, + 0x226642, + 0x12402, + 0x41d83, + 0x212402, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x110c5, 0x2000c2, - 0x202703, - 0x214a83, - 0x232dc3, - 0x209b03, - 0x308003, - 0x221dc4, - 0x2c4804, - 0x219a04, - 0x21a3c3, - 0x242543, - 0x2141c3, - 0x2fedc4, - 0x297a83, - 0x2ad843, - 0x37a2c4, - 0x349646, - 0x210603, - 0x139b05, - 0x17e707, - 0x2d2c43, - 0x6da46f08, - 0x2532c3, - 0x2bb143, - 0x25cc03, - 0x2137c3, - 0x3c0ac5, - 0x1b0603, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x20a883, - 0x22ee03, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21bc83, - 0x21a3c3, - 0x2801c4, - 0x1b4103, - 0x242543, - 0x24a004, - 0x139b05, - 0x2c8f85, - 0x17e707, - 0x201242, - 0x2052c2, + 0x24ac43, + 0x22ea43, + 0x233fc3, + 0x203983, + 0x266a83, + 0x20e704, + 0x2ca984, + 0x21e484, + 0x217fc3, + 0x23e083, + 0x216983, + 0x3010c4, + 0x32f643, + 0x2b0743, + 0x380784, + 0x37e046, + 0x20ebc3, + 0x146bc5, + 0x178d87, + 0x226dc3, + 0x6ee10c08, + 0x24cbc3, + 0x2c1183, + 0x21df43, + 0x215f83, + 0x3c7985, + 0x1ba6c3, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x210043, + 0x230743, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x2191c3, + 0x217fc3, + 0x2878c4, + 0x1c0443, + 0x23e083, + 0x25d244, + 0x146bc5, + 0x2ce8c5, + 0x178d87, + 0x212402, + 0x204542, 0x200382, - 0x208482, - 0x3dc3, + 0x203182, + 0x5803, 0x2003c2, - 0x4f04, - 0x214a83, - 0x235b44, - 0x232dc3, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x242543, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x219a04, - 0x21a3c3, - 0x3dc3, - 0x242543, - 0x20e2c3, - 0x2d3684, - 0x9a048, - 0x214a83, - 0x203dc3, - 0x3a83, - 0x122504, - 0x24c0c4, - 0x9a048, - 0x214a83, - 0x24d9c4, - 0x221dc4, - 0x203dc3, - 0x204042, - 0x1b4103, - 0x242543, - 0x22b983, - 0x3e804, - 0x208805, - 0x233442, - 0x325e43, - 0x68b49, - 0xe5986, - 0x149948, + 0x157c44, + 0x22ea43, + 0x236704, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x23e083, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x21e484, + 0x217fc3, + 0x5803, + 0x23e083, + 0x208503, + 0x24cd44, + 0xae888, + 0x22ea43, + 0x205803, + 0x10103, + 0x126d84, + 0x241ec4, + 0xae888, + 0x22ea43, + 0x24d704, + 0x20e704, + 0x205803, + 0x209282, + 0x1c0443, + 0x23e083, + 0x235403, + 0xddf84, + 0x37b845, + 0x22dc42, + 0x32a143, + 0x2149, + 0xe7546, + 0x17e348, 0x2000c2, - 0x9a048, - 0x201242, - 0x232dc3, - 0x308003, + 0xae888, + 0x212402, + 0x233fc3, + 0x266a83, 0x2005c2, - 0x3dc3, - 0x242543, - 0x7c42, + 0x5803, + 0x23e083, + 0xa882, 0x82, 0xc2, - 0x1c0407, - 0x142c09, - 0x7aec3, - 0x9a048, - 0x20f43, - 0x713233c7, - 0x14a83, - 0x944c8, - 0x32dc3, - 0x108003, - 0x1ab9c6, - 0x1bc83, - 0x92788, - 0xcae48, - 0xcff06, - 0x3c803, - 0xd8cc8, - 0x44b83, - 0x714eb886, - 0xf1c05, - 0x32fc7, - 0x1a3c3, - 0x11003, - 0x42543, - 0xeb02, - 0x17cd0a, - 0x2cc3, - 0xeda43, - 0x10a104, - 0x117acb, - 0x118088, - 0x90602, - 0x14540c7, - 0x15636c7, - 0x14cee08, - 0x14cf583, - 0x143acb, - 0xb342, - 0x12bcc7, - 0x11b504, + 0x1c9e47, + 0x14b509, + 0x3043, + 0xae888, + 0x10bec3, + 0x72727c47, + 0x2ea43, + 0xaf88, + 0x33fc3, + 0x66a83, + 0x3fec6, + 0x191c3, + 0x56288, + 0xd0ac8, + 0x7dec6, + 0x729a7285, + 0x3cb03, + 0xdb008, + 0x3fa83, + 0x72cedbc6, + 0xf2ec5, + 0x124d04, + 0x341c7, + 0x17fc3, + 0x3443, + 0x3e083, + 0x1b02, + 0x182c8a, + 0x9c43, + 0x732c3f4c, + 0x120303, + 0x5d884, + 0x11af8b, + 0x11b548, + 0x95f42, + 0x17ff03, + 0x1454747, + 0x15b4247, + 0x14d5248, + 0x157ff03, + 0x18b7c8, + 0x156ecb, + 0x10382, + 0x131247, + 0x181584, 0x2000c2, - 0x201242, - 0x235b44, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x242543, - 0x214a83, - 0x232dc3, - 0x308003, - 0x2137c3, - 0x21a3c3, - 0x242543, - 0x215d43, - 0x20e2c3, - 0x2fb03, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, + 0x212402, + 0x236704, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x23e083, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x215f83, + 0x217fc3, + 0x23e083, + 0x20d403, + 0x208503, + 0xe783, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, 0x602, - 0x3a83, - 0x108003, - 0x214a83, - 0x232dc3, - 0x308003, - 0x221dc4, - 0x2137c3, - 0x21a3c3, - 0x242543, - 0x20c782, + 0x10103, + 0x66a83, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x20e704, + 0x215f83, + 0x217fc3, + 0x23e083, + 0x21fcc2, 0x2000c1, 0x2000c2, 0x200201, - 0x332182, - 0x9a048, - 0x21ca05, + 0x337f82, + 0xae888, + 0x21aa05, 0x200101, - 0x14a83, - 0x2fe44, - 0x201301, + 0x2ea43, + 0x319c4, + 0x201381, 0x200501, - 0x205dc1, - 0x246bc2, - 0x387fc4, - 0x246bc3, + 0x201281, + 0x248442, + 0x38e084, + 0x248443, 0x200041, 0x200801, 0x200181, 0x200701, - 0x302fc7, - 0x30e38f, - 0x3ccc06, + 0x35c3c7, + 0x30fccf, + 0x39af46, 0x2004c1, - 0x322546, + 0x326dc6, 0x200bc1, 0x200581, - 0x3affce, + 0x3de50e, 0x2003c1, - 0x242543, + 0x23e083, 0x200a81, - 0x34c105, - 0x20eb02, - 0x2431c5, + 0x32b305, + 0x201b02, + 0x243bc5, 0x200401, 0x200741, 0x2007c1, - 0x233442, + 0x22dc42, 0x200081, - 0x201341, - 0x204f01, - 0x201b41, - 0x201441, - 0x50849, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x214903, - 0x214a83, - 0x308003, - 0x90548, - 0x23c803, - 0x21a3c3, - 0x7283, - 0x242543, - 0x14f62c8, - 0x1e0603, - 0xa788, - 0x139b05, - 0x9a048, - 0x3dc3, - 0x139b05, - 0xcd184, - 0xd1488, - 0x455c4, - 0xcf487, - 0xd3b05, - 0x50849, - 0x11d287, - 0x14f62ca, - 0x9a048, - 0x1b4103, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x220dc3, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x2e3504, - 0x242543, - 0x24f8c5, - 0x2d0204, - 0x214a83, - 0x232dc3, - 0x308003, - 0x209e82, - 0x21a3c3, - 0x242543, - 0xe2c3, - 0xac60a, - 0xe8006, - 0x102804, - 0x122046, - 0x202703, - 0x214a83, - 0x232dc3, - 0x308003, - 0x21a3c3, - 0x242543, - 0x201242, - 0x214a83, - 0x2303c9, - 0x232dc3, - 0x2aa909, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x78a84, - 0x3dc3, - 0x242543, - 0x2fe5c8, - 0x23c207, - 0x208805, - 0xdbc48, - 0x1d4408, - 0x1c0407, - 0xf81ca, - 0x6f98b, - 0x122787, - 0x3f888, - 0xd174a, - 0xf648, - 0x142c09, - 0x27a07, - 0x1fa87, - 0x3ec8, - 0x944c8, - 0x40d4f, - 0x3ad45, - 0x947c7, - 0x1ab9c6, - 0x3cd87, - 0x1dd2c6, - 0x92788, - 0x99786, - 0x1147, - 0x2fc9, - 0x18ab07, - 0x179dc9, - 0xc2749, - 0xc8d06, - 0xcae48, - 0xdbf05, - 0x7b74a, - 0xd8cc8, - 0x44b83, - 0xe07c8, - 0x32fc7, - 0x95d05, - 0x51590, - 0x11003, - 0x1b4103, - 0x2e47, - 0x1acc5, - 0xf9888, - 0x66605, - 0xeda43, - 0x1cb7c8, - 0xee06, - 0x32109, - 0xb2b87, - 0x68e0b, - 0x6cc44, - 0x111444, - 0x117acb, - 0x118088, - 0x118e87, - 0x139b05, - 0x214a83, - 0x232dc3, - 0x228503, - 0x242543, - 0x23e343, - 0x308003, - 0x1b4103, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x242543, - 0x91e4b, + 0x207d01, + 0x20a8c1, + 0x202341, + 0x201c41, + 0x51709, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x217c83, + 0x22ea43, + 0x266a83, + 0x95e88, + 0x23cb03, + 0x217fc3, + 0x91043, + 0x23e083, + 0x76ef8008, + 0x1e0f83, + 0xff48, + 0x10402, + 0xb9c3, + 0x293c2, + 0x72c2, + 0x146bc5, + 0xae888, + 0x11fe87, + 0x5803, + 0x146bc5, + 0x175d84, + 0x7f448, + 0x46d04, + 0x17fe07, + 0x1c4104, + 0xd5e45, + 0x51709, + 0x1424c7, + 0x5aa4a, + 0x14f800a, + 0xae888, + 0x1c0443, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x233f03, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x2e5904, + 0x23e083, + 0x24a845, + 0x27e1c4, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x20b982, + 0x217fc3, + 0x23e083, + 0x8503, + 0xaefca, + 0xea706, + 0x11fa04, + 0x1268c6, + 0x24ac43, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x217fc3, + 0x23e083, + 0x212402, + 0x22ea43, + 0x231f49, + 0x233fc3, + 0x2ac549, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x81004, + 0x5803, + 0x23e083, + 0x3008c8, + 0x239307, + 0x37b845, + 0xde248, + 0x1d6e08, + 0x1c9e47, + 0xf9cca, + 0x7650b, + 0x127007, + 0x40488, + 0x7f70a, + 0x25e48, + 0x14b509, + 0x25887, + 0x14dcc7, + 0x1b5208, + 0xaf88, + 0x4164f, + 0xa6845, + 0x148647, + 0x3fec6, + 0x36487, + 0x12ea86, + 0x56288, + 0x9a346, + 0x17dc87, + 0x1c1989, + 0x1cd6c7, + 0x19c009, + 0xc9049, + 0xce646, + 0xd0ac8, + 0xde505, + 0x8350a, + 0xdb008, + 0x3fa83, + 0xe2988, + 0x341c7, + 0x156b05, + 0x61950, + 0x3443, + 0x1c0443, + 0x17db07, + 0x2cd05, + 0xfb388, + 0x6db85, + 0x120303, + 0x1d1048, + 0xb2c06, + 0x33249, + 0xb6f47, + 0x240b, + 0x72344, + 0x113c44, + 0x11af8b, + 0x11b548, + 0x11be07, + 0x146bc5, + 0x22ea43, + 0x233fc3, + 0x280203, + 0x23e083, + 0x23e883, + 0x266a83, + 0x1c0443, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x23e083, + 0x1b1e8b, 0x2000c2, - 0x201242, - 0x242543, + 0x212402, + 0x23e083, 0xd42, - 0x9e82, - 0x7782, - 0x9a048, - 0x1b3089, - 0x1242, + 0xb982, + 0x83c2, + 0xae888, + 0x1357c9, + 0x18b7c8, + 0x12402, 0x2000c2, - 0x201242, + 0x212402, 0x200382, 0x2005c2, - 0x210942, - 0x21a3c3, - 0x13f246, + 0x204482, + 0x217fc3, + 0x14a9c6, 0x2003c2, - 0x3e804, + 0xddf84, 0x2000c2, - 0x202703, - 0x201242, - 0x214a83, - 0x232dc3, + 0x24ac43, + 0x212402, + 0x22ea43, + 0x233fc3, 0x200382, - 0x308003, - 0x21bc83, - 0x23c803, - 0x219a04, - 0x21a3c3, - 0x2125c3, - 0x3dc3, - 0x242543, - 0x30a104, - 0x207783, - 0x308003, - 0x201242, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x203dc3, - 0x242543, - 0x3bd187, - 0x214a83, - 0x27b0c7, - 0x397206, - 0x216c83, - 0x21bb43, - 0x308003, - 0x206c03, - 0x221dc4, - 0x28a404, - 0x3383c6, - 0x213a43, - 0x21a3c3, - 0x242543, - 0x24f8c5, - 0x2af384, - 0x323b43, - 0x2ce043, - 0x2d44c7, - 0x2cd845, - 0x68703, - 0x214a83, - 0x232dc3, - 0x308003, - 0x23c803, - 0x21a3c3, - 0x6e544, - 0x242543, - 0x14583, - 0x7c30988c, - 0x53547, - 0xe4846, - 0x91487, - 0x67f05, - 0x202b02, - 0x247403, - 0x214f03, - 0x202703, - 0x7ce14a83, - 0x208c02, - 0x232dc3, - 0x207083, - 0x308003, - 0x221dc4, - 0x2059c3, - 0x21b6c3, - 0x23c803, - 0x219a04, - 0x7d20ce02, - 0x21a3c3, - 0x242543, - 0x2308c3, - 0x21bd03, - 0x21a443, - 0x20c782, - 0x207783, - 0x9a048, - 0x308003, - 0x3a83, - 0x2135c4, - 0x202703, - 0x201242, - 0x214a83, - 0x235b44, - 0x232dc3, - 0x308003, - 0x221dc4, - 0x21bc83, - 0x3473c4, - 0x306c44, - 0x2e2406, - 0x219a04, - 0x21a3c3, - 0x242543, - 0x2141c3, - 0x253c46, - 0x34c8b, - 0x28886, - 0xec90a, - 0x11b94a, - 0x9a048, - 0x2136c4, - 0x7e614a83, - 0x2026c4, - 0x232dc3, - 0x270744, - 0x308003, - 0x2f3983, - 0x23c803, - 0x21a3c3, - 0x1b4103, - 0x242543, - 0x4cbc3, - 0x347f8b, - 0x3ca20a, - 0x3e010c, - 0xebe48, + 0x266a83, + 0x2191c3, + 0x23cb03, + 0x21e484, + 0x217fc3, + 0x213cc3, + 0x5803, + 0x23e083, + 0x25d884, + 0x20aa43, + 0x266a83, + 0x212402, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x205803, + 0x23e083, + 0x3c48c7, + 0x22ea43, + 0x282e87, + 0x394e06, + 0x208483, + 0x20fa03, + 0x266a83, + 0x204903, + 0x20e704, + 0x28f784, + 0x32bac6, + 0x208243, + 0x217fc3, + 0x23e083, + 0x24a845, + 0x2b21c4, + 0x3283c3, + 0x356703, + 0x2d6807, + 0x355f05, + 0x1d03, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x23cb03, + 0x217fc3, + 0x75504, + 0x23e083, + 0x16d43, + 0x7e308dcc, + 0x4e803, + 0x192c07, + 0xe6946, + 0x19dfc7, + 0x157585, + 0x222b02, + 0x23de83, + 0x20c5c3, + 0x24ac43, + 0x7ee2ea43, + 0x204302, + 0x233fc3, + 0x2033c3, + 0x266a83, + 0x20e704, + 0x3433c3, + 0x22d703, + 0x23cb03, + 0x21e484, + 0x7f216102, + 0x217fc3, + 0x23e083, + 0x204ac3, + 0x219243, + 0x218043, + 0x21fcc2, + 0x20aa43, + 0xae888, + 0x266a83, + 0x10103, + 0x215d84, + 0x24ac43, + 0x212402, + 0x22ea43, + 0x236704, + 0x233fc3, + 0x266a83, + 0x20e704, + 0x2191c3, + 0x33f584, + 0x217544, + 0x2e4806, + 0x21e484, + 0x217fc3, + 0x23e083, + 0x216983, + 0x269f86, + 0x3a9cb, + 0x36fc6, + 0xbd84a, + 0x11f48a, + 0xae888, + 0x215e84, + 0x8062ea43, + 0x37e504, + 0x233fc3, + 0x296d84, + 0x266a83, + 0x2f4c43, + 0x23cb03, + 0x217fc3, + 0x1c0443, + 0x23e083, + 0x54543, + 0x34a60b, + 0x3cf9ca, + 0x3e0a8c, + 0xee488, 0x2000c2, - 0x201242, + 0x212402, 0x200382, - 0x22d805, - 0x221dc4, - 0x209e82, - 0x23c803, - 0x306c44, - 0x208482, + 0x22f845, + 0x20e704, + 0x20b982, + 0x23cb03, + 0x217544, + 0x203182, 0x2003c2, - 0x2090c2, - 0x20c782, - 0x2703, - 0x15702, - 0x2cb209, - 0x365308, - 0x307e89, - 0x2073c9, - 0x20b40a, - 0x210f0a, - 0x206082, - 0x2167c2, - 0x1242, - 0x214a83, - 0x22ba02, - 0x240c46, - 0x377dc2, - 0x208d42, - 0x26fd0e, - 0x21410e, - 0x27e307, - 0x21a347, - 0x24dc82, - 0x232dc3, - 0x308003, - 0x210d82, + 0x208502, + 0x21fcc2, + 0x4ac43, + 0xcdc2, + 0x2d0e89, + 0x36c648, + 0x266909, + 0x213d49, + 0x2184ca, + 0x30aaca, + 0x209482, + 0x361e82, + 0x12402, + 0x22ea43, + 0x22c982, + 0x241546, + 0x37c682, + 0x2013c2, + 0x27688e, + 0x2168ce, + 0x217f47, + 0x211c42, + 0x233fc3, + 0x266a83, + 0x20f342, 0x2005c2, - 0x1bac3, - 0x235d4f, - 0x21fb02, - 0x2b8887, - 0x3520c7, - 0x2bc287, - 0x2e9ccc, - 0x2dc18c, - 0x20c304, - 0x38d04a, - 0x214042, - 0x201e42, - 0x2c5104, + 0xe703, + 0x23690f, + 0x241882, + 0x2c3587, + 0x2ec3c7, + 0x2de787, + 0x2e2b4c, + 0x2f024c, + 0x21f844, + 0x39334a, + 0x216802, + 0x206902, + 0x2cac84, 0x200702, - 0x2cc342, - 0x2dc3c4, - 0x20fe82, - 0x202042, - 0x1a8c3, - 0x299807, - 0x23a705, - 0x223502, - 0x23cd04, - 0x203f82, - 0x2eba08, - 0x21a3c3, - 0x376b08, - 0x2029c2, - 0x20c4c5, - 0x396e06, - 0x242543, - 0x20a882, - 0x2fa607, - 0xeb02, - 0x39e785, - 0x3c2f45, - 0x206442, - 0x20b382, - 0x33a90a, - 0x35094a, - 0x23c7c2, - 0x2a4284, - 0x203282, - 0x3d3788, - 0x20a5c2, - 0x359208, - 0xf01, - 0x314447, - 0x3149c9, - 0x2b7402, - 0x319985, - 0x3b9c45, - 0x2184cb, - 0x33894c, - 0x22c088, - 0x32bb08, - 0x21d642, - 0x2ac882, + 0x2c23c2, + 0x2f0484, + 0x214882, + 0x202702, + 0x1e1c3, + 0x29a3c7, + 0x30eac5, + 0x204202, + 0x236404, + 0x393b42, + 0x2edd48, + 0x217fc3, + 0x37b588, + 0x203242, + 0x21fa05, + 0x39da86, + 0x23e083, + 0x204fc2, + 0x2fc207, + 0x1b02, + 0x34bbc5, + 0x3dce85, + 0x20b502, + 0x206c82, + 0x34754a, + 0x28de4a, + 0x23cac2, + 0x2a39c4, + 0x200f02, + 0x21dd88, + 0x207ac2, + 0x31c248, + 0x1501, + 0x316b47, + 0x3175c9, + 0x2bb102, + 0x31d505, + 0x36ed45, + 0x212acb, + 0x32c04c, + 0x22c488, + 0x331088, + 0x226642, + 0x2af242, 0x2000c2, - 0x9a048, - 0x201242, - 0x214a83, + 0xae888, + 0x212402, + 0x22ea43, 0x200382, - 0x208482, - 0x3dc3, + 0x203182, + 0x5803, 0x2003c2, - 0x242543, - 0x2090c2, + 0x23e083, + 0x208502, 0x2000c2, - 0x139b05, - 0x7fa01242, - 0x1099c4, - 0x37e85, - 0x80708003, - 0x21a8c3, - 0x209e82, - 0x21a3c3, - 0x3b68c3, - 0x80a42543, - 0x2f7103, - 0x274d46, - 0x160e2c3, - 0x139b05, - 0x13f10b, - 0x9a048, - 0x7ff02e08, - 0x5c1c7, - 0x802c108a, - 0x6ddc7, - 0x97805, - 0x2a54d, - 0x8e242, - 0x118682, + 0x146bc5, + 0x81a12402, + 0x108f04, + 0x37e05, + 0x82a66a83, + 0x21e1c3, + 0x20b982, + 0x217fc3, + 0x3d6203, + 0x82e3e083, + 0x2f8e43, + 0x27a906, + 0x1608503, + 0x146bc5, + 0x14a88b, + 0xae888, + 0x81f64008, + 0x68f47, + 0x822c6aca, + 0x74d87, + 0x1b5a05, + 0x82600f89, + 0x2c10d, + 0x3fcc2, + 0x11bb42, 0xe01, - 0xad28a, - 0x150787, - 0x20c04, - 0x20c43, - 0x3c704, - 0x81202842, - 0x81600ac2, - 0x81a01182, - 0x81e02d02, - 0x82206b42, - 0x826086c2, - 0x17e707, - 0x82a01242, - 0x82e2ec02, - 0x8321f2c2, - 0x83602a42, - 0x214103, - 0xca04, - 0x22dcc3, - 0x83a0e442, - 0x5a988, - 0x83e015c2, - 0x4e2c7, - 0x1ad887, - 0x84200042, - 0x84600d82, - 0x84a00182, - 0x84e06182, - 0x85200f42, - 0x856005c2, - 0xf4185, - 0x24dec3, - 0x35c004, - 0x85a00702, - 0x85e14d42, - 0x86206002, - 0x7a04b, - 0x86600c42, - 0x86e01f42, - 0x87209e82, - 0x87610942, - 0x87a1d542, - 0x87e00bc2, - 0x88202382, - 0x8866c9c2, - 0x88a0ce02, - 0x88e03142, - 0x89208482, - 0x89637242, - 0x89a510c2, - 0x89e43802, - 0x5684, - 0x310543, - 0x8a200ec2, - 0x8a610e82, - 0x8aa0e742, - 0x8ae006c2, - 0x8b2003c2, - 0x8b600a82, - 0xf6bc8, - 0x91fc7, - 0x8ba141c2, - 0x8be06142, - 0x8c2090c2, - 0x8c6023c2, - 0x1aec8c, - 0x8ca02c02, - 0x8ce25b82, - 0x8d20f482, - 0x8d603642, - 0x8da00f02, - 0x8de0b582, - 0x8e201342, - 0x8e607302, - 0x8ea76002, - 0x8ee76542, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x23703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x86a059c3, - 0x223703, - 0x3c0b44, - 0x307d86, - 0x306403, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x374689, - 0x215702, - 0x39b6c3, - 0x2c2a43, - 0x2894c5, - 0x207083, - 0x2059c3, - 0x223703, - 0x267d83, - 0x211243, - 0x3c4409, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x2059c3, - 0x223703, - 0x215702, - 0x215702, - 0x2059c3, - 0x223703, - 0x8f614a83, - 0x232dc3, - 0x207603, - 0x23c803, - 0x21a3c3, - 0x3dc3, - 0x242543, - 0x9a048, - 0x201242, - 0x214a83, - 0x21a3c3, - 0x242543, - 0x141842, - 0x214a83, - 0x232dc3, - 0x308003, - 0x901192c2, - 0x23c803, - 0x21a3c3, - 0x3dc3, - 0x242543, - 0x1301, - 0x24c0c4, - 0x201242, - 0x214a83, + 0x107784, + 0xb018a, + 0x8dc87, + 0x10bb84, + 0x3ca03, + 0x3ca04, + 0x83603d82, + 0x83a00ac2, + 0x83e03502, + 0x84202e42, + 0x846074c2, + 0x84a0cf02, + 0x178d87, + 0x84e12402, + 0x85211d02, + 0x8561c782, + 0x85a0f982, + 0x2168c3, + 0x1ff44, + 0x28c543, + 0x85e12882, + 0x5a388, + 0x86207c82, + 0x4e007, + 0x1b77c7, + 0x86600042, + 0x86a00d82, + 0x86e00182, + 0x87209582, + 0x8760f782, + 0x87a005c2, + 0xfdd45, + 0x24dc03, + 0x3612c4, + 0x87e00702, + 0x8820a342, + 0x88601582, + 0x8d64b, + 0x88a00c42, + 0x89206a02, + 0x8960b982, + 0x89a04482, + 0x89e15782, + 0x8a200bc2, + 0x8a60a942, + 0x8aa720c2, + 0x8ae16102, + 0x8b201602, + 0x8b603182, + 0x8ba37282, + 0x8be05402, + 0x8c209ec2, + 0x1583c4, + 0x3169c3, + 0x8c634e42, + 0x8ca0f442, + 0x8ce03742, + 0x8d2006c2, + 0x8d6003c2, + 0x8da00a82, + 0xf8908, + 0x1b2007, + 0x8de16982, + 0x8e205302, + 0x8e608502, + 0x8ea0a1c2, + 0x1b800c, + 0x8ee03d02, + 0x8f224e42, + 0x8f601942, + 0x8fa034c2, + 0x8fe0e482, + 0x90203b02, + 0x90607d02, + 0x90a16382, + 0x90e7bcc2, + 0x9127c2c2, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x88f433c3, + 0x2220c3, + 0x3c7a04, + 0x266806, + 0x307183, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x26e9c9, + 0x20cdc2, + 0x3b3843, + 0x2c9343, + 0x260045, + 0x2033c3, + 0x3433c3, + 0x2220c3, + 0x2b8a83, + 0x20de03, + 0x3679c9, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x20cdc2, + 0x20cdc2, + 0x3433c3, + 0x2220c3, + 0x91a2ea43, + 0x233fc3, + 0x213f83, + 0x23cb03, + 0x217fc3, + 0x5803, + 0x23e083, + 0xae888, + 0x212402, + 0x22ea43, + 0x217fc3, + 0x23e083, + 0x6e842, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x924f6e82, + 0x23cb03, + 0x217fc3, + 0x5803, + 0x23e083, + 0x1381, + 0x241ec4, + 0x212402, + 0x22ea43, 0x200983, - 0x232dc3, - 0x24d9c4, - 0x228503, - 0x308003, - 0x221dc4, - 0x21bc83, - 0x23c803, - 0x21a3c3, - 0x242543, - 0x22b983, - 0x208805, - 0x211243, - 0x207783, + 0x233fc3, + 0x24d704, + 0x280203, + 0x266a83, + 0x20e704, + 0x2191c3, + 0x23cb03, + 0x217fc3, + 0x23e083, + 0x235403, + 0x37b845, + 0x20de03, + 0x20aa43, 0x882, - 0x3dc3, - 0x201242, - 0x214a83, - 0x2059c3, - 0x21a3c3, - 0x242543, + 0x5803, + 0x212402, + 0x22ea43, + 0x3433c3, + 0x217fc3, + 0x23e083, 0x2000c2, - 0x202703, - 0x9a048, - 0x214a83, - 0x232dc3, - 0x308003, - 0x22f7c6, - 0x221dc4, - 0x21bc83, - 0x219a04, - 0x21a3c3, - 0x242543, - 0x2141c3, - 0x29904, - 0x214a83, - 0x239c3, - 0x232dc3, - 0x9e82, - 0x21a3c3, - 0x242543, - 0x2aec2, - 0x2982, - 0x147ee07, - 0x1807, - 0x214a83, - 0x28886, - 0x232dc3, - 0x308003, - 0xedf86, - 0x21a3c3, - 0x242543, - 0x328e48, - 0x32b949, - 0x33e209, - 0x34ae08, - 0x399488, - 0x399489, - 0x322c0a, - 0x3602ca, - 0x39424a, - 0x39abca, - 0x3ca20a, - 0x3d818b, - 0x30838d, - 0x23fd4f, - 0x35d210, - 0x361d4d, - 0x37d8cc, - 0x39a90b, - 0x6dfc8, - 0x11d548, - 0x19d705, - 0x1486107, - 0xd7445, + 0x24ac43, + 0xae888, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x231346, + 0x20e704, + 0x2191c3, + 0x21e484, + 0x217fc3, + 0x23e083, + 0x216983, + 0x4cc4, + 0x161e82, + 0x22ea43, + 0x22383, + 0x233fc3, + 0xb982, + 0x217fc3, + 0x23e083, + 0x30242, + 0x2a82, + 0x1481bc7, + 0x8cc7, + 0x22ea43, + 0x36fc6, + 0x233fc3, + 0x266a83, + 0xf07c6, + 0x217fc3, + 0x23e083, + 0x32d948, + 0x330ec9, + 0x341dc9, + 0x34cfc8, + 0x3a01c8, + 0x3a01c9, + 0x32748a, + 0x3657ca, + 0x399a4a, + 0x3a124a, + 0x3cf9ca, + 0x3db28b, + 0x26604d, + 0x230b0f, + 0x240950, + 0x3692cd, + 0x38384c, + 0x3a0f8b, + 0x74f88, + 0xf6cc8, + 0xbe1c5, + 0x148e8c7, + 0xd9785, 0x2000c2, - 0x2cd685, - 0x202003, - 0x93601242, - 0x232dc3, - 0x308003, - 0x27e7c7, - 0x25cc03, - 0x23c803, - 0x21a3c3, - 0x24e283, - 0x2125c3, - 0x206a03, - 0x203dc3, - 0x242543, - 0x252b06, - 0x233442, - 0x207783, - 0x9a048, + 0x355d45, + 0x21e183, + 0x95a12402, + 0x233fc3, + 0x266a83, + 0x232b87, + 0x21df43, + 0x23cb03, + 0x217fc3, + 0x24dfc3, + 0x213cc3, + 0x210ec3, + 0x205803, + 0x23e083, + 0x2509c6, + 0x22dc42, + 0x20aa43, + 0xae888, 0x2000c2, - 0x202703, - 0x201242, - 0x214a83, - 0x232dc3, - 0x308003, - 0x221dc4, - 0x23c803, - 0x21a3c3, - 0x242543, - 0x20e2c3, - 0x1807, - 0xb342, - 0x68b44, - 0x151c306, + 0x24ac43, + 0x212402, + 0x22ea43, + 0x233fc3, + 0x266a83, + 0x20e704, + 0x23cb03, + 0x217fc3, + 0x23e083, + 0x208503, + 0x8cc7, + 0x10382, + 0x2144, + 0x1517446, 0x2000c2, - 0x201242, - 0x308003, - 0x23c803, - 0x242543, + 0x212402, + 0x266a83, + 0x23cb03, + 0x23e083, } // children is the list of nodes' children, the parent's wildcard bit and the @@ -9554,597 +9614,606 @@ var children = [...]uint32{ 0x40000000, 0x50000000, 0x60000000, - 0x17ec5f5, - 0x17f05fb, - 0x17f45fc, - 0x18185fd, - 0x1970606, - 0x198865c, - 0x199c662, - 0x19b4667, - 0x19d466d, - 0x19f4675, - 0x1a0c67d, - 0x1a2c683, - 0x1a3068b, - 0x1a5868c, + 0x17d05ee, + 0x17d45f4, + 0x17d85f5, + 0x17fc5f6, + 0x19545ff, + 0x196c655, + 0x198065b, + 0x1998660, + 0x19b8666, + 0x19d866e, + 0x19f0676, + 0x1a1067c, + 0x1a14684, + 0x1a3c685, + 0x1a4068f, + 0x1a58690, 0x1a5c696, - 0x1a74697, - 0x1a7869d, - 0x1a7c69e, - 0x1ab869f, - 0x1abc6ae, - 0x1ac06af, - 0x61ac86b0, - 0x21ad06b2, - 0x1b186b4, - 0x1b1c6c6, - 0x1b406c7, - 0x1b446d0, + 0x1a60697, + 0x1aa0698, + 0x1aa46a8, + 0x1aa86a9, + 0x21aac6aa, + 0x61ab46ab, + 0x21abc6ad, + 0x1b046af, + 0x1b086c1, + 0x1b2c6c2, + 0x1b306cb, + 0x1b446cc, 0x1b486d1, - 0x1b5c6d2, - 0x1b606d7, - 0x1b806d8, - 0x1bb06e0, - 0x1bcc6ec, - 0x1bf46f3, - 0x1c046fd, - 0x1c08701, - 0x1ca0702, - 0x1cb4728, - 0x1cc872d, - 0x1d00732, - 0x1d10740, - 0x1d24744, - 0x1d3c749, - 0x1de074f, - 0x1fe4778, - 0x1fe87f9, - 0x20547fa, - 0x20c0815, - 0x20d8830, - 0x20ec836, - 0x20f083b, - 0x20f883c, - 0x210c83e, - 0x2110843, - 0x2130844, - 0x218084c, - 0x2184860, - 0x22188861, - 0x21a4862, - 0x21a8869, - 0x21ac86a, - 0x21d086b, - 0x2214874, - 0x2218885, - 0x6221c886, - 0x2238887, - 0x226488e, - 0x2270899, - 0x228089c, - 0x23348a0, - 0x23388cd, - 0x223488ce, - 0x2234c8d2, - 0x223548d3, - 0x23ac8d5, - 0x23b08eb, - 0x23b48ec, - 0x28dc8ed, - 0x28e0a37, - 0x22988a38, - 0x2298ca62, - 0x22990a63, - 0x2299ca64, - 0x229a0a67, - 0x229aca68, - 0x229b0a6b, - 0x229b4a6c, - 0x229b8a6d, - 0x229bca6e, - 0x229c0a6f, - 0x229cca70, - 0x229d0a73, - 0x229dca74, - 0x229e0a77, - 0x229e4a78, - 0x229e8a79, - 0x229f4a7a, - 0x229f8a7d, - 0x22a04a7e, - 0x22a08a81, - 0x22a0ca82, + 0x1b686d2, + 0x1b986da, + 0x1bb46e6, + 0x1bdc6ed, + 0x1bec6f7, + 0x1bf06fb, + 0x1c886fc, + 0x1c9c722, + 0x1cb0727, + 0x1ce872c, + 0x1cf873a, + 0x1d0c73e, + 0x1d24743, + 0x1dc8749, + 0x1ffc772, + 0x20007ff, + 0x206c800, + 0x20d881b, + 0x20f0836, + 0x210483c, + 0x2108841, + 0x2110842, + 0x2124844, + 0x2128849, + 0x214884a, + 0x2198852, + 0x219c866, + 0x221a0867, + 0x21c0868, + 0x21c4870, + 0x21c8871, + 0x21f0872, + 0x621f487c, + 0x223887d, + 0x223c88e, + 0x6224088f, + 0x225c890, + 0x228c897, + 0x229c8a3, + 0x22ac8a7, + 0x23608ab, + 0x23648d8, + 0x223748d9, + 0x223788dd, + 0x223808de, + 0x23d88e0, + 0x23dc8f6, + 0x23e08f7, + 0x29348f8, + 0x2938a4d, + 0x62940a4e, + 0x229e8a50, + 0x229eca7a, + 0x229f0a7b, + 0x229fca7c, + 0x22a00a7f, + 0x22a0ca80, 0x22a10a83, - 0x2a14a84, + 0x22a14a84, 0x22a18a85, - 0x22a24a86, - 0x22a28a89, - 0x2a2ca8a, - 0x2a34a8b, - 0x62a40a8d, - 0x2a84a90, - 0x22aa4aa1, - 0x22aa8aa9, - 0x22aacaaa, - 0x22ab0aab, - 0x22ab8aac, - 0x22abcaae, - 0x2ac0aaf, - 0x22ac4ab0, - 0x22ac8ab1, - 0x22accab2, - 0x22ad0ab3, - 0x2ad8ab4, - 0x2ae0ab6, - 0x2ae4ab8, - 0x2b00ab9, - 0x2b18ac0, - 0x2b1cac6, - 0x2b2cac7, - 0x2b38acb, - 0x2b6cace, - 0x2b74adb, - 0x22b78add, - 0x2b90ade, - 0x22b98ae4, - 0x22b9cae6, - 0x22ba4ae7, - 0x2ca0ae9, - 0x22ca4b28, - 0x2cacb29, - 0x2cb0b2b, - 0x22cb4b2c, - 0x2cb8b2d, - 0x2ce0b2e, - 0x2ce4b38, - 0x2ce8b39, - 0x2cecb3a, - 0x2d04b3b, - 0x2d18b41, - 0x2d40b46, - 0x2d60b50, - 0x2d64b58, - 0x62d68b59, - 0x2d9cb5a, - 0x2da0b67, - 0x22da4b68, - 0x2da8b69, - 0x2dd0b6a, - 0x2dd4b74, - 0x2df8b75, - 0x2dfcb7e, - 0x2e10b7f, - 0x2e14b84, - 0x2e18b85, - 0x2e38b86, - 0x2e54b8e, + 0x22a1ca86, + 0x22a20a87, + 0x22a2ca88, + 0x22a30a8b, + 0x22a3ca8c, + 0x22a40a8f, + 0x22a44a90, + 0x22a48a91, + 0x22a54a92, + 0x22a58a95, + 0x22a64a96, + 0x22a68a99, + 0x22a6ca9a, + 0x22a70a9b, + 0x2a74a9c, + 0x22a78a9d, + 0x22a84a9e, + 0x22a88aa1, + 0x2a8caa2, + 0x2a94aa3, + 0x62aa0aa5, + 0x2ae4aa8, + 0x22b04ab9, + 0x22b08ac1, + 0x22b0cac2, + 0x22b10ac3, + 0x22b14ac4, + 0x22b1cac5, + 0x22b20ac7, + 0x2b24ac8, + 0x22b44ac9, + 0x22b48ad1, + 0x22b4cad2, + 0x22b50ad3, + 0x22b54ad4, + 0x22b58ad5, + 0x2b60ad6, + 0x2b68ad8, + 0x2b6cada, + 0x2b88adb, + 0x2ba0ae2, + 0x2ba4ae8, + 0x2bb4ae9, + 0x2bc0aed, + 0x2bf4af0, + 0x2bfcafd, + 0x22c00aff, + 0x2c18b00, + 0x22c20b06, + 0x22c24b08, + 0x22c2cb09, + 0x2d28b0b, + 0x22d2cb4a, + 0x2d34b4b, + 0x2d38b4d, + 0x22d3cb4e, + 0x2d40b4f, + 0x2d68b50, + 0x2d6cb5a, + 0x2d70b5b, + 0x2d88b5c, + 0x2d9cb62, + 0x2dc4b67, + 0x2de4b71, + 0x2de8b79, + 0x62decb7a, + 0x2e20b7b, + 0x2e24b88, + 0x22e28b89, + 0x2e2cb8a, + 0x2e54b8b, 0x2e58b95, - 0x22e5cb96, - 0x2e60b97, - 0x2e64b98, - 0x2e68b99, - 0x2e70b9a, - 0x2e84b9c, - 0x2e88ba1, - 0x2e8cba2, - 0x2eb4ba3, - 0x2eb8bad, - 0x2f2cbae, - 0x2f30bcb, - 0x2f34bcc, - 0x2f54bcd, - 0x2f6cbd5, - 0x2f70bdb, - 0x2f84bdc, - 0x2f9cbe1, - 0x2fbcbe7, - 0x2fd4bef, - 0x2fd8bf5, - 0x2ff4bf6, - 0x3010bfd, - 0x3014c04, - 0x3040c05, - 0x3060c10, - 0x3080c18, - 0x30e4c20, + 0x2e7cb96, + 0x2e80b9f, + 0x2e94ba0, + 0x2e98ba5, + 0x2e9cba6, + 0x2ebcba7, + 0x2ed8baf, + 0x2edcbb6, + 0x22ee0bb7, + 0x2ee4bb8, + 0x2ee8bb9, + 0x2eecbba, + 0x2ef4bbb, + 0x2f08bbd, + 0x2f0cbc2, + 0x2f10bc3, + 0x2f38bc4, + 0x2f3cbce, + 0x2fb0bcf, + 0x2fb4bec, + 0x2fb8bed, + 0x2fd8bee, + 0x2ff0bf6, + 0x2ff4bfc, + 0x3008bfd, + 0x3020c02, + 0x3040c08, + 0x3058c10, + 0x305cc16, + 0x3078c17, + 0x3094c1e, + 0x3098c25, + 0x30c4c26, + 0x30e4c31, 0x3104c39, - 0x3120c41, - 0x3124c48, - 0x313cc49, - 0x3180c4f, - 0x3200c60, - 0x3230c80, - 0x3234c8c, - 0x3240c8d, - 0x3260c90, - 0x3264c98, - 0x3288c99, - 0x3290ca2, - 0x32ccca4, - 0x3320cb3, - 0x3324cc8, - 0x3328cc9, - 0x3404cca, - 0x2340cd01, - 0x23410d03, - 0x23414d04, - 0x3418d05, - 0x2341cd06, - 0x23420d07, - 0x3424d08, - 0x23428d09, - 0x23438d0a, - 0x2343cd0e, - 0x23440d0f, - 0x23444d10, - 0x23448d11, - 0x2344cd12, - 0x3464d13, - 0x3488d19, - 0x34a8d22, - 0x3b14d2a, - 0x3b20ec5, - 0x3b40ec8, - 0x3d00ed0, - 0x3dd0f40, - 0x3e40f74, - 0x3e98f90, - 0x3f80fa6, - 0x3fd8fe0, - 0x4014ff6, - 0x4111005, - 0x41dd044, - 0x4275077, - 0x430509d, - 0x43690c1, - 0x45a10da, - 0x4659168, - 0x4725196, - 0x47711c9, - 0x47f91dc, - 0x48351fe, - 0x488520d, - 0x48fd221, - 0x6490123f, - 0x64905240, - 0x64909241, - 0x4985242, - 0x49e1261, - 0x4a5d278, - 0x4ad5297, - 0x4b552b5, - 0x4bc12d5, - 0x4ced2f0, - 0x4d4533b, - 0x64d49351, - 0x4de1352, - 0x4de9378, - 0x24ded37a, - 0x4e7537b, - 0x4ec139d, - 0x4f293b0, - 0x4fd13ca, - 0x50993f4, - 0x5101426, - 0x5215440, - 0x65219485, - 0x6521d486, - 0x5279487, - 0x52d549e, - 0x53654b5, - 0x53e14d9, - 0x54254f8, - 0x5509509, - 0x553d542, - 0x559d54f, - 0x5611567, - 0x5699584, - 0x56d95a6, - 0x57495b6, - 0x6574d5d2, - 0x57755d3, - 0x57795dd, - 0x57a95de, - 0x57c55ea, - 0x58095f1, - 0x5819602, - 0x5831606, - 0x58a960c, - 0x58b162a, - 0x58cd62c, - 0x58e1633, - 0x58fd638, - 0x592963f, - 0x592d64a, - 0x593564b, - 0x594964d, - 0x5969652, - 0x597965a, - 0x598565e, - 0x59c1661, - 0x59c9670, - 0x59dd672, - 0x5a05677, - 0x5a11681, - 0x5a19684, - 0x5a41686, - 0x5a65690, - 0x5a7d699, - 0x5a8169f, - 0x5a896a0, - 0x5a9d6a2, - 0x5b456a7, - 0x5b496d1, - 0x5b4d6d2, - 0x5b516d3, - 0x5b756d4, - 0x5b996dd, - 0x5bb56e6, - 0x5bc96ed, - 0x5bdd6f2, - 0x5be56f7, - 0x5bed6f9, - 0x5bf56fb, - 0x5c0d6fd, - 0x5c1d703, - 0x5c21707, - 0x5c3d708, - 0x64c570f, - 0x64fd931, - 0x652993f, - 0x654594a, - 0x6565951, - 0x6585959, - 0x65c9961, - 0x65d1972, - 0x265d5974, - 0x265d9975, - 0x65e1976, - 0x67cd978, - 0x267d19f3, - 0x67d59f4, - 0x267d99f5, - 0x267e99f6, - 0x267f19fa, - 0x267fd9fc, - 0x68019ff, - 0x26809a00, - 0x6811a02, - 0x6821a04, - 0x6849a08, - 0x6885a12, - 0x6889a21, - 0x68c1a22, - 0x68e5a30, - 0x743da39, - 0x7441d0f, - 0x7445d10, - 0x27449d11, - 0x744dd12, - 0x27451d13, - 0x7455d14, - 0x27461d15, - 0x7465d18, - 0x7469d19, - 0x2746dd1a, - 0x7471d1b, - 0x27479d1c, - 0x747dd1e, - 0x7481d1f, - 0x27491d20, - 0x7495d24, - 0x7499d25, - 0x749dd26, - 0x74a1d27, - 0x274a5d28, - 0x74a9d29, - 0x74add2a, - 0x74b1d2b, - 0x74b5d2c, - 0x274bdd2d, - 0x74c1d2f, - 0x74c5d30, - 0x74c9d31, - 0x274cdd32, - 0x74d1d33, - 0x274d9d34, - 0x274ddd36, - 0x74f9d37, - 0x7511d3e, - 0x7555d44, + 0x3168c41, + 0x3188c5a, + 0x31a8c62, + 0x31acc6a, + 0x31c4c6b, + 0x3208c71, + 0x3288c82, + 0x32b8ca2, + 0x32bccae, + 0x32c8caf, + 0x32e8cb2, + 0x32eccba, + 0x3310cbb, + 0x3318cc4, + 0x3354cc6, + 0x33a8cd5, + 0x33accea, + 0x33b0ceb, + 0x3494cec, + 0x2349cd25, + 0x234a0d27, + 0x234a4d28, + 0x34a8d29, + 0x234acd2a, + 0x234b0d2b, + 0x34b4d2c, + 0x234b8d2d, + 0x234c8d2e, + 0x234ccd32, + 0x234d0d33, + 0x234d4d34, + 0x234d8d35, + 0x234dcd36, + 0x34f4d37, + 0x3518d3d, + 0x3538d46, + 0x3ba4d4e, + 0x3bb0ee9, + 0x3bd0eec, + 0x3d90ef4, + 0x3e60f64, + 0x3ed0f98, + 0x3f28fb4, + 0x4010fca, + 0x4069004, + 0x40a501a, + 0x41a1029, + 0x426d068, + 0x430509b, + 0x43950c1, + 0x43f90e5, + 0x46310fe, + 0x46e918c, + 0x47b51ba, + 0x48011ed, + 0x4889200, + 0x48c5222, + 0x4915231, + 0x498d245, + 0x64991263, + 0x64995264, + 0x64999265, + 0x4a15266, + 0x4a71285, + 0x4aed29c, + 0x4b652bb, + 0x4be52d9, + 0x4c512f9, + 0x4d7d314, + 0x4dd535f, + 0x64dd9375, + 0x4e71376, + 0x4e7939c, + 0x24e7d39e, + 0x4f0539f, + 0x4f513c1, + 0x4fb93d4, + 0x50613ee, + 0x5129418, + 0x519144a, + 0x52a5464, + 0x652a94a9, + 0x652ad4aa, + 0x53094ab, + 0x53654c2, + 0x53f54d9, + 0x54714fd, + 0x54b551c, + 0x559952d, + 0x55cd566, + 0x562d573, + 0x56a158b, + 0x57295a8, + 0x57695ca, + 0x57d95da, + 0x657dd5f6, + 0x58055f7, + 0x5809601, + 0x5839602, + 0x585560e, + 0x5899615, + 0x58a9626, + 0x58c162a, + 0x5939630, + 0x594164e, + 0x595d650, + 0x5971657, + 0x598d65c, + 0x59b9663, + 0x59bd66e, + 0x59c566f, + 0x59d9671, + 0x59f9676, + 0x5a0967e, + 0x5a15682, + 0x5a51685, + 0x5a59694, + 0x5a6d696, + 0x5a9569b, + 0x5aa16a5, + 0x5aa96a8, + 0x5ad16aa, + 0x5af56b4, + 0x5b0d6bd, + 0x5b116c3, + 0x5b196c4, + 0x5b2d6c6, + 0x5bd56cb, + 0x5bd96f5, + 0x5bdd6f6, + 0x5be16f7, + 0x5c056f8, + 0x5c29701, + 0x5c4570a, + 0x5c59711, + 0x5c6d716, + 0x5c7571b, + 0x5c7d71d, + 0x5c8571f, + 0x5c9d721, + 0x5cad727, + 0x5cb172b, + 0x5ccd72c, + 0x6555733, + 0x658d955, + 0x65b9963, + 0x65d596e, + 0x65f5975, + 0x661597d, + 0x6659985, + 0x6661996, + 0x26665998, + 0x26669999, + 0x667199a, + 0x687199c, + 0x26875a1c, + 0x6879a1d, + 0x2687da1e, + 0x2688da1f, + 0x26895a23, + 0x268a1a25, + 0x68a5a28, + 0x268a9a29, + 0x268b1a2a, + 0x68b9a2c, + 0x68c9a2e, + 0x68f1a32, + 0x692da3c, + 0x6931a4b, + 0x6969a4c, + 0x698da5a, + 0x74e5a63, + 0x74e9d39, + 0x74edd3a, + 0x274f1d3b, + 0x74f5d3c, + 0x274f9d3d, + 0x74fdd3e, + 0x27509d3f, + 0x750dd42, + 0x7511d43, + 0x27515d44, + 0x7519d45, + 0x27521d46, + 0x7525d48, + 0x7529d49, + 0x27539d4a, + 0x753dd4e, + 0x7541d4f, + 0x7545d50, + 0x7549d51, + 0x2754dd52, + 0x7551d53, + 0x7555d54, 0x7559d55, - 0x757dd56, - 0x7589d5f, - 0x758dd62, - 0x7591d63, - 0x7755d64, - 0x27759dd5, - 0x27761dd6, - 0x27765dd8, - 0x27769dd9, - 0x7771dda, - 0x784dddc, - 0x27859e13, - 0x2785de16, - 0x27861e17, - 0x27865e18, - 0x7869e19, - 0x7895e1a, - 0x78a1e25, - 0x78a5e28, - 0x78c9e29, - 0x78d5e32, - 0x78f5e35, - 0x78f9e3d, - 0x7931e3e, - 0x7be1e4c, - 0x7c9def8, - 0x7ca1f27, - 0x7ca5f28, - 0x7cb9f29, - 0x7cbdf2e, - 0x7cf1f2f, - 0x7d29f3c, - 0x27d2df4a, - 0x7d49f4b, - 0x7d71f52, - 0x7d75f5c, - 0x7d99f5d, - 0x7db5f66, - 0x7dddf6d, - 0x7dedf77, - 0x7df1f7b, - 0x7df5f7c, - 0x7e2df7d, - 0x7e39f8b, - 0x7e61f8e, - 0x7ee1f98, - 0x27ee5fb8, - 0x7ef5fb9, - 0x7f05fbd, - 0x7f21fc1, - 0x7f41fc8, - 0x7f45fd0, - 0x7f59fd1, - 0x7f6dfd6, - 0x7f71fdb, - 0x7f75fdc, - 0x7f79fdd, - 0x7f99fde, - 0x8041fe6, - 0x8046010, - 0x8062011, - 0x808a018, - 0x808e022, - 0x8096023, - 0x80ba025, - 0x80c202e, - 0x80d6030, - 0x80f6035, - 0x811203d, - 0x8122044, - 0x813a048, - 0x817204e, - 0x817605c, - 0x824a05d, + 0x755dd56, + 0x27565d57, + 0x7569d59, + 0x756dd5a, + 0x7571d5b, + 0x27575d5c, + 0x7579d5d, + 0x27581d5e, + 0x27585d60, + 0x75a1d61, + 0x75b9d68, + 0x75fdd6e, + 0x7601d7f, + 0x7625d80, + 0x7631d89, + 0x7635d8c, + 0x7639d8d, + 0x77fdd8e, + 0x27801dff, + 0x27809e00, + 0x2780de02, + 0x27811e03, + 0x7819e04, + 0x78f5e06, + 0x27901e3d, + 0x27905e40, + 0x27909e41, + 0x2790de42, + 0x7911e43, + 0x793de44, + 0x7949e4f, + 0x794de52, + 0x7971e53, + 0x797de5c, + 0x799de5f, + 0x79a1e67, + 0x79d9e68, + 0x7c89e76, + 0x7d45f22, + 0x7d49f51, + 0x7d4df52, + 0x7d61f53, + 0x7d65f58, + 0x7d99f59, + 0x7dd1f66, + 0x27dd5f74, + 0x7df1f75, + 0x7e19f7c, + 0x7e1df86, + 0x7e41f87, + 0x7e5df90, + 0x7e85f97, + 0x7e95fa1, + 0x7e99fa5, + 0x7e9dfa6, + 0x7ed5fa7, + 0x7ee1fb5, + 0x7f09fb8, + 0x7f95fc2, + 0x27f99fe5, + 0x7f9dfe6, + 0x7fadfe7, + 0x27fb1feb, + 0x7fc1fec, + 0x7fddff0, + 0x7ffdff7, + 0x8001fff, + 0x8016000, + 0x802a005, + 0x802e00a, + 0x803200b, + 0x803600c, + 0x805600d, + 0x80fe015, + 0x810203f, + 0x811e040, + 0x8146047, + 0x28156051, + 0x815a055, + 0x8166056, + 0x8192059, + 0x819a064, + 0x81ae066, + 0x81ce06b, + 0x81ea073, + 0x81fa07a, + 0x821207e, + 0x824a084, 0x824e092, - 0x8262093, - 0x826a098, - 0x828209a, - 0x82860a0, - 0x82920a1, - 0x829e0a4, - 0x82a20a7, - 0x82a60a8, - 0x82aa0a9, - 0x82ce0aa, - 0x830e0b3, - 0x83120c3, - 0x83320c4, - 0x83820cc, - 0x83ae0e0, - 0x283b20eb, - 0x83ba0ec, - 0x84120ee, - 0x8416104, - 0x841a105, - 0x841e106, - 0x8462107, - 0x8472118, - 0x84b211c, - 0x84b612c, - 0x84e612d, - 0x8632139, - 0x865a18c, - 0x8692196, - 0x86b61a4, - 0x286be1ad, - 0x286c21af, - 0x86ca1b0, - 0x86d61b2, - 0x87f21b5, - 0x87fe1fc, - 0x880a1ff, - 0x8816202, - 0x8822205, - 0x882e208, - 0x883a20b, - 0x884620e, - 0x8852211, - 0x885e214, - 0x886a217, - 0x887621a, - 0x888221d, - 0x888e220, - 0x8896223, - 0x88a2225, - 0x88ae228, - 0x88ba22b, - 0x88c622e, - 0x88d2231, - 0x88de234, - 0x88ea237, - 0x88f623a, - 0x890223d, - 0x890e240, - 0x891a243, - 0x8946246, - 0x8952251, - 0x895e254, - 0x896a257, - 0x897625a, - 0x898225d, - 0x898a260, - 0x8996262, - 0x89a2265, - 0x89ae268, - 0x89ba26b, - 0x89c626e, - 0x89d2271, - 0x89de274, - 0x89ea277, - 0x89f627a, - 0x8a0227d, - 0x8a0e280, - 0x8a16283, - 0x8a22285, - 0x8a2a288, + 0x8322093, + 0x83260c8, + 0x833a0c9, + 0x83420ce, + 0x835a0d0, + 0x835e0d6, + 0x836a0d7, + 0x83760da, + 0x837a0dd, + 0x83820de, + 0x83860e0, + 0x83aa0e1, + 0x83ea0ea, + 0x83ee0fa, + 0x840e0fb, + 0x845e103, + 0x848e117, + 0x28492123, + 0x849a124, + 0x84f2126, + 0x84f613c, + 0x84fa13d, + 0x84fe13e, + 0x854213f, + 0x8552150, + 0x8592154, + 0x8596164, + 0x85c6165, + 0x870e171, + 0x87361c3, + 0x876e1cd, + 0x87961db, + 0x2879e1e5, + 0x287a21e7, + 0x287a61e8, + 0x87ae1e9, + 0x87ba1eb, + 0x88d61ee, + 0x88e2235, + 0x88ee238, + 0x88fa23b, + 0x890623e, + 0x8912241, + 0x891e244, + 0x892a247, + 0x893624a, + 0x894224d, + 0x894e250, + 0x895a253, + 0x8966256, + 0x8972259, + 0x897a25c, + 0x898625e, + 0x8992261, + 0x899e264, + 0x89aa267, + 0x89b626a, + 0x89c226d, + 0x89ce270, + 0x89da273, + 0x89e6276, + 0x89f2279, + 0x89fe27c, + 0x8a2a27f, 0x8a3628a, 0x8a4228d, 0x8a4e290, 0x8a5a293, 0x8a66296, - 0x8a72299, - 0x8a7e29c, - 0x8a8a29f, - 0x8a8e2a2, - 0x8a9a2a3, - 0x8ab62a6, - 0x8aba2ad, - 0x8aca2ae, - 0x8aee2b2, - 0x8af22bb, - 0x8b362bc, - 0x8b3e2cd, - 0x8b522cf, - 0x8b862d4, - 0x8ba22e1, - 0x8baa2e8, - 0x8bce2ea, - 0x8be62f3, - 0x8bfe2f9, - 0x8c162ff, - 0x8c2a305, - 0x28c7230a, - 0x8c7631c, - 0x8ca231d, - 0x8cb2328, - 0x8cc632c, + 0x8a6e299, + 0x8a7a29b, + 0x8a8629e, + 0x8a922a1, + 0x8a9e2a4, + 0x8aaa2a7, + 0x8ab62aa, + 0x8ac22ad, + 0x8ace2b0, + 0x8ada2b3, + 0x8ae62b6, + 0x8af22b9, + 0x8afa2bc, + 0x8b062be, + 0x8b0e2c1, + 0x8b1a2c3, + 0x8b262c6, + 0x8b322c9, + 0x8b3e2cc, + 0x8b4a2cf, + 0x8b562d2, + 0x8b622d5, + 0x8b6e2d8, + 0x8b722db, + 0x8b7e2dc, + 0x8b9a2df, + 0x8b9e2e6, + 0x8bae2e7, + 0x8bd22eb, + 0x8bd62f4, + 0x8c1a2f5, + 0x8c22306, + 0x8c36308, + 0x8c6a30d, + 0x8c8a31a, + 0x8c92322, + 0x8cb6324, + 0x8cce32d, + 0x8ce6333, + 0x8cfe339, + 0x8d1233f, + 0x28d5a344, + 0x8d5e356, + 0x8d8a357, + 0x8d9a362, + 0x8dae366, } -// max children 592 (capacity 1023) -// max text offset 30772 (capacity 32767) +// max children 601 (capacity 1023) +// max text offset 30901 (capacity 32767) // max text length 36 (capacity 63) -// max hi 9009 (capacity 16383) -// max lo 9004 (capacity 16383) +// max hi 9067 (capacity 16383) +// max lo 9062 (capacity 16383) diff --git a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go index 5ee692d38..dc6177c12 100644 --- a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go +++ b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go @@ -19,8 +19,7 @@ import ( var debug = false -// GetSizes returns the sizes used by the underlying driver with the given parameters. -func GetSizes(ctx context.Context, buildFlags, env []string, dir string, usesExportData bool) (types.Sizes, error) { +func GetSizes(ctx context.Context, buildFlags, env []string, gocmdRunner *gocommand.Runner, dir string) (types.Sizes, error) { // TODO(matloob): Clean this up. This code is mostly a copy of packages.findExternalDriver. const toolPrefix = "GOPACKAGESDRIVER=" tool := "" @@ -40,7 +39,7 @@ func GetSizes(ctx context.Context, buildFlags, env []string, dir string, usesExp } if tool == "off" { - return GetSizesGolist(ctx, buildFlags, env, dir, usesExportData) + return GetSizesGolist(ctx, buildFlags, env, gocmdRunner, dir) } req, err := json.Marshal(struct { @@ -76,7 +75,7 @@ func GetSizes(ctx context.Context, buildFlags, env []string, dir string, usesExp return response.Sizes, nil } -func GetSizesGolist(ctx context.Context, buildFlags, env []string, dir string, usesExportData bool) (types.Sizes, error) { +func GetSizesGolist(ctx context.Context, buildFlags, env []string, gocmdRunner *gocommand.Runner, dir string) (types.Sizes, error) { inv := gocommand.Invocation{ Verb: "list", Args: []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"}, @@ -84,7 +83,7 @@ func GetSizesGolist(ctx context.Context, buildFlags, env []string, dir string, u BuildFlags: buildFlags, WorkingDir: dir, } - stdout, stderr, friendlyErr, rawErr := inv.RunRaw(ctx) + stdout, stderr, friendlyErr, rawErr := gocmdRunner.RunRaw(ctx, inv) var goarch, compiler string if rawErr != nil { if strings.Contains(rawErr.Error(), "cannot find main module") { @@ -96,7 +95,7 @@ func GetSizesGolist(ctx context.Context, buildFlags, env []string, dir string, u Env: env, WorkingDir: dir, } - envout, enverr := inv.Run(ctx) + envout, enverr := gocmdRunner.Run(ctx, inv) if enverr != nil { return nil, enverr } diff --git a/vendor/golang.org/x/tools/go/packages/golist.go b/vendor/golang.org/x/tools/go/packages/golist.go index b4a13ef45..bc04503c1 100644 --- a/vendor/golang.org/x/tools/go/packages/golist.go +++ b/vendor/golang.org/x/tools/go/packages/golist.go @@ -24,7 +24,7 @@ import ( "golang.org/x/tools/go/internal/packagesdriver" "golang.org/x/tools/internal/gocommand" - "golang.org/x/tools/internal/packagesinternal" + "golang.org/x/xerrors" ) // debug controls verbose logging. @@ -89,6 +89,10 @@ type golistState struct { rootDirsError error rootDirs map[string]string + goVersionOnce sync.Once + goVersionError error + goVersion string // third field of 'go version' + // vendorDirs caches the (non)existence of vendor directories. vendorDirs map[string]bool } @@ -142,7 +146,7 @@ func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) { sizeswg.Add(1) go func() { var sizes types.Sizes - sizes, sizeserr = packagesdriver.GetSizesGolist(ctx, cfg.BuildFlags, cfg.Env, cfg.Dir, usesExportData(cfg)) + sizes, sizeserr = packagesdriver.GetSizesGolist(ctx, cfg.BuildFlags, cfg.Env, cfg.gocmdRunner, cfg.Dir) // types.SizesFor always returns nil or a *types.StdSizes. response.dr.Sizes, _ = sizes.(*types.StdSizes) sizeswg.Done() @@ -242,6 +246,21 @@ extractQueries: } } } + // Add root for any package that matches a pattern. This applies only to + // packages that are modified by overlays, since they are not added as + // roots automatically. + for _, pattern := range restPatterns { + match := matchPattern(pattern) + for _, pkgID := range modifiedPkgs { + pkg, ok := response.seenPackages[pkgID] + if !ok { + continue + } + if match(pkg.PkgPath) { + response.addRoot(pkg.ID) + } + } + } sizeswg.Wait() if sizeserr != nil { @@ -381,7 +400,7 @@ type jsonPackage struct { Imports []string ImportMap map[string]string Deps []string - Module *packagesinternal.Module + Module *Module TestGoFiles []string TestImports []string XTestGoFiles []string @@ -502,10 +521,19 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse errkind = "use of internal package not allowed" } if errkind != "" { - if len(old.Error.ImportStack) < 2 { - return nil, fmt.Errorf(`internal error: go list gave a %q error with an import stack with fewer than two elements`, errkind) + if len(old.Error.ImportStack) < 1 { + return nil, fmt.Errorf(`internal error: go list gave a %q error with empty import stack`, errkind) + } + importingPkg := old.Error.ImportStack[len(old.Error.ImportStack)-1] + if importingPkg == old.ImportPath { + // Using an older version of Go which put this package itself on top of import + // stack, instead of the importer. Look for importer in second from top + // position. + if len(old.Error.ImportStack) < 2 { + return nil, fmt.Errorf(`internal error: go list gave a %q error with an import stack without importing package`, errkind) + } + importingPkg = old.Error.ImportStack[len(old.Error.ImportStack)-2] } - importingPkg := old.Error.ImportStack[len(old.Error.ImportStack)-2] additionalErrors[importingPkg] = append(additionalErrors[importingPkg], Error{ Pos: old.Error.Pos, Msg: old.Error.Err, @@ -531,7 +559,26 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse CompiledGoFiles: absJoin(p.Dir, p.CompiledGoFiles), OtherFiles: absJoin(p.Dir, otherFiles(p)...), forTest: p.ForTest, - module: p.Module, + Module: p.Module, + } + + if (state.cfg.Mode&typecheckCgo) != 0 && len(p.CgoFiles) != 0 { + if len(p.CompiledGoFiles) > len(p.GoFiles) { + // We need the cgo definitions, which are in the first + // CompiledGoFile after the non-cgo ones. This is a hack but there + // isn't currently a better way to find it. We also need the pure + // Go files and unprocessed cgo files, all of which are already + // in pkg.GoFiles. + cgoTypes := p.CompiledGoFiles[len(p.GoFiles)] + pkg.CompiledGoFiles = append([]string{cgoTypes}, pkg.GoFiles...) + } else { + // golang/go#38990: go list silently fails to do cgo processing + pkg.CompiledGoFiles = nil + pkg.Errors = append(pkg.Errors, Error{ + Msg: "go list failed to return CompiledGoFiles; https://golang.org/issue/38990?", + Kind: ListError, + }) + } } // Work around https://golang.org/issue/28749: @@ -607,6 +654,39 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse pkg.CompiledGoFiles = pkg.GoFiles } + // Temporary work-around for golang/go#39986. Parse filenames out of + // error messages. This happens if there are unrecoverable syntax + // errors in the source, so we can't match on a specific error message. + if err := p.Error; err != nil && state.shouldAddFilenameFromError(p) { + addFilenameFromPos := func(pos string) bool { + split := strings.Split(pos, ":") + if len(split) < 1 { + return false + } + filename := strings.TrimSpace(split[0]) + if filename == "" { + return false + } + if !filepath.IsAbs(filename) { + filename = filepath.Join(state.cfg.Dir, filename) + } + info, _ := os.Stat(filename) + if info == nil { + return false + } + pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, filename) + pkg.GoFiles = append(pkg.GoFiles, filename) + return true + } + found := addFilenameFromPos(err.Pos) + // In some cases, go list only reports the error position in the + // error text, not the error position. One such case is when the + // file's package name is a keyword (see golang.org/issue/39763). + if !found { + addFilenameFromPos(err.Err) + } + } + if p.Error != nil { msg := strings.TrimSpace(p.Error.Err) // Trim to work around golang.org/issue/32363. // Address golang.org/issue/35964 by appending import stack to error message. @@ -636,7 +716,60 @@ func (state *golistState) createDriverResponse(words ...string) (*driverResponse return &response, nil } -// getPkgPath finds the package path of a directory if it's relative to a root directory. +func (state *golistState) shouldAddFilenameFromError(p *jsonPackage) bool { + if len(p.GoFiles) > 0 || len(p.CompiledGoFiles) > 0 { + return false + } + + goV, err := state.getGoVersion() + if err != nil { + return false + } + + // On Go 1.14 and earlier, only add filenames from errors if the import stack is empty. + // The import stack behaves differently for these versions than newer Go versions. + if strings.HasPrefix(goV, "go1.13") || strings.HasPrefix(goV, "go1.14") { + return len(p.Error.ImportStack) == 0 + } + + // On Go 1.15 and later, only parse filenames out of error if there's no import stack, + // or the current package is at the top of the import stack. This is not guaranteed + // to work perfectly, but should avoid some cases where files in errors don't belong to this + // package. + return len(p.Error.ImportStack) == 0 || p.Error.ImportStack[len(p.Error.ImportStack)-1] == p.ImportPath +} + +func (state *golistState) getGoVersion() (string, error) { + state.goVersionOnce.Do(func() { + var b *bytes.Buffer + // Invoke go version. Don't use invokeGo because it will supply build flags, and + // go version doesn't expect build flags. + inv := gocommand.Invocation{ + Verb: "version", + Env: state.cfg.Env, + Logf: state.cfg.Logf, + } + gocmdRunner := state.cfg.gocmdRunner + if gocmdRunner == nil { + gocmdRunner = &gocommand.Runner{} + } + b, _, _, state.goVersionError = gocmdRunner.RunRaw(state.cfg.Context, inv) + if state.goVersionError != nil { + return + } + + sp := strings.Split(b.String(), " ") + if len(sp) < 3 { + state.goVersionError = fmt.Errorf("go version output: expected 'go version ', got '%s'", b.String()) + return + } + state.goVersion = sp[2] + }) + return state.goVersion, state.goVersionError +} + +// getPkgPath finds the package path of a directory if it's relative to a root +// directory. func (state *golistState) getPkgPath(dir string) (string, bool, error) { absDir, err := filepath.Abs(dir) if err != nil { @@ -707,7 +840,7 @@ func golistargs(cfg *Config, words []string) []string { func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer, error) { cfg := state.cfg - inv := &gocommand.Invocation{ + inv := gocommand.Invocation{ Verb: verb, Args: args, BuildFlags: cfg.BuildFlags, @@ -715,8 +848,11 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer, Logf: cfg.Logf, WorkingDir: cfg.Dir, } - - stdout, stderr, _, err := inv.RunRaw(cfg.Context) + gocmdRunner := cfg.gocmdRunner + if gocmdRunner == nil { + gocmdRunner = &gocommand.Runner{} + } + stdout, stderr, _, err := gocmdRunner.RunRaw(cfg.Context, inv) if err != nil { // Check for 'go' executable not being found. if ee, ok := err.(*exec.Error); ok && ee.Err == exec.ErrNotFound { @@ -727,7 +863,7 @@ func (state *golistState) invokeGo(verb string, args ...string) (*bytes.Buffer, if !ok { // Catastrophic error: // - context cancellation - return nil, fmt.Errorf("couldn't run 'go': %v", err) + return nil, xerrors.Errorf("couldn't run 'go': %w", err) } // Old go version? diff --git a/vendor/golang.org/x/tools/go/packages/golist_overlay.go b/vendor/golang.org/x/tools/go/packages/golist_overlay.go index 7974a6c9b..874f90134 100644 --- a/vendor/golang.org/x/tools/go/packages/golist_overlay.go +++ b/vendor/golang.org/x/tools/go/packages/golist_overlay.go @@ -5,11 +5,15 @@ import ( "fmt" "go/parser" "go/token" + "log" "os" "path/filepath" + "regexp" "sort" "strconv" "strings" + + "golang.org/x/tools/internal/gocommand" ) // processGolistOverlay provides rudimentary support for adding @@ -22,10 +26,15 @@ func (state *golistState) processGolistOverlay(response *responseDeduper) (modif needPkgsSet := make(map[string]bool) modifiedPkgsSet := make(map[string]bool) + pkgOfDir := make(map[string][]*Package) for _, pkg := range response.dr.Packages { // This is an approximation of import path to id. This can be // wrong for tests, vendored packages, and a number of other cases. havePkgs[pkg.PkgPath] = pkg.ID + x := commonDir(pkg.GoFiles) + if x != "" { + pkgOfDir[x] = append(pkgOfDir[x], pkg) + } } // If no new imports are added, it is safe to avoid loading any needPkgs. @@ -64,6 +73,9 @@ func (state *golistState) processGolistOverlay(response *responseDeduper) (modif // to the overlay. continue } + // If all the overlay files belong to a different package, change the + // package name to that package. + maybeFixPackageName(pkgName, isTestFile, pkgOfDir[dir]) nextPackage: for _, p := range response.dr.Packages { if pkgName != p.Name && p.ID != "command-line-arguments" { @@ -80,9 +92,19 @@ func (state *golistState) processGolistOverlay(response *responseDeduper) (modif // because the file is generated in another directory. testVariantOf = p continue nextPackage + } else if !isTestFile && hasTestFiles(p) { + // We're examining a test variant, but the overlaid file is + // a non-test file. Because the overlay implementation + // (currently) only adds a file to one package, skip this + // package, so that we can add the file to the production + // variant of the package. (https://golang.org/issue/36857 + // tracks handling overlays on both the production and test + // variant of a package). + continue nextPackage } - // We must have already seen the package of which this is a test variant. if pkg != nil && p != pkg && pkg.PkgPath == p.PkgPath { + // We have already seen the production version of the + // for which p is a test variant. if hasTestFiles(p) { testVariantOf = pkg } @@ -93,8 +115,11 @@ func (state *golistState) processGolistOverlay(response *responseDeduper) (modif } } } - // The overlay could have included an entirely new package. - if pkg == nil { + // The overlay could have included an entirely new package or an + // ad-hoc package. An ad-hoc package is one that we have manually + // constructed from inadequate `go list` results for a file= query. + // It will have the ID command-line-arguments. + if pkg == nil || pkg.ID == "command-line-arguments" { // Try to find the module or gopath dir the file is contained in. // Then for modules, add the module opath to the beginning. pkgPath, ok, err := state.getPkgPath(dir) @@ -104,34 +129,53 @@ func (state *golistState) processGolistOverlay(response *responseDeduper) (modif if !ok { break } + var forTest string // only set for x tests isXTest := strings.HasSuffix(pkgName, "_test") if isXTest { + forTest = pkgPath pkgPath += "_test" } id := pkgPath - if isTestFile && !isXTest { - id = fmt.Sprintf("%s [%s.test]", pkgPath, pkgPath) - } - // Try to reclaim a package with the same id if it exists in the response. - for _, p := range response.dr.Packages { - if reclaimPackage(p, id, opath, contents) { - pkg = p - break + if isTestFile { + if isXTest { + id = fmt.Sprintf("%s [%s.test]", pkgPath, forTest) + } else { + id = fmt.Sprintf("%s [%s.test]", pkgPath, pkgPath) } } - // Otherwise, create a new package - if pkg == nil { - pkg = &Package{PkgPath: pkgPath, ID: id, Name: pkgName, Imports: make(map[string]*Package)} - response.addPackage(pkg) - havePkgs[pkg.PkgPath] = id - // Add the production package's sources for a test variant. - if isTestFile && !isXTest && testVariantOf != nil { - pkg.GoFiles = append(pkg.GoFiles, testVariantOf.GoFiles...) - pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, testVariantOf.CompiledGoFiles...) - // Add the package under test and its imports to the test variant. - pkg.forTest = testVariantOf.PkgPath - for k, v := range testVariantOf.Imports { - pkg.Imports[k] = &Package{ID: v.ID} + if pkg != nil { + // TODO(rstambler): We should change the package's path and ID + // here. The only issue is that this messes with the roots. + } else { + // Try to reclaim a package with the same ID, if it exists in the response. + for _, p := range response.dr.Packages { + if reclaimPackage(p, id, opath, contents) { + pkg = p + break + } + } + // Otherwise, create a new package. + if pkg == nil { + pkg = &Package{ + PkgPath: pkgPath, + ID: id, + Name: pkgName, + Imports: make(map[string]*Package), + } + response.addPackage(pkg) + havePkgs[pkg.PkgPath] = id + // Add the production package's sources for a test variant. + if isTestFile && !isXTest && testVariantOf != nil { + pkg.GoFiles = append(pkg.GoFiles, testVariantOf.GoFiles...) + pkg.CompiledGoFiles = append(pkg.CompiledGoFiles, testVariantOf.CompiledGoFiles...) + // Add the package under test and its imports to the test variant. + pkg.forTest = testVariantOf.PkgPath + for k, v := range testVariantOf.Imports { + pkg.Imports[k] = &Package{ID: v.ID} + } + } + if isXTest { + pkg.forTest = forTest } } } @@ -149,6 +193,8 @@ func (state *golistState) processGolistOverlay(response *responseDeduper) (modif continue } for _, imp := range imports { + // TODO(rstambler): If the package is an x test and the import has + // a test variant, make sure to replace it. if _, found := pkg.Imports[imp]; found { continue } @@ -282,14 +328,25 @@ func (state *golistState) determineRootDirs() (map[string]string, error) { } func (state *golistState) determineRootDirsModules() (map[string]string, error) { + // List all of the modules--the first will be the directory for the main + // module. Any replaced modules will also need to be treated as roots. + // Editing files in the module cache isn't a great idea, so we don't + // plan to ever support that. out, err := state.invokeGo("list", "-m", "-json", "all") if err != nil { - return nil, err + // 'go list all' will fail if we're outside of a module and + // GO111MODULE=on. Try falling back without 'all'. + var innerErr error + out, innerErr = state.invokeGo("list", "-m", "-json") + if innerErr != nil { + return nil, err + } } - m := map[string]string{} - type jsonMod struct{ Path, Dir string } + roots := map[string]string{} + modules := map[string]string{} + var i int for dec := json.NewDecoder(out); dec.More(); { - mod := new(jsonMod) + mod := new(gocommand.ModuleJSON) if err := dec.Decode(mod); err != nil { return nil, err } @@ -299,10 +356,15 @@ func (state *golistState) determineRootDirsModules() (map[string]string, error) if err != nil { return nil, err } - m[absDir] = mod.Path + modules[absDir] = mod.Path + // The first result is the main module. + if i == 0 || mod.Replace != nil && mod.Replace.Path != "" { + roots[absDir] = mod.Path + } } + i++ } - return m, nil + return roots, nil } func (state *golistState) determineRootDirsGOPATH() (map[string]string, error) { @@ -374,3 +436,133 @@ func extractPackageName(filename string, contents []byte) (string, bool) { } return f.Name.Name, true } + +func commonDir(a []string) string { + seen := make(map[string]bool) + x := append([]string{}, a...) + for _, f := range x { + seen[filepath.Dir(f)] = true + } + if len(seen) > 1 { + log.Fatalf("commonDir saw %v for %v", seen, x) + } + for k := range seen { + // len(seen) == 1 + return k + } + return "" // no files +} + +// It is possible that the files in the disk directory dir have a different package +// name from newName, which is deduced from the overlays. If they all have a different +// package name, and they all have the same package name, then that name becomes +// the package name. +// It returns true if it changes the package name, false otherwise. +func maybeFixPackageName(newName string, isTestFile bool, pkgsOfDir []*Package) { + names := make(map[string]int) + for _, p := range pkgsOfDir { + names[p.Name]++ + } + if len(names) != 1 { + // some files are in different packages + return + } + var oldName string + for k := range names { + oldName = k + } + if newName == oldName { + return + } + // We might have a case where all of the package names in the directory are + // the same, but the overlay file is for an x test, which belongs to its + // own package. If the x test does not yet exist on disk, we may not yet + // have its package name on disk, but we should not rename the packages. + // + // We use a heuristic to determine if this file belongs to an x test: + // The test file should have a package name whose package name has a _test + // suffix or looks like "newName_test". + maybeXTest := strings.HasPrefix(oldName+"_test", newName) || strings.HasSuffix(newName, "_test") + if isTestFile && maybeXTest { + return + } + for _, p := range pkgsOfDir { + p.Name = newName + } +} + +// This function is copy-pasted from +// https://github.com/golang/go/blob/9706f510a5e2754595d716bd64be8375997311fb/src/cmd/go/internal/search/search.go#L360. +// It should be deleted when we remove support for overlays from go/packages. +// +// NOTE: This does not handle any ./... or ./ style queries, as this function +// doesn't know the working directory. +// +// matchPattern(pattern)(name) reports whether +// name matches pattern. Pattern is a limited glob +// pattern in which '...' means 'any string' and there +// is no other special syntax. +// Unfortunately, there are two special cases. Quoting "go help packages": +// +// First, /... at the end of the pattern can match an empty string, +// so that net/... matches both net and packages in its subdirectories, like net/http. +// Second, any slash-separated pattern element containing a wildcard never +// participates in a match of the "vendor" element in the path of a vendored +// package, so that ./... does not match packages in subdirectories of +// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do. +// Note, however, that a directory named vendor that itself contains code +// is not a vendored package: cmd/vendor would be a command named vendor, +// and the pattern cmd/... matches it. +func matchPattern(pattern string) func(name string) bool { + // Convert pattern to regular expression. + // The strategy for the trailing /... is to nest it in an explicit ? expression. + // The strategy for the vendor exclusion is to change the unmatchable + // vendor strings to a disallowed code point (vendorChar) and to use + // "(anything but that codepoint)*" as the implementation of the ... wildcard. + // This is a bit complicated but the obvious alternative, + // namely a hand-written search like in most shell glob matchers, + // is too easy to make accidentally exponential. + // Using package regexp guarantees linear-time matching. + + const vendorChar = "\x00" + + if strings.Contains(pattern, vendorChar) { + return func(name string) bool { return false } + } + + re := regexp.QuoteMeta(pattern) + re = replaceVendor(re, vendorChar) + switch { + case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`): + re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)` + case re == vendorChar+`/\.\.\.`: + re = `(/vendor|/` + vendorChar + `/\.\.\.)` + case strings.HasSuffix(re, `/\.\.\.`): + re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?` + } + re = strings.ReplaceAll(re, `\.\.\.`, `[^`+vendorChar+`]*`) + + reg := regexp.MustCompile(`^` + re + `$`) + + return func(name string) bool { + if strings.Contains(name, vendorChar) { + return false + } + return reg.MatchString(replaceVendor(name, vendorChar)) + } +} + +// replaceVendor returns the result of replacing +// non-trailing vendor path elements in x with repl. +func replaceVendor(x, repl string) string { + if !strings.Contains(x, "vendor") { + return x + } + elem := strings.Split(x, "/") + for i := 0; i < len(elem)-1; i++ { + if elem[i] == "vendor" { + elem[i] = repl + } + } + return strings.Join(elem, "/") +} diff --git a/vendor/golang.org/x/tools/go/packages/loadmode_string.go b/vendor/golang.org/x/tools/go/packages/loadmode_string.go index aff94a3fe..7ea37e7ee 100644 --- a/vendor/golang.org/x/tools/go/packages/loadmode_string.go +++ b/vendor/golang.org/x/tools/go/packages/loadmode_string.go @@ -38,7 +38,7 @@ var modeStrings = []string{ func (mod LoadMode) String() string { m := mod if m == 0 { - return fmt.Sprintf("LoadMode(0)") + return "LoadMode(0)" } var out []string for i, x := range allModes { diff --git a/vendor/golang.org/x/tools/go/packages/packages.go b/vendor/golang.org/x/tools/go/packages/packages.go index 1ac6558c1..04053f1e7 100644 --- a/vendor/golang.org/x/tools/go/packages/packages.go +++ b/vendor/golang.org/x/tools/go/packages/packages.go @@ -21,9 +21,12 @@ import ( "path/filepath" "strings" "sync" + "time" "golang.org/x/tools/go/gcexportdata" + "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/packagesinternal" + "golang.org/x/tools/internal/typesinternal" ) // A LoadMode controls the amount of detail to return when loading. @@ -69,6 +72,13 @@ const ( // NeedTypesSizes adds TypesSizes. NeedTypesSizes + + // typecheckCgo enables full support for type checking cgo. Requires Go 1.15+. + // Modifies CompiledGoFiles and Types, and has no effect on its own. + typecheckCgo + + // NeedModule adds Module. + NeedModule ) const ( @@ -127,6 +137,9 @@ type Config struct { // Env []string + // gocmdRunner guards go command calls from concurrency errors. + gocmdRunner *gocommand.Runner + // BuildFlags is a list of command-line flags to be passed through to // the build system's query tool. BuildFlags []string @@ -178,6 +191,13 @@ type driver func(cfg *Config, patterns ...string) (*driverResponse, error) // driverResponse contains the results for a driver query. type driverResponse struct { + // NotHandled is returned if the request can't be handled by the current + // driver. If an external driver returns a response with NotHandled, the + // rest of the driverResponse is ignored, and go/packages will fallback + // to the next driver. If go/packages is extended in the future to support + // lists of multiple drivers, go/packages will fall back to the next driver. + NotHandled bool + // Sizes, if not nil, is the types.Sizes to use when type checking. Sizes *types.StdSizes @@ -219,14 +239,22 @@ func Load(cfg *Config, patterns ...string) ([]*Package, error) { return l.refine(response.Roots, response.Packages...) } -// defaultDriver is a driver that looks for an external driver binary, and if -// it does not find it falls back to the built in go list driver. +// defaultDriver is a driver that implements go/packages' fallback behavior. +// It will try to request to an external driver, if one exists. If there's +// no external driver, or the driver returns a response with NotHandled set, +// defaultDriver will fall back to the go list driver. func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, error) { driver := findExternalDriver(cfg) if driver == nil { driver = goListDriver } - return driver(cfg, patterns...) + response, err := driver(cfg, patterns...) + if err != nil { + return response, err + } else if response.NotHandled { + return goListDriver(cfg, patterns...) + } + return response, nil } // A Package describes a loaded Go package. @@ -253,7 +281,7 @@ type Package struct { GoFiles []string // CompiledGoFiles lists the absolute file paths of the package's source - // files that were presented to the compiler. + // files that are suitable for type checking. // This may differ from GoFiles if files are processed before compilation. CompiledGoFiles []string @@ -301,16 +329,39 @@ type Package struct { forTest string // module is the module information for the package if it exists. - module *packagesinternal.Module + Module *Module +} + +// Module provides module information for a package. +type Module struct { + Path string // module path + Version string // module version + Replace *Module // replaced by this module + Time *time.Time // time version was created + Main bool // is this the main module? + Indirect bool // is this module only an indirect dependency of main module? + Dir string // directory holding files for this module, if any + GoMod string // path to go.mod file used when loading this module, if any + GoVersion string // go version used in module + Error *ModuleError // error loading module +} + +// ModuleError holds errors loading a module. +type ModuleError struct { + Err string // the error itself } func init() { packagesinternal.GetForTest = func(p interface{}) string { return p.(*Package).forTest } - packagesinternal.GetModule = func(p interface{}) *packagesinternal.Module { - return p.(*Package).module + packagesinternal.GetGoCmdRunner = func(config interface{}) *gocommand.Runner { + return config.(*Config).gocmdRunner } + packagesinternal.SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) { + config.(*Config).gocmdRunner = runner + } + packagesinternal.TypecheckCgo = int(typecheckCgo) } // An Error describes a problem with a package's metadata, syntax, or types. @@ -473,6 +524,9 @@ func newLoader(cfg *Config) *loader { if ld.Config.Env == nil { ld.Config.Env = os.Environ() } + if ld.Config.gocmdRunner == nil { + ld.Config.gocmdRunner = &gocommand.Runner{} + } if ld.Context == nil { ld.Context = context.Background() } @@ -690,6 +744,9 @@ func (ld *loader) refine(roots []string, list ...*Package) ([]*Package, error) { if ld.requestedMode&NeedTypesSizes == 0 { ld.pkgs[i].TypesSizes = nil } + if ld.requestedMode&NeedModule == 0 { + ld.pkgs[i].Module = nil + } } return result, nil @@ -865,6 +922,15 @@ func (ld *loader) loadPackage(lpkg *loaderPackage) { Error: appendError, Sizes: ld.sizes, } + if (ld.Mode & typecheckCgo) != 0 { + if !typesinternal.SetUsesCgo(tc) { + appendError(Error{ + Msg: "typecheckCgo requires Go 1.15+", + Kind: ListError, + }) + return + } + } types.NewChecker(tc, ld.Fset, lpkg.Types, lpkg.TypesInfo).Files(lpkg.Syntax) lpkg.importErrors = nil // no longer needed diff --git a/vendor/golang.org/x/tools/imports/forward.go b/vendor/golang.org/x/tools/imports/forward.go index dbe5b49a9..a4e40adba 100644 --- a/vendor/golang.org/x/tools/imports/forward.go +++ b/vendor/golang.org/x/tools/imports/forward.go @@ -3,10 +3,10 @@ package imports // import "golang.org/x/tools/imports" import ( - "go/build" + "io/ioutil" "log" - "os" + "golang.org/x/tools/internal/gocommand" intimp "golang.org/x/tools/internal/imports" ) @@ -31,31 +31,34 @@ var Debug = false var LocalPrefix string // Process formats and adjusts imports for the provided file. -// If opt is nil the defaults are used. +// If opt is nil the defaults are used, and if src is nil the source +// is read from the filesystem. // // Note that filename's directory influences which imports can be chosen, // so it is important that filename be accurate. // To process data ``as if'' it were in filename, pass the data as a non-nil src. func Process(filename string, src []byte, opt *Options) ([]byte, error) { + var err error + if src == nil { + src, err = ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + } if opt == nil { opt = &Options{Comments: true, TabIndent: true, TabWidth: 8} } intopt := &intimp.Options{ Env: &intimp.ProcessEnv{ - GOPATH: build.Default.GOPATH, - GOROOT: build.Default.GOROOT, - GOFLAGS: os.Getenv("GOFLAGS"), - GO111MODULE: os.Getenv("GO111MODULE"), - GOPROXY: os.Getenv("GOPROXY"), - GOSUMDB: os.Getenv("GOSUMDB"), - LocalPrefix: LocalPrefix, + GocmdRunner: &gocommand.Runner{}, }, - AllErrors: opt.AllErrors, - Comments: opt.Comments, - FormatOnly: opt.FormatOnly, - Fragment: opt.Fragment, - TabIndent: opt.TabIndent, - TabWidth: opt.TabWidth, + LocalPrefix: LocalPrefix, + AllErrors: opt.AllErrors, + Comments: opt.Comments, + FormatOnly: opt.FormatOnly, + Fragment: opt.Fragment, + TabIndent: opt.TabIndent, + TabWidth: opt.TabWidth, } if Debug { intopt.Env.Logf = log.Printf diff --git a/vendor/golang.org/x/tools/internal/event/core/event.go b/vendor/golang.org/x/tools/internal/event/core/event.go new file mode 100644 index 000000000..e37b49491 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/event/core/event.go @@ -0,0 +1,85 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package core provides support for event based telemetry. +package core + +import ( + "fmt" + "time" + + "golang.org/x/tools/internal/event/label" +) + +// Event holds the information about an event of note that ocurred. +type Event struct { + at time.Time + + // As events are often on the stack, storing the first few labels directly + // in the event can avoid an allocation at all for the very common cases of + // simple events. + // The length needs to be large enough to cope with the majority of events + // but no so large as to cause undue stack pressure. + // A log message with two values will use 3 labels (one for each value and + // one for the message itself). + + static [3]label.Label // inline storage for the first few labels + dynamic []label.Label // dynamically sized storage for remaining labels +} + +// eventLabelMap implements label.Map for a the labels of an Event. +type eventLabelMap struct { + event Event +} + +func (ev Event) At() time.Time { return ev.at } + +func (ev Event) Format(f fmt.State, r rune) { + if !ev.at.IsZero() { + fmt.Fprint(f, ev.at.Format("2006/01/02 15:04:05 ")) + } + for index := 0; ev.Valid(index); index++ { + if l := ev.Label(index); l.Valid() { + fmt.Fprintf(f, "\n\t%v", l) + } + } +} + +func (ev Event) Valid(index int) bool { + return index >= 0 && index < len(ev.static)+len(ev.dynamic) +} + +func (ev Event) Label(index int) label.Label { + if index < len(ev.static) { + return ev.static[index] + } + return ev.dynamic[index-len(ev.static)] +} + +func (ev Event) Find(key label.Key) label.Label { + for _, l := range ev.static { + if l.Key() == key { + return l + } + } + for _, l := range ev.dynamic { + if l.Key() == key { + return l + } + } + return label.Label{} +} + +func MakeEvent(static [3]label.Label, labels []label.Label) Event { + return Event{ + static: static, + dynamic: labels, + } +} + +// CloneEvent event returns a copy of the event with the time adjusted to at. +func CloneEvent(ev Event, at time.Time) Event { + ev.at = at + return ev +} diff --git a/vendor/golang.org/x/tools/internal/event/core/export.go b/vendor/golang.org/x/tools/internal/event/core/export.go new file mode 100644 index 000000000..05f3a9a57 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/event/core/export.go @@ -0,0 +1,70 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package core + +import ( + "context" + "sync/atomic" + "time" + "unsafe" + + "golang.org/x/tools/internal/event/label" +) + +// Exporter is a function that handles events. +// It may return a modified context and event. +type Exporter func(context.Context, Event, label.Map) context.Context + +var ( + exporter unsafe.Pointer +) + +// SetExporter sets the global exporter function that handles all events. +// The exporter is called synchronously from the event call site, so it should +// return quickly so as not to hold up user code. +func SetExporter(e Exporter) { + p := unsafe.Pointer(&e) + if e == nil { + // &e is always valid, and so p is always valid, but for the early abort + // of ProcessEvent to be efficient it needs to make the nil check on the + // pointer without having to dereference it, so we make the nil function + // also a nil pointer + p = nil + } + atomic.StorePointer(&exporter, p) +} + +// deliver is called to deliver an event to the supplied exporter. +// it will fill in the time. +func deliver(ctx context.Context, exporter Exporter, ev Event) context.Context { + // add the current time to the event + ev.at = time.Now() + // hand the event off to the current exporter + return exporter(ctx, ev, ev) +} + +// Export is called to deliver an event to the global exporter if set. +func Export(ctx context.Context, ev Event) context.Context { + // get the global exporter and abort early if there is not one + exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter)) + if exporterPtr == nil { + return ctx + } + return deliver(ctx, *exporterPtr, ev) +} + +// ExportPair is called to deliver a start event to the supplied exporter. +// It also returns a function that will deliver the end event to the same +// exporter. +// It will fill in the time. +func ExportPair(ctx context.Context, begin, end Event) (context.Context, func()) { + // get the global exporter and abort early if there is not one + exporterPtr := (*Exporter)(atomic.LoadPointer(&exporter)) + if exporterPtr == nil { + return ctx, func() {} + } + ctx = deliver(ctx, *exporterPtr, begin) + return ctx, func() { deliver(ctx, *exporterPtr, end) } +} diff --git a/vendor/golang.org/x/tools/internal/event/core/fast.go b/vendor/golang.org/x/tools/internal/event/core/fast.go new file mode 100644 index 000000000..06c1d4615 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/event/core/fast.go @@ -0,0 +1,77 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package core + +import ( + "context" + + "golang.org/x/tools/internal/event/keys" + "golang.org/x/tools/internal/event/label" +) + +// Log1 takes a message and one label delivers a log event to the exporter. +// It is a customized version of Print that is faster and does no allocation. +func Log1(ctx context.Context, message string, t1 label.Label) { + Export(ctx, MakeEvent([3]label.Label{ + keys.Msg.Of(message), + t1, + }, nil)) +} + +// Log2 takes a message and two labels and delivers a log event to the exporter. +// It is a customized version of Print that is faster and does no allocation. +func Log2(ctx context.Context, message string, t1 label.Label, t2 label.Label) { + Export(ctx, MakeEvent([3]label.Label{ + keys.Msg.Of(message), + t1, + t2, + }, nil)) +} + +// Metric1 sends a label event to the exporter with the supplied labels. +func Metric1(ctx context.Context, t1 label.Label) context.Context { + return Export(ctx, MakeEvent([3]label.Label{ + keys.Metric.New(), + t1, + }, nil)) +} + +// Metric2 sends a label event to the exporter with the supplied labels. +func Metric2(ctx context.Context, t1, t2 label.Label) context.Context { + return Export(ctx, MakeEvent([3]label.Label{ + keys.Metric.New(), + t1, + t2, + }, nil)) +} + +// Start1 sends a span start event with the supplied label list to the exporter. +// It also returns a function that will end the span, which should normally be +// deferred. +func Start1(ctx context.Context, name string, t1 label.Label) (context.Context, func()) { + return ExportPair(ctx, + MakeEvent([3]label.Label{ + keys.Start.Of(name), + t1, + }, nil), + MakeEvent([3]label.Label{ + keys.End.New(), + }, nil)) +} + +// Start2 sends a span start event with the supplied label list to the exporter. +// It also returns a function that will end the span, which should normally be +// deferred. +func Start2(ctx context.Context, name string, t1, t2 label.Label) (context.Context, func()) { + return ExportPair(ctx, + MakeEvent([3]label.Label{ + keys.Start.Of(name), + t1, + t2, + }, nil), + MakeEvent([3]label.Label{ + keys.End.New(), + }, nil)) +} diff --git a/vendor/golang.org/x/tools/internal/event/doc.go b/vendor/golang.org/x/tools/internal/event/doc.go new file mode 100644 index 000000000..5dc6e6bab --- /dev/null +++ b/vendor/golang.org/x/tools/internal/event/doc.go @@ -0,0 +1,7 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package event provides a set of packages that cover the main +// concepts of telemetry in an implementation agnostic way. +package event diff --git a/vendor/golang.org/x/tools/internal/event/event.go b/vendor/golang.org/x/tools/internal/event/event.go new file mode 100644 index 000000000..4d55e577d --- /dev/null +++ b/vendor/golang.org/x/tools/internal/event/event.go @@ -0,0 +1,127 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package event + +import ( + "context" + + "golang.org/x/tools/internal/event/core" + "golang.org/x/tools/internal/event/keys" + "golang.org/x/tools/internal/event/label" +) + +// Exporter is a function that handles events. +// It may return a modified context and event. +type Exporter func(context.Context, core.Event, label.Map) context.Context + +// SetExporter sets the global exporter function that handles all events. +// The exporter is called synchronously from the event call site, so it should +// return quickly so as not to hold up user code. +func SetExporter(e Exporter) { + core.SetExporter(core.Exporter(e)) +} + +// Log takes a message and a label list and combines them into a single event +// before delivering them to the exporter. +func Log(ctx context.Context, message string, labels ...label.Label) { + core.Export(ctx, core.MakeEvent([3]label.Label{ + keys.Msg.Of(message), + }, labels)) +} + +// IsLog returns true if the event was built by the Log function. +// It is intended to be used in exporters to identify the semantics of the +// event when deciding what to do with it. +func IsLog(ev core.Event) bool { + return ev.Label(0).Key() == keys.Msg +} + +// Error takes a message and a label list and combines them into a single event +// before delivering them to the exporter. It captures the error in the +// delivered event. +func Error(ctx context.Context, message string, err error, labels ...label.Label) { + core.Export(ctx, core.MakeEvent([3]label.Label{ + keys.Msg.Of(message), + keys.Err.Of(err), + }, labels)) +} + +// IsError returns true if the event was built by the Error function. +// It is intended to be used in exporters to identify the semantics of the +// event when deciding what to do with it. +func IsError(ev core.Event) bool { + return ev.Label(0).Key() == keys.Msg && + ev.Label(1).Key() == keys.Err +} + +// Metric sends a label event to the exporter with the supplied labels. +func Metric(ctx context.Context, labels ...label.Label) { + core.Export(ctx, core.MakeEvent([3]label.Label{ + keys.Metric.New(), + }, labels)) +} + +// IsMetric returns true if the event was built by the Metric function. +// It is intended to be used in exporters to identify the semantics of the +// event when deciding what to do with it. +func IsMetric(ev core.Event) bool { + return ev.Label(0).Key() == keys.Metric +} + +// Label sends a label event to the exporter with the supplied labels. +func Label(ctx context.Context, labels ...label.Label) context.Context { + return core.Export(ctx, core.MakeEvent([3]label.Label{ + keys.Label.New(), + }, labels)) +} + +// IsLabel returns true if the event was built by the Label function. +// It is intended to be used in exporters to identify the semantics of the +// event when deciding what to do with it. +func IsLabel(ev core.Event) bool { + return ev.Label(0).Key() == keys.Label +} + +// Start sends a span start event with the supplied label list to the exporter. +// It also returns a function that will end the span, which should normally be +// deferred. +func Start(ctx context.Context, name string, labels ...label.Label) (context.Context, func()) { + return core.ExportPair(ctx, + core.MakeEvent([3]label.Label{ + keys.Start.Of(name), + }, labels), + core.MakeEvent([3]label.Label{ + keys.End.New(), + }, nil)) +} + +// IsStart returns true if the event was built by the Start function. +// It is intended to be used in exporters to identify the semantics of the +// event when deciding what to do with it. +func IsStart(ev core.Event) bool { + return ev.Label(0).Key() == keys.Start +} + +// IsEnd returns true if the event was built by the End function. +// It is intended to be used in exporters to identify the semantics of the +// event when deciding what to do with it. +func IsEnd(ev core.Event) bool { + return ev.Label(0).Key() == keys.End +} + +// Detach returns a context without an associated span. +// This allows the creation of spans that are not children of the current span. +func Detach(ctx context.Context) context.Context { + return core.Export(ctx, core.MakeEvent([3]label.Label{ + keys.Detach.New(), + }, nil)) +} + +// IsDetach returns true if the event was built by the Detach function. +// It is intended to be used in exporters to identify the semantics of the +// event when deciding what to do with it. +func IsDetach(ev core.Event) bool { + return ev.Label(0).Key() == keys.Detach +} diff --git a/vendor/golang.org/x/tools/internal/event/keys/keys.go b/vendor/golang.org/x/tools/internal/event/keys/keys.go new file mode 100644 index 000000000..a02206e30 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/event/keys/keys.go @@ -0,0 +1,564 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package keys + +import ( + "fmt" + "io" + "math" + "strconv" + + "golang.org/x/tools/internal/event/label" +) + +// Value represents a key for untyped values. +type Value struct { + name string + description string +} + +// New creates a new Key for untyped values. +func New(name, description string) *Value { + return &Value{name: name, description: description} +} + +func (k *Value) Name() string { return k.name } +func (k *Value) Description() string { return k.description } + +func (k *Value) Format(w io.Writer, buf []byte, l label.Label) { + fmt.Fprint(w, k.From(l)) +} + +// Get can be used to get a label for the key from a label.Map. +func (k *Value) Get(lm label.Map) interface{} { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return nil +} + +// From can be used to get a value from a Label. +func (k *Value) From(t label.Label) interface{} { return t.UnpackValue() } + +// Of creates a new Label with this key and the supplied value. +func (k *Value) Of(value interface{}) label.Label { return label.OfValue(k, value) } + +// Tag represents a key for tagging labels that have no value. +// These are used when the existence of the label is the entire information it +// carries, such as marking events to be of a specific kind, or from a specific +// package. +type Tag struct { + name string + description string +} + +// NewTag creates a new Key for tagging labels. +func NewTag(name, description string) *Tag { + return &Tag{name: name, description: description} +} + +func (k *Tag) Name() string { return k.name } +func (k *Tag) Description() string { return k.description } + +func (k *Tag) Format(w io.Writer, buf []byte, l label.Label) {} + +// New creates a new Label with this key. +func (k *Tag) New() label.Label { return label.OfValue(k, nil) } + +// Int represents a key +type Int struct { + name string + description string +} + +// NewInt creates a new Key for int values. +func NewInt(name, description string) *Int { + return &Int{name: name, description: description} +} + +func (k *Int) Name() string { return k.name } +func (k *Int) Description() string { return k.description } + +func (k *Int) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendInt(buf, int64(k.From(l)), 10)) +} + +// Of creates a new Label with this key and the supplied value. +func (k *Int) Of(v int) label.Label { return label.Of64(k, uint64(v)) } + +// Get can be used to get a label for the key from a label.Map. +func (k *Int) Get(lm label.Map) int { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return 0 +} + +// From can be used to get a value from a Label. +func (k *Int) From(t label.Label) int { return int(t.Unpack64()) } + +// Int8 represents a key +type Int8 struct { + name string + description string +} + +// NewInt8 creates a new Key for int8 values. +func NewInt8(name, description string) *Int8 { + return &Int8{name: name, description: description} +} + +func (k *Int8) Name() string { return k.name } +func (k *Int8) Description() string { return k.description } + +func (k *Int8) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendInt(buf, int64(k.From(l)), 10)) +} + +// Of creates a new Label with this key and the supplied value. +func (k *Int8) Of(v int8) label.Label { return label.Of64(k, uint64(v)) } + +// Get can be used to get a label for the key from a label.Map. +func (k *Int8) Get(lm label.Map) int8 { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return 0 +} + +// From can be used to get a value from a Label. +func (k *Int8) From(t label.Label) int8 { return int8(t.Unpack64()) } + +// Int16 represents a key +type Int16 struct { + name string + description string +} + +// NewInt16 creates a new Key for int16 values. +func NewInt16(name, description string) *Int16 { + return &Int16{name: name, description: description} +} + +func (k *Int16) Name() string { return k.name } +func (k *Int16) Description() string { return k.description } + +func (k *Int16) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendInt(buf, int64(k.From(l)), 10)) +} + +// Of creates a new Label with this key and the supplied value. +func (k *Int16) Of(v int16) label.Label { return label.Of64(k, uint64(v)) } + +// Get can be used to get a label for the key from a label.Map. +func (k *Int16) Get(lm label.Map) int16 { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return 0 +} + +// From can be used to get a value from a Label. +func (k *Int16) From(t label.Label) int16 { return int16(t.Unpack64()) } + +// Int32 represents a key +type Int32 struct { + name string + description string +} + +// NewInt32 creates a new Key for int32 values. +func NewInt32(name, description string) *Int32 { + return &Int32{name: name, description: description} +} + +func (k *Int32) Name() string { return k.name } +func (k *Int32) Description() string { return k.description } + +func (k *Int32) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendInt(buf, int64(k.From(l)), 10)) +} + +// Of creates a new Label with this key and the supplied value. +func (k *Int32) Of(v int32) label.Label { return label.Of64(k, uint64(v)) } + +// Get can be used to get a label for the key from a label.Map. +func (k *Int32) Get(lm label.Map) int32 { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return 0 +} + +// From can be used to get a value from a Label. +func (k *Int32) From(t label.Label) int32 { return int32(t.Unpack64()) } + +// Int64 represents a key +type Int64 struct { + name string + description string +} + +// NewInt64 creates a new Key for int64 values. +func NewInt64(name, description string) *Int64 { + return &Int64{name: name, description: description} +} + +func (k *Int64) Name() string { return k.name } +func (k *Int64) Description() string { return k.description } + +func (k *Int64) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendInt(buf, k.From(l), 10)) +} + +// Of creates a new Label with this key and the supplied value. +func (k *Int64) Of(v int64) label.Label { return label.Of64(k, uint64(v)) } + +// Get can be used to get a label for the key from a label.Map. +func (k *Int64) Get(lm label.Map) int64 { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return 0 +} + +// From can be used to get a value from a Label. +func (k *Int64) From(t label.Label) int64 { return int64(t.Unpack64()) } + +// UInt represents a key +type UInt struct { + name string + description string +} + +// NewUInt creates a new Key for uint values. +func NewUInt(name, description string) *UInt { + return &UInt{name: name, description: description} +} + +func (k *UInt) Name() string { return k.name } +func (k *UInt) Description() string { return k.description } + +func (k *UInt) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendUint(buf, uint64(k.From(l)), 10)) +} + +// Of creates a new Label with this key and the supplied value. +func (k *UInt) Of(v uint) label.Label { return label.Of64(k, uint64(v)) } + +// Get can be used to get a label for the key from a label.Map. +func (k *UInt) Get(lm label.Map) uint { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return 0 +} + +// From can be used to get a value from a Label. +func (k *UInt) From(t label.Label) uint { return uint(t.Unpack64()) } + +// UInt8 represents a key +type UInt8 struct { + name string + description string +} + +// NewUInt8 creates a new Key for uint8 values. +func NewUInt8(name, description string) *UInt8 { + return &UInt8{name: name, description: description} +} + +func (k *UInt8) Name() string { return k.name } +func (k *UInt8) Description() string { return k.description } + +func (k *UInt8) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendUint(buf, uint64(k.From(l)), 10)) +} + +// Of creates a new Label with this key and the supplied value. +func (k *UInt8) Of(v uint8) label.Label { return label.Of64(k, uint64(v)) } + +// Get can be used to get a label for the key from a label.Map. +func (k *UInt8) Get(lm label.Map) uint8 { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return 0 +} + +// From can be used to get a value from a Label. +func (k *UInt8) From(t label.Label) uint8 { return uint8(t.Unpack64()) } + +// UInt16 represents a key +type UInt16 struct { + name string + description string +} + +// NewUInt16 creates a new Key for uint16 values. +func NewUInt16(name, description string) *UInt16 { + return &UInt16{name: name, description: description} +} + +func (k *UInt16) Name() string { return k.name } +func (k *UInt16) Description() string { return k.description } + +func (k *UInt16) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendUint(buf, uint64(k.From(l)), 10)) +} + +// Of creates a new Label with this key and the supplied value. +func (k *UInt16) Of(v uint16) label.Label { return label.Of64(k, uint64(v)) } + +// Get can be used to get a label for the key from a label.Map. +func (k *UInt16) Get(lm label.Map) uint16 { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return 0 +} + +// From can be used to get a value from a Label. +func (k *UInt16) From(t label.Label) uint16 { return uint16(t.Unpack64()) } + +// UInt32 represents a key +type UInt32 struct { + name string + description string +} + +// NewUInt32 creates a new Key for uint32 values. +func NewUInt32(name, description string) *UInt32 { + return &UInt32{name: name, description: description} +} + +func (k *UInt32) Name() string { return k.name } +func (k *UInt32) Description() string { return k.description } + +func (k *UInt32) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendUint(buf, uint64(k.From(l)), 10)) +} + +// Of creates a new Label with this key and the supplied value. +func (k *UInt32) Of(v uint32) label.Label { return label.Of64(k, uint64(v)) } + +// Get can be used to get a label for the key from a label.Map. +func (k *UInt32) Get(lm label.Map) uint32 { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return 0 +} + +// From can be used to get a value from a Label. +func (k *UInt32) From(t label.Label) uint32 { return uint32(t.Unpack64()) } + +// UInt64 represents a key +type UInt64 struct { + name string + description string +} + +// NewUInt64 creates a new Key for uint64 values. +func NewUInt64(name, description string) *UInt64 { + return &UInt64{name: name, description: description} +} + +func (k *UInt64) Name() string { return k.name } +func (k *UInt64) Description() string { return k.description } + +func (k *UInt64) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendUint(buf, k.From(l), 10)) +} + +// Of creates a new Label with this key and the supplied value. +func (k *UInt64) Of(v uint64) label.Label { return label.Of64(k, v) } + +// Get can be used to get a label for the key from a label.Map. +func (k *UInt64) Get(lm label.Map) uint64 { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return 0 +} + +// From can be used to get a value from a Label. +func (k *UInt64) From(t label.Label) uint64 { return t.Unpack64() } + +// Float32 represents a key +type Float32 struct { + name string + description string +} + +// NewFloat32 creates a new Key for float32 values. +func NewFloat32(name, description string) *Float32 { + return &Float32{name: name, description: description} +} + +func (k *Float32) Name() string { return k.name } +func (k *Float32) Description() string { return k.description } + +func (k *Float32) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendFloat(buf, float64(k.From(l)), 'E', -1, 32)) +} + +// Of creates a new Label with this key and the supplied value. +func (k *Float32) Of(v float32) label.Label { + return label.Of64(k, uint64(math.Float32bits(v))) +} + +// Get can be used to get a label for the key from a label.Map. +func (k *Float32) Get(lm label.Map) float32 { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return 0 +} + +// From can be used to get a value from a Label. +func (k *Float32) From(t label.Label) float32 { + return math.Float32frombits(uint32(t.Unpack64())) +} + +// Float64 represents a key +type Float64 struct { + name string + description string +} + +// NewFloat64 creates a new Key for int64 values. +func NewFloat64(name, description string) *Float64 { + return &Float64{name: name, description: description} +} + +func (k *Float64) Name() string { return k.name } +func (k *Float64) Description() string { return k.description } + +func (k *Float64) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendFloat(buf, k.From(l), 'E', -1, 64)) +} + +// Of creates a new Label with this key and the supplied value. +func (k *Float64) Of(v float64) label.Label { + return label.Of64(k, math.Float64bits(v)) +} + +// Get can be used to get a label for the key from a label.Map. +func (k *Float64) Get(lm label.Map) float64 { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return 0 +} + +// From can be used to get a value from a Label. +func (k *Float64) From(t label.Label) float64 { + return math.Float64frombits(t.Unpack64()) +} + +// String represents a key +type String struct { + name string + description string +} + +// NewString creates a new Key for int64 values. +func NewString(name, description string) *String { + return &String{name: name, description: description} +} + +func (k *String) Name() string { return k.name } +func (k *String) Description() string { return k.description } + +func (k *String) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendQuote(buf, k.From(l))) +} + +// Of creates a new Label with this key and the supplied value. +func (k *String) Of(v string) label.Label { return label.OfString(k, v) } + +// Get can be used to get a label for the key from a label.Map. +func (k *String) Get(lm label.Map) string { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return "" +} + +// From can be used to get a value from a Label. +func (k *String) From(t label.Label) string { return t.UnpackString() } + +// Boolean represents a key +type Boolean struct { + name string + description string +} + +// NewBoolean creates a new Key for bool values. +func NewBoolean(name, description string) *Boolean { + return &Boolean{name: name, description: description} +} + +func (k *Boolean) Name() string { return k.name } +func (k *Boolean) Description() string { return k.description } + +func (k *Boolean) Format(w io.Writer, buf []byte, l label.Label) { + w.Write(strconv.AppendBool(buf, k.From(l))) +} + +// Of creates a new Label with this key and the supplied value. +func (k *Boolean) Of(v bool) label.Label { + if v { + return label.Of64(k, 1) + } + return label.Of64(k, 0) +} + +// Get can be used to get a label for the key from a label.Map. +func (k *Boolean) Get(lm label.Map) bool { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return false +} + +// From can be used to get a value from a Label. +func (k *Boolean) From(t label.Label) bool { return t.Unpack64() > 0 } + +// Error represents a key +type Error struct { + name string + description string +} + +// NewError creates a new Key for int64 values. +func NewError(name, description string) *Error { + return &Error{name: name, description: description} +} + +func (k *Error) Name() string { return k.name } +func (k *Error) Description() string { return k.description } + +func (k *Error) Format(w io.Writer, buf []byte, l label.Label) { + io.WriteString(w, k.From(l).Error()) +} + +// Of creates a new Label with this key and the supplied value. +func (k *Error) Of(v error) label.Label { return label.OfValue(k, v) } + +// Get can be used to get a label for the key from a label.Map. +func (k *Error) Get(lm label.Map) error { + if t := lm.Find(k); t.Valid() { + return k.From(t) + } + return nil +} + +// From can be used to get a value from a Label. +func (k *Error) From(t label.Label) error { + err, _ := t.UnpackValue().(error) + return err +} diff --git a/vendor/golang.org/x/tools/internal/event/keys/standard.go b/vendor/golang.org/x/tools/internal/event/keys/standard.go new file mode 100644 index 000000000..7e9586659 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/event/keys/standard.go @@ -0,0 +1,22 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package keys + +var ( + // Msg is a key used to add message strings to label lists. + Msg = NewString("message", "a readable message") + // Label is a key used to indicate an event adds labels to the context. + Label = NewTag("label", "a label context marker") + // Start is used for things like traces that have a name. + Start = NewString("start", "span start") + // Metric is a key used to indicate an event records metrics. + End = NewTag("end", "a span end marker") + // Metric is a key used to indicate an event records metrics. + Detach = NewTag("detach", "a span detach marker") + // Err is a key used to add error values to label lists. + Err = NewError("error", "an error that occurred") + // Metric is a key used to indicate an event records metrics. + Metric = NewTag("metric", "a metric event marker") +) diff --git a/vendor/golang.org/x/tools/internal/event/label/label.go b/vendor/golang.org/x/tools/internal/event/label/label.go new file mode 100644 index 000000000..b55c12eb2 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/event/label/label.go @@ -0,0 +1,213 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package label + +import ( + "fmt" + "io" + "reflect" + "unsafe" +) + +// Key is used as the identity of a Label. +// Keys are intended to be compared by pointer only, the name should be unique +// for communicating with external systems, but it is not required or enforced. +type Key interface { + // Name returns the key name. + Name() string + // Description returns a string that can be used to describe the value. + Description() string + + // Format is used in formatting to append the value of the label to the + // supplied buffer. + // The formatter may use the supplied buf as a scratch area to avoid + // allocations. + Format(w io.Writer, buf []byte, l Label) +} + +// Label holds a key and value pair. +// It is normally used when passing around lists of labels. +type Label struct { + key Key + packed uint64 + untyped interface{} +} + +// Map is the interface to a collection of Labels indexed by key. +type Map interface { + // Find returns the label that matches the supplied key. + Find(key Key) Label +} + +// List is the interface to something that provides an iterable +// list of labels. +// Iteration should start from 0 and continue until Valid returns false. +type List interface { + // Valid returns true if the index is within range for the list. + // It does not imply the label at that index will itself be valid. + Valid(index int) bool + // Label returns the label at the given index. + Label(index int) Label +} + +// list implements LabelList for a list of Labels. +type list struct { + labels []Label +} + +// filter wraps a LabelList filtering out specific labels. +type filter struct { + keys []Key + underlying List +} + +// listMap implements LabelMap for a simple list of labels. +type listMap struct { + labels []Label +} + +// mapChain implements LabelMap for a list of underlying LabelMap. +type mapChain struct { + maps []Map +} + +// OfValue creates a new label from the key and value. +// This method is for implementing new key types, label creation should +// normally be done with the Of method of the key. +func OfValue(k Key, value interface{}) Label { return Label{key: k, untyped: value} } + +// UnpackValue assumes the label was built using LabelOfValue and returns the value +// that was passed to that constructor. +// This method is for implementing new key types, for type safety normal +// access should be done with the From method of the key. +func (t Label) UnpackValue() interface{} { return t.untyped } + +// Of64 creates a new label from a key and a uint64. This is often +// used for non uint64 values that can be packed into a uint64. +// This method is for implementing new key types, label creation should +// normally be done with the Of method of the key. +func Of64(k Key, v uint64) Label { return Label{key: k, packed: v} } + +// Unpack64 assumes the label was built using LabelOf64 and returns the value that +// was passed to that constructor. +// This method is for implementing new key types, for type safety normal +// access should be done with the From method of the key. +func (t Label) Unpack64() uint64 { return t.packed } + +// OfString creates a new label from a key and a string. +// This method is for implementing new key types, label creation should +// normally be done with the Of method of the key. +func OfString(k Key, v string) Label { + hdr := (*reflect.StringHeader)(unsafe.Pointer(&v)) + return Label{ + key: k, + packed: uint64(hdr.Len), + untyped: unsafe.Pointer(hdr.Data), + } +} + +// UnpackString assumes the label was built using LabelOfString and returns the +// value that was passed to that constructor. +// This method is for implementing new key types, for type safety normal +// access should be done with the From method of the key. +func (t Label) UnpackString() string { + var v string + hdr := (*reflect.StringHeader)(unsafe.Pointer(&v)) + hdr.Data = uintptr(t.untyped.(unsafe.Pointer)) + hdr.Len = int(t.packed) + return *(*string)(unsafe.Pointer(hdr)) +} + +// Valid returns true if the Label is a valid one (it has a key). +func (t Label) Valid() bool { return t.key != nil } + +// Key returns the key of this Label. +func (t Label) Key() Key { return t.key } + +// Format is used for debug printing of labels. +func (t Label) Format(f fmt.State, r rune) { + if !t.Valid() { + io.WriteString(f, `nil`) + return + } + io.WriteString(f, t.Key().Name()) + io.WriteString(f, "=") + var buf [128]byte + t.Key().Format(f, buf[:0], t) +} + +func (l *list) Valid(index int) bool { + return index >= 0 && index < len(l.labels) +} + +func (l *list) Label(index int) Label { + return l.labels[index] +} + +func (f *filter) Valid(index int) bool { + return f.underlying.Valid(index) +} + +func (f *filter) Label(index int) Label { + l := f.underlying.Label(index) + for _, f := range f.keys { + if l.Key() == f { + return Label{} + } + } + return l +} + +func (lm listMap) Find(key Key) Label { + for _, l := range lm.labels { + if l.Key() == key { + return l + } + } + return Label{} +} + +func (c mapChain) Find(key Key) Label { + for _, src := range c.maps { + l := src.Find(key) + if l.Valid() { + return l + } + } + return Label{} +} + +var emptyList = &list{} + +func NewList(labels ...Label) List { + if len(labels) == 0 { + return emptyList + } + return &list{labels: labels} +} + +func Filter(l List, keys ...Key) List { + if len(keys) == 0 { + return l + } + return &filter{keys: keys, underlying: l} +} + +func NewMap(labels ...Label) Map { + return listMap{labels: labels} +} + +func MergeMaps(srcs ...Map) Map { + var nonNil []Map + for _, src := range srcs { + if src != nil { + nonNil = append(nonNil, src) + } + } + if len(nonNil) == 1 { + return nonNil[0] + } + return mapChain{maps: nonNil} +} diff --git a/vendor/golang.org/x/tools/internal/gocommand/invoke.go b/vendor/golang.org/x/tools/internal/gocommand/invoke.go index 468db4010..f516e1762 100644 --- a/vendor/golang.org/x/tools/internal/gocommand/invoke.go +++ b/vendor/golang.org/x/tools/internal/gocommand/invoke.go @@ -1,3 +1,7 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + // Package gocommand is a helper for calling the go command. package gocommand @@ -8,10 +12,119 @@ import ( "io" "os" "os/exec" + "regexp" "strings" + "sync" "time" + + "golang.org/x/tools/internal/event" ) +// An Runner will run go command invocations and serialize +// them if it sees a concurrency error. +type Runner struct { + // once guards the runner initialization. + once sync.Once + + // inFlight tracks available workers. + inFlight chan struct{} + + // serialized guards the ability to run a go command serially, + // to avoid deadlocks when claiming workers. + serialized chan struct{} +} + +const maxInFlight = 10 + +func (runner *Runner) initialize() { + runner.once.Do(func() { + runner.inFlight = make(chan struct{}, maxInFlight) + runner.serialized = make(chan struct{}, 1) + }) +} + +// 1.13: go: updates to go.mod needed, but contents have changed +// 1.14: go: updating go.mod: existing contents have changed since last read +var modConcurrencyError = regexp.MustCompile(`go:.*go.mod.*contents have changed`) + +// Run is a convenience wrapper around RunRaw. +// It returns only stdout and a "friendly" error. +func (runner *Runner) Run(ctx context.Context, inv Invocation) (*bytes.Buffer, error) { + stdout, _, friendly, _ := runner.RunRaw(ctx, inv) + return stdout, friendly +} + +// RunPiped runs the invocation serially, always waiting for any concurrent +// invocations to complete first. +func (runner *Runner) RunPiped(ctx context.Context, inv Invocation, stdout, stderr io.Writer) error { + _, err := runner.runPiped(ctx, inv, stdout, stderr) + return err +} + +// RunRaw runs the invocation, serializing requests only if they fight over +// go.mod changes. +func (runner *Runner) RunRaw(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) { + // Make sure the runner is always initialized. + runner.initialize() + + // First, try to run the go command concurrently. + stdout, stderr, friendlyErr, err := runner.runConcurrent(ctx, inv) + + // If we encounter a load concurrency error, we need to retry serially. + if friendlyErr == nil || !modConcurrencyError.MatchString(friendlyErr.Error()) { + return stdout, stderr, friendlyErr, err + } + event.Error(ctx, "Load concurrency error, will retry serially", err) + + // Run serially by calling runPiped. + stdout.Reset() + stderr.Reset() + friendlyErr, err = runner.runPiped(ctx, inv, stdout, stderr) + return stdout, stderr, friendlyErr, err +} + +func (runner *Runner) runConcurrent(ctx context.Context, inv Invocation) (*bytes.Buffer, *bytes.Buffer, error, error) { + // Wait for 1 worker to become available. + select { + case <-ctx.Done(): + return nil, nil, nil, ctx.Err() + case runner.inFlight <- struct{}{}: + defer func() { <-runner.inFlight }() + } + + stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{} + friendlyErr, err := inv.runWithFriendlyError(ctx, stdout, stderr) + return stdout, stderr, friendlyErr, err +} + +func (runner *Runner) runPiped(ctx context.Context, inv Invocation, stdout, stderr io.Writer) (error, error) { + // Make sure the runner is always initialized. + runner.initialize() + + // Acquire the serialization lock. This avoids deadlocks between two + // runPiped commands. + select { + case <-ctx.Done(): + return nil, ctx.Err() + case runner.serialized <- struct{}{}: + defer func() { <-runner.serialized }() + } + + // Wait for all in-progress go commands to return before proceeding, + // to avoid load concurrency errors. + for i := 0; i < maxInFlight; i++ { + select { + case <-ctx.Done(): + return nil, ctx.Err() + case runner.inFlight <- struct{}{}: + // Make sure we always "return" any workers we took. + defer func() { <-runner.inFlight }() + } + } + + return inv.runWithFriendlyError(ctx, stdout, stderr) +} + // An Invocation represents a call to the go command. type Invocation struct { Verb string @@ -22,20 +135,10 @@ type Invocation struct { Logf func(format string, args ...interface{}) } -// Run runs the invocation, returning its stdout and an error suitable for -// human consumption, including stderr. -func (i *Invocation) Run(ctx context.Context) (*bytes.Buffer, error) { - stdout, _, friendly, _ := i.RunRaw(ctx) - return stdout, friendly -} - -// RunRaw is like RunPiped, but also returns the raw stderr and error for callers -// that want to do low-level error handling/recovery. -func (i *Invocation) RunRaw(ctx context.Context) (stdout *bytes.Buffer, stderr *bytes.Buffer, friendlyError error, rawError error) { - stdout = &bytes.Buffer{} - stderr = &bytes.Buffer{} - rawError = i.RunPiped(ctx, stdout, stderr) +func (i *Invocation) runWithFriendlyError(ctx context.Context, stdout, stderr io.Writer) (friendlyError error, rawError error) { + rawError = i.run(ctx, stdout, stderr) if rawError != nil { + friendlyError = rawError // Check for 'go' executable not being found. if ee, ok := rawError.(*exec.Error); ok && ee.Err == exec.ErrNotFound { friendlyError = fmt.Errorf("go command required, not found: %v", ee) @@ -43,13 +146,12 @@ func (i *Invocation) RunRaw(ctx context.Context) (stdout *bytes.Buffer, stderr * if ctx.Err() != nil { friendlyError = ctx.Err() } - friendlyError = fmt.Errorf("err: %v: stderr: %s", rawError, stderr) + friendlyError = fmt.Errorf("err: %v: stderr: %s", friendlyError, stderr) } return } -// RunPiped is like Run, but relies on the given stdout/stderr -func (i *Invocation) RunPiped(ctx context.Context, stdout, stderr io.Writer) error { +func (i *Invocation) run(ctx context.Context, stdout, stderr io.Writer) error { log := i.Logf if log == nil { log = func(string, ...interface{}) {} @@ -78,9 +180,11 @@ func (i *Invocation) RunPiped(ctx context.Context, stdout, stderr io.Writer) err // The Go stdlib has a special feature where if the cwd and the PWD are the // same node then it trusts the PWD, so by setting it in the env for the child // process we fix up all the paths returned by the go command. - cmd.Env = append(append([]string{}, i.Env...), "PWD="+i.WorkingDir) - cmd.Dir = i.WorkingDir - + cmd.Env = append(os.Environ(), i.Env...) + if i.WorkingDir != "" { + cmd.Env = append(cmd.Env, "PWD="+i.WorkingDir) + cmd.Dir = i.WorkingDir + } defer func(start time.Time) { log("%s for %v", time.Since(start), cmdDebugStr(cmd)) }(time.Now()) return runCmdContext(ctx, cmd) diff --git a/vendor/golang.org/x/tools/internal/gocommand/vendor.go b/vendor/golang.org/x/tools/internal/gocommand/vendor.go new file mode 100644 index 000000000..1cd8d8473 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/gocommand/vendor.go @@ -0,0 +1,102 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gocommand + +import ( + "bytes" + "context" + "fmt" + "os" + "path/filepath" + "regexp" + "strings" + + "golang.org/x/mod/semver" +) + +// ModuleJSON holds information about a module. +type ModuleJSON struct { + Path string // module path + Replace *ModuleJSON // replaced by this module + Main bool // is this the main module? + Indirect bool // is this module only an indirect dependency of main module? + Dir string // directory holding files for this module, if any + GoMod string // path to go.mod file for this module, if any + GoVersion string // go version used in module +} + +var modFlagRegexp = regexp.MustCompile(`-mod[ =](\w+)`) + +// VendorEnabled reports whether vendoring is enabled. It takes a *Runner to execute Go commands +// with the supplied context.Context and Invocation. The Invocation can contain pre-defined fields, +// of which only Verb and Args are modified to run the appropriate Go command. +// Inspired by setDefaultBuildMod in modload/init.go +func VendorEnabled(ctx context.Context, inv Invocation, r *Runner) (*ModuleJSON, bool, error) { + mainMod, go114, err := getMainModuleAnd114(ctx, inv, r) + if err != nil { + return nil, false, err + } + + // We check the GOFLAGS to see if there is anything overridden or not. + inv.Verb = "env" + inv.Args = []string{"GOFLAGS"} + stdout, err := r.Run(ctx, inv) + if err != nil { + return nil, false, err + } + goflags := string(bytes.TrimSpace(stdout.Bytes())) + matches := modFlagRegexp.FindStringSubmatch(goflags) + var modFlag string + if len(matches) != 0 { + modFlag = matches[1] + } + if modFlag != "" { + // Don't override an explicit '-mod=' argument. + return mainMod, modFlag == "vendor", nil + } + if mainMod == nil || !go114 { + return mainMod, false, nil + } + // Check 1.14's automatic vendor mode. + if fi, err := os.Stat(filepath.Join(mainMod.Dir, "vendor")); err == nil && fi.IsDir() { + if mainMod.GoVersion != "" && semver.Compare("v"+mainMod.GoVersion, "v1.14") >= 0 { + // The Go version is at least 1.14, and a vendor directory exists. + // Set -mod=vendor by default. + return mainMod, true, nil + } + } + return mainMod, false, nil +} + +// getMainModuleAnd114 gets the main module's information and whether the +// go command in use is 1.14+. This is the information needed to figure out +// if vendoring should be enabled. +func getMainModuleAnd114(ctx context.Context, inv Invocation, r *Runner) (*ModuleJSON, bool, error) { + const format = `{{.Path}} +{{.Dir}} +{{.GoMod}} +{{.GoVersion}} +{{range context.ReleaseTags}}{{if eq . "go1.14"}}{{.}}{{end}}{{end}} +` + inv.Verb = "list" + inv.Args = []string{"-m", "-f", format} + stdout, err := r.Run(ctx, inv) + if err != nil { + return nil, false, err + } + + lines := strings.Split(stdout.String(), "\n") + if len(lines) < 5 { + return nil, false, fmt.Errorf("unexpected stdout: %q", stdout.String()) + } + mod := &ModuleJSON{ + Path: lines[0], + Dir: lines[1], + GoMod: lines[2], + GoVersion: lines[3], + Main: true, + } + return mod, lines[4] == "go1.14", nil +} diff --git a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go b/vendor/golang.org/x/tools/internal/gopathwalk/walk.go index 390cb9db7..925ff5356 100644 --- a/vendor/golang.org/x/tools/internal/gopathwalk/walk.go +++ b/vendor/golang.org/x/tools/internal/gopathwalk/walk.go @@ -10,7 +10,6 @@ import ( "bufio" "bytes" "fmt" - "go/build" "io/ioutil" "log" "os" @@ -47,16 +46,6 @@ type Root struct { Type RootType } -// SrcDirsRoots returns the roots from build.Default.SrcDirs(). Not modules-compatible. -func SrcDirsRoots(ctx *build.Context) []Root { - var roots []Root - roots = append(roots, Root{filepath.Join(ctx.GOROOT, "src"), RootGOROOT}) - for _, p := range filepath.SplitList(ctx.GOPATH) { - roots = append(roots, Root{filepath.Join(p, "src"), RootGOPATH}) - } - return roots -} - // Walk walks Go source directories ($GOROOT, $GOPATH, etc) to find packages. // For each package found, add will be called (concurrently) with the absolute // paths of the containing source directory and the package directory. diff --git a/vendor/golang.org/x/tools/internal/imports/fix.go b/vendor/golang.org/x/tools/internal/imports/fix.go index 92a23439f..613afc4d6 100644 --- a/vendor/golang.org/x/tools/internal/imports/fix.go +++ b/vendor/golang.org/x/tools/internal/imports/fix.go @@ -7,6 +7,7 @@ package imports import ( "bytes" "context" + "encoding/json" "fmt" "go/ast" "go/build" @@ -31,35 +32,36 @@ import ( // importToGroup is a list of functions which map from an import path to // a group number. -var importToGroup = []func(env *ProcessEnv, importPath string) (num int, ok bool){ - func(env *ProcessEnv, importPath string) (num int, ok bool) { - if env.LocalPrefix == "" { +var importToGroup = []func(localPrefix, importPath string) (num int, ok bool){ + func(localPrefix, importPath string) (num int, ok bool) { + if localPrefix == "" { return } - for _, p := range strings.Split(env.LocalPrefix, ",") { + for _, p := range strings.Split(localPrefix, ",") { if strings.HasPrefix(importPath, p) || strings.TrimSuffix(p, "/") == importPath { return 3, true } } return }, - func(_ *ProcessEnv, importPath string) (num int, ok bool) { + func(_, importPath string) (num int, ok bool) { if strings.HasPrefix(importPath, "appengine") { return 2, true } return }, - func(_ *ProcessEnv, importPath string) (num int, ok bool) { - if strings.Contains(importPath, ".") { + func(_, importPath string) (num int, ok bool) { + firstComponent := strings.Split(importPath, "/")[0] + if strings.Contains(firstComponent, ".") { return 1, true } return }, } -func importGroup(env *ProcessEnv, importPath string) int { +func importGroup(localPrefix, importPath string) int { for _, fn := range importToGroup { - if n, ok := fn(env, importPath); ok { + if n, ok := fn(localPrefix, importPath); ok { return n } } @@ -276,7 +278,12 @@ func (p *pass) loadPackageNames(imports []*ImportInfo) error { unknown = append(unknown, imp.ImportPath) } - names, err := p.env.GetResolver().loadPackageNames(unknown, p.srcDir) + resolver, err := p.env.GetResolver() + if err != nil { + return err + } + + names, err := resolver.loadPackageNames(unknown, p.srcDir) if err != nil { return err } @@ -566,7 +573,9 @@ func getFixes(fset *token.FileSet, f *ast.File, filename string, env *ProcessEnv return fixes, nil } - addStdlibCandidates(p, p.missingRefs) + if err := addStdlibCandidates(p, p.missingRefs); err != nil { + return nil, err + } p.assumeSiblingImportsValid() if fixes, done := p.fix(); done { return fixes, nil @@ -594,15 +603,19 @@ func getCandidatePkgs(ctx context.Context, wrappedCallback *scanCallback, filena notSelf := func(p *pkg) bool { return p.packageName != filePkg || p.dir != filepath.Dir(filename) } + goenv, err := env.goEnv() + if err != nil { + return err + } // Start off with the standard library. for importPath, exports := range stdlib { p := &pkg{ - dir: filepath.Join(env.GOROOT, "src", importPath), + dir: filepath.Join(goenv["GOROOT"], "src", importPath), importPathShort: importPath, packageName: path.Base(importPath), relevance: MaxRelevance, } - if notSelf(p) && wrappedCallback.packageNameLoaded(p) { + if notSelf(p) && wrappedCallback.dirFound(p) && wrappedCallback.packageNameLoaded(p) { wrappedCallback.exportsLoaded(p, exports) } } @@ -638,15 +651,23 @@ func getCandidatePkgs(ctx context.Context, wrappedCallback *scanCallback, filena wrappedCallback.exportsLoaded(pkg, exports) }, } - return env.GetResolver().scan(ctx, scanFilter) + resolver, err := env.GetResolver() + if err != nil { + return err + } + return resolver.scan(ctx, scanFilter) } -func ScoreImportPaths(ctx context.Context, env *ProcessEnv, paths []string) map[string]int { +func ScoreImportPaths(ctx context.Context, env *ProcessEnv, paths []string) (map[string]int, error) { result := make(map[string]int) - for _, path := range paths { - result[path] = env.GetResolver().scoreImportPath(ctx, path) + resolver, err := env.GetResolver() + if err != nil { + return nil, err } - return result + for _, path := range paths { + result[path] = resolver.scoreImportPath(ctx, path) + } + return result, nil } func PrimeCache(ctx context.Context, env *ProcessEnv) error { @@ -672,8 +693,9 @@ func candidateImportName(pkg *pkg) string { return "" } -// getAllCandidates gets all of the candidates to be imported, regardless of if they are needed. -func getAllCandidates(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error { +// GetAllCandidates calls wrapped for each package whose name starts with +// searchPrefix, and can be imported from filename with the package name filePkg. +func GetAllCandidates(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error { callback := &scanCallback{ rootFound: func(gopathwalk.Root) bool { return true @@ -706,13 +728,43 @@ func getAllCandidates(ctx context.Context, wrapped func(ImportFix), searchPrefix return getCandidatePkgs(ctx, callback, filename, filePkg, env) } +// GetImportPaths calls wrapped for each package whose import path starts with +// searchPrefix, and can be imported from filename with the package name filePkg. +func GetImportPaths(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error { + callback := &scanCallback{ + rootFound: func(gopathwalk.Root) bool { + return true + }, + dirFound: func(pkg *pkg) bool { + if !canUse(filename, pkg.dir) { + return false + } + return strings.HasPrefix(pkg.importPathShort, searchPrefix) + }, + packageNameLoaded: func(pkg *pkg) bool { + wrapped(ImportFix{ + StmtInfo: ImportInfo{ + ImportPath: pkg.importPathShort, + Name: candidateImportName(pkg), + }, + IdentName: pkg.packageName, + FixType: AddImport, + Relevance: pkg.relevance, + }) + return false + }, + } + return getCandidatePkgs(ctx, callback, filename, filePkg, env) +} + // A PackageExport is a package and its exports. type PackageExport struct { Fix *ImportFix Exports []string } -func getPackageExports(ctx context.Context, wrapped func(PackageExport), searchPkg, filename, filePkg string, env *ProcessEnv) error { +// GetPackageExports returns all known packages with name pkg and their exports. +func GetPackageExports(ctx context.Context, wrapped func(PackageExport), searchPkg, filename, filePkg string, env *ProcessEnv) error { callback := &scanCallback{ rootFound: func(gopathwalk.Root) bool { return true @@ -742,67 +794,126 @@ func getPackageExports(ctx context.Context, wrapped func(PackageExport), searchP return getCandidatePkgs(ctx, callback, filename, filePkg, env) } +var RequiredGoEnvVars = []string{"GO111MODULE", "GOFLAGS", "GOINSECURE", "GOMOD", "GOMODCACHE", "GONOPROXY", "GONOSUMDB", "GOPATH", "GOPROXY", "GOROOT", "GOSUMDB"} + // ProcessEnv contains environment variables and settings that affect the use of // the go command, the go/build package, etc. type ProcessEnv struct { - LocalPrefix string + GocmdRunner *gocommand.Runner BuildFlags []string - // If non-empty, these will be used instead of the - // process-wide values. - GOPATH, GOROOT, GO111MODULE, GOPROXY, GOFLAGS, GOSUMDB string - WorkingDir string + // Env overrides the OS environment, and can be used to specify + // GOPROXY, GO111MODULE, etc. PATH cannot be set here, because + // exec.Command will not honor it. + // Specifying all of RequiredGoEnvVars avoids a call to `go env`. + Env map[string]string + + WorkingDir string // If Logf is non-nil, debug logging is enabled through this function. Logf func(format string, args ...interface{}) + initialized bool + resolver Resolver } +func (e *ProcessEnv) goEnv() (map[string]string, error) { + if err := e.init(); err != nil { + return nil, err + } + return e.Env, nil +} + +func (e *ProcessEnv) matchFile(dir, name string) (bool, error) { + return build.Default.MatchFile(dir, name) +} + // CopyConfig copies the env's configuration into a new env. func (e *ProcessEnv) CopyConfig() *ProcessEnv { - copy := *e - copy.resolver = nil - return © + copy := &ProcessEnv{ + GocmdRunner: e.GocmdRunner, + initialized: e.initialized, + BuildFlags: e.BuildFlags, + Logf: e.Logf, + WorkingDir: e.WorkingDir, + resolver: nil, + Env: map[string]string{}, + } + for k, v := range e.Env { + copy.Env[k] = v + } + return copy +} + +func (e *ProcessEnv) init() error { + if e.initialized { + return nil + } + + foundAllRequired := true + for _, k := range RequiredGoEnvVars { + if _, ok := e.Env[k]; !ok { + foundAllRequired = false + break + } + } + if foundAllRequired { + e.initialized = true + return nil + } + + if e.Env == nil { + e.Env = map[string]string{} + } + + goEnv := map[string]string{} + stdout, err := e.invokeGo(context.TODO(), "env", append([]string{"-json"}, RequiredGoEnvVars...)...) + if err != nil { + return err + } + if err := json.Unmarshal(stdout.Bytes(), &goEnv); err != nil { + return err + } + for k, v := range goEnv { + e.Env[k] = v + } + e.initialized = true + return nil } func (e *ProcessEnv) env() []string { - env := os.Environ() - add := func(k, v string) { - if v != "" { - env = append(env, k+"="+v) - } - } - add("GOPATH", e.GOPATH) - add("GOROOT", e.GOROOT) - add("GO111MODULE", e.GO111MODULE) - add("GOPROXY", e.GOPROXY) - add("GOFLAGS", e.GOFLAGS) - add("GOSUMDB", e.GOSUMDB) - if e.WorkingDir != "" { - add("PWD", e.WorkingDir) + var env []string // the gocommand package will prepend os.Environ. + for k, v := range e.Env { + env = append(env, k+"="+v) } return env } -func (e *ProcessEnv) GetResolver() Resolver { +func (e *ProcessEnv) GetResolver() (Resolver, error) { if e.resolver != nil { - return e.resolver + return e.resolver, nil } - out, err := e.invokeGo(context.TODO(), "env", "GOMOD") - if err != nil || len(bytes.TrimSpace(out.Bytes())) == 0 { + if err := e.init(); err != nil { + return nil, err + } + if len(e.Env["GOMOD"]) == 0 { e.resolver = newGopathResolver(e) - return e.resolver + return e.resolver, nil } e.resolver = newModuleResolver(e) - return e.resolver + return e.resolver, nil } -func (e *ProcessEnv) buildContext() *build.Context { +func (e *ProcessEnv) buildContext() (*build.Context, error) { ctx := build.Default - ctx.GOROOT = e.GOROOT - ctx.GOPATH = e.GOPATH + goenv, err := e.goEnv() + if err != nil { + return nil, err + } + ctx.GOROOT = goenv["GOROOT"] + ctx.GOPATH = goenv["GOPATH"] // As of Go 1.14, build.Context has a Dir field // (see golang.org/issue/34860). @@ -818,7 +929,7 @@ func (e *ProcessEnv) buildContext() *build.Context { dir.SetString(e.WorkingDir) } - return &ctx + return &ctx, nil } func (e *ProcessEnv) invokeGo(ctx context.Context, verb string, args ...string) (*bytes.Buffer, error) { @@ -830,13 +941,17 @@ func (e *ProcessEnv) invokeGo(ctx context.Context, verb string, args ...string) Logf: e.Logf, WorkingDir: e.WorkingDir, } - return inv.Run(ctx) + return e.GocmdRunner.Run(ctx, inv) } -func addStdlibCandidates(pass *pass, refs references) { +func addStdlibCandidates(pass *pass, refs references) error { + goenv, err := pass.env.goEnv() + if err != nil { + return err + } add := func(pkg string) { // Prevent self-imports. - if path.Base(pkg) == pass.f.Name.Name && filepath.Join(pass.env.GOROOT, "src", pkg) == pass.srcDir { + if path.Base(pkg) == pass.f.Name.Name && filepath.Join(goenv["GOROOT"], "src", pkg) == pass.srcDir { return } exports := copyExports(stdlib[pkg]) @@ -857,6 +972,7 @@ func addStdlibCandidates(pass *pass, refs references) { } } } + return nil } // A Resolver does the build-system-specific parts of goimports. @@ -921,10 +1037,13 @@ func addExternalCandidates(pass *pass, refs references, filename string) error { return false // We'll do our own loading after we sort. }, } - err := pass.env.GetResolver().scan(context.Background(), callback) + resolver, err := pass.env.GetResolver() if err != nil { return err } + if err = resolver.scan(context.Background(), callback); err != nil { + return err + } // Search for imports matching potential package references. type result struct { @@ -1050,21 +1169,24 @@ func (r *gopathResolver) ClearForNewScan() { func (r *gopathResolver) loadPackageNames(importPaths []string, srcDir string) (map[string]string, error) { names := map[string]string{} + bctx, err := r.env.buildContext() + if err != nil { + return nil, err + } for _, path := range importPaths { - names[path] = importPathToName(r.env, path, srcDir) + names[path] = importPathToName(bctx, path, srcDir) } return names, nil } // importPathToName finds out the actual package name, as declared in its .go files. -// If there's a problem, it returns "". -func importPathToName(env *ProcessEnv, importPath, srcDir string) (packageName string) { +func importPathToName(bctx *build.Context, importPath, srcDir string) string { // Fast path for standard library without going to disk. if _, ok := stdlib[importPath]; ok { return path.Base(importPath) // stdlib packages always match their paths. } - buildPkg, err := env.buildContext().Import(importPath, srcDir, build.FindOnly) + buildPkg, err := bctx.Import(importPath, srcDir, build.FindOnly) if err != nil { return "" } @@ -1225,8 +1347,18 @@ func (r *gopathResolver) scan(ctx context.Context, callback *scanCallback) error } stop := r.cache.ScanAndListen(ctx, processDir) defer stop() + + goenv, err := r.env.goEnv() + if err != nil { + return err + } + var roots []gopathwalk.Root + roots = append(roots, gopathwalk.Root{filepath.Join(goenv["GOROOT"], "src"), gopathwalk.RootGOROOT}) + for _, p := range filepath.SplitList(goenv["GOPATH"]) { + roots = append(roots, gopathwalk.Root{filepath.Join(p, "src"), gopathwalk.RootGOPATH}) + } // The callback is not necessarily safe to use in the goroutine below. Process roots eagerly. - roots := filterRoots(gopathwalk.SrcDirsRoots(r.env.buildContext()), callback.rootFound) + roots = filterRoots(roots, callback.rootFound) // We can't cancel walks, because we need them to finish to have a usable // cache. Instead, run them in a separate goroutine and detach. scanDone := make(chan struct{}) @@ -1286,8 +1418,6 @@ func VendorlessPath(ipath string) string { } func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, includeTest bool) (string, []string, error) { - var exports []string - // Look for non-test, buildable .go files which could provide exports. all, err := ioutil.ReadDir(dir) if err != nil { @@ -1299,7 +1429,7 @@ func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, incl if !strings.HasSuffix(name, ".go") || (!includeTest && strings.HasSuffix(name, "_test.go")) { continue } - match, err := env.buildContext().MatchFile(dir, fi.Name()) + match, err := env.matchFile(dir, fi.Name()) if err != nil || !match { continue } @@ -1311,6 +1441,7 @@ func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, incl } var pkgName string + var exports []string fset := token.NewFileSet() for _, fi := range files { select { @@ -1322,7 +1453,10 @@ func loadExportsFromFiles(ctx context.Context, env *ProcessEnv, dir string, incl fullFile := filepath.Join(dir, fi.Name()) f, err := parser.ParseFile(fset, fullFile, nil, 0) if err != nil { - return "", nil, fmt.Errorf("parsing %s: %v", fullFile, err) + if env.Logf != nil { + env.Logf("error parsing %v: %v", fullFile, err) + } + continue } if f.Name.Name == "documentation" { // Special case from go/build.ImportDir, not @@ -1362,6 +1496,10 @@ func findImport(ctx context.Context, pass *pass, candidates []pkgDistance, pkgNa pass.env.Logf("%s candidate %d/%d: %v in %v", pkgName, i+1, len(candidates), c.pkg.importPathShort, c.pkg.dir) } } + resolver, err := pass.env.GetResolver() + if err != nil { + return nil, err + } // Collect exports for packages with matching names. rescv := make([]chan *pkg, len(candidates)) @@ -1400,7 +1538,7 @@ func findImport(ctx context.Context, pass *pass, candidates []pkgDistance, pkgNa } // If we're an x_test, load the package under test's test variant. includeTest := strings.HasSuffix(pass.f.Name.Name, "_test") && c.pkg.dir == pass.srcDir - _, exports, err := pass.env.GetResolver().loadExports(ctx, c.pkg, includeTest) + _, exports, err := resolver.loadExports(ctx, c.pkg, includeTest) if err != nil { if pass.env.Logf != nil { pass.env.Logf("loading exports in dir %s (seeking package %s): %v", c.pkg.dir, pkgName, err) diff --git a/vendor/golang.org/x/tools/internal/imports/imports.go b/vendor/golang.org/x/tools/internal/imports/imports.go index b18daea29..2815edc33 100644 --- a/vendor/golang.org/x/tools/internal/imports/imports.go +++ b/vendor/golang.org/x/tools/internal/imports/imports.go @@ -11,17 +11,13 @@ package imports import ( "bufio" "bytes" - "context" "fmt" "go/ast" - "go/build" "go/format" "go/parser" "go/printer" "go/token" "io" - "io/ioutil" - "os" "regexp" "strconv" "strings" @@ -33,6 +29,11 @@ import ( type Options struct { Env *ProcessEnv // The environment to use. Note: this contains the cached module and filesystem state. + // LocalPrefix is a comma-separated string of import path prefixes, which, if + // set, instructs Process to sort the import paths with the given prefixes + // into another group after 3rd-party packages. + LocalPrefix string + Fragment bool // Accept fragment of a source file (no package statement) AllErrors bool // Report all errors (not just the first 10 on different lines) @@ -43,13 +44,8 @@ type Options struct { FormatOnly bool // Disable the insertion and deletion of imports } -// Process implements golang.org/x/tools/imports.Process with explicit context in env. +// Process implements golang.org/x/tools/imports.Process with explicit context in opt.Env. func Process(filename string, src []byte, opt *Options) (formatted []byte, err error) { - src, opt, err = initialize(filename, src, opt) - if err != nil { - return nil, err - } - fileSet := token.NewFileSet() file, adjust, err := parse(fileSet, filename, src, opt) if err != nil { @@ -65,16 +61,12 @@ func Process(filename string, src []byte, opt *Options) (formatted []byte, err e } // FixImports returns a list of fixes to the imports that, when applied, -// will leave the imports in the same state as Process. +// will leave the imports in the same state as Process. src and opt must +// be specified. // // Note that filename's directory influences which imports can be chosen, // so it is important that filename be accurate. func FixImports(filename string, src []byte, opt *Options) (fixes []*ImportFix, err error) { - src, opt, err = initialize(filename, src, opt) - if err != nil { - return nil, err - } - fileSet := token.NewFileSet() file, _, err := parse(fileSet, filename, src, opt) if err != nil { @@ -85,13 +77,9 @@ func FixImports(filename string, src []byte, opt *Options) (fixes []*ImportFix, } // ApplyFixes applies all of the fixes to the file and formats it. extraMode -// is added in when parsing the file. +// is added in when parsing the file. src and opts must be specified, but no +// env is needed. func ApplyFixes(fixes []*ImportFix, filename string, src []byte, opt *Options, extraMode parser.Mode) (formatted []byte, err error) { - src, opt, err = initialize(filename, src, opt) - if err != nil { - return nil, err - } - // Don't use parse() -- we don't care about fragments or statement lists // here, and we need to work with unparseable files. fileSet := token.NewFileSet() @@ -115,59 +103,9 @@ func ApplyFixes(fixes []*ImportFix, filename string, src []byte, opt *Options, e return formatFile(fileSet, file, src, nil, opt) } -// GetAllCandidates gets all of the packages starting with prefix that can be -// imported by filename, sorted by import path. -func GetAllCandidates(ctx context.Context, callback func(ImportFix), searchPrefix, filename, filePkg string, opt *Options) error { - _, opt, err := initialize(filename, []byte{}, opt) - if err != nil { - return err - } - return getAllCandidates(ctx, callback, searchPrefix, filename, filePkg, opt.Env) -} - -// GetPackageExports returns all known packages with name pkg and their exports. -func GetPackageExports(ctx context.Context, callback func(PackageExport), searchPkg, filename, filePkg string, opt *Options) error { - _, opt, err := initialize(filename, []byte{}, opt) - if err != nil { - return err - } - return getPackageExports(ctx, callback, searchPkg, filename, filePkg, opt.Env) -} - -// initialize sets the values for opt and src. -// If they are provided, they are not changed. Otherwise opt is set to the -// default values and src is read from the file system. -func initialize(filename string, src []byte, opt *Options) ([]byte, *Options, error) { - // Use defaults if opt is nil. - if opt == nil { - opt = &Options{Comments: true, TabIndent: true, TabWidth: 8} - } - - // Set the env if the user has not provided it. - if opt.Env == nil { - opt.Env = &ProcessEnv{ - GOPATH: build.Default.GOPATH, - GOROOT: build.Default.GOROOT, - GOFLAGS: os.Getenv("GOFLAGS"), - GO111MODULE: os.Getenv("GO111MODULE"), - GOPROXY: os.Getenv("GOPROXY"), - GOSUMDB: os.Getenv("GOSUMDB"), - } - } - if src == nil { - b, err := ioutil.ReadFile(filename) - if err != nil { - return nil, nil, err - } - src = b - } - - return src, opt, nil -} - func formatFile(fileSet *token.FileSet, file *ast.File, src []byte, adjust func(orig []byte, src []byte) []byte, opt *Options) ([]byte, error) { - mergeImports(opt.Env, fileSet, file) - sortImports(opt.Env, fileSet, file) + mergeImports(fileSet, file) + sortImports(opt.LocalPrefix, fileSet, file) imps := astutil.Imports(fileSet, file) var spacesBefore []string // import paths we need spaces before for _, impSection := range imps { @@ -178,7 +116,7 @@ func formatFile(fileSet *token.FileSet, file *ast.File, src []byte, adjust func( lastGroup := -1 for _, importSpec := range impSection { importPath, _ := strconv.Unquote(importSpec.Path.Value) - groupNum := importGroup(opt.Env, importPath) + groupNum := importGroup(opt.LocalPrefix, importPath) if groupNum != lastGroup && lastGroup != -1 { spacesBefore = append(spacesBefore, importPath) } diff --git a/vendor/golang.org/x/tools/internal/imports/mod.go b/vendor/golang.org/x/tools/internal/imports/mod.go index 69e3eecc4..94880d616 100644 --- a/vendor/golang.org/x/tools/internal/imports/mod.go +++ b/vendor/golang.org/x/tools/internal/imports/mod.go @@ -15,7 +15,7 @@ import ( "strings" "golang.org/x/mod/module" - "golang.org/x/mod/semver" + "golang.org/x/tools/internal/gocommand" "golang.org/x/tools/internal/gopathwalk" ) @@ -24,31 +24,21 @@ import ( type ModuleResolver struct { env *ProcessEnv moduleCacheDir string - dummyVendorMod *ModuleJSON // If vendoring is enabled, the pseudo-module that represents the /vendor directory. + dummyVendorMod *gocommand.ModuleJSON // If vendoring is enabled, the pseudo-module that represents the /vendor directory. roots []gopathwalk.Root scanSema chan struct{} // scanSema prevents concurrent scans and guards scannedRoots. scannedRoots map[gopathwalk.Root]bool initialized bool - main *ModuleJSON - modsByModPath []*ModuleJSON // All modules, ordered by # of path components in module Path... - modsByDir []*ModuleJSON // ...or Dir. + main *gocommand.ModuleJSON + modsByModPath []*gocommand.ModuleJSON // All modules, ordered by # of path components in module Path... + modsByDir []*gocommand.ModuleJSON // ...or Dir. // moduleCacheCache stores information about the module cache. moduleCacheCache *dirInfoCache otherCache *dirInfoCache } -type ModuleJSON struct { - Path string // module path - Replace *ModuleJSON // replaced by this module - Main bool // is this the main module? - Indirect bool // is this module only an indirect dependency of main module? - Dir string // directory holding files for this module, if any - GoMod string // path to go.mod file for this module, if any - GoVersion string // go version used in module -} - func newModuleResolver(e *ProcessEnv) *ModuleResolver { r := &ModuleResolver{ env: e, @@ -62,7 +52,18 @@ func (r *ModuleResolver) init() error { if r.initialized { return nil } - mainMod, vendorEnabled, err := vendorEnabled(r.env) + + goenv, err := r.env.goEnv() + if err != nil { + return err + } + inv := gocommand.Invocation{ + BuildFlags: r.env.BuildFlags, + Env: r.env.env(), + Logf: r.env.Logf, + WorkingDir: r.env.WorkingDir, + } + mainMod, vendorEnabled, err := gocommand.VendorEnabled(context.TODO(), inv, r.env.GocmdRunner) if err != nil { return err } @@ -71,18 +72,22 @@ func (r *ModuleResolver) init() error { // Vendor mode is on, so all the non-Main modules are irrelevant, // and we need to search /vendor for everything. r.main = mainMod - r.dummyVendorMod = &ModuleJSON{ + r.dummyVendorMod = &gocommand.ModuleJSON{ Path: "", Dir: filepath.Join(mainMod.Dir, "vendor"), } - r.modsByModPath = []*ModuleJSON{mainMod, r.dummyVendorMod} - r.modsByDir = []*ModuleJSON{mainMod, r.dummyVendorMod} + r.modsByModPath = []*gocommand.ModuleJSON{mainMod, r.dummyVendorMod} + r.modsByDir = []*gocommand.ModuleJSON{mainMod, r.dummyVendorMod} } else { // Vendor mode is off, so run go list -m ... to find everything. r.initAllMods() } - r.moduleCacheDir = filepath.Join(filepath.SplitList(r.env.GOPATH)[0], "/pkg/mod") + if gmc := r.env.Env["GOMODCACHE"]; gmc != "" { + r.moduleCacheDir = gmc + } else { + r.moduleCacheDir = filepath.Join(filepath.SplitList(goenv["GOPATH"])[0], "/pkg/mod") + } sort.Slice(r.modsByModPath, func(i, j int) bool { count := func(x int) int { @@ -98,7 +103,7 @@ func (r *ModuleResolver) init() error { }) r.roots = []gopathwalk.Root{ - {filepath.Join(r.env.GOROOT, "/src"), gopathwalk.RootGOROOT}, + {filepath.Join(goenv["GOROOT"], "/src"), gopathwalk.RootGOROOT}, } if r.main != nil { r.roots = append(r.roots, gopathwalk.Root{r.main.Dir, gopathwalk.RootCurrentModule}) @@ -106,7 +111,7 @@ func (r *ModuleResolver) init() error { if vendorEnabled { r.roots = append(r.roots, gopathwalk.Root{r.dummyVendorMod.Dir, gopathwalk.RootOther}) } else { - addDep := func(mod *ModuleJSON) { + addDep := func(mod *gocommand.ModuleJSON) { if mod.Replace == nil { // This is redundant with the cache, but we'll skip it cheaply enough. r.roots = append(r.roots, gopathwalk.Root{mod.Dir, gopathwalk.RootModuleCache}) @@ -151,7 +156,7 @@ func (r *ModuleResolver) initAllMods() error { return err } for dec := json.NewDecoder(stdout); dec.More(); { - mod := &ModuleJSON{} + mod := &gocommand.ModuleJSON{} if err := dec.Decode(mod); err != nil { return err } @@ -197,7 +202,7 @@ func (r *ModuleResolver) ClearForNewMod() { // findPackage returns the module and directory that contains the package at // the given import path, or returns nil, "" if no module is in scope. -func (r *ModuleResolver) findPackage(importPath string) (*ModuleJSON, string) { +func (r *ModuleResolver) findPackage(importPath string) (*gocommand.ModuleJSON, string) { // This can't find packages in the stdlib, but that's harmless for all // the existing code paths. for _, m := range r.modsByModPath { @@ -239,7 +244,7 @@ func (r *ModuleResolver) findPackage(importPath string) (*ModuleJSON, string) { // files in that directory. If not, it could be provided by an // outer module. See #29736. for _, fi := range pkgFiles { - if ok, _ := r.env.buildContext().MatchFile(pkgDir, fi.Name()); ok { + if ok, _ := r.env.matchFile(pkgDir, fi.Name()); ok { return m, pkgDir } } @@ -283,7 +288,7 @@ func (r *ModuleResolver) cacheExports(ctx context.Context, env *ProcessEnv, info // findModuleByDir returns the module that contains dir, or nil if no such // module is in scope. -func (r *ModuleResolver) findModuleByDir(dir string) *ModuleJSON { +func (r *ModuleResolver) findModuleByDir(dir string) *gocommand.ModuleJSON { // This is quite tricky and may not be correct. dir could be: // - a package in the main module. // - a replace target underneath the main module's directory. @@ -310,7 +315,7 @@ func (r *ModuleResolver) findModuleByDir(dir string) *ModuleJSON { // dirIsNestedModule reports if dir is contained in a nested module underneath // mod, not actually in mod. -func (r *ModuleResolver) dirIsNestedModule(dir string, mod *ModuleJSON) bool { +func (r *ModuleResolver) dirIsNestedModule(dir string, mod *gocommand.ModuleJSON) bool { if !strings.HasPrefix(dir, mod.Dir) { return false } @@ -490,7 +495,7 @@ func (r *ModuleResolver) scoreImportPath(ctx context.Context, path string) int { return modRelevance(mod) } -func modRelevance(mod *ModuleJSON) int { +func modRelevance(mod *gocommand.ModuleJSON) int { switch { case mod == nil: // out of scope return MaxRelevance - 4 @@ -656,63 +661,3 @@ func modulePath(mod []byte) string { } return "" // missing module path } - -var modFlagRegexp = regexp.MustCompile(`-mod[ =](\w+)`) - -// vendorEnabled indicates if vendoring is enabled. -// Inspired by setDefaultBuildMod in modload/init.go -func vendorEnabled(env *ProcessEnv) (*ModuleJSON, bool, error) { - mainMod, go114, err := getMainModuleAnd114(env) - if err != nil { - return nil, false, err - } - matches := modFlagRegexp.FindStringSubmatch(env.GOFLAGS) - var modFlag string - if len(matches) != 0 { - modFlag = matches[1] - } - if modFlag != "" { - // Don't override an explicit '-mod=' argument. - return mainMod, modFlag == "vendor", nil - } - if mainMod == nil || !go114 { - return mainMod, false, nil - } - // Check 1.14's automatic vendor mode. - if fi, err := os.Stat(filepath.Join(mainMod.Dir, "vendor")); err == nil && fi.IsDir() { - if mainMod.GoVersion != "" && semver.Compare("v"+mainMod.GoVersion, "v1.14") >= 0 { - // The Go version is at least 1.14, and a vendor directory exists. - // Set -mod=vendor by default. - return mainMod, true, nil - } - } - return mainMod, false, nil -} - -// getMainModuleAnd114 gets the main module's information and whether the -// go command in use is 1.14+. This is the information needed to figure out -// if vendoring should be enabled. -func getMainModuleAnd114(env *ProcessEnv) (*ModuleJSON, bool, error) { - const format = `{{.Path}} -{{.Dir}} -{{.GoMod}} -{{.GoVersion}} -{{range context.ReleaseTags}}{{if eq . "go1.14"}}{{.}}{{end}}{{end}} -` - stdout, err := env.invokeGo(context.TODO(), "list", "-m", "-f", format) - if err != nil { - return nil, false, nil - } - lines := strings.Split(stdout.String(), "\n") - if len(lines) < 5 { - return nil, false, fmt.Errorf("unexpected stdout: %q", stdout) - } - mod := &ModuleJSON{ - Path: lines[0], - Dir: lines[1], - GoMod: lines[2], - GoVersion: lines[3], - Main: true, - } - return mod, lines[4] == "go1.14", nil -} diff --git a/vendor/golang.org/x/tools/internal/imports/sortimports.go b/vendor/golang.org/x/tools/internal/imports/sortimports.go index 226279471..be8ffa25f 100644 --- a/vendor/golang.org/x/tools/internal/imports/sortimports.go +++ b/vendor/golang.org/x/tools/internal/imports/sortimports.go @@ -15,7 +15,7 @@ import ( // sortImports sorts runs of consecutive import lines in import blocks in f. // It also removes duplicate imports when it is possible to do so without data loss. -func sortImports(env *ProcessEnv, fset *token.FileSet, f *ast.File) { +func sortImports(localPrefix string, fset *token.FileSet, f *ast.File) { for i, d := range f.Decls { d, ok := d.(*ast.GenDecl) if !ok || d.Tok != token.IMPORT { @@ -40,11 +40,11 @@ func sortImports(env *ProcessEnv, fset *token.FileSet, f *ast.File) { for j, s := range d.Specs { if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line { // j begins a new run. End this one. - specs = append(specs, sortSpecs(env, fset, f, d.Specs[i:j])...) + specs = append(specs, sortSpecs(localPrefix, fset, f, d.Specs[i:j])...) i = j } } - specs = append(specs, sortSpecs(env, fset, f, d.Specs[i:])...) + specs = append(specs, sortSpecs(localPrefix, fset, f, d.Specs[i:])...) d.Specs = specs // Deduping can leave a blank line before the rparen; clean that up. @@ -60,7 +60,7 @@ func sortImports(env *ProcessEnv, fset *token.FileSet, f *ast.File) { // mergeImports merges all the import declarations into the first one. // Taken from golang.org/x/tools/ast/astutil. -func mergeImports(env *ProcessEnv, fset *token.FileSet, f *ast.File) { +func mergeImports(fset *token.FileSet, f *ast.File) { if len(f.Decls) <= 1 { return } @@ -142,7 +142,7 @@ type posSpan struct { End token.Pos } -func sortSpecs(env *ProcessEnv, fset *token.FileSet, f *ast.File, specs []ast.Spec) []ast.Spec { +func sortSpecs(localPrefix string, fset *token.FileSet, f *ast.File, specs []ast.Spec) []ast.Spec { // Can't short-circuit here even if specs are already sorted, // since they might yet need deduplication. // A lone import, however, may be safely ignored. @@ -191,7 +191,7 @@ func sortSpecs(env *ProcessEnv, fset *token.FileSet, f *ast.File, specs []ast.Sp // Reassign the import paths to have the same position sequence. // Reassign each comment to abut the end of its spec. // Sort the comments by new position. - sort.Sort(byImportSpec{env, specs}) + sort.Sort(byImportSpec{localPrefix, specs}) // Dedup. Thanks to our sorting, we can just consider // adjacent pairs of imports. @@ -245,8 +245,8 @@ func sortSpecs(env *ProcessEnv, fset *token.FileSet, f *ast.File, specs []ast.Sp } type byImportSpec struct { - env *ProcessEnv - specs []ast.Spec // slice of *ast.ImportSpec + localPrefix string + specs []ast.Spec // slice of *ast.ImportSpec } func (x byImportSpec) Len() int { return len(x.specs) } @@ -255,8 +255,8 @@ func (x byImportSpec) Less(i, j int) bool { ipath := importPath(x.specs[i]) jpath := importPath(x.specs[j]) - igroup := importGroup(x.env, ipath) - jgroup := importGroup(x.env, jpath) + igroup := importGroup(x.localPrefix, ipath) + jgroup := importGroup(x.localPrefix, jpath) if igroup != jgroup { return igroup < jgroup } diff --git a/vendor/golang.org/x/tools/internal/imports/zstdlib.go b/vendor/golang.org/x/tools/internal/imports/zstdlib.go index 7e60eb04e..7b573b983 100644 --- a/vendor/golang.org/x/tools/internal/imports/zstdlib.go +++ b/vendor/golang.org/x/tools/internal/imports/zstdlib.go @@ -56,6 +56,7 @@ var stdlib = map[string][]string{ }, "bufio": []string{ "ErrAdvanceTooFar", + "ErrBadReadCount", "ErrBufferFull", "ErrFinalToken", "ErrInvalidUnreadByte", @@ -303,7 +304,9 @@ var stdlib = map[string][]string{ "PrivateKey", "PublicKey", "Sign", + "SignASN1", "Verify", + "VerifyASN1", }, "crypto/ed25519": []string{ "GenerateKey", @@ -322,11 +325,13 @@ var stdlib = map[string][]string{ "CurveParams", "GenerateKey", "Marshal", + "MarshalCompressed", "P224", "P256", "P384", "P521", "Unmarshal", + "UnmarshalCompressed", }, "crypto/hmac": []string{ "Equal", @@ -415,6 +420,9 @@ var stdlib = map[string][]string{ "crypto/tls": []string{ "Certificate", "CertificateRequestInfo", + "CipherSuite", + "CipherSuiteName", + "CipherSuites", "Client", "ClientAuthType", "ClientHelloInfo", @@ -429,11 +437,13 @@ var stdlib = map[string][]string{ "CurveP521", "Dial", "DialWithDialer", + "Dialer", "ECDSAWithP256AndSHA256", "ECDSAWithP384AndSHA384", "ECDSAWithP521AndSHA512", "ECDSAWithSHA1", "Ed25519", + "InsecureCipherSuites", "Listen", "LoadX509KeyPair", "NewLRUClientSessionCache", @@ -465,6 +475,7 @@ var stdlib = map[string][]string{ "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", @@ -473,6 +484,7 @@ var stdlib = map[string][]string{ "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_RC4_128_SHA", "TLS_FALLBACK_SCSV", "TLS_RSA_WITH_3DES_EDE_CBC_SHA", @@ -501,6 +513,7 @@ var stdlib = map[string][]string{ "ConstraintViolationError", "CreateCertificate", "CreateCertificateRequest", + "CreateRevocationList", "DSA", "DSAWithSHA1", "DSAWithSHA256", @@ -575,6 +588,7 @@ var stdlib = map[string][]string{ "PublicKeyAlgorithm", "PureEd25519", "RSA", + "RevocationList", "SHA1WithRSA", "SHA256WithRSA", "SHA256WithRSAPSS", @@ -688,6 +702,7 @@ var stdlib = map[string][]string{ "String", "Tx", "TxOptions", + "Validator", "Value", "ValueConverter", "Valuer", @@ -698,36 +713,65 @@ var stdlib = map[string][]string{ "Attr", "AttrAbstractOrigin", "AttrAccessibility", + "AttrAddrBase", "AttrAddrClass", + "AttrAlignment", "AttrAllocated", "AttrArtificial", "AttrAssociated", "AttrBaseTypes", + "AttrBinaryScale", "AttrBitOffset", "AttrBitSize", "AttrByteSize", + "AttrCallAllCalls", + "AttrCallAllSourceCalls", + "AttrCallAllTailCalls", "AttrCallColumn", + "AttrCallDataLocation", + "AttrCallDataValue", "AttrCallFile", "AttrCallLine", + "AttrCallOrigin", + "AttrCallPC", + "AttrCallParameter", + "AttrCallReturnPC", + "AttrCallTailCall", + "AttrCallTarget", + "AttrCallTargetClobbered", + "AttrCallValue", "AttrCalling", "AttrCommonRef", "AttrCompDir", + "AttrConstExpr", "AttrConstValue", "AttrContainingType", "AttrCount", + "AttrDataBitOffset", "AttrDataLocation", "AttrDataMemberLoc", + "AttrDecimalScale", + "AttrDecimalSign", "AttrDeclColumn", "AttrDeclFile", "AttrDeclLine", "AttrDeclaration", "AttrDefaultValue", + "AttrDefaulted", + "AttrDeleted", "AttrDescription", + "AttrDigitCount", "AttrDiscr", "AttrDiscrList", "AttrDiscrValue", + "AttrDwoName", + "AttrElemental", "AttrEncoding", + "AttrEndianity", "AttrEntrypc", + "AttrEnumClass", + "AttrExplicit", + "AttrExportSymbols", "AttrExtension", "AttrExternal", "AttrFrameBase", @@ -738,27 +782,47 @@ var stdlib = map[string][]string{ "AttrInline", "AttrIsOptional", "AttrLanguage", + "AttrLinkageName", "AttrLocation", + "AttrLoclistsBase", "AttrLowerBound", "AttrLowpc", "AttrMacroInfo", + "AttrMacros", + "AttrMainSubprogram", + "AttrMutable", "AttrName", "AttrNamelistItem", + "AttrNoreturn", + "AttrObjectPointer", "AttrOrdering", + "AttrPictureString", "AttrPriority", "AttrProducer", "AttrPrototyped", + "AttrPure", "AttrRanges", + "AttrRank", + "AttrRecursive", + "AttrReference", "AttrReturnAddr", + "AttrRnglistsBase", + "AttrRvalueReference", "AttrSegment", "AttrSibling", + "AttrSignature", + "AttrSmall", "AttrSpecification", "AttrStartScope", "AttrStaticLink", "AttrStmtList", + "AttrStrOffsetsBase", "AttrStride", "AttrStrideSize", "AttrStringLength", + "AttrStringLengthBitSize", + "AttrStringLengthByteSize", + "AttrThreadsScaled", "AttrTrampoline", "AttrType", "AttrUpperBound", @@ -772,18 +836,23 @@ var stdlib = map[string][]string{ "BoolType", "CharType", "Class", + "ClassAddrPtr", "ClassAddress", "ClassBlock", "ClassConstant", "ClassExprLoc", "ClassFlag", "ClassLinePtr", + "ClassLocList", "ClassLocListPtr", "ClassMacPtr", "ClassRangeListPtr", "ClassReference", "ClassReferenceAlt", "ClassReferenceSig", + "ClassRngList", + "ClassRngListsPtr", + "ClassStrOffsetsPtr", "ClassString", "ClassStringAlt", "ClassUnknown", @@ -814,9 +883,13 @@ var stdlib = map[string][]string{ "Tag", "TagAccessDeclaration", "TagArrayType", + "TagAtomicType", "TagBaseType", + "TagCallSite", + "TagCallSiteParameter", "TagCatchDwarfBlock", "TagClassType", + "TagCoarrayType", "TagCommonDwarfBlock", "TagCommonInclusion", "TagCompileUnit", @@ -824,12 +897,15 @@ var stdlib = map[string][]string{ "TagConstType", "TagConstant", "TagDwarfProcedure", + "TagDynamicType", "TagEntryPoint", "TagEnumerationType", "TagEnumerator", "TagFileType", "TagFormalParameter", "TagFriend", + "TagGenericSubrange", + "TagImmutableType", "TagImportedDeclaration", "TagImportedModule", "TagImportedUnit", @@ -853,6 +929,7 @@ var stdlib = map[string][]string{ "TagRvalueReferenceType", "TagSetType", "TagSharedType", + "TagSkeletonUnit", "TagStringType", "TagStructType", "TagSubprogram", @@ -2281,6 +2358,27 @@ var stdlib = map[string][]string{ "IMAGE_DIRECTORY_ENTRY_RESOURCE", "IMAGE_DIRECTORY_ENTRY_SECURITY", "IMAGE_DIRECTORY_ENTRY_TLS", + "IMAGE_DLLCHARACTERISTICS_APPCONTAINER", + "IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE", + "IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY", + "IMAGE_DLLCHARACTERISTICS_GUARD_CF", + "IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA", + "IMAGE_DLLCHARACTERISTICS_NO_BIND", + "IMAGE_DLLCHARACTERISTICS_NO_ISOLATION", + "IMAGE_DLLCHARACTERISTICS_NO_SEH", + "IMAGE_DLLCHARACTERISTICS_NX_COMPAT", + "IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE", + "IMAGE_DLLCHARACTERISTICS_WDM_DRIVER", + "IMAGE_FILE_32BIT_MACHINE", + "IMAGE_FILE_AGGRESIVE_WS_TRIM", + "IMAGE_FILE_BYTES_REVERSED_HI", + "IMAGE_FILE_BYTES_REVERSED_LO", + "IMAGE_FILE_DEBUG_STRIPPED", + "IMAGE_FILE_DLL", + "IMAGE_FILE_EXECUTABLE_IMAGE", + "IMAGE_FILE_LARGE_ADDRESS_AWARE", + "IMAGE_FILE_LINE_NUMS_STRIPPED", + "IMAGE_FILE_LOCAL_SYMS_STRIPPED", "IMAGE_FILE_MACHINE_AM33", "IMAGE_FILE_MACHINE_AMD64", "IMAGE_FILE_MACHINE_ARM", @@ -2303,6 +2401,25 @@ var stdlib = map[string][]string{ "IMAGE_FILE_MACHINE_THUMB", "IMAGE_FILE_MACHINE_UNKNOWN", "IMAGE_FILE_MACHINE_WCEMIPSV2", + "IMAGE_FILE_NET_RUN_FROM_SWAP", + "IMAGE_FILE_RELOCS_STRIPPED", + "IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP", + "IMAGE_FILE_SYSTEM", + "IMAGE_FILE_UP_SYSTEM_ONLY", + "IMAGE_SUBSYSTEM_EFI_APPLICATION", + "IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER", + "IMAGE_SUBSYSTEM_EFI_ROM", + "IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER", + "IMAGE_SUBSYSTEM_NATIVE", + "IMAGE_SUBSYSTEM_NATIVE_WINDOWS", + "IMAGE_SUBSYSTEM_OS2_CUI", + "IMAGE_SUBSYSTEM_POSIX_CUI", + "IMAGE_SUBSYSTEM_UNKNOWN", + "IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION", + "IMAGE_SUBSYSTEM_WINDOWS_CE_GUI", + "IMAGE_SUBSYSTEM_WINDOWS_CUI", + "IMAGE_SUBSYSTEM_WINDOWS_GUI", + "IMAGE_SUBSYSTEM_XBOX", "ImportDirectory", "NewFile", "Open", @@ -2359,6 +2476,7 @@ var stdlib = map[string][]string{ "RawValue", "StructuralError", "SyntaxError", + "TagBMPString", "TagBitString", "TagBoolean", "TagEnum", @@ -2787,6 +2905,7 @@ var stdlib = map[string][]string{ "IsPredeclared", "Mode", "New", + "NewFromFiles", "Note", "Package", "PreserveAST", @@ -3115,6 +3234,11 @@ var stdlib = map[string][]string{ "New64", "New64a", }, + "hash/maphash": []string{ + "Hash", + "MakeSeed", + "Seed", + }, "html": []string{ "EscapeString", "UnescapeString", @@ -3367,6 +3491,7 @@ var stdlib = map[string][]string{ "Ldate", "Llongfile", "Lmicroseconds", + "Lmsgprefix", "Logger", "Lshortfile", "LstdFlags", @@ -3443,6 +3568,7 @@ var stdlib = map[string][]string{ "Exp", "Exp2", "Expm1", + "FMA", "Float32bits", "Float32frombits", "Float64bits", @@ -3567,6 +3693,9 @@ var stdlib = map[string][]string{ "OnesCount32", "OnesCount64", "OnesCount8", + "Rem", + "Rem32", + "Rem64", "Reverse", "Reverse16", "Reverse32", @@ -4108,6 +4237,7 @@ var stdlib = map[string][]string{ "DevNull", "Environ", "ErrClosed", + "ErrDeadlineExceeded", "ErrExist", "ErrInvalid", "ErrNoDeadline", @@ -4566,6 +4696,7 @@ var stdlib = map[string][]string{ "ErrRange", "ErrSyntax", "FormatBool", + "FormatComplex", "FormatFloat", "FormatInt", "FormatUint", @@ -4575,6 +4706,7 @@ var stdlib = map[string][]string{ "Itoa", "NumError", "ParseBool", + "ParseComplex", "ParseFloat", "ParseInt", "ParseUint", @@ -5140,7 +5272,10 @@ var stdlib = map[string][]string{ "CTL_NET", "CTL_QUERY", "CTRL_BREAK_EVENT", + "CTRL_CLOSE_EVENT", "CTRL_C_EVENT", + "CTRL_LOGOFF_EVENT", + "CTRL_SHUTDOWN_EVENT", "CancelIo", "CancelIoEx", "CertAddCertificateContextToStore", @@ -10112,6 +10247,7 @@ var stdlib = map[string][]string{ "Duployan", "Egyptian_Hieroglyphs", "Elbasan", + "Elymaic", "Ethiopic", "Extender", "FoldCategory", @@ -10215,6 +10351,7 @@ var stdlib = map[string][]string{ "Myanmar", "N", "Nabataean", + "Nandinagari", "Nd", "New_Tai_Lue", "Newa", @@ -10224,6 +10361,7 @@ var stdlib = map[string][]string{ "Noncharacter_Code_Point", "Number", "Nushu", + "Nyiakeng_Puachue_Hmong", "Ogham", "Ol_Chiki", "Old_Hungarian", @@ -10331,6 +10469,7 @@ var stdlib = map[string][]string{ "Vai", "Variation_Selector", "Version", + "Wancho", "Warang_Citi", "White_Space", "Yi", diff --git a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go index b13ce33a3..2c4527f24 100644 --- a/vendor/golang.org/x/tools/internal/packagesinternal/packages.go +++ b/vendor/golang.org/x/tools/internal/packagesinternal/packages.go @@ -1,27 +1,14 @@ // Package packagesinternal exposes internal-only fields from go/packages. package packagesinternal -import "time" - -// Fields must match go list; -type Module struct { - Path string // module path - Version string // module version - Versions []string // available module versions (with -versions) - Replace *Module // replaced by this module - Time *time.Time // time version was created - Update *Module // available update, if any (with -u) - Main bool // is this the main module? - Indirect bool // is this module only an indirect dependency of main module? - Dir string // directory holding files for this module, if any - GoMod string // path to go.mod file used when loading this module, if any - GoVersion string // go version used in module - Error *ModuleError // error loading module -} -type ModuleError struct { - Err string // the error itself -} +import ( + "golang.org/x/tools/internal/gocommand" +) var GetForTest = func(p interface{}) string { return "" } -var GetModule = func(p interface{}) *Module { return nil } +var GetGoCmdRunner = func(config interface{}) *gocommand.Runner { return nil } + +var SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) {} + +var TypecheckCgo int diff --git a/vendor/golang.org/x/tools/internal/typesinternal/types.go b/vendor/golang.org/x/tools/internal/typesinternal/types.go new file mode 100644 index 000000000..a5bb408e2 --- /dev/null +++ b/vendor/golang.org/x/tools/internal/typesinternal/types.go @@ -0,0 +1,28 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package typesinternal + +import ( + "go/types" + "reflect" + "unsafe" +) + +func SetUsesCgo(conf *types.Config) bool { + v := reflect.ValueOf(conf).Elem() + + f := v.FieldByName("go115UsesCgo") + if !f.IsValid() { + f = v.FieldByName("UsesCgo") + if !f.IsValid() { + return false + } + } + + addr := unsafe.Pointer(f.UnsafeAddr()) + *(*bool)(addr) = true + + return true +} diff --git a/vendor/gopkg.in/yaml.v2/.travis.yml b/vendor/gopkg.in/yaml.v2/.travis.yml index 9f556934d..055480b9e 100644 --- a/vendor/gopkg.in/yaml.v2/.travis.yml +++ b/vendor/gopkg.in/yaml.v2/.travis.yml @@ -1,12 +1,16 @@ language: go go: - - 1.4 - - 1.5 - - 1.6 - - 1.7 - - 1.8 - - 1.9 - - tip + - "1.4.x" + - "1.5.x" + - "1.6.x" + - "1.7.x" + - "1.8.x" + - "1.9.x" + - "1.10.x" + - "1.11.x" + - "1.12.x" + - "1.13.x" + - "tip" go_import_path: gopkg.in/yaml.v2 diff --git a/vendor/gopkg.in/yaml.v2/apic.go b/vendor/gopkg.in/yaml.v2/apic.go index 1f7e87e67..d2c2308f1 100644 --- a/vendor/gopkg.in/yaml.v2/apic.go +++ b/vendor/gopkg.in/yaml.v2/apic.go @@ -86,6 +86,7 @@ func yaml_emitter_initialize(emitter *yaml_emitter_t) { raw_buffer: make([]byte, 0, output_raw_buffer_size), states: make([]yaml_emitter_state_t, 0, initial_stack_size), events: make([]yaml_event_t, 0, initial_queue_size), + best_width: -1, } } diff --git a/vendor/gopkg.in/yaml.v2/decode.go b/vendor/gopkg.in/yaml.v2/decode.go index 531087655..129bc2a97 100644 --- a/vendor/gopkg.in/yaml.v2/decode.go +++ b/vendor/gopkg.in/yaml.v2/decode.go @@ -319,10 +319,14 @@ func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unm } const ( - // 400,000 decode operations is ~500kb of dense object declarations, or ~5kb of dense object declarations with 10000% alias expansion + // 400,000 decode operations is ~500kb of dense object declarations, or + // ~5kb of dense object declarations with 10000% alias expansion alias_ratio_range_low = 400000 - // 4,000,000 decode operations is ~5MB of dense object declarations, or ~4.5MB of dense object declarations with 10% alias expansion + + // 4,000,000 decode operations is ~5MB of dense object declarations, or + // ~4.5MB of dense object declarations with 10% alias expansion alias_ratio_range_high = 4000000 + // alias_ratio_range is the range over which we scale allowed alias ratios alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low) ) @@ -784,8 +788,7 @@ func (d *decoder) merge(n *node, out reflect.Value) { case mappingNode: d.unmarshal(n, out) case aliasNode: - an, ok := d.doc.anchors[n.value] - if ok && an.kind != mappingNode { + if n.alias != nil && n.alias.kind != mappingNode { failWantMap() } d.unmarshal(n, out) @@ -794,8 +797,7 @@ func (d *decoder) merge(n *node, out reflect.Value) { for i := len(n.children) - 1; i >= 0; i-- { ni := n.children[i] if ni.kind == aliasNode { - an, ok := d.doc.anchors[ni.value] - if ok && an.kind != mappingNode { + if ni.alias != nil && ni.alias.kind != mappingNode { failWantMap() } } else if ni.kind != mappingNode { diff --git a/vendor/gopkg.in/yaml.v2/scannerc.go b/vendor/gopkg.in/yaml.v2/scannerc.go index 570b8ecd1..0b9bb6030 100644 --- a/vendor/gopkg.in/yaml.v2/scannerc.go +++ b/vendor/gopkg.in/yaml.v2/scannerc.go @@ -626,30 +626,17 @@ func trace(args ...interface{}) func() { func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool { // While we need more tokens to fetch, do it. for { - // Check if we really need to fetch more tokens. - need_more_tokens := false - - if parser.tokens_head == len(parser.tokens) { - // Queue is empty. - need_more_tokens = true - } else { - // Check if any potential simple key may occupy the head position. - if !yaml_parser_stale_simple_keys(parser) { + if parser.tokens_head != len(parser.tokens) { + // If queue is non-empty, check if any potential simple key may + // occupy the head position. + head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed] + if !ok { + break + } else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok { return false + } else if !valid { + break } - - for i := range parser.simple_keys { - simple_key := &parser.simple_keys[i] - if simple_key.possible && simple_key.token_number == parser.tokens_parsed { - need_more_tokens = true - break - } - } - } - - // We are finished. - if !need_more_tokens { - break } // Fetch the next token. if !yaml_parser_fetch_next_token(parser) { @@ -678,11 +665,6 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool { return false } - // Remove obsolete potential simple keys. - if !yaml_parser_stale_simple_keys(parser) { - return false - } - // Check the indentation level against the current column. if !yaml_parser_unroll_indent(parser, parser.mark.column) { return false @@ -837,29 +819,30 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool { "found character that cannot start any token") } -// Check the list of potential simple keys and remove the positions that -// cannot contain simple keys anymore. -func yaml_parser_stale_simple_keys(parser *yaml_parser_t) bool { - // Check for a potential simple key for each flow level. - for i := range parser.simple_keys { - simple_key := &parser.simple_keys[i] - - // The specification requires that a simple key - // - // - is limited to a single line, - // - is shorter than 1024 characters. - if simple_key.possible && (simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index) { - - // Check if the potential simple key to be removed is required. - if simple_key.required { - return yaml_parser_set_scanner_error(parser, - "while scanning a simple key", simple_key.mark, - "could not find expected ':'") - } - simple_key.possible = false - } +func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) { + if !simple_key.possible { + return false, true } - return true + + // The 1.2 specification says: + // + // "If the ? indicator is omitted, parsing needs to see past the + // implicit key to recognize it as such. To limit the amount of + // lookahead required, the “:” indicator must appear at most 1024 + // Unicode characters beyond the start of the key. In addition, the key + // is restricted to a single line." + // + if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index { + // Check if the potential simple key to be removed is required. + if simple_key.required { + return false, yaml_parser_set_scanner_error(parser, + "while scanning a simple key", simple_key.mark, + "could not find expected ':'") + } + simple_key.possible = false + return false, true + } + return true, true } // Check if a simple key may start at the current position and add it if @@ -879,13 +862,14 @@ func yaml_parser_save_simple_key(parser *yaml_parser_t) bool { possible: true, required: required, token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), + mark: parser.mark, } - simple_key.mark = parser.mark if !yaml_parser_remove_simple_key(parser) { return false } parser.simple_keys[len(parser.simple_keys)-1] = simple_key + parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1 } return true } @@ -900,9 +884,10 @@ func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool { "while scanning a simple key", parser.simple_keys[i].mark, "could not find expected ':'") } + // Remove the key from the stack. + parser.simple_keys[i].possible = false + delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number) } - // Remove the key from the stack. - parser.simple_keys[i].possible = false return true } @@ -912,7 +897,12 @@ const max_flow_level = 10000 // Increase the flow level and resize the simple key list if needed. func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool { // Reset the simple key on the next level. - parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) + parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{ + possible: false, + required: false, + token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head), + mark: parser.mark, + }) // Increase the flow level. parser.flow_level++ @@ -928,7 +918,9 @@ func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool { func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool { if parser.flow_level > 0 { parser.flow_level-- - parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1] + last := len(parser.simple_keys) - 1 + delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number) + parser.simple_keys = parser.simple_keys[:last] } return true } @@ -1005,6 +997,8 @@ func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool { // Initialize the simple key stack. parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{}) + parser.simple_keys_by_tok = make(map[int]int) + // A simple key is allowed at the beginning of the stream. parser.simple_key_allowed = true @@ -1286,7 +1280,11 @@ func yaml_parser_fetch_value(parser *yaml_parser_t) bool { simple_key := &parser.simple_keys[len(parser.simple_keys)-1] // Have we found a simple key? - if simple_key.possible { + if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok { + return false + + } else if valid { + // Create the KEY token and insert it into the queue. token := yaml_token_t{ typ: yaml_KEY_TOKEN, @@ -1304,6 +1302,7 @@ func yaml_parser_fetch_value(parser *yaml_parser_t) bool { // Remove the simple key. simple_key.possible = false + delete(parser.simple_keys_by_tok, simple_key.token_number) // A simple key cannot follow another simple key. parser.simple_key_allowed = false diff --git a/vendor/gopkg.in/yaml.v2/yaml.go b/vendor/gopkg.in/yaml.v2/yaml.go index de85aa4cd..89650e293 100644 --- a/vendor/gopkg.in/yaml.v2/yaml.go +++ b/vendor/gopkg.in/yaml.v2/yaml.go @@ -89,7 +89,7 @@ func UnmarshalStrict(in []byte, out interface{}) (err error) { return unmarshal(in, out, true) } -// A Decorder reads and decodes YAML values from an input stream. +// A Decoder reads and decodes YAML values from an input stream. type Decoder struct { strict bool parser *parser diff --git a/vendor/gopkg.in/yaml.v2/yamlh.go b/vendor/gopkg.in/yaml.v2/yamlh.go index e25cee563..f6a9c8e34 100644 --- a/vendor/gopkg.in/yaml.v2/yamlh.go +++ b/vendor/gopkg.in/yaml.v2/yamlh.go @@ -579,6 +579,7 @@ type yaml_parser_t struct { simple_key_allowed bool // May a simple key occur at the current position? simple_keys []yaml_simple_key_t // The stack of simple keys. + simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number // Parser stuff diff --git a/vendor/modules.txt b/vendor/modules.txt index 48b432abd..ea595a4df 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,4 +1,4 @@ -# github.com/99designs/gqlgen v0.9.0 +# github.com/99designs/gqlgen v0.12.2 github.com/99designs/gqlgen github.com/99designs/gqlgen/api github.com/99designs/gqlgen/cmd @@ -7,17 +7,34 @@ github.com/99designs/gqlgen/codegen/config github.com/99designs/gqlgen/codegen/templates github.com/99designs/gqlgen/complexity github.com/99designs/gqlgen/graphql +github.com/99designs/gqlgen/graphql/errcode +github.com/99designs/gqlgen/graphql/executor +github.com/99designs/gqlgen/graphql/handler +github.com/99designs/gqlgen/graphql/handler/extension +github.com/99designs/gqlgen/graphql/handler/lru +github.com/99designs/gqlgen/graphql/handler/transport github.com/99designs/gqlgen/graphql/introspection +github.com/99designs/gqlgen/graphql/playground github.com/99designs/gqlgen/handler github.com/99designs/gqlgen/internal/code github.com/99designs/gqlgen/internal/imports +github.com/99designs/gqlgen/internal/rewrite github.com/99designs/gqlgen/plugin +github.com/99designs/gqlgen/plugin/federation github.com/99designs/gqlgen/plugin/modelgen github.com/99designs/gqlgen/plugin/resolvergen github.com/99designs/gqlgen/plugin/servergen # github.com/BurntSushi/toml v0.3.1 github.com/BurntSushi/toml -# github.com/agnivade/levenshtein v1.0.1 +# github.com/Yamashou/gqlgenc v0.0.0-20200902035953-4dbef3551953 +github.com/Yamashou/gqlgenc +github.com/Yamashou/gqlgenc/client +github.com/Yamashou/gqlgenc/clientgen +github.com/Yamashou/gqlgenc/config +github.com/Yamashou/gqlgenc/generator +github.com/Yamashou/gqlgenc/graphqljson +github.com/Yamashou/gqlgenc/introspection +# github.com/agnivade/levenshtein v1.1.0 github.com/agnivade/levenshtein # github.com/antchfx/htmlquery v1.2.3 github.com/antchfx/htmlquery @@ -75,6 +92,8 @@ github.com/chromedp/cdproto/webauthn github.com/chromedp/chromedp github.com/chromedp/chromedp/device github.com/chromedp/chromedp/kb +# github.com/cpuguy83/go-md2man/v2 v2.0.0 +github.com/cpuguy83/go-md2man/v2/md2man # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew # github.com/disintegration/imaging v1.6.0 @@ -192,6 +211,9 @@ github.com/mailru/easyjson/jwriter github.com/markbates/oncer # github.com/markbates/safe v1.0.1 github.com/markbates/safe +# github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007 +github.com/matryer/moq +github.com/matryer/moq/pkg/moq # github.com/mattn/go-sqlite3 v1.13.0 github.com/mattn/go-sqlite3 # github.com/mitchellh/go-homedir v1.1.0 @@ -206,7 +228,7 @@ github.com/modern-go/reflect2 github.com/natefinch/pie # github.com/pelletier/go-toml v1.2.0 github.com/pelletier/go-toml -# github.com/pkg/errors v0.8.1 +# github.com/pkg/errors v0.9.1 github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib/difflib @@ -221,10 +243,14 @@ github.com/rs/zerolog github.com/rs/zerolog/internal/cbor github.com/rs/zerolog/internal/json github.com/rs/zerolog/log +# github.com/russross/blackfriday/v2 v2.0.1 +github.com/russross/blackfriday/v2 # github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f github.com/shurcooL/graphql github.com/shurcooL/graphql/ident github.com/shurcooL/graphql/internal/jsonutil +# github.com/shurcooL/sanitized_anchor_name v1.0.0 +github.com/shurcooL/sanitized_anchor_name # github.com/sirupsen/logrus v1.4.2 github.com/sirupsen/logrus # github.com/spf13/afero v1.2.0 @@ -253,26 +279,27 @@ github.com/tidwall/gjson github.com/tidwall/match # github.com/tidwall/pretty v1.0.0 github.com/tidwall/pretty -# github.com/urfave/cli v1.20.0 -github.com/urfave/cli +# github.com/urfave/cli/v2 v2.1.1 +github.com/urfave/cli/v2 # github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e github.com/vektah/dataloaden github.com/vektah/dataloaden/pkg/generator -# github.com/vektah/gqlparser v1.1.2 -github.com/vektah/gqlparser -github.com/vektah/gqlparser/ast -github.com/vektah/gqlparser/gqlerror -github.com/vektah/gqlparser/lexer -github.com/vektah/gqlparser/parser -github.com/vektah/gqlparser/validator -github.com/vektah/gqlparser/validator/rules +# github.com/vektah/gqlparser/v2 v2.0.1 +github.com/vektah/gqlparser/v2 +github.com/vektah/gqlparser/v2/ast +github.com/vektah/gqlparser/v2/formatter +github.com/vektah/gqlparser/v2/gqlerror +github.com/vektah/gqlparser/v2/lexer +github.com/vektah/gqlparser/v2/parser +github.com/vektah/gqlparser/v2/validator +github.com/vektah/gqlparser/v2/validator/rules # github.com/vektra/mockery/v2 v2.2.1 github.com/vektra/mockery/v2 github.com/vektra/mockery/v2/cmd github.com/vektra/mockery/v2/pkg github.com/vektra/mockery/v2/pkg/config github.com/vektra/mockery/v2/pkg/logging -# golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 +# golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/crypto/bcrypt golang.org/x/crypto/blowfish golang.org/x/crypto/ssh/terminal @@ -285,10 +312,10 @@ golang.org/x/image/tiff/lzw golang.org/x/image/vp8 golang.org/x/image/vp8l golang.org/x/image/webp -# golang.org/x/mod v0.2.0 +# golang.org/x/mod v0.3.0 golang.org/x/mod/module golang.org/x/mod/semver -# golang.org/x/net v0.0.0-20200602114024-627f9648deb9 +# golang.org/x/net v0.0.0-20200822124328-c89045814202 golang.org/x/net/context/ctxhttp golang.org/x/net/html golang.org/x/net/html/atom @@ -316,22 +343,27 @@ golang.org/x/text/language golang.org/x/text/runes golang.org/x/text/transform golang.org/x/text/unicode/norm -# golang.org/x/tools v0.0.0-20200323144430-8dcfad9e016e +# golang.org/x/tools v0.0.0-20200915031644-64986481280e golang.org/x/tools/go/ast/astutil golang.org/x/tools/go/gcexportdata golang.org/x/tools/go/internal/gcimporter golang.org/x/tools/go/internal/packagesdriver golang.org/x/tools/go/packages golang.org/x/tools/imports +golang.org/x/tools/internal/event +golang.org/x/tools/internal/event/core +golang.org/x/tools/internal/event/keys +golang.org/x/tools/internal/event/label golang.org/x/tools/internal/fastwalk golang.org/x/tools/internal/gocommand golang.org/x/tools/internal/gopathwalk golang.org/x/tools/internal/imports golang.org/x/tools/internal/packagesinternal -# golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 +golang.org/x/tools/internal/typesinternal +# golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 golang.org/x/xerrors golang.org/x/xerrors/internal # gopkg.in/ini.v1 v1.51.0 gopkg.in/ini.v1 -# gopkg.in/yaml.v2 v2.2.4 +# gopkg.in/yaml.v2 v2.3.0 gopkg.in/yaml.v2